From 1dde989919d2c272ca7fcaa5c4b2d9ee02c490a0 Mon Sep 17 00:00:00 2001 From: Ram N Date: Mon, 12 Mar 2018 14:47:50 -0700 Subject: [PATCH 0001/1109] Add support for springDamping in SpringInterpolator Reviewed By: mdvacca Differential Revision: D7201334 fbshipit-source-id: 50929b4294188cd5a2a8ffa2080c38c0a9983535 --- .../AbstractLayoutAnimation.java | 28 +++++++++++-------- .../SimpleSpringInterpolator.java | 24 +++++++++++++++- 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AbstractLayoutAnimation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AbstractLayoutAnimation.java index 4fbd6938a9c574..1ad6ccab3946d5 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AbstractLayoutAnimation.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AbstractLayoutAnimation.java @@ -2,21 +2,20 @@ package com.facebook.react.uimanager.layoutanimation; -import javax.annotation.Nullable; - -import java.util.Map; - +import android.os.Build; import android.view.View; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.AccelerateInterpolator; import android.view.animation.Animation; +import android.view.animation.BaseInterpolator; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; import android.view.animation.LinearInterpolator; - import com.facebook.react.bridge.ReadableMap; import com.facebook.react.common.MapBuilder; import com.facebook.react.uimanager.IllegalViewOperationException; +import java.util.Map; +import javax.annotation.Nullable; /** * Class responsible for parsing and converting layout animation data into native {@link Animation} @@ -36,12 +35,11 @@ */ abstract @Nullable Animation createAnimationImpl(View view, int x, int y, int width, int height); - private static final Map INTERPOLATOR = MapBuilder.of( + private static final Map INTERPOLATOR = MapBuilder.of( InterpolatorType.LINEAR, new LinearInterpolator(), InterpolatorType.EASE_IN, new AccelerateInterpolator(), InterpolatorType.EASE_OUT, new DecelerateInterpolator(), - InterpolatorType.EASE_IN_EASE_OUT, new AccelerateDecelerateInterpolator(), - InterpolatorType.SPRING, new SimpleSpringInterpolator()); + InterpolatorType.EASE_IN_EASE_OUT, new AccelerateDecelerateInterpolator()); private @Nullable Interpolator mInterpolator; private int mDelayMs; @@ -64,7 +62,7 @@ public void initializeFromConfig(ReadableMap data, int globalDuration) { if (!data.hasKey("type")) { throw new IllegalArgumentException("Missing interpolation type."); } - mInterpolator = getInterpolator(InterpolatorType.fromString(data.getString("type"))); + mInterpolator = getInterpolator(InterpolatorType.fromString(data.getString("type")), data); if (!isValid()) { throw new IllegalViewOperationException("Invalid layout animation : " + data); @@ -100,8 +98,16 @@ public void initializeFromConfig(ReadableMap data, int globalDuration) { return animation; } - private static Interpolator getInterpolator(InterpolatorType type) { - Interpolator interpolator = INTERPOLATOR.get(type); + private static Interpolator getInterpolator(InterpolatorType type, ReadableMap params) { + Interpolator interpolator = null; + if (type.equals(InterpolatorType.SPRING)) { + interpolator = new SimpleSpringInterpolator(SimpleSpringInterpolator.getSpringDamping(params)); + } else { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { + // Conversion from BaseInterpolator to Interpolator is only possible on this Android versions + interpolator = INTERPOLATOR.get(type); + } + } if (interpolator == null) { throw new IllegalArgumentException("Missing interpolator for type : " + type); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/SimpleSpringInterpolator.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/SimpleSpringInterpolator.java index 9696fe90a1a3ad..7ca2de98a06068 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/SimpleSpringInterpolator.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/SimpleSpringInterpolator.java @@ -3,6 +3,8 @@ package com.facebook.react.uimanager.layoutanimation; import android.view.animation.Interpolator; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.ReadableType; /** * Simple spring interpolator @@ -11,10 +13,30 @@ /* package */ class SimpleSpringInterpolator implements Interpolator { private static final float FACTOR = 0.5f; + public static final String PARAM_SPRING_DAMPING = "springDamping"; + private final float mSpringDamping; + + public static float getSpringDamping(ReadableMap params){ + if (params.getType(PARAM_SPRING_DAMPING).equals(ReadableType.Number)){ + return (float) params.getDouble(PARAM_SPRING_DAMPING); + } else { + return FACTOR; + } + } + + public SimpleSpringInterpolator() { + mSpringDamping = FACTOR; + } + + public SimpleSpringInterpolator(float springDamping){ + mSpringDamping = springDamping; + } @Override public float getInterpolation(float input) { + // Using mSpringDamping in this equation is not really the exact mathematical springDamping, but a good approximation + // We need to replace this equation with the right Factor that accounts for damping and friction return (float) - (1 + Math.pow(2, -10 * input) * Math.sin((input - FACTOR / 4) * Math.PI * 2 / FACTOR)); + (1 + Math.pow(2, -10 * input) * Math.sin((input - mSpringDamping / 4) * Math.PI * 2 / mSpringDamping)); } } From 0459e4ffaadb161598ce1a5b14c08d49a9257c9c Mon Sep 17 00:00:00 2001 From: Moti Zilberman Date: Mon, 12 Mar 2018 16:05:40 -0700 Subject: [PATCH 0002/1109] Support Image resizeMode=repeat on Android Summary: `` for Android, matching the iOS implementation (#7968). (Non-goal: changing the component's API for finer-grained control / feature parity with CSS - this would be nice in the future) As requested in e.g. #14158. Given https://github.com/facebook/fresco/issues/1575, and lacking the context to follow the specific recommendations in https://github.com/facebook/fresco/issues/1575#issuecomment-267004303, I've opted for a minimal change within RN itself. It's likely that performance can be improved by offloading this work to Fresco in some clever way; but I'm assuming that the present naive approach is still an improvement over a userland implementation with `onLayout` and multiple `` instances. - Picking up on a TODO note in the existing code, I implemented `MultiPostprocessor` to allow arbitrary chaining of Fresco-compatible postprocessors inside `ReactImageView`. - Rather than extensively refactor `ImageResizeMode`, `ReactImageManager` and `ReactImageView`, I mostly preserved the existing API that maps `resizeMode` values to [`ScaleType`](http://frescolib.org/javadoc/reference/com/facebook/drawee/drawable/ScalingUtils.ScaleType.html) instances, and simply added a second mapping, to [`TileMode`](https://developer.android.com/reference/android/graphics/Shader.TileMode.html). - To match the iOS rendering exactly for oversized images, I found that scaling with a custom `ScaleType` was required - a kind of combination of `CENTER_INSIDE` and `FIT_START` which Fresco doesn't provide - so I implemented that as `ScaleTypeStartInside`. (This is, frankly, questionable as the default behaviour on iOS to begin with - but I am aiming for parity here) - `resizeMode="repeat"` is therefore unpacked by the view manager to the effect of: ```js view.setScaleType(ScaleTypeStartInside.INSTANCE); view.setTileMode(Shader.TileMode.REPEAT); ``` And the added postprocessing in the view (in case of a non-`CLAMP` tile mode) consists of waiting for layout, allocating a destination bitmap and painting the source bitmap with the requested tile mode and scale type. Note that as in https://github.com/facebook/react-native/pull/17398#issue-285235247, I have neither updated nor tested the "Flat" UI implementation - everything compiles but I've taken [this comment](https://github.com/facebook/react-native/issues/12770#issuecomment-294052694) to mean there's no point in trying to wade through it on my own right now; I'm happy to tackle it if given some pointers. Also, I'm happy to address any code style issues or other feedback; I'm new to this codebase and a very infrequent Android/Java coder. Tested by enabling the relevant case in RNTester on Android. | iOS | Android | |-|-| | | | Docs update: https://github.com/facebook/react-native-website/pull/106 [ANDROID] [FEATURE] [Image] - Implement resizeMode=repeat Closes https://github.com/facebook/react-native/pull/17404 Reviewed By: achen1 Differential Revision: D7070329 Pulled By: mdvacca fbshipit-source-id: 6a72fcbdcc7c7c2daf293dc1d8b6728f54ad0249 --- Libraries/Image/Image.android.js | 2 +- RNTester/js/ImageExample.js | 22 +++--- .../react/views/image/ImageResizeMode.java | 32 ++++++++ .../react/views/image/MultiPostprocessor.java | 79 +++++++++++++++++++ .../react/views/image/ReactImageManager.java | 1 + .../react/views/image/ReactImageView.java | 70 ++++++++++++++-- .../views/image/ScaleTypeStartInside.java | 40 ++++++++++ 7 files changed, 227 insertions(+), 19 deletions(-) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/image/MultiPostprocessor.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/image/ScaleTypeStartInside.java diff --git a/Libraries/Image/Image.android.js b/Libraries/Image/Image.android.js index bdb29ab8fe8965..4e218487c9b505 100644 --- a/Libraries/Image/Image.android.js +++ b/Libraries/Image/Image.android.js @@ -119,7 +119,7 @@ var Image = createReactClass({ * * See https://facebook.github.io/react-native/docs/image.html#resizemode */ - resizeMode: PropTypes.oneOf(['cover', 'contain', 'stretch', 'center']), + resizeMode: PropTypes.oneOf(['cover', 'contain', 'stretch', 'repeat', 'center']), }, statics: { diff --git a/RNTester/js/ImageExample.js b/RNTester/js/ImageExample.js index d30a24ca7c93b2..37f36b697de32a 100644 --- a/RNTester/js/ImageExample.js +++ b/RNTester/js/ImageExample.js @@ -558,18 +558,16 @@ exports.examples = [ source={image} /> - { Platform.OS === 'ios' ? - - - Repeat - - - - : null } + + + Repeat + + + Center diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ImageResizeMode.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ImageResizeMode.java index 3cff8b9667a292..3f98058feedd0c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/image/ImageResizeMode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ImageResizeMode.java @@ -9,6 +9,7 @@ import javax.annotation.Nullable; +import android.graphics.Shader; import com.facebook.react.bridge.JSApplicationIllegalArgumentException; import com.facebook.drawee.drawable.ScalingUtils; @@ -34,6 +35,10 @@ public static ScalingUtils.ScaleType toScaleType(@Nullable String resizeModeValu if ("center".equals(resizeModeValue)) { return ScalingUtils.ScaleType.CENTER_INSIDE; } + if ("repeat".equals(resizeModeValue)) { + // Handled via a combination of ScaleType and TileMode + return ScaleTypeStartInside.INSTANCE; + } if (resizeModeValue == null) { // Use the default. Never use null. return defaultValue(); @@ -42,6 +47,29 @@ public static ScalingUtils.ScaleType toScaleType(@Nullable String resizeModeValu "Invalid resize mode: '" + resizeModeValue + "'"); } + /** + * Converts JS resize modes into {@code Shader.TileMode}. + * See {@code ImageResizeMode.js}. + */ + public static Shader.TileMode toTileMode(@Nullable String resizeModeValue) { + if ("contain".equals(resizeModeValue) + || "cover".equals(resizeModeValue) + || "stretch".equals(resizeModeValue) + || "center".equals(resizeModeValue)) { + return Shader.TileMode.CLAMP; + } + if ("repeat".equals(resizeModeValue)) { + // Handled via a combination of ScaleType and TileMode + return Shader.TileMode.REPEAT; + } + if (resizeModeValue == null) { + // Use the default. Never use null. + return defaultTileMode(); + } + throw new JSApplicationIllegalArgumentException( + "Invalid resize mode: '" + resizeModeValue + "'"); + } + /** * This is the default as per web and iOS. * We want to be consistent across platforms. @@ -49,4 +77,8 @@ public static ScalingUtils.ScaleType toScaleType(@Nullable String resizeModeValu public static ScalingUtils.ScaleType defaultValue() { return ScalingUtils.ScaleType.CENTER_CROP; } + + public static Shader.TileMode defaultTileMode() { + return Shader.TileMode.CLAMP; + } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/MultiPostprocessor.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/MultiPostprocessor.java new file mode 100644 index 00000000000000..d6cf6a3ca8d6c4 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/MultiPostprocessor.java @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +package com.facebook.react.views.image; + +import android.graphics.Bitmap; + +import com.facebook.cache.common.CacheKey; +import com.facebook.cache.common.MultiCacheKey; +import com.facebook.common.references.CloseableReference; +import com.facebook.imagepipeline.bitmaps.PlatformBitmapFactory; +import com.facebook.imagepipeline.request.Postprocessor; + +import java.util.LinkedList; +import java.util.List; + +public class MultiPostprocessor implements Postprocessor { + private final List mPostprocessors; + + public static Postprocessor from(List postprocessors) { + switch (postprocessors.size()) { + case 0: + return null; + case 1: + return postprocessors.get(0); + default: + return new MultiPostprocessor(postprocessors); + } + } + + private MultiPostprocessor(List postprocessors) { + mPostprocessors = new LinkedList<>(postprocessors); + } + + @Override + public String getName () { + StringBuilder name = new StringBuilder(); + for (Postprocessor p: mPostprocessors) { + if (name.length() > 0) { + name.append(","); + } + name.append(p.getName()); + } + name.insert(0, "MultiPostProcessor ("); + name.append(")"); + return name.toString(); + } + + @Override + public CacheKey getPostprocessorCacheKey () { + LinkedList keys = new LinkedList<>(); + for (Postprocessor p: mPostprocessors) { + keys.push(p.getPostprocessorCacheKey()); + } + return new MultiCacheKey(keys); + } + + @Override + public CloseableReference process(Bitmap sourceBitmap, PlatformBitmapFactory bitmapFactory) { + CloseableReference prevBitmap = null, nextBitmap = null; + + try { + for (Postprocessor p : mPostprocessors) { + nextBitmap = p.process(prevBitmap != null ? prevBitmap.get() : sourceBitmap, bitmapFactory); + CloseableReference.closeSafely(prevBitmap); + prevBitmap = nextBitmap.clone(); + } + return nextBitmap.clone(); + } finally { + CloseableReference.closeSafely(nextBitmap); + } + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java index 21014c5c7b0fd5..938524d3012156 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java @@ -139,6 +139,7 @@ public void setBorderRadius(ReactImageView view, int index, float borderRadius) @ReactProp(name = ViewProps.RESIZE_MODE) public void setResizeMode(ReactImageView view, @Nullable String resizeMode) { view.setScaleType(ImageResizeMode.toScaleType(resizeMode)); + view.setTileMode(ImageResizeMode.toTileMode(resizeMode)); } @ReactProp(name = ViewProps.RESIZE_METHOD) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java index 3fa2e66eb82e6d..9396cac1c5c1f2 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java @@ -22,6 +22,7 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.widget.Toast; +import com.facebook.common.references.CloseableReference; import com.facebook.common.util.UriUtil; import com.facebook.drawee.controller.AbstractDraweeControllerBuilder; import com.facebook.drawee.controller.BaseControllerListener; @@ -33,6 +34,7 @@ import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; import com.facebook.drawee.generic.RoundingParams; import com.facebook.drawee.view.GenericDraweeView; +import com.facebook.imagepipeline.bitmaps.PlatformBitmapFactory; import com.facebook.imagepipeline.common.ResizeOptions; import com.facebook.imagepipeline.image.ImageInfo; import com.facebook.imagepipeline.postprocessors.IterativeBoxBlurPostProcessor; @@ -49,6 +51,7 @@ import com.facebook.react.uimanager.PixelUtil; import com.facebook.react.uimanager.UIManagerModule; import com.facebook.react.uimanager.events.EventDispatcher; +import com.facebook.react.views.image.ImageResizeMode; import com.facebook.react.views.imagehelper.ImageSource; import com.facebook.react.views.imagehelper.MultiSourceHelper; import com.facebook.react.views.imagehelper.MultiSourceHelper.MultiSourceResult; @@ -141,6 +144,40 @@ public void process(Bitmap output, Bitmap source) { } } + // Fresco lacks support for repeating images, see https://github.com/facebook/fresco/issues/1575 + // We implement it here as a postprocessing step. + private static final Matrix sTileMatrix = new Matrix(); + + private class TilePostprocessor extends BasePostprocessor { + @Override + public CloseableReference process(Bitmap source, PlatformBitmapFactory bitmapFactory) { + final Rect destRect = new Rect(0, 0, getWidth(), getHeight()); + + mScaleType.getTransform( + sTileMatrix, + destRect, + source.getWidth(), + source.getHeight(), + 0.0f, + 0.0f); + + Paint paint = new Paint(); + paint.setAntiAlias(true); + Shader shader = new BitmapShader(source, mTileMode, mTileMode); + shader.setLocalMatrix(sTileMatrix); + paint.setShader(shader); + + CloseableReference output = bitmapFactory.createBitmap(getWidth(), getHeight()); + try { + Canvas canvas = new Canvas(output.get()); + canvas.drawRect(destRect, paint); + return output.clone(); + } finally { + CloseableReference.closeSafely(output); + } + } + } + private final List mSources; private @Nullable ImageSource mImageSource; @@ -152,9 +189,11 @@ public void process(Bitmap output, Bitmap source) { private float mBorderRadius = YogaConstants.UNDEFINED; private @Nullable float[] mBorderCornerRadii; private ScalingUtils.ScaleType mScaleType; + private Shader.TileMode mTileMode = ImageResizeMode.defaultTileMode(); private boolean mIsDirty; private final AbstractDraweeControllerBuilder mDraweeControllerBuilder; private final RoundedCornerPostprocessor mRoundedCornerPostprocessor; + private final TilePostprocessor mTilePostprocessor; private @Nullable IterativeBoxBlurPostProcessor mIterativeBoxBlurPostProcessor; private @Nullable ControllerListener mControllerListener; private @Nullable ControllerListener mControllerForTesting; @@ -180,6 +219,7 @@ public ReactImageView( mScaleType = ImageResizeMode.defaultValue(); mDraweeControllerBuilder = draweeControllerBuilder; mRoundedCornerPostprocessor = new RoundedCornerPostprocessor(); + mTilePostprocessor = new TilePostprocessor(); mGlobalImageLoadListener = globalImageLoadListener; mCallerContext = callerContext; mSources = new LinkedList<>(); @@ -275,6 +315,11 @@ public void setScaleType(ScalingUtils.ScaleType scaleType) { mIsDirty = true; } + public void setTileMode(Shader.TileMode tileMode) { + mTileMode = tileMode; + mIsDirty = true; + } + public void setResizeMethod(ImageResizeMethod resizeMethod) { mResizeMethod = resizeMethod; mIsDirty = true; @@ -362,6 +407,11 @@ public void maybeUpdateView() { return; } + if (isTiled() && (getWidth() <= 0 || getHeight() <= 0)) { + // If need to tile and the size is not yet set, wait until the layout pass provides one + return; + } + GenericDraweeHierarchy hierarchy = getHierarchy(); hierarchy.setActualImageScaleType(mScaleType); @@ -396,13 +446,17 @@ public void maybeUpdateView() { ? mFadeDurationMs : mImageSource.isResource() ? 0 : REMOTE_IMAGE_FADE_DURATION_MS); - // TODO: t13601664 Support multiple PostProcessors - Postprocessor postprocessor = null; + List postprocessors = new LinkedList<>(); if (usePostprocessorScaling) { - postprocessor = mRoundedCornerPostprocessor; - } else if (mIterativeBoxBlurPostProcessor != null) { - postprocessor = mIterativeBoxBlurPostProcessor; + postprocessors.add(mRoundedCornerPostprocessor); + } + if (mIterativeBoxBlurPostProcessor != null) { + postprocessors.add(mIterativeBoxBlurPostProcessor); + } + if (isTiled()) { + postprocessors.add(mTilePostprocessor); } + Postprocessor postprocessor = MultiPostprocessor.from(postprocessors); ResizeOptions resizeOptions = doResize ? new ResizeOptions(getWidth(), getHeight()) : null; @@ -468,7 +522,7 @@ public void setControllerListener(ControllerListener controllerListener) { protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); if (w > 0 && h > 0) { - mIsDirty = mIsDirty || hasMultipleSources(); + mIsDirty = mIsDirty || hasMultipleSources() || isTiled(); maybeUpdateView(); } } @@ -485,6 +539,10 @@ private boolean hasMultipleSources() { return mSources.size() > 1; } + private boolean isTiled() { + return mTileMode != Shader.TileMode.CLAMP; + } + private void setSourceImage() { mImageSource = null; if (mSources.isEmpty()) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ScaleTypeStartInside.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ScaleTypeStartInside.java new file mode 100644 index 00000000000000..e2b902b2c5248f --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ScaleTypeStartInside.java @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +package com.facebook.react.views.image; + +import android.graphics.Matrix; +import android.graphics.Rect; +import com.facebook.drawee.drawable.ScalingUtils; + +public class ScaleTypeStartInside extends ScalingUtils.AbstractScaleType { + public static final ScalingUtils.ScaleType INSTANCE = new ScaleTypeStartInside(); + + @Override + public void getTransformImpl( + Matrix outTransform, + Rect parentRect, + int childWidth, + int childHeight, + float focusX, + float focusY, + float scaleX, + float scaleY) { + float scale = Math.min(Math.min(scaleX, scaleY), 1.0f); + float dx = parentRect.left; + float dy = parentRect.top; + outTransform.setScale(scale, scale); + outTransform.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f)); + } + + @Override + public String toString() { + return "start_inside"; + } +} From ab92c00245c0ce717819ddb0ab8b9204d4c13c34 Mon Sep 17 00:00:00 2001 From: Eli White Date: Mon, 12 Mar 2018 17:39:54 -0700 Subject: [PATCH 0003/1109] Convert Text to ES6 Class Summary: Utilizing ES6 Classes instead of createReactClass lets us actually enforce the way Text is used via Flow. Reviewed By: fkgozali Differential Revision: D7227755 fbshipit-source-id: 8e8285f9ebb3783a0dc4837c37c163178910ff9f --- Libraries/Text/Text.js | 107 +++++++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 48 deletions(-) diff --git a/Libraries/Text/Text.js b/Libraries/Text/Text.js index 866f46819e9bce..83b02877b88386 100644 --- a/Libraries/Text/Text.js +++ b/Libraries/Text/Text.js @@ -10,19 +10,35 @@ */ 'use strict'; -const NativeMethodsMixin = require('NativeMethodsMixin'); const React = require('React'); +const ReactNative = require('ReactNative'); const ReactNativeViewAttributes = require('ReactNativeViewAttributes'); const TextPropTypes = require('TextPropTypes'); const Touchable = require('Touchable'); const UIManager = require('UIManager'); -const createReactClass = require('create-react-class'); const createReactNativeComponentClass = require('createReactNativeComponentClass'); const mergeFast = require('mergeFast'); const processColor = require('processColor'); const {ViewContextTypes} = require('ViewContext'); +import type {PressEvent} from 'CoreEventTypes'; +import type {TextProps} from 'TextProps'; +import type {ViewChildContext} from 'ViewContext'; + +type State = { + isHighlighted: boolean, +}; + +type RectOffset = { + top: number, + left: number, + right: number, + bottom: number, +}; + +const PRESS_RECT_OFFSET = {top: 20, left: 20, right: 20, bottom: 30}; + const viewConfig = { validAttributes: mergeFast(ReactNativeViewAttributes.UIView, { isHighlighted: true, @@ -39,54 +55,54 @@ const viewConfig = { uiViewClassName: 'RCTText', }; -import type {ViewChildContext} from 'ViewContext'; - /** * A React component for displaying text. * * See https://facebook.github.io/react-native/docs/text.html */ +class Text extends ReactNative.NativeComponent { + static propTypes = TextPropTypes; + static childContextTypes = ViewContextTypes; + static contextTypes = ViewContextTypes; + + static defaultProps = { + accessible: true, + allowFontScaling: true, + ellipsizeMode: 'tail', + }; + + state = mergeFast(Touchable.Mixin.touchableGetInitialState(), { + isHighlighted: false, + }); + + viewConfig = viewConfig; -const Text = createReactClass({ - displayName: 'Text', - propTypes: TextPropTypes, - getDefaultProps(): Object { - return { - accessible: true, - allowFontScaling: true, - ellipsizeMode: 'tail', - }; - }, - getInitialState: function(): Object { - return mergeFast(Touchable.Mixin.touchableGetInitialState(), { - isHighlighted: false, - }); - }, - mixins: [NativeMethodsMixin], - viewConfig: viewConfig, getChildContext(): ViewChildContext { return { isInAParentText: true, }; - }, - childContextTypes: ViewContextTypes, - contextTypes: ViewContextTypes, - /** - * Only assigned if touch is needed. - */ - _handlers: (null: ?Object), + } + + _handlers: ?Object; + _hasPressHandler(): boolean { return !!this.props.onPress || !!this.props.onLongPress; - }, + } /** * These are assigned lazily the first time the responder is set to make plain * text nodes as cheap as possible. */ - touchableHandleActivePressIn: (null: ?Function), - touchableHandleActivePressOut: (null: ?Function), - touchableHandlePress: (null: ?Function), - touchableHandleLongPress: (null: ?Function), - touchableGetPressRectOffset: (null: ?Function), + touchableHandleActivePressIn: ?Function; + touchableHandleActivePressOut: ?Function; + touchableHandlePress: ?Function; + touchableHandleLongPress: ?Function; + touchableHandleResponderGrant: ?Function; + touchableHandleResponderMove: ?Function; + touchableHandleResponderRelease: ?Function; + touchableHandleResponderTerminate: ?Function; + touchableHandleResponderTerminationRequest: ?Function; + touchableGetPressRectOffset: ?Function; + render(): React.Element { let newProps = this.props; if (this.props.onStartShouldSetResponder || this._hasPressHandler()) { @@ -95,7 +111,6 @@ const Text = createReactClass({ onStartShouldSetResponder: (): boolean => { const shouldSetFromProps = this.props.onStartShouldSetResponder && - // $FlowFixMe(>=0.41.0) this.props.onStartShouldSetResponder(); const setResponder = shouldSetFromProps || this._hasPressHandler(); if (setResponder && !this.touchableHandleActivePressIn) { @@ -130,11 +145,11 @@ const Text = createReactClass({ }); }; - this.touchableHandlePress = (e: SyntheticEvent<>) => { + this.touchableHandlePress = (e: PressEvent) => { this.props.onPress && this.props.onPress(e); }; - this.touchableHandleLongPress = (e: SyntheticEvent<>) => { + this.touchableHandleLongPress = (e: PressEvent) => { this.props.onLongPress && this.props.onLongPress(e); }; @@ -145,21 +160,25 @@ const Text = createReactClass({ return setResponder; }, onResponderGrant: function(e: SyntheticEvent<>, dispatchID: string) { + // $FlowFixMe TouchableMixin handlers couldn't actually be null this.touchableHandleResponderGrant(e, dispatchID); this.props.onResponderGrant && this.props.onResponderGrant.apply(this, arguments); }.bind(this), onResponderMove: function(e: SyntheticEvent<>) { + // $FlowFixMe TouchableMixin handlers couldn't actually be null this.touchableHandleResponderMove(e); this.props.onResponderMove && this.props.onResponderMove.apply(this, arguments); }.bind(this), onResponderRelease: function(e: SyntheticEvent<>) { + // $FlowFixMe TouchableMixin handlers couldn't actually be null this.touchableHandleResponderRelease(e); this.props.onResponderRelease && this.props.onResponderRelease.apply(this, arguments); }.bind(this), onResponderTerminate: function(e: SyntheticEvent<>) { + // $FlowFixMe TouchableMixin handlers couldn't actually be null this.touchableHandleResponderTerminate(e); this.props.onResponderTerminate && this.props.onResponderTerminate.apply(this, arguments); @@ -167,6 +186,7 @@ const Text = createReactClass({ onResponderTerminationRequest: function(): boolean { // Allow touchable or props.onResponderTerminationRequest to deny // the request + // $FlowFixMe TouchableMixin handlers couldn't actually be null var allowTermination = this.touchableHandleResponderTerminationRequest(); if (allowTermination && this.props.onResponderTerminationRequest) { allowTermination = this.props.onResponderTerminationRequest.apply( @@ -201,17 +221,8 @@ const Text = createReactClass({ } else { return ; } - }, -}); - -type RectOffset = { - top: number, - left: number, - right: number, - bottom: number, -}; - -var PRESS_RECT_OFFSET = {top: 20, left: 20, right: 20, bottom: 30}; + } +} var RCTText = createReactNativeComponentClass( viewConfig.uiViewClassName, From 7a1c618de6a222f90f6525e7756a018e83b9134a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Mon, 12 Mar 2018 20:20:21 -0700 Subject: [PATCH 0004/1109] Change newly imported file to MIT license Summary: The project at large switched to MIT last month. A PR that was opened prior to the change was merged, this PR updates the file to use the correct license. None, trivial PR [ANDROID] [MINOR] [Image] Update license Closes https://github.com/facebook/react-native/pull/18343 Differential Revision: D7252836 Pulled By: hramos fbshipit-source-id: b7c207c782f4bf19c12d121e86f394e52326a5ab --- .../com/facebook/react/views/image/MultiPostprocessor.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/MultiPostprocessor.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/MultiPostprocessor.java index d6cf6a3ca8d6c4..03ad027c2618b2 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/image/MultiPostprocessor.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/MultiPostprocessor.java @@ -1,10 +1,8 @@ /** * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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.image; From aa323d4aa9d87874f45eda8a4798086fa91fd08e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Tue, 13 Mar 2018 10:28:43 -0700 Subject: [PATCH 0005/1109] Use MIT license Summary: Closes https://github.com/facebook/react-native/pull/18352 Differential Revision: D7257144 Pulled By: hramos fbshipit-source-id: 477ff82f74cfa3fd0681c9522cc5199a60b24921 --- .../facebook/react/views/image/ScaleTypeStartInside.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ScaleTypeStartInside.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ScaleTypeStartInside.java index e2b902b2c5248f..96640d044d5a14 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/image/ScaleTypeStartInside.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ScaleTypeStartInside.java @@ -1,10 +1,8 @@ /** * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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.image; From c136c54ff0211e2bf149fab600cd6e295f9d19dd Mon Sep 17 00:00:00 2001 From: Peter Argany Date: Tue, 13 Mar 2018 11:05:53 -0700 Subject: [PATCH 0006/1109] Refactor RCTInputAccessoryView view hierarchy and names Reviewed By: shergin Differential Revision: D7196162 fbshipit-source-id: 07a5c13d4cdb876f5a632d7d53859eab5e235f49 --- .../Text/TextInput/RCTBaseTextInputView.m | 2 +- .../Text/TextInput/RCTInputAccessoryView.h | 2 - .../Text/TextInput/RCTInputAccessoryView.m | 38 +++++++----- .../TextInput/RCTInputAccessoryViewContent.h | 2 - .../TextInput/RCTInputAccessoryViewContent.m | 58 +++++++++---------- .../TextInput/RCTInputAccessoryViewManager.m | 2 +- 6 files changed, 52 insertions(+), 52 deletions(-) diff --git a/Libraries/Text/TextInput/RCTBaseTextInputView.m b/Libraries/Text/TextInput/RCTBaseTextInputView.m index d9c47ff16311d4..65885a4882a686 100644 --- a/Libraries/Text/TextInput/RCTBaseTextInputView.m +++ b/Libraries/Text/TextInput/RCTBaseTextInputView.m @@ -419,7 +419,7 @@ - (void)setCustomInputAccessoryViewWithNativeID:(NSString *)nativeID UIView *accessoryView = [strongSelf->_bridge.uiManager viewForNativeID:nativeID withRootTag:rootView.reactTag]; if (accessoryView && [accessoryView isKindOfClass:[RCTInputAccessoryView class]]) { - strongSelf.backedTextInputView.inputAccessoryView = ((RCTInputAccessoryView *)accessoryView).content.inputAccessoryView; + strongSelf.backedTextInputView.inputAccessoryView = ((RCTInputAccessoryView *)accessoryView).inputAccessoryView; [strongSelf reloadInputViewsIfNecessary]; } } diff --git a/Libraries/Text/TextInput/RCTInputAccessoryView.h b/Libraries/Text/TextInput/RCTInputAccessoryView.h index b2517534baf3bb..207203fc22321e 100644 --- a/Libraries/Text/TextInput/RCTInputAccessoryView.h +++ b/Libraries/Text/TextInput/RCTInputAccessoryView.h @@ -14,6 +14,4 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge; -@property (nonatomic, readonly, strong) RCTInputAccessoryViewContent *content; - @end diff --git a/Libraries/Text/TextInput/RCTInputAccessoryView.m b/Libraries/Text/TextInput/RCTInputAccessoryView.m index a1902a80ea5fd4..1f66e473966c06 100644 --- a/Libraries/Text/TextInput/RCTInputAccessoryView.m +++ b/Libraries/Text/TextInput/RCTInputAccessoryView.m @@ -13,56 +13,66 @@ #import "RCTInputAccessoryViewContent.h" +@interface RCTInputAccessoryView() + +// Overriding `inputAccessoryView` to `readwrite`. +@property (nonatomic, readwrite, retain) UIView *inputAccessoryView; + +@end + @implementation RCTInputAccessoryView { - BOOL _contentShouldBeFirstResponder; + BOOL _shouldBecomeFirstResponder; } - (instancetype)initWithBridge:(RCTBridge *)bridge { if (self = [super init]) { - _content = [RCTInputAccessoryViewContent new]; + _inputAccessoryView = [RCTInputAccessoryViewContent new]; RCTTouchHandler *const touchHandler = [[RCTTouchHandler alloc] initWithBridge:bridge]; - [touchHandler attachToView:_content.inputAccessoryView]; - [self addSubview:_content]; + [touchHandler attachToView:_inputAccessoryView]; } return self; } +- (BOOL)canBecomeFirstResponder +{ + return true; +} + - (void)reactSetFrame:(CGRect)frame { - [_content.inputAccessoryView setFrame:frame]; - [_content.contentView setFrame:frame]; + [_inputAccessoryView setFrame:frame]; - if (_contentShouldBeFirstResponder) { - _contentShouldBeFirstResponder = NO; - [_content becomeFirstResponder]; + if (_shouldBecomeFirstResponder) { + _shouldBecomeFirstResponder = NO; + [self becomeFirstResponder]; } } - (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)index { [super insertReactSubview:subview atIndex:index]; - [_content insertReactSubview:subview atIndex:index]; + [_inputAccessoryView insertReactSubview:subview atIndex:index]; } - (void)removeReactSubview:(UIView *)subview { [super removeReactSubview:subview]; - [_content removeReactSubview:subview]; + [_inputAccessoryView removeReactSubview:subview]; } - (void)didUpdateReactSubviews { - // Do nothing, as subviews are managed by `insertReactSubview:atIndex:` + // Do nothing, as subviews are managed by `insertReactSubview:atIndex:`. } - (void)didSetProps:(NSArray *)changedProps { // If the accessory view is not linked to a text input via nativeID, assume it is - // a standalone component that should get focus whenever it is rendered + // a standalone component that should get focus whenever it is rendered. if (![changedProps containsObject:@"nativeID"] && !self.nativeID) { - _contentShouldBeFirstResponder = YES; + _shouldBecomeFirstResponder = YES; } } diff --git a/Libraries/Text/TextInput/RCTInputAccessoryViewContent.h b/Libraries/Text/TextInput/RCTInputAccessoryViewContent.h index 7c24d010e2d270..7dca711a648d83 100644 --- a/Libraries/Text/TextInput/RCTInputAccessoryViewContent.h +++ b/Libraries/Text/TextInput/RCTInputAccessoryViewContent.h @@ -9,6 +9,4 @@ @interface RCTInputAccessoryViewContent : UIView -@property (nonatomic, readwrite, retain) UIView *contentView; - @end diff --git a/Libraries/Text/TextInput/RCTInputAccessoryViewContent.m b/Libraries/Text/TextInput/RCTInputAccessoryViewContent.m index 3fb7fca715c608..73ec648ad8e128 100644 --- a/Libraries/Text/TextInput/RCTInputAccessoryViewContent.m +++ b/Libraries/Text/TextInput/RCTInputAccessoryViewContent.m @@ -9,65 +9,59 @@ #import -@interface RCTInputAccessoryViewContent() - -// Overriding `inputAccessoryView` to `readwrite`. -@property (nonatomic, readwrite, retain) UIView *inputAccessoryView; - -@end - @implementation RCTInputAccessoryViewContent +{ + UIView *_safeAreaContainer; +} -- (BOOL)canBecomeFirstResponder +- (instancetype)init { - return true; + if (self = [super init]) { + _safeAreaContainer = [UIView new]; + [self addSubview:_safeAreaContainer]; + } + return self; } -- (BOOL)becomeFirstResponder +- (void)didMoveToSuperview { - const BOOL becameFirstResponder = [super becomeFirstResponder]; - #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */ - // Avoiding the home pill and notch (landscape mode) on iphoneX. - if (becameFirstResponder) { - if (@available(iOS 11.0, *)) { - [_contentView.bottomAnchor - constraintLessThanOrEqualToSystemSpacingBelowAnchor:_contentView.window.safeAreaLayoutGuide.bottomAnchor +#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */ + // Avoid the home pill (in portrait mode) and notch (in landscape mode) on iPhoneX. + if (@available(iOS 11.0, *)) { + if (self.window) { + [_safeAreaContainer.bottomAnchor + constraintLessThanOrEqualToSystemSpacingBelowAnchor:self.window.safeAreaLayoutGuide.bottomAnchor multiplier:1.0f].active = YES; - [_contentView.leftAnchor - constraintLessThanOrEqualToSystemSpacingAfterAnchor:_contentView.window.safeAreaLayoutGuide.leftAnchor + [_safeAreaContainer.leftAnchor + constraintGreaterThanOrEqualToSystemSpacingAfterAnchor:self.window.safeAreaLayoutGuide.leftAnchor multiplier:1.0f].active = YES; - [_contentView.rightAnchor - constraintLessThanOrEqualToSystemSpacingAfterAnchor:_contentView.window.safeAreaLayoutGuide.rightAnchor + [_safeAreaContainer.rightAnchor + constraintLessThanOrEqualToSystemSpacingAfterAnchor:self.window.safeAreaLayoutGuide.rightAnchor multiplier:1.0f].active = YES; } } - #endif +#endif - return becameFirstResponder; } -- (UIView *)inputAccessoryView +- (void)setFrame:(CGRect)frame { - if (!_inputAccessoryView) { - _inputAccessoryView = [UIView new]; - _contentView = [UIView new]; - [_inputAccessoryView addSubview:_contentView]; - } - return _inputAccessoryView; + [super setFrame:frame]; + [_safeAreaContainer setFrame:frame]; } - (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)index { [super insertReactSubview:subview atIndex:index]; - [_contentView insertSubview:subview atIndex:index]; + [_safeAreaContainer insertSubview:subview atIndex:index]; } - (void)removeReactSubview:(UIView *)subview { [super removeReactSubview:subview]; [subview removeFromSuperview]; - if ([[_inputAccessoryView subviews] count] == 0 && [self isFirstResponder]) { + if ([[_safeAreaContainer subviews] count] == 0 && [self isFirstResponder]) { [self resignFirstResponder]; } } diff --git a/Libraries/Text/TextInput/RCTInputAccessoryViewManager.m b/Libraries/Text/TextInput/RCTInputAccessoryViewManager.m index b293889eb6de84..aeeff835e844b4 100644 --- a/Libraries/Text/TextInput/RCTInputAccessoryViewManager.m +++ b/Libraries/Text/TextInput/RCTInputAccessoryViewManager.m @@ -23,6 +23,6 @@ - (UIView *)view return [[RCTInputAccessoryView alloc] initWithBridge:self.bridge]; } -RCT_REMAP_VIEW_PROPERTY(backgroundColor, content.inputAccessoryView.backgroundColor, UIColor) +RCT_REMAP_VIEW_PROPERTY(backgroundColor, inputAccessoryView.backgroundColor, UIColor) @end From ca898f4367083e0943603521a41c48dec403e6c9 Mon Sep 17 00:00:00 2001 From: Teddy Martin Date: Tue, 13 Mar 2018 15:17:28 -0700 Subject: [PATCH 0007/1109] Add docs for Swift usage to RCTBridgeModule.h Summary: Clarifies how to get a reference to RCTBridge from a Swift RCTBridgeModule. In writing native modules for Swift, I have run into issues where the documentation applies only to Objective-C and does not supply adequate information for how one might accomplish something in Swift. This is a good example, where the `synthesize` method simply does not apply to Swift code. [IOS][ENHANCEMENT][Base/RCTBridgeModule.h] Add documentation for Swift usage. Closes https://github.com/facebook/react-native/pull/18231 Differential Revision: D7262850 Pulled By: hramos fbshipit-source-id: c6babb3edd786be8571eb49258d594f2fb99141d --- React/Base/RCTBridgeModule.h | 1 + 1 file changed, 1 insertion(+) diff --git a/React/Base/RCTBridgeModule.h b/React/Base/RCTBridgeModule.h index 07116bb80ef950..75908a1b0f797d 100644 --- a/React/Base/RCTBridgeModule.h +++ b/React/Base/RCTBridgeModule.h @@ -83,6 +83,7 @@ RCT_EXTERN void RCTRegisterModule(Class); \ * to bridge features, such as sending events or making JS calls. This * will be set automatically by the bridge when it initializes the module. * To implement this in your module, just add `@synthesize bridge = _bridge;` + * If using Swift, add `@objc var bridge: RCTBridge!` to your module. */ @property (nonatomic, weak, readonly) RCTBridge *bridge; From 41acb0a75b1ed5b4cf2feb74c64113a06a284e85 Mon Sep 17 00:00:00 2001 From: Naris Siamwalla Date: Tue, 13 Mar 2018 16:16:27 -0700 Subject: [PATCH 0008/1109] Fix clang-6 compile error (virtual destructor) Reviewed By: smeenai Differential Revision: D7264312 fbshipit-source-id: f0567452127ceba6cfa13d05bb2a00a5af7aac05 --- React/Fabric/RCTFabricPlatformUIOperationManager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/React/Fabric/RCTFabricPlatformUIOperationManager.h b/React/Fabric/RCTFabricPlatformUIOperationManager.h index 2e9df3c770445c..2043959760eae1 100644 --- a/React/Fabric/RCTFabricPlatformUIOperationManager.h +++ b/React/Fabric/RCTFabricPlatformUIOperationManager.h @@ -24,7 +24,7 @@ namespace react { class RCTFabricPlatformUIOperationManagerConnector : public IFabricPlatformUIOperationManager { public: RCTFabricPlatformUIOperationManagerConnector(); - ~RCTFabricPlatformUIOperationManagerConnector(); + virtual ~RCTFabricPlatformUIOperationManagerConnector(); void performUIOperation(); From 9737774b965d1b4e875f697b9c004fdcbafe7698 Mon Sep 17 00:00:00 2001 From: Ram N Date: Tue, 13 Mar 2018 17:56:33 -0700 Subject: [PATCH 0009/1109] Fix crash in Sapienz bot for Interpolator type Reviewed By: mdvacca Differential Revision: D7252818 fbshipit-source-id: 30c585a2e6f6c2d7a7e7013c26c6228d8ef29aa6 --- .../layoutanimation/AbstractLayoutAnimation.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AbstractLayoutAnimation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AbstractLayoutAnimation.java index 1ad6ccab3946d5..67e7f19d2c3ff6 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AbstractLayoutAnimation.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AbstractLayoutAnimation.java @@ -2,7 +2,6 @@ package com.facebook.react.uimanager.layoutanimation; -import android.os.Build; import android.view.View; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.AccelerateInterpolator; @@ -99,14 +98,11 @@ public void initializeFromConfig(ReadableMap data, int globalDuration) { } private static Interpolator getInterpolator(InterpolatorType type, ReadableMap params) { - Interpolator interpolator = null; + Interpolator interpolator; if (type.equals(InterpolatorType.SPRING)) { interpolator = new SimpleSpringInterpolator(SimpleSpringInterpolator.getSpringDamping(params)); } else { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { - // Conversion from BaseInterpolator to Interpolator is only possible on this Android versions - interpolator = INTERPOLATOR.get(type); - } + interpolator = INTERPOLATOR.get(type); } if (interpolator == null) { throw new IllegalArgumentException("Missing interpolator for type : " + type); From db061ea8c7b78d7e9df4a450c9e7a24d9b2382b4 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Tue, 13 Mar 2018 17:57:36 -0700 Subject: [PATCH 0010/1109] Don't wrap ListEmptyComponent in an extra view Summary: A common UI pattern for list empty states is some text/images centered inside the visible part of the list. This is pretty hard to do currently because we wrap ListEmptyComponent with an extra view with no way to style it so we cannot just use `flex: 1` to make it fill the available space. - Added an example of ListEmptyComponent in the FlatList example in RNTester Before (no way to make ListEmptyComponent fill the space): screen shot 2018-03-05 at 5 24 15 pm After: screen shot 2018-03-05 at 5 09 20 pm - Tested some edge cases like returning null from the ListEmptyComponent - Tested in an app that uses FlatList + ListEmptyComponent [GENERAL] [MINOR] [VirtualizedList] - Don't wrap ListEmptyComponent in an extra view Closes https://github.com/facebook/react-native/pull/18206 Differential Revision: D7266274 Pulled By: sahrens fbshipit-source-id: 4636d2418474a4c86ac63e5e18a9afc391a518c5 --- Libraries/Lists/VirtualizedList.js | 26 ++++++++++--------- .../VirtualizedList-test.js.snap | 7 +---- RNTester/js/FlatListExample.js | 9 +++++-- RNTester/js/ListExampleShared.js | 16 ++++++++++++ 4 files changed, 38 insertions(+), 20 deletions(-) diff --git a/Libraries/Lists/VirtualizedList.js b/Libraries/Lists/VirtualizedList.js index 58fe055a373cde..8ee3da2ea4f451 100644 --- a/Libraries/Lists/VirtualizedList.js +++ b/Libraries/Lists/VirtualizedList.js @@ -850,23 +850,25 @@ class VirtualizedList extends React.PureComponent { ); } } else if (ListEmptyComponent) { - const element = React.isValidElement(ListEmptyComponent) ? ( + const element: React.Element = (React.isValidElement( + ListEmptyComponent, + ) ? ( ListEmptyComponent ) : ( // $FlowFixMe - ); + ): any); cells.push( - - {/* - Flow doesn't know this is a React.Element and not a React.Component - $FlowFixMe https://fburl.com/b9xmtm09 - */} - {element} - , + React.cloneElement(element, { + key: '$empty', + onLayout: event => { + this._onLayoutEmpty(event); + if (element.props.onLayout) { + element.props.onLayout(event); + } + }, + style: [element.props.style, inversionStyle], + }), ); } if (ListFooterComponent) { diff --git a/Libraries/Lists/__tests__/__snapshots__/VirtualizedList-test.js.snap b/Libraries/Lists/__tests__/__snapshots__/VirtualizedList-test.js.snap index 7ebe23df231878..9cf5c2d9ea29a8 100644 --- a/Libraries/Lists/__tests__/__snapshots__/VirtualizedList-test.js.snap +++ b/Libraries/Lists/__tests__/__snapshots__/VirtualizedList-test.js.snap @@ -683,12 +683,7 @@ exports[`VirtualizedList renders empty list with empty component 1`] = ` >
- - - + { fixedHeight: true, logViewable: false, virtualized: true, + empty: false, }; _onChangeFilterText = (filterText) => { @@ -109,8 +111,9 @@ class FlatListExample extends React.PureComponent<{}, $FlowFixMeState> { {renderSmallSwitchOption(this, 'virtualized')} {renderSmallSwitchOption(this, 'horizontal')} {renderSmallSwitchOption(this, 'fixedHeight')} - {renderSmallSwitchOption(this, 'logViewable')} + {renderSmallSwitchOption(this, 'log')} {renderSmallSwitchOption(this, 'inverted')} + {renderSmallSwitchOption(this, 'empty')} {renderSmallSwitchOption(this, 'debug')} @@ -120,7 +123,8 @@ class FlatListExample extends React.PureComponent<{}, $FlowFixMeState> { ItemSeparatorComponent={ItemSeparatorComponent} ListHeaderComponent={} ListFooterComponent={FooterComponent} - data={filteredData} + ListEmptyComponent={ListEmptyComponent} + data={this.state.empty ? [] : filteredData} debug={this.state.debug} disableVirtualization={!this.state.virtualized} getItemLayout={this.state.fixedHeight ? @@ -210,6 +214,7 @@ const styles = StyleSheet.create({ }, list: { backgroundColor: 'white', + flexGrow: 1, }, options: { flexDirection: 'row', diff --git a/RNTester/js/ListExampleShared.js b/RNTester/js/ListExampleShared.js index c5eef14dbac902..75ef6bb4b65cd4 100644 --- a/RNTester/js/ListExampleShared.js +++ b/RNTester/js/ListExampleShared.js @@ -117,6 +117,16 @@ class HeaderComponent extends React.PureComponent<{}> { } } +class ListEmptyComponent extends React.PureComponent<{}> { + render() { + return ( + + The list is empty :o + + ); + } +} + class SeparatorComponent extends React.PureComponent<{}> { render() { return ; @@ -240,6 +250,11 @@ const styles = StyleSheet.create({ headerFooterContainer: { backgroundColor: 'rgb(239, 239, 244)', }, + listEmpty: { + alignItems: 'center', + justifyContent: 'center', + flexGrow: 1, + }, horizItem: { alignSelf: 'flex-start', // Necessary for touch highlight }, @@ -317,6 +332,7 @@ const styles = StyleSheet.create({ module.exports = { FooterComponent, HeaderComponent, + ListEmptyComponent, ItemComponent, ItemSeparatorComponent, PlainInput, From 8466db0fd355aea778ff71cfb10c927cfd18a551 Mon Sep 17 00:00:00 2001 From: Sahil Ohri Date: Tue, 13 Mar 2018 19:14:18 -0700 Subject: [PATCH 0011/1109] Revert #17927 Summary: This change is a revert of [#17927](https://github.com/facebook/react-native/pull/17927) pull-request. The pull-request caused an issue with the keyboard covering the text field at the bottom of the scroll view. Reviewed By: shergin Differential Revision: D7246609 fbshipit-source-id: 149f825274c4fa79ab593f1bae3602667d16ddee --- React/Views/ScrollView/RCTScrollView.m | 3 --- 1 file changed, 3 deletions(-) diff --git a/React/Views/ScrollView/RCTScrollView.m b/React/Views/ScrollView/RCTScrollView.m index 6a8f3353942625..f146ba0d2369a0 100644 --- a/React/Views/ScrollView/RCTScrollView.m +++ b/React/Views/ScrollView/RCTScrollView.m @@ -575,9 +575,6 @@ - (void)scrollToOffset:(CGPoint)offset - (void)scrollToOffset:(CGPoint)offset animated:(BOOL)animated { if (!CGPointEqualToPoint(_scrollView.contentOffset, offset)) { - CGFloat maxOffsetX = _scrollView.contentSize.width - _scrollView.bounds.size.width + _scrollView.contentInset.right; - CGFloat maxOffsetY = _scrollView.contentSize.height - _scrollView.bounds.size.height + _scrollView.contentInset.bottom; - offset = CGPointMake(MAX(0, MIN(maxOffsetX, offset.x)), MAX(0, MIN(maxOffsetY, offset.y))); // Ensure at least one scroll event will fire _allowNextScrollNoMatterWhat = YES; [_scrollView setContentOffset:offset animated:animated]; From af4a36337de8befbf26017a9d0773a18d300477d Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Wed, 14 Mar 2018 04:17:05 -0700 Subject: [PATCH 0012/1109] Remove the usage of YGUndefined in the default values of Border in YGStyle Reviewed By: emilsjolander Differential Revision: D7195115 fbshipit-source-id: e635cf55ac94d8a90caef6cafce281579da2cbfc --- ReactCommon/yoga/yoga/Utils.cpp | 4 ++++ ReactCommon/yoga/yoga/Utils.h | 3 +++ ReactCommon/yoga/yoga/YGStyle.cpp | 2 +- ReactCommon/yoga/yoga/Yoga.cpp | 30 +++++++++++++++++++++++++++++- ReactCommon/yoga/yoga/Yoga.h | 5 +++++ 5 files changed, 42 insertions(+), 2 deletions(-) diff --git a/ReactCommon/yoga/yoga/Utils.cpp b/ReactCommon/yoga/yoga/Utils.cpp index 412845723b22b1..5ca834c84b5fb5 100644 --- a/ReactCommon/yoga/yoga/Utils.cpp +++ b/ReactCommon/yoga/yoga/Utils.cpp @@ -49,3 +49,7 @@ bool YGFloatsEqual(const float a, const float b) { } return YGFloatIsUndefined(a) && YGFloatIsUndefined(b); } + +float YGFloatSanitize(const float& val) { + return YGFloatIsUndefined(val) ? 0 : val; +} diff --git a/ReactCommon/yoga/yoga/Utils.h b/ReactCommon/yoga/yoga/Utils.h index 6ebeb86fc6b2b5..44cfd300f1c466 100644 --- a/ReactCommon/yoga/yoga/Utils.h +++ b/ReactCommon/yoga/yoga/Utils.h @@ -86,6 +86,9 @@ bool YGFloatArrayEqual( return areEqual; } +// This function returns 0 if YGFloatIsUndefined(val) is true and val otherwise +float YGFloatSanitize(const float& val); + YGFlexDirection YGFlexDirectionCross( const YGFlexDirection flexDirection, const YGDirection direction); diff --git a/ReactCommon/yoga/yoga/YGStyle.cpp b/ReactCommon/yoga/yoga/YGStyle.cpp index f3bc16fe1cc21b..c4ccf7770e98fc 100644 --- a/ReactCommon/yoga/yoga/YGStyle.cpp +++ b/ReactCommon/yoga/yoga/YGStyle.cpp @@ -7,7 +7,7 @@ #include "YGStyle.h" -const YGValue kYGValueUndefined = {YGUndefined, YGUnitUndefined}; +const YGValue kYGValueUndefined = {0, YGUnitUndefined}; const YGValue kYGValueAuto = {YGUndefined, YGUnitAuto}; diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index 41f89e877e4caa..61ceee7750fa70 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -760,7 +760,35 @@ YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Position, position, position); YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Margin, margin, margin); YG_NODE_STYLE_EDGE_PROPERTY_UNIT_AUTO_IMPL(YGValue, Margin, margin); YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Padding, padding, padding); -YG_NODE_STYLE_EDGE_PROPERTY_IMPL(float, Border, border, border); + +// TODO: Change the API to accept YGFloatOptional. +void YGNodeStyleSetBorder( + const YGNodeRef node, + const YGEdge edge, + const float border) { + YGValue value = { + .value = YGFloatSanitize(border), + .unit = YGFloatIsUndefined(border) ? YGUnitUndefined : YGUnitPoint, + }; + if ((node->getStyle().border[edge].value != value.value && + value.unit != YGUnitUndefined) || + node->getStyle().border[edge].unit != value.unit) { + YGStyle style = node->getStyle(); + style.border[edge] = value; + node->setStyle(style); + node->markDirtyAndPropogate(); + } +} + +float YGNodeStyleGetBorder(const YGNodeRef node, const YGEdge edge) { + if (node->getStyle().border[edge].unit == YGUnitUndefined) { + // TODO: Rather than returning YGUndefined, change the api to return + // YGFloatOptional. + return YGUndefined; + } + + return node->getStyle().border[edge].value; +} YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(YGValue, Width, width, dimensions[YGDimensionWidth]); YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(YGValue, Height, height, dimensions[YGDimensionHeight]); diff --git a/ReactCommon/yoga/yoga/Yoga.h b/ReactCommon/yoga/yoga/Yoga.h index a632917af859b7..56fe95ff2ec2b8 100644 --- a/ReactCommon/yoga/yoga/Yoga.h +++ b/ReactCommon/yoga/yoga/Yoga.h @@ -42,6 +42,11 @@ typedef struct YGValue { YGUnit unit; } YGValue; +struct YGFloatOptional { + bool isUndefined; + float value; +}; + extern const YGValue YGValueUndefined; extern const YGValue YGValueAuto; From 9f7e70363a36807f0113fb958b0438cc5003a66a Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Wed, 14 Mar 2018 04:17:07 -0700 Subject: [PATCH 0013/1109] Changed the return type of YGResolveValue Reviewed By: emilsjolander Differential Revision: D7195099 fbshipit-source-id: 72c4163cd08691cf6e40df05394cc52e83b0de14 --- ReactCommon/yoga/yoga/Utils.cpp | 4 ++ ReactCommon/yoga/yoga/Utils.h | 17 +++-- ReactCommon/yoga/yoga/YGNode.cpp | 30 ++++----- ReactCommon/yoga/yoga/Yoga.cpp | 106 +++++++++++++++---------------- 4 files changed, 79 insertions(+), 78 deletions(-) diff --git a/ReactCommon/yoga/yoga/Utils.cpp b/ReactCommon/yoga/yoga/Utils.cpp index 5ca834c84b5fb5..c57e5af3fa8233 100644 --- a/ReactCommon/yoga/yoga/Utils.cpp +++ b/ReactCommon/yoga/yoga/Utils.cpp @@ -53,3 +53,7 @@ bool YGFloatsEqual(const float a, const float b) { float YGFloatSanitize(const float& val) { return YGFloatIsUndefined(val) ? 0 : val; } + +float YGUnwrapFloatOptional(const YGFloatOptional& op) { + return op.isUndefined ? YGUndefined : op.value; +} diff --git a/ReactCommon/yoga/yoga/Utils.h b/ReactCommon/yoga/yoga/Utils.h index 44cfd300f1c466..6fbd33a44db466 100644 --- a/ReactCommon/yoga/yoga/Utils.h +++ b/ReactCommon/yoga/yoga/Utils.h @@ -89,6 +89,11 @@ bool YGFloatArrayEqual( // This function returns 0 if YGFloatIsUndefined(val) is true and val otherwise float YGFloatSanitize(const float& val); +// This function unwraps optional and returns YGUndefined if not defined or +// op.value otherwise +// TODO: Get rid off this function +float YGUnwrapFloatOptional(const YGFloatOptional& op); + YGFlexDirection YGFlexDirectionCross( const YGFlexDirection flexDirection, const YGDirection direction); @@ -98,17 +103,17 @@ inline bool YGFlexDirectionIsRow(const YGFlexDirection flexDirection) { flexDirection == YGFlexDirectionRowReverse; } -inline float YGResolveValue(const YGValue value, const float parentSize) { +inline YGFloatOptional YGResolveValue(const YGValue value, const float parentSize) { switch (value.unit) { case YGUnitUndefined: case YGUnitAuto: - return YGUndefined; + return {true, 0}; case YGUnitPoint: - return value.value; + return {false, value.value}; case YGUnitPercent: - return value.value * parentSize * 0.01; + return {false, static_cast(value.value * parentSize * 0.01)}; } - return YGUndefined; + return {true, 0}; } inline bool YGFlexDirectionIsColumn(const YGFlexDirection flexDirection) { @@ -133,5 +138,5 @@ inline YGFlexDirection YGResolveFlexDirection( static inline float YGResolveValueMargin( const YGValue value, const float parentSize) { - return value.unit == YGUnitAuto ? 0 : YGResolveValue(value, parentSize); + return value.unit == YGUnitAuto ? 0 : YGUnwrapFloatOptional(YGResolveValue(value, parentSize)); } diff --git a/ReactCommon/yoga/yoga/YGNode.cpp b/ReactCommon/yoga/yoga/YGNode.cpp index ae7fce26e8ce3a..6b02eeb45429ec 100644 --- a/ReactCommon/yoga/yoga/YGNode.cpp +++ b/ReactCommon/yoga/yoga/YGNode.cpp @@ -92,7 +92,7 @@ float YGNode::getLeadingPosition( const YGValue* leadingPosition = YGComputedEdgeValue(style_.position, YGEdgeStart, &YGValueUndefined); if (leadingPosition->unit != YGUnitUndefined) { - return YGResolveValue(*leadingPosition, axisSize); + return YGUnwrapFloatOptional(YGResolveValue(*leadingPosition, axisSize)); } } @@ -101,7 +101,7 @@ float YGNode::getLeadingPosition( return leadingPosition->unit == YGUnitUndefined ? 0.0f - : YGResolveValue(*leadingPosition, axisSize); + : YGUnwrapFloatOptional(YGResolveValue(*leadingPosition, axisSize)); } float YGNode::getTrailingPosition( @@ -111,7 +111,7 @@ float YGNode::getTrailingPosition( const YGValue* trailingPosition = YGComputedEdgeValue(style_.position, YGEdgeEnd, &YGValueUndefined); if (trailingPosition->unit != YGUnitUndefined) { - return YGResolveValue(*trailingPosition, axisSize); + return YGUnwrapFloatOptional(YGResolveValue(*trailingPosition, axisSize)); } } @@ -120,7 +120,7 @@ float YGNode::getTrailingPosition( return trailingPosition->unit == YGUnitUndefined ? 0.0f - : YGResolveValue(*trailingPosition, axisSize); + : YGUnwrapFloatOptional(YGResolveValue(*trailingPosition, axisSize)); } bool YGNode::isLeadingPositionDefined(const YGFlexDirection axis) { @@ -653,15 +653,14 @@ float YGNode::getLeadingPadding( const float widthSize) { if (YGFlexDirectionIsRow(axis) && style_.padding[YGEdgeStart].unit != YGUnitUndefined && - !YGFloatIsUndefined( - YGResolveValue(style_.padding[YGEdgeStart], widthSize)) && - YGResolveValue(style_.padding[YGEdgeStart], widthSize) > 0.0f) { - return YGResolveValue(style_.padding[YGEdgeStart], widthSize); + !YGResolveValue(style_.padding[YGEdgeStart], widthSize).isUndefined && + YGUnwrapFloatOptional(YGResolveValue(style_.padding[YGEdgeStart], widthSize)) > 0.0f) { + return YGUnwrapFloatOptional(YGResolveValue(style_.padding[YGEdgeStart], widthSize)); } - float resolvedValue = YGResolveValue( + float resolvedValue = YGUnwrapFloatOptional(YGResolveValue( *YGComputedEdgeValue(style_.padding, leading[axis], &YGValueZero), - widthSize); + widthSize)); return YGFloatMax(resolvedValue, 0.0f); } @@ -670,15 +669,14 @@ float YGNode::getTrailingPadding( const float widthSize) { if (YGFlexDirectionIsRow(axis) && style_.padding[YGEdgeEnd].unit != YGUnitUndefined && - !YGFloatIsUndefined( - YGResolveValue(style_.padding[YGEdgeEnd], widthSize)) && - YGResolveValue(style_.padding[YGEdgeEnd], widthSize) >= 0.0f) { - return YGResolveValue(style_.padding[YGEdgeEnd], widthSize); + !YGResolveValue(style_.padding[YGEdgeEnd], widthSize).isUndefined && + YGUnwrapFloatOptional(YGResolveValue(style_.padding[YGEdgeEnd], widthSize)) >= 0.0f) { + return YGUnwrapFloatOptional(YGResolveValue(style_.padding[YGEdgeEnd], widthSize)); } - float resolvedValue = YGResolveValue( + float resolvedValue = YGUnwrapFloatOptional(YGResolveValue( *YGComputedEdgeValue(style_.padding, trailing[axis], &YGValueZero), - widthSize); + widthSize)); return YGFloatMax(resolvedValue, 0.0f); } diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index 61ceee7750fa70..7b4719f3aebaba 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -6,6 +6,7 @@ */ #include "Yoga.h" +#include #include #include #include "Utils.h" @@ -967,15 +968,15 @@ static float YGNodeBoundAxisWithinMinAndMax(const YGNodeRef node, float max = YGUndefined; if (YGFlexDirectionIsColumn(axis)) { - min = YGResolveValue( - node->getStyle().minDimensions[YGDimensionHeight], axisSize); - max = YGResolveValue( - node->getStyle().maxDimensions[YGDimensionHeight], axisSize); + min = YGUnwrapFloatOptional(YGResolveValue( + node->getStyle().minDimensions[YGDimensionHeight], axisSize)); + max = YGUnwrapFloatOptional(YGResolveValue( + node->getStyle().maxDimensions[YGDimensionHeight], axisSize)); } else if (YGFlexDirectionIsRow(axis)) { - min = YGResolveValue( - node->getStyle().minDimensions[YGDimensionWidth], axisSize); - max = YGResolveValue( - node->getStyle().maxDimensions[YGDimensionWidth], axisSize); + min = YGUnwrapFloatOptional(YGResolveValue( + node->getStyle().minDimensions[YGDimensionWidth], axisSize)); + max = YGUnwrapFloatOptional(YGResolveValue( + node->getStyle().maxDimensions[YGDimensionWidth], axisSize)); } float boundValue = value; @@ -1021,8 +1022,8 @@ static void YGConstrainMaxSizeForMode(const YGNodeRef node, YGMeasureMode *mode, float *size) { const float maxSize = - YGResolveValue( - node->getStyle().maxDimensions[dim[axis]], parentAxisSize) + + YGUnwrapFloatOptional(YGResolveValue( + node->getStyle().maxDimensions[dim[axis]], parentAxisSize)) + node->getMarginForAxis(axis, parentWidth); switch (*mode) { case YGMeasureModeExactly: @@ -1060,7 +1061,7 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node, YGMeasureMode childHeightMeasureMode; const float resolvedFlexBasis = - YGResolveValue(child->resolveFlexBasisPtr(), mainAxisParentSize); + YGUnwrapFloatOptional(YGResolveValue(child->resolveFlexBasisPtr(), mainAxisParentSize)); const bool isRowStyleDimDefined = YGNodeIsStyleDimDefined(child, YGFlexDirectionRow, parentWidth); const bool isColumnStyleDimDefined = YGNodeIsStyleDimDefined(child, YGFlexDirectionColumn, parentHeight); @@ -1078,14 +1079,14 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node, } else if (isMainAxisRow && isRowStyleDimDefined) { // The width is definite, so use that as the flex basis. child->setLayoutComputedFlexBasis(YGFloatMax( - YGResolveValue( - child->getResolvedDimension(YGDimensionWidth), parentWidth), + YGUnwrapFloatOptional(YGResolveValue( + child->getResolvedDimension(YGDimensionWidth), parentWidth)), YGNodePaddingAndBorderForAxis(child, YGFlexDirectionRow, parentWidth))); } else if (!isMainAxisRow && isColumnStyleDimDefined) { // The height is definite, so use that as the flex basis. child->setLayoutComputedFlexBasis(YGFloatMax( - YGResolveValue( - child->getResolvedDimension(YGDimensionHeight), parentHeight), + YGUnwrapFloatOptional(YGResolveValue( + child->getResolvedDimension(YGDimensionHeight), parentHeight)), YGNodePaddingAndBorderForAxis( child, YGFlexDirectionColumn, parentWidth))); } else { @@ -1103,15 +1104,15 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node, if (isRowStyleDimDefined) { childWidth = - YGResolveValue( - child->getResolvedDimension(YGDimensionWidth), parentWidth) + + YGUnwrapFloatOptional(YGResolveValue( + child->getResolvedDimension(YGDimensionWidth), parentWidth)) + marginRow; childWidthMeasureMode = YGMeasureModeExactly; } if (isColumnStyleDimDefined) { childHeight = - YGResolveValue( - child->getResolvedDimension(YGDimensionHeight), parentHeight) + + YGUnwrapFloatOptional(YGResolveValue( + child->getResolvedDimension(YGDimensionHeight), parentHeight)) + marginColumn; childHeightMeasureMode = YGMeasureModeExactly; } @@ -1228,7 +1229,7 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, if (YGNodeIsStyleDimDefined(child, YGFlexDirectionRow, width)) { childWidth = - YGResolveValue(child->getResolvedDimension(YGDimensionWidth), width) + + YGUnwrapFloatOptional(YGResolveValue(child->getResolvedDimension(YGDimensionWidth), width)) + marginRow; } else { // If the child doesn't have a specified width, compute the width based @@ -1247,7 +1248,7 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, if (YGNodeIsStyleDimDefined(child, YGFlexDirectionColumn, height)) { childHeight = - YGResolveValue(child->getResolvedDimension(YGDimensionHeight), height) + + YGUnwrapFloatOptional(YGResolveValue(child->getResolvedDimension(YGDimensionHeight), height)) + marginColumn; } else { // If the child doesn't have a specified height, compute the height @@ -1584,15 +1585,14 @@ static float YGNodeCalculateAvailableInnerDim( if (!YGFloatIsUndefined(availableInnerDim)) { // We want to make sure our available height does not violate min and max // constraints - const float minInnerDim = - YGFloatIsUndefined(YGResolveValue( - node->getStyle().minDimensions[dimension], parentDim)) + const YGFloatOptional minDimensionOptional = YGResolveValue(node->getStyle().minDimensions[dimension], parentDim); + const float minInnerDim = minDimensionOptional.isUndefined ? 0.0f - : YGResolveValue(node->getStyle().minDimensions[dimension], parentDim) - - paddingAndBorder; - const float maxInnerDim = - YGResolveValue(node->getStyle().maxDimensions[dimension], parentDim) - - paddingAndBorder; + : minDimensionOptional.value - paddingAndBorder; + + const YGFloatOptional maxDimensionOptional = YGResolveValue(node->getStyle().maxDimensions[dimension], parentDim) ; + + const float maxInnerDim = maxDimensionOptional.isUndefined ? FLT_MAX : maxDimensionOptional.value - paddingAndBorder; availableInnerDim = YGFloatMax(YGFloatMin(availableInnerDim, maxInnerDim), minInnerDim); } @@ -1881,9 +1881,9 @@ static float YGDistributeFreeSpaceSecondPass( : YGMeasureModeAtMost; } else { childCrossSize = - YGResolveValue( + YGUnwrapFloatOptional(YGResolveValue( currentRelativeChild->getResolvedDimension(dim[crossAxis]), - availableInnerCrossDim) + + availableInnerCrossDim)) + marginCross; const bool isLoosePercentageMeasurement = currentRelativeChild->getResolvedDimension(dim[crossAxis]).unit == @@ -2124,12 +2124,11 @@ static void YGJustifyMainAxis( if (measureModeMainDim == YGMeasureModeAtMost && collectedFlexItemsValues.remainingFreeSpace > 0) { if (style.minDimensions[dim[mainAxis]].unit != YGUnitUndefined && - !YGFloatIsUndefined(YGResolveValue( - style.minDimensions[dim[mainAxis]], mainAxisParentSize))) { + !YGResolveValue(style.minDimensions[dim[mainAxis]], mainAxisParentSize).isUndefined) { collectedFlexItemsValues.remainingFreeSpace = YGFloatMax( 0, - YGResolveValue( - style.minDimensions[dim[mainAxis]], mainAxisParentSize) - + YGUnwrapFloatOptional(YGResolveValue( + style.minDimensions[dim[mainAxis]], mainAxisParentSize)) - (availableInnerMainDim - collectedFlexItemsValues.remainingFreeSpace)); } else { @@ -2487,20 +2486,17 @@ static void YGNodelayoutImpl(const YGNodeRef node, node->getMarginForAxis(YGFlexDirectionColumn, parentWidth); const float minInnerWidth = - YGResolveValue( - node->getStyle().minDimensions[YGDimensionWidth], parentWidth) - + YGUnwrapFloatOptional(YGResolveValue(node->getStyle().minDimensions[YGDimensionWidth], parentWidth)) - paddingAndBorderAxisRow; const float maxInnerWidth = - YGResolveValue( - node->getStyle().maxDimensions[YGDimensionWidth], parentWidth) - + YGUnwrapFloatOptional(YGResolveValue(node->getStyle().maxDimensions[YGDimensionWidth], parentWidth)) - paddingAndBorderAxisRow; const float minInnerHeight = - YGResolveValue( - node->getStyle().minDimensions[YGDimensionHeight], parentHeight) - + YGUnwrapFloatOptional(YGResolveValue(node->getStyle().minDimensions[YGDimensionHeight], parentHeight)) - paddingAndBorderAxisColumn; const float maxInnerHeight = - YGResolveValue( - node->getStyle().maxDimensions[YGDimensionHeight], parentHeight) - + YGUnwrapFloatOptional(YGResolveValue( + node->getStyle().maxDimensions[YGDimensionHeight], parentHeight)) - paddingAndBorderAxisColumn; const float minInnerMainDim = isMainAxisRow ? minInnerWidth : minInnerHeight; @@ -3629,15 +3625,15 @@ void YGNodeCalculateLayout( YGMeasureMode widthMeasureMode = YGMeasureModeUndefined; if (YGNodeIsStyleDimDefined(node, YGFlexDirectionRow, parentWidth)) { width = - YGResolveValue( - node->getResolvedDimension(dim[YGFlexDirectionRow]), parentWidth) + + YGUnwrapFloatOptional(YGResolveValue( + node->getResolvedDimension(dim[YGFlexDirectionRow]), parentWidth)) + node->getMarginForAxis(YGFlexDirectionRow, parentWidth); widthMeasureMode = YGMeasureModeExactly; - } else if (!YGFloatIsUndefined(YGResolveValue( + } else if (!YGResolveValue( node->getStyle().maxDimensions[YGDimensionWidth], - parentWidth))) { - width = YGResolveValue( - node->getStyle().maxDimensions[YGDimensionWidth], parentWidth); + parentWidth).isUndefined) { + width = YGUnwrapFloatOptional(YGResolveValue( + node->getStyle().maxDimensions[YGDimensionWidth], parentWidth)); widthMeasureMode = YGMeasureModeAtMost; } else { width = parentWidth; @@ -3648,16 +3644,14 @@ void YGNodeCalculateLayout( float height = YGUndefined; YGMeasureMode heightMeasureMode = YGMeasureModeUndefined; if (YGNodeIsStyleDimDefined(node, YGFlexDirectionColumn, parentHeight)) { - height = YGResolveValue( + height = YGUnwrapFloatOptional(YGResolveValue( node->getResolvedDimension(dim[YGFlexDirectionColumn]), - parentHeight) + + parentHeight)) + node->getMarginForAxis(YGFlexDirectionColumn, parentWidth); heightMeasureMode = YGMeasureModeExactly; - } else if (!YGFloatIsUndefined(YGResolveValue( - node->getStyle().maxDimensions[YGDimensionHeight], - parentHeight))) { - height = YGResolveValue( - node->getStyle().maxDimensions[YGDimensionHeight], parentHeight); + } else if (!YGResolveValue(node->getStyle().maxDimensions[YGDimensionHeight], + parentHeight).isUndefined) { + height = YGUnwrapFloatOptional(YGResolveValue(node->getStyle().maxDimensions[YGDimensionHeight], parentHeight)); heightMeasureMode = YGMeasureModeAtMost; } else { height = parentHeight; From 5b3d59598a27bb200c06e7df3105420eb1ffd950 Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Wed, 14 Mar 2018 04:17:09 -0700 Subject: [PATCH 0014/1109] Change the type of flex to YGFloatOptional Reviewed By: emilsjolander Differential Revision: D7211327 fbshipit-source-id: 0d979b6ba00317317b98bbc6e63979c7f1feb2da --- ReactCommon/yoga/yoga/Utils.cpp | 6 ++++++ ReactCommon/yoga/yoga/Utils.h | 6 ++++++ ReactCommon/yoga/yoga/YGNode.cpp | 12 ++++++------ ReactCommon/yoga/yoga/YGNodePrint.cpp | 11 ++++++++++- ReactCommon/yoga/yoga/YGStyle.cpp | 12 +++++++++--- ReactCommon/yoga/yoga/YGStyle.h | 2 +- ReactCommon/yoga/yoga/Yoga.cpp | 27 +++++++++++++++++++++++---- ReactCommon/yoga/yoga/Yoga.h | 1 - 8 files changed, 61 insertions(+), 16 deletions(-) diff --git a/ReactCommon/yoga/yoga/Utils.cpp b/ReactCommon/yoga/yoga/Utils.cpp index c57e5af3fa8233..8c6e91cce6ee82 100644 --- a/ReactCommon/yoga/yoga/Utils.cpp +++ b/ReactCommon/yoga/yoga/Utils.cpp @@ -57,3 +57,9 @@ float YGFloatSanitize(const float& val) { float YGUnwrapFloatOptional(const YGFloatOptional& op) { return op.isUndefined ? YGUndefined : op.value; } + +bool YGFloatOptionalFloatEquals( + const YGFloatOptional& optional, + const float& val) { + return YGUnwrapFloatOptional(optional) == val; +} diff --git a/ReactCommon/yoga/yoga/Utils.h b/ReactCommon/yoga/yoga/Utils.h index 6fbd33a44db466..311030e23f0c42 100644 --- a/ReactCommon/yoga/yoga/Utils.h +++ b/ReactCommon/yoga/yoga/Utils.h @@ -94,6 +94,12 @@ float YGFloatSanitize(const float& val); // TODO: Get rid off this function float YGUnwrapFloatOptional(const YGFloatOptional& op); +// This function returns true if val and optional both are undefined or if val +// and optional.val is true, otherwise its false. +bool YGFloatOptionalFloatEquals( + const YGFloatOptional& optional, + const float& val); + YGFlexDirection YGFlexDirectionCross( const YGFlexDirection flexDirection, const YGDirection direction); diff --git a/ReactCommon/yoga/yoga/YGNode.cpp b/ReactCommon/yoga/yoga/YGNode.cpp index 6b02eeb45429ec..e7b1472aaec680 100644 --- a/ReactCommon/yoga/yoga/YGNode.cpp +++ b/ReactCommon/yoga/yoga/YGNode.cpp @@ -500,7 +500,7 @@ YGValue YGNode::resolveFlexBasisPtr() const { if (flexBasis.unit != YGUnitAuto && flexBasis.unit != YGUnitUndefined) { return flexBasis; } - if (!YGFloatIsUndefined(style_.flex) && style_.flex > 0.0f) { + if (!style_.flex.isUndefined && style_.flex.value > 0.0f) { return config_->useWebDefaults ? YGValueAuto : YGValueZero; } return YGValueAuto; @@ -595,8 +595,8 @@ float YGNode::resolveFlexGrow() { if (!YGFloatIsUndefined(style_.flexGrow)) { return style_.flexGrow; } - if (!YGFloatIsUndefined(style_.flex) && style_.flex > 0.0f) { - return style_.flex; + if (!style_.flex.isUndefined && style_.flex.value > 0.0f) { + return style_.flex.value; } return kDefaultFlexGrow; } @@ -608,9 +608,9 @@ float YGNode::resolveFlexShrink() { if (!YGFloatIsUndefined(style_.flexShrink)) { return style_.flexShrink; } - if (!config_->useWebDefaults && !YGFloatIsUndefined(style_.flex) && - style_.flex < 0.0f) { - return -style_.flex; + if (!config_->useWebDefaults && !style_.flex.isUndefined && + style_.flex.value < 0.0f) { + return -style_.flex.value; } return config_->useWebDefaults ? kWebDefaultFlexShrink : kDefaultFlexShrink; } diff --git a/ReactCommon/yoga/yoga/YGNodePrint.cpp b/ReactCommon/yoga/yoga/YGNodePrint.cpp index 395fe1819ad067..2a7a11df8c7c04 100644 --- a/ReactCommon/yoga/yoga/YGNodePrint.cpp +++ b/ReactCommon/yoga/yoga/YGNodePrint.cpp @@ -39,6 +39,15 @@ static void appendFormatedString(string* str, const char* fmt, ...) { str->append(result); } +static void appendFloatOptionalIfDefined( + string* base, + const string key, + const YGFloatOptional num) { + if (!num.isUndefined) { + appendFormatedString(base, "%s: %g; ", key.c_str(), num.value); + } +} + static void appendFloatIfNotUndefined(string* base, const string key, const float num) { if (!YGFloatIsUndefined(num)) { @@ -155,7 +164,7 @@ void YGNodeToString( appendFloatIfNotUndefined(str, "flex-grow", node->getStyle().flexGrow); appendFloatIfNotUndefined(str, "flex-shrink", node->getStyle().flexShrink); appendNumberIfNotAuto(str, "flex-basis", node->getStyle().flexBasis); - appendFloatIfNotUndefined(str, "flex", node->getStyle().flex); + appendFloatOptionalIfDefined(str, "flex", node->getStyle().flex); if (node->getStyle().flexWrap != YGNode().getStyle().flexWrap) { appendFormatedString( diff --git a/ReactCommon/yoga/yoga/YGStyle.cpp b/ReactCommon/yoga/yoga/YGStyle.cpp index c4ccf7770e98fc..2ac3da93e12342 100644 --- a/ReactCommon/yoga/yoga/YGStyle.cpp +++ b/ReactCommon/yoga/yoga/YGStyle.cpp @@ -7,6 +7,9 @@ #include "YGStyle.h" +#define YGFloatOptionalUndefined \ + { true, 0 } + const YGValue kYGValueUndefined = {0, YGUnitUndefined}; const YGValue kYGValueAuto = {YGUndefined, YGUnitAuto}; @@ -39,7 +42,7 @@ YGStyle::YGStyle() flexWrap(YGWrapNoWrap), overflow(YGOverflowVisible), display(YGDisplayFlex), - flex(YGUndefined), + flex(YGFloatOptionalUndefined), flexGrow(YGUndefined), flexShrink(YGUndefined), flexBasis(kYGValueAuto), @@ -69,8 +72,11 @@ bool YGStyle::operator==(const YGStyle& style) { YGValueArrayEqual(minDimensions, style.minDimensions) && YGValueArrayEqual(maxDimensions, style.maxDimensions); - if (!(YGFloatIsUndefined(flex) && YGFloatIsUndefined(style.flex))) { - areNonFloatValuesEqual = areNonFloatValuesEqual && flex == style.flex; + areNonFloatValuesEqual = + areNonFloatValuesEqual && flex.isUndefined == style.flex.isUndefined; + if (areNonFloatValuesEqual && !flex.isUndefined && !style.flex.isUndefined) { + areNonFloatValuesEqual = + areNonFloatValuesEqual && flex.value == style.flex.value; } if (!(YGFloatIsUndefined(flexGrow) && YGFloatIsUndefined(style.flexGrow))) { diff --git a/ReactCommon/yoga/yoga/YGStyle.h b/ReactCommon/yoga/yoga/YGStyle.h index 74b9d6e0baa367..99e1f18cf3fdc4 100644 --- a/ReactCommon/yoga/yoga/YGStyle.h +++ b/ReactCommon/yoga/yoga/YGStyle.h @@ -20,7 +20,7 @@ struct YGStyle { YGWrap flexWrap; YGOverflow overflow; YGDisplay display; - float flex; + YGFloatOptional flex; float flexGrow; float flexShrink; YGValue flexBasis; diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index 7b4719f3aebaba..bc80a63679b2e7 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -752,7 +752,26 @@ YG_NODE_STYLE_PROPERTY_IMPL(YGWrap, FlexWrap, flexWrap, flexWrap); YG_NODE_STYLE_PROPERTY_IMPL(YGOverflow, Overflow, overflow, overflow); YG_NODE_STYLE_PROPERTY_IMPL(YGDisplay, Display, display, display); -YG_NODE_STYLE_PROPERTY_IMPL(float, Flex, flex, flex); +// TODO(T26792433): Change the API to accept YGFloatOptional. +void YGNodeStyleSetFlex(const YGNodeRef node, const float flex) { + if (!YGFloatOptionalFloatEquals(node->getStyle().flex, flex)) { + YGStyle style = node->getStyle(); + if (YGFloatIsUndefined(flex)) { + style.flex = {true, 0}; + } else { + style.flex = {false, flex}; + } + node->setStyle(style); + node->markDirtyAndPropogate(); + } +} + +// TODO(T26792433): Change the API to accept YGFloatOptional. +float YGNodeStyleGetFlex(const YGNodeRef node) { + return node->getStyle().flex.isUndefined ? YGUndefined + : node->getStyle().flex.value; +} + YG_NODE_STYLE_PROPERTY_SETTER_IMPL(float, FlexGrow, flexGrow, flexGrow); YG_NODE_STYLE_PROPERTY_SETTER_IMPL(float, FlexShrink, flexShrink, flexShrink); YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(YGValue, FlexBasis, flexBasis, flexBasis); @@ -762,7 +781,7 @@ YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Margin, margin, margin); YG_NODE_STYLE_EDGE_PROPERTY_UNIT_AUTO_IMPL(YGValue, Margin, margin); YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Padding, padding, padding); -// TODO: Change the API to accept YGFloatOptional. +// TODO(T26792433): Change the API to accept YGFloatOptional. void YGNodeStyleSetBorder( const YGNodeRef node, const YGEdge edge, @@ -783,8 +802,8 @@ void YGNodeStyleSetBorder( float YGNodeStyleGetBorder(const YGNodeRef node, const YGEdge edge) { if (node->getStyle().border[edge].unit == YGUnitUndefined) { - // TODO: Rather than returning YGUndefined, change the api to return - // YGFloatOptional. + // TODO(T26792433): Rather than returning YGUndefined, change the api to + // return YGFloatOptional. return YGUndefined; } diff --git a/ReactCommon/yoga/yoga/Yoga.h b/ReactCommon/yoga/yoga/Yoga.h index 56fe95ff2ec2b8..baeb28e2219c36 100644 --- a/ReactCommon/yoga/yoga/Yoga.h +++ b/ReactCommon/yoga/yoga/Yoga.h @@ -195,7 +195,6 @@ YG_NODE_STYLE_PROPERTY(YGPositionType, PositionType, positionType); YG_NODE_STYLE_PROPERTY(YGWrap, FlexWrap, flexWrap); YG_NODE_STYLE_PROPERTY(YGOverflow, Overflow, overflow); YG_NODE_STYLE_PROPERTY(YGDisplay, Display, display); - YG_NODE_STYLE_PROPERTY(float, Flex, flex); YG_NODE_STYLE_PROPERTY(float, FlexGrow, flexGrow); YG_NODE_STYLE_PROPERTY(float, FlexShrink, flexShrink); From 3274e9fa519abf411304c82e6450dc6e4346d826 Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Wed, 14 Mar 2018 04:17:11 -0700 Subject: [PATCH 0015/1109] Change the type of flexGrow to YGFloatOptional Reviewed By: emilsjolander Differential Revision: D7215355 fbshipit-source-id: 1298ee332551d44e4d070169a1e4103d005c4f43 --- ReactCommon/yoga/yoga/YGNode.cpp | 4 ++-- ReactCommon/yoga/yoga/YGNodePrint.cpp | 2 +- ReactCommon/yoga/yoga/YGStyle.cpp | 8 +++++--- ReactCommon/yoga/yoga/YGStyle.h | 2 +- ReactCommon/yoga/yoga/Yoga.cpp | 20 +++++++++++++++++--- 5 files changed, 26 insertions(+), 10 deletions(-) diff --git a/ReactCommon/yoga/yoga/YGNode.cpp b/ReactCommon/yoga/yoga/YGNode.cpp index e7b1472aaec680..e3e44e72006114 100644 --- a/ReactCommon/yoga/yoga/YGNode.cpp +++ b/ReactCommon/yoga/yoga/YGNode.cpp @@ -592,8 +592,8 @@ float YGNode::resolveFlexGrow() { if (parent_ == nullptr) { return 0.0; } - if (!YGFloatIsUndefined(style_.flexGrow)) { - return style_.flexGrow; + if (!style_.flexGrow.isUndefined) { + return style_.flexGrow.value; } if (!style_.flex.isUndefined && style_.flex.value > 0.0f) { return style_.flex.value; diff --git a/ReactCommon/yoga/yoga/YGNodePrint.cpp b/ReactCommon/yoga/yoga/YGNodePrint.cpp index 2a7a11df8c7c04..fd515b51d7845c 100644 --- a/ReactCommon/yoga/yoga/YGNodePrint.cpp +++ b/ReactCommon/yoga/yoga/YGNodePrint.cpp @@ -161,7 +161,7 @@ void YGNodeToString( appendFormatedString( str, "align-self: %s; ", YGAlignToString(node->getStyle().alignSelf)); } - appendFloatIfNotUndefined(str, "flex-grow", node->getStyle().flexGrow); + appendFloatOptionalIfDefined(str, "flex-grow", node->getStyle().flexGrow); appendFloatIfNotUndefined(str, "flex-shrink", node->getStyle().flexShrink); appendNumberIfNotAuto(str, "flex-basis", node->getStyle().flexBasis); appendFloatOptionalIfDefined(str, "flex", node->getStyle().flex); diff --git a/ReactCommon/yoga/yoga/YGStyle.cpp b/ReactCommon/yoga/yoga/YGStyle.cpp index 2ac3da93e12342..d3c18e0ec3a0d2 100644 --- a/ReactCommon/yoga/yoga/YGStyle.cpp +++ b/ReactCommon/yoga/yoga/YGStyle.cpp @@ -43,7 +43,7 @@ YGStyle::YGStyle() overflow(YGOverflowVisible), display(YGDisplayFlex), flex(YGFloatOptionalUndefined), - flexGrow(YGUndefined), + flexGrow(YGFloatOptionalUndefined), flexShrink(YGUndefined), flexBasis(kYGValueAuto), margin(kYGDefaultEdgeValuesUnit), @@ -79,9 +79,11 @@ bool YGStyle::operator==(const YGStyle& style) { areNonFloatValuesEqual && flex.value == style.flex.value; } - if (!(YGFloatIsUndefined(flexGrow) && YGFloatIsUndefined(style.flexGrow))) { + areNonFloatValuesEqual = areNonFloatValuesEqual && + flexGrow.isUndefined == style.flexGrow.isUndefined; + if (areNonFloatValuesEqual && !flexGrow.isUndefined) { areNonFloatValuesEqual = - areNonFloatValuesEqual && flexGrow == style.flexGrow; + areNonFloatValuesEqual && flexGrow.value == style.flexGrow.value; } if (!(YGFloatIsUndefined(flexShrink) && diff --git a/ReactCommon/yoga/yoga/YGStyle.h b/ReactCommon/yoga/yoga/YGStyle.h index 99e1f18cf3fdc4..0da5b77fdb5f4c 100644 --- a/ReactCommon/yoga/yoga/YGStyle.h +++ b/ReactCommon/yoga/yoga/YGStyle.h @@ -21,7 +21,7 @@ struct YGStyle { YGOverflow overflow; YGDisplay display; YGFloatOptional flex; - float flexGrow; + YGFloatOptional flexGrow; float flexShrink; YGValue flexBasis; std::array margin; diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index bc80a63679b2e7..fd3a88a2d11508 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -511,9 +511,9 @@ void YGNodeCopyStyle(const YGNodeRef dstNode, const YGNodeRef srcNode) { } float YGNodeStyleGetFlexGrow(const YGNodeRef node) { - return YGFloatIsUndefined(node->getStyle().flexGrow) + return node->getStyle().flexGrow.isUndefined ? kDefaultFlexGrow - : node->getStyle().flexGrow; + : node->getStyle().flexGrow.value; } float YGNodeStyleGetFlexShrink(const YGNodeRef node) { @@ -772,7 +772,21 @@ float YGNodeStyleGetFlex(const YGNodeRef node) { : node->getStyle().flex.value; } -YG_NODE_STYLE_PROPERTY_SETTER_IMPL(float, FlexGrow, flexGrow, flexGrow); +// TODO(T26792433): Change the API to accept YGFloatOptional. +void YGNodeStyleSetFlexGrow(const YGNodeRef node, const float flexGrow) { + if (!YGFloatOptionalFloatEquals(node->getStyle().flexGrow, flexGrow)) { + YGStyle style = node->getStyle(); + if (YGFloatIsUndefined(flexGrow)) { + style.flexGrow = {true, 0}; + } else { + style.flexGrow = {false, flexGrow}; + } + node->setStyle(style); + node->markDirtyAndPropogate(); + } +} + +// YG_NODE_STYLE_PROPERTY_SETTER_IMPL(float, FlexGrow, flexGrow, flexGrow); YG_NODE_STYLE_PROPERTY_SETTER_IMPL(float, FlexShrink, flexShrink, flexShrink); YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(YGValue, FlexBasis, flexBasis, flexBasis); From e3af1508c8ec4e68ab85d8a881952ebf637dd5f4 Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Wed, 14 Mar 2018 04:17:16 -0700 Subject: [PATCH 0016/1109] Change the type of flexShrink to YGFloatOptional Reviewed By: emilsjolander Differential Revision: D7232171 fbshipit-source-id: 3111119d3d74a7035c01132bff61b30cf44e120a --- ReactCommon/yoga/yoga/YGNode.cpp | 4 ++-- ReactCommon/yoga/yoga/YGNodePrint.cpp | 10 ++-------- ReactCommon/yoga/yoga/YGStyle.cpp | 9 +++++---- ReactCommon/yoga/yoga/YGStyle.h | 2 +- ReactCommon/yoga/yoga/Yoga.cpp | 21 ++++++++++++++++----- 5 files changed, 26 insertions(+), 20 deletions(-) diff --git a/ReactCommon/yoga/yoga/YGNode.cpp b/ReactCommon/yoga/yoga/YGNode.cpp index e3e44e72006114..df61b14a896601 100644 --- a/ReactCommon/yoga/yoga/YGNode.cpp +++ b/ReactCommon/yoga/yoga/YGNode.cpp @@ -605,8 +605,8 @@ float YGNode::resolveFlexShrink() { if (parent_ == nullptr) { return 0.0; } - if (!YGFloatIsUndefined(style_.flexShrink)) { - return style_.flexShrink; + if (!style_.flexShrink.isUndefined) { + return style_.flexShrink.value; } if (!config_->useWebDefaults && !style_.flex.isUndefined && style_.flex.value < 0.0f) { diff --git a/ReactCommon/yoga/yoga/YGNodePrint.cpp b/ReactCommon/yoga/yoga/YGNodePrint.cpp index fd515b51d7845c..8585b725171fb2 100644 --- a/ReactCommon/yoga/yoga/YGNodePrint.cpp +++ b/ReactCommon/yoga/yoga/YGNodePrint.cpp @@ -48,13 +48,6 @@ static void appendFloatOptionalIfDefined( } } -static void -appendFloatIfNotUndefined(string* base, const string key, const float num) { - if (!YGFloatIsUndefined(num)) { - appendFormatedString(base, "%s: %g; ", key.c_str(), num); - } -} - static void appendNumberIfNotUndefined( string* base, const string key, @@ -162,7 +155,8 @@ void YGNodeToString( str, "align-self: %s; ", YGAlignToString(node->getStyle().alignSelf)); } appendFloatOptionalIfDefined(str, "flex-grow", node->getStyle().flexGrow); - appendFloatIfNotUndefined(str, "flex-shrink", node->getStyle().flexShrink); + appendFloatOptionalIfDefined( + str, "flex-shrink", node->getStyle().flexShrink); appendNumberIfNotAuto(str, "flex-basis", node->getStyle().flexBasis); appendFloatOptionalIfDefined(str, "flex", node->getStyle().flex); diff --git a/ReactCommon/yoga/yoga/YGStyle.cpp b/ReactCommon/yoga/yoga/YGStyle.cpp index d3c18e0ec3a0d2..c1f60bb5741a28 100644 --- a/ReactCommon/yoga/yoga/YGStyle.cpp +++ b/ReactCommon/yoga/yoga/YGStyle.cpp @@ -44,7 +44,7 @@ YGStyle::YGStyle() display(YGDisplayFlex), flex(YGFloatOptionalUndefined), flexGrow(YGFloatOptionalUndefined), - flexShrink(YGUndefined), + flexShrink(YGFloatOptionalUndefined), flexBasis(kYGValueAuto), margin(kYGDefaultEdgeValuesUnit), position(kYGDefaultEdgeValuesUnit), @@ -86,10 +86,11 @@ bool YGStyle::operator==(const YGStyle& style) { areNonFloatValuesEqual && flexGrow.value == style.flexGrow.value; } - if (!(YGFloatIsUndefined(flexShrink) && - YGFloatIsUndefined(style.flexShrink))) { + areNonFloatValuesEqual = areNonFloatValuesEqual && + flexShrink.isUndefined == style.flexShrink.isUndefined; + if (areNonFloatValuesEqual && !style.flexShrink.isUndefined) { areNonFloatValuesEqual = - areNonFloatValuesEqual && flexShrink == style.flexShrink; + areNonFloatValuesEqual && flexShrink.value == style.flexShrink.value; } if (!(YGFloatIsUndefined(aspectRatio) && diff --git a/ReactCommon/yoga/yoga/YGStyle.h b/ReactCommon/yoga/yoga/YGStyle.h index 0da5b77fdb5f4c..3abc4c084d4db3 100644 --- a/ReactCommon/yoga/yoga/YGStyle.h +++ b/ReactCommon/yoga/yoga/YGStyle.h @@ -22,7 +22,7 @@ struct YGStyle { YGDisplay display; YGFloatOptional flex; YGFloatOptional flexGrow; - float flexShrink; + YGFloatOptional flexShrink; YGValue flexBasis; std::array margin; std::array position; diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index fd3a88a2d11508..107e39c8c5f0d2 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -517,10 +517,10 @@ float YGNodeStyleGetFlexGrow(const YGNodeRef node) { } float YGNodeStyleGetFlexShrink(const YGNodeRef node) { - return YGFloatIsUndefined(node->getStyle().flexShrink) + return node->getStyle().flexShrink.isUndefined ? (node->getConfig()->useWebDefaults ? kWebDefaultFlexShrink : kDefaultFlexShrink) - : node->getStyle().flexShrink; + : node->getStyle().flexShrink.value; } #define YG_NODE_STYLE_PROPERTY_SETTER_IMPL( \ @@ -786,10 +786,21 @@ void YGNodeStyleSetFlexGrow(const YGNodeRef node, const float flexGrow) { } } -// YG_NODE_STYLE_PROPERTY_SETTER_IMPL(float, FlexGrow, flexGrow, flexGrow); -YG_NODE_STYLE_PROPERTY_SETTER_IMPL(float, FlexShrink, flexShrink, flexShrink); -YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(YGValue, FlexBasis, flexBasis, flexBasis); +// TODO(T26792433): Change the API to accept YGFloatOptional. +void YGNodeStyleSetFlexShrink(const YGNodeRef node, const float flexShrink) { + if (!YGFloatOptionalFloatEquals(node->getStyle().flexShrink, flexShrink)) { + YGStyle style = node->getStyle(); + if (YGFloatIsUndefined(flexShrink)) { + style.flexGrow = {true, 0}; + } else { + style.flexShrink = {false, flexShrink}; + } + node->setStyle(style); + node->markDirtyAndPropogate(); + } +} +YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(YGValue, FlexBasis, flexBasis, flexBasis); YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Position, position, position); YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Margin, margin, margin); YG_NODE_STYLE_EDGE_PROPERTY_UNIT_AUTO_IMPL(YGValue, Margin, margin); From f3ef8f85103938162d77622a2730790dfb3f2d7d Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Wed, 14 Mar 2018 04:17:18 -0700 Subject: [PATCH 0017/1109] Remove the use of YGUndefined for flex-basis Reviewed By: emilsjolander Differential Revision: D7243924 fbshipit-source-id: 2bfaca1a5e3da40d5292a273cabf705f59c9d666 --- ReactCommon/yoga/yoga/YGStyle.cpp | 2 +- ReactCommon/yoga/yoga/Yoga.cpp | 49 ++++++++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/ReactCommon/yoga/yoga/YGStyle.cpp b/ReactCommon/yoga/yoga/YGStyle.cpp index c1f60bb5741a28..031443c8cbf550 100644 --- a/ReactCommon/yoga/yoga/YGStyle.cpp +++ b/ReactCommon/yoga/yoga/YGStyle.cpp @@ -45,7 +45,7 @@ YGStyle::YGStyle() flex(YGFloatOptionalUndefined), flexGrow(YGFloatOptionalUndefined), flexShrink(YGFloatOptionalUndefined), - flexBasis(kYGValueAuto), + flexBasis({0, YGUnitAuto}), margin(kYGDefaultEdgeValuesUnit), position(kYGDefaultEdgeValuesUnit), padding(kYGDefaultEdgeValuesUnit), diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index 107e39c8c5f0d2..b3f3e2206a1395 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -800,7 +800,54 @@ void YGNodeStyleSetFlexShrink(const YGNodeRef node, const float flexShrink) { } } -YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(YGValue, FlexBasis, flexBasis, flexBasis); +YGValue YGNodeStyleGetFlexBasis(const YGNodeRef node) { + YGValue flexBasis = node->getStyle().flexBasis; + if (flexBasis.unit == YGUnitUndefined || flexBasis.unit == YGUnitAuto) { + // TODO(T26792433): Get rid off the use of YGUndefined at client side + flexBasis.value = YGUndefined; + } + return flexBasis; +} + +void YGNodeStyleSetFlexBasis(const YGNodeRef node, const float flexBasis) { + YGValue value = { + .value = YGFloatSanitize(flexBasis), + .unit = YGFloatIsUndefined(flexBasis) ? YGUnitUndefined : YGUnitPoint, + }; + if ((node->getStyle().flexBasis.value != value.value && + value.unit != YGUnitUndefined) || + node->getStyle().flexBasis.unit != value.unit) { + YGStyle style = node->getStyle(); + style.flexBasis = value; + node->setStyle(style); + node->markDirtyAndPropogate(); + } +} + +void YGNodeStyleSetFlexBasisPercent( + const YGNodeRef node, + const float flexBasisPercent) { + if (node->getStyle().flexBasis.value != flexBasisPercent || + node->getStyle().flexBasis.unit != YGUnitPercent) { + YGStyle style = node->getStyle(); + style.flexBasis.value = YGFloatSanitize(flexBasisPercent); + style.flexBasis.unit = + YGFloatIsUndefined(flexBasisPercent) ? YGUnitAuto : YGUnitPercent; + node->setStyle(style); + node->markDirtyAndPropogate(); + } +} + +void YGNodeStyleSetFlexBasisAuto(const YGNodeRef node) { + if (node->getStyle().flexBasis.unit != YGUnitAuto) { + YGStyle style = node->getStyle(); + style.flexBasis.value = 0; + style.flexBasis.unit = YGUnitAuto; + node->setStyle(style); + node->markDirtyAndPropogate(); + } +} + YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Position, position, position); YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Margin, margin, margin); YG_NODE_STYLE_EDGE_PROPERTY_UNIT_AUTO_IMPL(YGValue, Margin, margin); From 321b107685e8f5d3bd36f673d81041ec3876b34e Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Wed, 14 Mar 2018 08:37:55 -0700 Subject: [PATCH 0018/1109] Expose layout diffing flag to java Reviewed By: emilsjolander Differential Revision: D7272067 fbshipit-source-id: e67e82eb057e4c7124904c715f9dca4dcfea21ea --- .../java/com/facebook/yoga/YogaConfig.java | 13 +++++ .../main/java/com/facebook/yoga/YogaNode.java | 6 +++ .../jni/first-party/yogajni/jni/YGJNI.cpp | 51 +++++++++++++------ ReactCommon/yoga/yoga/Yoga.cpp | 10 ++++ ReactCommon/yoga/yoga/Yoga.h | 5 +- 5 files changed, 69 insertions(+), 16 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfig.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfig.java index e68c512140f015..2d90eec9de9dca 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfig.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfig.java @@ -74,6 +74,19 @@ public void setUseLegacyStretchBehaviour(boolean useLegacyStretchBehaviour) { jni_YGConfigSetUseLegacyStretchBehaviour(mNativePointer, useLegacyStretchBehaviour); } + private native void jni_YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour( + long nativePointer, boolean shouldDiffLayoutWithoutLegacyStretchBehaviour); + /** + * If this flag is set then yoga would diff the layout without legacy flag and would set a bool in + * YogaNode(mDoesLegacyStretchFlagAffectsLayout) with true if the layouts were different and false + * if not + */ + public void setShouldDiffLayoutWithoutLegacyStretchBehaviour( + boolean shouldDiffLayoutWithoutLegacyStretchBehaviour) { + jni_YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour( + mNativePointer, shouldDiffLayoutWithoutLegacyStretchBehaviour); + } + private native void jni_YGConfigSetLogger(long nativePointer, Object logger); public void setLogger(YogaLogger logger) { mLogger = logger; diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java index df5fae91712879..1c6e67a55eb9e5 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java @@ -82,6 +82,7 @@ public class YogaNode implements Cloneable { private int mLayoutDirection = 0; @DoNotStrip private boolean mHasNewLayout = true; + @DoNotStrip private boolean mDoesLegacyStretchFlagAffectsLayout = false; private native long jni_YGNodeNew(); public YogaNode() { @@ -136,6 +137,7 @@ public void reset() { mMeasureFunction = null; mBaselineFunction = null; mData = null; + mDoesLegacyStretchFlagAffectsLayout = false; jni_YGNodeReset(mNativePointer); } @@ -573,6 +575,10 @@ public float getLayoutHeight() { return mHeight; } + public boolean getDoesLegacyStretchFlagAffectsLayout() { + return mDoesLegacyStretchFlagAffectsLayout; + } + public float getLayoutMargin(YogaEdge edge) { switch (edge) { case LEFT: 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 46d73b44b4d7ff..cc75df96a15131 100644 --- a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp +++ b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp @@ -67,6 +67,9 @@ static void YGTransferLayoutOutputsRecursive(YGNodeRef root) { static auto edgeSetFlagField = obj->getClass()->getField("mEdgeSetFlag"); static auto hasNewLayoutField = obj->getClass()->getField("mHasNewLayout"); + static auto doesLegacyStretchBehaviour = + obj->getClass()->getField( + "mDoesLegacyStretchFlagAffectsLayout"); /* Those flags needs be in sync with YogaNode.java */ const int MARGIN = 1; @@ -79,12 +82,19 @@ static void YGTransferLayoutOutputsRecursive(YGNodeRef root) { obj->setFieldValue(heightField, YGNodeLayoutGetHeight(root)); obj->setFieldValue(leftField, YGNodeLayoutGetLeft(root)); obj->setFieldValue(topField, YGNodeLayoutGetTop(root)); + obj->setFieldValue( + doesLegacyStretchBehaviour, + YGNodeLayoutGetDidLegacyStretchFlagAffectLayout(root)); if ((hasEdgeSetFlag & MARGIN) == MARGIN) { - obj->setFieldValue(marginLeftField, YGNodeLayoutGetMargin(root, YGEdgeLeft)); - obj->setFieldValue(marginTopField, YGNodeLayoutGetMargin(root, YGEdgeTop)); - obj->setFieldValue(marginRightField, YGNodeLayoutGetMargin(root, YGEdgeRight)); - obj->setFieldValue(marginBottomField, YGNodeLayoutGetMargin(root, YGEdgeBottom)); + obj->setFieldValue( + marginLeftField, YGNodeLayoutGetMargin(root, YGEdgeLeft)); + obj->setFieldValue( + marginTopField, YGNodeLayoutGetMargin(root, YGEdgeTop)); + obj->setFieldValue( + marginRightField, YGNodeLayoutGetMargin(root, YGEdgeRight)); + obj->setFieldValue( + marginBottomField, YGNodeLayoutGetMargin(root, YGEdgeBottom)); } if ((hasEdgeSetFlag & PADDING) == PADDING) { @@ -467,6 +477,14 @@ void jni_YGConfigSetExperimentalFeatureEnabled(alias_ref, enabled); } +void jni_YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour( + alias_ref, + jlong nativePointer, + jboolean enabled) { + const YGConfigRef config = _jlong2YGConfigRef(nativePointer); + YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour(config, enabled); +} + void jni_YGConfigSetUseWebDefaults(alias_ref, jlong nativePointer, jboolean useWebDefaults) { @@ -624,16 +642,19 @@ jint JNI_OnLoad(JavaVM *vm, void *) { YGMakeNativeMethod(jni_YGNodePrint), YGMakeNativeMethod(jni_YGNodeClone), }); - registerNatives("com/facebook/yoga/YogaConfig", - { - YGMakeNativeMethod(jni_YGConfigNew), - YGMakeNativeMethod(jni_YGConfigFree), - YGMakeNativeMethod(jni_YGConfigSetExperimentalFeatureEnabled), - YGMakeNativeMethod(jni_YGConfigSetUseWebDefaults), - YGMakeNativeMethod(jni_YGConfigSetPointScaleFactor), - YGMakeNativeMethod(jni_YGConfigSetUseLegacyStretchBehaviour), - YGMakeNativeMethod(jni_YGConfigSetLogger), - YGMakeNativeMethod(jni_YGConfigSetHasNodeClonedFunc), - }); + registerNatives( + "com/facebook/yoga/YogaConfig", + { + YGMakeNativeMethod(jni_YGConfigNew), + YGMakeNativeMethod(jni_YGConfigFree), + YGMakeNativeMethod(jni_YGConfigSetExperimentalFeatureEnabled), + YGMakeNativeMethod(jni_YGConfigSetUseWebDefaults), + YGMakeNativeMethod(jni_YGConfigSetPointScaleFactor), + YGMakeNativeMethod(jni_YGConfigSetUseLegacyStretchBehaviour), + YGMakeNativeMethod(jni_YGConfigSetLogger), + YGMakeNativeMethod(jni_YGConfigSetHasNodeClonedFunc), + YGMakeNativeMethod( + jni_YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour), + }); }); } diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index b3f3e2206a1395..b5e1e4c044f54c 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -905,6 +905,10 @@ YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Margin, margin); YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Border, border); YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Padding, padding); +bool YGNodeLayoutGetDidLegacyStretchFlagAffectLayout(const YGNodeRef node) { + return node->getLayout().doesLegacyStretchFlagAffectsLayout; +} + uint32_t gCurrentGenerationCount = 0; bool YGLayoutNodeInternal(const YGNodeRef node, @@ -3842,6 +3846,12 @@ void YGConfigSetLogger(const YGConfigRef config, YGLogger logger) { } } +void YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour( + const YGConfigRef config, + const bool shouldDiffLayout) { + config->shouldDiffLayoutWithoutLegacyStretchBehaviour = shouldDiffLayout; +} + static void YGVLog(const YGConfigRef config, const YGNodeRef node, YGLogLevel level, diff --git a/ReactCommon/yoga/yoga/Yoga.h b/ReactCommon/yoga/yoga/Yoga.h index baeb28e2219c36..83eefa02689347 100644 --- a/ReactCommon/yoga/yoga/Yoga.h +++ b/ReactCommon/yoga/yoga/Yoga.h @@ -236,6 +236,7 @@ YG_NODE_LAYOUT_PROPERTY(float, Width); YG_NODE_LAYOUT_PROPERTY(float, Height); YG_NODE_LAYOUT_PROPERTY(YGDirection, Direction); YG_NODE_LAYOUT_PROPERTY(bool, HadOverflow); +bool YGNodeLayoutGetDidLegacyStretchFlagAffectLayout(const YGNodeRef node); // Get the computed values for these nodes after performing layout. If they were set using // point values then the returned value will be the same as YGNodeStyleGetXXX. However if @@ -253,10 +254,12 @@ WIN_EXPORT void YGAssertWithNode(const YGNodeRef node, const bool condition, con WIN_EXPORT void YGAssertWithConfig(const YGConfigRef config, const bool condition, const char *message); - // Set this to number of pixels in 1 point to round calculation results // If you want to avoid rounding - set PointScaleFactor to 0 WIN_EXPORT void YGConfigSetPointScaleFactor(const YGConfigRef config, const float pixelsInPoint); +void YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour( + const YGConfigRef config, + const bool shouldDiffLayout); // Yoga previously had an error where containers would take the maximum space possible instead of // the minimum From a01ae8b68a789e9b6fadf5e0707432e3667c6e7b Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Wed, 14 Mar 2018 08:45:02 -0700 Subject: [PATCH 0019/1109] Bump metro@0.30.1 Reviewed By: BYK Differential Revision: D7259632 fbshipit-source-id: ef713d35a953cd829d6a8684d2fa9cfa30e69ac4 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 33f5268f154280..5c554719e5f0a9 100644 --- a/package.json +++ b/package.json @@ -175,8 +175,8 @@ "graceful-fs": "^4.1.3", "inquirer": "^3.0.6", "lodash": "^4.17.5", - "metro": "^0.30.0", - "metro-core": "^0.30.0", + "metro": "^0.30.1", + "metro-core": "^0.30.1", "mime": "^1.3.4", "minimist": "^1.2.0", "mkdirp": "^0.5.1", From 4f8328bf2fb71b104baa70178a1e1f9636773c6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Wed, 14 Mar 2018 08:47:36 -0700 Subject: [PATCH 0020/1109] React sync for revisions ab4280b...ad9544f Reviewed By: bvaughn Differential Revision: D7256390 fbshipit-source-id: 9fe1324da93cb8f4a7f478e1037944774b9b95ff --- Libraries/Renderer/REVISION | 2 +- Libraries/Renderer/ReactFabric-dev.js | 157 +++++++++------ Libraries/Renderer/ReactFabric-prod.js | 189 +++++++++++------- Libraries/Renderer/ReactNativeRenderer-dev.js | 157 +++++++++------ .../Renderer/ReactNativeRenderer-prod.js | 189 +++++++++++------- Libraries/Renderer/shims/ReactFabric.js | 4 - Libraries/Renderer/shims/ReactNativeTypes.js | 17 +- Libraries/Renderer/shims/ReactTypes.js | 10 +- 8 files changed, 436 insertions(+), 289 deletions(-) diff --git a/Libraries/Renderer/REVISION b/Libraries/Renderer/REVISION index bb434f321ae390..824ff8c33a4c4f 100644 --- a/Libraries/Renderer/REVISION +++ b/Libraries/Renderer/REVISION @@ -1 +1 @@ -ab4280b3e98dbb97d3e753083dab19879167c3f5 \ No newline at end of file +ad9544f48e58f2599a8ea0de1e9f4dd104db30bb \ No newline at end of file diff --git a/Libraries/Renderer/ReactFabric-dev.js b/Libraries/Renderer/ReactFabric-dev.js index 9a30ceeda7036a..867873cd41d55b 100644 --- a/Libraries/Renderer/ReactFabric-dev.js +++ b/Libraries/Renderer/ReactFabric-dev.js @@ -3622,6 +3622,11 @@ var ReactNativeComponent = (function(_React$Component) { /** * 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() { TextInputState.blurTextInput(findNumericNodeHandleFiber(this)); }; @@ -8327,11 +8332,11 @@ var rendererSigil = void 0; function pushProvider(providerFiber) { var context = providerFiber.type.context; index$1 += 1; - changedBitsStack[index$1] = context.changedBits; - currentValueStack[index$1] = context.currentValue; + changedBitsStack[index$1] = context._changedBits; + currentValueStack[index$1] = context._currentValue; stack[index$1] = providerFiber; - context.currentValue = providerFiber.pendingProps.value; - context.changedBits = providerFiber.stateNode; + context._currentValue = providerFiber.pendingProps.value; + context._changedBits = providerFiber.stateNode; { warning( @@ -8358,16 +8363,16 @@ function popProvider(providerFiber) { stack[index$1] = null; index$1 -= 1; var context = providerFiber.type.context; - context.currentValue = currentValue; - context.changedBits = changedBits; + context._currentValue = currentValue; + context._changedBits = changedBits; } function resetProviderStack() { for (var i = index$1; i > -1; i--) { var providerFiber = stack[i]; var context = providerFiber.type.context; - context.currentValue = context.defaultValue; - context.changedBits = 0; + context._currentValue = context._defaultValue; + context._changedBits = 0; changedBitsStack[i] = null; currentValueStack[i] = null; stack[i] = null; @@ -9149,48 +9154,70 @@ var ReactFiberBeginWork = function( pushProvider(workInProgress); return bailoutOnAlreadyFinishedWork(current, workInProgress); } - workInProgress.memoizedProps = newProps; var newValue = newProps.value; + workInProgress.memoizedProps = newProps; var changedBits = void 0; if (oldProps === null) { // Initial render changedBits = MAX_SIGNED_31_BIT_INT; } else { - var oldValue = oldProps.value; - // Use Object.is to compare the new context value to the old value. - // Inlined Object.is polyfill. - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is - if ( - (oldValue === newValue && - (oldValue !== 0 || 1 / oldValue === 1 / newValue)) || - (oldValue !== oldValue && newValue !== newValue) // eslint-disable-line no-self-compare - ) { - // No change. + if (oldProps.value === newProps.value) { + // No change. Bailout early if children are the same. + if (oldProps.children === newProps.children) { + workInProgress.stateNode = 0; + pushProvider(workInProgress); + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } changedBits = 0; } else { - changedBits = - typeof context.calculateChangedBits === "function" - ? context.calculateChangedBits(oldValue, newValue) - : MAX_SIGNED_31_BIT_INT; - { - warning( - (changedBits & MAX_SIGNED_31_BIT_INT) === changedBits, - "calculateChangedBits: Expected the return value to be a " + - "31-bit integer. Instead received: %s", - changedBits - ); - } - changedBits |= 0; - - if (changedBits !== 0) { - propagateContextChange( - workInProgress, - context, - changedBits, - renderExpirationTime - ); + var oldValue = oldProps.value; + // Use Object.is to compare the new context value to the old value. + // Inlined Object.is polyfill. + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is + if ( + (oldValue === newValue && + (oldValue !== 0 || 1 / oldValue === 1 / newValue)) || + (oldValue !== oldValue && newValue !== newValue) // eslint-disable-line no-self-compare + ) { + // No change. Bailout early if children are the same. + if (oldProps.children === newProps.children) { + workInProgress.stateNode = 0; + pushProvider(workInProgress); + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + changedBits = 0; + } else { + changedBits = + typeof context._calculateChangedBits === "function" + ? context._calculateChangedBits(oldValue, newValue) + : MAX_SIGNED_31_BIT_INT; + { + warning( + (changedBits & MAX_SIGNED_31_BIT_INT) === changedBits, + "calculateChangedBits: Expected the return value to be a " + + "31-bit integer. Instead received: %s", + changedBits + ); + } + changedBits |= 0; + + if (changedBits === 0) { + // No change. Bailout early if children are the same. + if (oldProps.children === newProps.children) { + workInProgress.stateNode = 0; + pushProvider(workInProgress); + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + } else { + propagateContextChange( + workInProgress, + context, + changedBits, + renderExpirationTime + ); + } } } } @@ -9198,9 +9225,6 @@ var ReactFiberBeginWork = function( workInProgress.stateNode = changedBits; pushProvider(workInProgress); - if (oldProps !== null && oldProps.children === newProps.children) { - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } var newChildren = newProps.children; reconcileChildren(current, workInProgress, newChildren); return workInProgress.child; @@ -9213,11 +9237,28 @@ var ReactFiberBeginWork = function( ) { var context = workInProgress.type; var newProps = workInProgress.pendingProps; + var oldProps = workInProgress.memoizedProps; + + var newValue = context._currentValue; + var changedBits = context._changedBits; + + if (hasContextChanged()) { + // Normally we can bail out on props equality but if context has changed + // we don't do the bailout and we have to reuse existing props instead. + } else if (changedBits === 0 && oldProps === newProps) { + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + workInProgress.memoizedProps = newProps; - var newValue = context.currentValue; - var changedBits = context.changedBits; + var observedBits = newProps.unstable_observedBits; + if (observedBits === undefined || observedBits === null) { + // Subscribe to all changes by default + observedBits = MAX_SIGNED_31_BIT_INT; + } + // Store the observedBits on the fiber's stateNode for quick access. + workInProgress.stateNode = observedBits; - if (changedBits !== 0) { + if ((changedBits & observedBits) !== 0) { // Context change propagation stops at matching consumers, for time- // slicing. Continue the propagation here. propagateContextChange( @@ -9226,24 +9267,20 @@ var ReactFiberBeginWork = function( changedBits, renderExpirationTime ); + } else if (oldProps !== null && oldProps.children === newProps.children) { + // No change. Bailout early if children are the same. + return bailoutOnAlreadyFinishedWork(current, workInProgress); } - // Store the observedBits on the fiber's stateNode for quick access. - var observedBits = newProps.observedBits; - if (observedBits === undefined || observedBits === null) { - // Subscribe to all changes by default - observedBits = MAX_SIGNED_31_BIT_INT; - } - workInProgress.stateNode = observedBits; - var render = newProps.children; - if (typeof render !== "function") { - invariant( - 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." + { + warning( + typeof render === "function", + "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." ); } diff --git a/Libraries/Renderer/ReactFabric-prod.js b/Libraries/Renderer/ReactFabric-prod.js index 9605c98520cda9..950e09890f8203 100644 --- a/Libraries/Renderer/ReactFabric-prod.js +++ b/Libraries/Renderer/ReactFabric-prod.js @@ -3122,11 +3122,11 @@ var reconcileChildFibers = ChildReconciler(!0), function pushProvider(providerFiber) { var context = providerFiber.type.context; index$1 += 1; - changedBitsStack[index$1] = context.changedBits; - currentValueStack[index$1] = context.currentValue; + changedBitsStack[index$1] = context._changedBits; + currentValueStack[index$1] = context._currentValue; stack[index$1] = providerFiber; - context.currentValue = providerFiber.pendingProps.value; - context.changedBits = providerFiber.stateNode; + context._currentValue = providerFiber.pendingProps.value; + context._changedBits = providerFiber.stateNode; } function popProvider(providerFiber) { var changedBits = changedBitsStack[index$1], @@ -3136,8 +3136,8 @@ function popProvider(providerFiber) { stack[index$1] = null; --index$1; providerFiber = providerFiber.type.context; - providerFiber.currentValue = currentValue; - providerFiber.changedBits = changedBits; + providerFiber._currentValue = currentValue; + providerFiber._changedBits = changedBits; } function ReactFiberBeginWork( config, @@ -3289,6 +3289,72 @@ function ReactFiberBeginWork( fiber = nextFiber; } } + function updateContextProvider( + current, + workInProgress, + renderExpirationTime + ) { + var context = workInProgress.type.context, + newProps = workInProgress.pendingProps, + oldProps = workInProgress.memoizedProps; + if (!didPerformWorkStackCursor.current && oldProps === newProps) + return ( + (workInProgress.stateNode = 0), + pushProvider(workInProgress), + bailoutOnAlreadyFinishedWork(current, workInProgress) + ); + var newValue = newProps.value; + workInProgress.memoizedProps = newProps; + if (null === oldProps) newValue = 1073741823; + else if (oldProps.value === newProps.value) { + if (oldProps.children === newProps.children) + return ( + (workInProgress.stateNode = 0), + pushProvider(workInProgress), + bailoutOnAlreadyFinishedWork(current, workInProgress) + ); + newValue = 0; + } else { + var oldValue = oldProps.value; + if ( + (oldValue === newValue && + (0 !== oldValue || 1 / oldValue === 1 / newValue)) || + (oldValue !== oldValue && newValue !== newValue) + ) { + if (oldProps.children === newProps.children) + return ( + (workInProgress.stateNode = 0), + pushProvider(workInProgress), + bailoutOnAlreadyFinishedWork(current, workInProgress) + ); + newValue = 0; + } else if ( + ((newValue = + "function" === typeof context._calculateChangedBits + ? context._calculateChangedBits(oldValue, newValue) + : 1073741823), + (newValue |= 0), + 0 === newValue) + ) { + if (oldProps.children === newProps.children) + return ( + (workInProgress.stateNode = 0), + pushProvider(workInProgress), + bailoutOnAlreadyFinishedWork(current, workInProgress) + ); + } else + propagateContextChange( + workInProgress, + context, + newValue, + renderExpirationTime + ); + } + workInProgress.stateNode = newValue; + pushProvider(workInProgress); + reconcileChildren(current, workInProgress, newProps.children); + return workInProgress.child; + } function bailoutOnAlreadyFinishedWork(current, workInProgress) { invariant( null === current || workInProgress.child === current.child, @@ -3641,71 +3707,50 @@ function ReactFiberBeginWork( current ); case 13: - props = workInProgress.type.context; - fn = workInProgress.pendingProps; - unmaskedContext = workInProgress.memoizedProps; - if (didPerformWorkStackCursor.current || unmaskedContext !== fn) { - workInProgress.memoizedProps = fn; - updateQueue = fn.value; - if (null === unmaskedContext) updateQueue = 1073741823; - else { - var oldValue = unmaskedContext.value; - (oldValue === updateQueue && - (0 !== oldValue || 1 / oldValue === 1 / updateQueue)) || - (oldValue !== oldValue && updateQueue !== updateQueue) - ? (updateQueue = 0) - : ((updateQueue = - "function" === typeof props.calculateChangedBits - ? props.calculateChangedBits(oldValue, updateQueue) - : 1073741823), - (updateQueue |= 0), - 0 !== updateQueue && - propagateContextChange( - workInProgress, - props, - updateQueue, - renderExpirationTime - )); - } - workInProgress.stateNode = updateQueue; - pushProvider(workInProgress); - null !== unmaskedContext && unmaskedContext.children === fn.children - ? (current = bailoutOnAlreadyFinishedWork( - current, - workInProgress - )) - : (reconcileChildren(current, workInProgress, fn.children), - (current = workInProgress.child)); - } else - (workInProgress.stateNode = 0), - pushProvider(workInProgress), - (current = bailoutOnAlreadyFinishedWork(current, workInProgress)); - return current; + return updateContextProvider( + current, + workInProgress, + renderExpirationTime + ); case 12: - unmaskedContext = workInProgress.type; - fn = workInProgress.pendingProps; - props = unmaskedContext.currentValue; - updateQueue = unmaskedContext.changedBits; - 0 !== updateQueue && - propagateContextChange( - workInProgress, - unmaskedContext, - updateQueue, - renderExpirationTime - ); - renderExpirationTime = fn.observedBits; - if (void 0 === renderExpirationTime || null === renderExpirationTime) - renderExpirationTime = 1073741823; - workInProgress.stateNode = renderExpirationTime; - renderExpirationTime = fn.children; - "function" !== typeof renderExpirationTime && - invariant( - !1, - "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." - ); - renderExpirationTime = renderExpirationTime(props); - reconcileChildren(current, workInProgress, renderExpirationTime); - return workInProgress.child; + a: { + fn = workInProgress.type; + unmaskedContext = workInProgress.pendingProps; + updateQueue = workInProgress.memoizedProps; + props = fn._currentValue; + var changedBits = fn._changedBits; + if ( + didPerformWorkStackCursor.current || + 0 !== changedBits || + updateQueue !== unmaskedContext + ) { + workInProgress.memoizedProps = unmaskedContext; + var observedBits = unmaskedContext.unstable_observedBits; + if (void 0 === observedBits || null === observedBits) + observedBits = 1073741823; + workInProgress.stateNode = observedBits; + if (0 !== (changedBits & observedBits)) + propagateContextChange( + workInProgress, + fn, + changedBits, + renderExpirationTime + ); + else if ( + null !== updateQueue && + updateQueue.children === unmaskedContext.children + ) { + current = bailoutOnAlreadyFinishedWork(current, workInProgress); + break a; + } + renderExpirationTime = unmaskedContext.children; + renderExpirationTime = renderExpirationTime(props); + reconcileChildren(current, workInProgress, renderExpirationTime); + current = workInProgress.child; + } else + current = bailoutOnAlreadyFinishedWork(current, workInProgress); + } + return current; default: invariant( !1, @@ -4581,8 +4626,8 @@ function ReactFiberScheduler(config) { resetHostContainer(); for (var i = index$1; -1 < i; i--) { var context = stack[i].type.context; - context.currentValue = context.defaultValue; - context.changedBits = 0; + context._currentValue = context._defaultValue; + context._changedBits = 0; changedBitsStack[i] = null; currentValueStack[i] = null; stack[i] = null; diff --git a/Libraries/Renderer/ReactNativeRenderer-dev.js b/Libraries/Renderer/ReactNativeRenderer-dev.js index fc98f17e176f8b..400472d29a3875 100644 --- a/Libraries/Renderer/ReactNativeRenderer-dev.js +++ b/Libraries/Renderer/ReactNativeRenderer-dev.js @@ -3968,6 +3968,11 @@ var ReactNativeComponent = (function(_React$Component) { /** * 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() { TextInputState.blurTextInput(findNumericNodeHandleFiber(this)); }; @@ -8585,11 +8590,11 @@ var rendererSigil = void 0; function pushProvider(providerFiber) { var context = providerFiber.type.context; index$1 += 1; - changedBitsStack[index$1] = context.changedBits; - currentValueStack[index$1] = context.currentValue; + changedBitsStack[index$1] = context._changedBits; + currentValueStack[index$1] = context._currentValue; stack[index$1] = providerFiber; - context.currentValue = providerFiber.pendingProps.value; - context.changedBits = providerFiber.stateNode; + context._currentValue = providerFiber.pendingProps.value; + context._changedBits = providerFiber.stateNode; { warning( @@ -8616,16 +8621,16 @@ function popProvider(providerFiber) { stack[index$1] = null; index$1 -= 1; var context = providerFiber.type.context; - context.currentValue = currentValue; - context.changedBits = changedBits; + context._currentValue = currentValue; + context._changedBits = changedBits; } function resetProviderStack() { for (var i = index$1; i > -1; i--) { var providerFiber = stack[i]; var context = providerFiber.type.context; - context.currentValue = context.defaultValue; - context.changedBits = 0; + context._currentValue = context._defaultValue; + context._changedBits = 0; changedBitsStack[i] = null; currentValueStack[i] = null; stack[i] = null; @@ -9407,48 +9412,70 @@ var ReactFiberBeginWork = function( pushProvider(workInProgress); return bailoutOnAlreadyFinishedWork(current, workInProgress); } - workInProgress.memoizedProps = newProps; var newValue = newProps.value; + workInProgress.memoizedProps = newProps; var changedBits = void 0; if (oldProps === null) { // Initial render changedBits = MAX_SIGNED_31_BIT_INT; } else { - var oldValue = oldProps.value; - // Use Object.is to compare the new context value to the old value. - // Inlined Object.is polyfill. - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is - if ( - (oldValue === newValue && - (oldValue !== 0 || 1 / oldValue === 1 / newValue)) || - (oldValue !== oldValue && newValue !== newValue) // eslint-disable-line no-self-compare - ) { - // No change. + if (oldProps.value === newProps.value) { + // No change. Bailout early if children are the same. + if (oldProps.children === newProps.children) { + workInProgress.stateNode = 0; + pushProvider(workInProgress); + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } changedBits = 0; } else { - changedBits = - typeof context.calculateChangedBits === "function" - ? context.calculateChangedBits(oldValue, newValue) - : MAX_SIGNED_31_BIT_INT; - { - warning( - (changedBits & MAX_SIGNED_31_BIT_INT) === changedBits, - "calculateChangedBits: Expected the return value to be a " + - "31-bit integer. Instead received: %s", - changedBits - ); - } - changedBits |= 0; - - if (changedBits !== 0) { - propagateContextChange( - workInProgress, - context, - changedBits, - renderExpirationTime - ); + var oldValue = oldProps.value; + // Use Object.is to compare the new context value to the old value. + // Inlined Object.is polyfill. + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is + if ( + (oldValue === newValue && + (oldValue !== 0 || 1 / oldValue === 1 / newValue)) || + (oldValue !== oldValue && newValue !== newValue) // eslint-disable-line no-self-compare + ) { + // No change. Bailout early if children are the same. + if (oldProps.children === newProps.children) { + workInProgress.stateNode = 0; + pushProvider(workInProgress); + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + changedBits = 0; + } else { + changedBits = + typeof context._calculateChangedBits === "function" + ? context._calculateChangedBits(oldValue, newValue) + : MAX_SIGNED_31_BIT_INT; + { + warning( + (changedBits & MAX_SIGNED_31_BIT_INT) === changedBits, + "calculateChangedBits: Expected the return value to be a " + + "31-bit integer. Instead received: %s", + changedBits + ); + } + changedBits |= 0; + + if (changedBits === 0) { + // No change. Bailout early if children are the same. + if (oldProps.children === newProps.children) { + workInProgress.stateNode = 0; + pushProvider(workInProgress); + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + } else { + propagateContextChange( + workInProgress, + context, + changedBits, + renderExpirationTime + ); + } } } } @@ -9456,9 +9483,6 @@ var ReactFiberBeginWork = function( workInProgress.stateNode = changedBits; pushProvider(workInProgress); - if (oldProps !== null && oldProps.children === newProps.children) { - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } var newChildren = newProps.children; reconcileChildren(current, workInProgress, newChildren); return workInProgress.child; @@ -9471,11 +9495,28 @@ var ReactFiberBeginWork = function( ) { var context = workInProgress.type; var newProps = workInProgress.pendingProps; + var oldProps = workInProgress.memoizedProps; + + var newValue = context._currentValue; + var changedBits = context._changedBits; + + if (hasContextChanged()) { + // Normally we can bail out on props equality but if context has changed + // we don't do the bailout and we have to reuse existing props instead. + } else if (changedBits === 0 && oldProps === newProps) { + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + workInProgress.memoizedProps = newProps; - var newValue = context.currentValue; - var changedBits = context.changedBits; + var observedBits = newProps.unstable_observedBits; + if (observedBits === undefined || observedBits === null) { + // Subscribe to all changes by default + observedBits = MAX_SIGNED_31_BIT_INT; + } + // Store the observedBits on the fiber's stateNode for quick access. + workInProgress.stateNode = observedBits; - if (changedBits !== 0) { + if ((changedBits & observedBits) !== 0) { // Context change propagation stops at matching consumers, for time- // slicing. Continue the propagation here. propagateContextChange( @@ -9484,24 +9525,20 @@ var ReactFiberBeginWork = function( changedBits, renderExpirationTime ); + } else if (oldProps !== null && oldProps.children === newProps.children) { + // No change. Bailout early if children are the same. + return bailoutOnAlreadyFinishedWork(current, workInProgress); } - // Store the observedBits on the fiber's stateNode for quick access. - var observedBits = newProps.observedBits; - if (observedBits === undefined || observedBits === null) { - // Subscribe to all changes by default - observedBits = MAX_SIGNED_31_BIT_INT; - } - workInProgress.stateNode = observedBits; - var render = newProps.children; - if (typeof render !== "function") { - invariant( - 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." + { + warning( + typeof render === "function", + "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." ); } diff --git a/Libraries/Renderer/ReactNativeRenderer-prod.js b/Libraries/Renderer/ReactNativeRenderer-prod.js index dd0cd8b9cb5346..ca27b720b33dfe 100644 --- a/Libraries/Renderer/ReactNativeRenderer-prod.js +++ b/Libraries/Renderer/ReactNativeRenderer-prod.js @@ -3376,11 +3376,11 @@ var reconcileChildFibers = ChildReconciler(!0), function pushProvider(providerFiber) { var context = providerFiber.type.context; index$1 += 1; - changedBitsStack[index$1] = context.changedBits; - currentValueStack[index$1] = context.currentValue; + changedBitsStack[index$1] = context._changedBits; + currentValueStack[index$1] = context._currentValue; stack[index$1] = providerFiber; - context.currentValue = providerFiber.pendingProps.value; - context.changedBits = providerFiber.stateNode; + context._currentValue = providerFiber.pendingProps.value; + context._changedBits = providerFiber.stateNode; } function popProvider(providerFiber) { var changedBits = changedBitsStack[index$1], @@ -3390,8 +3390,8 @@ function popProvider(providerFiber) { stack[index$1] = null; --index$1; providerFiber = providerFiber.type.context; - providerFiber.currentValue = currentValue; - providerFiber.changedBits = changedBits; + providerFiber._currentValue = currentValue; + providerFiber._changedBits = changedBits; } function ReactFiberBeginWork( config, @@ -3552,6 +3552,72 @@ function ReactFiberBeginWork( fiber = nextFiber; } } + function updateContextProvider( + current, + workInProgress, + renderExpirationTime + ) { + var context = workInProgress.type.context, + newProps = workInProgress.pendingProps, + oldProps = workInProgress.memoizedProps; + if (!didPerformWorkStackCursor.current && oldProps === newProps) + return ( + (workInProgress.stateNode = 0), + pushProvider(workInProgress), + bailoutOnAlreadyFinishedWork(current, workInProgress) + ); + var newValue = newProps.value; + workInProgress.memoizedProps = newProps; + if (null === oldProps) newValue = 1073741823; + else if (oldProps.value === newProps.value) { + if (oldProps.children === newProps.children) + return ( + (workInProgress.stateNode = 0), + pushProvider(workInProgress), + bailoutOnAlreadyFinishedWork(current, workInProgress) + ); + newValue = 0; + } else { + var oldValue = oldProps.value; + if ( + (oldValue === newValue && + (0 !== oldValue || 1 / oldValue === 1 / newValue)) || + (oldValue !== oldValue && newValue !== newValue) + ) { + if (oldProps.children === newProps.children) + return ( + (workInProgress.stateNode = 0), + pushProvider(workInProgress), + bailoutOnAlreadyFinishedWork(current, workInProgress) + ); + newValue = 0; + } else if ( + ((newValue = + "function" === typeof context._calculateChangedBits + ? context._calculateChangedBits(oldValue, newValue) + : 1073741823), + (newValue |= 0), + 0 === newValue) + ) { + if (oldProps.children === newProps.children) + return ( + (workInProgress.stateNode = 0), + pushProvider(workInProgress), + bailoutOnAlreadyFinishedWork(current, workInProgress) + ); + } else + propagateContextChange( + workInProgress, + context, + newValue, + renderExpirationTime + ); + } + workInProgress.stateNode = newValue; + pushProvider(workInProgress); + reconcileChildren(current, workInProgress, newProps.children); + return workInProgress.child; + } function bailoutOnAlreadyFinishedWork(current, workInProgress) { invariant( null === current || workInProgress.child === current.child, @@ -3904,71 +3970,50 @@ function ReactFiberBeginWork( current ); case 13: - props = workInProgress.type.context; - fn = workInProgress.pendingProps; - unmaskedContext = workInProgress.memoizedProps; - if (didPerformWorkStackCursor.current || unmaskedContext !== fn) { - workInProgress.memoizedProps = fn; - updateQueue = fn.value; - if (null === unmaskedContext) updateQueue = 1073741823; - else { - var oldValue = unmaskedContext.value; - (oldValue === updateQueue && - (0 !== oldValue || 1 / oldValue === 1 / updateQueue)) || - (oldValue !== oldValue && updateQueue !== updateQueue) - ? (updateQueue = 0) - : ((updateQueue = - "function" === typeof props.calculateChangedBits - ? props.calculateChangedBits(oldValue, updateQueue) - : 1073741823), - (updateQueue |= 0), - 0 !== updateQueue && - propagateContextChange( - workInProgress, - props, - updateQueue, - renderExpirationTime - )); - } - workInProgress.stateNode = updateQueue; - pushProvider(workInProgress); - null !== unmaskedContext && unmaskedContext.children === fn.children - ? (current = bailoutOnAlreadyFinishedWork( - current, - workInProgress - )) - : (reconcileChildren(current, workInProgress, fn.children), - (current = workInProgress.child)); - } else - (workInProgress.stateNode = 0), - pushProvider(workInProgress), - (current = bailoutOnAlreadyFinishedWork(current, workInProgress)); - return current; + return updateContextProvider( + current, + workInProgress, + renderExpirationTime + ); case 12: - unmaskedContext = workInProgress.type; - fn = workInProgress.pendingProps; - props = unmaskedContext.currentValue; - updateQueue = unmaskedContext.changedBits; - 0 !== updateQueue && - propagateContextChange( - workInProgress, - unmaskedContext, - updateQueue, - renderExpirationTime - ); - renderExpirationTime = fn.observedBits; - if (void 0 === renderExpirationTime || null === renderExpirationTime) - renderExpirationTime = 1073741823; - workInProgress.stateNode = renderExpirationTime; - renderExpirationTime = fn.children; - "function" !== typeof renderExpirationTime && - invariant( - !1, - "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." - ); - renderExpirationTime = renderExpirationTime(props); - reconcileChildren(current, workInProgress, renderExpirationTime); - return workInProgress.child; + a: { + fn = workInProgress.type; + unmaskedContext = workInProgress.pendingProps; + updateQueue = workInProgress.memoizedProps; + props = fn._currentValue; + var changedBits = fn._changedBits; + if ( + didPerformWorkStackCursor.current || + 0 !== changedBits || + updateQueue !== unmaskedContext + ) { + workInProgress.memoizedProps = unmaskedContext; + var observedBits = unmaskedContext.unstable_observedBits; + if (void 0 === observedBits || null === observedBits) + observedBits = 1073741823; + workInProgress.stateNode = observedBits; + if (0 !== (changedBits & observedBits)) + propagateContextChange( + workInProgress, + fn, + changedBits, + renderExpirationTime + ); + else if ( + null !== updateQueue && + updateQueue.children === unmaskedContext.children + ) { + current = bailoutOnAlreadyFinishedWork(current, workInProgress); + break a; + } + renderExpirationTime = unmaskedContext.children; + renderExpirationTime = renderExpirationTime(props); + reconcileChildren(current, workInProgress, renderExpirationTime); + current = workInProgress.child; + } else + current = bailoutOnAlreadyFinishedWork(current, workInProgress); + } + return current; default: invariant( !1, @@ -4977,8 +5022,8 @@ function ReactFiberScheduler(config) { resetHostContainer(); for (var i = index$1; -1 < i; i--) { var context = stack[i].type.context; - context.currentValue = context.defaultValue; - context.changedBits = 0; + context._currentValue = context._defaultValue; + context._changedBits = 0; changedBitsStack[i] = null; currentValueStack[i] = null; stack[i] = null; diff --git a/Libraries/Renderer/shims/ReactFabric.js b/Libraries/Renderer/shims/ReactFabric.js index 4162ca62fef73d..4a396c224cd4ff 100644 --- a/Libraries/Renderer/shims/ReactFabric.js +++ b/Libraries/Renderer/shims/ReactFabric.js @@ -9,8 +9,6 @@ */ 'use strict'; -const BatchedBridge = require('BatchedBridge'); - // TODO @sema: Adjust types import type {ReactNativeType} from 'ReactNativeTypes'; @@ -22,6 +20,4 @@ if (__DEV__) { ReactFabric = require('ReactFabric-prod'); } -BatchedBridge.registerCallableModule('ReactFabric', ReactFabric); - module.exports = (ReactFabric: ReactNativeType); diff --git a/Libraries/Renderer/shims/ReactNativeTypes.js b/Libraries/Renderer/shims/ReactNativeTypes.js index 121a2fdd4d3dd3..f20bb30faa7938 100644 --- a/Libraries/Renderer/shims/ReactNativeTypes.js +++ b/Libraries/Renderer/shims/ReactNativeTypes.js @@ -86,27 +86,12 @@ type SecretInternalsType = { // And how much information to fill in for the above types. }; -declare class ReactNativeComponent - extends React$Component { - - blur(): void, - focus(): void, - measure(callback: MeasureOnSuccessCallback): void, - measureInWindow(callback: MeasureInWindowOnSuccessCallback): void, - measureLayout( - relativeToNativeNode: number, - onSuccess: MeasureLayoutOnSuccessCallback, - onFail: () => void, - ): void, - setNativeProps(nativeProps: Object): void, -} - /** * Flat ReactNative renderer bundles are too big for Flow to parse efficiently. * Provide minimal Flow typing for the high-level RN API and call it a day. */ export type ReactNativeType = { - NativeComponent: typeof ReactNativeComponent, + NativeComponent: any, findNodeHandle(componentOrHandle: any): ?number, render( element: React$Element, diff --git a/Libraries/Renderer/shims/ReactTypes.js b/Libraries/Renderer/shims/ReactTypes.js index 26ada3c5e842f5..bede9f00e30069 100644 --- a/Libraries/Renderer/shims/ReactTypes.js +++ b/Libraries/Renderer/shims/ReactTypes.js @@ -80,10 +80,12 @@ export type ReactContext = { $$typeof: Symbol | number, Consumer: ReactContext, Provider: ReactProviderType, - calculateChangedBits: ((a: T, b: T) => number) | null, - defaultValue: T, - currentValue: T, - changedBits: number, + + _calculateChangedBits: ((a: T, b: T) => number) | null, + _defaultValue: T, + + _currentValue: T, + _changedBits: number, // DEV only _currentRenderer?: Object | null, From bec97dc24312ed59377888672fa821b2276a8a9f Mon Sep 17 00:00:00 2001 From: Eric Czarny Date: Wed, 14 Mar 2018 11:04:56 -0700 Subject: [PATCH 0021/1109] Expose native show message method in header Reviewed By: mmmulani Differential Revision: D7201691 fbshipit-source-id: b5f74351a9be7e6e9a7fc7145a09ba9854efc002 --- React/DevSupport/RCTDevLoadingView.h | 3 +++ React/DevSupport/RCTDevLoadingView.m | 1 + 2 files changed, 4 insertions(+) diff --git a/React/DevSupport/RCTDevLoadingView.h b/React/DevSupport/RCTDevLoadingView.h index dae01f04577142..61a7121c5476a0 100644 --- a/React/DevSupport/RCTDevLoadingView.h +++ b/React/DevSupport/RCTDevLoadingView.h @@ -5,6 +5,8 @@ * LICENSE file in the root directory of this source tree. */ +#import + #import @class RCTLoadingProgress; @@ -12,6 +14,7 @@ @interface RCTDevLoadingView : NSObject + (void)setEnabled:(BOOL)enabled; +- (void)showMessage:(NSString *)message color:(UIColor *)color backgroundColor:(UIColor *)backgroundColor; - (void)showWithURL:(NSURL *)URL; - (void)updateProgress:(RCTLoadingProgress *)progress; - (void)hide; diff --git a/React/DevSupport/RCTDevLoadingView.m b/React/DevSupport/RCTDevLoadingView.m index e7614a896489f4..9382c91caa6ea6 100644 --- a/React/DevSupport/RCTDevLoadingView.m +++ b/React/DevSupport/RCTDevLoadingView.m @@ -161,6 +161,7 @@ @implementation RCTDevLoadingView + (NSString *)moduleName { return nil; } + (void)setEnabled:(BOOL)enabled { } +- (void)showMessage:(NSString *)message color:(UIColor *)color backgroundColor:(UIColor *)backgroundColor { } - (void)showWithURL:(NSURL *)URL { } - (void)updateProgress:(RCTLoadingProgress *)progress { } - (void)hide { } From 3a2bdf5c50d48305d1538256a816420a6ebcaa48 Mon Sep 17 00:00:00 2001 From: "Andrew Chen (Eng)" Date: Wed, 14 Mar 2018 11:31:27 -0700 Subject: [PATCH 0022/1109] Move Fabric JSC bindings to oss Reviewed By: mdvacca Differential Revision: D7205065 fbshipit-source-id: 5876cb3e08ee96e39b80e6b377c60600f404ca21 --- .../java/com/facebook/react/fabric/jsc/BUCK | 24 ++ .../react/fabric/jsc/FabricJSCBinding.java | 35 +++ .../com/facebook/react/fabric/jsc/jni/BUCK | 20 ++ .../react/fabric/jsc/jni/FabricJSCBinding.cpp | 296 ++++++++++++++++++ .../react/fabric/jsc/jni/FabricJSCBinding.h | 29 ++ .../facebook/react/fabric/jsc/jni/OnLoad.cpp | 12 + 6 files changed, 416 insertions(+) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/BUCK create mode 100644 ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/FabricJSCBinding.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/BUCK create mode 100644 ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/FabricJSCBinding.cpp create mode 100644 ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/FabricJSCBinding.h create mode 100644 ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/OnLoad.cpp diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/BUCK b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/BUCK new file mode 100644 index 00000000000000..ac6ce3d53025ba --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/BUCK @@ -0,0 +1,24 @@ +load("@xplat//ReactNative:DEFS.bzl", "react_native_dep", "react_native_target", "rn_android_library", "IS_OSS_BUILD") + +rn_android_library( + name = "jsc", + srcs = glob(["**/*.java"]), + exported_deps = [ + react_native_dep("java/com/facebook/jni:jni"), + react_native_dep("java/com/facebook/proguard/annotations:annotations"), + ], + provided_deps = [ + react_native_dep("third-party/android/support/v4:lib-support-v4"), + ], + required_for_source_only_abi = True, + visibility = [ + "PUBLIC", + ], + deps = [ + react_native_dep("libraries/soloader/java/com/facebook/soloader:soloader"), + react_native_dep("third-party/java/infer-annotations:infer-annotations"), + react_native_target("java/com/facebook/react/bridge:bridge"), + react_native_target("java/com/facebook/react/fabric:fabric"), + react_native_target("java/com/facebook/react/fabric/jsc/jni:jni"), + ], +) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/FabricJSCBinding.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/FabricJSCBinding.java new file mode 100644 index 00000000000000..ab7352f9ede0bd --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/FabricJSCBinding.java @@ -0,0 +1,35 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +package com.facebook.react.fabric.jsc; + +import com.facebook.jni.HybridData; +import com.facebook.proguard.annotations.DoNotStrip; +import com.facebook.react.bridge.JavaScriptContextHolder; +import com.facebook.react.fabric.FabricBinding; +import com.facebook.react.fabric.FabricUIManager; +import com.facebook.soloader.SoLoader; + +@DoNotStrip +public class FabricJSCBinding implements FabricBinding { + + static { + SoLoader.loadLibrary("fabricjscjni"); + } + + // used from native + @SuppressWarnings("unused") + private final HybridData mHybridData; + + private static native HybridData initHybrid(); + + private native void installFabric(long jsContextNativePointer, Object fabricModule); + + public FabricJSCBinding() { + mHybridData = initHybrid(); + } + + @Override + public void installFabric(JavaScriptContextHolder jsContext, FabricUIManager fabricModule) { + installFabric(jsContext.get(), fabricModule); + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/BUCK b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/BUCK new file mode 100644 index 00000000000000..cbf088f2d277e8 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/BUCK @@ -0,0 +1,20 @@ +load("@xplat//ReactNative:DEFS.bzl", "react_native_target", "react_native_xplat_target", "rn_xplat_cxx_library", "FBJNI_TARGET", "ANDROID") + +rn_xplat_cxx_library( + name = "jni", + srcs = glob(["*.cpp"]), + headers = glob(["*.h"]), + compiler_flags = [ + "-Wall", + "-fexceptions", + "-std=gnu++1y", + ], + platforms = ANDROID, + soname = "libfabricjscjni.$(ext)", + visibility = ["PUBLIC"], + deps = [ + FBJNI_TARGET, + react_native_xplat_target("jschelpers:jschelpers"), + react_native_target("jni/react/jni:jni"), + ], +) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/FabricJSCBinding.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/FabricJSCBinding.cpp new file mode 100644 index 00000000000000..044143210b1c27 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/FabricJSCBinding.cpp @@ -0,0 +1,296 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include "FabricJSCBinding.h" +#include +#include +#include +#include + +using namespace facebook::jni; + +namespace facebook { +namespace react { + +namespace { + +bool useCustomJSC = false; + +struct JList : public JavaClass { + static constexpr auto kJavaDescriptor = "Ljava/util/List;"; +}; + +struct JShadowNode : public JavaClass { + static constexpr auto kJavaDescriptor = "Lcom/facebook/react/uimanager/ReactShadowNode;"; +}; + +typedef struct FabricJSCUIManager { + FabricJSCUIManager(alias_ref module, JSClassRef classRef, bool customJSC) + : wrapperObjectClassRef(classRef) + , useCustomJSC(customJSC) { + fabricUiManager = make_global(module); + } + global_ref fabricUiManager; + JSClassRef wrapperObjectClassRef; + bool useCustomJSC; +} FabricJSCUIManager; + +jobject makePlainGlobalRef(jobject object) { + // When storing the global reference we need it to be a plain + // pointer. That's why we use plain jni instead of fbjni here. + return Environment::current()->NewGlobalRef(object); +} + +local_ref JSValueToJString(JSContextRef ctx, JSValueRef value) { + JSStringRef strRef = JSC_JSValueToStringCopy(ctx, value, NULL); + const size_t size = JSStringGetMaximumUTF8CStringSize(strRef); + char buffer[size]; + JSStringGetUTF8CString(strRef, buffer, size); + JSC_JSStringRelease(ctx, strRef); + return make_jstring(buffer); +} + +local_ref JSValueToJShadowNode(JSContextRef ctx, JSValueRef value) { + JSObjectRef obj = JSC_JSValueToObject(ctx, value, NULL); + auto node = static_cast(JSC_JSObjectGetPrivate(useCustomJSC, obj)); + return make_local(node); +} + +local_ref JSValueToJList(JSContextRef ctx, JSValueRef value) { + JSObjectRef obj = JSC_JSValueToObject(ctx, value, NULL); + auto node = static_cast(JSC_JSObjectGetPrivate(useCustomJSC, obj)); + return make_local(node); +} + +local_ref JSValueToReadableMapViaJSON(JSContextRef ctx, JSValueRef value) { + JSStringRef jsonRef = JSC_JSValueCreateJSONString(ctx, value, 0, NULL); + size_t size = JSC_JSStringGetLength(ctx, jsonRef); + const JSChar* utf16 = JSC_JSStringGetCharactersPtr(ctx, jsonRef); + std::string json = unicode::utf16toUTF8(utf16, size); + JSC_JSStringRelease(ctx, jsonRef); + folly::dynamic dynamicValue = folly::parseJson(json); + return ReadableNativeMap::newObjectCxxArgs(std::move(dynamicValue)); +} + +JSValueRef createNode(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) { + FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function); + alias_ref manager = managerWrapper->fabricUiManager; + JSClassRef classRef = managerWrapper->wrapperObjectClassRef; + + static auto createNode = + jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") + ->getMethod(jint, jstring, jint, ReadableNativeMap::javaobject)>("createNode"); + + int reactTag = (int)JSC_JSValueToNumber(ctx, arguments[0], NULL); + auto viewName = JSValueToJString(ctx, arguments[1]); + int rootTag = (int)JSC_JSValueToNumber(ctx, arguments[2], NULL); + auto props = JSC_JSValueIsNull(ctx, arguments[3]) ? local_ref(nullptr) : + JSValueToReadableMapViaJSON(ctx, arguments[3]);; + + // TODO: Retain object in arguments[4] using a weak ref. + + auto node = createNode(manager, reactTag, viewName.get(), rootTag, props.get()); + + return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(node.get())); +} + +JSValueRef cloneNode(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) { + FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function); + alias_ref manager = managerWrapper->fabricUiManager; + JSClassRef classRef = managerWrapper->wrapperObjectClassRef; + + static auto cloneNode = + jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") + ->getMethod(JShadowNode::javaobject)>("cloneNode"); + + auto previousNode = JSValueToJShadowNode(ctx, arguments[0]); + auto newNode = cloneNode(manager, previousNode.get()); + + return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(newNode.get())); +} + +JSValueRef cloneNodeWithNewChildren(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) { + FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function); + alias_ref manager = managerWrapper->fabricUiManager; + JSClassRef classRef = managerWrapper->wrapperObjectClassRef; + + static auto cloneNodeWithNewChildren = + jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") + ->getMethod(JShadowNode::javaobject)>("cloneNodeWithNewChildren"); + + auto previousNode = JSValueToJShadowNode(ctx, arguments[0]); + auto newNode = cloneNodeWithNewChildren(manager, previousNode.get()); + + return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(newNode.get())); +} + +JSValueRef cloneNodeWithNewProps(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) { + FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function); + alias_ref manager = managerWrapper->fabricUiManager; + JSClassRef classRef = managerWrapper->wrapperObjectClassRef; + + static auto cloneNodeWithNewProps = + jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") + ->getMethod(JShadowNode::javaobject, ReadableNativeMap::javaobject)>("cloneNodeWithNewProps"); + + auto previousNode = JSValueToJShadowNode(ctx, arguments[0]); + auto props = JSValueToReadableMapViaJSON(ctx, arguments[1]); + auto newNode = cloneNodeWithNewProps(manager, previousNode.get(), props.get()); + + return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(newNode.get())); +} + +JSValueRef cloneNodeWithNewChildrenAndProps(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) { + FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function); + alias_ref manager = managerWrapper->fabricUiManager; + JSClassRef classRef = managerWrapper->wrapperObjectClassRef; + + static auto cloneNodeWithNewChildrenAndProps = + jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") + ->getMethod(JShadowNode::javaobject, ReadableNativeMap::javaobject)>("cloneNodeWithNewChildrenAndProps"); + + auto previousNode = JSValueToJShadowNode(ctx, arguments[0]); + auto props = JSValueToReadableMapViaJSON(ctx, arguments[1]); + auto newNode = cloneNodeWithNewChildrenAndProps(manager, previousNode.get(), props.get()); + + return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(newNode.get())); +} + +JSValueRef appendChild(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) { + FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function); + alias_ref manager = managerWrapper->fabricUiManager; + + static auto appendChild = + jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") + ->getMethod("appendChild"); + + auto parentNode = JSValueToJShadowNode(ctx, arguments[0]); + auto childNode = JSValueToJShadowNode(ctx, arguments[1]); + + appendChild(manager, parentNode.get(), childNode.get()); + + return JSC_JSValueMakeUndefined(ctx); +} + +JSValueRef createChildSet(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) { + FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function); + alias_ref manager = managerWrapper->fabricUiManager; + JSClassRef classRef = managerWrapper->wrapperObjectClassRef; + + static auto createChildSet = + jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") + ->getMethod(jint)>("createChildSet"); + + int rootTag = (int)JSC_JSValueToNumber(ctx, arguments[0], NULL); + auto childSet = createChildSet(manager, rootTag); + + return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(childSet.get())); +} + +JSValueRef appendChildToSet(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) { + FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function); + alias_ref manager = managerWrapper->fabricUiManager; + + static auto appendChildToSet = + jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") + ->getMethod("appendChildToSet"); + + auto childSet = JSValueToJList(ctx, arguments[0]); + auto childNode = JSValueToJShadowNode(ctx, arguments[1]); + + appendChildToSet(manager, childSet.get(), childNode.get()); + + return JSC_JSValueMakeUndefined(ctx); +} + +JSValueRef completeRoot(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) { + FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function); + alias_ref manager = managerWrapper->fabricUiManager; + + static auto completeRoot = + jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") + ->getMethod("completeRoot"); + + int rootTag = (int)JSC_JSValueToNumber(ctx, arguments[0], NULL); + auto childSet = JSValueToJList(ctx, arguments[1]); + + completeRoot(manager, rootTag, childSet.get()); + + return JSC_JSValueMakeUndefined(ctx); +} + +void finalizeJNIObject(JSObjectRef object) { + // Release whatever global ref object we're storing here. + jobject globalRef = (jobject)JSC_JSObjectGetPrivate(useCustomJSC, object); + Environment::current()->DeleteGlobalRef(globalRef); +} + +void finalizeWrapper(JSObjectRef object) { + FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, object); + delete managerWrapper; +} + +void addFabricMethod( + JSContextRef context, + jni::alias_ref fabricModule, + JSClassRef nodeClassRef, + JSObjectRef module, + const char *name, + JSObjectCallAsFunctionCallback callback +) { + JSClassDefinition definition = kJSClassDefinitionEmpty; + definition.callAsFunction = callback; + definition.finalize = finalizeWrapper; + JSClassRef classRef = JSC_JSClassCreate(useCustomJSC, &definition); + FabricJSCUIManager *managerWrapper = new FabricJSCUIManager(fabricModule, nodeClassRef, useCustomJSC); + JSObjectRef functionRef = JSC_JSObjectMake(context, classRef, managerWrapper); + JSC_JSClassRelease(useCustomJSC, classRef); + + JSStringRef nameStr = JSC_JSStringCreateWithUTF8CString(context, name); + JSC_JSObjectSetProperty(context, module, nameStr, functionRef, kJSPropertyAttributeNone, NULL); + JSC_JSStringRelease(context, nameStr); +} + +} + +jni::local_ref FabricJSCBinding::initHybrid( + jni::alias_ref) { + return makeCxxInstance(); +} + +void FabricJSCBinding::installFabric(jlong jsContextNativePointer, + jni::alias_ref fabricModule) { + JSContextRef context = (JSContextRef)jsContextNativePointer; + useCustomJSC = facebook::react::isCustomJSCPtr(context); + + JSObjectRef module = JSC_JSObjectMake(context, NULL, NULL); + + // Class definition for wrapper objects around nodes and sets + JSClassDefinition definition = kJSClassDefinitionEmpty; + definition.finalize = finalizeJNIObject; + JSClassRef classRef = JSC_JSClassCreate(useCustomJSC, &definition); + + addFabricMethod(context, fabricModule, classRef, module, "createNode", createNode); + addFabricMethod(context, fabricModule, classRef, module, "cloneNode", cloneNode); + addFabricMethod(context, fabricModule, classRef, module, "cloneNodeWithNewChildren", cloneNodeWithNewChildren); + addFabricMethod(context, fabricModule, classRef, module, "cloneNodeWithNewProps", cloneNodeWithNewProps); + addFabricMethod(context, fabricModule, classRef, module, "cloneNodeWithNewChildrenAndProps", cloneNodeWithNewChildrenAndProps); + addFabricMethod(context, fabricModule, classRef, module, "appendChild", appendChild); + addFabricMethod(context, fabricModule, classRef, module, "createChildSet", createChildSet); + addFabricMethod(context, fabricModule, classRef, module, "appendChildToSet", appendChildToSet); + addFabricMethod(context, fabricModule, classRef, module, "completeRoot", completeRoot); + + JSObjectRef globalObject = JSC_JSContextGetGlobalObject(context); + JSStringRef globalName = JSC_JSStringCreateWithUTF8CString(context, "nativeFabricUIManager"); + JSC_JSObjectSetProperty(context, globalObject, globalName, module, kJSPropertyAttributeNone, NULL); + JSC_JSStringRelease(context, globalName); +} + +void FabricJSCBinding::registerNatives() { + registerHybrid({ + makeNativeMethod("initHybrid", FabricJSCBinding::initHybrid), + makeNativeMethod("installFabric", FabricJSCBinding::installFabric), + }); +} + +} +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/FabricJSCBinding.h b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/FabricJSCBinding.h new file mode 100644 index 00000000000000..e23c9524ef2026 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/FabricJSCBinding.h @@ -0,0 +1,29 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include + +namespace facebook { +namespace react { + +class Instance; + +class FabricJSCBinding : public jni::HybridClass { +public: + constexpr static const char *const kJavaDescriptor = + "Lcom/facebook/react/fabric/jsc/FabricJSCBinding;"; + + static void registerNatives(); + +private: + + static jni::local_ref initHybrid(jni::alias_ref); + + void installFabric(jlong jsContextNativePointer, jni::alias_ref fabricModule); + +}; + +} +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/OnLoad.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/OnLoad.cpp new file mode 100644 index 00000000000000..1ca90c4e9d93b7 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/OnLoad.cpp @@ -0,0 +1,12 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include +#include + +#include "FabricJSCBinding.h" + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { + return facebook::xplat::initialize(vm, [] { + facebook::react::FabricJSCBinding::registerNatives(); + }); +} From 7ce943ef3bf6e3c3b74bbcdbe0e125e3843e8924 Mon Sep 17 00:00:00 2001 From: Alejandro Paredes Alva Date: Wed, 14 Mar 2018 13:04:41 -0700 Subject: [PATCH 0023/1109] Adds _lineHeight = NAN; to RCTTextAttributes Summary: On iOS, when the parent Text contains the `lineHeight` style prop, and the children are also Text components they don't inherit the lineHeight prop. This is for **iOS** only. Create a react-native project with React Native 0.54.0 or 0.54.1 and change the app to: ```js import React, { Component } from 'react'; import { StyleSheet, Text, View } from 'react-native'; type Props = {}; export default class App extends Component { render() { return ( I am bold and orange, I am bold and red, I am bold and blue, I am bold and purple, I am bold and yellow, I am bold and pink ); } } const styles = StyleSheet.create({ container: { backgroundColor: 'black', flex: 1, justifyContent: 'center', padding: 50, }, }); ``` It displays: ![iphone - 2018-03-12 at 21 51 53](https://user-images.githubusercontent.com/480605/37308941-b56f082e-263f-11e8-9c23-892f77077169.png) But should look like: ![iphone - 2018-03-12 at 21 48 15](https://user-images.githubusercontent.com/480605/37308784-4efaddf2-263f-11e8-992b-ee0b6bb9a97b.png) New <Text> iOS https://github.com/facebook/react-native/commit/2716f53 [IOS] [MINOR] [Text] - Inherit lineheight Closes https://github.com/facebook/react-native/pull/18340 Differential Revision: D7276655 Pulled By: shergin fbshipit-source-id: 0fe26536bb74da77be8405911fc699a622bc0b2f --- Libraries/Text/RCTTextAttributes.m | 1 + 1 file changed, 1 insertion(+) diff --git a/Libraries/Text/RCTTextAttributes.m b/Libraries/Text/RCTTextAttributes.m index 6427e303158bb9..d74e0ab7611b57 100644 --- a/Libraries/Text/RCTTextAttributes.m +++ b/Libraries/Text/RCTTextAttributes.m @@ -21,6 +21,7 @@ - (instancetype)init if (self = [super init]) { _fontSize = NAN; _letterSpacing = NAN; + _lineHeight = NAN; _textDecorationStyle = NSUnderlineStyleSingle; _fontSizeMultiplier = NAN; _alignment = NSTextAlignmentNatural; From 67656991b32075e8b4a99c6409b0a131206c6941 Mon Sep 17 00:00:00 2001 From: Eli White Date: Wed, 14 Mar 2018 14:04:19 -0700 Subject: [PATCH 0024/1109] Move Image PropTypes to a new file Reviewed By: yungsters Differential Revision: D7270058 fbshipit-source-id: 91ad7700b7e89c393c6977bfd82494d2febda4a4 --- Libraries/Image/Image.ios.js | 118 +----------------------------- Libraries/Image/ImageProps.js | 134 ++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+), 116 deletions(-) create mode 100644 Libraries/Image/ImageProps.js diff --git a/Libraries/Image/Image.ios.js b/Libraries/Image/Image.ios.js index 173d78704f6610..c3e9ad5359c166 100644 --- a/Libraries/Image/Image.ios.js +++ b/Libraries/Image/Image.ios.js @@ -11,6 +11,7 @@ 'use strict'; const EdgeInsetsPropType = require('EdgeInsetsPropType'); +const ImageProps = require('ImageProps'); const ImageResizeMode = require('ImageResizeMode'); const ImageSourcePropType = require('ImageSourcePropType'); const ImageStylePropTypes = require('ImageStylePropTypes'); @@ -38,122 +39,7 @@ const ImageViewManager = NativeModules.ImageViewManager; */ const Image = createReactClass({ displayName: 'Image', - propTypes: { - /** - * See https://facebook.github.io/react-native/docs/image.html#style - */ - style: StyleSheetPropType(ImageStylePropTypes), - /** - * The image source (either a remote URL or a local file resource). - * - * See https://facebook.github.io/react-native/docs/image.html#source - */ - source: ImageSourcePropType, - /** - * A static image to display while loading the image source. - * - * See https://facebook.github.io/react-native/docs/image.html#defaultsource - */ - defaultSource: PropTypes.oneOfType([ - PropTypes.shape({ - uri: PropTypes.string, - width: PropTypes.number, - height: PropTypes.number, - scale: PropTypes.number, - }), - PropTypes.number, - ]), - /** - * When true, indicates the image is an accessibility element. - * - * See https://facebook.github.io/react-native/docs/image.html#accessible - */ - accessible: PropTypes.bool, - /** - * The text that's read by the screen reader when the user interacts with - * the image. - * - * See https://facebook.github.io/react-native/docs/image.html#accessibilitylabel - */ - accessibilityLabel: PropTypes.node, - /** - * blurRadius: the blur radius of the blur filter added to the image - * - * See https://facebook.github.io/react-native/docs/image.html#blurradius - */ - blurRadius: PropTypes.number, - /** - * See https://facebook.github.io/react-native/docs/image.html#capinsets - */ - capInsets: EdgeInsetsPropType, - /** - * See https://facebook.github.io/react-native/docs/image.html#resizemethod - */ - resizeMethod: PropTypes.oneOf(['auto', 'resize', 'scale']), - /** - * Determines how to resize the image when the frame doesn't match the raw - * image dimensions. - * - * See https://facebook.github.io/react-native/docs/image.html#resizemode - */ - resizeMode: PropTypes.oneOf([ - 'cover', - 'contain', - 'stretch', - 'repeat', - 'center', - ]), - /** - * A unique identifier for this element to be used in UI Automation - * testing scripts. - * - * See https://facebook.github.io/react-native/docs/image.html#testid - */ - testID: PropTypes.string, - /** - * Invoked on mount and layout changes with - * `{nativeEvent: {layout: {x, y, width, height}}}`. - * - * See https://facebook.github.io/react-native/docs/image.html#onlayout - */ - onLayout: PropTypes.func, - /** - * Invoked on load start. - * - * See https://facebook.github.io/react-native/docs/image.html#onloadstart - */ - onLoadStart: PropTypes.func, - /** - * Invoked on download progress with `{nativeEvent: {loaded, total}}`. - * - * See https://facebook.github.io/react-native/docs/image.html#onprogress - */ - onProgress: PropTypes.func, - /** - * Invoked on load error with `{nativeEvent: {error}}`. - * - * See https://facebook.github.io/react-native/docs/image.html#onerror - */ - onError: PropTypes.func, - /** - * Invoked when a partial load of the image is complete. - * - * See https://facebook.github.io/react-native/docs/image.html#onpartialload - */ - onPartialLoad: PropTypes.func, - /** - * Invoked when load completes successfully. - * - * See https://facebook.github.io/react-native/docs/image.html#onload - */ - onLoad: PropTypes.func, - /** - * Invoked when load either succeeds or fails. - * - * See https://facebook.github.io/react-native/docs/image.html#onloadend - */ - onLoadEnd: PropTypes.func, - }, + propTypes: ImageProps, statics: { resizeMode: ImageResizeMode, diff --git a/Libraries/Image/ImageProps.js b/Libraries/Image/ImageProps.js new file mode 100644 index 00000000000000..eb09ccd8e4ea37 --- /dev/null +++ b/Libraries/Image/ImageProps.js @@ -0,0 +1,134 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @providesModule ImageProps + * @flow + */ + +'use strict'; + +const EdgeInsetsPropType = require('EdgeInsetsPropType'); +const ImageSourcePropType = require('ImageSourcePropType'); +const ImageStylePropTypes = require('ImageStylePropTypes'); +const PropTypes = require('prop-types'); +const StyleSheetPropType = require('StyleSheetPropType'); + +module.exports = { + /** + * See https://facebook.github.io/react-native/docs/image.html#style + */ + style: StyleSheetPropType(ImageStylePropTypes), + /** + * The image source (either a remote URL or a local file resource). + * + * See https://facebook.github.io/react-native/docs/image.html#source + */ + source: ImageSourcePropType, + /** + * A static image to display while loading the image source. + * + * See https://facebook.github.io/react-native/docs/image.html#defaultsource + */ + defaultSource: PropTypes.oneOfType([ + PropTypes.shape({ + uri: PropTypes.string, + width: PropTypes.number, + height: PropTypes.number, + scale: PropTypes.number, + }), + PropTypes.number, + ]), + /** + * When true, indicates the image is an accessibility element. + * + * See https://facebook.github.io/react-native/docs/image.html#accessible + */ + accessible: PropTypes.bool, + /** + * The text that's read by the screen reader when the user interacts with + * the image. + * + * See https://facebook.github.io/react-native/docs/image.html#accessibilitylabel + */ + accessibilityLabel: PropTypes.node, + /** + * blurRadius: the blur radius of the blur filter added to the image + * + * See https://facebook.github.io/react-native/docs/image.html#blurradius + */ + blurRadius: PropTypes.number, + /** + * See https://facebook.github.io/react-native/docs/image.html#capinsets + */ + capInsets: EdgeInsetsPropType, + /** + * See https://facebook.github.io/react-native/docs/image.html#resizemethod + */ + resizeMethod: PropTypes.oneOf(['auto', 'resize', 'scale']), + /** + * Determines how to resize the image when the frame doesn't match the raw + * image dimensions. + * + * See https://facebook.github.io/react-native/docs/image.html#resizemode + */ + resizeMode: PropTypes.oneOf([ + 'cover', + 'contain', + 'stretch', + 'repeat', + 'center', + ]), + /** + * A unique identifier for this element to be used in UI Automation + * testing scripts. + * + * See https://facebook.github.io/react-native/docs/image.html#testid + */ + testID: PropTypes.string, + /** + * Invoked on mount and layout changes with + * `{nativeEvent: {layout: {x, y, width, height}}}`. + * + * See https://facebook.github.io/react-native/docs/image.html#onlayout + */ + onLayout: PropTypes.func, + /** + * Invoked on load start. + * + * See https://facebook.github.io/react-native/docs/image.html#onloadstart + */ + onLoadStart: PropTypes.func, + /** + * Invoked on download progress with `{nativeEvent: {loaded, total}}`. + * + * See https://facebook.github.io/react-native/docs/image.html#onprogress + */ + onProgress: PropTypes.func, + /** + * Invoked on load error with `{nativeEvent: {error}}`. + * + * See https://facebook.github.io/react-native/docs/image.html#onerror + */ + onError: PropTypes.func, + /** + * Invoked when a partial load of the image is complete. + * + * See https://facebook.github.io/react-native/docs/image.html#onpartialload + */ + onPartialLoad: PropTypes.func, + /** + * Invoked when load completes successfully. + * + * See https://facebook.github.io/react-native/docs/image.html#onload + */ + onLoad: PropTypes.func, + /** + * Invoked when load either succeeds or fails. + * + * See https://facebook.github.io/react-native/docs/image.html#onloadend + */ + onLoadEnd: PropTypes.func, +}; From 8bac869f5d1f2ef42e707d0ec817afc6ac98b3b2 Mon Sep 17 00:00:00 2001 From: Eli White Date: Wed, 14 Mar 2018 14:04:21 -0700 Subject: [PATCH 0025/1109] Create Flow Props for Image Reviewed By: yungsters Differential Revision: D7270057 fbshipit-source-id: 1ecac28e4060fe0e85a4f0698406f8986ae16caf --- Libraries/Image/ImageProps.js | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Libraries/Image/ImageProps.js b/Libraries/Image/ImageProps.js index eb09ccd8e4ea37..f075d9ccecedca 100644 --- a/Libraries/Image/ImageProps.js +++ b/Libraries/Image/ImageProps.js @@ -6,6 +6,7 @@ * * @providesModule ImageProps * @flow + * @format */ 'use strict'; @@ -16,6 +17,36 @@ const ImageStylePropTypes = require('ImageStylePropTypes'); const PropTypes = require('prop-types'); const StyleSheetPropType = require('StyleSheetPropType'); +import type {ImageSource} from 'ImageSource'; +import type {EdgeInsetsProp} from 'EdgeInsetsPropType'; +import type {LayoutEvent} from 'CoreEventTypes'; +import type {SyntheticEvent} from 'CoreEventTypes'; + +export type ImageProps = { + accessible?: boolean, + accessibilityLabel?: ?(string | Array | any), + blurRadius?: number, + capInsets?: ?EdgeInsetsProp, + + onError?: ?(event: SyntheticEvent<$ReadOnly<{||}>>) => void, + onLayout?: ?(event: LayoutEvent) => void, + onLoad?: ?() => void, + onLoadEnd?: ?() => void, + onLoadStart?: ?() => void, + resizeMethod?: ?('auto' | 'resize' | 'scale'), + resizeMode?: ?('cover' | 'contain' | 'stretch' | 'repeat' | 'center'), + source?: ?ImageSource, + style?: typeof ImageStylePropTypes, + testID?: ?string, + + // ios + defaultSource?: ?ImageSource, + onPartialLoad?: ?() => void, + onProgress?: ?( + event: SyntheticEvent<$ReadOnly<{|loaded: number, total: number|}>>, + ) => void, +}; + module.exports = { /** * See https://facebook.github.io/react-native/docs/image.html#style From 28c9c68cfa51ea224466d9e0f1aac5ec39d220e0 Mon Sep 17 00:00:00 2001 From: Eli White Date: Wed, 14 Mar 2018 14:30:44 -0700 Subject: [PATCH 0026/1109] Adding documentation to new StyleSheet Flow Types Summary: Adding some explanation and examples of when to use these types. Reviewed By: yungsters Differential Revision: D7270185 fbshipit-source-id: c82f061ffb77e33133a59d268a08f7a95fd02fb6 --- Libraries/StyleSheet/StyleSheet.js | 36 +++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/Libraries/StyleSheet/StyleSheet.js b/Libraries/StyleSheet/StyleSheet.js index 3320c459b68ca0..f2552f3e66d1c4 100644 --- a/Libraries/StyleSheet/StyleSheet.js +++ b/Libraries/StyleSheet/StyleSheet.js @@ -27,11 +27,45 @@ import type { LayoutStyle, } from 'StyleSheetTypes'; -export type DangerouslyImpreciseStyleProp = ____DangerouslyImpreciseStyleProp_Internal; +/** + * This type should be used as the type for a prop that is passed through + * to a 's `style` prop. This ensures call sites of the component + * can't pass styles that View doesn't support such as `fontSize`.` + * + * type Props = {style: ViewStyleProp} + * const MyComponent = (props: Props) => + */ export type ViewStyleProp = ____ViewStyleProp_Internal; + +/** + * This type should be used as the type for a prop that is passed through + * to a 's `style` prop. This ensures call sites of the component + * can't pass styles that Text doesn't support such as `resizeMode`.` + * + * type Props = {style: TextStyleProp} + * const MyComponent = (props: Props) => + */ export type TextStyleProp = ____TextStyleProp_Internal; + +/** + * This type should be used as the type for a prop that is passed through + * to an 's `style` prop. This ensures call sites of the component + * can't pass styles that Image doesn't support such as `fontSize`.` + * + * type Props = {style: ImageStyleProp} + * const MyComponent = (props: Props) => + */ export type ImageStyleProp = ____ImageStyleProp_Internal; +/** + * WARNING: You probably shouldn't be using this type. This type + * is similar to the ones above except it allows styles that are accepted + * by all of View, Text, or Image. It is therefore very unsafe to pass this + * through to an underlying component. Using this is almost always a mistake + * and using one of the other more restrictive types is likely the right choice. + */ +export type DangerouslyImpreciseStyleProp = ____DangerouslyImpreciseStyleProp_Internal; + let hairlineWidth = PixelRatio.roundToNearestPixel(0.4); if (hairlineWidth === 0) { hairlineWidth = 1 / PixelRatio.get(); From c595509048cc5f6cab360cd2ccbe7c86405baf92 Mon Sep 17 00:00:00 2001 From: Khaer Ansori Date: Wed, 14 Mar 2018 14:41:58 -0700 Subject: [PATCH 0027/1109] Add number-pad keyboardType Summary: On Android there's no number-pad but numeric instead, for my use-case I need number only (without decimal and sign, for PIN input) I write it so there's no breaking change for those already using the `TextInput` Component None [ANDROID][ENHANCEMENT][Component] Add number-pad keyboardType Closes https://github.com/facebook/react-native/pull/18350 Reviewed By: achen1 Differential Revision: D7269721 Pulled By: mdvacca fbshipit-source-id: 82571dce948e0cf2e4354dc46c69198ec69ba65a --- Libraries/Components/TextInput/TextInput.js | 4 ++-- .../react/views/textinput/ReactTextInputManager.java | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js index deb3b40e48bdee..2c6c4f8ef19b2e 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -244,6 +244,7 @@ const TextInput = createReactClass({ * * - `default` * - `numeric` + * - `number-pad` * - `email-address` * - `phone-pad` * @@ -254,7 +255,6 @@ const TextInput = createReactClass({ * - `ascii-capable` * - `numbers-and-punctuation` * - `url` - * - `number-pad` * - `name-phone-pad` * - `decimal-pad` * - `twitter` @@ -272,11 +272,11 @@ const TextInput = createReactClass({ 'email-address', 'numeric', 'phone-pad', + 'number-pad', // iOS-only 'ascii-capable', 'numbers-and-punctuation', 'url', - 'number-pad', 'name-phone-pad', 'decimal-pad', 'twitter', diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java index 637027140ec010..2c5013a7e712a8 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java @@ -68,8 +68,9 @@ public class ReactTextInputManager extends BaseViewManager Date: Wed, 14 Mar 2018 15:38:35 -0700 Subject: [PATCH 0028/1109] Add MIT license to Fabric Reviewed By: fkgozali Differential Revision: D7278262 fbshipit-source-id: 39f4c73b8f693162eb037125bf64fecc7eb0cf8b --- .../main/java/com/facebook/react/fabric/FabricBinding.java | 7 +++++++ .../java/com/facebook/react/fabric/FabricUIManager.java | 7 ++++++- .../com/facebook/react/fabric/RootShadowNodeRegistry.java | 7 +++++++ .../com/facebook/react/fabric/jsc/FabricJSCBinding.java | 7 ++++++- .../com/facebook/react/fabric/jsc/jni/FabricJSCBinding.cpp | 7 ++++++- .../com/facebook/react/fabric/jsc/jni/FabricJSCBinding.h | 7 ++++++- .../main/java/com/facebook/react/fabric/jsc/jni/OnLoad.cpp | 7 ++++++- 7 files changed, 44 insertions(+), 5 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricBinding.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricBinding.java index 37a943afac69b7..97535f0a0d74c3 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricBinding.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricBinding.java @@ -1,3 +1,10 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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.fabric; import com.facebook.react.bridge.JavaScriptContextHolder; 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 6fd4c1ae2d69db..38eea630d4bb46 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -1,4 +1,9 @@ -// Copyright 2004-present Facebook. All Rights Reserved. +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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.fabric; diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/RootShadowNodeRegistry.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/RootShadowNodeRegistry.java index 95f2c1cedaee02..49884cfc1f243e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/RootShadowNodeRegistry.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/RootShadowNodeRegistry.java @@ -1,3 +1,10 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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.fabric; import android.util.SparseArray; diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/FabricJSCBinding.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/FabricJSCBinding.java index ab7352f9ede0bd..8ae05ff6580893 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/FabricJSCBinding.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/FabricJSCBinding.java @@ -1,4 +1,9 @@ -// Copyright 2004-present Facebook. All Rights Reserved. +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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.fabric.jsc; diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/FabricJSCBinding.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/FabricJSCBinding.cpp index 044143210b1c27..6ce8b9976e34bf 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/FabricJSCBinding.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/FabricJSCBinding.cpp @@ -1,4 +1,9 @@ -// Copyright 2004-present Facebook. All Rights Reserved. +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ #include "FabricJSCBinding.h" #include diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/FabricJSCBinding.h b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/FabricJSCBinding.h index e23c9524ef2026..6327ec690a4278 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/FabricJSCBinding.h +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/FabricJSCBinding.h @@ -1,4 +1,9 @@ -// Copyright 2004-present Facebook. All Rights Reserved. +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ #pragma once diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/OnLoad.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/OnLoad.cpp index 1ca90c4e9d93b7..e6b84dd24c9b63 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/OnLoad.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/OnLoad.cpp @@ -1,4 +1,9 @@ -// Copyright 2004-present Facebook. All Rights Reserved. +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ #include #include From d678058402bd2faad3f6503182386a92109392a9 Mon Sep 17 00:00:00 2001 From: "Andrew Chen (Eng)" Date: Wed, 14 Mar 2018 16:01:32 -0700 Subject: [PATCH 0029/1109] Add Fabric integration test Reviewed By: fkgozali Differential Revision: D7207630 fbshipit-source-id: 69cc10d7d45031eec9f3d934b981a5e4bb62a0ef --- Libraries/ReactNative/AppRegistry.js | 26 +++++++-- .../java/com/facebook/react/testing/BUCK | 2 + .../ReactAppInstrumentationTestCase.java | 17 +++--- .../react/testing/ReactAppTestActivity.java | 54 +++++++++++++++++++ 4 files changed, 90 insertions(+), 9 deletions(-) diff --git a/Libraries/ReactNative/AppRegistry.js b/Libraries/ReactNative/AppRegistry.js index 87bd07a6dd14f2..21fdca68a43d56 100644 --- a/Libraries/ReactNative/AppRegistry.js +++ b/Libraries/ReactNative/AppRegistry.js @@ -20,6 +20,10 @@ const infoLog = require('infoLog'); const invariant = require('fbjs/lib/invariant'); const renderApplication = require('renderApplication'); +// Renderer provider must be supplied by each app. If none, traditional +// renderApplication() will be used. +let fabricRendererProvider: ?() => typeof renderApplication = null; + type Task = (taskData: any) => Promise; type TaskProvider = () => Task; export type ComponentProvider = () => React$ComponentType; @@ -31,6 +35,7 @@ export type AppConfig = { component?: ComponentProvider, run?: Function, section?: boolean, + fabric?: boolean, }; export type Runnable = { component?: ComponentProvider, @@ -80,6 +85,7 @@ const AppRegistry = { appConfig.appKey, appConfig.component, appConfig.section, + appConfig.fabric, ); } }); @@ -94,16 +100,26 @@ const AppRegistry = { appKey: string, componentProvider: ComponentProvider, section?: boolean, + fabric?: boolean, ): string { runnables[appKey] = { componentProvider, - run: appParameters => - renderApplication( + run: appParameters => { + let renderFunc = renderApplication; + if (fabric) { + invariant( + fabricRendererProvider != null, + 'A Fabric renderer provider must be set to render Fabric components', + ); + renderFunc = fabricRendererProvider(); + } + renderFunc( componentProviderInstrumentationHook(componentProvider), appParameters.initialProps, appParameters.rootTag, wrapperComponentProvider && wrapperComponentProvider(appParameters), - ), + ); + }, }; if (section) { sections[appKey] = runnables[appKey]; @@ -236,6 +252,10 @@ const AppRegistry = { NativeModules.HeadlessJsTaskSupport.notifyTaskFinished(taskId); }); }, + + setFabricRendererProvider(provider: () => typeof renderApplication): void { + fabricRendererProvider = provider; + }, }; BatchedBridge.registerCallableModule('AppRegistry', AppRegistry); diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/BUCK b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/BUCK index 9654ee54083e2c..7d96b9b3bb530e 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/BUCK +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/BUCK @@ -27,6 +27,8 @@ 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/devsupport:interfaces"), + react_native_target("java/com/facebook/react/fabric:fabric"), + react_native_target("java/com/facebook/react/fabric/jsc:jsc"), 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/modules/core:core"), diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppInstrumentationTestCase.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppInstrumentationTestCase.java index 8b93eeb8b19a87..863e249cbfe375 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppInstrumentationTestCase.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppInstrumentationTestCase.java @@ -7,19 +7,17 @@ package com.facebook.react.testing; -import javax.annotation.Nullable; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - +import android.content.Intent; import android.graphics.Bitmap; import android.test.ActivityInstrumentationTestCase2; import android.view.View; import android.view.ViewGroup; - import com.facebook.infer.annotation.Assertions; import com.facebook.react.bridge.ReactContext; import com.facebook.react.testing.idledetection.IdleWaiter; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import javax.annotation.Nullable; /** * Base class for instrumentation tests that runs React based react application in UI mode @@ -35,6 +33,9 @@ public ReactAppInstrumentationTestCase() { protected void setUp() throws Exception { super.setUp(); + Intent intent = new Intent(); + intent.putExtra(ReactAppTestActivity.EXTRA_IS_FABRIC_TEST, isFabricTest()); + setActivityIntent(intent); final ReactAppTestActivity activity = getActivity(); try { runTestOnUiThread(new Runnable() { @@ -144,6 +145,10 @@ protected boolean getEnableDevSupport() { return false; } + protected boolean isFabricTest() { + return false; + } + /** * Override this method to provide extra native modules to be loaded before the app starts */ diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java index 96c18030635055..0a68ad1ed5dfcd 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java @@ -7,6 +7,7 @@ package com.facebook.react.testing; +import android.content.Intent; import android.graphics.Bitmap; import android.os.Bundle; import android.support.v4.app.FragmentActivity; @@ -17,8 +18,16 @@ import com.facebook.react.ReactInstanceManager; import com.facebook.react.ReactInstanceManagerBuilder; import com.facebook.react.ReactRootView; +import com.facebook.react.bridge.JSIModule; +import com.facebook.react.bridge.JSIModuleHolder; +import com.facebook.react.bridge.JSIModulesProvider; +import com.facebook.react.bridge.JavaScriptContextHolder; +import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContext; +import com.facebook.react.bridge.UIManager; import com.facebook.react.common.LifecycleState; +import com.facebook.react.fabric.FabricUIManager; +import com.facebook.react.fabric.jsc.FabricJSCBinding; import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; import com.facebook.react.modules.core.PermissionAwareActivity; import com.facebook.react.modules.core.PermissionListener; @@ -26,6 +35,10 @@ import com.facebook.react.testing.idledetection.ReactBridgeIdleSignaler; import com.facebook.react.testing.idledetection.ReactIdleDetectionUtil; import com.facebook.react.uimanager.UIImplementationProvider; +import com.facebook.react.uimanager.ViewManager; +import com.facebook.react.uimanager.ViewManagerRegistry; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import javax.annotation.Nullable; @@ -33,6 +46,8 @@ public class ReactAppTestActivity extends FragmentActivity implements DefaultHardwareBackBtnHandler, PermissionAwareActivity { + public static final String EXTRA_IS_FABRIC_TEST = "is_fabric_test"; + private static final String DEFAULT_BUNDLE_NAME = "AndroidTestBundle.js"; private static final int ROOT_VIEW_ID = 8675309; // we need a bigger timeout for CI builds because they run on a slow emulator @@ -62,6 +77,11 @@ protected void onCreate(Bundle savedInstanceState) { rootView.addView(mScreenshotingFrameLayout); mReactRootView = new ReactRootView(this); + Intent intent = getIntent(); + if (intent != null && intent.getBooleanExtra(EXTRA_IS_FABRIC_TEST, false)) { + mReactRootView.setIsFabric(true); + } + mScreenshotingFrameLayout.addView(mReactRootView); } @@ -179,6 +199,36 @@ public void loadApp( .setUseDeveloperSupport(useDevSupport) .setBridgeIdleDebugListener(mBridgeIdleSignaler) .setInitialLifecycleState(mLifecycleState) + .setJSIModulesProvider( + new JSIModulesProvider() { + @Override + public List getJSIModules( + final ReactApplicationContext reactApplicationContext, + final JavaScriptContextHolder jsContext) { + + List modules = new ArrayList<>(); + modules.add( + new JSIModuleHolder() { + + @Override + public Class getJSIModuleClass() { + return UIManager.class; + } + + @Override + public FabricUIManager getJSIModule() { + List viewManagers = + getReactInstanceManager().getOrCreateViewManagers(reactApplicationContext); + FabricUIManager fabricUIManager = + new FabricUIManager( + reactApplicationContext, new ViewManagerRegistry(viewManagers)); + new FabricJSCBinding().installFabric(jsContext, fabricUIManager); + return fabricUIManager; + } + }); + + return modules; + }}) .setUIImplementationProvider(uiImplementationProvider); mReactInstanceManager = builder.build(); @@ -195,6 +245,10 @@ public void onGlobalLayout() { .startReactApplication(mReactInstanceManager, appKey, initialProps); } + private ReactInstanceManager getReactInstanceManager() { + return mReactInstanceManager; + } + public boolean waitForLayout(long millis) throws InterruptedException { return mLayoutEvent.await(millis, TimeUnit.MILLISECONDS); } From 22004db81912f66650e9f9776d0045b88df61b5b Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Wed, 14 Mar 2018 23:23:11 -0700 Subject: [PATCH 0030/1109] React sync for revisions ad9544f...ced176e Reviewed By: sebmarkbage Differential Revision: D7281277 fbshipit-source-id: 75a638114cf2a65a5c973dbdf218f6d3ba042cc4 --- Libraries/Renderer/REVISION | 2 +- Libraries/Renderer/ReactFabric-dev.js | 55 +++++++++++++++---- Libraries/Renderer/ReactFabric-prod.js | 51 ++++++++++------- Libraries/Renderer/ReactNativeRenderer-dev.js | 55 +++++++++++++++---- .../Renderer/ReactNativeRenderer-prod.js | 49 ++++++++++------- Libraries/Renderer/shims/ReactTypes.js | 2 +- package.json | 6 +- 7 files changed, 153 insertions(+), 67 deletions(-) diff --git a/Libraries/Renderer/REVISION b/Libraries/Renderer/REVISION index 824ff8c33a4c4f..3210553184230d 100644 --- a/Libraries/Renderer/REVISION +++ b/Libraries/Renderer/REVISION @@ -1 +1 @@ -ad9544f48e58f2599a8ea0de1e9f4dd104db30bb \ No newline at end of file +ced176edb7605a25e916895fd060f3943c647fee \ No newline at end of file diff --git a/Libraries/Renderer/ReactFabric-dev.js b/Libraries/Renderer/ReactFabric-dev.js index 867873cd41d55b..e485c562182322 100644 --- a/Libraries/Renderer/ReactFabric-dev.js +++ b/Libraries/Renderer/ReactFabric-dev.js @@ -810,6 +810,7 @@ var Fragment = 10; var Mode = 11; var ContextConsumer = 12; var ContextProvider = 13; +var ForwardRef = 14; function getParent(inst) { do { @@ -2356,6 +2357,9 @@ var REACT_CONTEXT_TYPE = hasSymbol ? Symbol["for"]("react.context") : 0xeace; var REACT_ASYNC_MODE_TYPE = hasSymbol ? Symbol["for"]("react.async_mode") : 0xeacf; +var REACT_FORWARD_REF_TYPE = hasSymbol + ? Symbol["for"]("react.forward_ref") + : 0xead0; var MAYBE_ITERATOR_SYMBOL = typeof Symbol === "function" && Symbol.iterator; var FAUX_ITERATOR_SYMBOL = "@@iterator"; @@ -2637,7 +2641,7 @@ var TouchHistoryMath = { // TODO: this is special because it gets imported during build. -var ReactVersion = "16.3.0-alpha.1"; +var ReactVersion = "16.3.0-alpha.2"; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { @@ -5242,6 +5246,9 @@ function createFiberFromElement(element, mode, expirationTime) { // This is a consumer fiberTag = ContextConsumer; break; + case REACT_FORWARD_REF_TYPE: + fiberTag = ForwardRef; + break; default: if (typeof type.tag === "number") { // Currently assumed to be a continuation and therefore is a @@ -6834,20 +6841,20 @@ var ReactFiberClassComponent = function( // In order to support react-lifecycles-compat polyfilled components, // Unsafe lifecycles should not be invoked for any component with the new gDSFP. if ( - (typeof instance.UNSAFE_componentWillUpdate === "function" || - typeof instance.componentWillUpdate === "function") && + (typeof instance.UNSAFE_componentWillMount === "function" || + typeof instance.componentWillMount === "function") && typeof ctor.getDerivedStateFromProps !== "function" ) { - startPhaseTimer(workInProgress, "componentWillUpdate"); - if (typeof instance.componentWillUpdate === "function") { - instance.componentWillUpdate(newProps, newState, newContext); + startPhaseTimer(workInProgress, "componentWillMount"); + if (typeof instance.componentWillMount === "function") { + instance.componentWillMount(); } - if (typeof instance.UNSAFE_componentWillUpdate === "function") { - instance.UNSAFE_componentWillUpdate(newProps, newState, newContext); + if (typeof instance.UNSAFE_componentWillMount === "function") { + instance.UNSAFE_componentWillMount(); } stopPhaseTimer(); } - if (typeof instance.componentDidUpdate === "function") { + if (typeof instance.componentDidMount === "function") { workInProgress.effectTag |= Update; } } else { @@ -8467,6 +8474,14 @@ var ReactFiberBeginWork = function( } } + function updateForwardRef(current, workInProgress) { + var render = workInProgress.type.render; + var nextChildren = render(workInProgress.pendingProps, workInProgress.ref); + reconcileChildren(current, workInProgress, nextChildren); + memoizeProps(workInProgress, nextChildren); + return workInProgress.child; + } + function updateFragment(current, workInProgress) { var nextChildren = workInProgress.pendingProps; if (hasContextChanged()) { @@ -9420,6 +9435,8 @@ var ReactFiberBeginWork = function( workInProgress, renderExpirationTime ); + case ForwardRef: + return updateForwardRef(current, workInProgress); case Fragment: return updateFragment(current, workInProgress); case Mode: @@ -9972,6 +9989,8 @@ var ReactFiberCompleteWork = function(config, hostContext, hydrationContext) { case ReturnComponent: // Does nothing. return null; + case ForwardRef: + return null; case Fragment: return null; case Mode: @@ -10277,7 +10296,7 @@ var ReactFiberCommitWork = function( } } } else { - ref.value = null; + ref.current = null; } } } @@ -10442,7 +10461,19 @@ var ReactFiberCommitWork = function( if (typeof ref === "function") { ref(instanceToUse); } else { - ref.value = instanceToUse; + { + if (!ref.hasOwnProperty("current")) { + warning( + false, + "Unexpected ref object provided for %s. " + + "Use either a ref-setter function or Reacte.createRef().%s", + getComponentName(finishedWork), + getStackAddendumByWorkInProgressFiber(finishedWork) + ); + } + } + + ref.current = instanceToUse; } } } @@ -10453,7 +10484,7 @@ var ReactFiberCommitWork = function( if (typeof currentRef === "function") { currentRef(null); } else { - currentRef.value = null; + currentRef.current = null; } } } diff --git a/Libraries/Renderer/ReactFabric-prod.js b/Libraries/Renderer/ReactFabric-prod.js index 950e09890f8203..637481f04146cb 100644 --- a/Libraries/Renderer/ReactFabric-prod.js +++ b/Libraries/Renderer/ReactFabric-prod.js @@ -945,6 +945,9 @@ var hasSymbol = "function" === typeof Symbol && Symbol["for"], REACT_PROVIDER_TYPE = hasSymbol ? Symbol["for"]("react.provider") : 60109, REACT_CONTEXT_TYPE = hasSymbol ? Symbol["for"]("react.context") : 60110, REACT_ASYNC_MODE_TYPE = hasSymbol ? Symbol["for"]("react.async_mode") : 60111, + REACT_FORWARD_REF_TYPE = hasSymbol + ? Symbol["for"]("react.forward_ref") + : 60112, MAYBE_ITERATOR_SYMBOL = "function" === typeof Symbol && Symbol.iterator; function getIteratorFn(maybeIterable) { if (null === maybeIterable || "undefined" === typeof maybeIterable) @@ -1843,6 +1846,9 @@ function createFiberFromElement(element, mode, expirationTime) { case REACT_CONTEXT_TYPE: fiberTag = 12; break; + case REACT_FORWARD_REF_TYPE: + fiberTag = 14; + break; default: if ("number" === typeof type.tag) return ( @@ -2312,22 +2318,14 @@ function ReactFiberClassComponent( renderExpirationTime, newUnmaskedContext )) - ? (("function" !== typeof instance.UNSAFE_componentWillUpdate && - "function" !== typeof instance.componentWillUpdate) || + ? (("function" !== typeof instance.UNSAFE_componentWillMount && + "function" !== typeof instance.componentWillMount) || "function" === typeof ctor.getDerivedStateFromProps || - ("function" === typeof instance.componentWillUpdate && - instance.componentWillUpdate( - newProps, - renderExpirationTime, - newUnmaskedContext - ), - "function" === typeof instance.UNSAFE_componentWillUpdate && - instance.UNSAFE_componentWillUpdate( - newProps, - renderExpirationTime, - newUnmaskedContext - )), - "function" === typeof instance.componentDidUpdate && + ("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), @@ -3669,6 +3667,17 @@ function ReactFiberBeginWork( )), current ); + case 14: + return ( + (renderExpirationTime = workInProgress.type.render), + (renderExpirationTime = renderExpirationTime( + workInProgress.pendingProps, + workInProgress.ref + )), + reconcileChildren(current, workInProgress, renderExpirationTime), + (workInProgress.memoizedProps = renderExpirationTime), + workInProgress.child + ); case 10: return ( (renderExpirationTime = workInProgress.pendingProps), @@ -4058,6 +4067,8 @@ function ReactFiberCompleteWork(config, hostContext, hydrationContext) { return (workInProgress.tag = 7), null; case 9: return null; + case 14: + return null; case 10: return null; case 11: @@ -4191,7 +4202,7 @@ function ReactFiberCommitWork( } catch (refError) { captureError(current, refError); } - else ref.value = null; + else ref.current = null; } function commitLifeCycles(finishedRoot, current, finishedWork) { switch (finishedWork.tag) { @@ -4305,13 +4316,15 @@ function ReactFiberCommitWork( } "function" === typeof ref ? ref(finishedWork) - : (ref.value = finishedWork); + : (ref.current = finishedWork); } } function commitDetachRef(current) { current = current.ref; null !== current && - ("function" === typeof current ? current(null) : (current.value = null)); + ("function" === typeof current + ? current(null) + : (current.current = null)); } function commitNestedUnmounts(root) { for (var node = root; ; ) { @@ -5891,7 +5904,7 @@ ReactFabricRenderer.injectIntoDevTools({ findFiberByHostInstance: getInstanceFromTag, getInspectorDataForViewTag: getInspectorDataForViewTag, bundleType: 0, - version: "16.3.0-alpha.1", + version: "16.3.0-alpha.2", rendererPackageName: "react-native-renderer" }); var ReactFabric$2 = Object.freeze({ default: ReactFabric }), diff --git a/Libraries/Renderer/ReactNativeRenderer-dev.js b/Libraries/Renderer/ReactNativeRenderer-dev.js index 400472d29a3875..d54c9f31c6cda3 100644 --- a/Libraries/Renderer/ReactNativeRenderer-dev.js +++ b/Libraries/Renderer/ReactNativeRenderer-dev.js @@ -965,6 +965,7 @@ var Fragment = 10; var Mode = 11; var ContextConsumer = 12; var ContextProvider = 13; +var ForwardRef = 14; function getParent(inst) { do { @@ -2802,6 +2803,9 @@ var REACT_CONTEXT_TYPE = hasSymbol ? Symbol["for"]("react.context") : 0xeace; var REACT_ASYNC_MODE_TYPE = hasSymbol ? Symbol["for"]("react.async_mode") : 0xeacf; +var REACT_FORWARD_REF_TYPE = hasSymbol + ? Symbol["for"]("react.forward_ref") + : 0xead0; var MAYBE_ITERATOR_SYMBOL = typeof Symbol === "function" && Symbol.iterator; var FAUX_ITERATOR_SYMBOL = "@@iterator"; @@ -2983,7 +2987,7 @@ var TouchHistoryMath = { // TODO: this is special because it gets imported during build. -var ReactVersion = "16.3.0-alpha.1"; +var ReactVersion = "16.3.0-alpha.2"; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { @@ -5500,6 +5504,9 @@ function createFiberFromElement(element, mode, expirationTime) { // This is a consumer fiberTag = ContextConsumer; break; + case REACT_FORWARD_REF_TYPE: + fiberTag = ForwardRef; + break; default: if (typeof type.tag === "number") { // Currently assumed to be a continuation and therefore is a @@ -7092,20 +7099,20 @@ var ReactFiberClassComponent = function( // In order to support react-lifecycles-compat polyfilled components, // Unsafe lifecycles should not be invoked for any component with the new gDSFP. if ( - (typeof instance.UNSAFE_componentWillUpdate === "function" || - typeof instance.componentWillUpdate === "function") && + (typeof instance.UNSAFE_componentWillMount === "function" || + typeof instance.componentWillMount === "function") && typeof ctor.getDerivedStateFromProps !== "function" ) { - startPhaseTimer(workInProgress, "componentWillUpdate"); - if (typeof instance.componentWillUpdate === "function") { - instance.componentWillUpdate(newProps, newState, newContext); + startPhaseTimer(workInProgress, "componentWillMount"); + if (typeof instance.componentWillMount === "function") { + instance.componentWillMount(); } - if (typeof instance.UNSAFE_componentWillUpdate === "function") { - instance.UNSAFE_componentWillUpdate(newProps, newState, newContext); + if (typeof instance.UNSAFE_componentWillMount === "function") { + instance.UNSAFE_componentWillMount(); } stopPhaseTimer(); } - if (typeof instance.componentDidUpdate === "function") { + if (typeof instance.componentDidMount === "function") { workInProgress.effectTag |= Update; } } else { @@ -8725,6 +8732,14 @@ var ReactFiberBeginWork = function( } } + function updateForwardRef(current, workInProgress) { + var render = workInProgress.type.render; + var nextChildren = render(workInProgress.pendingProps, workInProgress.ref); + reconcileChildren(current, workInProgress, nextChildren); + memoizeProps(workInProgress, nextChildren); + return workInProgress.child; + } + function updateFragment(current, workInProgress) { var nextChildren = workInProgress.pendingProps; if (hasContextChanged()) { @@ -9678,6 +9693,8 @@ var ReactFiberBeginWork = function( workInProgress, renderExpirationTime ); + case ForwardRef: + return updateForwardRef(current, workInProgress); case Fragment: return updateFragment(current, workInProgress); case Mode: @@ -10230,6 +10247,8 @@ var ReactFiberCompleteWork = function(config, hostContext, hydrationContext) { case ReturnComponent: // Does nothing. return null; + case ForwardRef: + return null; case Fragment: return null; case Mode: @@ -10569,7 +10588,7 @@ var ReactFiberCommitWork = function( } } } else { - ref.value = null; + ref.current = null; } } } @@ -10734,7 +10753,19 @@ var ReactFiberCommitWork = function( if (typeof ref === "function") { ref(instanceToUse); } else { - ref.value = instanceToUse; + { + if (!ref.hasOwnProperty("current")) { + warning( + false, + "Unexpected ref object provided for %s. " + + "Use either a ref-setter function or Reacte.createRef().%s", + getComponentName(finishedWork), + getStackAddendumByWorkInProgressFiber(finishedWork) + ); + } + } + + ref.current = instanceToUse; } } } @@ -10745,7 +10776,7 @@ var ReactFiberCommitWork = function( if (typeof currentRef === "function") { currentRef(null); } else { - currentRef.value = null; + currentRef.current = null; } } } diff --git a/Libraries/Renderer/ReactNativeRenderer-prod.js b/Libraries/Renderer/ReactNativeRenderer-prod.js index ca27b720b33dfe..258608b7f31a6b 100644 --- a/Libraries/Renderer/ReactNativeRenderer-prod.js +++ b/Libraries/Renderer/ReactNativeRenderer-prod.js @@ -1174,6 +1174,9 @@ var hasSymbol = "function" === typeof Symbol && Symbol["for"], REACT_PROVIDER_TYPE = hasSymbol ? Symbol["for"]("react.provider") : 60109, REACT_CONTEXT_TYPE = hasSymbol ? Symbol["for"]("react.context") : 60110, REACT_ASYNC_MODE_TYPE = hasSymbol ? Symbol["for"]("react.async_mode") : 60111, + REACT_FORWARD_REF_TYPE = hasSymbol + ? Symbol["for"]("react.forward_ref") + : 60112, MAYBE_ITERATOR_SYMBOL = "function" === typeof Symbol && Symbol.iterator; function getIteratorFn(maybeIterable) { if (null === maybeIterable || "undefined" === typeof maybeIterable) @@ -2037,6 +2040,9 @@ function createFiberFromElement(element, mode, expirationTime) { case REACT_CONTEXT_TYPE: fiberTag = 12; break; + case REACT_FORWARD_REF_TYPE: + fiberTag = 14; + break; default: if ("number" === typeof type.tag) return ( @@ -2551,22 +2557,14 @@ function ReactFiberClassComponent( renderExpirationTime, newUnmaskedContext )) - ? (("function" !== typeof instance.UNSAFE_componentWillUpdate && - "function" !== typeof instance.componentWillUpdate) || + ? (("function" !== typeof instance.UNSAFE_componentWillMount && + "function" !== typeof instance.componentWillMount) || "function" === typeof ctor.getDerivedStateFromProps || - ("function" === typeof instance.componentWillUpdate && - instance.componentWillUpdate( - newProps, - renderExpirationTime, - newUnmaskedContext - ), - "function" === typeof instance.UNSAFE_componentWillUpdate && - instance.UNSAFE_componentWillUpdate( - newProps, - renderExpirationTime, - newUnmaskedContext - )), - "function" === typeof instance.componentDidUpdate && + ("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), @@ -3932,6 +3930,17 @@ function ReactFiberBeginWork( )), current ); + case 14: + return ( + (renderExpirationTime = workInProgress.type.render), + (renderExpirationTime = renderExpirationTime( + workInProgress.pendingProps, + workInProgress.ref + )), + reconcileChildren(current, workInProgress, renderExpirationTime), + (workInProgress.memoizedProps = renderExpirationTime), + workInProgress.child + ); case 10: return ( (renderExpirationTime = workInProgress.pendingProps), @@ -4263,6 +4272,8 @@ function ReactFiberCompleteWork(config, hostContext, hydrationContext) { return (workInProgress.tag = 7), null; case 9: return null; + case 14: + return null; case 10: return null; case 11: @@ -4415,7 +4426,7 @@ function ReactFiberCommitWork( } catch (refError) { captureError(current, refError); } - else ref.value = null; + else ref.current = null; } function commitUnmount(current) { "function" === typeof onCommitUnmount && onCommitUnmount(current); @@ -4795,7 +4806,7 @@ function ReactFiberCommitWork( } "function" === typeof ref ? ref(finishedWork) - : (ref.value = finishedWork); + : (ref.current = finishedWork); } }, commitDetachRef: function(current) { @@ -4803,7 +4814,7 @@ function ReactFiberCommitWork( null !== current && ("function" === typeof current ? current(null) - : (current.value = null)); + : (current.current = null)); } }; } @@ -6352,7 +6363,7 @@ NativeRenderer.injectIntoDevTools({ findFiberByHostInstance: getInstanceFromTag, getInspectorDataForViewTag: getInspectorDataForViewTag, bundleType: 0, - version: "16.3.0-alpha.1", + version: "16.3.0-alpha.2", rendererPackageName: "react-native-renderer" }); var ReactNativeRenderer$2 = Object.freeze({ default: ReactNativeRenderer }), diff --git a/Libraries/Renderer/shims/ReactTypes.js b/Libraries/Renderer/shims/ReactTypes.js index bede9f00e30069..f6a56ccc96ed4e 100644 --- a/Libraries/Renderer/shims/ReactTypes.js +++ b/Libraries/Renderer/shims/ReactTypes.js @@ -101,5 +101,5 @@ export type ReactPortal = { }; export type RefObject = {| - value: any, + current: any, |}; diff --git a/package.json b/package.json index 5c554719e5f0a9..bc2e7cd11a03fb 100644 --- a/package.json +++ b/package.json @@ -142,7 +142,7 @@ "react-native": "local-cli/wrong-react-native.js" }, "peerDependencies": { - "react": "^16.3.0-alpha.0" + "react": "^16.3.0-alpha.2" }, "dependencies": { "absolute-path": "^0.0.0", @@ -219,8 +219,8 @@ "jest": "22.4.2", "jest-junit": "3.6.0", "prettier": "1.9.1", - "react": "^16.3.0-alpha.1", - "react-test-renderer": "^16.3.0-alpha.1", + "react": "^16.3.0-alpha.2", + "react-test-renderer": "^16.3.0-alpha.2", "shelljs": "^0.7.8", "sinon": "^2.2.0" } From 6b1dc7174082a78a283c922ac975642bb2862fba Mon Sep 17 00:00:00 2001 From: Peter van der Zee Date: Thu, 15 Mar 2018 06:46:12 -0700 Subject: [PATCH 0031/1109] Refactor resolvePlugins out to prepare for babel 7 Reviewed By: BYK Differential Revision: D7287074 fbshipit-source-id: ec703f7292b63b679dbad055a6e43ac907729bfe --- babel-preset/configs/main.js | 64 ++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 35 deletions(-) diff --git a/babel-preset/configs/main.js b/babel-preset/configs/main.js index dca6ddebd8e216..96405f002f9538 100644 --- a/babel-preset/configs/main.js +++ b/babel-preset/configs/main.js @@ -4,47 +4,41 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ -'use strict'; -const resolvePlugins = require('../lib/resolvePlugins'); -const resolvePlugin = resolvePlugins.resolvePlugin; +'use strict'; -const defaultPlugins = resolvePlugins([ - 'syntax-class-properties', - 'syntax-trailing-function-commas', - 'transform-class-properties', - 'transform-es2015-block-scoping', - 'transform-es2015-computed-properties', - 'transform-es2015-destructuring', - 'transform-es2015-function-name', - 'transform-es2015-literals', - 'transform-es2015-parameters', - 'transform-es2015-shorthand-properties', - 'transform-flow-strip-types', - 'transform-react-jsx', - 'transform-regenerator', +const defaultPlugins = [ + [require('babel-plugin-syntax-class-properties')], + [require('babel-plugin-syntax-trailing-function-commas')], + [require('babel-plugin-transform-class-properties')], + [require('babel-plugin-transform-es2015-block-scoping')], + [require('babel-plugin-transform-es2015-computed-properties')], + [require('babel-plugin-transform-es2015-destructuring')], + [require('babel-plugin-transform-es2015-function-name')], + [require('babel-plugin-transform-es2015-literals')], + [require('babel-plugin-transform-es2015-parameters')], + [require('babel-plugin-transform-es2015-shorthand-properties')], + [require('babel-plugin-transform-flow-strip-types')], + [require('babel-plugin-transform-react-jsx')], + [require('babel-plugin-transform-regenerator')], [ - 'transform-es2015-modules-commonjs', + require('babel-plugin-transform-es2015-modules-commonjs'), {strict: false, allowTopLevelThis: true}, ], -]); +]; -const checkES2015Constants = resolvePlugin('check-es2015-constants'); -const es2015ArrowFunctions = resolvePlugin('transform-es2015-arrow-functions'); -const es2015Classes = resolvePlugin('transform-es2015-classes'); -const es2015ForOf = resolvePlugin(['transform-es2015-for-of', {loose: true}]); -const es2015Spread = resolvePlugin('transform-es2015-spread'); -const es2015TemplateLiterals = resolvePlugin( - 'transform-es2015-template-literals' -); -const asyncFunctions = resolvePlugin('syntax-async-functions'); -const exponentiationOperator = resolvePlugin( - 'transform-exponentiation-operator' -); -const objectAssign = resolvePlugin('transform-object-assign'); -const objectRestSpread = resolvePlugin('transform-object-rest-spread'); -const reactDisplayName = resolvePlugin('transform-react-display-name'); -const reactJsxSource = resolvePlugin('transform-react-jsx-source'); +const checkES2015Constants = [require('babel-plugin-check-es2015-constants')]; +const es2015ArrowFunctions = [require('babel-plugin-transform-es2015-arrow-functions')]; +const es2015Classes = [require('babel-plugin-transform-es2015-classes')]; +const es2015ForOf = [require('babel-plugin-transform-es2015-for-of'), {loose: true}]; +const es2015Spread = [require('babel-plugin-transform-es2015-spread')]; +const es2015TemplateLiterals = [require('babel-plugin-transform-es2015-template-literals')]; +const asyncFunctions = [require('babel-plugin-syntax-async-functions')]; +const exponentiationOperator = [require('babel-plugin-transform-exponentiation-operator')]; +const objectAssign = [require('babel-plugin-transform-object-assign')]; +const objectRestSpread = [require('babel-plugin-transform-object-rest-spread')]; +const reactDisplayName = [require('babel-plugin-transform-react-display-name')]; +const reactJsxSource = [require('babel-plugin-transform-react-jsx-source')]; const symbolMember = [require('../transforms/transform-symbol-member')]; const getPreset = (src, options) => { From 040642dba3a64c7ab650e4968feeca03a0c01639 Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Thu, 15 Mar 2018 07:13:02 -0700 Subject: [PATCH 0032/1109] Fix setter and getter of margin, position, border and padding Reviewed By: emilsjolander Differential Revision: D7274115 fbshipit-source-id: 942a91e6562ef789ae79102a828f397889468fa7 --- ReactCommon/yoga/yoga/YGNodePrint.cpp | 5 +++- ReactCommon/yoga/yoga/Yoga.cpp | 34 +++++++-------------------- 2 files changed, 13 insertions(+), 26 deletions(-) diff --git a/ReactCommon/yoga/yoga/YGNodePrint.cpp b/ReactCommon/yoga/yoga/YGNodePrint.cpp index 8585b725171fb2..ab0666d07eb59e 100644 --- a/ReactCommon/yoga/yoga/YGNodePrint.cpp +++ b/ReactCommon/yoga/yoga/YGNodePrint.cpp @@ -72,7 +72,10 @@ appendNumberIfNotAuto(string* base, const string& key, const YGValue number) { static void appendNumberIfNotZero(string* base, const string& str, const YGValue number) { - if (!YGFloatsEqual(number.value, 0)) { + + if (number.unit == YGUnitAuto) { + base->append(str + ": auto; "); + } else if (!YGFloatsEqual(number.value, 0)) { appendNumberIfNotUndefined(base, str, number); } } diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index b5e1e4c044f54c..5ccb6b1eff3d1c 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -637,7 +637,7 @@ float YGNodeStyleGetFlexShrink(const YGNodeRef node) { void YGNodeStyleSet##name##Auto(const YGNodeRef node, const YGEdge edge) { \ if (node->getStyle().instanceName[edge].unit != YGUnitAuto) { \ YGStyle style = node->getStyle(); \ - style.instanceName[edge].value = YGUndefined; \ + style.instanceName[edge].value = 0; \ style.instanceName[edge].unit = YGUnitAuto; \ node->setStyle(style); \ node->markDirtyAndPropogate(); \ @@ -649,7 +649,7 @@ float YGNodeStyleGetFlexShrink(const YGNodeRef node) { void YGNodeStyleSet##name( \ const YGNodeRef node, const YGEdge edge, const float paramName) { \ YGValue value = { \ - .value = paramName, \ + .value = YGFloatSanitize(paramName), \ .unit = YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \ }; \ if ((node->getStyle().instanceName[edge].value != value.value && \ @@ -665,7 +665,7 @@ float YGNodeStyleGetFlexShrink(const YGNodeRef node) { void YGNodeStyleSet##name##Percent( \ const YGNodeRef node, const YGEdge edge, const float paramName) { \ YGValue value = { \ - .value = paramName, \ + .value = YGFloatSanitize(paramName), \ .unit = \ YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPercent, \ }; \ @@ -681,28 +681,11 @@ float YGNodeStyleGetFlexShrink(const YGNodeRef node) { \ WIN_STRUCT(type) \ YGNodeStyleGet##name(const YGNodeRef node, const YGEdge edge) { \ - return WIN_STRUCT_REF(node->getStyle().instanceName[edge]); \ - } - -#define YG_NODE_STYLE_EDGE_PROPERTY_IMPL(type, name, paramName, instanceName) \ - void YGNodeStyleSet##name( \ - const YGNodeRef node, const YGEdge edge, const float paramName) { \ - YGValue value = { \ - .value = paramName, \ - .unit = YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \ - }; \ - if ((node->getStyle().instanceName[edge].value != value.value && \ - value.unit != YGUnitUndefined) || \ - node->getStyle().instanceName[edge].unit != value.unit) { \ - YGStyle style = node->getStyle(); \ - style.instanceName[edge] = value; \ - node->setStyle(style); \ - node->markDirtyAndPropogate(); \ + YGValue value = node->getStyle().instanceName[edge]; \ + if (value.unit == YGUnitUndefined || value.unit == YGUnitAuto) { \ + value.value = YGUndefined; \ } \ - } \ - \ - float YGNodeStyleGet##name(const YGNodeRef node, const YGEdge edge) { \ - return node->getStyle().instanceName[edge].value; \ + return WIN_STRUCT_REF(value); \ } #define YG_NODE_LAYOUT_PROPERTY_IMPL(type, name, instanceName) \ @@ -873,7 +856,8 @@ void YGNodeStyleSetBorder( } float YGNodeStyleGetBorder(const YGNodeRef node, const YGEdge edge) { - if (node->getStyle().border[edge].unit == YGUnitUndefined) { + if (node->getStyle().border[edge].unit == YGUnitUndefined || + node->getStyle().border[edge].unit == YGUnitAuto) { // TODO(T26792433): Rather than returning YGUndefined, change the api to // return YGFloatOptional. return YGUndefined; From da2d410122fd2072497f55a9934325f38cfcbba7 Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Thu, 15 Mar 2018 07:13:03 -0700 Subject: [PATCH 0033/1109] Fix getters and setters if min and max Dimension Reviewed By: emilsjolander Differential Revision: D7274807 fbshipit-source-id: 7c1a4c19e8d0552b089a410c3330392cb26a6a47 --- ReactCommon/yoga/yoga/Yoga.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index 5ccb6b1eff3d1c..e38ff26870c0f9 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -538,7 +538,7 @@ float YGNodeStyleGetFlexShrink(const YGNodeRef node) { type, name, paramName, instanceName) \ void YGNodeStyleSet##name(const YGNodeRef node, const type paramName) { \ YGValue value = { \ - .value = paramName, \ + .value = YGFloatSanitize(paramName), \ .unit = YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \ }; \ if ((node->getStyle().instanceName.value != value.value && \ @@ -554,7 +554,7 @@ float YGNodeStyleGetFlexShrink(const YGNodeRef node) { void YGNodeStyleSet##name##Percent( \ const YGNodeRef node, const type paramName) { \ YGValue value = { \ - .value = paramName, \ + .value = YGFloatSanitize(paramName), \ .unit = \ YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPercent, \ }; \ @@ -621,7 +621,11 @@ float YGNodeStyleGetFlexShrink(const YGNodeRef node) { float, name, paramName, instanceName) \ \ type YGNodeStyleGet##name(const YGNodeRef node) { \ - return node->getStyle().instanceName; \ + YGValue value = node->getStyle().instanceName; \ + if (value.unit == YGUndefined || value.unit == YGUnitAuto) { \ + value.value = YGUndefined; \ + } \ + return value; \ } #define YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL( \ From c989ea87281f9ee667090b119469754035dfcd7e Mon Sep 17 00:00:00 2001 From: Dmitry Zakharov Date: Thu, 15 Mar 2018 09:21:04 -0700 Subject: [PATCH 0034/1109] Extract NativeExtensionsProvider definition Reviewed By: danzimm Differential Revision: D6964355 fbshipit-source-id: e20dfa99bd9d8784a5f31a313302104d6dc33652 --- ReactAndroid/src/main/jni/react/jni/AndroidJSCFactory.cpp | 2 +- ReactAndroid/src/main/jni/react/jni/AndroidJSCFactory.h | 3 ++- ReactCommon/cxxreact/JSCExecutor.cpp | 2 +- ReactCommon/cxxreact/JSCExecutor.h | 8 ++++---- ReactCommon/cxxreact/JSExecutor.h | 2 ++ 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/ReactAndroid/src/main/jni/react/jni/AndroidJSCFactory.cpp b/ReactAndroid/src/main/jni/react/jni/AndroidJSCFactory.cpp index ed551a61a2b590..73d774e7d5d8f1 100644 --- a/ReactAndroid/src/main/jni/react/jni/AndroidJSCFactory.cpp +++ b/ReactAndroid/src/main/jni/react/jni/AndroidJSCFactory.cpp @@ -90,7 +90,7 @@ void injectJSCExecutorAndroidPlatform() { } std::unique_ptr makeAndroidJSCExecutorFactory( - const folly::dynamic& jscConfig, std::function nativeExtensionsProvider) { + const folly::dynamic& jscConfig, NativeExtensionsProvider nativeExtensionsProvider) { detail::injectJSCExecutorAndroidPlatform(); return folly::make_unique(std::move(jscConfig), std::move(nativeExtensionsProvider)); } diff --git a/ReactAndroid/src/main/jni/react/jni/AndroidJSCFactory.h b/ReactAndroid/src/main/jni/react/jni/AndroidJSCFactory.h index e1e782145c91e8..5de2f99eefc7e9 100644 --- a/ReactAndroid/src/main/jni/react/jni/AndroidJSCFactory.h +++ b/ReactAndroid/src/main/jni/react/jni/AndroidJSCFactory.h @@ -3,6 +3,7 @@ #pragma once #include +#include namespace folly { @@ -23,7 +24,7 @@ void injectJSCExecutorAndroidPlatform(); } std::unique_ptr makeAndroidJSCExecutorFactory( - const folly::dynamic& jscConfig, std::function nativeExtensionsProvider); + const folly::dynamic& jscConfig, NativeExtensionsProvider nativeExtensionsProvider); } } diff --git a/ReactCommon/cxxreact/JSCExecutor.cpp b/ReactCommon/cxxreact/JSCExecutor.cpp index 81e71eddbaa5e9..ddae9fdda4b678 100644 --- a/ReactCommon/cxxreact/JSCExecutor.cpp +++ b/ReactCommon/cxxreact/JSCExecutor.cpp @@ -121,7 +121,7 @@ namespace facebook { JSCExecutor::JSCExecutor(std::shared_ptr delegate, std::shared_ptr messageQueueThread, const folly::dynamic& jscConfig, - std::function nativeExtensionsProvider) throw(JSException) : + NativeExtensionsProvider nativeExtensionsProvider) throw(JSException) : m_delegate(delegate), m_messageQueueThread(messageQueueThread), m_nativeModules(delegate ? delegate->getModuleRegistry() : nullptr), diff --git a/ReactCommon/cxxreact/JSCExecutor.h b/ReactCommon/cxxreact/JSCExecutor.h index 5acc967722e5ca..44b13aa94b2a20 100644 --- a/ReactCommon/cxxreact/JSCExecutor.h +++ b/ReactCommon/cxxreact/JSCExecutor.h @@ -27,7 +27,7 @@ class RAMBundleRegistry; class RN_EXPORT JSCExecutorFactory : public JSExecutorFactory { public: - JSCExecutorFactory(const folly::dynamic& jscConfig, std::function provider) : + JSCExecutorFactory(const folly::dynamic& jscConfig, NativeExtensionsProvider provider) : m_jscConfig(jscConfig), m_nativeExtensionsProvider(provider) {} std::unique_ptr createJSExecutor( std::shared_ptr delegate, @@ -35,7 +35,7 @@ class RN_EXPORT JSCExecutorFactory : public JSExecutorFactory { private: std::string m_cacheDir; folly::dynamic m_jscConfig; - std::function m_nativeExtensionsProvider; + NativeExtensionsProvider m_nativeExtensionsProvider; }; template @@ -60,7 +60,7 @@ class RN_EXPORT JSCExecutor : public JSExecutor, public PrivateDataBase { explicit JSCExecutor(std::shared_ptr delegate, std::shared_ptr messageQueueThread, const folly::dynamic& jscConfig, - std::function nativeExtensionsProvider) throw(JSException); + NativeExtensionsProvider nativeExtensionsProvider) throw(JSException); ~JSCExecutor() override; virtual void loadApplicationScript( @@ -106,7 +106,7 @@ class RN_EXPORT JSCExecutor : public JSExecutor, public PrivateDataBase { JSCNativeModules m_nativeModules; folly::dynamic m_jscConfig; std::once_flag m_bindFlag; - std::function m_nativeExtensionsProvider; + NativeExtensionsProvider m_nativeExtensionsProvider; folly::Optional m_invokeCallbackAndReturnFlushedQueueJS; folly::Optional m_callFunctionReturnFlushedQueueJS; diff --git a/ReactCommon/cxxreact/JSExecutor.h b/ReactCommon/cxxreact/JSExecutor.h index 91bc070c493789..85b4bfcb0364ee 100644 --- a/ReactCommon/cxxreact/JSExecutor.h +++ b/ReactCommon/cxxreact/JSExecutor.h @@ -32,6 +32,8 @@ class ExecutorDelegate { JSExecutor& executor, unsigned int moduleId, unsigned int methodId, folly::dynamic&& args) = 0; }; +using NativeExtensionsProvider = std::function; + class JSExecutorFactory { public: virtual std::unique_ptr createJSExecutor( From 8e85bf84e8139caebc79d2034313ff0f4c936bea Mon Sep 17 00:00:00 2001 From: Dmitry Zakharov Date: Thu, 15 Mar 2018 09:21:08 -0700 Subject: [PATCH 0035/1109] Gatekeeper for Native Extensions Reviewed By: danzimm, johnislarry Differential Revision: D6965463 fbshipit-source-id: 28bcfbff980abfda3c63d7016ccf05beb1d178eb --- ReactCommon/cxxreact/JSCExecutor.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ReactCommon/cxxreact/JSCExecutor.cpp b/ReactCommon/cxxreact/JSCExecutor.cpp index ddae9fdda4b678..a7d8c72cbf7048 100644 --- a/ReactCommon/cxxreact/JSCExecutor.cpp +++ b/ReactCommon/cxxreact/JSCExecutor.cpp @@ -134,8 +134,10 @@ namespace facebook { installGlobalProxy(m_context, "nativeModuleProxy", exceptionWrapMethod<&JSCExecutor::getNativeModule>()); } - installGlobalProxy(m_context, "nativeExtensions", - exceptionWrapMethod<&JSCExecutor::getNativeExtension>()); + if (nativeExtensionsProvider) { + installGlobalProxy(m_context, "nativeExtensions", + exceptionWrapMethod<&JSCExecutor::getNativeExtension>()); + } } JSCExecutor::~JSCExecutor() { From 139d554c48560c3273c10a8881543c2f44ec64d0 Mon Sep 17 00:00:00 2001 From: Peter Argany Date: Thu, 15 Mar 2018 09:58:16 -0700 Subject: [PATCH 0036/1109] Replace js Dimensions with shadow view in InputAccessoryViewExample Reviewed By: mmmulani Differential Revision: D7196168 fbshipit-source-id: 031ed5ab24d1075f775ec71e5b78d32e03fe8f6f --- .../Text/TextInput/RCTInputAccessoryShadowView.h | 7 +++++++ .../Text/TextInput/RCTInputAccessoryShadowView.m | 15 +++++++++++++++ .../Text/TextInput/RCTInputAccessoryViewManager.m | 6 ++++++ RNTester/js/InputAccessoryViewExample.js | 4 +--- 4 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 Libraries/Text/TextInput/RCTInputAccessoryShadowView.h create mode 100644 Libraries/Text/TextInput/RCTInputAccessoryShadowView.m diff --git a/Libraries/Text/TextInput/RCTInputAccessoryShadowView.h b/Libraries/Text/TextInput/RCTInputAccessoryShadowView.h new file mode 100644 index 00000000000000..4731cea4d8e139 --- /dev/null +++ b/Libraries/Text/TextInput/RCTInputAccessoryShadowView.h @@ -0,0 +1,7 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#import + +@interface RCTInputAccessoryShadowView : RCTShadowView + +@end diff --git a/Libraries/Text/TextInput/RCTInputAccessoryShadowView.m b/Libraries/Text/TextInput/RCTInputAccessoryShadowView.m new file mode 100644 index 00000000000000..b2664aaec8bd5a --- /dev/null +++ b/Libraries/Text/TextInput/RCTInputAccessoryShadowView.m @@ -0,0 +1,15 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#import "RCTInputAccessoryShadowView.h" + +#import + +@implementation RCTInputAccessoryShadowView + +- (void)insertReactSubview:(RCTShadowView *)subview atIndex:(NSInteger)atIndex +{ + [super insertReactSubview:subview atIndex:atIndex]; + subview.width = (YGValue) { RCTScreenSize().width, YGUnitPoint }; +} + +@end diff --git a/Libraries/Text/TextInput/RCTInputAccessoryViewManager.m b/Libraries/Text/TextInput/RCTInputAccessoryViewManager.m index aeeff835e844b4..490aa841aa49a2 100644 --- a/Libraries/Text/TextInput/RCTInputAccessoryViewManager.m +++ b/Libraries/Text/TextInput/RCTInputAccessoryViewManager.m @@ -7,6 +7,7 @@ #import "RCTInputAccessoryViewManager.h" +#import "RCTInputAccessoryShadowView.h" #import "RCTInputAccessoryView.h" @implementation RCTInputAccessoryViewManager @@ -23,6 +24,11 @@ - (UIView *)view return [[RCTInputAccessoryView alloc] initWithBridge:self.bridge]; } +- (RCTShadowView *)shadowView +{ + return [RCTInputAccessoryShadowView new]; +} + RCT_REMAP_VIEW_PROPERTY(backgroundColor, inputAccessoryView.backgroundColor, UIColor) @end diff --git a/RNTester/js/InputAccessoryViewExample.js b/RNTester/js/InputAccessoryViewExample.js index 13b5885789b967..7ebcf5f0090ac4 100644 --- a/RNTester/js/InputAccessoryViewExample.js +++ b/RNTester/js/InputAccessoryViewExample.js @@ -13,7 +13,6 @@ const Alert = require('Alert'); const Button = require('Button'); -const Dimensions = require('Dimensions'); const InputAccessoryView = require('InputAccessoryView'); const React = require('React'); const ScrollView = require('ScrollView'); @@ -36,9 +35,8 @@ class TextInputBar extends React.PureComponent<*, *> { state = {text: ''}; render() { - const {width} = Dimensions.get('window'); return ( - + { From ce92b8592b08e78e11d8e16f330c054528af1bf2 Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Thu, 15 Mar 2018 12:29:00 -0700 Subject: [PATCH 0037/1109] Fixed a typo and added a test case Reviewed By: emilsjolander Differential Revision: D7289221 fbshipit-source-id: 48ee9ccfac4adee51d515a366b5a11790f7236fc --- ReactCommon/yoga/yoga/Yoga.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index e38ff26870c0f9..b21b23d2e183ec 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -778,7 +778,7 @@ void YGNodeStyleSetFlexShrink(const YGNodeRef node, const float flexShrink) { if (!YGFloatOptionalFloatEquals(node->getStyle().flexShrink, flexShrink)) { YGStyle style = node->getStyle(); if (YGFloatIsUndefined(flexShrink)) { - style.flexGrow = {true, 0}; + style.flexShrink = {true, 0}; } else { style.flexShrink = {false, flexShrink}; } From 9102ff94e7b9527e2162357a5e1334f7fffe8bcd Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Thu, 15 Mar 2018 12:29:02 -0700 Subject: [PATCH 0038/1109] Moved YGFloatOptional from C struct to C++ struct Reviewed By: emilsjolander Differential Revision: D7288555 fbshipit-source-id: f61cc92c8fd0d48d2fc1f4d0e6fcef155f19ff8a --- React/React.xcodeproj/project.pbxproj | 12 ++++++ ReactCommon/yoga/yoga/Utils.cpp | 2 +- ReactCommon/yoga/yoga/Utils.h | 9 +++-- ReactCommon/yoga/yoga/YGFloatOptional.cpp | 32 ++++++++++++++++ ReactCommon/yoga/yoga/YGFloatOptional.h | 26 +++++++++++++ ReactCommon/yoga/yoga/YGNode.cpp | 30 ++++++++------- ReactCommon/yoga/yoga/YGNodePrint.cpp | 4 +- ReactCommon/yoga/yoga/YGStyle.cpp | 32 ++++++++-------- ReactCommon/yoga/yoga/YGStyle.h | 1 + ReactCommon/yoga/yoga/Yoga.cpp | 46 ++++++++++++----------- ReactCommon/yoga/yoga/Yoga.h | 5 --- 11 files changed, 135 insertions(+), 64 deletions(-) create mode 100644 ReactCommon/yoga/yoga/YGFloatOptional.cpp create mode 100644 ReactCommon/yoga/yoga/YGFloatOptional.h diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj index 1ec79122f44a68..dbc8cef8aad008 100644 --- a/React/React.xcodeproj/project.pbxproj +++ b/React/React.xcodeproj/project.pbxproj @@ -978,6 +978,10 @@ 53D1239F1FBF1EFB001B8A10 /* Yoga-internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 53CBF1851FB4FE80002CBB31 /* Yoga-internal.h */; }; 53D123A01FBF1EFF001B8A10 /* Yoga.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53CBF1871FB4FE80002CBB31 /* Yoga.cpp */; }; 53D123A11FBF1EFF001B8A10 /* Yoga.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53CBF1871FB4FE80002CBB31 /* Yoga.cpp */; }; + 53DEF6EA205AE5A0006A3890 /* YGFloatOptional.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53DEF6E6205AE59B006A3890 /* YGFloatOptional.cpp */; }; + 53DEF6EB205AE5A1006A3890 /* YGFloatOptional.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53DEF6E6205AE59B006A3890 /* YGFloatOptional.cpp */; }; + 53DEF6EC205AE5A6006A3890 /* YGFloatOptional.h in Headers */ = {isa = PBXBuildFile; fileRef = 53DEF6E7205AE59C006A3890 /* YGFloatOptional.h */; }; + 53DEF6ED205AE5A7006A3890 /* YGFloatOptional.h in Headers */ = {isa = PBXBuildFile; fileRef = 53DEF6E7205AE59C006A3890 /* YGFloatOptional.h */; }; 53EC85E21FDEC75F0051B2B5 /* YGNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53EC85DF1FDEC75A0051B2B5 /* YGNode.cpp */; }; 53EC85E31FDEC75F0051B2B5 /* YGNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53EC85DF1FDEC75A0051B2B5 /* YGNode.cpp */; }; 53EC85E41FDEC7630051B2B5 /* YGNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 53EC85DE1FDEC75A0051B2B5 /* YGNode.h */; }; @@ -2169,6 +2173,8 @@ 53CBF1861FB4FE80002CBB31 /* YGEnums.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YGEnums.cpp; sourceTree = ""; }; 53CBF1871FB4FE80002CBB31 /* Yoga.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Yoga.cpp; sourceTree = ""; }; 53D123831FBF1D49001B8A10 /* libyoga.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libyoga.a; path = "../../../../../../../../../Library/Developer/Xcode/DerivedData/yoga-hdfifpwsinitsibujacpiefkjfdy/Build/Products/Debug/libyoga.a"; sourceTree = ""; }; + 53DEF6E6205AE59B006A3890 /* YGFloatOptional.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YGFloatOptional.cpp; sourceTree = ""; }; + 53DEF6E7205AE59C006A3890 /* YGFloatOptional.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGFloatOptional.h; sourceTree = ""; }; 53EC85DE1FDEC75A0051B2B5 /* YGNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGNode.h; sourceTree = ""; }; 53EC85DF1FDEC75A0051B2B5 /* YGNode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YGNode.cpp; sourceTree = ""; }; 58114A121AAE854800E7D092 /* RCTPicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPicker.h; sourceTree = ""; }; @@ -2349,6 +2355,8 @@ 130A77021DF767AF001F9587 /* yoga */ = { isa = PBXGroup; children = ( + 53DEF6E6205AE59B006A3890 /* YGFloatOptional.cpp */, + 53DEF6E7205AE59C006A3890 /* YGFloatOptional.h */, 5343895E203905B6008E0CB3 /* YGLayout.cpp */, 5343895F203905B6008E0CB3 /* YGLayout.h */, 5352C5722038FF8D00A3B97E /* YGStyle.cpp */, @@ -3299,6 +3307,7 @@ 5376C5E71FC6DDC20083513D /* YGNodePrint.h in Headers */, 3DFE0D191DF8574D00459392 /* Yoga.h in Headers */, 53438965203905C0008E0CB3 /* YGLayout.h in Headers */, + 53DEF6ED205AE5A7006A3890 /* YGFloatOptional.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3379,6 +3388,7 @@ 5376C5E61FC6DDC10083513D /* YGNodePrint.h in Headers */, 133957891DF76D3500EC27BE /* YGMacros.h in Headers */, 53438964203905BF008E0CB3 /* YGLayout.h in Headers */, + 53DEF6EC205AE5A6006A3890 /* YGFloatOptional.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4318,6 +4328,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 53DEF6EA205AE5A0006A3890 /* YGFloatOptional.cpp in Sources */, 53D123A01FBF1EFF001B8A10 /* Yoga.cpp in Sources */, 5352C5752038FF9500A3B97E /* YGStyle.cpp in Sources */, 53EC85E21FDEC75F0051B2B5 /* YGNode.cpp in Sources */, @@ -4332,6 +4343,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 53DEF6EB205AE5A1006A3890 /* YGFloatOptional.cpp in Sources */, 53D123A11FBF1EFF001B8A10 /* Yoga.cpp in Sources */, 5352C5762038FF9700A3B97E /* YGStyle.cpp in Sources */, 53EC85E31FDEC75F0051B2B5 /* YGNode.cpp in Sources */, diff --git a/ReactCommon/yoga/yoga/Utils.cpp b/ReactCommon/yoga/yoga/Utils.cpp index 8c6e91cce6ee82..aec7564fb66b89 100644 --- a/ReactCommon/yoga/yoga/Utils.cpp +++ b/ReactCommon/yoga/yoga/Utils.cpp @@ -55,7 +55,7 @@ float YGFloatSanitize(const float& val) { } float YGUnwrapFloatOptional(const YGFloatOptional& op) { - return op.isUndefined ? YGUndefined : op.value; + return op.isUndefined() ? YGUndefined : op.getValue(); } bool YGFloatOptionalFloatEquals( diff --git a/ReactCommon/yoga/yoga/Utils.h b/ReactCommon/yoga/yoga/Utils.h index 311030e23f0c42..7190fd7ff2495c 100644 --- a/ReactCommon/yoga/yoga/Utils.h +++ b/ReactCommon/yoga/yoga/Utils.h @@ -113,13 +113,14 @@ inline YGFloatOptional YGResolveValue(const YGValue value, const float parentSiz switch (value.unit) { case YGUnitUndefined: case YGUnitAuto: - return {true, 0}; + return YGFloatOptional(); case YGUnitPoint: - return {false, value.value}; + return YGFloatOptional(value.value); case YGUnitPercent: - return {false, static_cast(value.value * parentSize * 0.01)}; + return YGFloatOptional( + static_cast(value.value * parentSize * 0.01)); } - return {true, 0}; + return YGFloatOptional(); } inline bool YGFlexDirectionIsColumn(const YGFlexDirection flexDirection) { diff --git a/ReactCommon/yoga/yoga/YGFloatOptional.cpp b/ReactCommon/yoga/yoga/YGFloatOptional.cpp new file mode 100644 index 00000000000000..af9a6fc42ad786 --- /dev/null +++ b/ReactCommon/yoga/yoga/YGFloatOptional.cpp @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "YGFloatOptional.h" +#include +#include + +YGFloatOptional::YGFloatOptional(const float& value) + : value_(value), isUndefined_(false) {} +YGFloatOptional::YGFloatOptional() : value_(0), isUndefined_(true) {} + +float YGFloatOptional::getValue() const { + if (isUndefined_) { + // Abort, accessing a value of an undefined float optional + std::cerr << "Tried to get value of an undefined YGFloatOptional\n"; + std::exit(EXIT_FAILURE); + } + return value_; +} + +void YGFloatOptional::setValue(const float& val) { + value_ = val; + isUndefined_ = false; +} + +bool YGFloatOptional::isUndefined() const { + return isUndefined_; +} diff --git a/ReactCommon/yoga/yoga/YGFloatOptional.h b/ReactCommon/yoga/yoga/YGFloatOptional.h new file mode 100644 index 00000000000000..d82230be3ff714 --- /dev/null +++ b/ReactCommon/yoga/yoga/YGFloatOptional.h @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +struct YGFloatOptional { + private: + float value_; + bool isUndefined_; + + public: + YGFloatOptional(const float& value); + YGFloatOptional(); + + // Program will terminate if the value of an undefined is accessed. Please + // make sure to check if the optional is defined before calling this function. + // To check if float optional is defined, use `isUndefined()`. + float getValue() const; + + // Sets the value of float optional, and thus isUndefined is assigned false. + void setValue(const float& val); + + bool isUndefined() const; +}; diff --git a/ReactCommon/yoga/yoga/YGNode.cpp b/ReactCommon/yoga/yoga/YGNode.cpp index df61b14a896601..5a33c6e86e73ea 100644 --- a/ReactCommon/yoga/yoga/YGNode.cpp +++ b/ReactCommon/yoga/yoga/YGNode.cpp @@ -500,7 +500,7 @@ YGValue YGNode::resolveFlexBasisPtr() const { if (flexBasis.unit != YGUnitAuto && flexBasis.unit != YGUnitUndefined) { return flexBasis; } - if (!style_.flex.isUndefined && style_.flex.value > 0.0f) { + if (!style_.flex.isUndefined() && style_.flex.getValue() > 0.0f) { return config_->useWebDefaults ? YGValueAuto : YGValueZero; } return YGValueAuto; @@ -592,11 +592,11 @@ float YGNode::resolveFlexGrow() { if (parent_ == nullptr) { return 0.0; } - if (!style_.flexGrow.isUndefined) { - return style_.flexGrow.value; + if (!style_.flexGrow.isUndefined()) { + return style_.flexGrow.getValue(); } - if (!style_.flex.isUndefined && style_.flex.value > 0.0f) { - return style_.flex.value; + if (!style_.flex.isUndefined() && style_.flex.getValue() > 0.0f) { + return style_.flex.getValue(); } return kDefaultFlexGrow; } @@ -605,12 +605,12 @@ float YGNode::resolveFlexShrink() { if (parent_ == nullptr) { return 0.0; } - if (!style_.flexShrink.isUndefined) { - return style_.flexShrink.value; + if (!style_.flexShrink.isUndefined()) { + return style_.flexShrink.getValue(); } - if (!config_->useWebDefaults && !style_.flex.isUndefined && - style_.flex.value < 0.0f) { - return -style_.flex.value; + if (!config_->useWebDefaults && !style_.flex.isUndefined() && + style_.flex.getValue() < 0.0f) { + return -style_.flex.getValue(); } return config_->useWebDefaults ? kWebDefaultFlexShrink : kDefaultFlexShrink; } @@ -653,8 +653,9 @@ float YGNode::getLeadingPadding( const float widthSize) { if (YGFlexDirectionIsRow(axis) && style_.padding[YGEdgeStart].unit != YGUnitUndefined && - !YGResolveValue(style_.padding[YGEdgeStart], widthSize).isUndefined && - YGUnwrapFloatOptional(YGResolveValue(style_.padding[YGEdgeStart], widthSize)) > 0.0f) { + !YGResolveValue(style_.padding[YGEdgeStart], widthSize).isUndefined() && + YGUnwrapFloatOptional( + YGResolveValue(style_.padding[YGEdgeStart], widthSize)) > 0.0f) { return YGUnwrapFloatOptional(YGResolveValue(style_.padding[YGEdgeStart], widthSize)); } @@ -669,8 +670,9 @@ float YGNode::getTrailingPadding( const float widthSize) { if (YGFlexDirectionIsRow(axis) && style_.padding[YGEdgeEnd].unit != YGUnitUndefined && - !YGResolveValue(style_.padding[YGEdgeEnd], widthSize).isUndefined && - YGUnwrapFloatOptional(YGResolveValue(style_.padding[YGEdgeEnd], widthSize)) >= 0.0f) { + !YGResolveValue(style_.padding[YGEdgeEnd], widthSize).isUndefined() && + YGUnwrapFloatOptional( + YGResolveValue(style_.padding[YGEdgeEnd], widthSize)) >= 0.0f) { return YGUnwrapFloatOptional(YGResolveValue(style_.padding[YGEdgeEnd], widthSize)); } diff --git a/ReactCommon/yoga/yoga/YGNodePrint.cpp b/ReactCommon/yoga/yoga/YGNodePrint.cpp index ab0666d07eb59e..ab3aa7c7b3be04 100644 --- a/ReactCommon/yoga/yoga/YGNodePrint.cpp +++ b/ReactCommon/yoga/yoga/YGNodePrint.cpp @@ -43,8 +43,8 @@ static void appendFloatOptionalIfDefined( string* base, const string key, const YGFloatOptional num) { - if (!num.isUndefined) { - appendFormatedString(base, "%s: %g; ", key.c_str(), num.value); + if (!num.isUndefined()) { + appendFormatedString(base, "%s: %g; ", key.c_str(), num.getValue()); } } diff --git a/ReactCommon/yoga/yoga/YGStyle.cpp b/ReactCommon/yoga/yoga/YGStyle.cpp index 031443c8cbf550..437b682d614607 100644 --- a/ReactCommon/yoga/yoga/YGStyle.cpp +++ b/ReactCommon/yoga/yoga/YGStyle.cpp @@ -7,9 +7,6 @@ #include "YGStyle.h" -#define YGFloatOptionalUndefined \ - { true, 0 } - const YGValue kYGValueUndefined = {0, YGUnitUndefined}; const YGValue kYGValueAuto = {YGUndefined, YGUnitAuto}; @@ -42,9 +39,9 @@ YGStyle::YGStyle() flexWrap(YGWrapNoWrap), overflow(YGOverflowVisible), display(YGDisplayFlex), - flex(YGFloatOptionalUndefined), - flexGrow(YGFloatOptionalUndefined), - flexShrink(YGFloatOptionalUndefined), + flex(YGFloatOptional()), + flexGrow(YGFloatOptional()), + flexShrink(YGFloatOptional()), flexBasis({0, YGUnitAuto}), margin(kYGDefaultEdgeValuesUnit), position(kYGDefaultEdgeValuesUnit), @@ -73,24 +70,25 @@ bool YGStyle::operator==(const YGStyle& style) { YGValueArrayEqual(maxDimensions, style.maxDimensions); areNonFloatValuesEqual = - areNonFloatValuesEqual && flex.isUndefined == style.flex.isUndefined; - if (areNonFloatValuesEqual && !flex.isUndefined && !style.flex.isUndefined) { + areNonFloatValuesEqual && flex.isUndefined() == style.flex.isUndefined(); + if (areNonFloatValuesEqual && !flex.isUndefined() && + !style.flex.isUndefined()) { areNonFloatValuesEqual = - areNonFloatValuesEqual && flex.value == style.flex.value; + areNonFloatValuesEqual && flex.getValue() == style.flex.getValue(); } areNonFloatValuesEqual = areNonFloatValuesEqual && - flexGrow.isUndefined == style.flexGrow.isUndefined; - if (areNonFloatValuesEqual && !flexGrow.isUndefined) { - areNonFloatValuesEqual = - areNonFloatValuesEqual && flexGrow.value == style.flexGrow.value; + flexGrow.isUndefined() == style.flexGrow.isUndefined(); + if (areNonFloatValuesEqual && !flexGrow.isUndefined()) { + areNonFloatValuesEqual = areNonFloatValuesEqual && + flexGrow.getValue() == style.flexGrow.getValue(); } areNonFloatValuesEqual = areNonFloatValuesEqual && - flexShrink.isUndefined == style.flexShrink.isUndefined; - if (areNonFloatValuesEqual && !style.flexShrink.isUndefined) { - areNonFloatValuesEqual = - areNonFloatValuesEqual && flexShrink.value == style.flexShrink.value; + flexShrink.isUndefined() == style.flexShrink.isUndefined(); + if (areNonFloatValuesEqual && !style.flexShrink.isUndefined()) { + areNonFloatValuesEqual = areNonFloatValuesEqual && + flexShrink.getValue() == style.flexShrink.getValue(); } if (!(YGFloatIsUndefined(aspectRatio) && diff --git a/ReactCommon/yoga/yoga/YGStyle.h b/ReactCommon/yoga/yoga/YGStyle.h index 3abc4c084d4db3..7a7f519a5f9b67 100644 --- a/ReactCommon/yoga/yoga/YGStyle.h +++ b/ReactCommon/yoga/yoga/YGStyle.h @@ -6,6 +6,7 @@ */ #pragma once +#include "YGFloatOptional.h" #include "Yoga-internal.h" #include "Yoga.h" diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index b21b23d2e183ec..570f7ab964e157 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -13,7 +13,6 @@ #include "YGNode.h" #include "YGNodePrint.h" #include "Yoga-internal.h" - #ifdef _MSC_VER #include @@ -511,16 +510,16 @@ void YGNodeCopyStyle(const YGNodeRef dstNode, const YGNodeRef srcNode) { } float YGNodeStyleGetFlexGrow(const YGNodeRef node) { - return node->getStyle().flexGrow.isUndefined + return node->getStyle().flexGrow.isUndefined() ? kDefaultFlexGrow - : node->getStyle().flexGrow.value; + : node->getStyle().flexGrow.getValue(); } float YGNodeStyleGetFlexShrink(const YGNodeRef node) { - return node->getStyle().flexShrink.isUndefined + return node->getStyle().flexShrink.isUndefined() ? (node->getConfig()->useWebDefaults ? kWebDefaultFlexShrink : kDefaultFlexShrink) - : node->getStyle().flexShrink.value; + : node->getStyle().flexShrink.getValue(); } #define YG_NODE_STYLE_PROPERTY_SETTER_IMPL( \ @@ -744,9 +743,9 @@ void YGNodeStyleSetFlex(const YGNodeRef node, const float flex) { if (!YGFloatOptionalFloatEquals(node->getStyle().flex, flex)) { YGStyle style = node->getStyle(); if (YGFloatIsUndefined(flex)) { - style.flex = {true, 0}; + style.flex = YGFloatOptional(); } else { - style.flex = {false, flex}; + style.flex = YGFloatOptional(flex); } node->setStyle(style); node->markDirtyAndPropogate(); @@ -755,8 +754,8 @@ void YGNodeStyleSetFlex(const YGNodeRef node, const float flex) { // TODO(T26792433): Change the API to accept YGFloatOptional. float YGNodeStyleGetFlex(const YGNodeRef node) { - return node->getStyle().flex.isUndefined ? YGUndefined - : node->getStyle().flex.value; + return node->getStyle().flex.isUndefined() ? YGUndefined + : node->getStyle().flex.getValue(); } // TODO(T26792433): Change the API to accept YGFloatOptional. @@ -764,9 +763,9 @@ void YGNodeStyleSetFlexGrow(const YGNodeRef node, const float flexGrow) { if (!YGFloatOptionalFloatEquals(node->getStyle().flexGrow, flexGrow)) { YGStyle style = node->getStyle(); if (YGFloatIsUndefined(flexGrow)) { - style.flexGrow = {true, 0}; + style.flexGrow = YGFloatOptional(); } else { - style.flexGrow = {false, flexGrow}; + style.flexGrow = YGFloatOptional(flexGrow); } node->setStyle(style); node->markDirtyAndPropogate(); @@ -778,9 +777,9 @@ void YGNodeStyleSetFlexShrink(const YGNodeRef node, const float flexShrink) { if (!YGFloatOptionalFloatEquals(node->getStyle().flexShrink, flexShrink)) { YGStyle style = node->getStyle(); if (YGFloatIsUndefined(flexShrink)) { - style.flexShrink = {true, 0}; + style.flexShrink = YGFloatOptional(); } else { - style.flexShrink = {false, flexShrink}; + style.flexShrink = YGFloatOptional(flexShrink); } node->setStyle(style); node->markDirtyAndPropogate(); @@ -1669,13 +1668,15 @@ static float YGNodeCalculateAvailableInnerDim( // We want to make sure our available height does not violate min and max // constraints const YGFloatOptional minDimensionOptional = YGResolveValue(node->getStyle().minDimensions[dimension], parentDim); - const float minInnerDim = minDimensionOptional.isUndefined + const float minInnerDim = minDimensionOptional.isUndefined() ? 0.0f - : minDimensionOptional.value - paddingAndBorder; + : minDimensionOptional.getValue() - paddingAndBorder; const YGFloatOptional maxDimensionOptional = YGResolveValue(node->getStyle().maxDimensions[dimension], parentDim) ; - const float maxInnerDim = maxDimensionOptional.isUndefined ? FLT_MAX : maxDimensionOptional.value - paddingAndBorder; + const float maxInnerDim = maxDimensionOptional.isUndefined() + ? FLT_MAX + : maxDimensionOptional.getValue() - paddingAndBorder; availableInnerDim = YGFloatMax(YGFloatMin(availableInnerDim, maxInnerDim), minInnerDim); } @@ -2207,7 +2208,8 @@ static void YGJustifyMainAxis( if (measureModeMainDim == YGMeasureModeAtMost && collectedFlexItemsValues.remainingFreeSpace > 0) { if (style.minDimensions[dim[mainAxis]].unit != YGUnitUndefined && - !YGResolveValue(style.minDimensions[dim[mainAxis]], mainAxisParentSize).isUndefined) { + !YGResolveValue(style.minDimensions[dim[mainAxis]], mainAxisParentSize) + .isUndefined()) { collectedFlexItemsValues.remainingFreeSpace = YGFloatMax( 0, YGUnwrapFloatOptional(YGResolveValue( @@ -3713,8 +3715,8 @@ void YGNodeCalculateLayout( node->getMarginForAxis(YGFlexDirectionRow, parentWidth); widthMeasureMode = YGMeasureModeExactly; } else if (!YGResolveValue( - node->getStyle().maxDimensions[YGDimensionWidth], - parentWidth).isUndefined) { + node->getStyle().maxDimensions[YGDimensionWidth], parentWidth) + .isUndefined()) { width = YGUnwrapFloatOptional(YGResolveValue( node->getStyle().maxDimensions[YGDimensionWidth], parentWidth)); widthMeasureMode = YGMeasureModeAtMost; @@ -3732,8 +3734,10 @@ void YGNodeCalculateLayout( parentHeight)) + node->getMarginForAxis(YGFlexDirectionColumn, parentWidth); heightMeasureMode = YGMeasureModeExactly; - } else if (!YGResolveValue(node->getStyle().maxDimensions[YGDimensionHeight], - parentHeight).isUndefined) { + } else if (!YGResolveValue( + node->getStyle().maxDimensions[YGDimensionHeight], + parentHeight) + .isUndefined()) { height = YGUnwrapFloatOptional(YGResolveValue(node->getStyle().maxDimensions[YGDimensionHeight], parentHeight)); heightMeasureMode = YGMeasureModeAtMost; } else { diff --git a/ReactCommon/yoga/yoga/Yoga.h b/ReactCommon/yoga/yoga/Yoga.h index 83eefa02689347..2ec6a687ee742f 100644 --- a/ReactCommon/yoga/yoga/Yoga.h +++ b/ReactCommon/yoga/yoga/Yoga.h @@ -42,11 +42,6 @@ typedef struct YGValue { YGUnit unit; } YGValue; -struct YGFloatOptional { - bool isUndefined; - float value; -}; - extern const YGValue YGValueUndefined; extern const YGValue YGValueAuto; From f376fe3232fb23c7ffefe2cbc7a1b51c64632a08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Thu, 15 Mar 2018 16:27:02 -0700 Subject: [PATCH 0039/1109] Remove @xplat cell syntax in open source Differential Revision: D7292243 fbshipit-source-id: f1c162be8bc90669481f04de8aa71f3d9dbece36 --- .../src/main/java/com/facebook/react/fabric/jsc/jni/BUCK | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/BUCK b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/BUCK index cbf088f2d277e8..4c4dd27047f949 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/BUCK @@ -1,4 +1,4 @@ -load("@xplat//ReactNative:DEFS.bzl", "react_native_target", "react_native_xplat_target", "rn_xplat_cxx_library", "FBJNI_TARGET", "ANDROID") +load("//ReactNative:DEFS.bzl", "react_native_target", "react_native_xplat_target", "rn_xplat_cxx_library", "FBJNI_TARGET", "ANDROID") rn_xplat_cxx_library( name = "jni", From b02b1670d65118c333d3e0b83ddc99d2dc39dbed Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Thu, 15 Mar 2018 18:19:05 -0700 Subject: [PATCH 0040/1109] Bump metro@0.30.2 Reviewed By: BYK Differential Revision: D7292431 fbshipit-source-id: 2d81e502e060ecd278977b838e0ef2db7e13b0e3 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index bc2e7cd11a03fb..3aab6dca4ba026 100644 --- a/package.json +++ b/package.json @@ -175,8 +175,8 @@ "graceful-fs": "^4.1.3", "inquirer": "^3.0.6", "lodash": "^4.17.5", - "metro": "^0.30.1", - "metro-core": "^0.30.1", + "metro": "^0.30.2", + "metro-core": "^0.30.2", "mime": "^1.3.4", "minimist": "^1.2.0", "mkdirp": "^0.5.1", From dbd47592a18ed09ee6e94c79bed16d63be625af6 Mon Sep 17 00:00:00 2001 From: Thibault Malbranche Date: Fri, 16 Mar 2018 11:11:40 -0700 Subject: [PATCH 0041/1109] Local cli/android/normalize project name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Scoped packages are starting to be the new thing, and gradle does not work properly with '/' in the project name, so this PR links them and replaces '/' by '_' . This only affects android. I added tests in the 2 impacted functions + a test file for the normalizer function [CLI] [BUGFIX] [local-cli/link/link.js] - On android, Scoped packages will now get the '/' replaced with '_' to ensure gradle works nicely. ⚠️ However if you previously linked scoped packages, they will get linked again. ⚠️ Closes https://github.com/facebook/react-native/pull/18275 Differential Revision: D7305227 Pulled By: hramos fbshipit-source-id: 1c95563e884175529692948b29407a7733c44353 --- .../__tests__/android/makeBuildPatch.spec.js | 18 +++++++++++ .../android/makeSettingsPatch.spec.js | 30 +++++++++++++++++++ .../android/normalizeProjectName.spec.js | 26 ++++++++++++++++ .../link/android/patches/makeBuildPatch.js | 7 +++-- .../link/android/patches/makeSettingsPatch.js | 8 +++-- .../android/patches/normalizeProjectName.js | 4 +++ 6 files changed, 89 insertions(+), 4 deletions(-) create mode 100644 local-cli/link/__tests__/android/normalizeProjectName.spec.js create mode 100644 local-cli/link/android/patches/normalizeProjectName.js diff --git a/local-cli/link/__tests__/android/makeBuildPatch.spec.js b/local-cli/link/__tests__/android/makeBuildPatch.spec.js index 0fd082da91f650..fdcdad0453b198 100644 --- a/local-cli/link/__tests__/android/makeBuildPatch.spec.js +++ b/local-cli/link/__tests__/android/makeBuildPatch.spec.js @@ -10,7 +10,11 @@ 'use strict'; const makeBuildPatch = require('../../android/patches/makeBuildPatch'); +const normalizeProjectName = require('../../android/patches/normalizeProjectName'); + const name = 'test'; +const scopedName = '@scoped/test'; +const normalizedScopedName = normalizeProjectName('@scoped/test'); describe('makeBuildPatch', () => { it('should build a patch function', () => { @@ -29,3 +33,17 @@ describe('makeBuildPatch', () => { expect(installPattern.toString()).toBe(match); }); }); + + +describe('makeBuildPatchWithScopedPackage', () => { + it('should make a correct patch', () => { + const {patch} = makeBuildPatch(scopedName); + expect(patch).toBe(` compile project(':${normalizedScopedName}')\n`); + }); + + it('should make a correct install check pattern', () => { + const {installPattern} = makeBuildPatch(scopedName); + const match = `/\\s{4}(compile)(\\(|\\s)(project)\\(\\':${normalizedScopedName}\\'\\)(\\)|\\s)/`; + expect(installPattern.toString()).toBe(match); + }); +}); diff --git a/local-cli/link/__tests__/android/makeSettingsPatch.spec.js b/local-cli/link/__tests__/android/makeSettingsPatch.spec.js index a8c7e3c2ba8d4f..63954af8155f77 100644 --- a/local-cli/link/__tests__/android/makeSettingsPatch.spec.js +++ b/local-cli/link/__tests__/android/makeSettingsPatch.spec.js @@ -11,8 +11,11 @@ const path = require('path'); const makeSettingsPatch = require('../../android/patches/makeSettingsPatch'); +const normalizeProjectName = require('../../android/patches/normalizeProjectName'); const name = 'test'; +const scopedName = '@scoped/test'; +const normalizedScopedName = normalizeProjectName('@scoped/test'); const projectConfig = { sourceDir: '/home/project/android/app', settingsGradlePath: '/home/project/android/settings.gradle', @@ -20,6 +23,9 @@ const projectConfig = { const dependencyConfig = { sourceDir: `/home/project/node_modules/${name}/android`, }; +const scopedDependencyConfig = { + sourceDir: `/home/project/node_modules/${scopedName}/android`, +}; describe('makeSettingsPatch', () => { it('should build a patch function', () => { @@ -44,3 +50,27 @@ describe('makeSettingsPatch', () => { ); }); }); + +describe('makeSettingsPatchWithScopedPackage', () => { + it('should build a patch function', () => { + expect(Object.prototype.toString( + makeSettingsPatch(scopedName, scopedDependencyConfig, projectConfig) + )).toBe('[object Object]'); + }); + + it('should make a correct patch', () => { + const projectDir = path.relative( + path.dirname(projectConfig.settingsGradlePath), + scopedDependencyConfig.sourceDir + ); + + const {patch} = makeSettingsPatch(scopedName, scopedDependencyConfig, projectConfig); + + expect(patch) + .toBe( + `include ':${normalizedScopedName}'\n` + + `project(':${normalizedScopedName}').projectDir = ` + + `new File(rootProject.projectDir, '${projectDir}')\n` + ); + }); +}); diff --git a/local-cli/link/__tests__/android/normalizeProjectName.spec.js b/local-cli/link/__tests__/android/normalizeProjectName.spec.js new file mode 100644 index 00000000000000..e4e236aca42f45 --- /dev/null +++ b/local-cli/link/__tests__/android/normalizeProjectName.spec.js @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * All rights reserved. + * + * @emails oncall+javascript_foundation + */ + + 'use strict'; + +const normalizeProjectName = require('../../android/patches/normalizeProjectName'); + +const name = 'test'; +const scopedName = '@scoped/test'; + + describe('normalizeProjectName', () => { + it('should replace slashes with underscores', () => { + expect(normalizeProjectName(name)) + .toBe('test'); + expect(normalizeProjectName(scopedName)) + .toBe('@scoped_test'); + }); +}); diff --git a/local-cli/link/android/patches/makeBuildPatch.js b/local-cli/link/android/patches/makeBuildPatch.js index 67f7d8aac3f1d2..3c4969af22d8db 100644 --- a/local-cli/link/android/patches/makeBuildPatch.js +++ b/local-cli/link/android/patches/makeBuildPatch.js @@ -5,14 +5,17 @@ * LICENSE file in the root directory of this source tree. */ +const normalizeProjectName = require('./normalizeProjectName'); + module.exports = function makeBuildPatch(name) { + const normalizedProjectName = normalizeProjectName(name); const installPattern = new RegExp( - `\\s{4}(compile)(\\(|\\s)(project)\\(\\\':${name}\\\'\\)(\\)|\\s)` + `\\s{4}(compile)(\\(|\\s)(project)\\(\\\':${normalizedProjectName}\\\'\\)(\\)|\\s)` ); return { installPattern, pattern: /[^ \t]dependencies {\n/, - patch: ` compile project(':${name}')\n` + patch: ` compile project(':${normalizedProjectName}')\n` }; }; diff --git a/local-cli/link/android/patches/makeSettingsPatch.js b/local-cli/link/android/patches/makeSettingsPatch.js index a8a6e148333f04..a39de2be17dc16 100644 --- a/local-cli/link/android/patches/makeSettingsPatch.js +++ b/local-cli/link/android/patches/makeSettingsPatch.js @@ -6,6 +6,8 @@ */ const path = require('path'); +const normalizeProjectName = require('./normalizeProjectName'); + const isWin = process.platform === 'win32'; module.exports = function makeSettingsPatch(name, androidConfig, projectConfig) { @@ -13,6 +15,8 @@ module.exports = function makeSettingsPatch(name, androidConfig, projectConfig) path.dirname(projectConfig.settingsGradlePath), androidConfig.sourceDir ); + const normalizedProjectName = normalizeProjectName(name); + /* * Fix for Windows @@ -26,8 +30,8 @@ module.exports = function makeSettingsPatch(name, androidConfig, projectConfig) return { pattern: '\n', - patch: `include ':${name}'\n` + - `project(':${name}').projectDir = ` + + patch: `include ':${normalizedProjectName}'\n` + + `project(':${normalizedProjectName}').projectDir = ` + `new File(rootProject.projectDir, '${projectDir}')\n`, }; }; diff --git a/local-cli/link/android/patches/normalizeProjectName.js b/local-cli/link/android/patches/normalizeProjectName.js new file mode 100644 index 00000000000000..fd52d1bb108b84 --- /dev/null +++ b/local-cli/link/android/patches/normalizeProjectName.js @@ -0,0 +1,4 @@ + +module.exports = function normalizeProjectName(name) { + return name.replace(/\//g, '_'); +}; From 076b1cea3563cae30e11d63cc100ceaed9082692 Mon Sep 17 00:00:00 2001 From: Tadeu Valentt Date: Fri, 16 Mar 2018 16:35:37 -0700 Subject: [PATCH 0042/1109] Prevent show a hidden status bar when opening modals, fix #7474 Summary: Closes the old #7474, keeping the status bar hidden when displaying a modal or dialog, this is accomplished by verifying if the activity status bar is hidden or not. Added a test to [RNTester](https://github.com/facebook/react-native/tree/master/RNTester), so it can be tested from there: 1. Run [RNTester](https://github.com/facebook/react-native/tree/master/RNTester) project 2. Go to tests 3. Set `hidden: true` in the *StatusBar hidden* samples 4. Set `modal visible: true` and see the result Here are some gifs to help see the results: ![fail](https://user-images.githubusercontent.com/1649955/36345378-f443ad7e-1407-11e8-850d-d6317fb34da4.gif) ![success](https://user-images.githubusercontent.com/1649955/36345392-1c590b56-1408-11e8-9244-a2e828f579ab.gif) none [ GENERAL ] [ BUGFIX ] [StatusBar] - Prevent show a hidden status bar when opening modals Closes https://github.com/facebook/react-native/pull/18004 Differential Revision: D7307564 Pulled By: hramos fbshipit-source-id: 47e481ead78204865811ddf2ef3d27da77ad8b8f --- RNTester/js/StatusBarExample.js | 59 ++++++++++++++++++- .../react/views/modal/ReactModalHostView.java | 11 ++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/RNTester/js/StatusBarExample.js b/RNTester/js/StatusBarExample.js index 0df43f42edb371..e5dae5c77c49c2 100644 --- a/RNTester/js/StatusBarExample.js +++ b/RNTester/js/StatusBarExample.js @@ -17,6 +17,7 @@ const { Text, TouchableHighlight, View, + Modal, } = ReactNative; exports.framework = 'React'; @@ -100,6 +101,7 @@ class StatusBarHiddenExample extends React.Component<{}, $FlowFixMeState> { + ); } @@ -380,6 +382,48 @@ class StatusBarStaticAndroidExample extends React.Component<{}> { } } + +class ModalExample extends React.Component<{}, $FlowFixMeState> { + state = { + modalVisible: false, + }; + + _onChangeModalVisible = () => { + this.setState({modalVisible: !this.state.modalVisible}); + }; + + render() { + return ( + + + + modal visible: {this.state.hidden ? 'true' : 'false'} + + + + + + This modal was presented! + + + Close + + + + + + + ); + } +} + const examples = [{ title: 'StatusBar hidden', render() { @@ -436,6 +480,16 @@ const examples = [{ exports.examples = examples; var styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + padding: 20, + backgroundColor: '#f5fcff' + }, + innerContainer: { + borderRadius: 10, + alignItems: 'center', + }, wrapper: { borderRadius: 5, marginBottom: 5, @@ -449,5 +503,8 @@ var styles = StyleSheet.create({ marginTop: 16, marginBottom: 8, fontWeight: 'bold', - } + }, + modalButton: { + marginTop: 10, + }, }); diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java index 1d64cb83f8f018..00eac510ab8f35 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java @@ -276,6 +276,17 @@ private View getContentView() { private void updateProperties() { Assertions.assertNotNull(mDialog, "mDialog must exist when we call updateProperties"); + Activity currentActivity = getCurrentActivity(); + if (currentActivity != null) { + int activityWindowFlags = currentActivity.getWindow().getAttributes().flags; + if ((activityWindowFlags + & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0) { + mDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + } else { + mDialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + } + } + if (mTransparent) { mDialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); } else { From 6f6084db69de372cbc6dcec259389e4b7dfd7fa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Fri, 16 Mar 2018 16:48:36 -0700 Subject: [PATCH 0043/1109] Explicitly set path to yarn Summary: Due to issues with Circle's Docker images ([link](https://twitter.com/circleci/status/974694807091073024)), jobs are failing with an error "yarn not found". Test Plan Run on Circle Release Notes [GENERAL][MINOR][.circleci] - Fix Circle issue Closes https://github.com/facebook/react-native/pull/18419 Differential Revision: D7312052 Pulled By: hramos fbshipit-source-id: 2768b9c69046a2f80518430024d3e7afbbd7de65 --- .circleci/config.yml | 10 +++++++--- scripts/circleci/analyze_code.sh | 12 ++++++++++++ scripts/circleci/exec_swallow_error.sh | 13 +++++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) create mode 100755 scripts/circleci/analyze_code.sh create mode 100755 scripts/circleci/exec_swallow_error.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index 100bc1276ffd33..4006882af1b7f6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -157,10 +157,11 @@ aliases: - &run-js-tests name: JavaScript Test Suite command: yarn test-ci - + + # eslint sometimes runs into trouble generating the reports - &run-lint-checks name: Lint code - command: yarn lint --format junit -o ~/react-native/reports/junit/js-lint-results.xml + command: scripts/circleci/exec_swallow_error.sh yarn lint --format junit -o ~/react-native/reports/junit/js-lint-results.xml when: always - &run-flow-checks @@ -251,6 +252,8 @@ js_defaults: &js_defaults <<: *defaults docker: - image: circleci/node:8 + environment: + - PATH: "/opt/yarn/yarn-v1.5.1/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" android_defaults: &android_defaults <<: *defaults @@ -258,6 +261,7 @@ android_defaults: &android_defaults - image: circleci/android:api-26-alpha resource_class: "large" environment: + - PATH: "/opt/yarn/yarn-v1.5.1/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" - TERM: "dumb" - ADB_INSTALL_TIMEOUT: 10 - _JAVA_OPTIONS: "-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap" @@ -539,7 +543,7 @@ jobs: command: | # GITHUB_TOKEN=eslint-bot public_repo access token if [ -n "$CIRCLE_PR_NUMBER" ]; then - cat <(echo eslint; yarn --silent lint --format=json; echo flow; yarn --silent flow check --json) | GITHUB_TOKEN="af6ef0d15709bc91d""06a6217a5a826a226fb57b7" CI_USER=$CIRCLE_PROJECT_USERNAME CI_REPO=$CIRCLE_PROJECT_REPONAME PULL_REQUEST_NUMBER=$CIRCLE_PR_NUMBER node bots/code-analysis-bot.js + GITHUB_TOKEN="af6ef0d15709bc91d""06a6217a5a826a226fb57b7" CI_USER=$CIRCLE_PROJECT_USERNAME CI_REPO=$CIRCLE_PROJECT_REPONAME PULL_REQUEST_NUMBER=$CIRCLE_PR_NUMBER scripts/circleci/analyze_code.sh else echo "Skipping code analysis." fi diff --git a/scripts/circleci/analyze_code.sh b/scripts/circleci/analyze_code.sh new file mode 100755 index 00000000000000..9569a4fa8e73ff --- /dev/null +++ b/scripts/circleci/analyze_code.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +cat <(echo eslint; yarn --silent lint --format=json; echo flow; yarn --silent flow check --json) | GITHUB_TOKEN=$GITHUB_TOKEN CI_USER=$CI_USER CI_REPO=$CI_REPO PULL_REQUEST_NUMBER=$PULL_REQUEST_NUMBER node bots/code-analysis-bot.js + +# check status +STATUS=$? +if [ $STATUS == 0 ]; then + echo "Code analyzed successfully" +else + echo "Code analyzis failed, error status $STATUS" +fi + diff --git a/scripts/circleci/exec_swallow_error.sh b/scripts/circleci/exec_swallow_error.sh new file mode 100755 index 00000000000000..297cf5b01219d9 --- /dev/null +++ b/scripts/circleci/exec_swallow_error.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# execute command +$@ + +# check status +STATUS=$? +if [ $STATUS == 0 ]; then + echo "Command '$@' completed successfully" +else + echo "Command '$@' exited with error status $STATUS" +fi + From 6426735e825a466d9e2e1c27c22dbfad6329d395 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Fri, 16 Mar 2018 16:48:45 -0700 Subject: [PATCH 0044/1109] Simplify templates Summary: Trivial PR. [GENERAL][MINOR][.circleci/, bots/] - Simplify GitHub templates Closes https://github.com/facebook/react-native/pull/18418 Differential Revision: D7311869 Pulled By: hramos fbshipit-source-id: b87599c53938406d585d711492aacbdde2fcb02a --- .github/ISSUE_TEMPLATE.md | 38 +++++++++++----------- .github/PULL_REQUEST_TEMPLATE.md | 53 ++++++++++++++++--------------- .github/no-response.yml | 9 ------ bots/NewIssueGreeting.md | 9 ------ bots/QuestionGreeting.md | 5 --- bots/dangerfile.js | 26 +-------------- bots/pr-inactivity-bookmarklet.js | 1 - bots/question-bookmarklet.js | 1 - breaking-changes.md | 3 -- 9 files changed, 47 insertions(+), 98 deletions(-) delete mode 100644 .github/no-response.yml delete mode 100644 bots/NewIssueGreeting.md delete mode 100644 bots/QuestionGreeting.md delete mode 100644 bots/pr-inactivity-bookmarklet.js delete mode 100644 bots/question-bookmarklet.js delete mode 100644 breaking-changes.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index bbe1d31e0b8f46..46d7bb4760de02 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,29 +1,27 @@ -(Describe your issue in detail.) +- [ ] I have reviewed the [documentation](https://facebook.github.io/react-native) +- [ ] I have searched [existing issues](https://github.com/facebook/react-native/issues) +- [ ] I am using the [latest React Native version](https://github.com/facebook/react-native/releases) -### Environment + -(Run `react-native info` in your terminal and paste its contents here.) +## Environment + -### Expected Behavior - -(Write what you thought would happen.) - -### Actual Behavior - -(Write what happened. Include screenshots if needed.) - -### Steps to Reproduce - -(Link to Snack, or steps to reproduce.) +## Steps to Reproduce + - - This is a good guide to creating bug demos: https://stackoverflow.com/help/mcve ---> +## Actual Behavior + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index d8a1469f329099..93f140001bd706 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,43 +1,46 @@ - -## Motivation - -(Write your motivation here.) - ## Test Plan -(Write your test plan here. If you changed any code, please provide us with clear instructions on how you verified your changes work. Bonus points for screenshots and videos!) + ## Related PRs -(If this PR adds or changes functionality, please take some time to update the docs at https://github.com/facebook/react-native-website, and link to your PR here.) + ## Release Notes - - CATEGORY -[----------] TYPE -[ CLI ] [-------------] LOCATION -[ DOCS ] [ BREAKING ] [-------------] -[ GENERAL ] [ BUGFIX ] [-{Component}-] -[ INTERNAL ] [ ENHANCEMENT ] [ {File} ] -[ IOS ] [ FEATURE ] [ {Directory} ] |-----------| -[ ANDROID ] [ MINOR ] [ {Framework} ] - | {Message} | -[----------] [-------------] [-------------] |-----------| +[CATEGORY] [TYPE] [LOCATION] - Message -[CATEGORY] [TYPE] [LOCATION] - MESSAGE + The caret/cursor did not appear when the TextInput was empty. Found that the cause was because the frame of the TextInput had an height of 0 Just fill and clear a TextInput and the caret/cursor will always appear there. [IOS] [BUGFIX] [TextInput] - This was causing the cursor/caret to not appear since the size of the frame had an height of 0. Closes https://github.com/facebook/react-native/pull/18355 Differential Revision: D7319723 Pulled By: shergin fbshipit-source-id: b0249ab5493b6ac310d1898ff20c0bad78cf82c9 --- Libraries/Text/TextInput/RCTBaseTextInputShadowView.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Libraries/Text/TextInput/RCTBaseTextInputShadowView.m b/Libraries/Text/TextInput/RCTBaseTextInputShadowView.m index d1fdbcd3d25012..f5a7ca1724754d 100644 --- a/Libraries/Text/TextInput/RCTBaseTextInputShadowView.m +++ b/Libraries/Text/TextInput/RCTBaseTextInputShadowView.m @@ -180,8 +180,8 @@ - (NSAttributedString *)measurableAttributedText // Placeholder also can represent the intrinsic size when it is visible. NSString *text = self.placeholder; if (!text.length) { - // Zero-width space - text = @"\u200B"; + // Note: `zero-width space` is insufficient in some cases. + text = @"I"; } attributedText = [[NSAttributedString alloc] initWithString:text attributes:self.textAttributes.effectiveTextAttributes]; } From c73242938c2b9d45f9da02b201a02f3b5993eaf5 Mon Sep 17 00:00:00 2001 From: Dmitry Zakharov Date: Mon, 19 Mar 2018 09:30:35 -0700 Subject: [PATCH 0064/1109] Make access to SourceCode Native Extension lazy Reviewed By: fromcelticpark Differential Revision: D6987478 fbshipit-source-id: 6d600131239be34480bd1c5a0ca84b4fab360386 --- Libraries/Image/resolveAssetSource.js | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/Libraries/Image/resolveAssetSource.js b/Libraries/Image/resolveAssetSource.js index 24fec6ef33c78a..0d160a28077deb 100644 --- a/Libraries/Image/resolveAssetSource.js +++ b/Libraries/Image/resolveAssetSource.js @@ -17,11 +17,26 @@ const AssetSourceResolver = require('AssetSourceResolver'); import type { ResolvedAssetSource } from 'AssetSourceResolver'; let _customSourceTransformer, _serverURL, _scriptURL; + let _sourceCodeScriptURL: ?string; +function getSourceCodeScriptURL(): ?string { + if (_sourceCodeScriptURL) { + return _sourceCodeScriptURL; + } + + let sourceCode = global.nativeExtensions && global.nativeExtensions.SourceCode; + if (!sourceCode) { + const NativeModules = require('NativeModules'); + sourceCode = NativeModules && NativeModules.SourceCode; + } + _sourceCodeScriptURL = sourceCode.scriptURL; + return _sourceCodeScriptURL; +} function getDevServerURL(): ?string { if (_serverURL === undefined) { - const match = _sourceCodeScriptURL && _sourceCodeScriptURL.match(/^https?:\/\/.*?\//); + const sourceCodeScriptURL = getSourceCodeScriptURL(); + const match = sourceCodeScriptURL && sourceCodeScriptURL.match(/^https?:\/\/.*?\//); if (match) { // jsBundle was loaded from network _serverURL = match[0]; @@ -51,7 +66,7 @@ function _coerceLocalScriptURL(scriptURL: ?string): ?string { function getScriptURL(): ?string { if (_scriptURL === undefined) { - _scriptURL = _coerceLocalScriptURL(_sourceCodeScriptURL); + _scriptURL = _coerceLocalScriptURL(getSourceCodeScriptURL()); } return _scriptURL; } @@ -87,13 +102,6 @@ function resolveAssetSource(source: any): ?ResolvedAssetSource { return resolver.defaultAsset(); } -let sourceCode = global.nativeExtensions && global.nativeExtensions.SourceCode; -if (!sourceCode) { - const NativeModules = require('NativeModules'); - sourceCode = NativeModules && NativeModules.SourceCode; -} -_sourceCodeScriptURL = sourceCode && sourceCode.scriptURL; - module.exports = resolveAssetSource; module.exports.pickScale = AssetSourceResolver.pickScale; module.exports.setCustomSourceTransformer = setCustomSourceTransformer; From 15bc6d1e0b6f14ed42100515fef7a26419e71b0e Mon Sep 17 00:00:00 2001 From: Peter Argany Date: Mon, 19 Mar 2018 10:06:58 -0700 Subject: [PATCH 0065/1109] Added console warning to InputAccessoryView Reviewed By: mmmulani Differential Revision: D7305377 fbshipit-source-id: 4a9888b5592014956c3aa44baffb2ac3a0329b88 --- Libraries/Components/TextInput/InputAccessoryView.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Libraries/Components/TextInput/InputAccessoryView.js b/Libraries/Components/TextInput/InputAccessoryView.js index cd12758435ff96..73d83c03a22b60 100644 --- a/Libraries/Components/TextInput/InputAccessoryView.js +++ b/Libraries/Components/TextInput/InputAccessoryView.js @@ -90,6 +90,8 @@ type Props = { class InputAccessoryView extends React.Component { render(): React.Node { + console.warn(' is not supported on Android yet.'); + if (React.Children.count(this.props.children) === 0) { return null; } From 12c208cbd483c13587b4977c48f582e61eaea50e Mon Sep 17 00:00:00 2001 From: "Andrew Chen (Eng)" Date: Mon, 19 Mar 2018 10:34:57 -0700 Subject: [PATCH 0066/1109] Create a new instrumentation test that does not enforce rendering a single RN component Reviewed By: mdvacca Differential Revision: D7293466 fbshipit-source-id: 8ddaf9a52f4d6324e8b37f3c6fd4d3e0db6f3a12 --- .../react/testing/ReactAppTestActivity.java | 96 ++++++++------ .../testing/ReactInstrumentationTest.java | 124 ++++++++++++++++++ 2 files changed, 181 insertions(+), 39 deletions(-) create mode 100644 ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactInstrumentationTest.java diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java index 0a68ad1ed5dfcd..341c8781494238 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java @@ -176,8 +176,36 @@ public void loadApp( String bundleName, boolean useDevSupport, UIImplementationProvider uiImplementationProvider) { + loadBundle(spec, bundleName, useDevSupport, uiImplementationProvider); + renderComponent(appKey, initialProps); + } + public void renderComponent(String appKey, @Nullable Bundle initialProps) { final CountDownLatch currentLayoutEvent = mLayoutEvent = new CountDownLatch(1); + Assertions.assertNotNull(mReactRootView).getViewTreeObserver().addOnGlobalLayoutListener( + new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + currentLayoutEvent.countDown(); + } + }); + Assertions.assertNotNull(mReactRootView) + .startReactApplication(mReactInstanceManager, appKey, initialProps); + } + + public void loadBundle( + ReactInstanceSpecForTest spec, + String bundleName, + boolean useDevSupport) { + loadBundle(spec, bundleName, useDevSupport, null); + } + + public void loadBundle( + ReactInstanceSpecForTest spec, + String bundleName, + boolean useDevSupport, + UIImplementationProvider uiImplementationProvider) { + mBridgeIdleSignaler = new ReactBridgeIdleSignaler(); ReactInstanceManagerBuilder builder = @@ -200,49 +228,39 @@ public void loadApp( .setBridgeIdleDebugListener(mBridgeIdleSignaler) .setInitialLifecycleState(mLifecycleState) .setJSIModulesProvider( - new JSIModulesProvider() { - @Override - public List getJSIModules( - final ReactApplicationContext reactApplicationContext, - final JavaScriptContextHolder jsContext) { - - List modules = new ArrayList<>(); - modules.add( - new JSIModuleHolder() { - - @Override - public Class getJSIModuleClass() { - return UIManager.class; - } - - @Override - public FabricUIManager getJSIModule() { - List viewManagers = - getReactInstanceManager().getOrCreateViewManagers(reactApplicationContext); - FabricUIManager fabricUIManager = - new FabricUIManager( - reactApplicationContext, new ViewManagerRegistry(viewManagers)); - new FabricJSCBinding().installFabric(jsContext, fabricUIManager); - return fabricUIManager; - } - }); - - return modules; - }}) + new JSIModulesProvider() { + @Override + public List getJSIModules( + final ReactApplicationContext reactApplicationContext, + final JavaScriptContextHolder jsContext) { + + List modules = new ArrayList<>(); + modules.add( + new JSIModuleHolder() { + + @Override + public Class getJSIModuleClass() { + return UIManager.class; + } + + @Override + public FabricUIManager getJSIModule() { + List viewManagers = + getReactInstanceManager().getOrCreateViewManagers(reactApplicationContext); + FabricUIManager fabricUIManager = + new FabricUIManager( + reactApplicationContext, new ViewManagerRegistry(viewManagers)); + new FabricJSCBinding().installFabric(jsContext, fabricUIManager); + return fabricUIManager; + } + }); + + return modules; + }}) .setUIImplementationProvider(uiImplementationProvider); mReactInstanceManager = builder.build(); mReactInstanceManager.onHostResume(this, this); - - Assertions.assertNotNull(mReactRootView).getViewTreeObserver().addOnGlobalLayoutListener( - new ViewTreeObserver.OnGlobalLayoutListener() { - @Override - public void onGlobalLayout() { - currentLayoutEvent.countDown(); - } - }); - Assertions.assertNotNull(mReactRootView) - .startReactApplication(mReactInstanceManager, appKey, initialProps); } private ReactInstanceManager getReactInstanceManager() { diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactInstrumentationTest.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactInstrumentationTest.java new file mode 100644 index 00000000000000..fe6c7c687aec52 --- /dev/null +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactInstrumentationTest.java @@ -0,0 +1,124 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * + * 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.testing; + +import android.content.Intent; +import android.test.ActivityInstrumentationTestCase2; +import android.view.View; +import android.view.ViewGroup; +import com.facebook.react.bridge.ReactContext; +import com.facebook.react.testing.idledetection.IdleWaiter; + +/** + * Base class for instrumentation tests that runs React based application. + * + * This is similar to ReactAppInstrumentationTestCase except ReactInstrumentationTest allows + * optional rendering of components. A test case can render no components or render multiple + * components. + */ +public abstract class ReactInstrumentationTest extends + ActivityInstrumentationTestCase2 implements IdleWaiter { + + public ReactInstrumentationTest() { + super(ReactAppTestActivity.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + Intent intent = new Intent(); + intent.putExtra(ReactAppTestActivity.EXTRA_IS_FABRIC_TEST, isFabricTest()); + setActivityIntent(intent); + final ReactAppTestActivity activity = getActivity(); + try { + runTestOnUiThread(new Runnable() { + @Override + public void run() { + activity.loadBundle( + createReactInstanceSpecForTest(), + getBundleName(), + getEnableDevSupport()); + } + }); + } catch (Throwable t) { + throw new Exception("Unable to load react bundle " + getBundleName(), t); + } + } + + /** + * Renders this component within this test's activity + */ + public void renderComponent(final String componentName) throws Exception { + final ReactAppTestActivity activity = getActivity(); + try { + runTestOnUiThread(new Runnable() { + @Override + public void run() { + activity.renderComponent(componentName, null); + } + }); + } catch (Throwable t) { + throw new Exception("Unable to render component " + componentName, t); + } + assertTrue("Layout never occurred!", activity.waitForLayout(5000)); + waitForBridgeAndUIIdle(); + } + + @Override + protected void tearDown() throws Exception { + ReactAppTestActivity activity = getActivity(); + super.tearDown(); + activity.waitForDestroy(5000); + } + + public ViewGroup getRootView() { + return (ViewGroup) getActivity().getRootView(); + } + + public T getViewByTestId(String testID) { + return (T) ReactTestHelper + .getViewWithReactTestId((ViewGroup) getRootView().getParent(), testID); + } + + public SingleTouchGestureGenerator createGestureGenerator() { + return new SingleTouchGestureGenerator(getRootView(), this); + } + + public void waitForBridgeAndUIIdle() { + getActivity().waitForBridgeAndUIIdle(); + } + + public void waitForBridgeAndUIIdle(long timeoutMs) { + getActivity().waitForBridgeAndUIIdle(timeoutMs); + } + + protected boolean getEnableDevSupport() { + return false; + } + + protected boolean isFabricTest() { + return false; + } + + /** + * Override this method to provide extra native modules to be loaded before the app starts + */ + protected ReactInstanceSpecForTest createReactInstanceSpecForTest() { + return new ReactInstanceSpecForTest(); + } + + /** + * Implement this method to provide the bundle for this test + */ + protected abstract String getBundleName(); + + protected ReactContext getReactContext() { + return getActivity().getReactContext(); + } +} From 9d45de60accda028d11b715a3407119353a81d2c Mon Sep 17 00:00:00 2001 From: Mehdi Mulani Date: Mon, 19 Mar 2018 10:51:01 -0700 Subject: [PATCH 0067/1109] Properly tear down the reachabilityRef in RCTNetInfo Summary: The pull request that added this (#17397) simply forgot to remove the callback, which would cause crashes if the RCTNetInfo module was ever deallocated. While that usually doesn't happen in apps, it can if the user logs out and you need to wipe all the RCT modules (to remove user data, for instance). Reviewed By: PeteTheHeat Differential Revision: D7322999 fbshipit-source-id: e49ec7311b39920f7b7743a5854c0dda1dbccc73 --- Libraries/Network/RCTNetInfo.m | 1 + 1 file changed, 1 insertion(+) diff --git a/Libraries/Network/RCTNetInfo.m b/Libraries/Network/RCTNetInfo.m index afc3d1db33334c..9b51a5c1ab4ff6 100644 --- a/Libraries/Network/RCTNetInfo.m +++ b/Libraries/Network/RCTNetInfo.m @@ -164,6 +164,7 @@ - (BOOL)setReachabilityStatus:(SCNetworkReachabilityFlags)flags reject:(__unused RCTPromiseRejectBlock)reject) { SCNetworkReachabilityRef reachability = [self getReachabilityRef]; + SCNetworkReachabilityUnscheduleFromRunLoop(reachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); CFRelease(reachability); resolve(@{@"connectionType": _connectionType ?: RCTConnectionTypeUnknown, @"effectiveConnectionType": _effectiveConnectionType ?: RCTEffectiveConnectionTypeUnknown, From 41db09d573a458fb7a0787a87ba55aa0f47af2ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Mon, 19 Mar 2018 12:23:57 -0700 Subject: [PATCH 0068/1109] Remove @xplat cell syntax in open source, part 2 Differential Revision: D7325421 fbshipit-source-id: 95e3ee0a6c41292b1d2e1fc8b0691861ad69468f --- ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/BUCK | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/BUCK b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/BUCK index ac6ce3d53025ba..38ed913d7aa404 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/BUCK @@ -1,4 +1,4 @@ -load("@xplat//ReactNative:DEFS.bzl", "react_native_dep", "react_native_target", "rn_android_library", "IS_OSS_BUILD") +load("//ReactNative:DEFS.bzl", "react_native_dep", "react_native_target", "rn_android_library", "IS_OSS_BUILD") rn_android_library( name = "jsc", From ff70ecf868cf12fc66b45dc1496391d0a1e9011f Mon Sep 17 00:00:00 2001 From: Peter Argany Date: Mon, 19 Mar 2018 14:09:32 -0700 Subject: [PATCH 0069/1109] Fixed bug with autocapitalization Reviewed By: shergin Differential Revision: D7304936 fbshipit-source-id: ef587db89b64e7111dfdeb049c3a1a334c15430b --- Libraries/Text/TextInput/RCTBaseTextInputView.m | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Libraries/Text/TextInput/RCTBaseTextInputView.m b/Libraries/Text/TextInput/RCTBaseTextInputView.m index 65885a4882a686..64a3a865c6d7e7 100644 --- a/Libraries/Text/TextInput/RCTBaseTextInputView.m +++ b/Libraries/Text/TextInput/RCTBaseTextInputView.m @@ -102,7 +102,17 @@ - (void)setAttributedText:(NSAttributedString *)attributedText { NSInteger eventLag = _nativeEventCount - _mostRecentEventCount; - if (eventLag == 0 && ![attributedText isEqualToAttributedString:self.backedTextInputView.attributedText]) { + // Remove tag attribute to ensure correct attributed string comparison. + NSMutableAttributedString *const backedTextInputViewTextCopy = [self.backedTextInputView.attributedText mutableCopy]; + NSMutableAttributedString *const attributedTextCopy = [attributedText mutableCopy]; + + [backedTextInputViewTextCopy removeAttribute:RCTTextAttributesTagAttributeName + range:NSMakeRange(0, backedTextInputViewTextCopy.length)]; + + [attributedTextCopy removeAttribute:RCTTextAttributesTagAttributeName + range:NSMakeRange(0, attributedTextCopy.length)]; + + if (eventLag == 0 && ![attributedTextCopy isEqualToAttributedString:backedTextInputViewTextCopy]) { UITextRange *selection = self.backedTextInputView.selectedTextRange; NSInteger oldTextLength = self.backedTextInputView.attributedText.string.length; From 12535ae69d25930b438299fec7cbe6e16007e307 Mon Sep 17 00:00:00 2001 From: Naris Siamwalla Date: Mon, 19 Mar 2018 14:23:24 -0700 Subject: [PATCH 0070/1109] Fix clang-6 strictness surrounding virtual destructors Reviewed By: smeenai Differential Revision: D7326765 fbshipit-source-id: 9df477dfa89812e05e79b5e6d510bcbbc793381c --- ReactCommon/exceptions/ExceptionManager.h | 2 ++ .../fabric/core/componentdescriptor/ComponentDescriptor.h | 2 ++ ReactCommon/fabric/core/shadownode/Props.h | 2 ++ ReactCommon/fabric/debug/DebugStringConvertible.h | 2 ++ 4 files changed, 8 insertions(+) diff --git a/ReactCommon/exceptions/ExceptionManager.h b/ReactCommon/exceptions/ExceptionManager.h index ba07912bfa5940..842975b3ba879a 100644 --- a/ReactCommon/exceptions/ExceptionManager.h +++ b/ReactCommon/exceptions/ExceptionManager.h @@ -16,6 +16,8 @@ namespace react { */ class ExceptionManager { public: + virtual ~ExceptionManager() = default; + virtual void handleSoftException(const std::exception &e) const = 0; virtual void handleFatalException(const std::exception &e) const = 0; }; diff --git a/ReactCommon/fabric/core/componentdescriptor/ComponentDescriptor.h b/ReactCommon/fabric/core/componentdescriptor/ComponentDescriptor.h index 975900c91cf503..7b7b7a5578d678 100644 --- a/ReactCommon/fabric/core/componentdescriptor/ComponentDescriptor.h +++ b/ReactCommon/fabric/core/componentdescriptor/ComponentDescriptor.h @@ -26,6 +26,8 @@ using SharedComponentDescriptor = std::shared_ptr; class ComponentDescriptor { public: + virtual ~ComponentDescriptor() = default; + /* * Returns `componentHandle` associated with particular kind of components. * All `ShadowNode`s of this type must return same `componentHandle`. diff --git a/ReactCommon/fabric/core/shadownode/Props.h b/ReactCommon/fabric/core/shadownode/Props.h index da9f4f3b6f14ab..8a6a738348792f 100644 --- a/ReactCommon/fabric/core/shadownode/Props.h +++ b/ReactCommon/fabric/core/shadownode/Props.h @@ -28,6 +28,8 @@ class Props: public virtual DebugStringConvertible { public: + virtual ~Props() = default; + virtual void apply(const RawProps &rawProps); private: diff --git a/ReactCommon/fabric/debug/DebugStringConvertible.h b/ReactCommon/fabric/debug/DebugStringConvertible.h index b47d0c0d435fb4..8ef96d8882fdae 100644 --- a/ReactCommon/fabric/debug/DebugStringConvertible.h +++ b/ReactCommon/fabric/debug/DebugStringConvertible.h @@ -31,6 +31,8 @@ struct DebugStringConvertibleOptions { class DebugStringConvertible { public: + virtual ~DebugStringConvertible() = default; + // Returns a name of the object. // Default implementation returns "Node". virtual std::string getDebugName() const; From 75a735976d039c6d2db815d79e99731f086e306e Mon Sep 17 00:00:00 2001 From: Frederic Barthelemy Date: Mon, 19 Mar 2018 15:10:14 -0700 Subject: [PATCH 0071/1109] RCTObjcExecutor: fix initializer-list initialization order build warning. Summary: Fixes: #18384 Previously line 42 had a warning of: `Field 'm_jsThread' will be initialized after field 'm_delegate'` This appears to be because the private member fields are declared in a different order than the initializer-list was told to initialize things. I chose to re-order the initializer list because that fixes the warning by matching the code structure to what the compiler was telling us it was going to do. An alternate fix would be to change the order of the member variables declared in the `private:` section to match the coded order in the initializer list. This might be the right move if the initializer list had the correct intent, but this would be a breaking change from a behavior perspective, so I'd need somebody with more knowledge to suggest this is the right move. A. Examine line to see the warning is gone. B. Get a C++ guru to figure out the intent of this file and see if this actually exposed a bug that recommends we go with the alternate fix suggested above. [IOS][MINOR][React/CxxBridge/] - Build warning fix Closes https://github.com/facebook/react-native/pull/18385 Differential Revision: D7328272 Pulled By: mhorowitz fbshipit-source-id: 59d7ace6222c4609ac7d023f97e522e85e02a9db --- React/CxxBridge/RCTObjcExecutor.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/React/CxxBridge/RCTObjcExecutor.mm b/React/CxxBridge/RCTObjcExecutor.mm index 2f861ffc983ec8..6039ef24a50ad3 100644 --- a/React/CxxBridge/RCTObjcExecutor.mm +++ b/React/CxxBridge/RCTObjcExecutor.mm @@ -39,8 +39,8 @@ std::shared_ptr delegate) : m_jse(jse) , m_errorBlock(errorBlock) - , m_jsThread(std::move(jsThread)) , m_delegate(std::move(delegate)) + , m_jsThread(std::move(jsThread)) { m_jsCallback = ^(id json, NSError *error) { if (error) { From aaaa946e6d4774b1ae3a758428e1254adf38e142 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Mon, 19 Mar 2018 16:51:29 -0700 Subject: [PATCH 0072/1109] Fabric: Equality operators for geometry types Summary: We will need this soon. Reviewed By: fkgozali Differential Revision: D7330338 fbshipit-source-id: 30aeadc182893e86c6a039c74d245f9b56624151 --- ReactCommon/fabric/graphics/Geometry.h | 44 ++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/ReactCommon/fabric/graphics/Geometry.h b/ReactCommon/fabric/graphics/Geometry.h index dcaf88f43f54a3..8471b1d1a7db88 100644 --- a/ReactCommon/fabric/graphics/Geometry.h +++ b/ReactCommon/fabric/graphics/Geometry.h @@ -34,6 +34,16 @@ struct Point { friend Point operator + (Point lhs, const Point& rhs) { return lhs += rhs; } + + bool operator ==(const Point& rhs) const { + return + std::tie(this->x, this->y) == + std::tie(rhs.x, rhs.y); + } + + bool operator !=(const Point& rhs) const { + return !(*this == rhs); + } }; /* @@ -42,6 +52,16 @@ struct Point { struct Size { Float width {0}; Float height {0}; + + bool operator ==(const Size& rhs) const { + return + std::tie(this->width, this->height) == + std::tie(rhs.width, rhs.height); + } + + bool operator !=(const Size& rhs) const { + return !(*this == rhs); + } }; /* @@ -50,16 +70,36 @@ struct Size { struct Rect { Point origin {0, 0}; Size size {0, 0}; + + bool operator ==(const Rect& rhs) const { + return + std::tie(this->origin, this->size) == + std::tie(rhs.origin, rhs.size); + } + + bool operator !=(const Rect& rhs) const { + return !(*this == rhs); + } }; /* * EdgeInsets */ struct EdgeInsets { - Float top {0}; Float left {0}; - Float bottom {0}; + Float top {0}; Float right {0}; + Float bottom {0}; + + bool operator ==(const EdgeInsets& rhs) const { + return + std::tie(this->left, this->top, this->right, this->bottom) == + std::tie(rhs.left, rhs.top, rhs.right, rhs.bottom); + } + + bool operator !=(const EdgeInsets& rhs) const { + return !(*this == rhs); + } }; } // namespace react From a5a34565e070c40f7f98aad8a09fdba904a73906 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Mon, 19 Mar 2018 16:51:30 -0700 Subject: [PATCH 0073/1109] Fabric: Proper return value of `LayoutableShadowNode::setLayoutMetrics()` Summary: `LayoutableShadowNode::setLayoutMetrics()` must return `false` is nothing was changes. Reviewed By: fkgozali Differential Revision: D7330334 fbshipit-source-id: 700d50b0047919fa2b919acfa72825f100cd496f --- ReactCommon/fabric/core/layout/LayoutMetrics.h | 10 ++++++++++ .../fabric/core/layout/LayoutableShadowNode.cpp | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/ReactCommon/fabric/core/layout/LayoutMetrics.h b/ReactCommon/fabric/core/layout/LayoutMetrics.h index d34d7d9f9780d7..4bc2641a91bd75 100644 --- a/ReactCommon/fabric/core/layout/LayoutMetrics.h +++ b/ReactCommon/fabric/core/layout/LayoutMetrics.h @@ -22,6 +22,16 @@ struct LayoutMetrics { EdgeInsets borderWidth {0}; DisplayType displayType {Flex}; LayoutDirection layoutDirection {Undefined}; + + bool operator ==(const LayoutMetrics& rhs) const { + return + std::tie(this->frame, this->contentInsets, this->borderWidth, this->displayType, this->layoutDirection) == + std::tie(rhs.frame, rhs.contentInsets, rhs.borderWidth, rhs.displayType, rhs.layoutDirection); + } + + bool operator !=(const LayoutMetrics& rhs) const { + return !(*this == rhs); + } }; } // namespace react diff --git a/ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp b/ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp index 3f0b50ae747ab4..ea2de415cdfed2 100644 --- a/ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp +++ b/ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp @@ -19,6 +19,10 @@ LayoutMetrics LayoutableShadowNode::getLayoutMetrics() const { } bool LayoutableShadowNode::setLayoutMetrics(LayoutMetrics layoutMetrics) { + if (layoutMetrics_ == layoutMetrics) { + return false; + } + layoutMetrics_ = layoutMetrics; return true; } From ff288b7416977d81ac442fd9fbf210b6f2b85e31 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Mon, 19 Mar 2018 16:51:32 -0700 Subject: [PATCH 0074/1109] Fabric: Complete implementation of `layoutMetricsFromYogaNode` Summary: That was simply incomplete. Reviewed By: fkgozali Differential Revision: D7330336 fbshipit-source-id: c495c7f61d8e551fa963bfa6cc0408343eb8439b --- .../view/yoga/yogaValuesConversions.cpp | 38 +++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/ReactCommon/fabric/view/yoga/yogaValuesConversions.cpp b/ReactCommon/fabric/view/yoga/yogaValuesConversions.cpp index e329b8437644d3..e780d2cecd6fb1 100644 --- a/ReactCommon/fabric/view/yoga/yogaValuesConversions.cpp +++ b/ReactCommon/fabric/view/yoga/yogaValuesConversions.cpp @@ -15,10 +15,18 @@ namespace facebook { namespace react { Float fabricFloatFromYogaFloat(float value) { + if (value == YGUndefined) { + return Undefined; + } + return (Float)value; } float yogaFloatFromFabricFloat(Float value) { + if (value == Undefined) { + return YGUndefined; + } + return (float)value; } @@ -44,11 +52,35 @@ LayoutMetrics layoutMetricsFromYogaNode(YGNode &yogaNode) { YGLayout layout = yogaNode.getLayout(); layoutMetrics.frame = Rect { - Point {fabricFloatFromYogaFloat(layout.position[0]), fabricFloatFromYogaFloat(layout.position[1])}, - Size {fabricFloatFromYogaFloat(layout.dimensions[0]), fabricFloatFromYogaFloat(layout.dimensions[1])} + Point { + fabricFloatFromYogaFloat(layout.position[YGEdgeLeft]), + fabricFloatFromYogaFloat(layout.position[YGEdgeTop]) + }, + Size { + fabricFloatFromYogaFloat(layout.dimensions[YGDimensionWidth]), + fabricFloatFromYogaFloat(layout.dimensions[YGDimensionHeight]) + } }; - // FIXME: Add more. + layoutMetrics.borderWidth = EdgeInsets { + fabricFloatFromYogaFloat(layout.border[YGEdgeLeft]), + fabricFloatFromYogaFloat(layout.border[YGEdgeTop]), + fabricFloatFromYogaFloat(layout.border[YGEdgeRight]), + fabricFloatFromYogaFloat(layout.border[YGEdgeBottom]) + }; + + layoutMetrics.contentInsets = EdgeInsets { + fabricFloatFromYogaFloat(layout.border[YGEdgeLeft] + layout.padding[YGEdgeLeft]), + fabricFloatFromYogaFloat(layout.border[YGEdgeTop] + layout.padding[YGEdgeTop]), + fabricFloatFromYogaFloat(layout.border[YGEdgeRight] + layout.padding[YGEdgeRight]), + fabricFloatFromYogaFloat(layout.border[YGEdgeBottom] + layout.padding[YGEdgeBottom]) + }; + + layoutMetrics.displayType = + yogaNode.getStyle().display == YGDisplayNone ? None : Flex; + + layoutMetrics.layoutDirection = + layout.direction == YGDirectionRTL ? RightToLeft : LeftToRight; return layoutMetrics; } From 39383d1189a23eb52e9ea6bdcbb11bba81cefb61 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Mon, 19 Mar 2018 16:51:35 -0700 Subject: [PATCH 0075/1109] Fabric: Improved YogaLayoutableShadowNode printing Summary: `LTR` is actually a default value for `direction` here, because an `inherit` value makes no sense for YGLayout (because it's *computed* value by definition). Reviewed By: fkgozali Differential Revision: D7330335 fbshipit-source-id: b3c7736c104689f2296e150f0cf57d622483d537 --- ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp index 3684f75abc4bea..09301f35b50afa 100644 --- a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp +++ b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp @@ -149,6 +149,7 @@ SharedDebugStringConvertibleList YogaLayoutableShadowNode::getDebugProps() const } YGLayout defaultYogaLayout = YGLayout(); + defaultYogaLayout.direction = YGDirectionLTR; YGLayout currentYogaLayout = std::const_pointer_cast(yogaNode_)->getLayout(); #define YOGA_LAYOUT_PROPS_ADD_TO_SET(stringName, propertyName, accessor, convertor) \ From b808bfdce2384837197f92ffa730a188c6411a98 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Mon, 19 Mar 2018 16:51:39 -0700 Subject: [PATCH 0076/1109] Fabric: Introducting `ShadowNode.sourceNode`, the node used in copy-constructor Summary: We will need this later in the diffing alogrithm. Reviewed By: fkgozali Differential Revision: D7330337 fbshipit-source-id: 3da44a62e4d5f30deed28b18a5779544153244f3 --- .../fabric/core/shadownode/ShadowNode.cpp | 21 +++++++++++++++++-- .../fabric/core/shadownode/ShadowNode.h | 6 ++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp index d095a882186dde..3f7aee7be56b63 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp @@ -41,7 +41,8 @@ ShadowNode::ShadowNode( tag_(shadowNode->tag_), instanceHandle_(shadowNode->instanceHandle_), props_(props ? props : shadowNode->props_), - children_(children ? children : shadowNode->children_) {} + children_(children ? children : shadowNode->children_), + sourceNode_(shadowNode) {} #pragma mark - Getters @@ -57,7 +58,9 @@ Tag ShadowNode::getTag() const { return tag_; } -#pragma mark - Mutating Methods +SharedShadowNode ShadowNode::getSourceNode() const { + return sourceNode_; +} void ShadowNode::sealRecursive() const { if (getSealed()) { @@ -73,6 +76,8 @@ void ShadowNode::sealRecursive() const { } } +#pragma mark - Mutating Methods + void ShadowNode::appendChild(const SharedShadowNode &child) { ensureUnsealed(); @@ -95,6 +100,11 @@ void ShadowNode::replaceChild(const SharedShadowNode &oldChild, const SharedShad children_ = std::make_shared(nonConstChildrenCopy); } +void ShadowNode::clearSourceNode() { + ensureUnsealed(); + sourceNode_ = nullptr; +} + #pragma mark - DebugStringConvertible std::string ShadowNode::getDebugName() const { @@ -127,6 +137,13 @@ SharedDebugStringConvertibleList ShadowNode::getDebugProps() const { list.push_back(std::make_shared("handle", std::to_string((size_t)instanceHandle_))); } + if (sourceNode_) { + list.push_back(std::make_shared( + "source", + sourceNode_->getDebugDescription({.maximumDepth = 1, .format = false}) + )); + } + SharedDebugStringConvertibleList propsList = props_->getDebugProps(); std::move(propsList.begin(), propsList.end(), std::back_inserter(list)); return list; diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.h b/ReactCommon/fabric/core/shadownode/ShadowNode.h index 0f2fab928056cd..7fcb9d04cfa08e 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.h +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.h @@ -55,13 +55,14 @@ class ShadowNode: SharedShadowNodeSharedList getChildren() const; SharedProps getProps() const; Tag getTag() const; + SharedShadowNode getSourceNode() const; + void sealRecursive() const; #pragma mark - Mutating Methods - void sealRecursive() const; - void appendChild(const SharedShadowNode &child); void replaceChild(const SharedShadowNode &oldChild, const SharedShadowNode &newChild); + void clearSourceNode(); #pragma mark - DebugStringConvertible @@ -76,6 +77,7 @@ class ShadowNode: InstanceHandle instanceHandle_; SharedProps props_; SharedShadowNodeSharedList children_; + SharedShadowNode sourceNode_; }; } // namespace react From e2462e90166d29cd3cbfa95ad4bbeccc17b78426 Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Mon, 19 Mar 2018 17:33:04 -0700 Subject: [PATCH 0077/1109] iOS: set the default measure size correctly for RCTSurfaceHostingView Summary: The RCTRootView default needs to be translated during init of RCTSurfaceHostingView correctly. Reviewed By: shergin Differential Revision: D7327918 fbshipit-source-id: 67a2a42b554782b37a032cc0470d794554cc1e5a --- .../RCTSurfaceHostingProxyRootView.mm | 5 ++++- .../SurfaceHostingView/RCTSurfaceHostingView.h | 6 ++++-- .../SurfaceHostingView/RCTSurfaceHostingView.mm | 11 ++++------- React/Fabric/Surface/RCTFabricSurfaceHostingView.mm | 3 ++- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingProxyRootView.mm b/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingProxyRootView.mm index 4fc100f6b6c15c..076773a58b567c 100644 --- a/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingProxyRootView.mm +++ b/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingProxyRootView.mm @@ -61,7 +61,10 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge [bridge.performanceLogger markStartForTag:RCTPLTTI]; } - if (self = [super initWithBridge:bridge moduleName:moduleName initialProperties:initialProperties]) { + // `RCTRootViewSizeFlexibilityNone` is the RCTRootView's default. + RCTSurfaceSizeMeasureMode sizeMeasureMode = convertToSurfaceSizeMeasureMode(RCTRootViewSizeFlexibilityNone); + + if (self = [super initWithBridge:bridge moduleName:moduleName initialProperties:initialProperties sizeMeasureMode:sizeMeasureMode]) { self.backgroundColor = [UIColor whiteColor]; } diff --git a/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h b/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h index 4434df84e00503..25894ec0015611 100644 --- a/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h +++ b/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h @@ -31,7 +31,8 @@ NS_ASSUME_NONNULL_BEGIN * Instanciates a view with given Surface object. * Note: The view retains the surface object. */ -- (instancetype)initWithSurface:(RCTSurface *)surface NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithSurface:(RCTSurface *)surface + sizeMeasureMode:(RCTSurfaceSizeMeasureMode)sizeMeasureMode NS_DESIGNATED_INITIALIZER; /** * Convenience initializer. @@ -40,7 +41,8 @@ NS_ASSUME_NONNULL_BEGIN */ - (instancetype)initWithBridge:(RCTBridge *)bridge moduleName:(NSString *)moduleName - initialProperties:(NSDictionary *)initialProperties; + initialProperties:(NSDictionary *)initialProperties + sizeMeasureMode:(RCTSurfaceSizeMeasureMode)sizeMeasureMode; /** * Create an instance of RCTSurface to be hosted. diff --git a/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm b/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm index 3c3ab2bf7fa8a5..9eb41ff0b2d091 100644 --- a/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm +++ b/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm @@ -33,20 +33,17 @@ @implementation RCTSurfaceHostingView { - (instancetype)initWithBridge:(RCTBridge *)bridge moduleName:(NSString *)moduleName initialProperties:(NSDictionary *)initialProperties + sizeMeasureMode:(RCTSurfaceSizeMeasureMode)sizeMeasureMode { RCTSurface *surface = [self createSurfaceWithBridge:bridge moduleName:moduleName initialProperties:initialProperties]; - return [self initWithSurface:surface]; - + return [self initWithSurface:surface sizeMeasureMode:sizeMeasureMode]; } -- (instancetype)initWithSurface:(RCTSurface *)surface +- (instancetype)initWithSurface:(RCTSurface *)surface sizeMeasureMode:(RCTSurfaceSizeMeasureMode)sizeMeasureMode { if (self = [super initWithFrame:CGRectZero]) { _surface = surface; - - _sizeMeasureMode = - RCTSurfaceSizeMeasureModeWidthAtMost | - RCTSurfaceSizeMeasureModeHeightAtMost; + _sizeMeasureMode = sizeMeasureMode; _surface.delegate = self; _stage = surface.stage; diff --git a/React/Fabric/Surface/RCTFabricSurfaceHostingView.mm b/React/Fabric/Surface/RCTFabricSurfaceHostingView.mm index 395d40afb68e21..eec159cceb9236 100644 --- a/React/Fabric/Surface/RCTFabricSurfaceHostingView.mm +++ b/React/Fabric/Surface/RCTFabricSurfaceHostingView.mm @@ -14,11 +14,12 @@ @implementation RCTFabricSurfaceHostingView - (instancetype)initWithBridge:(RCTBridge *)bridge moduleName:(NSString *)moduleName initialProperties:(NSDictionary *)initialProperties + sizeMeasureMode:(RCTSurfaceSizeMeasureMode)sizeMeasureMode { RCTFabricSurface *surface = [[RCTFabricSurface alloc] initWithBridge:bridge moduleName:moduleName initialProperties:initialProperties]; - return [self initWithSurface:surface]; + return [self initWithSurface:surface sizeMeasureMode:sizeMeasureMode]; } @end From 0930fef46d23d4b2894f3f05afb2c2807b2b354c Mon Sep 17 00:00:00 2001 From: David Vacca Date: Mon, 19 Mar 2018 18:21:34 -0700 Subject: [PATCH 0078/1109] Disable YogaNode cloning in Android Reviewed By: achen1 Differential Revision: D7313239 fbshipit-source-id: ecf905a22e04a2115ab968fd29f7582301f0f3c9 --- .../react/uimanager/ReactShadowNodeImpl.java | 65 ++++++++++--------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java index 664dd09729af13..dddaf466caa3ec 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java @@ -111,35 +111,32 @@ public ReactShadowNodeImpl() { } } - public ReactShadowNodeImpl(ReactShadowNodeImpl original) { - try { - mReactTag = original.mReactTag; - mRootTag = original.mRootTag; - mViewClassName = original.mViewClassName; - mRootNode = original.mRootNode; - mThemedContext = original.mThemedContext; - mShouldNotifyOnLayout = original.mShouldNotifyOnLayout; - mNodeUpdated = original.mNodeUpdated; - mChildren = original.mChildren == null ? null : new ArrayList<>(original.mChildren); - mIsLayoutOnly = original.mIsLayoutOnly; - mTotalNativeChildren = original.mTotalNativeChildren; - mNativeParent = original.mNativeParent; - mNativeChildren = original.mNativeChildren == null ? null : new ArrayList<>(original.mNativeChildren); - mNativeParent = original.mNativeParent; - mScreenX = original.mScreenX; - mScreenY = original.mScreenY; - mScreenWidth = original.mScreenWidth; - mScreenHeight = original.mScreenHeight; - arraycopy(original.mPadding, 0, mPadding, 0, original.mPadding.length); - arraycopy(original.mPaddingIsPercent, 0, mPaddingIsPercent, 0, original.mPaddingIsPercent.length); - mYogaNode = original.mYogaNode.clone(); - mYogaNode.setData(this); - mParent = null; - mNewProps = null; - } catch (CloneNotSupportedException e) { - // it should never happen - throw new IllegalArgumentException(); - } + protected ReactShadowNodeImpl(ReactShadowNodeImpl original) { + mReactTag = original.mReactTag; + mRootTag = original.mRootTag; + mViewClassName = original.mViewClassName; + mRootNode = original.mRootNode; + mThemedContext = original.mThemedContext; + mShouldNotifyOnLayout = original.mShouldNotifyOnLayout; + mNodeUpdated = original.mNodeUpdated; + mIsLayoutOnly = original.mIsLayoutOnly; + mTotalNativeChildren = original.mTotalNativeChildren; + mNativeParent = original.mNativeParent; + mNativeParent = original.mNativeParent; + mScreenX = original.mScreenX; + mScreenY = original.mScreenY; + mScreenWidth = original.mScreenWidth; + mScreenHeight = original.mScreenHeight; + arraycopy(original.mPadding, 0, mPadding, 0, original.mPadding.length); + arraycopy(original.mPaddingIsPercent, 0, mPaddingIsPercent, 0, original.mPaddingIsPercent.length); + mNewProps = null; + mParent = null; + mYogaNode = original.mYogaNode; + // TODO: T26729293 clone YogaNode instead of reusing the same instance + //mYogaNode = original.mYogaNode.clone(); + mNativeChildren = original.mNativeChildren == null ? null : new ArrayList<>(original.mNativeChildren); + mChildren = original.mChildren == null ? null : new ArrayList<>(original.mChildren); + mYogaNode.setData(this); } @Override @@ -279,6 +276,16 @@ public void addChildAt(ReactShadowNodeImpl child, int i) { + toString() + "')"); } + // TODO: T26729293 This is a temporary code that will be replaced as part of T26729293. + YogaNode parent = childYogaNode.getParent(); + if (parent != null) { + for (int k = 0; k < parent.getChildCount(); k++) { + if (parent.getChildAt(k) == childYogaNode) { + parent.removeChildAt(k); + break; + } + } + } mYogaNode.addChildAt(childYogaNode, i); } markUpdated(); From b43afcdde964a4be48c45cbec24c0c8001031a84 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Mon, 19 Mar 2018 18:21:35 -0700 Subject: [PATCH 0079/1109] Change cloning mechanism for mutableCopyWithNewChildren method Reviewed By: achen1 Differential Revision: D7239873 fbshipit-source-id: d931e753c3a0b26d439eb450d62af93a672641f4 --- .../react/fabric/FabricUIManager.java | 2 +- .../react/uimanager/LayoutShadowNode.java | 4 +- .../react/uimanager/ReactShadowNode.java | 7 +++ .../react/uimanager/ReactShadowNodeImpl.java | 46 +++++++++++++------ .../react/views/art/ARTGroupShadowNode.java | 2 +- .../react/views/art/ARTShapeShadowNode.java | 2 +- .../react/views/art/ARTTextShadowNode.java | 2 +- .../views/modal/ModalHostShadowNode.java | 2 +- .../progressbar/ProgressBarShadowNode.java | 2 +- .../views/slider/ReactSliderManager.java | 2 +- .../views/switchview/ReactSwitchManager.java | 2 +- .../views/text/ReactRawTextShadowNode.java | 2 +- .../react/views/text/ReactTextShadowNode.java | 2 +- .../text/ReactVirtualTextShadowNode.java | 2 +- ...coBasedReactTextInlineImageShadowNode.java | 2 +- .../textinput/ReactTextInputShadowNode.java | 2 +- 16 files changed, 53 insertions(+), 30 deletions(-) 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 38eea630d4bb46..f66b0ce568238f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -177,7 +177,7 @@ public ReactShadowNode cloneNodeWithNewChildrenAndProps( private void assertReactShadowNodeCopy(ReactShadowNode source, ReactShadowNode target) { Assertions.assertCondition(source.getClass().equals(target.getClass()), "Found " + target.getClass() + " class when expecting: " + source.getClass() + - ". Check that " + source.getClass() + " implements the mutableCopy() method correctly."); + ". Check that " + source.getClass() + " implements the copy() method correctly."); } /** diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java index b941c21672a4ae..86c1a7832ba778 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java @@ -74,11 +74,11 @@ public LayoutShadowNode() { protected LayoutShadowNode(LayoutShadowNode node) { super(node); - mTempYogaValue = new MutableYogaValue(node.mTempYogaValue); + mTempYogaValue = new MutableYogaValue(); } @Override - public LayoutShadowNode mutableCopy() { + protected LayoutShadowNode copy() { return new LayoutShadowNode(this); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java index ab8e2692533ab8..75ae4fb8ac0ef4 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java @@ -18,6 +18,7 @@ import com.facebook.yoga.YogaPositionType; import com.facebook.yoga.YogaValue; import com.facebook.yoga.YogaWrap; +import java.util.List; import javax.annotation.Nullable; /** @@ -358,4 +359,10 @@ public interface ReactShadowNode { boolean isMeasureDefined(); void dispose(); + + /** + * @return an immutable {@link List} containing the children of this + * {@link ReactShadowNode}. + */ + List getChildrenList(); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java index dddaf466caa3ec..7673c45236f3eb 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java @@ -28,6 +28,8 @@ import com.facebook.yoga.YogaWrap; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.List; import javax.annotation.Nullable; /** @@ -96,7 +98,7 @@ public void onNodeCloned(YogaNode oldYogaNode, private final Spacing mDefaultPadding = new Spacing(0); private final float[] mPadding = new float[Spacing.ALL + 1]; private final boolean[] mPaddingIsPercent = new boolean[Spacing.ALL + 1]; - private final YogaNode mYogaNode; + private YogaNode mYogaNode; private @Nullable ReactStylesDiffMap mNewProps; @@ -120,8 +122,6 @@ protected ReactShadowNodeImpl(ReactShadowNodeImpl original) { mShouldNotifyOnLayout = original.mShouldNotifyOnLayout; mNodeUpdated = original.mNodeUpdated; mIsLayoutOnly = original.mIsLayoutOnly; - mTotalNativeChildren = original.mTotalNativeChildren; - mNativeParent = original.mNativeParent; mNativeParent = original.mNativeParent; mScreenX = original.mScreenX; mScreenY = original.mScreenY; @@ -131,24 +131,38 @@ protected ReactShadowNodeImpl(ReactShadowNodeImpl original) { arraycopy(original.mPaddingIsPercent, 0, mPaddingIsPercent, 0, original.mPaddingIsPercent.length); mNewProps = null; mParent = null; - mYogaNode = original.mYogaNode; - // TODO: T26729293 clone YogaNode instead of reusing the same instance - //mYogaNode = original.mYogaNode.clone(); - mNativeChildren = original.mNativeChildren == null ? null : new ArrayList<>(original.mNativeChildren); - mChildren = original.mChildren == null ? null : new ArrayList<>(original.mChildren); - mYogaNode.setData(this); + } + + /** + * @return a copy of this object (no including copy of its children or the underlying yogaNode). + */ + protected ReactShadowNodeImpl copy() { + return new ReactShadowNodeImpl(this); } @Override public ReactShadowNodeImpl mutableCopy() { - return new ReactShadowNodeImpl(this); + ReactShadowNodeImpl copy = copy(); + copy.mYogaNode = mYogaNode; + // TODO: T26729293 clone YogaNode instead of reusing the same instance + //mYogaNode = original.mYogaNode.clone(); + copy.mNativeChildren = mNativeChildren == null ? null : new ArrayList<>(mNativeChildren); + copy.mTotalNativeChildren = mTotalNativeChildren; + copy.mChildren = mChildren == null ? null : new ArrayList<>(mChildren); + copy.mYogaNode.setData(this); + return copy; } @Override public ReactShadowNodeImpl mutableCopyWithNewChildren() { - ReactShadowNodeImpl copy = mutableCopy(); + ReactShadowNodeImpl copy = copy(); + copy.mYogaNode = mYogaNode; + // TODO: T26729293 clone YogaNode instead of reusing the same instance + //mYogaNode = original.mYogaNode.cloneWithNewChildren(); copy.mNativeChildren = null; copy.mChildren = null; + copy.mTotalNativeChildren = 0; + copy.mYogaNode.setData(this); return copy; } @@ -253,10 +267,6 @@ public final boolean isDirty() { @Override public void addChildAt(ReactShadowNodeImpl child, int i) { - if (child.getParent() != null) { - throw new IllegalViewOperationException( - "Tried to add child that already has a parent! Remove it from its parent first."); - } if (mChildren == null) { mChildren = new ArrayList<>(4); } @@ -1056,4 +1066,10 @@ public void dispose() { YogaNodePool.get().release(mYogaNode); } } + + @Nullable + @Override + public List getChildrenList() { + return mChildren == null ? null : Collections.unmodifiableList(mChildren); + } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTGroupShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTGroupShadowNode.java index 35cf8169ca18fe..fdb9f53b301869 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTGroupShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTGroupShadowNode.java @@ -43,7 +43,7 @@ public void setClipping(@Nullable ReadableArray clippingDims) { } @Override - public ReactShadowNodeImpl mutableCopy() { + protected ReactShadowNodeImpl copy() { return new ARTGroupShadowNode(this); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTShapeShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTShapeShadowNode.java index e60ad880397b89..d4bc72e284f425 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTShapeShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTShapeShadowNode.java @@ -72,7 +72,7 @@ public ARTShapeShadowNode(ARTShapeShadowNode node) { } @Override - public ARTShapeShadowNode mutableCopy() { + protected ARTShapeShadowNode copy() { return new ARTShapeShadowNode(this); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTTextShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTTextShadowNode.java index 4a52e7a28a06c1..accb79e4ef8323 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTTextShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTTextShadowNode.java @@ -49,7 +49,7 @@ public ARTTextShadowNode(ARTTextShadowNode node) { } @Override - public ARTShapeShadowNode mutableCopy() { + protected ARTShapeShadowNode copy() { return new ARTTextShadowNode(this); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ModalHostShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ModalHostShadowNode.java index 5e429ac67bb2c6..5b63f107dd6b0e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ModalHostShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ModalHostShadowNode.java @@ -28,7 +28,7 @@ private ModalHostShadowNode(ModalHostShadowNode node) { } @Override - public ModalHostShadowNode mutableCopy() { + protected ModalHostShadowNode copy() { return new ModalHostShadowNode(this); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarShadowNode.java index 5e44b62135e278..367f4a90bd3d71 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarShadowNode.java @@ -53,7 +53,7 @@ public ProgressBarShadowNode(ProgressBarShadowNode node) { } @Override - public ProgressBarShadowNode mutableCopy() { + protected ProgressBarShadowNode copy() { return new ProgressBarShadowNode(this); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/slider/ReactSliderManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/slider/ReactSliderManager.java index 9ab464ad0e19d6..a73aa6ec72f6ce 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/slider/ReactSliderManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/slider/ReactSliderManager.java @@ -64,7 +64,7 @@ private void initMeasureFunction() { } @Override - public ReactSliderShadowNode mutableCopy() { + protected ReactSliderShadowNode copy() { return new ReactSliderShadowNode(this); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java index 62a3ad3f41fac3..1c9bff1ce1b9ad 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java @@ -56,7 +56,7 @@ private void initMeasureFunction() { } @Override - public ReactSwitchShadowNode mutableCopy() { + protected ReactSwitchShadowNode copy() { return new ReactSwitchShadowNode(this); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactRawTextShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactRawTextShadowNode.java index 87f6d53692c59f..488abfe84c0651 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactRawTextShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactRawTextShadowNode.java @@ -30,7 +30,7 @@ private ReactRawTextShadowNode(ReactRawTextShadowNode node) { } @Override - public ReactShadowNodeImpl mutableCopy() { + protected ReactShadowNodeImpl copy() { return new ReactRawTextShadowNode(this); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java index 72e044ee8b047a..37b13700fc3670 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java @@ -154,7 +154,7 @@ private void initMeasureFunction() { } @Override - public LayoutShadowNode mutableCopy() { + protected LayoutShadowNode copy() { return new ReactTextShadowNode(this); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactVirtualTextShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactVirtualTextShadowNode.java index 6506e9697abb4a..59ae82cc710225 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactVirtualTextShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactVirtualTextShadowNode.java @@ -19,7 +19,7 @@ private ReactVirtualTextShadowNode(ReactVirtualTextShadowNode node) { } @Override - public ReactVirtualTextShadowNode mutableCopy() { + protected ReactVirtualTextShadowNode copy() { return new ReactVirtualTextShadowNode(this); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageShadowNode.java index 56298de90205f3..c66f009714c8f2 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageShadowNode.java @@ -60,7 +60,7 @@ private FrescoBasedReactTextInlineImageShadowNode(FrescoBasedReactTextInlineImag } @Override - public FrescoBasedReactTextInlineImageShadowNode mutableCopy() { + protected FrescoBasedReactTextInlineImageShadowNode copy() { return new FrescoBasedReactTextInlineImageShadowNode(this); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java index 375c02a6285711..2fb427ee805793 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java @@ -61,7 +61,7 @@ private ReactTextInputShadowNode(ReactTextInputShadowNode node) { } @Override - public ReactTextInputShadowNode mutableCopy() { + protected ReactTextInputShadowNode copy() { return new ReactTextInputShadowNode(this); } From 3f84a0a6f483aed1aeb93820550451c9f35eb726 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Mon, 19 Mar 2018 18:21:37 -0700 Subject: [PATCH 0080/1109] Extend ReactShadowNode in order to have a reference to the ReactShadowNode that was used to clone a node Reviewed By: achen1 Differential Revision: D7289345 fbshipit-source-id: 34bfba8aca43299a3a8929a0e3eb85721f736dd0 --- .../com/facebook/react/uimanager/ReactShadowNode.java | 8 ++++++++ .../facebook/react/uimanager/ReactShadowNodeImpl.java | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java index 75ae4fb8ac0ef4..dbf64b1355b84b 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java @@ -365,4 +365,12 @@ public interface ReactShadowNode { * {@link ReactShadowNode}. */ List getChildrenList(); + + /** + * @return the {@link ReactShadowNode} that was used during the cloning mechanism to create + * this {@link ReactShadowNode} or null if this object was not created using a clone operation. + */ + @Nullable ReactShadowNode getOriginalReactShadowNode(); + + void setOriginalReactShadowNode(@Nullable ReactShadowNode node); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java index 7673c45236f3eb..d097842e4e135c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java @@ -99,6 +99,7 @@ public void onNodeCloned(YogaNode oldYogaNode, private final float[] mPadding = new float[Spacing.ALL + 1]; private final boolean[] mPaddingIsPercent = new boolean[Spacing.ALL + 1]; private YogaNode mYogaNode; + private ReactShadowNode mOriginalReactShadowNode = null; private @Nullable ReactStylesDiffMap mNewProps; @@ -1072,4 +1073,14 @@ public void dispose() { public List getChildrenList() { return mChildren == null ? null : Collections.unmodifiableList(mChildren); } + + @Override + public ReactShadowNode getOriginalReactShadowNode() { + return mOriginalReactShadowNode; + } + + @Override + public void setOriginalReactShadowNode(ReactShadowNode node) { + mOriginalReactShadowNode = node; + } } From 7d3de1016a37e28977840d71104b9f1348525419 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Mon, 19 Mar 2018 18:21:39 -0700 Subject: [PATCH 0081/1109] Implement Fabric Reconciler Reviewed By: achen1 Differential Revision: D7240208 fbshipit-source-id: 236b76146c50fb7f357190b08f8a5bfcef7f6645 --- .../com/facebook/react/common/ArrayUtils.java | 9 + .../main/java/com/facebook/react/fabric/BUCK | 1 + .../react/fabric/FabricReconciler.java | 108 +++++++++++ .../react/fabric/FabricUIManager.java | 180 +++++++++--------- .../react/uimanager/ReactShadowNodeImpl.java | 8 + 5 files changed, 214 insertions(+), 92 deletions(-) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/common/ArrayUtils.java b/ReactAndroid/src/main/java/com/facebook/react/common/ArrayUtils.java index 0036e9bac13abb..41b62c19f2554a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/common/ArrayUtils.java +++ b/ReactAndroid/src/main/java/com/facebook/react/common/ArrayUtils.java @@ -1,6 +1,7 @@ package com.facebook.react.common; import java.util.Arrays; +import java.util.List; public class ArrayUtils { @@ -8,4 +9,12 @@ public static float[] copyArray(float[] array) { return array == null ? null : Arrays.copyOf(array, array.length); } + public static int[] copyListToArray(List list) { + int[] array = new int[list.size()]; + for (int t = 0 ; t < list.size() ; t++) { + array[t] = list.get(t); + } + return array; + } + } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/BUCK b/ReactAndroid/src/main/java/com/facebook/react/fabric/BUCK index a5c3d74099be35..da59ddbf2bfc3d 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/BUCK @@ -18,6 +18,7 @@ rn_android_library( react_native_target("java/com/facebook/react/uimanager:uimanager"), react_native_target("java/com/facebook/react/uimanager/annotations:annotations"), react_native_target("java/com/facebook/react/module/annotations:annotations"), + react_native_target("java/com/facebook/react/common:common"), react_native_target("java/com/facebook/react/modules/i18nmanager:i18nmanager"), ], ) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java new file mode 100644 index 00000000000000..a4666759c9905a --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java @@ -0,0 +1,108 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * + * 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.fabric; + +import com.facebook.react.common.ArrayUtils; +import com.facebook.react.uimanager.ReactShadowNode; +import com.facebook.react.uimanager.UIViewOperationQueue; +import com.facebook.react.uimanager.ViewAtIndex; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import javax.annotation.Nullable; + +public class FabricReconciler { + + private UIViewOperationQueue uiViewOperationQueue; + + public FabricReconciler(UIViewOperationQueue uiViewOperationQueue) { + this.uiViewOperationQueue = uiViewOperationQueue; + } + + public void manageChildren(ReactShadowNode previousRootShadowNode, ReactShadowNode newRootShadowNode) { + List prevList = + previousRootShadowNode == null ? null : previousRootShadowNode.getChildrenList(); + manageChildren(newRootShadowNode, prevList, newRootShadowNode.getChildrenList()); + } + + private void manageChildren( + ReactShadowNode parent, + @Nullable List prevList, + @Nullable List newList) { + prevList = prevList == null ? Collections.emptyList() : prevList; + newList = newList == null ? Collections.emptyList() : newList; + + // Iterate through each child list and compare each previous and next child. Same nodes + // implies no change is needed. If the nodes are different but are referencing the same view, + // the view needs to be updated with new props and children. Otherwise, there has been + // a change in the children positions. + int sameReactTagIndex = 0; + for (; sameReactTagIndex < Math.min(prevList.size(), newList.size()); sameReactTagIndex++) { + ReactShadowNode prevNode = prevList.get(sameReactTagIndex); + ReactShadowNode newNode = newList.get(sameReactTagIndex); + if (prevNode == newNode) { + continue; + } + if (prevNode.getReactTag() != newNode.getReactTag()) { + break; + } + + if (newNode.getNewProps() != null) { + uiViewOperationQueue.enqueueUpdateProperties( + newNode.getReactTag(), newNode.getViewClass(), newNode.getNewProps()); + } + + manageChildren(prevNode, prevNode.getChildrenList(), newNode.getChildrenList()); + prevNode.setOriginalReactShadowNode(newNode); + } + int firstRemovedOrAddedViewIndex = sameReactTagIndex; + + // Every ReactShadowNode on the newList that is on the right side of + // firstRemovedOrAddedViewIndex is defined as an added view. + // It is more efficient to reorder removing and adding all the views in the right order, instead + // of calculating the minimum amount of reorder operations. + Set addedTags = new HashSet<>(); + ViewAtIndex[] viewsToAdd = new ViewAtIndex[newList.size() - firstRemovedOrAddedViewIndex]; + int viewsToAddIndex = 0; + for (int k = firstRemovedOrAddedViewIndex; k < newList.size(); k++) { + ReactShadowNode newNode = newList.get(k); + if (newNode.getNewProps() != null) { + uiViewOperationQueue.enqueueUpdateProperties( + newNode.getReactTag(), newNode.getViewClass(), newNode.getNewProps()); + } + viewsToAdd[viewsToAddIndex++] = new ViewAtIndex(newNode.getReactTag(), k); + List previousChildrenList = newNode.getOriginalReactShadowNode() == null ? null : newNode.getOriginalReactShadowNode().getChildrenList(); + manageChildren(newNode, previousChildrenList, newNode.getChildrenList()); + newNode.setOriginalReactShadowNode(newNode); + addedTags.add(newNode.getReactTag()); + } + + // Every ReactShadowNode on the prevList that is on the right side of + // firstRemovedOrAddedViewIndex is defined as a removed view. + // It is more efficient to reorder removing and adding all the views in the right order, instead + // of calculating the minimum amount of reorder operations. + // If a View is not re-ordered, then the ReactTag is deleted (ReactShadowNode and native View + // are released from memory) + List tagsToDelete = new LinkedList<>(); + int[] indicesToRemove = new int[prevList.size() - firstRemovedOrAddedViewIndex]; + int indicesToRemoveIndex = 0; + for (int j = firstRemovedOrAddedViewIndex; j < prevList.size(); j++) { + ReactShadowNode nodeToRemove = prevList.get(j); + indicesToRemove[indicesToRemoveIndex++] = j; + if (!addedTags.contains(nodeToRemove.getReactTag())) { + tagsToDelete.add(nodeToRemove.getReactTag()); + } + } + + uiViewOperationQueue.enqueueManageChildren( + parent.getReactTag(), indicesToRemove, viewsToAdd, ArrayUtils.copyListToArray(tagsToDelete)); + } + +} 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 f66b0ce568238f..4820e8496d816b 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -14,7 +14,6 @@ import android.util.Log; import android.view.View; import com.facebook.infer.annotation.Assertions; -import com.facebook.react.bridge.JavaOnlyArray; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReadableNativeMap; @@ -28,7 +27,6 @@ import com.facebook.react.uimanager.ReactStylesDiffMap; import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.UIViewOperationQueue; -import com.facebook.react.uimanager.ViewAtIndex; import com.facebook.react.uimanager.ViewManager; import com.facebook.react.uimanager.ViewManagerRegistry; import com.facebook.react.uimanager.common.MeasureSpecProvider; @@ -38,8 +36,8 @@ import javax.annotation.Nullable; /** - * This class is responsible to create, clone and update {@link ReactShadowNode} using the - * Fabric API. + * This class is responsible to create, clone and update {@link ReactShadowNode} using the Fabric + * API. */ @SuppressWarnings("unused") // used from JNI public class FabricUIManager implements UIManager { @@ -49,23 +47,25 @@ public class FabricUIManager implements UIManager { private final ReactApplicationContext mReactApplicationContext; private final ViewManagerRegistry mViewManagerRegistry; private final UIViewOperationQueue mUIViewOperationQueue; + private volatile int mCurrentBatch = 0; + private ReactShadowNode mCurrentRootShadowNode; + private FabricReconciler mFabricReconciler; - public FabricUIManager(ReactApplicationContext reactContext, - ViewManagerRegistry viewManagerRegistry) { + public FabricUIManager( + ReactApplicationContext reactContext, ViewManagerRegistry viewManagerRegistry) { DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(reactContext); mReactApplicationContext = reactContext; mViewManagerRegistry = viewManagerRegistry; - mUIViewOperationQueue = new UIViewOperationQueue(reactContext, new NativeViewHierarchyManager(viewManagerRegistry), 0); + mUIViewOperationQueue = + new UIViewOperationQueue( + reactContext, new NativeViewHierarchyManager(viewManagerRegistry), 0); + mFabricReconciler = new FabricReconciler(mUIViewOperationQueue); } - /** - * Creates a new {@link ReactShadowNode} - */ + /** Creates a new {@link ReactShadowNode} */ @Nullable - public ReactShadowNode createNode(int reactTag, - String viewName, - int rootTag, - ReadableNativeMap props) { + public ReactShadowNode createNode( + int reactTag, String viewName, int rootTag, ReadableNativeMap props) { try { ViewManager viewManager = mViewManagerRegistry.get(viewName); ReactShadowNode node = viewManager.createShadowNodeInstance(mReactApplicationContext); @@ -78,8 +78,8 @@ public ReactShadowNode createNode(int reactTag, ReactStylesDiffMap styles = updateProps(node, props); if (!node.isVirtual()) { - mUIViewOperationQueue - .enqueueCreateView(rootNode.getThemedContext(), reactTag, viewName, styles); + mUIViewOperationQueue.enqueueCreateView( + rootNode.getThemedContext(), reactTag, viewName, styles); } return node; } catch (Throwable t) { @@ -103,8 +103,8 @@ private ReactStylesDiffMap updateProps(ReactShadowNode node, @Nullable ReadableN /** * @return a clone of the {@link ReactShadowNode} received by parameter. The cloned - * ReactShadowNode will contain a copy of all the internal data of the original node, including - * its children set (note that the children nodes will not be cloned). + * ReactShadowNode will contain a copy of all the internal data of the original node, + * including its children set (note that the children nodes will not be cloned). */ @Nullable public ReactShadowNode cloneNode(ReactShadowNode node) { @@ -120,8 +120,8 @@ public ReactShadowNode cloneNode(ReactShadowNode node) { /** * @return a clone of the {@link ReactShadowNode} received by parameter. The cloned - * ReactShadowNode will contain a copy of all the internal data of the original node, but - * its children set will be empty. + * ReactShadowNode will contain a copy of all the internal data of the original node, but its + * children set will be empty. */ @Nullable public ReactShadowNode cloneNodeWithNewChildren(ReactShadowNode node) { @@ -137,15 +137,15 @@ public ReactShadowNode cloneNodeWithNewChildren(ReactShadowNode node) { /** * @return a clone of the {@link ReactShadowNode} received by parameter. The cloned - * ReactShadowNode will contain a copy of all the internal data of the original node, but its - * props will be overridden with the {@link ReadableMap} received by parameter. + * ReactShadowNode will contain a copy of all the internal data of the original node, but its + * props will be overridden with the {@link ReadableMap} received by parameter. */ @Nullable public ReactShadowNode cloneNodeWithNewProps( - ReactShadowNode node, - @Nullable ReadableNativeMap newProps) { + ReactShadowNode node, @Nullable ReadableNativeMap newProps) { try { - ReactShadowNode clone = node.mutableCopyWithNewProps(newProps == null ? null : new ReactStylesDiffMap(newProps)); + ReactShadowNode clone = + node.mutableCopyWithNewProps(newProps == null ? null : new ReactStylesDiffMap(newProps)); assertReactShadowNodeCopy(node, clone); return clone; } catch (Throwable t) { @@ -156,16 +156,17 @@ public ReactShadowNode cloneNodeWithNewProps( /** * @return a clone of the {@link ReactShadowNode} received by parameter. The cloned - * ReactShadowNode will contain a copy of all the internal data of the original node, but its - * props will be overridden with the {@link ReadableMap} received by parameter and its children - * set will be empty. + * ReactShadowNode will contain a copy of all the internal data of the original node, but its + * props will be overridden with the {@link ReadableMap} received by parameter and its + * children set will be empty. */ @Nullable public ReactShadowNode cloneNodeWithNewChildrenAndProps( - ReactShadowNode node, - ReadableNativeMap newProps) { + ReactShadowNode node, ReadableNativeMap newProps) { try { - ReactShadowNode clone = node.mutableCopyWithNewChildrenAndProps(newProps == null ? null : new ReactStylesDiffMap(newProps)); + ReactShadowNode clone = + node.mutableCopyWithNewChildrenAndProps( + newProps == null ? null : new ReactStylesDiffMap(newProps)); assertReactShadowNodeCopy(node, clone); return clone; } catch (Throwable t) { @@ -175,38 +176,33 @@ public ReactShadowNode cloneNodeWithNewChildrenAndProps( } private void assertReactShadowNodeCopy(ReactShadowNode source, ReactShadowNode target) { - Assertions.assertCondition(source.getClass().equals(target.getClass()), - "Found " + target.getClass() + " class when expecting: " + source.getClass() + - ". Check that " + source.getClass() + " implements the copy() method correctly."); + Assertions.assertCondition( + source.getClass().equals(target.getClass()), + "Found " + + target.getClass() + + " class when expecting: " + + source.getClass() + + ". Check that " + + source.getClass() + + " implements the copy() method correctly."); } /** - * Appends the child {@link ReactShadowNode} to the children set of the parent - * {@link ReactShadowNode}. + * Appends the child {@link ReactShadowNode} to the children set of the parent {@link + * ReactShadowNode}. */ @Nullable public void appendChild(ReactShadowNode parent, ReactShadowNode child) { try { - int childIndex = parent.getChildCount(); - parent.addChildAt(child, childIndex); - ViewAtIndex[] viewsToAdd = - new ViewAtIndex[]{new ViewAtIndex(child.getReactTag(), childIndex)}; - if (!child.isVirtual()) { - mUIViewOperationQueue.enqueueManageChildren( - parent.getReactTag(), - null, - viewsToAdd, - null - ); - } + parent.addChildAt(child, parent.getChildCount()); } catch (Throwable t) { handleException(parent, t); } } /** - * @return an empty {@link List} that will be used to append the - * {@link ReactShadowNode} elements of the root. Typically this List will contain one element. + * @return an empty {@link List} that will be used to append the {@link + * ReactShadowNode} elements of the root. Typically this List will contain one element. */ public List createChildSet(int rootTag) { return new ArrayList<>(1); @@ -219,22 +215,24 @@ public void appendChildToSet(List childList, ReactShadowNode ch childList.add(child); } - public void completeRoot(int rootTag, List childList) { + public synchronized void completeRoot(int rootTag, List childList) { try { ReactShadowNode rootNode = getRootNode(rootTag); Assertions.assertNotNull( - rootNode, - "Root view with tag " + rootTag + " must be added before completeRoot is called"); - for (int i = 0; i < childList.size(); i++) { - ReactShadowNode child = childList.get(i); - appendChild(rootNode, child); - } + rootNode, + "Root view with tag " + rootTag + " must be added before completeRoot is called"); + + + rootNode = calculateDiffingAndCreateNewRootNode(rootNode, childList); notifyOnBeforeLayoutRecursive(rootNode); - calculateRootLayout(rootNode); + rootNode.calculateLayout(); + applyUpdatesRecursive(rootNode, 0, 0); - mUIViewOperationQueue - .dispatchViewUpdates(1, System.currentTimeMillis(), System.currentTimeMillis()); + mUIViewOperationQueue.dispatchViewUpdates( + mCurrentBatch++, System.currentTimeMillis(), System.currentTimeMillis()); + + mCurrentRootShadowNode = rootNode; } catch (Exception e) { handleException(getRootNode(rootTag), e); } @@ -250,46 +248,45 @@ private void notifyOnBeforeLayoutRecursive(ReactShadowNode node) { node.onBeforeLayout(); } - private void calculateRootLayout(ReactShadowNode cssRoot) { - cssRoot.calculateLayout(); - } + private ReactShadowNode calculateDiffingAndCreateNewRootNode( + ReactShadowNode currentRootShadowNode, List newChildList) { + ReactShadowNode newRootShadowNode = currentRootShadowNode.mutableCopyWithNewChildren(); + for (ReactShadowNode child : newChildList) { + appendChild(newRootShadowNode, child); + } - private void applyUpdatesRecursive( - ReactShadowNode cssNode, - float absoluteX, - float absoluteY) { + mFabricReconciler.manageChildren(mCurrentRootShadowNode, newRootShadowNode); + return newRootShadowNode; + } - if (!cssNode.hasUpdates()) { + private void applyUpdatesRecursive(ReactShadowNode node, float absoluteX, float absoluteY) { + if (!node.hasUpdates()) { return; } - if (!cssNode.isVirtualAnchor()) { - for (int i = 0; i < cssNode.getChildCount(); i++) { + if (!node.isVirtualAnchor()) { + for (int i = 0; i < node.getChildCount(); i++) { applyUpdatesRecursive( - cssNode.getChildAt(i), - absoluteX + cssNode.getLayoutX(), - absoluteY + cssNode.getLayoutY()); + node.getChildAt(i), + absoluteX + node.getLayoutX(), + absoluteY + node.getLayoutY()); } } - int tag = cssNode.getReactTag(); + int tag = node.getReactTag(); if (mRootShadowNodeRegistry.getNode(tag) == null) { - boolean frameDidChange = cssNode.dispatchUpdates( - absoluteX, - absoluteY, - mUIViewOperationQueue, - null); + boolean frameDidChange = + node.dispatchUpdates(absoluteX, absoluteY, mUIViewOperationQueue, null); } - cssNode.markUpdateSeen(); + node.markUpdateSeen(); } @Override public int addRootView( - final T rootView) { + final T rootView) { int rootTag = ReactRootViewTagGenerator.getNextRootViewTag(); - ThemedReactContext themedRootContext = new ThemedReactContext( - mReactApplicationContext, - rootView.getContext()); + ThemedReactContext themedRootContext = + new ThemedReactContext(mReactApplicationContext, rootView.getContext()); ReactShadowNode rootShadowNode = createRootShadowNode(rootTag, themedRootContext); @@ -321,18 +318,18 @@ private ReactShadowNode createRootShadowNode(int rootTag, ThemedReactContext the * parameters. */ public void updateRootView( - ReactShadowNode rootCSSNode, int widthMeasureSpec, int heightMeasureSpec) { + ReactShadowNode node, int widthMeasureSpec, int heightMeasureSpec) { int widthMode = View.MeasureSpec.getMode(widthMeasureSpec); int widthSize = View.MeasureSpec.getSize(widthMeasureSpec); switch (widthMode) { case EXACTLY: - rootCSSNode.setStyleWidth(widthSize); + node.setStyleWidth(widthSize); break; case AT_MOST: - rootCSSNode.setStyleMaxWidth(widthSize); + node.setStyleMaxWidth(widthSize); break; case UNSPECIFIED: - rootCSSNode.setStyleWidthAuto(); + node.setStyleWidthAuto(); break; } @@ -340,13 +337,13 @@ public void updateRootView( int heightSize = View.MeasureSpec.getSize(heightMeasureSpec); switch (heightMode) { case EXACTLY: - rootCSSNode.setStyleHeight(heightSize); + node.setStyleHeight(heightSize); break; case AT_MOST: - rootCSSNode.setStyleMaxHeight(heightSize); + node.setStyleMaxHeight(heightSize); break; case UNSPECIFIED: - rootCSSNode.setStyleHeightAuto(); + node.setStyleHeightAuto(); break; } } @@ -362,5 +359,4 @@ private void handleException(ReactShadowNode node, Throwable t) { throw new RuntimeException(ex.getMessage(), t); } } - } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java index d097842e4e135c..a43355e84fc8f0 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java @@ -132,6 +132,7 @@ protected ReactShadowNodeImpl(ReactShadowNodeImpl original) { arraycopy(original.mPaddingIsPercent, 0, mPaddingIsPercent, 0, original.mPaddingIsPercent.length); mNewProps = null; mParent = null; + mOriginalReactShadowNode = original; } /** @@ -151,6 +152,13 @@ public ReactShadowNodeImpl mutableCopy() { copy.mTotalNativeChildren = mTotalNativeChildren; copy.mChildren = mChildren == null ? null : new ArrayList<>(mChildren); copy.mYogaNode.setData(this); + if (mChildren != null) { + for (ReactShadowNode child : mChildren) { + if (child.getOriginalReactShadowNode() == null) { + child.setOriginalReactShadowNode(child); + } + } + } return copy; } From cc3d45d2e9cc701604d27714103cbee49171bcfa Mon Sep 17 00:00:00 2001 From: David Vacca Date: Mon, 19 Mar 2018 18:21:43 -0700 Subject: [PATCH 0082/1109] Add logging to debug Fabric diffing algorithm Reviewed By: achen1 Differential Revision: D7319185 fbshipit-source-id: fe47c21db5e1415aebe806f0d74b1f65f667a397 --- .../facebook/react/fabric/FabricReconciler.java | 16 +++++++++++++++- .../facebook/react/fabric/FabricUIManager.java | 13 ++++++++++++- .../facebook/react/uimanager/ViewAtIndex.java | 5 +++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java index a4666759c9905a..d60cfdaed796c1 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java @@ -7,10 +7,12 @@ package com.facebook.react.fabric; +import android.util.Log; import com.facebook.react.common.ArrayUtils; import com.facebook.react.uimanager.ReactShadowNode; import com.facebook.react.uimanager.UIViewOperationQueue; import com.facebook.react.uimanager.ViewAtIndex; +import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; @@ -20,6 +22,9 @@ public class FabricReconciler { + private static final String TAG = FabricReconciler.class.getSimpleName(); + private static final boolean DEBUG = true; + private UIViewOperationQueue uiViewOperationQueue; public FabricReconciler(UIViewOperationQueue uiViewOperationQueue) { @@ -101,8 +106,17 @@ private void manageChildren( } } + int[] tagsToDeleteArray = ArrayUtils.copyListToArray(tagsToDelete); + if (DEBUG) { + Log.d( + TAG, + "manageChildren.enqueueManageChildren parent: " + parent.getReactTag() + + "\n\tIndices2Remove: " + Arrays.toString(indicesToRemove) + + "\n\tViews2Add: " + Arrays.toString(viewsToAdd) + + "\n\tTags2Delete: " + Arrays.toString(tagsToDeleteArray)); + } uiViewOperationQueue.enqueueManageChildren( - parent.getReactTag(), indicesToRemove, viewsToAdd, ArrayUtils.copyListToArray(tagsToDelete)); + parent.getReactTag(), indicesToRemove, viewsToAdd, tagsToDeleteArray); } } 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 4820e8496d816b..8fd0dd706a76b9 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -42,7 +42,8 @@ @SuppressWarnings("unused") // used from JNI public class FabricUIManager implements UIManager { - private static final String TAG = FabricUIManager.class.toString(); + private static final String TAG = FabricUIManager.class.getSimpleName(); + private static final boolean DEBUG = true; private final RootShadowNodeRegistry mRootShadowNodeRegistry = new RootShadowNodeRegistry(); private final ReactApplicationContext mReactApplicationContext; private final ViewManagerRegistry mViewManagerRegistry; @@ -225,9 +226,19 @@ public synchronized void completeRoot(int rootTag, List childLi rootNode = calculateDiffingAndCreateNewRootNode(rootNode, childList); + if (DEBUG) { + Log.d(TAG, "ReactShadowNodeHierarchy after diffing: " + rootNode.getHierarchyInfo()); + } + notifyOnBeforeLayoutRecursive(rootNode); rootNode.calculateLayout(); + if (DEBUG) { + Log.d( + TAG, + "ReactShadowNodeHierarchy after calculate Layout: " + rootNode.getHierarchyInfo()); + } + applyUpdatesRecursive(rootNode, 0, 0); mUIViewOperationQueue.dispatchViewUpdates( mCurrentBatch++, System.currentTimeMillis(), System.currentTimeMillis()); diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewAtIndex.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewAtIndex.java index 6000e0554c854f..ef2a914d3cf358 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewAtIndex.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewAtIndex.java @@ -28,4 +28,9 @@ public ViewAtIndex(int tag, int index) { mTag = tag; mIndex = index; } + + @Override + public String toString() { + return "[" + mIndex + ", " + mTag + "]"; + } } From 5347ecfd296cdc882c7c198e6489f7482f27a073 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Mon, 19 Mar 2018 18:21:45 -0700 Subject: [PATCH 0083/1109] Fix removal of ReactShadowNode Reviewed By: achen1 Differential Revision: D7323294 fbshipit-source-id: 411aa1bcd93cc4f9df78f64ceb0c0d8c127bc3b0 --- .../main/java/com/facebook/react/fabric/FabricReconciler.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java index d60cfdaed796c1..4ea5d143bcdd14 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java @@ -103,6 +103,9 @@ private void manageChildren( indicesToRemove[indicesToRemoveIndex++] = j; if (!addedTags.contains(nodeToRemove.getReactTag())) { tagsToDelete.add(nodeToRemove.getReactTag()); + // TODO: T26729293 since we are not cloning ReactShadowNode's we need to "manually" remove + // from the ReactShadowTree when one of the nodes is deleted in JS. + nodeToRemove.getParent().removeChildAt(j); } } From 0d924dd629046b522f1a093bef8660219626f731 Mon Sep 17 00:00:00 2001 From: Sam Goldman Date: Mon, 19 Mar 2018 18:24:11 -0700 Subject: [PATCH 0084/1109] Upgrade to Flow v0.68.0 Reviewed By: gabelevi Differential Revision: D7310349 fbshipit-source-id: 70d29815dd7912704aec8a015c970be3fafeeba3 --- .flowconfig | 2 +- Libraries/Animated/src/nodes/AnimatedValue.js | 3 +++ .../SwipeableRow/SwipeableListView.js | 6 ++++++ Libraries/Lists/VirtualizedList.js | 14 ++++++-------- Libraries/ReactNative/YellowBox.js | 9 +++++++++ Libraries/ReactNative/renderApplication.js | 3 +++ Libraries/ReactNative/renderFabricSurface.js | 3 +++ Libraries/ReactNative/requireFabricComponent.js | 3 +++ Libraries/ReactNative/requireNativeComponent.js | 3 +++ Libraries/WebSocket/WebSocket.js | 3 +++ RNTester/js/CameraRollView.js | 3 +++ RNTester/js/RNTesterExampleList.js | 9 +++++++++ RNTester/js/RNTesterPage.js | 3 +++ local-cli/server/runServer.js | 15 +++++++++++++++ local-cli/templates/HelloWorld/_flowconfig | 2 +- package.json | 2 +- 16 files changed, 72 insertions(+), 11 deletions(-) diff --git a/.flowconfig b/.flowconfig index 361d475f24042d..182bf0f089e611 100644 --- a/.flowconfig +++ b/.flowconfig @@ -52,4 +52,4 @@ suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError [version] -^0.67.0 +^0.68.0 diff --git a/Libraries/Animated/src/nodes/AnimatedValue.js b/Libraries/Animated/src/nodes/AnimatedValue.js index 862d25f8e53a28..9d06c751cefbea 100644 --- a/Libraries/Animated/src/nodes/AnimatedValue.js +++ b/Libraries/Animated/src/nodes/AnimatedValue.js @@ -51,6 +51,9 @@ let _uniqueId = 1; function _flush(rootNode: AnimatedValue): void { const animatedStyles = new Set(); function findAnimatedStyles(node) { + /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.68 was deployed. To see the error delete this + * comment and run Flow. */ if (typeof node.update === 'function') { animatedStyles.add(node); } else { diff --git a/Libraries/Experimental/SwipeableRow/SwipeableListView.js b/Libraries/Experimental/SwipeableRow/SwipeableListView.js index 569f3581d04770..c6623be75b3ba6 100644 --- a/Libraries/Experimental/SwipeableRow/SwipeableListView.js +++ b/Libraries/Experimental/SwipeableRow/SwipeableListView.js @@ -142,6 +142,9 @@ class SwipeableListView extends React.Component { * (from high 20s to almost consistently 60 fps) */ _setListViewScrollable(value: boolean): void { + /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.68 was deployed. To see the error delete this + * comment and run Flow. */ if (this._listViewRef && typeof this._listViewRef.setNativeProps === 'function') { this._listViewRef.setNativeProps({ scrollEnabled: value, @@ -151,6 +154,9 @@ class SwipeableListView extends React.Component { // Passing through ListView's getScrollResponder() function getScrollResponder(): ?Object { + /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.68 was deployed. To see the error delete this + * comment and run Flow. */ if (this._listViewRef && typeof this._listViewRef.getScrollResponder === 'function') { return this._listViewRef.getScrollResponder(); } diff --git a/Libraries/Lists/VirtualizedList.js b/Libraries/Lists/VirtualizedList.js index 8ee3da2ea4f451..4c7a83b19d77fb 100644 --- a/Libraries/Lists/VirtualizedList.js +++ b/Libraries/Lists/VirtualizedList.js @@ -748,10 +748,6 @@ class VirtualizedList extends React.PureComponent { cellKey={this._getCellKey() + '-header'} key="$header"> - {/* - Flow doesn't know this is a React.Element and not a React.Component - $FlowFixMe https://fburl.com/b9xmtm09 - */} {element} , @@ -883,10 +879,6 @@ class VirtualizedList extends React.PureComponent { cellKey={this._getCellKey() + '-footer'} key="$footer"> - {/* - Flow doesn't know this is a React.Element and not a React.Component - $FlowFixMe https://fburl.com/b9xmtm09 - */} {element} , @@ -1122,6 +1114,9 @@ class VirtualizedList extends React.PureComponent { const itemCount = this.props.getItemCount(this.props.data); for (let ii = 0; ii < itemCount; ii++) { const frame = this._getFrameMetricsApprox(ii); + /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.68 was deployed. To see the error delete this + * comment and run Flow. */ if (frame.inLayout) { framesInLayout.push(frame); } @@ -1646,6 +1641,9 @@ class CellRenderer extends React.Component< separators: this._separators, }); const onLayout = + /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.68 was deployed. To see the error delete this + * comment and run Flow. */ getItemLayout && !parentProps.debug && !fillRateHelper.enabled() ? undefined : this.props.onLayout; diff --git a/Libraries/ReactNative/YellowBox.js b/Libraries/ReactNative/YellowBox.js index 8bd31d3cd8b768..26749987affb41 100644 --- a/Libraries/ReactNative/YellowBox.js +++ b/Libraries/ReactNative/YellowBox.js @@ -105,6 +105,9 @@ function sprintf(format, ...args) { } function updateWarningMap(...args): void { + /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an error + * found when Flow v0.68 was deployed. To see the error delete this comment + * and run Flow. */ if (console.disableYellowBox) { return; } @@ -178,6 +181,9 @@ function isWarningIgnored(warning: string): boolean { // DEPRECATED return ( + /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.68 was deployed. To see the error delete this + * comment and run Flow. */ Array.isArray(console.ignoredYellowBox) && console.ignoredYellowBox.some(ignorePrefix => warning.startsWith(String(ignorePrefix)), @@ -379,6 +385,9 @@ class YellowBox extends React.Component< } render() { + /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.68 was deployed. To see the error delete this + * comment and run Flow. */ if (console.disableYellowBox || this.state.warningMap.size === 0) { return null; } diff --git a/Libraries/ReactNative/renderApplication.js b/Libraries/ReactNative/renderApplication.js index e72853e8e459c0..896c88207eb068 100644 --- a/Libraries/ReactNative/renderApplication.js +++ b/Libraries/ReactNative/renderApplication.js @@ -38,6 +38,9 @@ function renderApplication( // to be async also. To do this, wrap AppContainer with an async marker. // For more info see https://fb.me/is-component-async if ( + /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.68 was deployed. To see the error delete this + * comment and run Flow. */ RootComponent.prototype != null && RootComponent.prototype.unstable_isAsyncReactComponent === true ) { diff --git a/Libraries/ReactNative/renderFabricSurface.js b/Libraries/ReactNative/renderFabricSurface.js index 841a079b1d0675..0279f1759926d6 100644 --- a/Libraries/ReactNative/renderFabricSurface.js +++ b/Libraries/ReactNative/renderFabricSurface.js @@ -42,6 +42,9 @@ function renderFabricSurface( // to be async also. To do this, wrap AppContainer with an async marker. // For more info see https://fb.me/is-component-async if ( + /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.68 was deployed. To see the error delete this + * comment and run Flow. */ RootComponent.prototype != null && RootComponent.prototype.unstable_isAsyncReactComponent === true ) { diff --git a/Libraries/ReactNative/requireFabricComponent.js b/Libraries/ReactNative/requireFabricComponent.js index 1544c6fdff976e..4b6010a0c26422 100644 --- a/Libraries/ReactNative/requireFabricComponent.js +++ b/Libraries/ReactNative/requireFabricComponent.js @@ -121,6 +121,9 @@ function requireNativeComponent( // TODO (bvaughn) Revert this particular change any time after April 1 if (componentInterface) { viewConfig.propTypes = + /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.68 was deployed. To see the error delete + * this comment and run Flow. */ typeof componentInterface.__propTypesSecretDontUseThesePlease === 'object' ? componentInterface.__propTypesSecretDontUseThesePlease diff --git a/Libraries/ReactNative/requireNativeComponent.js b/Libraries/ReactNative/requireNativeComponent.js index 2a6c7c8ca71e8d..4a6fd4c1310c0d 100644 --- a/Libraries/ReactNative/requireNativeComponent.js +++ b/Libraries/ReactNative/requireNativeComponent.js @@ -119,6 +119,9 @@ function requireNativeComponent( // TODO (bvaughn) Revert this particular change any time after April 1 if (componentInterface) { viewConfig.propTypes = + /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.68 was deployed. To see the error delete + * this comment and run Flow. */ typeof componentInterface.__propTypesSecretDontUseThesePlease === 'object' ? componentInterface.__propTypesSecretDontUseThesePlease diff --git a/Libraries/WebSocket/WebSocket.js b/Libraries/WebSocket/WebSocket.js index daa1ed77ca050d..021e42507e5db0 100644 --- a/Libraries/WebSocket/WebSocket.js +++ b/Libraries/WebSocket/WebSocket.js @@ -103,6 +103,9 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) { const {headers = {}, ...unrecognized} = options || {}; // Preserve deprecated backwards compatibility for the 'origin' option + /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.68 was deployed. To see the error delete this + * comment and run Flow. */ if (unrecognized && typeof unrecognized.origin === 'string') { console.warn('Specifying `origin` as a WebSocket connection option is deprecated. Include it under `headers` instead.'); /* $FlowFixMe(>=0.54.0 site=react_native_fb,react_native_oss) This diff --git a/RNTester/js/CameraRollView.js b/RNTester/js/CameraRollView.js index f69a4feed65fcb..c08aeb71e833c7 100644 --- a/RNTester/js/CameraRollView.js +++ b/RNTester/js/CameraRollView.js @@ -123,6 +123,9 @@ var CameraRollView = createReactClass({ this.fetch(); }, + /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an error + * found when Flow v0.68 was deployed. To see the error delete this comment + * and run Flow. */ UNSAFE_componentWillReceiveProps: function(nextProps: {groupTypes?: string}) { if (this.props.groupTypes !== nextProps.groupTypes) { this.fetch(true); diff --git a/RNTester/js/RNTesterExampleList.js b/RNTester/js/RNTesterExampleList.js index 96e1ed9b474a68..e043e2d5cba1d2 100644 --- a/RNTester/js/RNTesterExampleList.js +++ b/RNTester/js/RNTesterExampleList.js @@ -76,6 +76,9 @@ class RNTesterExampleList extends React.Component { const filterText = this.props.persister.state.filter; const filterRegex = new RegExp(String(filterText), 'i'); const filter = (example) => + /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.68 was deployed. To see the error delete this + * comment and run Flow. */ this.props.disableSearch || filterRegex.test(example.module.title) && (!Platform.isTVOS || example.supportsTVOS); @@ -128,6 +131,9 @@ class RNTesterExampleList extends React.Component { ); _renderTitleRow(): ?React.Element { + /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.68 was deployed. To see the error delete this + * comment and run Flow. */ if (!this.props.displayTitleRow) { return null; } @@ -146,6 +152,9 @@ class RNTesterExampleList extends React.Component { } _renderTextInput(): ?React.Element { + /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.68 was deployed. To see the error delete this + * comment and run Flow. */ if (this.props.disableSearch) { return null; } diff --git a/RNTester/js/RNTesterPage.js b/RNTester/js/RNTesterPage.js index 5dfb3bda2039ea..96b016a00000fb 100644 --- a/RNTester/js/RNTesterPage.js +++ b/RNTester/js/RNTesterPage.js @@ -41,6 +41,9 @@ class RNTesterPage extends React.Component<{ wrapperProps.keyboardShouldPersistTaps = 'handled'; wrapperProps.keyboardDismissMode = 'interactive'; } + /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.68 was deployed. To see the error delete this + * comment and run Flow. */ var title = this.props.title ? : null; diff --git a/local-cli/server/runServer.js b/local-cli/server/runServer.js index 371f43a39af560..8b790eac4d1fc7 100644 --- a/local-cli/server/runServer.js +++ b/local-cli/server/runServer.js @@ -78,6 +78,9 @@ function runServer( var ms = null; const terminal = new Terminal(process.stdout); + /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an error + * found when Flow v0.68 was deployed. To see the error delete this comment + * and run Flow. */ const ReporterImpl = getReporterImpl(args.customLogReporterPath || null); const reporter = new ReporterImpl(terminal); const packagerServer = getPackagerServer(args, config, reporter); @@ -105,10 +108,16 @@ function runServer( app.use(morgan('combined')).use(errorhandler()); + /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an error + * found when Flow v0.68 was deployed. To see the error delete this comment + * and run Flow. */ if (args.https && (!args.key || !args.cert)) { throw new Error('Cannot use https without specifying key and cert options'); } + /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an error + * found when Flow v0.68 was deployed. To see the error delete this comment + * and run Flow. */ const serverInstance = args.https ? https.createServer( { @@ -157,11 +166,17 @@ function getReporterImpl(customLogReporterPath: ?string) { } function getPackagerServer(args, config, reporter) { + /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an error + * found when Flow v0.68 was deployed. To see the error delete this comment + * and run Flow. */ const transformModulePath = args.transformer ? path.resolve(args.transformer) : config.getTransformModulePath(); const providesModuleNodeModules = + /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.68 was deployed. To see the error delete this + * comment and run Flow. */ args.providesModuleNodeModules || defaultProvidesModuleNodeModules; return Metro.createServer({ diff --git a/local-cli/templates/HelloWorld/_flowconfig b/local-cli/templates/HelloWorld/_flowconfig index 7d5e2d3362ba40..3813ec4a1011c9 100644 --- a/local-cli/templates/HelloWorld/_flowconfig +++ b/local-cli/templates/HelloWorld/_flowconfig @@ -51,4 +51,4 @@ suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError [version] -^0.67.0 +^0.68.0 diff --git a/package.json b/package.json index 3aab6dca4ba026..e7a8250c4d16e5 100644 --- a/package.json +++ b/package.json @@ -215,7 +215,7 @@ "eslint-plugin-jest": "21.8.0", "eslint-plugin-prettier": "2.6.0", "eslint-plugin-react": "7.6.1", - "flow-bin": "^0.67.1", + "flow-bin": "^0.68.0", "jest": "22.4.2", "jest-junit": "3.6.0", "prettier": "1.9.1", From 785c8f7eb920e3df7d1c74875e199d03eda074a8 Mon Sep 17 00:00:00 2001 From: "Andrew Chen (Eng)" Date: Tue, 20 Mar 2018 00:58:05 -0700 Subject: [PATCH 0085/1109] Use native as the source of truth to decide if a test should use Fabric Reviewed By: fkgozali Differential Revision: D7304221 fbshipit-source-id: cdd7053e6ce6522474df261db5710e2d9c013be6 --- Libraries/Components/View/TestFabricView.js | 24 ++++++++++++ .../testing/ReactInstrumentationTest.java | 7 +++- .../testing/fabric/FabricTestModule.java | 39 +++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 Libraries/Components/View/TestFabricView.js create mode 100644 ReactAndroid/src/androidTest/java/com/facebook/react/testing/fabric/FabricTestModule.java diff --git a/Libraries/Components/View/TestFabricView.js b/Libraries/Components/View/TestFabricView.js new file mode 100644 index 00000000000000..01e0e4897b2bcc --- /dev/null +++ b/Libraries/Components/View/TestFabricView.js @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @providesModule TestFabricView + * @flow + * @format + */ +'use strict'; + +/** + * This is a switch on the correct View to use for Fabric testing purposes + */ +let TestFabricView; +const FabricTestModule = require('NativeModules').FabricTestModule; +if (FabricTestModule && FabricTestModule.IS_FABRIC_ENABLED) { + TestFabricView = require('FabricView'); +} else { + TestFabricView = require('View'); +} + +module.exports = TestFabricView; diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactInstrumentationTest.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactInstrumentationTest.java index fe6c7c687aec52..849254353378fd 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactInstrumentationTest.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactInstrumentationTest.java @@ -12,6 +12,7 @@ import android.view.View; import android.view.ViewGroup; import com.facebook.react.bridge.ReactContext; +import com.facebook.react.testing.fabric.FabricTestModule; import com.facebook.react.testing.idledetection.IdleWaiter; /** @@ -110,7 +111,11 @@ protected boolean isFabricTest() { * Override this method to provide extra native modules to be loaded before the app starts */ protected ReactInstanceSpecForTest createReactInstanceSpecForTest() { - return new ReactInstanceSpecForTest(); + ReactInstanceSpecForTest instanceSpec = new ReactInstanceSpecForTest(); + if (isFabricTest()) { + instanceSpec.addNativeModule(new FabricTestModule(isFabricTest())); + } + return instanceSpec; } /** diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/fabric/FabricTestModule.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/fabric/FabricTestModule.java new file mode 100644 index 00000000000000..0e4fe05b099ab8 --- /dev/null +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/fabric/FabricTestModule.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * + * 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.testing.fabric; + +import com.facebook.react.common.MapBuilder; +import java.util.Map; +import javax.annotation.Nullable; + +import com.facebook.react.bridge.BaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.bridge.ReadableMap; + +/** + * Module to indicate if a test is using Fabric + */ +public final class FabricTestModule extends BaseJavaModule { + + private final boolean mIsFabricEnabled; + + public FabricTestModule(boolean isFabricEnabled) { + mIsFabricEnabled = isFabricEnabled; + } + + @Override + public String getName() { + return "FabricTestModule"; + } + + @Override + public Map getConstants() { + return MapBuilder.of("IS_FABRIC_ENABLED", mIsFabricEnabled); + } +} From c49afb174f76b74e390f531ee67d43997d76f71b Mon Sep 17 00:00:00 2001 From: "Andrew Chen (Eng)" Date: Tue, 20 Mar 2018 00:58:10 -0700 Subject: [PATCH 0086/1109] Add debug logs to FabricUIManager Reviewed By: mdvacca Differential Revision: D7310879 fbshipit-source-id: 3c874fd4dbd75dd865f7d94e7e31f538ef67eb66 --- .../react/fabric/FabricUIManager.java | 28 +++++++++++++++++++ .../react/uimanager/ReactShadowNodeImpl.java | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) 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 8fd0dd706a76b9..81a60435097896 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -44,6 +44,7 @@ public class FabricUIManager implements UIManager { private static final String TAG = FabricUIManager.class.getSimpleName(); private static final boolean DEBUG = true; + private final RootShadowNodeRegistry mRootShadowNodeRegistry = new RootShadowNodeRegistry(); private final ReactApplicationContext mReactApplicationContext; private final ViewManagerRegistry mViewManagerRegistry; @@ -67,6 +68,12 @@ public FabricUIManager( @Nullable public ReactShadowNode createNode( int reactTag, String viewName, int rootTag, ReadableNativeMap props) { + if (DEBUG) { + Log.d(TAG, "createNode \n\ttag: " + reactTag + + "\n\tviewName: " + viewName + + "\n\trootTag: " + rootTag + + "\n\tprops: " + props); + } try { ViewManager viewManager = mViewManagerRegistry.get(viewName); ReactShadowNode node = viewManager.createShadowNodeInstance(mReactApplicationContext); @@ -109,6 +116,9 @@ private ReactStylesDiffMap updateProps(ReactShadowNode node, @Nullable ReadableN */ @Nullable public ReactShadowNode cloneNode(ReactShadowNode node) { + if (DEBUG) { + Log.d(TAG, "cloneNode \n\tnode: " + node); + } try { ReactShadowNode clone = node.mutableCopy(); assertReactShadowNodeCopy(node, clone); @@ -126,6 +136,9 @@ public ReactShadowNode cloneNode(ReactShadowNode node) { */ @Nullable public ReactShadowNode cloneNodeWithNewChildren(ReactShadowNode node) { + if (DEBUG) { + Log.d(TAG, "cloneNodeWithNewChildren \n\tnode: " + node); + } try { ReactShadowNode clone = node.mutableCopyWithNewChildren(); assertReactShadowNodeCopy(node, clone); @@ -144,6 +157,9 @@ public ReactShadowNode cloneNodeWithNewChildren(ReactShadowNode node) { @Nullable public ReactShadowNode cloneNodeWithNewProps( ReactShadowNode node, @Nullable ReadableNativeMap newProps) { + if (DEBUG) { + Log.d(TAG, "cloneNodeWithNewProps \n\tnode: " + node + "\n\tprops: " + newProps); + } try { ReactShadowNode clone = node.mutableCopyWithNewProps(newProps == null ? null : new ReactStylesDiffMap(newProps)); @@ -164,6 +180,9 @@ public ReactShadowNode cloneNodeWithNewProps( @Nullable public ReactShadowNode cloneNodeWithNewChildrenAndProps( ReactShadowNode node, ReadableNativeMap newProps) { + if (DEBUG) { + Log.d(TAG, "cloneNodeWithNewChildrenAndProps \n\tnode: " + node + "\n\tnewProps: " + newProps); + } try { ReactShadowNode clone = node.mutableCopyWithNewChildrenAndProps( @@ -194,6 +213,9 @@ private void assertReactShadowNodeCopy(ReactShadowNode source, ReactShadowNode t */ @Nullable public void appendChild(ReactShadowNode parent, ReactShadowNode child) { + if (DEBUG) { + Log.d(TAG, "appendChild \n\tparent: " + parent + "\n\tchild: " + child); + } try { parent.addChildAt(child, parent.getChildCount()); } catch (Throwable t) { @@ -206,6 +228,9 @@ public void appendChild(ReactShadowNode parent, ReactShadowNode child) { * ReactShadowNode} elements of the root. Typically this List will contain one element. */ public List createChildSet(int rootTag) { + if (DEBUG) { + Log.d(TAG, "createChildSet rootTag: " + rootTag); + } return new ArrayList<>(1); } @@ -217,6 +242,9 @@ public void appendChildToSet(List childList, ReactShadowNode ch } public synchronized void completeRoot(int rootTag, List childList) { + if (DEBUG) { + Log.d(TAG, "completeRoot rootTag: " + rootTag + ", childList: " + childList); + } try { ReactShadowNode rootNode = getRootNode(rootTag); Assertions.assertNotNull( diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java index a43355e84fc8f0..8d906c4bc29823 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java @@ -643,7 +643,7 @@ public boolean isDescendantOf(ReactShadowNodeImpl ancestorNode) { @Override public String toString() { - return mViewClassName; + return "[" + mViewClassName + " " + getReactTag() + "]"; } /* From f136ae136278c374e24989c693a5b3a0a101178c Mon Sep 17 00:00:00 2001 From: "Andrew Chen (Eng)" Date: Tue, 20 Mar 2018 00:58:16 -0700 Subject: [PATCH 0087/1109] Add test for FabricText Reviewed By: mdvacca Differential Revision: D7326562 fbshipit-source-id: e1229f84496e9181475979d757066e3796a24a3f --- Libraries/Text/FabricText.js | 242 ++++++++++++++++++ Libraries/Text/TestFabricText.js | 24 ++ .../com/facebook/react/common/ArrayUtils.java | 3 +- .../react/fabric/FabricReconciler.java | 18 +- 4 files changed, 279 insertions(+), 8 deletions(-) create mode 100644 Libraries/Text/FabricText.js create mode 100644 Libraries/Text/TestFabricText.js diff --git a/Libraries/Text/FabricText.js b/Libraries/Text/FabricText.js new file mode 100644 index 00000000000000..1eedd8b181c836 --- /dev/null +++ b/Libraries/Text/FabricText.js @@ -0,0 +1,242 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @providesModule FabricText + * @flow + * @format + */ +'use strict'; + +const React = require('React'); +const ReactNative = require('ReactNative'); +const ReactNativeViewAttributes = require('ReactNativeViewAttributes'); +const TextPropTypes = require('TextPropTypes'); +const Touchable = require('Touchable'); +const UIManager = require('UIManager'); + +const {createReactNativeComponentClass} = require('ReactFabricInternals'); +const mergeFast = require('mergeFast'); +const processColor = require('processColor'); +const {ViewContextTypes} = require('ViewContext'); + +import type {PressEvent} from 'CoreEventTypes'; +import type {TextProps} from 'TextProps'; +import type {ViewChildContext} from 'ViewContext'; + +type State = { + isHighlighted: boolean, +}; + +type RectOffset = { + top: number, + left: number, + right: number, + bottom: number, +}; + +const PRESS_RECT_OFFSET = {top: 20, left: 20, right: 20, bottom: 30}; + +const viewConfig = { + validAttributes: mergeFast(ReactNativeViewAttributes.UIView, { + isHighlighted: true, + numberOfLines: true, + ellipsizeMode: true, + allowFontScaling: true, + disabled: true, + selectable: true, + selectionColor: true, + adjustsFontSizeToFit: true, + minimumFontScale: true, + textBreakStrategy: true, + }), + uiViewClassName: 'RCTText', +}; + +/** + * A React component for displaying text. + * + * See https://facebook.github.io/react-native/docs/text.html + */ +class Text extends ReactNative.NativeComponent { + static propTypes = TextPropTypes; + static childContextTypes = ViewContextTypes; + static contextTypes = ViewContextTypes; + + static defaultProps = { + accessible: true, + allowFontScaling: true, + ellipsizeMode: 'tail', + }; + + state = mergeFast(Touchable.Mixin.touchableGetInitialState(), { + isHighlighted: false, + }); + + viewConfig = viewConfig; + + getChildContext(): ViewChildContext { + return { + isInAParentText: true, + }; + } + + _handlers: ?Object; + + _hasPressHandler(): boolean { + return !!this.props.onPress || !!this.props.onLongPress; + } + /** + * These are assigned lazily the first time the responder is set to make plain + * text nodes as cheap as possible. + */ + touchableHandleActivePressIn: ?Function; + touchableHandleActivePressOut: ?Function; + touchableHandlePress: ?Function; + touchableHandleLongPress: ?Function; + touchableHandleResponderGrant: ?Function; + touchableHandleResponderMove: ?Function; + touchableHandleResponderRelease: ?Function; + touchableHandleResponderTerminate: ?Function; + touchableHandleResponderTerminationRequest: ?Function; + touchableGetPressRectOffset: ?Function; + + render(): React.Element { + let newProps = this.props; + if (this.props.onStartShouldSetResponder || this._hasPressHandler()) { + if (!this._handlers) { + this._handlers = { + onStartShouldSetResponder: (): boolean => { + const shouldSetFromProps = + this.props.onStartShouldSetResponder && + this.props.onStartShouldSetResponder(); + const setResponder = shouldSetFromProps || this._hasPressHandler(); + if (setResponder && !this.touchableHandleActivePressIn) { + // Attach and bind all the other handlers only the first time a touch + // actually happens. + for (const key in Touchable.Mixin) { + if (typeof Touchable.Mixin[key] === 'function') { + (this: any)[key] = Touchable.Mixin[key].bind(this); + } + } + this.touchableHandleActivePressIn = () => { + if ( + this.props.suppressHighlighting || + !this._hasPressHandler() + ) { + return; + } + this.setState({ + isHighlighted: true, + }); + }; + + this.touchableHandleActivePressOut = () => { + if ( + this.props.suppressHighlighting || + !this._hasPressHandler() + ) { + return; + } + this.setState({ + isHighlighted: false, + }); + }; + + this.touchableHandlePress = (e: PressEvent) => { + this.props.onPress && this.props.onPress(e); + }; + + this.touchableHandleLongPress = (e: PressEvent) => { + this.props.onLongPress && this.props.onLongPress(e); + }; + + this.touchableGetPressRectOffset = function(): RectOffset { + return this.props.pressRetentionOffset || PRESS_RECT_OFFSET; + }; + } + return setResponder; + }, + onResponderGrant: function(e: SyntheticEvent<>, dispatchID: string) { + // $FlowFixMe TouchableMixin handlers couldn't actually be null + this.touchableHandleResponderGrant(e, dispatchID); + this.props.onResponderGrant && + this.props.onResponderGrant.apply(this, arguments); + }.bind(this), + onResponderMove: function(e: SyntheticEvent<>) { + // $FlowFixMe TouchableMixin handlers couldn't actually be null + this.touchableHandleResponderMove(e); + this.props.onResponderMove && + this.props.onResponderMove.apply(this, arguments); + }.bind(this), + onResponderRelease: function(e: SyntheticEvent<>) { + // $FlowFixMe TouchableMixin handlers couldn't actually be null + this.touchableHandleResponderRelease(e); + this.props.onResponderRelease && + this.props.onResponderRelease.apply(this, arguments); + }.bind(this), + onResponderTerminate: function(e: SyntheticEvent<>) { + // $FlowFixMe TouchableMixin handlers couldn't actually be null + this.touchableHandleResponderTerminate(e); + this.props.onResponderTerminate && + this.props.onResponderTerminate.apply(this, arguments); + }.bind(this), + onResponderTerminationRequest: function(): boolean { + // Allow touchable or props.onResponderTerminationRequest to deny + // the request + // $FlowFixMe TouchableMixin handlers couldn't actually be null + var allowTermination = this.touchableHandleResponderTerminationRequest(); + if (allowTermination && this.props.onResponderTerminationRequest) { + allowTermination = this.props.onResponderTerminationRequest.apply( + this, + arguments, + ); + } + return allowTermination; + }.bind(this), + }; + } + newProps = { + ...this.props, + ...this._handlers, + isHighlighted: this.state.isHighlighted, + }; + } + if (newProps.selectionColor != null) { + newProps = { + ...newProps, + selectionColor: processColor(newProps.selectionColor), + }; + } + if (Touchable.TOUCH_TARGET_DEBUG && newProps.onPress) { + newProps = { + ...newProps, + style: [this.props.style, {color: 'magenta'}], + }; + } + if (this.context.isInAParentText) { + return ; + } else { + return ; + } + } +} + +var RCTText = createReactNativeComponentClass( + viewConfig.uiViewClassName, + () => viewConfig, +); +var RCTVirtualText = RCTText; + +if (UIManager.RCTVirtualText) { + RCTVirtualText = createReactNativeComponentClass('RCTVirtualText', () => ({ + validAttributes: mergeFast(ReactNativeViewAttributes.UIView, { + isHighlighted: true, + }), + uiViewClassName: 'RCTVirtualText', + })); +} + +module.exports = Text; diff --git a/Libraries/Text/TestFabricText.js b/Libraries/Text/TestFabricText.js new file mode 100644 index 00000000000000..cdedcc3177ca64 --- /dev/null +++ b/Libraries/Text/TestFabricText.js @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @providesModule TestFabricText + * @flow + * @format + */ +'use strict'; + +/** + * This is a switch on the correct Text to use for Fabric testing purposes + */ +let TestFabricText; +const FabricTestModule = require('NativeModules').FabricTestModule; +if (FabricTestModule && FabricTestModule.IS_FABRIC_ENABLED) { + TestFabricText = require('FabricText'); +} else { + TestFabricText = require('Text'); +} + +module.exports = TestFabricText; diff --git a/ReactAndroid/src/main/java/com/facebook/react/common/ArrayUtils.java b/ReactAndroid/src/main/java/com/facebook/react/common/ArrayUtils.java index 41b62c19f2554a..5b2f32023c1c8f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/common/ArrayUtils.java +++ b/ReactAndroid/src/main/java/com/facebook/react/common/ArrayUtils.java @@ -11,10 +11,9 @@ public static float[] copyArray(float[] array) { public static int[] copyListToArray(List list) { int[] array = new int[list.size()]; - for (int t = 0 ; t < list.size() ; t++) { + for (int t = 0; t < list.size(); t++) { array[t] = list.get(t); } return array; } - } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java index 4ea5d143bcdd14..3d7571e496b93c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java @@ -8,6 +8,7 @@ package com.facebook.react.fabric; import android.util.Log; +import android.util.SparseArray; import com.facebook.react.common.ArrayUtils; import com.facebook.react.uimanager.ReactShadowNode; import com.facebook.react.uimanager.UIViewOperationQueue; @@ -74,15 +75,15 @@ private void manageChildren( // It is more efficient to reorder removing and adding all the views in the right order, instead // of calculating the minimum amount of reorder operations. Set addedTags = new HashSet<>(); - ViewAtIndex[] viewsToAdd = new ViewAtIndex[newList.size() - firstRemovedOrAddedViewIndex]; - int viewsToAddIndex = 0; + List viewsToAdd = new LinkedList<>(); for (int k = firstRemovedOrAddedViewIndex; k < newList.size(); k++) { ReactShadowNode newNode = newList.get(k); + if (newNode.isVirtual()) continue; if (newNode.getNewProps() != null) { uiViewOperationQueue.enqueueUpdateProperties( newNode.getReactTag(), newNode.getViewClass(), newNode.getNewProps()); } - viewsToAdd[viewsToAddIndex++] = new ViewAtIndex(newNode.getReactTag(), k); + viewsToAdd.add(new ViewAtIndex(newNode.getReactTag(), k)); List previousChildrenList = newNode.getOriginalReactShadowNode() == null ? null : newNode.getOriginalReactShadowNode().getChildrenList(); manageChildren(newNode, previousChildrenList, newNode.getChildrenList()); newNode.setOriginalReactShadowNode(newNode); @@ -100,6 +101,7 @@ private void manageChildren( int indicesToRemoveIndex = 0; for (int j = firstRemovedOrAddedViewIndex; j < prevList.size(); j++) { ReactShadowNode nodeToRemove = prevList.get(j); + if (nodeToRemove.isVirtual()) continue; indicesToRemove[indicesToRemoveIndex++] = j; if (!addedTags.contains(nodeToRemove.getReactTag())) { tagsToDelete.add(nodeToRemove.getReactTag()); @@ -110,16 +112,20 @@ private void manageChildren( } int[] tagsToDeleteArray = ArrayUtils.copyListToArray(tagsToDelete); + ViewAtIndex[] viewsToAddArray = viewsToAdd.toArray(new ViewAtIndex[viewsToAdd.size()]); if (DEBUG) { Log.d( TAG, "manageChildren.enqueueManageChildren parent: " + parent.getReactTag() + "\n\tIndices2Remove: " + Arrays.toString(indicesToRemove) + - "\n\tViews2Add: " + Arrays.toString(viewsToAdd) + + "\n\tViews2Add: " + Arrays.toString(viewsToAddArray) + "\n\tTags2Delete: " + Arrays.toString(tagsToDeleteArray)); } - uiViewOperationQueue.enqueueManageChildren( - parent.getReactTag(), indicesToRemove, viewsToAdd, tagsToDeleteArray); + // TODO (t27180994): Mutate views synchronously on main thread + if (indicesToRemove.length > 0 || viewsToAddArray.length > 0 || tagsToDeleteArray.length > 0) { + uiViewOperationQueue.enqueueManageChildren( + parent.getReactTag(), indicesToRemove, viewsToAddArray, tagsToDeleteArray); + } } } From af4282940436e81095804dc1729784d2413461aa Mon Sep 17 00:00:00 2001 From: "Andrew Chen (Eng)" Date: Tue, 20 Mar 2018 00:58:18 -0700 Subject: [PATCH 0088/1109] Fix TextRenderingTestCase Reviewed By: mdvacca Differential Revision: D7330681 fbshipit-source-id: 5dd2a60382d01fb841f16851a9b2027e2b08e748 --- .../com/facebook/react/testing/ReactInstrumentationTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactInstrumentationTest.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactInstrumentationTest.java index 849254353378fd..7544395157c665 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactInstrumentationTest.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactInstrumentationTest.java @@ -11,6 +11,7 @@ import android.test.ActivityInstrumentationTestCase2; import android.view.View; import android.view.ViewGroup; +import com.facebook.react.bridge.JavaScriptModule; import com.facebook.react.bridge.ReactContext; import com.facebook.react.testing.fabric.FabricTestModule; import com.facebook.react.testing.idledetection.IdleWaiter; @@ -107,6 +108,10 @@ protected boolean isFabricTest() { return false; } + protected T getJSModule(Class jsInterface) { + return getReactContext().getJSModule(jsInterface); + } + /** * Override this method to provide extra native modules to be loaded before the app starts */ From aabd5d1458798e6ba3c7f8194f489c17b28903ca Mon Sep 17 00:00:00 2001 From: Charles Dick Date: Tue, 20 Mar 2018 04:12:06 -0700 Subject: [PATCH 0089/1109] Use map instead of array Reviewed By: dcaspi Differential Revision: D7327839 fbshipit-source-id: e48d2b9f34e337d14f9519eac16b6a15fa56deb5 --- Libraries/BatchedBridge/MessageQueue.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Libraries/BatchedBridge/MessageQueue.js b/Libraries/BatchedBridge/MessageQueue.js index 428d388173989e..98662c28cc6dfb 100644 --- a/Libraries/BatchedBridge/MessageQueue.js +++ b/Libraries/BatchedBridge/MessageQueue.js @@ -44,8 +44,8 @@ let JSTimers = null; class MessageQueue { _lazyCallableModules: {[key: string]: (void) => Object}; _queue: [number[], number[], any[], number]; - _successCallbacks: (?Function)[]; - _failureCallbacks: (?Function)[]; + _successCallbacks: {[key: number]: ?Function}; + _failureCallbacks: {[key: number]: ?Function}; _callID: number; _inCall: number; _lastFlush: number; @@ -62,8 +62,8 @@ class MessageQueue { constructor(shouldUninstallGlobalErrorHandler: boolean = false) { this._lazyCallableModules = {}; this._queue = [[], [], [], 0]; - this._successCallbacks = []; - this._failureCallbacks = []; + this._successCallbacks = {}; + this._failureCallbacks = {}; this._callID = 0; this._lastFlush = 0; this._eventLoopStartTime = new Date().getTime(); @@ -394,7 +394,8 @@ class MessageQueue { return; } - this._successCallbacks[callID] = this._failureCallbacks[callID] = null; + delete this._successCallbacks[callID]; + delete this._failureCallbacks[callID]; callback(...args); if (__DEV__) { From fa7c322af42e0debed0cdc0944faaf55f17e6f15 Mon Sep 17 00:00:00 2001 From: Peter van der Zee Date: Tue, 20 Mar 2018 04:49:12 -0700 Subject: [PATCH 0090/1109] Depend on local version of babel-plugin-react-transform Reviewed By: jeanlauliac Differential Revision: D7319513 fbshipit-source-id: 4945ec753087206cd01eca4ba9464672d5fb05ba --- babel-preset/configs/hmr.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/babel-preset/configs/hmr.js b/babel-preset/configs/hmr.js index 91cb9a356c654b..cdf5a022c202eb 100644 --- a/babel-preset/configs/hmr.js +++ b/babel-preset/configs/hmr.js @@ -7,7 +7,6 @@ 'use strict'; var path = require('path'); -var resolvePlugins = require('../lib/resolvePlugins'); var hmrTransform = 'react-transform-hmr/lib/index.js'; var transformPath = require.resolve(hmrTransform); @@ -23,9 +22,9 @@ module.exports = function(options, filename) { } return { - plugins: resolvePlugins([ + plugins: [ [ - 'react-transform', + require('metro-babel7-plugin-react-transform').default, { transforms: [{ transform: transform, @@ -34,6 +33,6 @@ module.exports = function(options, filename) { }] }, ] - ]) + ] }; }; From f6bcd73ed7cdc1f76a940e301a42d8b578f890c8 Mon Sep 17 00:00:00 2001 From: Jeff Hampton Date: Tue, 20 Mar 2018 05:15:48 -0700 Subject: [PATCH 0091/1109] feat: Remove platform check in requireNativeComponent to support additional platforms Summary: Using platform checks can make it difficult to incorporate changes for other platforms (e.g. Windows). Using a check for the underlying function accomplishes the same goal without relying on an Android-specific check. This change allows this JS file to be re-used instead of copied and modified. [X] Run Jest tests [X] Test in RNTester on simulators [X] Test in Playground No related PR's found :) [GENERAL] [ENHANCEMENT] [Libraries/ReactNative/requireFabricComponent.js] - Simplified check against UIManager to support additional platforms, removing Android-specific check Closes https://github.com/facebook/react-native/pull/18381 Differential Revision: D7336214 Pulled By: hramos fbshipit-source-id: e936f1fdcf36556c528115ee3f79197883d7b7d4 --- .../ReactNative/requireFabricComponent.js | 31 +++++++++---------- .../ReactNative/requireNativeComponent.js | 31 +++++++++---------- 2 files changed, 30 insertions(+), 32 deletions(-) diff --git a/Libraries/ReactNative/requireFabricComponent.js b/Libraries/ReactNative/requireFabricComponent.js index 4b6010a0c26422..4d9fca04cd58d5 100644 --- a/Libraries/ReactNative/requireFabricComponent.js +++ b/Libraries/ReactNative/requireFabricComponent.js @@ -53,22 +53,21 @@ function requireNativeComponent( extraConfig?: ?{nativeOnly?: Object}, ): React$ComponentType | string { function attachDefaultEventTypes(viewConfig: any) { - if (Platform.OS === 'android') { - // This is supported on Android platform only, - // as lazy view managers discovery is Android-specific. - if (UIManager.ViewManagerNames) { - // Lazy view managers enabled. - viewConfig = merge(viewConfig, UIManager.getDefaultEventTypes()); - } else { - viewConfig.bubblingEventTypes = merge( - viewConfig.bubblingEventTypes, - UIManager.genericBubblingEventTypes, - ); - viewConfig.directEventTypes = merge( - viewConfig.directEventTypes, - UIManager.genericDirectEventTypes, - ); - } + // 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) { + // Lazy view managers enabled. + viewConfig = merge(viewConfig, UIManager.getDefaultEventTypes()); + } else { + viewConfig.bubblingEventTypes = merge( + viewConfig.bubblingEventTypes, + UIManager.genericBubblingEventTypes, + ); + viewConfig.directEventTypes = merge( + viewConfig.directEventTypes, + UIManager.genericDirectEventTypes, + ); } } diff --git a/Libraries/ReactNative/requireNativeComponent.js b/Libraries/ReactNative/requireNativeComponent.js index 4a6fd4c1310c0d..453be93f715b6f 100644 --- a/Libraries/ReactNative/requireNativeComponent.js +++ b/Libraries/ReactNative/requireNativeComponent.js @@ -51,22 +51,21 @@ function requireNativeComponent( extraConfig?: ?{nativeOnly?: Object}, ): React$ComponentType | string { function attachDefaultEventTypes(viewConfig: any) { - if (Platform.OS === 'android') { - // This is supported on Android platform only, - // as lazy view managers discovery is Android-specific. - if (UIManager.ViewManagerNames) { - // Lazy view managers enabled. - viewConfig = merge(viewConfig, UIManager.getDefaultEventTypes()); - } else { - viewConfig.bubblingEventTypes = merge( - viewConfig.bubblingEventTypes, - UIManager.genericBubblingEventTypes, - ); - viewConfig.directEventTypes = merge( - viewConfig.directEventTypes, - UIManager.genericDirectEventTypes, - ); - } + // 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) { + // Lazy view managers enabled. + viewConfig = merge(viewConfig, UIManager.getDefaultEventTypes()); + } else { + viewConfig.bubblingEventTypes = merge( + viewConfig.bubblingEventTypes, + UIManager.genericBubblingEventTypes, + ); + viewConfig.directEventTypes = merge( + viewConfig.directEventTypes, + UIManager.genericDirectEventTypes, + ); } } From ad6938cda188f30e38d1aa9cbc30ca791ef2d45f Mon Sep 17 00:00:00 2001 From: Naor Matania Date: Tue, 20 Mar 2018 06:32:57 -0700 Subject: [PATCH 0092/1109] Revert D7319513: Depend on local version of babel-plugin-react-transform Differential Revision: D7319513 Original commit changeset: 4945ec753087 fbshipit-source-id: 98de6a0fda19732c02ad780953497f9d9b451dea --- babel-preset/configs/hmr.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/babel-preset/configs/hmr.js b/babel-preset/configs/hmr.js index cdf5a022c202eb..91cb9a356c654b 100644 --- a/babel-preset/configs/hmr.js +++ b/babel-preset/configs/hmr.js @@ -7,6 +7,7 @@ 'use strict'; var path = require('path'); +var resolvePlugins = require('../lib/resolvePlugins'); var hmrTransform = 'react-transform-hmr/lib/index.js'; var transformPath = require.resolve(hmrTransform); @@ -22,9 +23,9 @@ module.exports = function(options, filename) { } return { - plugins: [ + plugins: resolvePlugins([ [ - require('metro-babel7-plugin-react-transform').default, + 'react-transform', { transforms: [{ transform: transform, @@ -33,6 +34,6 @@ module.exports = function(options, filename) { }] }, ] - ] + ]) }; }; From 6f339b6fcb011340d99d7b384f35987dcf03bdd4 Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Tue, 20 Mar 2018 06:53:37 -0700 Subject: [PATCH 0093/1109] Deprecate postProcessModules config param Reviewed By: mjesun Differential Revision: D7320671 fbshipit-source-id: 979108f0931f9ee0dd820025782137d4c726d19f --- local-cli/bundle/buildBundle.js | 1 - local-cli/server/runServer.js | 1 - 2 files changed, 2 deletions(-) diff --git a/local-cli/bundle/buildBundle.js b/local-cli/bundle/buildBundle.js index 10d1ecc6b78ba3..f476a139605455 100644 --- a/local-cli/bundle/buildBundle.js +++ b/local-cli/bundle/buildBundle.js @@ -95,7 +95,6 @@ async function buildBundle( maxWorkers: args.maxWorkers, platforms: defaultPlatforms.concat(platforms), postMinifyProcess: config.postMinifyProcess, - postProcessModules: config.postProcessModules, postProcessBundleSourcemap: config.postProcessBundleSourcemap, projectRoots: config.getProjectRoots(), providesModuleNodeModules: providesModuleNodeModules, diff --git a/local-cli/server/runServer.js b/local-cli/server/runServer.js index 8b790eac4d1fc7..b0daff3c52776e 100644 --- a/local-cli/server/runServer.js +++ b/local-cli/server/runServer.js @@ -198,7 +198,6 @@ function getPackagerServer(args, config, reporter) { polyfillModuleNames: config.getPolyfillModuleNames(), postMinifyProcess: config.postMinifyProcess, postProcessBundleSourcemap: config.postProcessBundleSourcemap, - postProcessModules: config.postProcessModules, projectRoots: args.projectRoots, providesModuleNodeModules: providesModuleNodeModules, reporter, From 15f0a7b76c7fc6ea86ca0f0e28e23ce492890431 Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Tue, 20 Mar 2018 06:53:49 -0700 Subject: [PATCH 0094/1109] Add getRunModuleStatement config param to configure the require() statements Reviewed By: cpojer Differential Revision: D7334078 fbshipit-source-id: c19340567c634e3173ee707e92389eaaa4e724e9 --- local-cli/bundle/buildBundle.js | 1 + local-cli/server/runServer.js | 1 + 2 files changed, 2 insertions(+) diff --git a/local-cli/bundle/buildBundle.js b/local-cli/bundle/buildBundle.js index f476a139605455..51427aa8f3a3d4 100644 --- a/local-cli/bundle/buildBundle.js +++ b/local-cli/bundle/buildBundle.js @@ -89,6 +89,7 @@ async function buildBundle( extraNodeModules: config.extraNodeModules, getModulesRunBeforeMainModule: config.getModulesRunBeforeMainModule, getPolyfills: config.getPolyfills, + getRunModuleStatement: config.getRunModuleStatement, getTransformOptions: config.getTransformOptions, globalTransformCache: null, hasteImplModulePath: config.hasteImplModulePath, diff --git a/local-cli/server/runServer.js b/local-cli/server/runServer.js index b0daff3c52776e..a9ba1557ddc7d1 100644 --- a/local-cli/server/runServer.js +++ b/local-cli/server/runServer.js @@ -190,6 +190,7 @@ function getPackagerServer(args, config, reporter) { dynamicDepsInPackages: config.dynamicDepsInPackages, getModulesRunBeforeMainModule: config.getModulesRunBeforeMainModule, getPolyfills: config.getPolyfills, + getRunModuleStatement: config.getRunModuleStatement, getTransformOptions: config.getTransformOptions, globalTransformCache: null, hasteImplModulePath: config.hasteImplModulePath, From ddfcaf96bcea0d08f89afe7d340be4a5f23679ce Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Tue, 20 Mar 2018 14:37:57 -0700 Subject: [PATCH 0095/1109] Drop fb{android|objc} prefixed keys for oss builds Reviewed By: hramos Differential Revision: D7329425 fbshipit-source-id: 8a2e5936991f99b0d5112a6940856e8ee1d32a55 --- ReactNative/DEFS.bzl | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/ReactNative/DEFS.bzl b/ReactNative/DEFS.bzl index 8842ed74f8cd23..b84007444e5e9c 100644 --- a/ReactNative/DEFS.bzl +++ b/ReactNative/DEFS.bzl @@ -34,8 +34,12 @@ with allow_unsafe_import(): # Building is not supported in OSS right now -def rn_xplat_cxx_library(name, platforms = None, **kwargs): - cxx_library(name=name, **kwargs) +def rn_xplat_cxx_library(name, **kwargs): + _ignore = kwargs + native.cxx_library( + name=name, + visibility=kwargs.get("visibility", []) + ) # Example: react_native_target('java/com/facebook/react/common:common') @@ -89,39 +93,39 @@ def rn_android_library(name, deps=[], plugins=[], *args, **kwargs): plugins = list(set(plugins + react_module_plugins)) - android_library(name=name, deps=deps, plugins=plugins, *args, **kwargs) + native.android_library(name=name, deps=deps, plugins=plugins, *args, **kwargs) def rn_android_binary(*args, **kwargs): - android_binary(*args, **kwargs) + native.android_binary(*args, **kwargs) def rn_android_build_config(*args, **kwargs): - android_build_config(*args, **kwargs) + native.android_build_config(*args, **kwargs) def rn_android_resource(*args, **kwargs): - android_resource(*args, **kwargs) + native.android_resource(*args, **kwargs) def rn_android_prebuilt_aar(*args, **kwargs): - android_prebuilt_aar(*args, **kwargs) + native.android_prebuilt_aar(*args, **kwargs) def rn_java_library(*args, **kwargs): - java_library(*args, **kwargs) + native.java_library(*args, **kwargs) def rn_java_annotation_processor(*args, **kwargs): - java_annotation_processor(*args, **kwargs) + native.java_annotation_processor(*args, **kwargs) def rn_prebuilt_native_library(*args, **kwargs): - prebuilt_native_library(*args, **kwargs) + native.prebuilt_native_library(*args, **kwargs) def rn_prebuilt_jar(*args, **kwargs): - prebuilt_jar(*args, **kwargs) + native.prebuilt_jar(*args, **kwargs) def rn_robolectric_test(name, srcs, vm_args=None, *args, **kwargs): @@ -166,10 +170,10 @@ def rn_robolectric_test(name, srcs, vm_args=None, *args, **kwargs): ) -original_cxx_library = cxx_library - - def cxx_library(allow_jni_merging=None, **kwargs): - kwargs.pop('fbandroid_deps', []) - kwargs.pop('fbobjc_deps', []) - original_cxx_library(**kwargs) + args = { + k: v + for k, v in kwargs.items() + if not (k.startswith("fbandroid_") or k.startswith("fbobjc_")) + } + native.cxx_library(**args) From ea92f47d901e260983a3e28e209a764a0d8b567b Mon Sep 17 00:00:00 2001 From: Artem Egorov Date: Tue, 20 Mar 2018 14:41:26 -0700 Subject: [PATCH 0096/1109] While linking plugin ask for params only once Summary: Resolve #18333 CLI should ask users for params only once and waiting for response while linking plugin Ran the `link` commands for iOS and Android and confirmed that params requested only once. [CLI][FEATURE][local-cli/link/link.js] - Requesting link params only once for all platforms Closes https://github.com/facebook/react-native/pull/18349 Differential Revision: D7342181 Pulled By: hramos fbshipit-source-id: a10f0f7f2170f067d78b30e5a5221634b77da577 --- local-cli/link/link.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/local-cli/link/link.js b/local-cli/link/link.js index b77c135f9f470f..66e9efbf563c8e 100644 --- a/local-cli/link/link.js +++ b/local-cli/link/link.js @@ -37,7 +37,9 @@ log.heading = 'rnpm-link'; const dedupeAssets = (assets) => uniqBy(assets, asset => path.basename(asset)); -const linkDependency = (platforms, project, dependency) => { +const linkDependency = async (platforms, project, dependency) => { + const params = await pollParams(dependency.config.params); + Object.keys(platforms || {}) .forEach(platform => { if (!project[platform] || !dependency.config[platform]) { @@ -56,18 +58,16 @@ const linkDependency = (platforms, project, dependency) => { return null; } - return pollParams(dependency.config.params).then(params => { - log.info(`Linking ${dependency.name} ${platform} dependency`); + log.info(`Linking ${dependency.name} ${platform} dependency`); - linkConfig.register( - dependency.name, - dependency.config[platform], - params, - project[platform] - ); + linkConfig.register( + dependency.name, + dependency.config[platform], + params, + project[platform] + ); - log.info(`Platform '${platform}' module ${dependency.name} has been successfully linked`); - }); + log.info(`Platform '${platform}' module ${dependency.name} has been successfully linked`); }); }; From 38fe8c2a9e35df5017c9e5fdef1338fd0394b80c Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Tue, 20 Mar 2018 15:28:17 -0700 Subject: [PATCH 0097/1109] moved ReactFabricInternals outside of shims Summary: Simply moving it out of shims to not confuse React project Reviewed By: bvaughn Differential Revision: D7341846 fbshipit-source-id: b1a0cdb0caca977de744699521f42556699993a7 --- Libraries/{Renderer/shims => ReactNative}/ReactFabricInternals.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Libraries/{Renderer/shims => ReactNative}/ReactFabricInternals.js (100%) diff --git a/Libraries/Renderer/shims/ReactFabricInternals.js b/Libraries/ReactNative/ReactFabricInternals.js similarity index 100% rename from Libraries/Renderer/shims/ReactFabricInternals.js rename to Libraries/ReactNative/ReactFabricInternals.js From 3b36a6bf06dee69481a47534e41426a6288bf617 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Tue, 20 Mar 2018 17:03:06 -0700 Subject: [PATCH 0098/1109] React sync for revisions ced176e...9d484ed Reviewed By: bvaughn Differential Revision: D7338640 fbshipit-source-id: e2d75d2f1795fb3c37f193d15216951c707711d9 --- Libraries/Renderer/REVISION | 2 +- Libraries/Renderer/ReactFabric-dev.js | 3259 ++++++++-------- Libraries/Renderer/ReactFabric-prod.js | 671 ++-- Libraries/Renderer/ReactNativeRenderer-dev.js | 3265 +++++++++-------- .../Renderer/ReactNativeRenderer-prod.js | 681 ++-- Libraries/Renderer/shims/ReactFabric.js | 5 + 6 files changed, 4154 insertions(+), 3729 deletions(-) diff --git a/Libraries/Renderer/REVISION b/Libraries/Renderer/REVISION index 3210553184230d..7e989de9720393 100644 --- a/Libraries/Renderer/REVISION +++ b/Libraries/Renderer/REVISION @@ -1 +1 @@ -ced176edb7605a25e916895fd060f3943c647fee \ No newline at end of file +9d484edc4b64160cb335a23a2cb21667fb2cdf4c \ No newline at end of file diff --git a/Libraries/Renderer/ReactFabric-dev.js b/Libraries/Renderer/ReactFabric-dev.js index e485c562182322..22c77f2e072d9c 100644 --- a/Libraries/Renderer/ReactFabric-dev.js +++ b/Libraries/Renderer/ReactFabric-dev.js @@ -25,8 +25,8 @@ var deepDiffer = require("deepDiffer"); var flattenStyle = require("flattenStyle"); var React = require("react"); var emptyObject = require("fbjs/lib/emptyObject"); -var checkPropTypes = require("prop-types/checkPropTypes"); var shallowEqual = require("fbjs/lib/shallowEqual"); +var checkPropTypes = require("prop-types/checkPropTypes"); var deepFreezeAndThrowOnMutationInDev = require("deepFreezeAndThrowOnMutationInDev"); var FabricUIManager = require("FabricUIManager"); @@ -4134,1645 +4134,1320 @@ function findCurrentHostFiberWithNoPortals(parent) { return null; } -var valueStack = []; +// 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; -var fiberStack = void 0; +// TODO: Use an opaque type once ESLint et al support the syntax -{ - fiberStack = []; -} +var NoWork = 0; +var Sync = 1; +var Never = MAX_SIGNED_31_BIT_INT; -var index = -1; +var UNIT_SIZE = 10; +var MAGIC_NUMBER_OFFSET = 2; -function createCursor(defaultValue) { - return { - current: defaultValue - }; +// 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 ((ms / UNIT_SIZE) | 0) + MAGIC_NUMBER_OFFSET; } -function pop(cursor, fiber) { - if (index < 0) { - { - warning(false, "Unexpected pop."); - } - return; - } +function expirationTimeToMs(expirationTime) { + return (expirationTime - MAGIC_NUMBER_OFFSET) * UNIT_SIZE; +} - { - if (fiber !== fiberStack[index]) { - warning(false, "Unexpected Fiber popped."); - } - } +function ceiling(num, precision) { + return (((num / precision) | 0) + 1) * precision; +} + +function computeExpirationBucket(currentTime, expirationInMs, bucketSizeMs) { + return ceiling( + currentTime + expirationInMs / UNIT_SIZE, + bucketSizeMs / UNIT_SIZE + ); +} - cursor.current = valueStack[index]; +var NoContext = 0; +var AsyncMode = 1; +var StrictMode = 2; - valueStack[index] = null; +var hasBadMapPolyfill = void 0; - { - fiberStack[index] = null; +{ + 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; - index--; +{ + debugCounter = 1; } -function push(cursor, value, fiber) { - index++; +function FiberNode(tag, pendingProps, key, mode) { + // Instance + this.tag = tag; + this.key = key; + this.type = null; + this.stateNode = null; - valueStack[index] = cursor.current; + // Fiber + this["return"] = null; + this.child = null; + this.sibling = null; + this.index = 0; - { - fiberStack[index] = fiber; - } + this.ref = null; - cursor.current = value; -} + this.pendingProps = pendingProps; + this.memoizedProps = null; + this.updateQueue = null; + this.memoizedState = null; -function reset() { - while (index > -1) { - valueStack[index] = null; + this.mode = mode; - { - fiberStack[index] = null; - } + // Effects + this.effectTag = NoEffect; + this.nextEffect = null; - index--; + this.firstEffect = null; + this.lastEffect = null; + + this.expirationTime = NoWork; + + this.alternate = null; + + { + this._debugID = debugCounter++; + this._debugSource = null; + this._debugOwner = null; + this._debugIsCurrentlyTiming = false; + if (!hasBadMapPolyfill && typeof Object.preventExtensions === "function") { + Object.preventExtensions(this); + } } } -var describeComponentFrame = function(name, source, ownerName) { - return ( - "\n in " + - (name || "Unknown") + - (source - ? " (at " + - source.fileName.replace(/^.*[\\\/]/, "") + - ":" + - source.lineNumber + - ")" - : ownerName ? " (created by " + ownerName + ")" : "") - ); +// 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 describeFiber(fiber) { - switch (fiber.tag) { - case IndeterminateComponent: - case FunctionalComponent: - case ClassComponent: - case HostComponent: - var owner = fiber._debugOwner; - var source = fiber._debugSource; - var name = getComponentName(fiber); - var ownerName = null; - if (owner) { - ownerName = getComponentName(owner); - } - return describeComponentFrame(name, source, ownerName); - default: - return ""; - } +function shouldConstruct(Component) { + return !!(Component.prototype && Component.prototype.isReactComponent); } -// This function can only be called with a work-in-progress fiber and -// only during begin or complete phase. Do not call it under any other -// circumstances. -function getStackAddendumByWorkInProgressFiber(workInProgress) { - var info = ""; - var node = workInProgress; - do { - info += describeFiber(node); - // Otherwise this return pointer might point to the wrong tree: - node = node["return"]; - } while (node); - return info; -} +// 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.type = current.type; + workInProgress.stateNode = current.stateNode; -function getCurrentFiberOwnerName() { - { - var fiber = ReactDebugCurrentFiber.current; - if (fiber === null) { - return null; - } - var owner = fiber._debugOwner; - if (owner !== null && typeof owner !== "undefined") { - return getComponentName(owner); + { + // DEV-only fields + workInProgress._debugID = current._debugID; + workInProgress._debugSource = current._debugSource; + workInProgress._debugOwner = current._debugOwner; } - } - return null; -} -function getCurrentFiberStackAddendum() { - { - var fiber = ReactDebugCurrentFiber.current; - if (fiber === null) { - return null; - } - // Safe because if current fiber exists, we are reconciling, - // and it is guaranteed to be the work-in-progress version. - return getStackAddendumByWorkInProgressFiber(fiber); + 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; } - return null; -} -function resetCurrentFiber() { - ReactDebugCurrentFrame.getCurrentStack = null; - ReactDebugCurrentFiber.current = null; - ReactDebugCurrentFiber.phase = null; -} + workInProgress.expirationTime = expirationTime; -function setCurrentFiber(fiber) { - ReactDebugCurrentFrame.getCurrentStack = getCurrentFiberStackAddendum; - ReactDebugCurrentFiber.current = fiber; - ReactDebugCurrentFiber.phase = null; + workInProgress.child = current.child; + workInProgress.memoizedProps = current.memoizedProps; + workInProgress.memoizedState = current.memoizedState; + workInProgress.updateQueue = current.updateQueue; + + // These will be overridden during the parent's reconciliation + workInProgress.sibling = current.sibling; + workInProgress.index = current.index; + workInProgress.ref = current.ref; + + return workInProgress; } -function setCurrentPhase(phase) { - ReactDebugCurrentFiber.phase = phase; +function createHostRootFiber(isAsync) { + var mode = isAsync ? AsyncMode | StrictMode : NoContext; + return createFiber(HostRoot, null, null, mode); } -var ReactDebugCurrentFiber = { - current: null, - phase: null, - resetCurrentFiber: resetCurrentFiber, - setCurrentFiber: setCurrentFiber, - setCurrentPhase: setCurrentPhase, - getCurrentFiberOwnerName: getCurrentFiberOwnerName, - getCurrentFiberStackAddendum: getCurrentFiberStackAddendum -}; - -var debugRenderPhaseSideEffects = false; -var debugRenderPhaseSideEffectsForStrictMode = false; - -var enableUserTimingAPI = true; -var enableGetDerivedStateFromCatch = false; -var warnAboutDeprecatedLifecycles = false; -var replayFailedUnitOfWorkWithInvokeGuardedCallback = true; - -// React Fabric uses persistent reconciler. -var enableMutatingReconciler = false; -var enableNoopReconciler = false; -var enablePersistentReconciler = true; - -// Only used in www builds. - -// 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$$1) { - var prefix = warning$$1 ? warningEmoji + " " : reactEmoji + " "; - var suffix = warning$$1 ? " Warning: " + warning$$1 : ""; - 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$$1) { - var formattedMarkName = formatMarkName(markName); - var formattedLabel = formatLabel(label, warning$$1); - 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) || "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) || "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$$1) { - var componentName = getComponentName(fiber) || "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$$1); -}; - -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 CallComponent: - case ReturnComponent: - case Fragment: - case ContextProvider: - case ContextConsumer: - 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$$1 = didExpire ? "React was blocked by main thread" : null; - endMark( - "(Waiting for async callback...)", - "(Waiting for async callback...)", - warning$$1 - ); - } - } -} - -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$$1 = "An error was thrown inside this error boundary"; - endFiberMark(fiber, null, warning$$1); - } -} - -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$$1 = hasScheduledUpdateInCurrentPhase - ? "Scheduled a cascading update" - : null; - endFiberMark(currentPhaseFiber, currentPhase, warning$$1); - } - 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) { - if (enableUserTimingAPI) { - if (!supportsUserTiming) { - return; - } - var warning$$1 = null; - if (interruptedBy !== null) { - if (interruptedBy.tag === HostRoot) { - warning$$1 = "A top-level update interrupted the previous render"; - } else { - var componentName = getComponentName(interruptedBy) || "Unknown"; - warning$$1 = - "An update to " + componentName + " interrupted the previous render"; - } - } else if (commitCountInCurrentWorkLoop > 1) { - warning$$1 = "There were cascading updates"; - } - commitCountInCurrentWorkLoop = 0; - // Pause any measurements until the next loop. - pauseTimers(); - endMark( - "(React Tree Reconciliation)", - "(React Tree Reconciliation)", - warning$$1 - ); - } -} - -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$$1 = null; - if (hasScheduledUpdateInCurrentCommit) { - warning$$1 = "Lifecycle hook scheduled a cascading update"; - } else if (commitCountInCurrentWorkLoop > 0) { - warning$$1 = "Caused by a cascading update in earlier commit"; - } - hasScheduledUpdateInCurrentCommit = false; - commitCountInCurrentWorkLoop++; - isCommitting = false; - labelsInCurrentCommit.clear(); - - endMark("(Committing Changes)", "(Committing Changes)", warning$$1); - } -} - -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 createFiberFromElement(element, mode, expirationTime) { + var owner = null; + { + owner = element._owner; } -} -function startCommitLifeCyclesTimer() { - if (enableUserTimingAPI) { - if (!supportsUserTiming) { - return; - } - effectCountInCurrentCommit = 0; - beginMark("(Calling Lifecycle Methods)"); - } -} + var fiber = void 0; + var type = element.type; + var key = element.key; + var pendingProps = element.props; -function stopCommitLifeCyclesTimer() { - if (enableUserTimingAPI) { - if (!supportsUserTiming) { - return; + var fiberTag = void 0; + if (typeof type === "function") { + fiberTag = shouldConstruct(type) ? ClassComponent : IndeterminateComponent; + } else if (typeof type === "string") { + fiberTag = HostComponent; + } else { + switch (type) { + case REACT_FRAGMENT_TYPE: + return createFiberFromFragment( + pendingProps.children, + mode, + expirationTime, + key + ); + case REACT_ASYNC_MODE_TYPE: + fiberTag = Mode; + mode |= AsyncMode | StrictMode; + break; + case REACT_STRICT_MODE_TYPE: + fiberTag = Mode; + mode |= StrictMode; + break; + case REACT_CALL_TYPE: + fiberTag = CallComponent; + break; + case REACT_RETURN_TYPE: + fiberTag = ReturnComponent; + break; + default: { + if (typeof type === "object" && type !== null) { + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + fiberTag = ContextProvider; + break; + case REACT_CONTEXT_TYPE: + // This is a consumer + fiberTag = ContextConsumer; + break; + case REACT_FORWARD_REF_TYPE: + fiberTag = ForwardRef; + break; + default: + if (typeof type.tag === "number") { + // Currently assumed to be a continuation and therefore is a + // fiber already. + // TODO: The yield system is currently broken for updates in + // some cases. The reified yield stores a fiber, but we don't + // know which fiber that is; the current or a workInProgress? + // When the continuation gets rendered here we don't know if we + // can reuse that fiber or if we need to clone it. There is + // probably a clever way to restructure this. + fiber = type; + fiber.pendingProps = pendingProps; + fiber.expirationTime = expirationTime; + return fiber; + } else { + throwOnInvalidElementType(type, owner); + } + break; + } + } else { + throwOnInvalidElementType(type, owner); + } + } } - var count = effectCountInCurrentCommit; - effectCountInCurrentCommit = 0; - endMark( - "(Calling Lifecycle Methods: " + count + " Total)", - "(Calling Lifecycle Methods)", - null - ); } -} - -var warnedAboutMissingGetChildContext = void 0; - -{ - warnedAboutMissingGetChildContext = {}; -} -// A cursor to the current merged context object on the stack. -var contextStackCursor = createCursor(emptyObject); -// 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 = emptyObject; + fiber = createFiber(fiberTag, pendingProps, key, mode); + fiber.type = type; + fiber.expirationTime = expirationTime; -function getUnmaskedContext(workInProgress) { - var hasOwnContext = isContextProvider(workInProgress); - if (hasOwnContext) { - // If the fiber is a context provider itself, when we read its context - // we 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; + { + fiber._debugSource = element._source; + fiber._debugOwner = element._owner; } - return contextStackCursor.current; -} -function cacheContext(workInProgress, unmaskedContext, maskedContext) { - var instance = workInProgress.stateNode; - instance.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; - instance.__reactInternalMemoizedMaskedChildContext = maskedContext; + return fiber; } -function getMaskedContext(workInProgress, unmaskedContext) { - var type = workInProgress.type; - var contextTypes = type.contextTypes; - if (!contextTypes) { - return emptyObject; - } - - // 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]; - } - +function throwOnInvalidElementType(type, owner) { + var info = ""; { - var name = getComponentName(workInProgress) || "Unknown"; - checkPropTypes( - contextTypes, - context, - "context", - name, - ReactDebugCurrentFiber.getCurrentFiberStackAddendum - ); - } - - // 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); + 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) : null; + if (ownerName) { + info += "\n\nCheck the render method of `" + ownerName + "`."; + } } - - return context; -} - -function hasContextChanged() { - return didPerformWorkStackCursor.current; + invariant( + false, + "Element type is invalid: expected a string (for built-in " + + "components) or a class/function (for composite components) " + + "but got: %s.%s", + type == null ? type : typeof type, + info + ); } -function isContextConsumer(fiber) { - return fiber.tag === ClassComponent && fiber.type.contextTypes != null; +function createFiberFromFragment(elements, mode, expirationTime, key) { + var fiber = createFiber(Fragment, elements, key, mode); + fiber.expirationTime = expirationTime; + return fiber; } -function isContextProvider(fiber) { - return fiber.tag === ClassComponent && fiber.type.childContextTypes != null; +function createFiberFromText(content, mode, expirationTime) { + var fiber = createFiber(HostText, content, null, mode); + fiber.expirationTime = expirationTime; + return fiber; } -function popContextProvider(fiber) { - if (!isContextProvider(fiber)) { - return; - } - - pop(didPerformWorkStackCursor, fiber); - pop(contextStackCursor, fiber); +function createFiberFromHostInstanceForDeletion() { + var fiber = createFiber(HostComponent, null, null, NoContext); + fiber.type = "DELETED"; + return fiber; } -function popTopLevelContextObject(fiber) { - pop(didPerformWorkStackCursor, fiber); - pop(contextStackCursor, 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; } -function pushTopLevelContextObject(fiber, context, didChange) { - invariant( - contextStackCursor.cursor == null, - "Unexpected context found on stack. " + - "This error is likely caused by a bug in React. Please file an issue." - ); +// TODO: This should be lifted into the renderer. - push(contextStackCursor, context, fiber); - push(didPerformWorkStackCursor, didChange, fiber); +function createFiberRoot(containerInfo, isAsync, hydrate) { + // Cyclic construction. This cheats the type system right now because + // stateNode is any. + var uninitializedFiber = createHostRootFiber(isAsync); + var root = { + current: uninitializedFiber, + containerInfo: containerInfo, + pendingChildren: null, + pendingCommitExpirationTime: NoWork, + finishedWork: null, + context: null, + pendingContext: null, + hydrate: hydrate, + remainingExpirationTime: NoWork, + firstBatch: null, + nextScheduledRoot: null + }; + uninitializedFiber.stateNode = root; + return root; } -function processChildContext(fiber, parentContext) { - var instance = fiber.stateNode; - var childContextTypes = fiber.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(fiber) || "Unknown"; +var onCommitFiberRoot = null; +var onCommitFiberUnmount = null; +var hasLoggedError = false; - if (!warnedAboutMissingGetChildContext[componentName]) { - warnedAboutMissingGetChildContext[componentName] = true; - warning( - 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 - ); +function catchErrors(fn) { + return function(arg) { + try { + return fn(arg); + } catch (err) { + if (true && !hasLoggedError) { + hasLoggedError = true; + warning(false, "React DevTools encountered an error: %s", err); } } - return parentContext; - } + }; +} - var childContext = void 0; - { - ReactDebugCurrentFiber.setCurrentPhase("getChildContext"); - } - startPhaseTimer(fiber, "getChildContext"); - childContext = instance.getChildContext(); - stopPhaseTimer(); - { - ReactDebugCurrentFiber.setCurrentPhase(null); +function injectInternals(internals) { + if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === "undefined") { + // No DevTools + return false; } - for (var contextKey in childContext) { - invariant( - contextKey in childContextTypes, - '%s.getChildContext(): key "%s" is not defined in childContextTypes.', - getComponentName(fiber) || "Unknown", - contextKey - ); + 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; } - { - var name = getComponentName(fiber) || "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. - ReactDebugCurrentFiber.getCurrentFiberStackAddendum - ); + if (!hook.supportsFiber) { + { + warning( + 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; } - - return Object.assign({}, parentContext, childContext); -} - -function pushContextProvider(workInProgress) { - if (!isContextProvider(workInProgress)) { - return false; + 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. + { + warning(false, "React DevTools encountered an error: %s.", err); + } } - - 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) || - emptyObject; - - // 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 - ); - + // DevTools exists return true; } -function invalidateContextProvider(workInProgress, didChange) { - var instance = workInProgress.stateNode; - invariant( - instance, - "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, 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 onCommitRoot(root) { + if (typeof onCommitFiberRoot === "function") { + onCommitFiberRoot(root); } } -function resetContext() { - previousContext = emptyObject; - contextStackCursor.current = emptyObject; - didPerformWorkStackCursor.current = false; -} - -function findCurrentUnmaskedContext(fiber) { - // Currently this is only used with renderSubtreeIntoContainer; not sure if it - // makes sense elsewhere - invariant( - isFiberMounted(fiber) && fiber.tag === ClassComponent, - "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; - while (node.tag !== HostRoot) { - if (isContextProvider(node)) { - return node.stateNode.__reactInternalMemoizedMergedChildContext; - } - var parent = node["return"]; - invariant( - parent, - "Found unexpected detached subtree parent. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - node = parent; +function onCommitUnmount(fiber) { + if (typeof onCommitFiberUnmount === "function") { + onCommitFiberUnmount(fiber); } - return node.stateNode.context; -} - -// 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; - -// TODO: Use an opaque type once ESLint et al support the syntax - -var NoWork = 0; -var Sync = 1; -var Never = MAX_SIGNED_31_BIT_INT; - -var UNIT_SIZE = 10; -var MAGIC_NUMBER_OFFSET = 2; - -// 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 ((ms / UNIT_SIZE) | 0) + MAGIC_NUMBER_OFFSET; -} - -function expirationTimeToMs(expirationTime) { - return (expirationTime - MAGIC_NUMBER_OFFSET) * UNIT_SIZE; -} - -function ceiling(num, precision) { - return (((num / precision) | 0) + 1) * precision; } -function computeExpirationBucket(currentTime, expirationInMs, bucketSizeMs) { - return ceiling( - currentTime + expirationInMs / UNIT_SIZE, - bucketSizeMs / UNIT_SIZE +var describeComponentFrame = function(name, source, ownerName) { + return ( + "\n in " + + (name || "Unknown") + + (source + ? " (at " + + source.fileName.replace(/^.*[\\\/]/, "") + + ":" + + source.lineNumber + + ")" + : ownerName ? " (created by " + ownerName + ")" : "") ); -} - -var NoContext = 0; -var AsyncMode = 1; -var StrictMode = 2; - -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; +function describeFiber(fiber) { + switch (fiber.tag) { + case IndeterminateComponent: + case FunctionalComponent: + case ClassComponent: + case HostComponent: + var owner = fiber._debugOwner; + var source = fiber._debugSource; + var name = getComponentName(fiber); + var ownerName = null; + if (owner) { + ownerName = getComponentName(owner); + } + return describeComponentFrame(name, source, ownerName); + default: + return ""; } } -// 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; +// This function can only be called with a work-in-progress fiber and +// only during begin or complete phase. Do not call it under any other +// circumstances. +function getStackAddendumByWorkInProgressFiber(workInProgress) { + var info = ""; + var node = workInProgress; + do { + info += describeFiber(node); + // Otherwise this return pointer might point to the wrong tree: + node = node["return"]; + } while (node); + return info; } -function FiberNode(tag, pendingProps, key, mode) { - // Instance - this.tag = tag; - this.key = key; - 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.mode = mode; +/** + * 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. + */ - // Effects - this.effectTag = NoEffect; - this.nextEffect = null; +var lowPriorityWarning = function() {}; - this.firstEffect = null; - this.lastEffect = null; +{ + 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]; + } - this.expirationTime = NoWork; + 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) {} + }; - this.alternate = null; + lowPriorityWarning = function(condition, format) { + if (format === undefined) { + throw new Error( + "`warning(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]; + } - { - this._debugID = debugCounter++; - this._debugSource = null; - this._debugOwner = null; - this._debugIsCurrentlyTiming = false; - if (!hasBadMapPolyfill && typeof Object.preventExtensions === "function") { - Object.preventExtensions(this); + printWarning.apply(undefined, [format].concat(args)); } - } + }; } -// 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); -}; +var lowPriorityWarning$1 = lowPriorityWarning; -function shouldConstruct(Component) { - return !!(Component.prototype && Component.prototype.isReactComponent); -} +var ReactStrictModeWarnings = { + discardPendingWarnings: function() {}, + flushPendingDeprecationWarnings: function() {}, + flushPendingUnsafeLifecycleWarnings: function() {}, + recordDeprecationWarnings: function(fiber, instance) {}, + recordUnsafeLifecycleWarnings: function(fiber, instance) {} +}; -// 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.type = current.type; - workInProgress.stateNode = current.stateNode; +{ + var LIFECYCLE_SUGGESTIONS = { + UNSAFE_componentWillMount: "componentDidMount", + UNSAFE_componentWillReceiveProps: "static getDerivedStateFromProps", + UNSAFE_componentWillUpdate: "componentDidUpdate" + }; - { - // DEV-only fields - workInProgress._debugID = current._debugID; - workInProgress._debugSource = current._debugSource; - workInProgress._debugOwner = current._debugOwner; - } + var pendingComponentWillMountWarnings = []; + var pendingComponentWillReceivePropsWarnings = []; + var pendingComponentWillUpdateWarnings = []; + var pendingUnsafeLifecycleWarnings = new Map(); - workInProgress.alternate = current; - current.alternate = workInProgress; - } else { - workInProgress.pendingProps = pendingProps; + // Tracks components we have already warned about. + var didWarnAboutDeprecatedLifecycles = new Set(); + var didWarnAboutUnsafeLifecycles = new Set(); - // We already have an alternate. - // Reset the effect tag. - workInProgress.effectTag = NoEffect; + ReactStrictModeWarnings.discardPendingWarnings = function() { + pendingComponentWillMountWarnings = []; + pendingComponentWillReceivePropsWarnings = []; + pendingComponentWillUpdateWarnings = []; + pendingUnsafeLifecycleWarnings = new Map(); + }; - // The effect list is no longer valid. - workInProgress.nextEffect = null; - workInProgress.firstEffect = null; - workInProgress.lastEffect = null; - } + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = function() { + pendingUnsafeLifecycleWarnings.forEach(function( + lifecycleWarningsMap, + strictRoot + ) { + var lifecyclesWarningMesages = []; - workInProgress.expirationTime = expirationTime; + 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) || "Component"); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); - workInProgress.child = current.child; - workInProgress.memoizedProps = current.memoizedProps; - workInProgress.memoizedState = current.memoizedState; - workInProgress.updateQueue = current.updateQueue; + var formatted = lifecycle.replace("UNSAFE_", ""); + var suggestion = LIFECYCLE_SUGGESTIONS[lifecycle]; + var sortedComponentNames = Array.from(componentNames) + .sort() + .join(", "); - // These will be overridden during the parent's reconciliation - workInProgress.sibling = current.sibling; - workInProgress.index = current.index; - workInProgress.ref = current.ref; + lifecyclesWarningMesages.push( + formatted + + ": Please update the following components to use " + + (suggestion + " instead: " + sortedComponentNames) + ); + } + }); - return workInProgress; -} + if (lifecyclesWarningMesages.length > 0) { + var strictRootComponentStack = getStackAddendumByWorkInProgressFiber( + strictRoot + ); -function createHostRootFiber(isAsync) { - var mode = isAsync ? AsyncMode | StrictMode : NoContext; - return createFiber(HostRoot, null, null, mode); -} + warning( + 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, + lifecyclesWarningMesages.join("\n\n") + ); + } + }); -function createFiberFromElement(element, mode, expirationTime) { - var owner = null; - { - owner = element._owner; - } + pendingUnsafeLifecycleWarnings = new Map(); + }; - var fiber = void 0; - var type = element.type; - var key = element.key; - var pendingProps = element.props; + var getStrictRoot = function(fiber) { + var maybeStrictRoot = null; - var fiberTag = void 0; - if (typeof type === "function") { - fiberTag = shouldConstruct(type) ? ClassComponent : IndeterminateComponent; - } else if (typeof type === "string") { - fiberTag = HostComponent; - } else { - switch (type) { - case REACT_FRAGMENT_TYPE: - return createFiberFromFragment( - pendingProps.children, - mode, - expirationTime, - key - ); - case REACT_ASYNC_MODE_TYPE: - fiberTag = Mode; - mode |= AsyncMode | StrictMode; - break; - case REACT_STRICT_MODE_TYPE: - fiberTag = Mode; - mode |= StrictMode; - break; - case REACT_CALL_TYPE: - fiberTag = CallComponent; - break; - case REACT_RETURN_TYPE: - fiberTag = ReturnComponent; - break; - default: { - if (typeof type === "object" && type !== null) { - switch (type.$$typeof) { - case REACT_PROVIDER_TYPE: - fiberTag = ContextProvider; - break; - case REACT_CONTEXT_TYPE: - // This is a consumer - fiberTag = ContextConsumer; - break; - case REACT_FORWARD_REF_TYPE: - fiberTag = ForwardRef; - break; - default: - if (typeof type.tag === "number") { - // Currently assumed to be a continuation and therefore is a - // fiber already. - // TODO: The yield system is currently broken for updates in - // some cases. The reified yield stores a fiber, but we don't - // know which fiber that is; the current or a workInProgress? - // When the continuation gets rendered here we don't know if we - // can reuse that fiber or if we need to clone it. There is - // probably a clever way to restructure this. - fiber = type; - fiber.pendingProps = pendingProps; - fiber.expirationTime = expirationTime; - return fiber; - } else { - throwOnInvalidElementType(type, owner); - } - break; - } - } else { - throwOnInvalidElementType(type, owner); - } + while (fiber !== null) { + if (fiber.mode & StrictMode) { + maybeStrictRoot = fiber; } + + fiber = fiber["return"]; } - } - fiber = createFiber(fiberTag, pendingProps, key, mode); - fiber.type = type; - fiber.expirationTime = expirationTime; + return maybeStrictRoot; + }; + + ReactStrictModeWarnings.flushPendingDeprecationWarnings = function() { + if (pendingComponentWillMountWarnings.length > 0) { + var uniqueNames = new Set(); + pendingComponentWillMountWarnings.forEach(function(fiber) { + uniqueNames.add(getComponentName(fiber) || "Component"); + didWarnAboutDeprecatedLifecycles.add(fiber.type); + }); - { - fiber._debugSource = element._source; - fiber._debugOwner = element._owner; - } + var sortedNames = Array.from(uniqueNames) + .sort() + .join(", "); - return fiber; -} + 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 + ); -function throwOnInvalidElementType(type, owner) { - 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."; + pendingComponentWillMountWarnings = []; } - var ownerName = owner ? getComponentName(owner) : null; - if (ownerName) { - info += "\n\nCheck the render method of `" + ownerName + "`."; + + if (pendingComponentWillReceivePropsWarnings.length > 0) { + var _uniqueNames = new Set(); + pendingComponentWillReceivePropsWarnings.forEach(function(fiber) { + _uniqueNames.add(getComponentName(fiber) || "Component"); + didWarnAboutDeprecatedLifecycles.add(fiber.type); + }); + + var _sortedNames = Array.from(_uniqueNames) + .sort() + .join(", "); + + 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 = []; } - } - invariant( - false, - "Element type is invalid: expected a string (for built-in " + - "components) or a class/function (for composite components) " + - "but got: %s.%s", - type == null ? type : typeof type, - info - ); -} -function createFiberFromFragment(elements, mode, expirationTime, key) { - var fiber = createFiber(Fragment, elements, key, mode); - fiber.expirationTime = expirationTime; - return fiber; -} + if (pendingComponentWillUpdateWarnings.length > 0) { + var _uniqueNames2 = new Set(); + pendingComponentWillUpdateWarnings.forEach(function(fiber) { + _uniqueNames2.add(getComponentName(fiber) || "Component"); + didWarnAboutDeprecatedLifecycles.add(fiber.type); + }); -function createFiberFromText(content, mode, expirationTime) { - var fiber = createFiber(HostText, content, null, mode); - fiber.expirationTime = expirationTime; - return fiber; -} + var _sortedNames2 = Array.from(_uniqueNames2) + .sort() + .join(", "); -function createFiberFromHostInstanceForDeletion() { - var fiber = createFiber(HostComponent, null, null, NoContext); - fiber.type = "DELETED"; - return fiber; -} + 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 + ); -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 + pendingComponentWillUpdateWarnings = []; + } }; - return fiber; -} -// TODO: This should be lifted into the renderer. + ReactStrictModeWarnings.recordDeprecationWarnings = function( + fiber, + instance + ) { + // Dedup strategy: Warn once per component. + if (didWarnAboutDeprecatedLifecycles.has(fiber.type)) { + return; + } -function createFiberRoot(containerInfo, isAsync, hydrate) { - // Cyclic construction. This cheats the type system right now because - // stateNode is any. - var uninitializedFiber = createHostRootFiber(isAsync); - var root = { - current: uninitializedFiber, - containerInfo: containerInfo, - pendingChildren: null, - pendingCommitExpirationTime: NoWork, - finishedWork: null, - context: null, - pendingContext: null, - hydrate: hydrate, - remainingExpirationTime: NoWork, - firstBatch: null, - nextScheduledRoot: null + // 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") { + pendingComponentWillUpdateWarnings.push(fiber); + } }; - uninitializedFiber.stateNode = root; - return root; -} -var onCommitFiberRoot = null; -var onCommitFiberUnmount = null; -var hasLoggedError = false; + ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function( + fiber, + instance + ) { + var strictRoot = getStrictRoot(fiber); -function catchErrors(fn) { - return function(arg) { - try { - return fn(arg); - } catch (err) { - if (true && !hasLoggedError) { - hasLoggedError = true; - warning(false, "React DevTools encountered an error: %s", err); - } + // 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; } - }; -} -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) { - { - warning( - 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" - ); + // Don't warn about react-lifecycles-compat polyfilled components. + // Note that it is sufficient to check for the presence of a + // single lifecycle, componentWillMount, with the polyfill flag. + if ( + typeof instance.componentWillMount === "function" && + instance.componentWillMount.__suppressDeprecationWarning === true + ) { + 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" || + typeof instance.UNSAFE_componentWillMount === "function" + ) { + unsafeLifecycles.push("UNSAFE_componentWillMount"); + } + if ( + typeof instance.componentWillReceiveProps === "function" || + typeof instance.UNSAFE_componentWillReceiveProps === "function" + ) { + unsafeLifecycles.push("UNSAFE_componentWillReceiveProps"); + } + if ( + typeof instance.componentWillUpdate === "function" || + typeof instance.UNSAFE_componentWillUpdate === "function" + ) { + unsafeLifecycles.push("UNSAFE_componentWillUpdate"); } - // 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. - { - warning(false, "React DevTools encountered an error: %s.", err); + + if (unsafeLifecycles.length > 0) { + unsafeLifecycles.forEach(function(lifecycle) { + warningsForRoot[lifecycle].push(fiber); + }); } - } - // DevTools exists - return true; + }; } -function onCommitRoot(root) { - if (typeof onCommitFiberRoot === "function") { - onCommitFiberRoot(root); +var debugRenderPhaseSideEffects = false; +var debugRenderPhaseSideEffectsForStrictMode = false; + +var enableUserTimingAPI = true; +var enableGetDerivedStateFromCatch = false; +var warnAboutDeprecatedLifecycles = false; +var replayFailedUnitOfWorkWithInvokeGuardedCallback = true; + +// React Fabric uses persistent reconciler. +var enableMutatingReconciler = false; +var enableNoopReconciler = false; +var enablePersistentReconciler = true; + +// Only used in www builds. + +function getCurrentFiberOwnerName() { + { + var fiber = ReactDebugCurrentFiber.current; + if (fiber === null) { + return null; + } + var owner = fiber._debugOwner; + if (owner !== null && typeof owner !== "undefined") { + return getComponentName(owner); + } } + return null; } -function onCommitUnmount(fiber) { - if (typeof onCommitFiberUnmount === "function") { - onCommitFiberUnmount(fiber); +function getCurrentFiberStackAddendum() { + { + var fiber = ReactDebugCurrentFiber.current; + if (fiber === null) { + return null; + } + // Safe because if current fiber exists, we are reconciling, + // and it is guaranteed to be the work-in-progress version. + return getStackAddendumByWorkInProgressFiber(fiber); } + return null; } -/** - * 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. - */ +function resetCurrentFiber() { + ReactDebugCurrentFrame.getCurrentStack = null; + ReactDebugCurrentFiber.current = null; + ReactDebugCurrentFiber.phase = null; +} -var lowPriorityWarning = function() {}; +function setCurrentFiber(fiber) { + ReactDebugCurrentFrame.getCurrentStack = getCurrentFiberStackAddendum; + ReactDebugCurrentFiber.current = fiber; + ReactDebugCurrentFiber.phase = null; +} -{ - 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]; - } +function setCurrentPhase(phase) { + ReactDebugCurrentFiber.phase = phase; +} - 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) {} - }; +var ReactDebugCurrentFiber = { + current: null, + phase: null, + resetCurrentFiber: resetCurrentFiber, + setCurrentFiber: setCurrentFiber, + setCurrentPhase: setCurrentPhase, + getCurrentFiberOwnerName: getCurrentFiberOwnerName, + getCurrentFiberStackAddendum: getCurrentFiberStackAddendum +}; - lowPriorityWarning = function(condition, format) { - if (format === undefined) { - throw new Error( - "`warning(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]; - } +// 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"; - printWarning.apply(undefined, [format].concat(args)); - } - }; -} +// 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 lowPriorityWarning$1 = lowPriorityWarning; +var formatMarkName = function(markName) { + return reactEmoji + " " + markName; +}; -var ReactStrictModeWarnings = { - discardPendingWarnings: function() {}, - flushPendingDeprecationWarnings: function() {}, - flushPendingUnsafeLifecycleWarnings: function() {}, - recordDeprecationWarnings: function(fiber, instance) {}, - recordUnsafeLifecycleWarnings: function(fiber, instance) {} +var formatLabel = function(label, warning$$1) { + var prefix = warning$$1 ? warningEmoji + " " : reactEmoji + " "; + var suffix = warning$$1 ? " Warning: " + warning$$1 : ""; + return "" + prefix + label + suffix; }; -{ - var LIFECYCLE_SUGGESTIONS = { - UNSAFE_componentWillMount: "componentDidMount", - UNSAFE_componentWillReceiveProps: "static getDerivedStateFromProps", - UNSAFE_componentWillUpdate: "componentDidUpdate" - }; +var beginMark = function(markName) { + performance.mark(formatMarkName(markName)); +}; - var pendingComponentWillMountWarnings = []; - var pendingComponentWillReceivePropsWarnings = []; - var pendingComponentWillUpdateWarnings = []; - var pendingUnsafeLifecycleWarnings = new Map(); +var clearMark = function(markName) { + performance.clearMarks(formatMarkName(markName)); +}; - // Tracks components we have already warned about. - var didWarnAboutDeprecatedLifecycles = new Set(); - var didWarnAboutUnsafeLifecycles = new Set(); +var endMark = function(label, markName, warning$$1) { + var formattedMarkName = formatMarkName(markName); + var formattedLabel = formatLabel(label, warning$$1); + 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. - ReactStrictModeWarnings.discardPendingWarnings = function() { - pendingComponentWillMountWarnings = []; - pendingComponentWillReceivePropsWarnings = []; - pendingComponentWillUpdateWarnings = []; - pendingUnsafeLifecycleWarnings = new Map(); - }; + // Clear marks immediately to avoid growing buffer. + performance.clearMarks(formattedMarkName); + performance.clearMeasures(formattedLabel); +}; - ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = function() { - pendingUnsafeLifecycleWarnings.forEach(function( - lifecycleWarningsMap, - strictRoot - ) { - var lifecyclesWarningMesages = []; +var getFiberMarkName = function(label, debugID) { + return label + " (#" + debugID + ")"; +}; - 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) || "Component"); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); +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 formatted = lifecycle.replace("UNSAFE_", ""); - var suggestion = LIFECYCLE_SUGGESTIONS[lifecycle]; - var sortedComponentNames = Array.from(componentNames) - .sort() - .join(", "); +var beginFiberMark = function(fiber, phase) { + var componentName = getComponentName(fiber) || "Unknown"; + var debugID = fiber._debugID; + var isMounted = fiber.alternate !== null; + var label = getFiberLabel(componentName, isMounted, phase); - lifecyclesWarningMesages.push( - formatted + - ": Please update the following components to use " + - (suggestion + " instead: " + sortedComponentNames) - ); - } - }); + 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); - if (lifecyclesWarningMesages.length > 0) { - var strictRootComponentStack = getStackAddendumByWorkInProgressFiber( - strictRoot - ); + var markName = getFiberMarkName(label, debugID); + beginMark(markName); + return true; +}; - warning( - 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, - lifecyclesWarningMesages.join("\n\n") - ); - } - }); +var clearFiberMark = function(fiber, phase) { + var componentName = getComponentName(fiber) || "Unknown"; + var debugID = fiber._debugID; + var isMounted = fiber.alternate !== null; + var label = getFiberLabel(componentName, isMounted, phase); + var markName = getFiberMarkName(label, debugID); + clearMark(markName); +}; - pendingUnsafeLifecycleWarnings = new Map(); - }; +var endFiberMark = function(fiber, phase, warning$$1) { + var componentName = getComponentName(fiber) || "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$$1); +}; - var getStrictRoot = function(fiber) { - var maybeStrictRoot = null; +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 CallComponent: + case ReturnComponent: + case Fragment: + case ContextProvider: + case ContextConsumer: + return true; + default: + return false; + } +}; - while (fiber !== null) { - if (fiber.mode & StrictMode) { - maybeStrictRoot = fiber; - } +var clearPendingPhaseMeasurement = function() { + if (currentPhase !== null && currentPhaseFiber !== null) { + clearFiberMark(currentPhaseFiber, currentPhase); + } + currentPhaseFiber = null; + currentPhase = null; + hasScheduledUpdateInCurrentPhase = false; +}; - fiber = fiber["return"]; +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"]; + } +}; - return maybeStrictRoot; - }; - - ReactStrictModeWarnings.flushPendingDeprecationWarnings = function() { - if (pendingComponentWillMountWarnings.length > 0) { - var uniqueNames = new Set(); - pendingComponentWillMountWarnings.forEach(function(fiber) { - uniqueNames.add(getComponentName(fiber) || "Component"); - didWarnAboutDeprecatedLifecycles.add(fiber.type); - }); +var resumeTimersRecursively = function(fiber) { + if (fiber["return"] !== null) { + resumeTimersRecursively(fiber["return"]); + } + if (fiber._debugIsCurrentlyTiming) { + beginFiberMark(fiber, null); + } +}; - var sortedNames = Array.from(uniqueNames) - .sort() - .join(", "); +var resumeTimers = function() { + // Resumes all measurements that were active during the last deferred loop. + if (currentFiber !== null) { + resumeTimersRecursively(currentFiber); + } +}; - 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 - ); +function recordEffect() { + if (enableUserTimingAPI) { + effectCountInCurrentCommit++; + } +} - pendingComponentWillMountWarnings = []; +function recordScheduleUpdate() { + if (enableUserTimingAPI) { + if (isCommitting) { + hasScheduledUpdateInCurrentCommit = true; } + if ( + currentPhase !== null && + currentPhase !== "componentWillMount" && + currentPhase !== "componentWillReceiveProps" + ) { + hasScheduledUpdateInCurrentPhase = true; + } + } +} - if (pendingComponentWillReceivePropsWarnings.length > 0) { - var _uniqueNames = new Set(); - pendingComponentWillReceivePropsWarnings.forEach(function(fiber) { - _uniqueNames.add(getComponentName(fiber) || "Component"); - didWarnAboutDeprecatedLifecycles.add(fiber.type); - }); - - var _sortedNames = Array.from(_uniqueNames) - .sort() - .join(", "); +function startRequestCallbackTimer() { + if (enableUserTimingAPI) { + if (supportsUserTiming && !isWaitingForCallback) { + isWaitingForCallback = true; + beginMark("(Waiting for async callback...)"); + } + } +} - 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 +function stopRequestCallbackTimer(didExpire) { + if (enableUserTimingAPI) { + if (supportsUserTiming) { + isWaitingForCallback = false; + var warning$$1 = didExpire ? "React was blocked by main thread" : null; + endMark( + "(Waiting for async callback...)", + "(Waiting for async callback...)", + warning$$1 ); - - pendingComponentWillReceivePropsWarnings = []; } + } +} - if (pendingComponentWillUpdateWarnings.length > 0) { - var _uniqueNames2 = new Set(); - pendingComponentWillUpdateWarnings.forEach(function(fiber) { - _uniqueNames2.add(getComponentName(fiber) || "Component"); - didWarnAboutDeprecatedLifecycles.add(fiber.type); - }); - - var _sortedNames2 = Array.from(_uniqueNames2) - .sort() - .join(", "); +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; + } +} - 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 - ); +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); + } +} - pendingComponentWillUpdateWarnings = []; +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); + } +} - ReactStrictModeWarnings.recordDeprecationWarnings = function( - fiber, - instance - ) { - // Dedup strategy: Warn once per component. - if (didWarnAboutDeprecatedLifecycles.has(fiber.type)) { +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$$1 = "An error was thrown inside this error boundary"; + endFiberMark(fiber, null, warning$$1); + } +} - // Don't warn about react-lifecycles-compat polyfilled components. - if ( - typeof instance.componentWillMount === "function" && - instance.componentWillMount.__suppressDeprecationWarning !== true - ) { - pendingComponentWillMountWarnings.push(fiber); +function startPhaseTimer(fiber, phase) { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; } - if ( - typeof instance.componentWillReceiveProps === "function" && - instance.componentWillReceiveProps.__suppressDeprecationWarning !== true - ) { - pendingComponentWillReceivePropsWarnings.push(fiber); + clearPendingPhaseMeasurement(); + if (!beginFiberMark(fiber, phase)) { + return; } - if (typeof instance.componentWillUpdate === "function") { - pendingComponentWillUpdateWarnings.push(fiber); + currentPhaseFiber = fiber; + currentPhase = phase; + } +} + +function stopPhaseTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; } - }; + if (currentPhase !== null && currentPhaseFiber !== null) { + var warning$$1 = hasScheduledUpdateInCurrentPhase + ? "Scheduled a cascading update" + : null; + endFiberMark(currentPhaseFiber, currentPhase, warning$$1); + } + currentPhase = null; + currentPhaseFiber = null; + } +} - ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function( - fiber, - instance - ) { - var strictRoot = getStrictRoot(fiber); +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(); + } +} - // 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)) { +function stopWorkLoopTimer(interruptedBy) { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { return; } + var warning$$1 = null; + if (interruptedBy !== null) { + if (interruptedBy.tag === HostRoot) { + warning$$1 = "A top-level update interrupted the previous render"; + } else { + var componentName = getComponentName(interruptedBy) || "Unknown"; + warning$$1 = + "An update to " + componentName + " interrupted the previous render"; + } + } else if (commitCountInCurrentWorkLoop > 1) { + warning$$1 = "There were cascading updates"; + } + commitCountInCurrentWorkLoop = 0; + // Pause any measurements until the next loop. + pauseTimers(); + endMark( + "(React Tree Reconciliation)", + "(React Tree Reconciliation)", + warning$$1 + ); + } +} - // Don't warn about react-lifecycles-compat polyfilled components. - // Note that it is sufficient to check for the presence of a - // single lifecycle, componentWillMount, with the polyfill flag. - if ( - typeof instance.componentWillMount === "function" && - instance.componentWillMount.__suppressDeprecationWarning === true - ) { +function startCommitTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { return; } + isCommitting = true; + hasScheduledUpdateInCurrentCommit = false; + labelsInCurrentCommit.clear(); + beginMark("(Committing Changes)"); + } +} - var warningsForRoot = void 0; - if (!pendingUnsafeLifecycleWarnings.has(strictRoot)) { - warningsForRoot = { - UNSAFE_componentWillMount: [], - UNSAFE_componentWillReceiveProps: [], - UNSAFE_componentWillUpdate: [] - }; +function stopCommitTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } - pendingUnsafeLifecycleWarnings.set(strictRoot, warningsForRoot); - } else { - warningsForRoot = pendingUnsafeLifecycleWarnings.get(strictRoot); + var warning$$1 = null; + if (hasScheduledUpdateInCurrentCommit) { + warning$$1 = "Lifecycle hook scheduled a cascading update"; + } else if (commitCountInCurrentWorkLoop > 0) { + warning$$1 = "Caused by a cascading update in earlier commit"; } + hasScheduledUpdateInCurrentCommit = false; + commitCountInCurrentWorkLoop++; + isCommitting = false; + labelsInCurrentCommit.clear(); - var unsafeLifecycles = []; - if ( - typeof instance.componentWillMount === "function" || - typeof instance.UNSAFE_componentWillMount === "function" - ) { - unsafeLifecycles.push("UNSAFE_componentWillMount"); + endMark("(Committing Changes)", "(Committing Changes)", warning$$1); + } +} + +function startCommitHostEffectsTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; } - if ( - typeof instance.componentWillReceiveProps === "function" || - typeof instance.UNSAFE_componentWillReceiveProps === "function" - ) { - unsafeLifecycles.push("UNSAFE_componentWillReceiveProps"); + effectCountInCurrentCommit = 0; + beginMark("(Committing Host Effects)"); + } +} + +function stopCommitHostEffectsTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; } - if ( - typeof instance.componentWillUpdate === "function" || - typeof instance.UNSAFE_componentWillUpdate === "function" - ) { - unsafeLifecycles.push("UNSAFE_componentWillUpdate"); + 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)"); + } +} - if (unsafeLifecycles.length > 0) { - unsafeLifecycles.forEach(function(lifecycle) { - warningsForRoot[lifecycle].push(fiber); - }); +function stopCommitLifeCyclesTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; } - }; + var count = effectCountInCurrentCommit; + effectCountInCurrentCommit = 0; + endMark( + "(Calling Lifecycle Methods: " + count + " Total)", + "(Calling Lifecycle Methods)", + null + ); + } } var didWarnUpdateInsideUpdate = void 0; @@ -6172,12 +5847,20 @@ function callGetDerivedStateFromCatch(ctor, capturedValues) { } var ReactFiberClassComponent = function( + legacyContext, scheduleWork, computeExpirationForFiber, memoizeProps, memoizeState ) { + var cacheContext = legacyContext.cacheContext, + getMaskedContext = legacyContext.getMaskedContext, + getUnmaskedContext = legacyContext.getUnmaskedContext, + isContextConsumer = legacyContext.isContextConsumer, + hasContextChanged = legacyContext.hasContextChanged; + // Class component state updater + var updater = { isMounted: isMounted, enqueueSetState: function(instance, partialState, callback) { @@ -8310,84 +7993,19 @@ function cloneChildFibers(current, workInProgress) { 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 changedBitsStack = []; -var currentValueStack = []; -var stack = []; -var index$1 = -1; - -var rendererSigil = void 0; -{ - // Use this to detect multiple renderers using the same context - rendererSigil = {}; -} - -function pushProvider(providerFiber) { - var context = providerFiber.type.context; - index$1 += 1; - changedBitsStack[index$1] = context._changedBits; - currentValueStack[index$1] = context._currentValue; - stack[index$1] = providerFiber; - context._currentValue = providerFiber.pendingProps.value; - context._changedBits = providerFiber.stateNode; - - { - warning( - context._currentRenderer === null || - context._currentRenderer === rendererSigil, - "Detected multiple renderers concurrently rendering the " + - "same context provider. This is currently unsupported." - ); - context._currentRenderer = rendererSigil; - } -} - -function popProvider(providerFiber) { - { - warning( - index$1 > -1 && providerFiber === stack[index$1], - "Unexpected pop." - ); - } - var changedBits = changedBitsStack[index$1]; - var currentValue = currentValueStack[index$1]; - changedBitsStack[index$1] = null; - currentValueStack[index$1] = null; - stack[index$1] = null; - index$1 -= 1; - var context = providerFiber.type.context; - context._currentValue = currentValue; - context._changedBits = changedBits; -} + workInProgress.child = newChild; -function resetProviderStack() { - for (var i = index$1; i > -1; i--) { - var providerFiber = stack[i]; - var context = providerFiber.type.context; - context._currentValue = context._defaultValue; - context._changedBits = 0; - changedBitsStack[i] = null; - currentValueStack[i] = null; - stack[i] = null; - { - context._currentRenderer = null; - } + newChild["return"] = workInProgress; + while (currentChild.sibling !== null) { + currentChild = currentChild.sibling; + newChild = newChild.sibling = createWorkInProgress( + currentChild, + currentChild.pendingProps, + currentChild.expirationTime + ); + newChild["return"] = workInProgress; } - index$1 = -1; + newChild.sibling = null; } var didWarnAboutBadClass = void 0; @@ -8403,6 +8021,8 @@ var didWarnAboutStatelessRefs = void 0; var ReactFiberBeginWork = function( config, hostContext, + legacyContext, + newContext, hydrationContext, scheduleWork, computeExpirationForFiber @@ -8411,12 +8031,20 @@ var ReactFiberBeginWork = function( shouldDeprioritizeSubtree = config.shouldDeprioritizeSubtree; var pushHostContext = hostContext.pushHostContext, pushHostContainer = hostContext.pushHostContainer; + var pushProvider = newContext.pushProvider; + var getMaskedContext = legacyContext.getMaskedContext, + getUnmaskedContext = legacyContext.getUnmaskedContext, + hasLegacyContextChanged = legacyContext.hasContextChanged, + pushLegacyContextProvider = legacyContext.pushContextProvider, + pushTopLevelContextObject = legacyContext.pushTopLevelContextObject, + invalidateContextProvider = legacyContext.invalidateContextProvider; var enterHydrationState = hydrationContext.enterHydrationState, resetHydrationState = hydrationContext.resetHydrationState, tryToClaimNextHydratableInstance = hydrationContext.tryToClaimNextHydratableInstance; var _ReactFiberClassCompo = ReactFiberClassComponent( + legacyContext, scheduleWork, computeExpirationForFiber, memoizeProps, @@ -8484,7 +8112,7 @@ var ReactFiberBeginWork = function( function updateFragment(current, workInProgress) { var nextChildren = workInProgress.pendingProps; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // Normally we can bail out on props equality but if context has changed // we don't do the bailout and we have to reuse existing props instead. } else if (workInProgress.memoizedProps === nextChildren) { @@ -8497,7 +8125,7 @@ var ReactFiberBeginWork = function( function updateMode(current, workInProgress) { var nextChildren = workInProgress.pendingProps.children; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // Normally we can bail out on props equality but if context has changed // we don't do the bailout and we have to reuse existing props instead. } else if ( @@ -8526,7 +8154,7 @@ var ReactFiberBeginWork = function( var fn = workInProgress.type; var nextProps = workInProgress.pendingProps; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // Normally we can bail out on props equality but if context has changed // we don't do the bailout and we have to reuse existing props instead. } else { @@ -8559,7 +8187,7 @@ var ReactFiberBeginWork = function( // 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 = pushContextProvider(workInProgress); + var hasContext = pushLegacyContextProvider(workInProgress); var shouldUpdate = void 0; if (current === null) { if (workInProgress.stateNode === null) { @@ -8784,7 +8412,7 @@ var ReactFiberBeginWork = function( var nextProps = workInProgress.pendingProps; var prevProps = current !== null ? current.memoizedProps : null; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // Normally we can bail out on props equality but if context has changed // we don't do the bailout and we have to reuse existing props instead. } else if (memoizedProps === nextProps) { @@ -8919,7 +8547,7 @@ var ReactFiberBeginWork = function( // 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 = pushContextProvider(workInProgress); + var hasContext = pushLegacyContextProvider(workInProgress); adoptClassInstance(workInProgress, value); mountClassInstance(workInProgress, renderExpirationTime); return finishClassComponent( @@ -8992,7 +8620,7 @@ var ReactFiberBeginWork = function( function updateCallComponent(current, workInProgress, renderExpirationTime) { var nextProps = workInProgress.pendingProps; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // Normally we can bail out on props equality but if context has changed // we don't do the bailout and we have to reuse existing props instead. } else if (workInProgress.memoizedProps === nextProps) { @@ -9035,7 +8663,7 @@ var ReactFiberBeginWork = function( ) { pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); var nextChildren = workInProgress.pendingProps; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // Normally we can bail out on props equality but if context has changed // we don't do the bailout and we have to reuse existing props instead. } else if (workInProgress.memoizedProps === nextChildren) { @@ -9069,6 +8697,10 @@ var ReactFiberBeginWork = function( 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. @@ -9161,7 +8793,7 @@ var ReactFiberBeginWork = function( var newProps = workInProgress.pendingProps; var oldProps = workInProgress.memoizedProps; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // Normally we can bail out on props equality but if context has changed // we don't do the bailout and we have to reuse existing props instead. } else if (oldProps === newProps) { @@ -9257,7 +8889,7 @@ var ReactFiberBeginWork = function( var newValue = context._currentValue; var changedBits = context._changedBits; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // Normally we can bail out on props equality but if context has changed // we don't do the bailout and we have to reuse existing props instead. } else if (changedBits === 0 && oldProps === newProps) { @@ -9354,7 +8986,7 @@ var ReactFiberBeginWork = function( pushHostRootContext(workInProgress); break; case ClassComponent: - pushContextProvider(workInProgress); + pushLegacyContextProvider(workInProgress); break; case HostPortal: pushHostContainer( @@ -9467,7 +9099,13 @@ var ReactFiberBeginWork = function( }; }; -var ReactFiberCompleteWork = function(config, hostContext, hydrationContext) { +var ReactFiberCompleteWork = function( + config, + hostContext, + legacyContext, + newContext, + hydrationContext +) { var createInstance = config.createInstance, createTextInstance = config.createTextInstance, appendInitialChild = config.appendInitialChild, @@ -9479,6 +9117,9 @@ var ReactFiberCompleteWork = function(config, hostContext, hydrationContext) { popHostContext = hostContext.popHostContext, getHostContext = hostContext.getHostContext, popHostContainer = hostContext.popHostContainer; + var popLegacyContextProvider = legacyContext.popContextProvider, + popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject; + var popProvider = newContext.popProvider; var prepareToHydrateHostInstance = hydrationContext.prepareToHydrateHostInstance, prepareToHydrateHostTextInstance = @@ -9794,7 +9435,7 @@ var ReactFiberCompleteWork = function(config, hostContext, hydrationContext) { return null; case ClassComponent: { // We are leaving this subtree, so pop context if any. - popContextProvider(workInProgress); + popLegacyContextProvider(workInProgress); // If this component caught an error, schedule an error log effect. var instance = workInProgress.stateNode; @@ -9813,7 +9454,7 @@ var ReactFiberCompleteWork = function(config, hostContext, hydrationContext) { } case HostRoot: { popHostContainer(workInProgress); - popTopLevelContextObject(workInProgress); + popTopLevelLegacyContextObject(workInProgress); var fiberRoot = workInProgress.stateNode; if (fiberRoot.pendingContext) { fiberRoot.context = fiberRoot.pendingContext; @@ -10040,11 +9681,16 @@ function createCapturedValue(value, source) { var ReactFiberUnwindWork = function( hostContext, + legacyContext, + newContext, scheduleWork, isAlreadyFailedLegacyErrorBoundary ) { var popHostContainer = hostContext.popHostContainer, popHostContext = hostContext.popHostContext; + var popLegacyContextProvider = legacyContext.popContextProvider, + popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject; + var popProvider = newContext.popProvider; function throwException(returnFiber, sourceFiber, rawValue) { // The source fiber did not complete. @@ -10100,7 +9746,7 @@ var ReactFiberUnwindWork = function( function unwindWork(workInProgress) { switch (workInProgress.tag) { case ClassComponent: { - popContextProvider(workInProgress); + popLegacyContextProvider(workInProgress); var effectTag = workInProgress.effectTag; if (effectTag & ShouldCapture) { workInProgress.effectTag = (effectTag & ~ShouldCapture) | DidCapture; @@ -10110,7 +9756,7 @@ var ReactFiberUnwindWork = function( } case HostRoot: { popHostContainer(workInProgress); - popTopLevelContextObject(workInProgress); + popTopLevelLegacyContextObject(workInProgress); var _effectTag = workInProgress.effectTag; if (_effectTag & ShouldCapture) { workInProgress.effectTag = (_effectTag & ~ShouldCapture) | DidCapture; @@ -10132,9 +9778,37 @@ var ReactFiberUnwindWork = function( return null; } } + + function unwindInterruptedWork(interruptedWork) { + switch (interruptedWork.tag) { + case ClassComponent: { + popLegacyContextProvider(interruptedWork); + break; + } + case HostRoot: { + popHostContainer(interruptedWork); + popTopLevelLegacyContextObject(interruptedWork); + break; + } + case HostComponent: { + popHostContext(interruptedWork); + break; + } + case HostPortal: + popHostContainer(interruptedWork); + break; + case ContextProvider: + popProvider(interruptedWork); + break; + default: + break; + } + } + return { throwException: throwException, - unwindWork: unwindWork + unwindWork: unwindWork, + unwindInterruptedWork: unwindInterruptedWork }; }; @@ -10466,7 +10140,7 @@ var ReactFiberCommitWork = function( warning( false, "Unexpected ref object provided for %s. " + - "Use either a ref-setter function or Reacte.createRef().%s", + "Use either a ref-setter function or React.createRef().%s", getComponentName(finishedWork), getStackAddendumByWorkInProgressFiber(finishedWork) ); @@ -10972,9 +10646,12 @@ var ReactFiberCommitWork = function( var NO_CONTEXT = {}; -var ReactFiberHostContext = function(config) { +var ReactFiberHostContext = function(config, stack) { var getChildHostContext = config.getChildHostContext, getRootHostContext = config.getRootHostContext; + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop; var contextStackCursor = createCursor(NO_CONTEXT); var contextFiberStackCursor = createCursor(NO_CONTEXT); @@ -11045,19 +10722,13 @@ var ReactFiberHostContext = function(config) { pop(contextFiberStackCursor, fiber); } - function resetHostContainer() { - contextStackCursor.current = NO_CONTEXT; - rootInstanceStackCursor.current = NO_CONTEXT; - } - return { getHostContext: getHostContext, getRootHostContainer: getRootHostContainer, popHostContainer: popHostContainer, popHostContext: popHostContext, pushHostContainer: pushHostContainer, - pushHostContext: pushHostContext, - resetHostContainer: resetHostContainer + pushHostContext: pushHostContext }; }; @@ -11427,6 +11098,425 @@ var ReactFiberInstrumentation = { var ReactFiberInstrumentation_1 = ReactFiberInstrumentation; +var warnedAboutMissingGetChildContext = void 0; + +{ + warnedAboutMissingGetChildContext = {}; +} + +var ReactFiberLegacyContext = function(stack) { + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop; + + // A cursor to the current merged context object on the stack. + + var contextStackCursor = createCursor(emptyObject); + // 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 = emptyObject; + + function getUnmaskedContext(workInProgress) { + var hasOwnContext = isContextProvider(workInProgress); + if (hasOwnContext) { + // If the fiber is a context provider itself, when we read its context + // we 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 emptyObject; + } + + // 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(workInProgress) || "Unknown"; + checkPropTypes( + contextTypes, + context, + "context", + name, + ReactDebugCurrentFiber.getCurrentFiberStackAddendum + ); + } + + // 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 isContextConsumer(fiber) { + return fiber.tag === ClassComponent && fiber.type.contextTypes != null; + } + + function isContextProvider(fiber) { + return fiber.tag === ClassComponent && fiber.type.childContextTypes != null; + } + + function popContextProvider(fiber) { + if (!isContextProvider(fiber)) { + return; + } + + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); + } + + function popTopLevelContextObject(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); + } + + function pushTopLevelContextObject(fiber, context, didChange) { + invariant( + contextStackCursor.cursor == null, + "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, parentContext) { + var instance = fiber.stateNode; + var childContextTypes = fiber.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(fiber) || "Unknown"; + + if (!warnedAboutMissingGetChildContext[componentName]) { + warnedAboutMissingGetChildContext[componentName] = true; + warning( + 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; + { + ReactDebugCurrentFiber.setCurrentPhase("getChildContext"); + } + startPhaseTimer(fiber, "getChildContext"); + childContext = instance.getChildContext(); + stopPhaseTimer(); + { + ReactDebugCurrentFiber.setCurrentPhase(null); + } + for (var contextKey in childContext) { + invariant( + contextKey in childContextTypes, + '%s.getChildContext(): key "%s" is not defined in childContextTypes.', + getComponentName(fiber) || "Unknown", + contextKey + ); + } + { + var name = getComponentName(fiber) || "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. + ReactDebugCurrentFiber.getCurrentFiberStackAddendum + ); + } + + return Object.assign({}, parentContext, childContext); + } + + function pushContextProvider(workInProgress) { + if (!isContextProvider(workInProgress)) { + return false; + } + + 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) || + emptyObject; + + // 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, didChange) { + var instance = workInProgress.stateNode; + invariant( + instance, + "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, 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 + invariant( + isFiberMounted(fiber) && fiber.tag === ClassComponent, + "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; + while (node.tag !== HostRoot) { + if (isContextProvider(node)) { + return node.stateNode.__reactInternalMemoizedMergedChildContext; + } + var parent = node["return"]; + invariant( + parent, + "Found unexpected detached subtree parent. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + node = parent; + } + return node.stateNode.context; + } + + return { + getUnmaskedContext: getUnmaskedContext, + cacheContext: cacheContext, + getMaskedContext: getMaskedContext, + hasContextChanged: hasContextChanged, + isContextConsumer: isContextConsumer, + isContextProvider: isContextProvider, + popContextProvider: popContextProvider, + popTopLevelContextObject: popTopLevelContextObject, + pushTopLevelContextObject: pushTopLevelContextObject, + processChildContext: processChildContext, + pushContextProvider: pushContextProvider, + invalidateContextProvider: invalidateContextProvider, + findCurrentUnmaskedContext: findCurrentUnmaskedContext + }; +}; + +var ReactFiberNewContext = function(stack) { + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop; + + var providerCursor = createCursor(null); + var valueCursor = createCursor(null); + var changedBitsCursor = createCursor(0); + + var rendererSigil = void 0; + { + // Use this to detect multiple renderers using the same context + rendererSigil = {}; + } + + function pushProvider(providerFiber) { + var context = providerFiber.type.context; + + push(changedBitsCursor, context._changedBits, providerFiber); + push(valueCursor, context._currentValue, providerFiber); + push(providerCursor, providerFiber, providerFiber); + + context._currentValue = providerFiber.pendingProps.value; + context._changedBits = providerFiber.stateNode; + + { + warning( + context._currentRenderer === null || + context._currentRenderer === rendererSigil, + "Detected multiple renderers concurrently rendering the " + + "same context provider. This is currently unsupported." + ); + context._currentRenderer = rendererSigil; + } + } + + function popProvider(providerFiber) { + var changedBits = changedBitsCursor.current; + var currentValue = valueCursor.current; + + pop(providerCursor, providerFiber); + pop(valueCursor, providerFiber); + pop(changedBitsCursor, providerFiber); + + var context = providerFiber.type.context; + context._currentValue = currentValue; + context._changedBits = changedBits; + } + + return { + pushProvider: pushProvider, + popProvider: popProvider + }; +}; + +var ReactFiberStack = function() { + var valueStack = []; + + var fiberStack = void 0; + + { + fiberStack = []; + } + + var index = -1; + + function createCursor(defaultValue) { + return { + current: defaultValue + }; + } + + function isEmpty() { + return index === -1; + } + + function pop(cursor, fiber) { + if (index < 0) { + { + warning(false, "Unexpected pop."); + } + return; + } + + { + if (fiber !== fiberStack[index]) { + warning(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; + } + + function checkThatStackIsEmpty() { + { + if (index !== -1) { + warning( + false, + "Expected an empty stack. Something was not reset properly." + ); + } + } + } + + function resetStackAfterFatalErrorInDev() { + { + index = -1; + valueStack.length = 0; + fiberStack.length = 0; + } + } + + return { + createCursor: createCursor, + isEmpty: isEmpty, + pop: pop, + push: push, + checkThatStackIsEmpty: checkThatStackIsEmpty, + resetStackAfterFatalErrorInDev: resetStackAfterFatalErrorInDev + }; +}; + var invokeGuardedCallback$2 = ReactErrorUtils.invokeGuardedCallback; var hasCaughtError = ReactErrorUtils.hasCaughtError; var clearCaughtError = ReactErrorUtils.clearCaughtError; @@ -11487,16 +11577,23 @@ var warnAboutInvalidUpdates = void 0; } var ReactFiberScheduler = function(config) { - var hostContext = ReactFiberHostContext(config); + var stack = ReactFiberStack(); + var hostContext = ReactFiberHostContext(config, stack); + var legacyContext = ReactFiberLegacyContext(stack); + var newContext = ReactFiberNewContext(stack); var popHostContext = hostContext.popHostContext, popHostContainer = hostContext.popHostContainer; + var popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject, + popLegacyContextProvider = legacyContext.popContextProvider; + var popProvider = newContext.popProvider; var hydrationContext = ReactFiberHydrationContext(config); - var resetHostContainer = hostContext.resetHostContainer; var _ReactFiberBeginWork = ReactFiberBeginWork( config, hostContext, + legacyContext, + newContext, hydrationContext, scheduleWork, computeExpirationForFiber @@ -11506,17 +11603,22 @@ var ReactFiberScheduler = function(config) { var _ReactFiberCompleteWo = ReactFiberCompleteWork( config, hostContext, + legacyContext, + newContext, hydrationContext ), completeWork = _ReactFiberCompleteWo.completeWork; var _ReactFiberUnwindWork = ReactFiberUnwindWork( hostContext, + legacyContext, + newContext, scheduleWork, isAlreadyFailedLegacyErrorBoundary ), throwException = _ReactFiberUnwindWork.throwException, - unwindWork = _ReactFiberUnwindWork.unwindWork; + unwindWork = _ReactFiberUnwindWork.unwindWork, + unwindInterruptedWork = _ReactFiberUnwindWork.unwindInterruptedWork; var _ReactFiberCommitWork = ReactFiberCommitWork( config, @@ -11585,13 +11687,13 @@ var ReactFiberScheduler = function(config) { switch (failedUnitOfWork.tag) { case HostRoot: popHostContainer(failedUnitOfWork); - popTopLevelContextObject(failedUnitOfWork); + popTopLevelLegacyContextObject(failedUnitOfWork); break; case HostComponent: popHostContext(failedUnitOfWork); break; case ClassComponent: - popContextProvider(failedUnitOfWork); + popLegacyContextProvider(failedUnitOfWork); break; case HostPortal: popHostContainer(failedUnitOfWork); @@ -11611,18 +11713,18 @@ var ReactFiberScheduler = function(config) { }; } - function resetContextStack() { - // Reset the stack - reset(); - // Reset the cursors - resetContext(); - resetHostContainer(); - - // TODO: Unify new context implementation with other stacks - resetProviderStack(); + function resetStack() { + if (nextUnitOfWork !== null) { + var interruptedWork = nextUnitOfWork["return"]; + while (interruptedWork !== null) { + unwindInterruptedWork(interruptedWork); + interruptedWork = interruptedWork["return"]; + } + } { ReactStrictModeWarnings.discardPendingWarnings(); + stack.checkThatStackIsEmpty(); } nextRoot = null; @@ -12146,7 +12248,7 @@ var ReactFiberScheduler = function(config) { nextUnitOfWork === null ) { // Reset the stack and start working from the root. - resetContextStack(); + resetStack(); nextRoot = root; nextRenderExpirationTime = expirationTime; nextUnitOfWork = createWorkInProgress( @@ -12199,6 +12301,9 @@ var ReactFiberScheduler = function(config) { // Yield back to main thread. if (didFatal) { // There was a fatal error. + { + stack.resetStackAfterFatalErrorInDev(); + } return null; } else if (nextUnitOfWork === null) { // We reached the root. @@ -12399,7 +12504,7 @@ var ReactFiberScheduler = function(config) { ) { // This is an interruption. (Used for performance tracking.) interruptedBy = fiber; - resetContextStack(); + resetStack(); } if (nextRoot !== root || !isWorking) { requestWork(root, expirationTime); @@ -12970,7 +13075,8 @@ var ReactFiberScheduler = function(config) { syncUpdates: syncUpdates, interactiveUpdates: interactiveUpdates, flushInteractiveUpdates: flushInteractiveUpdates, - computeUniqueAsyncExpiration: computeUniqueAsyncExpiration + computeUniqueAsyncExpiration: computeUniqueAsyncExpiration, + legacyContext: legacyContext }; }; @@ -12983,18 +13089,6 @@ var didWarnAboutNestedUpdates = void 0; // 0 is PROD, 1 is DEV. // Might add PROFILE later. -function getContextForSubtree(parentComponent) { - if (!parentComponent) { - return emptyObject; - } - - var fiber = get(parentComponent); - var parentContext = findCurrentUnmaskedContext(fiber); - return isContextProvider(fiber) - ? processChildContext(fiber, parentContext) - : parentContext; -} - var ReactFiberReconciler$1 = function(config) { var getPublicInstance = config.getPublicInstance; @@ -13013,7 +13107,24 @@ var ReactFiberReconciler$1 = function(config) { deferredUpdates = _ReactFiberScheduler.deferredUpdates, syncUpdates = _ReactFiberScheduler.syncUpdates, interactiveUpdates = _ReactFiberScheduler.interactiveUpdates, - flushInteractiveUpdates = _ReactFiberScheduler.flushInteractiveUpdates; + flushInteractiveUpdates = _ReactFiberScheduler.flushInteractiveUpdates, + legacyContext = _ReactFiberScheduler.legacyContext; + + var findCurrentUnmaskedContext = legacyContext.findCurrentUnmaskedContext, + isContextProvider = legacyContext.isContextProvider, + processChildContext = legacyContext.processChildContext; + + function getContextForSubtree(parentComponent) { + if (!parentComponent) { + return emptyObject; + } + + var fiber = get(parentComponent); + var parentContext = findCurrentUnmaskedContext(fiber); + return isContextProvider(fiber) + ? processChildContext(fiber, parentContext) + : parentContext; + } function scheduleRootUpdate( current, diff --git a/Libraries/Renderer/ReactFabric-prod.js b/Libraries/Renderer/ReactFabric-prod.js index 637481f04146cb..08f112c70d4570 100644 --- a/Libraries/Renderer/ReactFabric-prod.js +++ b/Libraries/Renderer/ReactFabric-prod.js @@ -1633,136 +1633,6 @@ function findCurrentHostFiberWithNoPortals(parent) { } return null; } -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; -} -function getStackAddendumByWorkInProgressFiber(workInProgress) { - var info = ""; - do { - a: switch (workInProgress.tag) { - case 0: - case 1: - case 2: - case 5: - var owner = workInProgress._debugOwner, - source = workInProgress._debugSource; - var JSCompiler_inline_result = getComponentName(workInProgress); - var ownerName = null; - owner && (ownerName = getComponentName(owner)); - owner = source; - JSCompiler_inline_result = - "\n in " + - (JSCompiler_inline_result || "Unknown") + - (owner - ? " (at " + - owner.fileName.replace(/^.*[\\\/]/, "") + - ":" + - owner.lineNumber + - ")" - : ownerName ? " (created by " + ownerName + ")" : ""); - break a; - default: - JSCompiler_inline_result = ""; - } - info += JSCompiler_inline_result; - workInProgress = workInProgress["return"]; - } while (workInProgress); - return info; -} -new Set(); -var contextStackCursor = { current: emptyObject }, - didPerformWorkStackCursor = { current: !1 }, - previousContext = emptyObject; -function getUnmaskedContext(workInProgress) { - return isContextProvider(workInProgress) - ? previousContext - : contextStackCursor.current; -} -function getMaskedContext(workInProgress, unmaskedContext) { - var contextTypes = workInProgress.type.contextTypes; - if (!contextTypes) return emptyObject; - 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(fiber) { - return 2 === fiber.tag && null != fiber.type.childContextTypes; -} -function popContextProvider(fiber) { - isContextProvider(fiber) && - (pop(didPerformWorkStackCursor, fiber), pop(contextStackCursor, fiber)); -} -function pushTopLevelContextObject(fiber, context, didChange) { - invariant( - null == contextStackCursor.cursor, - "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, parentContext) { - var instance = fiber.stateNode, - childContextTypes = fiber.type.childContextTypes; - if ("function" !== typeof instance.getChildContext) return parentContext; - instance = instance.getChildContext(); - for (var contextKey in instance) - invariant( - contextKey in childContextTypes, - '%s.getChildContext(): key "%s" is not defined in childContextTypes.', - getComponentName(fiber) || "Unknown", - contextKey - ); - return Object.assign({}, parentContext, instance); -} -function pushContextProvider(workInProgress) { - if (!isContextProvider(workInProgress)) return !1; - var instance = workInProgress.stateNode; - instance = - (instance && instance.__reactInternalMemoizedMergedChildContext) || - emptyObject; - previousContext = contextStackCursor.current; - push(contextStackCursor, instance, workInProgress); - push( - didPerformWorkStackCursor, - didPerformWorkStackCursor.current, - workInProgress - ); - return !0; -} -function invalidateContextProvider(workInProgress, didChange) { - var instance = workInProgress.stateNode; - invariant( - instance, - "Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue." - ); - if (didChange) { - var mergedContext = processChildContext(workInProgress, previousContext); - instance.__reactInternalMemoizedMergedChildContext = mergedContext; - pop(didPerformWorkStackCursor, workInProgress); - pop(contextStackCursor, workInProgress); - push(contextStackCursor, mergedContext, workInProgress); - } else pop(didPerformWorkStackCursor, workInProgress); - push(didPerformWorkStackCursor, didChange, workInProgress); -} function FiberNode(tag, pendingProps, key, mode) { this.tag = tag; this.key = key; @@ -1929,6 +1799,40 @@ function onCommitRoot(root) { function onCommitUnmount(fiber) { "function" === typeof onCommitFiberUnmount && onCommitFiberUnmount(fiber); } +function getStackAddendumByWorkInProgressFiber(workInProgress) { + var info = ""; + do { + a: switch (workInProgress.tag) { + case 0: + case 1: + case 2: + case 5: + var owner = workInProgress._debugOwner, + source = workInProgress._debugSource; + var JSCompiler_inline_result = getComponentName(workInProgress); + var ownerName = null; + owner && (ownerName = getComponentName(owner)); + owner = source; + JSCompiler_inline_result = + "\n in " + + (JSCompiler_inline_result || "Unknown") + + (owner + ? " (at " + + owner.fileName.replace(/^.*[\\\/]/, "") + + ":" + + owner.lineNumber + + ")" + : ownerName ? " (created by " + ownerName + ")" : ""); + break a; + default: + JSCompiler_inline_result = ""; + } + info += JSCompiler_inline_result; + workInProgress = workInProgress["return"]; + } while (workInProgress); + return info; +} +new Set(); function createUpdateQueue(baseState) { return { baseState: baseState, @@ -2084,6 +1988,7 @@ function commitCallbacks(queue, context) { } } function ReactFiberClassComponent( + legacyContext, scheduleWork, computeExpirationForFiber, memoizeProps, @@ -2140,62 +2045,66 @@ function ReactFiberClassComponent( workInProgress.memoizedState ); } - var updater = { - isMounted: isMounted, - enqueueSetState: function(instance, partialState, callback) { - instance = instance._reactInternalFiber; - callback = void 0 === callback ? null : callback; - var expirationTime = computeExpirationForFiber(instance); - insertUpdateIntoFiber(instance, { - expirationTime: expirationTime, - partialState: partialState, - callback: callback, - isReplace: !1, - isForced: !1, - capturedValue: null, - next: null - }); - scheduleWork(instance, expirationTime); - }, - enqueueReplaceState: function(instance, state, callback) { - instance = instance._reactInternalFiber; - callback = void 0 === callback ? null : callback; - var expirationTime = computeExpirationForFiber(instance); - insertUpdateIntoFiber(instance, { - expirationTime: expirationTime, - partialState: state, - callback: callback, - isReplace: !0, - isForced: !1, - capturedValue: null, - next: null - }); - scheduleWork(instance, expirationTime); - }, - enqueueForceUpdate: function(instance, callback) { - instance = instance._reactInternalFiber; - callback = void 0 === callback ? null : callback; - var expirationTime = computeExpirationForFiber(instance); - insertUpdateIntoFiber(instance, { - expirationTime: expirationTime, - partialState: null, - callback: callback, - isReplace: !1, - isForced: !0, - capturedValue: null, - next: null - }); - scheduleWork(instance, expirationTime); - } - }; + var cacheContext = legacyContext.cacheContext, + getMaskedContext = legacyContext.getMaskedContext, + getUnmaskedContext = legacyContext.getUnmaskedContext, + isContextConsumer = legacyContext.isContextConsumer, + hasContextChanged = legacyContext.hasContextChanged, + updater = { + isMounted: isMounted, + enqueueSetState: function(instance, partialState, callback) { + instance = instance._reactInternalFiber; + callback = void 0 === callback ? null : callback; + var expirationTime = computeExpirationForFiber(instance); + insertUpdateIntoFiber(instance, { + expirationTime: expirationTime, + partialState: partialState, + callback: callback, + isReplace: !1, + isForced: !1, + capturedValue: null, + next: null + }); + scheduleWork(instance, expirationTime); + }, + enqueueReplaceState: function(instance, state, callback) { + instance = instance._reactInternalFiber; + callback = void 0 === callback ? null : callback; + var expirationTime = computeExpirationForFiber(instance); + insertUpdateIntoFiber(instance, { + expirationTime: expirationTime, + partialState: state, + callback: callback, + isReplace: !0, + isForced: !1, + capturedValue: null, + next: null + }); + scheduleWork(instance, expirationTime); + }, + enqueueForceUpdate: function(instance, callback) { + instance = instance._reactInternalFiber; + callback = void 0 === callback ? null : callback; + var expirationTime = computeExpirationForFiber(instance); + insertUpdateIntoFiber(instance, { + expirationTime: expirationTime, + partialState: null, + callback: callback, + isReplace: !1, + isForced: !0, + capturedValue: null, + next: null + }); + scheduleWork(instance, expirationTime); + } + }; return { adoptClassInstance: adoptClassInstance, callGetDerivedStateFromProps: callGetDerivedStateFromProps, constructClassInstance: function(workInProgress, props) { var ctor = workInProgress.type, unmaskedContext = getUnmaskedContext(workInProgress), - needsContext = - 2 === workInProgress.tag && null != workInProgress.type.contextTypes, + needsContext = isContextConsumer(workInProgress), context = needsContext ? getMaskedContext(workInProgress, unmaskedContext) : emptyObject; @@ -2212,10 +2121,7 @@ function ReactFiberClassComponent( workInProgress.memoizedState, props )); - needsContext && - ((workInProgress = workInProgress.stateNode), - (workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext), - (workInProgress.__reactInternalMemoizedMaskedChildContext = context)); + needsContext && cacheContext(workInProgress, unmaskedContext, context); return ctor; }, mountClassInstance: function(workInProgress, renderExpirationTime) { @@ -2300,7 +2206,7 @@ function ReactFiberClassComponent( !( oldProps !== newProps || oldState !== renderExpirationTime || - didPerformWorkStackCursor.current || + hasContextChanged() || (null !== workInProgress.updateQueue && workInProgress.updateQueue.hasForceUpdate) ) @@ -2389,7 +2295,7 @@ function ReactFiberClassComponent( !( oldProps !== newProps || oldContext !== renderExpirationTime || - didPerformWorkStackCursor.current || + hasContextChanged() || (null !== workInProgress.updateQueue && workInProgress.updateQueue.hasForceUpdate) ) @@ -3112,34 +3018,12 @@ function ChildReconciler(shouldTrackSideEffects) { }; } var reconcileChildFibers = ChildReconciler(!0), - mountChildFibers = ChildReconciler(!1), - changedBitsStack = [], - currentValueStack = [], - stack = [], - index$1 = -1; -function pushProvider(providerFiber) { - var context = providerFiber.type.context; - index$1 += 1; - changedBitsStack[index$1] = context._changedBits; - currentValueStack[index$1] = context._currentValue; - stack[index$1] = providerFiber; - context._currentValue = providerFiber.pendingProps.value; - context._changedBits = providerFiber.stateNode; -} -function popProvider(providerFiber) { - var changedBits = changedBitsStack[index$1], - currentValue = currentValueStack[index$1]; - changedBitsStack[index$1] = null; - currentValueStack[index$1] = null; - stack[index$1] = null; - --index$1; - providerFiber = providerFiber.type.context; - providerFiber._currentValue = currentValue; - providerFiber._changedBits = changedBits; -} + mountChildFibers = ChildReconciler(!1); function ReactFiberBeginWork( config, hostContext, + legacyContext, + newContext, hydrationContext, scheduleWork, computeExpirationForFiber @@ -3236,7 +3120,12 @@ function ReactFiberBeginWork( changedBits, renderExpirationTime ) { - for (var fiber = workInProgress.child; null !== fiber; ) { + var fiber = workInProgress.child; + for ( + null !== fiber && (fiber["return"] = workInProgress); + null !== fiber; + + ) { switch (fiber.tag) { case 12: var nextFiber = fiber.stateNode | 0; @@ -3295,7 +3184,7 @@ function ReactFiberBeginWork( var context = workInProgress.type.context, newProps = workInProgress.pendingProps, oldProps = workInProgress.memoizedProps; - if (!didPerformWorkStackCursor.current && oldProps === newProps) + if (!hasLegacyContextChanged() && oldProps === newProps) return ( (workInProgress.stateNode = 0), pushProvider(workInProgress), @@ -3382,11 +3271,19 @@ function ReactFiberBeginWork( shouldDeprioritizeSubtree = config.shouldDeprioritizeSubtree, pushHostContext = hostContext.pushHostContext, pushHostContainer = hostContext.pushHostContainer, + pushProvider = newContext.pushProvider, + getMaskedContext = legacyContext.getMaskedContext, + getUnmaskedContext = legacyContext.getUnmaskedContext, + hasLegacyContextChanged = legacyContext.hasContextChanged, + pushLegacyContextProvider = legacyContext.pushContextProvider, + pushTopLevelContextObject = legacyContext.pushTopLevelContextObject, + invalidateContextProvider = legacyContext.invalidateContextProvider, enterHydrationState = hydrationContext.enterHydrationState, resetHydrationState = hydrationContext.resetHydrationState, tryToClaimNextHydratableInstance = hydrationContext.tryToClaimNextHydratableInstance; config = ReactFiberClassComponent( + legacyContext, scheduleWork, computeExpirationForFiber, function(workInProgress, nextProps) { @@ -3413,7 +3310,7 @@ function ReactFiberBeginWork( pushHostRootContext(workInProgress); break; case 2: - pushContextProvider(workInProgress); + pushLegacyContextProvider(workInProgress); break; case 4: pushHostContainer( @@ -3459,7 +3356,7 @@ function ReactFiberBeginWork( workInProgress.memoizedState, props ))), - (props = pushContextProvider(workInProgress)), + (props = pushLegacyContextProvider(workInProgress)), adoptClassInstance(workInProgress, fn), mountClassInstance(workInProgress, renderExpirationTime), (current = finishClassComponent( @@ -3479,7 +3376,7 @@ function ReactFiberBeginWork( return ( (props = workInProgress.type), (renderExpirationTime = workInProgress.pendingProps), - didPerformWorkStackCursor.current || + hasLegacyContextChanged() || workInProgress.memoizedProps !== renderExpirationTime ? ((fn = getUnmaskedContext(workInProgress)), (fn = getMaskedContext(workInProgress, fn)), @@ -3495,7 +3392,7 @@ function ReactFiberBeginWork( current ); case 2: - props = pushContextProvider(workInProgress); + props = pushLegacyContextProvider(workInProgress); null === current ? null === workInProgress.stateNode ? (constructClassInstance( @@ -3577,7 +3474,7 @@ function ReactFiberBeginWork( updateQueue = workInProgress.memoizedProps; fn = workInProgress.pendingProps; unmaskedContext = null !== current ? current.memoizedProps : null; - if (!didPerformWorkStackCursor.current && updateQueue === fn) { + if (!hasLegacyContextChanged() && updateQueue === fn) { if ( (updateQueue = workInProgress.mode & 1 && @@ -3619,7 +3516,7 @@ function ReactFiberBeginWork( case 7: return ( (props = workInProgress.pendingProps), - didPerformWorkStackCursor.current || + hasLegacyContextChanged() || workInProgress.memoizedProps !== props || (props = workInProgress.memoizedProps), (fn = props.children), @@ -3649,8 +3546,7 @@ function ReactFiberBeginWork( workInProgress.stateNode.containerInfo ), (props = workInProgress.pendingProps), - didPerformWorkStackCursor.current || - workInProgress.memoizedProps !== props + hasLegacyContextChanged() || workInProgress.memoizedProps !== props ? (null === current ? (workInProgress.child = reconcileChildFibers( workInProgress, @@ -3681,7 +3577,7 @@ function ReactFiberBeginWork( case 10: return ( (renderExpirationTime = workInProgress.pendingProps), - didPerformWorkStackCursor.current || + hasLegacyContextChanged() || workInProgress.memoizedProps !== renderExpirationTime ? (reconcileChildren( current, @@ -3699,7 +3595,7 @@ function ReactFiberBeginWork( case 11: return ( (renderExpirationTime = workInProgress.pendingProps.children), - didPerformWorkStackCursor.current || + hasLegacyContextChanged() || (null !== renderExpirationTime && workInProgress.memoizedProps !== renderExpirationTime) ? (reconcileChildren( @@ -3729,7 +3625,7 @@ function ReactFiberBeginWork( props = fn._currentValue; var changedBits = fn._changedBits; if ( - didPerformWorkStackCursor.current || + hasLegacyContextChanged() || 0 !== changedBits || updateQueue !== unmaskedContext ) { @@ -3769,7 +3665,13 @@ function ReactFiberBeginWork( } }; } -function ReactFiberCompleteWork(config, hostContext, hydrationContext) { +function ReactFiberCompleteWork( + config, + hostContext, + legacyContext, + newContext, + hydrationContext +) { function markUpdate(workInProgress) { workInProgress.effectTag |= 4; } @@ -3802,6 +3704,9 @@ function ReactFiberCompleteWork(config, hostContext, hydrationContext) { popHostContext = hostContext.popHostContext, getHostContext = hostContext.getHostContext, popHostContainer = hostContext.popHostContainer, + popLegacyContextProvider = legacyContext.popContextProvider, + popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject, + popProvider = newContext.popProvider, prepareToHydrateHostInstance = hydrationContext.prepareToHydrateHostInstance, prepareToHydrateHostTextInstance = @@ -3901,7 +3806,7 @@ function ReactFiberCompleteWork(config, hostContext, hydrationContext) { return null; case 2: return ( - popContextProvider(workInProgress), + popLegacyContextProvider(workInProgress), (current = workInProgress.stateNode), (newProps = workInProgress.updateQueue), null !== newProps && @@ -3914,8 +3819,7 @@ function ReactFiberCompleteWork(config, hostContext, hydrationContext) { ); case 3: popHostContainer(workInProgress); - pop(didPerformWorkStackCursor, workInProgress); - pop(contextStackCursor, workInProgress); + popTopLevelLegacyContextObject(workInProgress); newProps = workInProgress.stateNode; newProps.pendingContext && ((newProps.context = newProps.pendingContext), @@ -4099,11 +4003,16 @@ function ReactFiberCompleteWork(config, hostContext, hydrationContext) { } function ReactFiberUnwindWork( hostContext, + legacyContext, + newContext, scheduleWork, isAlreadyFailedLegacyErrorBoundary ) { var popHostContainer = hostContext.popHostContainer, - popHostContext = hostContext.popHostContext; + popHostContext = hostContext.popHostContext, + popLegacyContextProvider = legacyContext.popContextProvider, + popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject, + popProvider = newContext.popProvider; return { throwException: function(returnFiber, sourceFiber, rawValue) { sourceFiber.effectTag |= 512; @@ -4144,7 +4053,7 @@ function ReactFiberUnwindWork( unwindWork: function(workInProgress) { switch (workInProgress.tag) { case 2: - popContextProvider(workInProgress); + popLegacyContextProvider(workInProgress); var effectTag = workInProgress.effectTag; return effectTag & 1024 ? ((workInProgress.effectTag = (effectTag & -1025) | 64), @@ -4153,8 +4062,7 @@ function ReactFiberUnwindWork( case 3: return ( popHostContainer(workInProgress), - pop(didPerformWorkStackCursor, workInProgress), - pop(contextStackCursor, workInProgress), + popTopLevelLegacyContextObject(workInProgress), (effectTag = workInProgress.effectTag), effectTag & 1024 ? ((workInProgress.effectTag = (effectTag & -1025) | 64), @@ -4170,6 +4078,25 @@ function ReactFiberUnwindWork( default: return null; } + }, + unwindInterruptedWork: function(interruptedWork) { + switch (interruptedWork.tag) { + case 2: + popLegacyContextProvider(interruptedWork); + break; + case 3: + popHostContainer(interruptedWork); + popTopLevelLegacyContextObject(interruptedWork); + break; + case 5: + popHostContext(interruptedWork); + break; + case 4: + popHostContainer(interruptedWork); + break; + case 13: + popProvider(interruptedWork); + } } }; } @@ -4425,7 +4352,7 @@ function ReactFiberCommitWork( invariant(!1, "Mutating reconciler is disabled."); } var NO_CONTEXT = {}; -function ReactFiberHostContext(config) { +function ReactFiberHostContext(config, stack) { function requiredContext(c) { invariant( c !== NO_CONTEXT, @@ -4434,10 +4361,13 @@ function ReactFiberHostContext(config) { return c; } var getChildHostContext = config.getChildHostContext, - getRootHostContext = config.getRootHostContext, - contextStackCursor = { current: NO_CONTEXT }, - contextFiberStackCursor = { current: NO_CONTEXT }, - rootInstanceStackCursor = { current: NO_CONTEXT }; + getRootHostContext = config.getRootHostContext; + config = stack.createCursor; + var push = stack.push, + pop = stack.pop, + contextStackCursor = config(NO_CONTEXT), + contextFiberStackCursor = config(NO_CONTEXT), + rootInstanceStackCursor = config(NO_CONTEXT); return { getHostContext: function() { return requiredContext(contextStackCursor.current); @@ -4467,10 +4397,6 @@ function ReactFiberHostContext(config) { context !== rootInstance && (push(contextFiberStackCursor, fiber, fiber), push(contextStackCursor, rootInstance, fiber)); - }, - resetHostContainer: function() { - contextStackCursor.current = NO_CONTEXT; - rootInstanceStackCursor.current = NO_CONTEXT; } }; } @@ -4630,22 +4556,198 @@ function ReactFiberHydrationContext(config) { } }; } -function ReactFiberScheduler(config) { - function resetContextStack() { - for (; -1 < index; ) (valueStack[index] = null), index--; +function ReactFiberLegacyContext(stack) { + function cacheContext(workInProgress, unmaskedContext, maskedContext) { + workInProgress = workInProgress.stateNode; + workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; + workInProgress.__reactInternalMemoizedMaskedChildContext = maskedContext; + } + function isContextProvider(fiber) { + return 2 === fiber.tag && null != fiber.type.childContextTypes; + } + function processChildContext(fiber, parentContext) { + var instance = fiber.stateNode, + childContextTypes = fiber.type.childContextTypes; + if ("function" !== typeof instance.getChildContext) return parentContext; + instance = instance.getChildContext(); + for (var contextKey in instance) + invariant( + contextKey in childContextTypes, + '%s.getChildContext(): key "%s" is not defined in childContextTypes.', + getComponentName(fiber) || "Unknown", + contextKey + ); + return Object.assign({}, parentContext, instance); + } + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop, + contextStackCursor = createCursor(emptyObject), + didPerformWorkStackCursor = createCursor(!1), previousContext = emptyObject; - contextStackCursor.current = emptyObject; - didPerformWorkStackCursor.current = !1; - resetHostContainer(); - for (var i = index$1; -1 < i; i--) { - var context = stack[i].type.context; - context._currentValue = context._defaultValue; - context._changedBits = 0; - changedBitsStack[i] = null; - currentValueStack[i] = null; - stack[i] = null; + return { + getUnmaskedContext: function(workInProgress) { + return isContextProvider(workInProgress) + ? previousContext + : contextStackCursor.current; + }, + cacheContext: cacheContext, + getMaskedContext: function(workInProgress, unmaskedContext) { + var contextTypes = workInProgress.type.contextTypes; + if (!contextTypes) return emptyObject; + var instance = workInProgress.stateNode; + if ( + instance && + instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext + ) + return instance.__reactInternalMemoizedMaskedChildContext; + var context = {}, + key; + for (key in contextTypes) context[key] = unmaskedContext[key]; + instance && cacheContext(workInProgress, unmaskedContext, context); + return context; + }, + hasContextChanged: function() { + return didPerformWorkStackCursor.current; + }, + isContextConsumer: function(fiber) { + return 2 === fiber.tag && null != fiber.type.contextTypes; + }, + isContextProvider: isContextProvider, + popContextProvider: function(fiber) { + isContextProvider(fiber) && + (pop(didPerformWorkStackCursor, fiber), pop(contextStackCursor, fiber)); + }, + popTopLevelContextObject: function(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); + }, + pushTopLevelContextObject: function(fiber, context, didChange) { + invariant( + null == contextStackCursor.cursor, + "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); + }, + processChildContext: processChildContext, + pushContextProvider: function(workInProgress) { + if (!isContextProvider(workInProgress)) return !1; + var instance = workInProgress.stateNode; + instance = + (instance && instance.__reactInternalMemoizedMergedChildContext) || + emptyObject; + previousContext = contextStackCursor.current; + push(contextStackCursor, instance, workInProgress); + push( + didPerformWorkStackCursor, + didPerformWorkStackCursor.current, + workInProgress + ); + return !0; + }, + invalidateContextProvider: function(workInProgress, didChange) { + var instance = workInProgress.stateNode; + invariant( + instance, + "Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue." + ); + if (didChange) { + var mergedContext = processChildContext( + workInProgress, + previousContext + ); + instance.__reactInternalMemoizedMergedChildContext = mergedContext; + pop(didPerformWorkStackCursor, workInProgress); + pop(contextStackCursor, workInProgress); + push(contextStackCursor, mergedContext, workInProgress); + } else pop(didPerformWorkStackCursor, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); + }, + findCurrentUnmaskedContext: function(fiber) { + for ( + invariant( + 2 === isFiberMountedImpl(fiber) && 2 === fiber.tag, + "Expected subtree parent to be a mounted class component. This error is likely caused by a bug in React. Please file an issue." + ); + 3 !== fiber.tag; + + ) { + if (isContextProvider(fiber)) + return fiber.stateNode.__reactInternalMemoizedMergedChildContext; + fiber = fiber["return"]; + invariant( + fiber, + "Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + return fiber.stateNode.context; + } + }; +} +function ReactFiberNewContext(stack) { + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop, + providerCursor = createCursor(null), + valueCursor = createCursor(null), + changedBitsCursor = createCursor(0); + return { + pushProvider: function(providerFiber) { + var context = providerFiber.type.context; + push(changedBitsCursor, context._changedBits, providerFiber); + push(valueCursor, context._currentValue, providerFiber); + push(providerCursor, providerFiber, providerFiber); + context._currentValue = providerFiber.pendingProps.value; + context._changedBits = providerFiber.stateNode; + }, + popProvider: function(providerFiber) { + var changedBits = changedBitsCursor.current, + currentValue = valueCursor.current; + pop(providerCursor, providerFiber); + pop(valueCursor, providerFiber); + pop(changedBitsCursor, providerFiber); + providerFiber = providerFiber.type.context; + providerFiber._currentValue = currentValue; + providerFiber._changedBits = changedBits; } - index$1 = -1; + }; +} +function ReactFiberStack() { + var valueStack = [], + index = -1; + return { + createCursor: function(defaultValue) { + return { current: defaultValue }; + }, + isEmpty: function() { + return -1 === index; + }, + pop: function(cursor) { + 0 > index || + ((cursor.current = valueStack[index]), + (valueStack[index] = null), + index--); + }, + push: function(cursor, value) { + index++; + valueStack[index] = cursor.current; + cursor.current = value; + }, + checkThatStackIsEmpty: function() {}, + resetStackAfterFatalErrorInDev: function() {} + }; +} +function ReactFiberScheduler(config) { + function resetStack() { + if (null !== nextUnitOfWork) + for ( + var interruptedWork = nextUnitOfWork["return"]; + null !== interruptedWork; + + ) + unwindInterruptedWork(interruptedWork), + (interruptedWork = interruptedWork["return"]); nextRoot = null; nextRenderExpirationTime = 0; nextUnitOfWork = null; @@ -4751,7 +4853,7 @@ function ReactFiberScheduler(config) { root !== nextRoot || null === nextUnitOfWork ) - resetContextStack(), + resetStack(), (nextRoot = root), (nextRenderExpirationTime = expirationTime), (nextUnitOfWork = createWorkInProgress( @@ -4881,7 +4983,7 @@ function ReactFiberScheduler(config) { !isWorking && 0 !== nextRenderExpirationTime && expirationTime < nextRenderExpirationTime && - resetContextStack(); + resetStack(); (nextRoot === root && isWorking) || requestWork(root, expirationTime); nestedUpdateCount > NESTED_UPDATE_LIMIT && @@ -5225,25 +5327,37 @@ function ReactFiberScheduler(config) { nextFlushedRoot.remainingExpirationTime = 0; hasUnhandledError || ((hasUnhandledError = !0), (unhandledError = error)); } - var hostContext = ReactFiberHostContext(config), - hydrationContext = ReactFiberHydrationContext(config), - resetHostContainer = hostContext.resetHostContainer, + var stack = ReactFiberStack(), + hostContext = ReactFiberHostContext(config, stack), + legacyContext = ReactFiberLegacyContext(stack); + stack = ReactFiberNewContext(stack); + var hydrationContext = ReactFiberHydrationContext(config), beginWork = ReactFiberBeginWork( config, hostContext, + legacyContext, + stack, hydrationContext, scheduleWork, computeExpirationForFiber ).beginWork, - completeWork = ReactFiberCompleteWork(config, hostContext, hydrationContext) - .completeWork; + completeWork = ReactFiberCompleteWork( + config, + hostContext, + legacyContext, + stack, + hydrationContext + ).completeWork; hostContext = ReactFiberUnwindWork( hostContext, + legacyContext, + stack, scheduleWork, isAlreadyFailedLegacyErrorBoundary ); var throwException = hostContext.throwException, - unwindWork = hostContext.unwindWork; + unwindWork = hostContext.unwindWork, + unwindInterruptedWork = hostContext.unwindInterruptedWork; hostContext = ReactFiberCommitWork( config, onCommitPhaseError, @@ -5402,7 +5516,8 @@ function ReactFiberScheduler(config) { result <= lastUniqueAsyncExpiration && (result = lastUniqueAsyncExpiration + 1); return (lastUniqueAsyncExpiration = result); - } + }, + legacyContext: legacyContext }; } function ReactFiberReconciler$1(config) { @@ -5417,27 +5532,7 @@ function ReactFiberReconciler$1(config) { currentTime = container.current; if (parentComponent) { parentComponent = parentComponent._reactInternalFiber; - var parentContext; - b: { - invariant( - 2 === isFiberMountedImpl(parentComponent) && - 2 === parentComponent.tag, - "Expected subtree parent to be a mounted class component. This error is likely caused by a bug in React. Please file an issue." - ); - for (parentContext = parentComponent; 3 !== parentContext.tag; ) { - if (isContextProvider(parentContext)) { - parentContext = - parentContext.stateNode.__reactInternalMemoizedMergedChildContext; - break b; - } - parentContext = parentContext["return"]; - invariant( - parentContext, - "Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue." - ); - } - parentContext = parentContext.stateNode.context; - } + var parentContext = findCurrentUnmaskedContext(parentComponent); parentComponent = isContextProvider(parentComponent) ? processChildContext(parentComponent, parentContext) : parentContext; @@ -5466,7 +5561,11 @@ function ReactFiberReconciler$1(config) { config = ReactFiberScheduler(config); var recalculateCurrentTime = config.recalculateCurrentTime, computeExpirationForFiber = config.computeExpirationForFiber, - scheduleWork = config.scheduleWork; + scheduleWork = config.scheduleWork, + legacyContext = config.legacyContext, + findCurrentUnmaskedContext = legacyContext.findCurrentUnmaskedContext, + isContextProvider = legacyContext.isContextProvider, + processChildContext = legacyContext.processChildContext; return { createContainer: function(containerInfo, isAsync, hydrate) { isAsync = new FiberNode(3, null, null, isAsync ? 3 : 0); diff --git a/Libraries/Renderer/ReactNativeRenderer-dev.js b/Libraries/Renderer/ReactNativeRenderer-dev.js index d54c9f31c6cda3..8ea8bcf85094fd 100644 --- a/Libraries/Renderer/ReactNativeRenderer-dev.js +++ b/Libraries/Renderer/ReactNativeRenderer-dev.js @@ -26,9 +26,9 @@ var deepDiffer = require("deepDiffer"); var flattenStyle = require("flattenStyle"); var React = require("react"); var emptyObject = require("fbjs/lib/emptyObject"); -var checkPropTypes = require("prop-types/checkPropTypes"); var shallowEqual = require("fbjs/lib/shallowEqual"); var ExceptionsManager = require("ExceptionsManager"); +var checkPropTypes = require("prop-types/checkPropTypes"); var deepFreezeAndThrowOnMutationInDev = require("deepFreezeAndThrowOnMutationInDev"); var invokeGuardedCallback = function(name, func, context, a, b, c, d, e, f) { @@ -4389,1648 +4389,1323 @@ function findCurrentHostFiberWithNoPortals(parent) { return null; } -var valueStack = []; +// 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; -var fiberStack = void 0; +// TODO: Use an opaque type once ESLint et al support the syntax -{ - fiberStack = []; -} +var NoWork = 0; +var Sync = 1; +var Never = MAX_SIGNED_31_BIT_INT; -var index = -1; +var UNIT_SIZE = 10; +var MAGIC_NUMBER_OFFSET = 2; -function createCursor(defaultValue) { - return { - current: defaultValue - }; +// 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 ((ms / UNIT_SIZE) | 0) + MAGIC_NUMBER_OFFSET; } -function pop(cursor, fiber) { - if (index < 0) { - { - warning(false, "Unexpected pop."); - } - return; - } +function expirationTimeToMs(expirationTime) { + return (expirationTime - MAGIC_NUMBER_OFFSET) * UNIT_SIZE; +} - { - if (fiber !== fiberStack[index]) { - warning(false, "Unexpected Fiber popped."); - } - } +function ceiling(num, precision) { + return (((num / precision) | 0) + 1) * precision; +} + +function computeExpirationBucket(currentTime, expirationInMs, bucketSizeMs) { + return ceiling( + currentTime + expirationInMs / UNIT_SIZE, + bucketSizeMs / UNIT_SIZE + ); +} - cursor.current = valueStack[index]; +var NoContext = 0; +var AsyncMode = 1; +var StrictMode = 2; - valueStack[index] = null; +var hasBadMapPolyfill = void 0; - { - fiberStack[index] = null; +{ + 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; - index--; +{ + debugCounter = 1; } -function push(cursor, value, fiber) { - index++; +function FiberNode(tag, pendingProps, key, mode) { + // Instance + this.tag = tag; + this.key = key; + this.type = null; + this.stateNode = null; - valueStack[index] = cursor.current; + // Fiber + this["return"] = null; + this.child = null; + this.sibling = null; + this.index = 0; - { - fiberStack[index] = fiber; - } + this.ref = null; - cursor.current = value; -} + this.pendingProps = pendingProps; + this.memoizedProps = null; + this.updateQueue = null; + this.memoizedState = null; -function reset() { - while (index > -1) { - valueStack[index] = null; + this.mode = mode; - { - fiberStack[index] = null; - } + // Effects + this.effectTag = NoEffect; + this.nextEffect = null; - index--; + this.firstEffect = null; + this.lastEffect = null; + + this.expirationTime = NoWork; + + this.alternate = null; + + { + this._debugID = debugCounter++; + this._debugSource = null; + this._debugOwner = null; + this._debugIsCurrentlyTiming = false; + if (!hasBadMapPolyfill && typeof Object.preventExtensions === "function") { + Object.preventExtensions(this); + } } } -var describeComponentFrame = function(name, source, ownerName) { - return ( - "\n in " + - (name || "Unknown") + - (source - ? " (at " + - source.fileName.replace(/^.*[\\\/]/, "") + - ":" + - source.lineNumber + - ")" - : ownerName ? " (created by " + ownerName + ")" : "") - ); +// 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 describeFiber(fiber) { - switch (fiber.tag) { - case IndeterminateComponent: - case FunctionalComponent: - case ClassComponent: - case HostComponent: - var owner = fiber._debugOwner; - var source = fiber._debugSource; - var name = getComponentName(fiber); - var ownerName = null; - if (owner) { - ownerName = getComponentName(owner); - } - return describeComponentFrame(name, source, ownerName); - default: - return ""; - } +function shouldConstruct(Component) { + return !!(Component.prototype && Component.prototype.isReactComponent); } -// This function can only be called with a work-in-progress fiber and -// only during begin or complete phase. Do not call it under any other -// circumstances. -function getStackAddendumByWorkInProgressFiber(workInProgress) { - var info = ""; - var node = workInProgress; - do { - info += describeFiber(node); - // Otherwise this return pointer might point to the wrong tree: - node = node["return"]; - } while (node); - return info; -} +// 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.type = current.type; + workInProgress.stateNode = current.stateNode; -function getCurrentFiberOwnerName() { - { - var fiber = ReactDebugCurrentFiber.current; - if (fiber === null) { - return null; - } - var owner = fiber._debugOwner; - if (owner !== null && typeof owner !== "undefined") { - return getComponentName(owner); + { + // DEV-only fields + workInProgress._debugID = current._debugID; + workInProgress._debugSource = current._debugSource; + workInProgress._debugOwner = current._debugOwner; } - } - return null; -} -function getCurrentFiberStackAddendum() { - { - var fiber = ReactDebugCurrentFiber.current; - if (fiber === null) { - return null; - } - // Safe because if current fiber exists, we are reconciling, - // and it is guaranteed to be the work-in-progress version. - return getStackAddendumByWorkInProgressFiber(fiber); + 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; } - return null; -} -function resetCurrentFiber() { - ReactDebugCurrentFrame.getCurrentStack = null; - ReactDebugCurrentFiber.current = null; - ReactDebugCurrentFiber.phase = null; -} + workInProgress.expirationTime = expirationTime; -function setCurrentFiber(fiber) { - ReactDebugCurrentFrame.getCurrentStack = getCurrentFiberStackAddendum; - ReactDebugCurrentFiber.current = fiber; - ReactDebugCurrentFiber.phase = null; + workInProgress.child = current.child; + workInProgress.memoizedProps = current.memoizedProps; + workInProgress.memoizedState = current.memoizedState; + workInProgress.updateQueue = current.updateQueue; + + // These will be overridden during the parent's reconciliation + workInProgress.sibling = current.sibling; + workInProgress.index = current.index; + workInProgress.ref = current.ref; + + return workInProgress; } -function setCurrentPhase(phase) { - ReactDebugCurrentFiber.phase = phase; +function createHostRootFiber(isAsync) { + var mode = isAsync ? AsyncMode | StrictMode : NoContext; + return createFiber(HostRoot, null, null, mode); } -var ReactDebugCurrentFiber = { - current: null, - phase: null, - resetCurrentFiber: resetCurrentFiber, - setCurrentFiber: setCurrentFiber, - setCurrentPhase: setCurrentPhase, - getCurrentFiberOwnerName: getCurrentFiberOwnerName, - getCurrentFiberStackAddendum: getCurrentFiberStackAddendum -}; - -// Re-export dynamic flags from the fbsource version. -var _require = require("ReactFeatureFlags"); - -var enableGetDerivedStateFromCatch = _require.enableGetDerivedStateFromCatch; -var debugRenderPhaseSideEffects = _require.debugRenderPhaseSideEffects; -var debugRenderPhaseSideEffectsForStrictMode = - _require.debugRenderPhaseSideEffectsForStrictMode; -var warnAboutDeprecatedLifecycles = _require.warnAboutDeprecatedLifecycles; -var replayFailedUnitOfWorkWithInvokeGuardedCallback = - _require.replayFailedUnitOfWorkWithInvokeGuardedCallback; - -var enableUserTimingAPI = true; -var enableMutatingReconciler = true; -var enableNoopReconciler = false; -var enablePersistentReconciler = false; - -// Only used in www builds. - -// 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$$1) { - var prefix = warning$$1 ? warningEmoji + " " : reactEmoji + " "; - var suffix = warning$$1 ? " Warning: " + warning$$1 : ""; - 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$$1) { - var formattedMarkName = formatMarkName(markName); - var formattedLabel = formatLabel(label, warning$$1); - 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) || "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) || "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$$1) { - var componentName = getComponentName(fiber) || "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$$1); -}; - -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 CallComponent: - case ReturnComponent: - case Fragment: - case ContextProvider: - case ContextConsumer: - 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$$1 = didExpire ? "React was blocked by main thread" : null; - endMark( - "(Waiting for async callback...)", - "(Waiting for async callback...)", - warning$$1 - ); - } - } -} - -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$$1 = "An error was thrown inside this error boundary"; - endFiberMark(fiber, null, warning$$1); - } -} - -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$$1 = hasScheduledUpdateInCurrentPhase - ? "Scheduled a cascading update" - : null; - endFiberMark(currentPhaseFiber, currentPhase, warning$$1); - } - 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) { - if (enableUserTimingAPI) { - if (!supportsUserTiming) { - return; - } - var warning$$1 = null; - if (interruptedBy !== null) { - if (interruptedBy.tag === HostRoot) { - warning$$1 = "A top-level update interrupted the previous render"; - } else { - var componentName = getComponentName(interruptedBy) || "Unknown"; - warning$$1 = - "An update to " + componentName + " interrupted the previous render"; - } - } else if (commitCountInCurrentWorkLoop > 1) { - warning$$1 = "There were cascading updates"; - } - commitCountInCurrentWorkLoop = 0; - // Pause any measurements until the next loop. - pauseTimers(); - endMark( - "(React Tree Reconciliation)", - "(React Tree Reconciliation)", - warning$$1 - ); - } -} - -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$$1 = null; - if (hasScheduledUpdateInCurrentCommit) { - warning$$1 = "Lifecycle hook scheduled a cascading update"; - } else if (commitCountInCurrentWorkLoop > 0) { - warning$$1 = "Caused by a cascading update in earlier commit"; - } - hasScheduledUpdateInCurrentCommit = false; - commitCountInCurrentWorkLoop++; - isCommitting = false; - labelsInCurrentCommit.clear(); - - endMark("(Committing Changes)", "(Committing Changes)", warning$$1); - } -} - -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 createFiberFromElement(element, mode, expirationTime) { + var owner = null; + { + owner = element._owner; } -} -function startCommitLifeCyclesTimer() { - if (enableUserTimingAPI) { - if (!supportsUserTiming) { - return; - } - effectCountInCurrentCommit = 0; - beginMark("(Calling Lifecycle Methods)"); - } -} + var fiber = void 0; + var type = element.type; + var key = element.key; + var pendingProps = element.props; -function stopCommitLifeCyclesTimer() { - if (enableUserTimingAPI) { - if (!supportsUserTiming) { - return; + var fiberTag = void 0; + if (typeof type === "function") { + fiberTag = shouldConstruct(type) ? ClassComponent : IndeterminateComponent; + } else if (typeof type === "string") { + fiberTag = HostComponent; + } else { + switch (type) { + case REACT_FRAGMENT_TYPE: + return createFiberFromFragment( + pendingProps.children, + mode, + expirationTime, + key + ); + case REACT_ASYNC_MODE_TYPE: + fiberTag = Mode; + mode |= AsyncMode | StrictMode; + break; + case REACT_STRICT_MODE_TYPE: + fiberTag = Mode; + mode |= StrictMode; + break; + case REACT_CALL_TYPE: + fiberTag = CallComponent; + break; + case REACT_RETURN_TYPE: + fiberTag = ReturnComponent; + break; + default: { + if (typeof type === "object" && type !== null) { + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + fiberTag = ContextProvider; + break; + case REACT_CONTEXT_TYPE: + // This is a consumer + fiberTag = ContextConsumer; + break; + case REACT_FORWARD_REF_TYPE: + fiberTag = ForwardRef; + break; + default: + if (typeof type.tag === "number") { + // Currently assumed to be a continuation and therefore is a + // fiber already. + // TODO: The yield system is currently broken for updates in + // some cases. The reified yield stores a fiber, but we don't + // know which fiber that is; the current or a workInProgress? + // When the continuation gets rendered here we don't know if we + // can reuse that fiber or if we need to clone it. There is + // probably a clever way to restructure this. + fiber = type; + fiber.pendingProps = pendingProps; + fiber.expirationTime = expirationTime; + return fiber; + } else { + throwOnInvalidElementType(type, owner); + } + break; + } + } else { + throwOnInvalidElementType(type, owner); + } + } } - var count = effectCountInCurrentCommit; - effectCountInCurrentCommit = 0; - endMark( - "(Calling Lifecycle Methods: " + count + " Total)", - "(Calling Lifecycle Methods)", - null - ); } -} -var warnedAboutMissingGetChildContext = void 0; - -{ - warnedAboutMissingGetChildContext = {}; -} - -// A cursor to the current merged context object on the stack. -var contextStackCursor = createCursor(emptyObject); -// 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 = emptyObject; + fiber = createFiber(fiberTag, pendingProps, key, mode); + fiber.type = type; + fiber.expirationTime = expirationTime; -function getUnmaskedContext(workInProgress) { - var hasOwnContext = isContextProvider(workInProgress); - if (hasOwnContext) { - // If the fiber is a context provider itself, when we read its context - // we 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; + { + fiber._debugSource = element._source; + fiber._debugOwner = element._owner; } - return contextStackCursor.current; -} -function cacheContext(workInProgress, unmaskedContext, maskedContext) { - var instance = workInProgress.stateNode; - instance.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; - instance.__reactInternalMemoizedMaskedChildContext = maskedContext; + return fiber; } -function getMaskedContext(workInProgress, unmaskedContext) { - var type = workInProgress.type; - var contextTypes = type.contextTypes; - if (!contextTypes) { - return emptyObject; - } - - // 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]; - } - +function throwOnInvalidElementType(type, owner) { + var info = ""; { - var name = getComponentName(workInProgress) || "Unknown"; - checkPropTypes( - contextTypes, - context, - "context", - name, - ReactDebugCurrentFiber.getCurrentFiberStackAddendum - ); - } - - // 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); + 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) : null; + if (ownerName) { + info += "\n\nCheck the render method of `" + ownerName + "`."; + } } - - return context; -} - -function hasContextChanged() { - return didPerformWorkStackCursor.current; + invariant( + false, + "Element type is invalid: expected a string (for built-in " + + "components) or a class/function (for composite components) " + + "but got: %s.%s", + type == null ? type : typeof type, + info + ); } -function isContextConsumer(fiber) { - return fiber.tag === ClassComponent && fiber.type.contextTypes != null; +function createFiberFromFragment(elements, mode, expirationTime, key) { + var fiber = createFiber(Fragment, elements, key, mode); + fiber.expirationTime = expirationTime; + return fiber; } -function isContextProvider(fiber) { - return fiber.tag === ClassComponent && fiber.type.childContextTypes != null; +function createFiberFromText(content, mode, expirationTime) { + var fiber = createFiber(HostText, content, null, mode); + fiber.expirationTime = expirationTime; + return fiber; } -function popContextProvider(fiber) { - if (!isContextProvider(fiber)) { - return; - } - - pop(didPerformWorkStackCursor, fiber); - pop(contextStackCursor, fiber); +function createFiberFromHostInstanceForDeletion() { + var fiber = createFiber(HostComponent, null, null, NoContext); + fiber.type = "DELETED"; + return fiber; } -function popTopLevelContextObject(fiber) { - pop(didPerformWorkStackCursor, fiber); - pop(contextStackCursor, 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; } -function pushTopLevelContextObject(fiber, context, didChange) { - invariant( - contextStackCursor.cursor == null, - "Unexpected context found on stack. " + - "This error is likely caused by a bug in React. Please file an issue." - ); +// TODO: This should be lifted into the renderer. - push(contextStackCursor, context, fiber); - push(didPerformWorkStackCursor, didChange, fiber); +function createFiberRoot(containerInfo, isAsync, hydrate) { + // Cyclic construction. This cheats the type system right now because + // stateNode is any. + var uninitializedFiber = createHostRootFiber(isAsync); + var root = { + current: uninitializedFiber, + containerInfo: containerInfo, + pendingChildren: null, + pendingCommitExpirationTime: NoWork, + finishedWork: null, + context: null, + pendingContext: null, + hydrate: hydrate, + remainingExpirationTime: NoWork, + firstBatch: null, + nextScheduledRoot: null + }; + uninitializedFiber.stateNode = root; + return root; } -function processChildContext(fiber, parentContext) { - var instance = fiber.stateNode; - var childContextTypes = fiber.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(fiber) || "Unknown"; +var onCommitFiberRoot = null; +var onCommitFiberUnmount = null; +var hasLoggedError = false; - if (!warnedAboutMissingGetChildContext[componentName]) { - warnedAboutMissingGetChildContext[componentName] = true; - warning( - 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 - ); +function catchErrors(fn) { + return function(arg) { + try { + return fn(arg); + } catch (err) { + if (true && !hasLoggedError) { + hasLoggedError = true; + warning(false, "React DevTools encountered an error: %s", err); } } - return parentContext; - } + }; +} - var childContext = void 0; - { - ReactDebugCurrentFiber.setCurrentPhase("getChildContext"); - } - startPhaseTimer(fiber, "getChildContext"); - childContext = instance.getChildContext(); - stopPhaseTimer(); - { - ReactDebugCurrentFiber.setCurrentPhase(null); +function injectInternals(internals) { + if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === "undefined") { + // No DevTools + return false; } - for (var contextKey in childContext) { - invariant( - contextKey in childContextTypes, - '%s.getChildContext(): key "%s" is not defined in childContextTypes.', - getComponentName(fiber) || "Unknown", - contextKey - ); + 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; } - { - var name = getComponentName(fiber) || "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. - ReactDebugCurrentFiber.getCurrentFiberStackAddendum - ); + if (!hook.supportsFiber) { + { + warning( + 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; } - - return Object.assign({}, parentContext, childContext); -} - -function pushContextProvider(workInProgress) { - if (!isContextProvider(workInProgress)) { - return false; + 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. + { + warning(false, "React DevTools encountered an error: %s.", err); + } } - - 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) || - emptyObject; - - // 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 - ); - + // DevTools exists return true; } -function invalidateContextProvider(workInProgress, didChange) { - var instance = workInProgress.stateNode; - invariant( - instance, - "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, 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 onCommitRoot(root) { + if (typeof onCommitFiberRoot === "function") { + onCommitFiberRoot(root); } } -function resetContext() { - previousContext = emptyObject; - contextStackCursor.current = emptyObject; - didPerformWorkStackCursor.current = false; -} - -function findCurrentUnmaskedContext(fiber) { - // Currently this is only used with renderSubtreeIntoContainer; not sure if it - // makes sense elsewhere - invariant( - isFiberMounted(fiber) && fiber.tag === ClassComponent, - "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; - while (node.tag !== HostRoot) { - if (isContextProvider(node)) { - return node.stateNode.__reactInternalMemoizedMergedChildContext; - } - var parent = node["return"]; - invariant( - parent, - "Found unexpected detached subtree parent. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - node = parent; +function onCommitUnmount(fiber) { + if (typeof onCommitFiberUnmount === "function") { + onCommitFiberUnmount(fiber); } - return node.stateNode.context; -} - -// 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; - -// TODO: Use an opaque type once ESLint et al support the syntax - -var NoWork = 0; -var Sync = 1; -var Never = MAX_SIGNED_31_BIT_INT; - -var UNIT_SIZE = 10; -var MAGIC_NUMBER_OFFSET = 2; - -// 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 ((ms / UNIT_SIZE) | 0) + MAGIC_NUMBER_OFFSET; -} - -function expirationTimeToMs(expirationTime) { - return (expirationTime - MAGIC_NUMBER_OFFSET) * UNIT_SIZE; -} - -function ceiling(num, precision) { - return (((num / precision) | 0) + 1) * precision; } -function computeExpirationBucket(currentTime, expirationInMs, bucketSizeMs) { - return ceiling( - currentTime + expirationInMs / UNIT_SIZE, - bucketSizeMs / UNIT_SIZE +var describeComponentFrame = function(name, source, ownerName) { + return ( + "\n in " + + (name || "Unknown") + + (source + ? " (at " + + source.fileName.replace(/^.*[\\\/]/, "") + + ":" + + source.lineNumber + + ")" + : ownerName ? " (created by " + ownerName + ")" : "") ); -} - -var NoContext = 0; -var AsyncMode = 1; -var StrictMode = 2; - -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; +function describeFiber(fiber) { + switch (fiber.tag) { + case IndeterminateComponent: + case FunctionalComponent: + case ClassComponent: + case HostComponent: + var owner = fiber._debugOwner; + var source = fiber._debugSource; + var name = getComponentName(fiber); + var ownerName = null; + if (owner) { + ownerName = getComponentName(owner); + } + return describeComponentFrame(name, source, ownerName); + default: + return ""; } } -// 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; +// This function can only be called with a work-in-progress fiber and +// only during begin or complete phase. Do not call it under any other +// circumstances. +function getStackAddendumByWorkInProgressFiber(workInProgress) { + var info = ""; + var node = workInProgress; + do { + info += describeFiber(node); + // Otherwise this return pointer might point to the wrong tree: + node = node["return"]; + } while (node); + return info; } -function FiberNode(tag, pendingProps, key, mode) { - // Instance - this.tag = tag; - this.key = key; - 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.mode = mode; +/** + * 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. + */ - // Effects - this.effectTag = NoEffect; - this.nextEffect = null; +var lowPriorityWarning = function() {}; - this.firstEffect = null; - this.lastEffect = null; +{ + 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]; + } - this.expirationTime = NoWork; + 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) {} + }; - this.alternate = null; + lowPriorityWarning = function(condition, format) { + if (format === undefined) { + throw new Error( + "`warning(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]; + } - { - this._debugID = debugCounter++; - this._debugSource = null; - this._debugOwner = null; - this._debugIsCurrentlyTiming = false; - if (!hasBadMapPolyfill && typeof Object.preventExtensions === "function") { - Object.preventExtensions(this); + printWarning.apply(undefined, [format].concat(args)); } - } + }; } -// 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); -}; +var lowPriorityWarning$1 = lowPriorityWarning; -function shouldConstruct(Component) { - return !!(Component.prototype && Component.prototype.isReactComponent); -} +var ReactStrictModeWarnings = { + discardPendingWarnings: function() {}, + flushPendingDeprecationWarnings: function() {}, + flushPendingUnsafeLifecycleWarnings: function() {}, + recordDeprecationWarnings: function(fiber, instance) {}, + recordUnsafeLifecycleWarnings: function(fiber, instance) {} +}; -// 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.type = current.type; - workInProgress.stateNode = current.stateNode; +{ + var LIFECYCLE_SUGGESTIONS = { + UNSAFE_componentWillMount: "componentDidMount", + UNSAFE_componentWillReceiveProps: "static getDerivedStateFromProps", + UNSAFE_componentWillUpdate: "componentDidUpdate" + }; - { - // DEV-only fields - workInProgress._debugID = current._debugID; - workInProgress._debugSource = current._debugSource; - workInProgress._debugOwner = current._debugOwner; - } + var pendingComponentWillMountWarnings = []; + var pendingComponentWillReceivePropsWarnings = []; + var pendingComponentWillUpdateWarnings = []; + var pendingUnsafeLifecycleWarnings = new Map(); - workInProgress.alternate = current; - current.alternate = workInProgress; - } else { - workInProgress.pendingProps = pendingProps; + // Tracks components we have already warned about. + var didWarnAboutDeprecatedLifecycles = new Set(); + var didWarnAboutUnsafeLifecycles = new Set(); - // We already have an alternate. - // Reset the effect tag. - workInProgress.effectTag = NoEffect; + ReactStrictModeWarnings.discardPendingWarnings = function() { + pendingComponentWillMountWarnings = []; + pendingComponentWillReceivePropsWarnings = []; + pendingComponentWillUpdateWarnings = []; + pendingUnsafeLifecycleWarnings = new Map(); + }; - // The effect list is no longer valid. - workInProgress.nextEffect = null; - workInProgress.firstEffect = null; - workInProgress.lastEffect = null; - } + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = function() { + pendingUnsafeLifecycleWarnings.forEach(function( + lifecycleWarningsMap, + strictRoot + ) { + var lifecyclesWarningMesages = []; - workInProgress.expirationTime = expirationTime; + 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) || "Component"); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); - workInProgress.child = current.child; - workInProgress.memoizedProps = current.memoizedProps; - workInProgress.memoizedState = current.memoizedState; - workInProgress.updateQueue = current.updateQueue; + var formatted = lifecycle.replace("UNSAFE_", ""); + var suggestion = LIFECYCLE_SUGGESTIONS[lifecycle]; + var sortedComponentNames = Array.from(componentNames) + .sort() + .join(", "); - // These will be overridden during the parent's reconciliation - workInProgress.sibling = current.sibling; - workInProgress.index = current.index; - workInProgress.ref = current.ref; + lifecyclesWarningMesages.push( + formatted + + ": Please update the following components to use " + + (suggestion + " instead: " + sortedComponentNames) + ); + } + }); - return workInProgress; -} + if (lifecyclesWarningMesages.length > 0) { + var strictRootComponentStack = getStackAddendumByWorkInProgressFiber( + strictRoot + ); -function createHostRootFiber(isAsync) { - var mode = isAsync ? AsyncMode | StrictMode : NoContext; - return createFiber(HostRoot, null, null, mode); -} + warning( + 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, + lifecyclesWarningMesages.join("\n\n") + ); + } + }); -function createFiberFromElement(element, mode, expirationTime) { - var owner = null; - { - owner = element._owner; - } + pendingUnsafeLifecycleWarnings = new Map(); + }; - var fiber = void 0; - var type = element.type; - var key = element.key; - var pendingProps = element.props; + var getStrictRoot = function(fiber) { + var maybeStrictRoot = null; - var fiberTag = void 0; - if (typeof type === "function") { - fiberTag = shouldConstruct(type) ? ClassComponent : IndeterminateComponent; - } else if (typeof type === "string") { - fiberTag = HostComponent; - } else { - switch (type) { - case REACT_FRAGMENT_TYPE: - return createFiberFromFragment( - pendingProps.children, - mode, - expirationTime, - key - ); - case REACT_ASYNC_MODE_TYPE: - fiberTag = Mode; - mode |= AsyncMode | StrictMode; - break; - case REACT_STRICT_MODE_TYPE: - fiberTag = Mode; - mode |= StrictMode; - break; - case REACT_CALL_TYPE: - fiberTag = CallComponent; - break; - case REACT_RETURN_TYPE: - fiberTag = ReturnComponent; - break; - default: { - if (typeof type === "object" && type !== null) { - switch (type.$$typeof) { - case REACT_PROVIDER_TYPE: - fiberTag = ContextProvider; - break; - case REACT_CONTEXT_TYPE: - // This is a consumer - fiberTag = ContextConsumer; - break; - case REACT_FORWARD_REF_TYPE: - fiberTag = ForwardRef; - break; - default: - if (typeof type.tag === "number") { - // Currently assumed to be a continuation and therefore is a - // fiber already. - // TODO: The yield system is currently broken for updates in - // some cases. The reified yield stores a fiber, but we don't - // know which fiber that is; the current or a workInProgress? - // When the continuation gets rendered here we don't know if we - // can reuse that fiber or if we need to clone it. There is - // probably a clever way to restructure this. - fiber = type; - fiber.pendingProps = pendingProps; - fiber.expirationTime = expirationTime; - return fiber; - } else { - throwOnInvalidElementType(type, owner); - } - break; - } - } else { - throwOnInvalidElementType(type, owner); - } + while (fiber !== null) { + if (fiber.mode & StrictMode) { + maybeStrictRoot = fiber; } + + fiber = fiber["return"]; + } + + return maybeStrictRoot; + }; + + ReactStrictModeWarnings.flushPendingDeprecationWarnings = function() { + if (pendingComponentWillMountWarnings.length > 0) { + var uniqueNames = new Set(); + pendingComponentWillMountWarnings.forEach(function(fiber) { + uniqueNames.add(getComponentName(fiber) || "Component"); + didWarnAboutDeprecatedLifecycles.add(fiber.type); + }); + + var sortedNames = Array.from(uniqueNames) + .sort() + .join(", "); + + 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 = []; } - } - fiber = createFiber(fiberTag, pendingProps, key, mode); - fiber.type = type; - fiber.expirationTime = expirationTime; + if (pendingComponentWillReceivePropsWarnings.length > 0) { + var _uniqueNames = new Set(); + pendingComponentWillReceivePropsWarnings.forEach(function(fiber) { + _uniqueNames.add(getComponentName(fiber) || "Component"); + didWarnAboutDeprecatedLifecycles.add(fiber.type); + }); - { - fiber._debugSource = element._source; - fiber._debugOwner = element._owner; - } + var _sortedNames = Array.from(_uniqueNames) + .sort() + .join(", "); - return fiber; -} + 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 + ); -function throwOnInvalidElementType(type, owner) { - 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) : null; - if (ownerName) { - info += "\n\nCheck the render method of `" + ownerName + "`."; + pendingComponentWillReceivePropsWarnings = []; } - } - invariant( - false, - "Element type is invalid: expected a string (for built-in " + - "components) or a class/function (for composite components) " + - "but got: %s.%s", - type == null ? type : typeof type, - info - ); -} -function createFiberFromFragment(elements, mode, expirationTime, key) { - var fiber = createFiber(Fragment, elements, key, mode); - fiber.expirationTime = expirationTime; - return fiber; -} + if (pendingComponentWillUpdateWarnings.length > 0) { + var _uniqueNames2 = new Set(); + pendingComponentWillUpdateWarnings.forEach(function(fiber) { + _uniqueNames2.add(getComponentName(fiber) || "Component"); + didWarnAboutDeprecatedLifecycles.add(fiber.type); + }); -function createFiberFromText(content, mode, expirationTime) { - var fiber = createFiber(HostText, content, null, mode); - fiber.expirationTime = expirationTime; - return fiber; -} + var _sortedNames2 = Array.from(_uniqueNames2) + .sort() + .join(", "); -function createFiberFromHostInstanceForDeletion() { - var fiber = createFiber(HostComponent, null, null, NoContext); - fiber.type = "DELETED"; - return fiber; -} + 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 + ); -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 + pendingComponentWillUpdateWarnings = []; + } }; - return fiber; -} -// TODO: This should be lifted into the renderer. + ReactStrictModeWarnings.recordDeprecationWarnings = function( + fiber, + instance + ) { + // Dedup strategy: Warn once per component. + if (didWarnAboutDeprecatedLifecycles.has(fiber.type)) { + return; + } -function createFiberRoot(containerInfo, isAsync, hydrate) { - // Cyclic construction. This cheats the type system right now because - // stateNode is any. - var uninitializedFiber = createHostRootFiber(isAsync); - var root = { - current: uninitializedFiber, - containerInfo: containerInfo, - pendingChildren: null, - pendingCommitExpirationTime: NoWork, - finishedWork: null, - context: null, - pendingContext: null, - hydrate: hydrate, - remainingExpirationTime: NoWork, - firstBatch: null, - nextScheduledRoot: null + // 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") { + pendingComponentWillUpdateWarnings.push(fiber); + } }; - uninitializedFiber.stateNode = root; - return root; -} -var onCommitFiberRoot = null; -var onCommitFiberUnmount = null; -var hasLoggedError = false; + ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function( + fiber, + instance + ) { + var strictRoot = getStrictRoot(fiber); -function catchErrors(fn) { - return function(arg) { - try { - return fn(arg); - } catch (err) { - if (true && !hasLoggedError) { - hasLoggedError = true; - warning(false, "React DevTools encountered an error: %s", err); - } + // 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; + } + + // Don't warn about react-lifecycles-compat polyfilled components. + // Note that it is sufficient to check for the presence of a + // single lifecycle, componentWillMount, with the polyfill flag. + if ( + typeof instance.componentWillMount === "function" && + instance.componentWillMount.__suppressDeprecationWarning === true + ) { + 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" || + typeof instance.UNSAFE_componentWillMount === "function" + ) { + unsafeLifecycles.push("UNSAFE_componentWillMount"); + } + if ( + typeof instance.componentWillReceiveProps === "function" || + typeof instance.UNSAFE_componentWillReceiveProps === "function" + ) { + unsafeLifecycles.push("UNSAFE_componentWillReceiveProps"); + } + if ( + typeof instance.componentWillUpdate === "function" || + typeof instance.UNSAFE_componentWillUpdate === "function" + ) { + unsafeLifecycles.push("UNSAFE_componentWillUpdate"); + } + + if (unsafeLifecycles.length > 0) { + unsafeLifecycles.forEach(function(lifecycle) { + warningsForRoot[lifecycle].push(fiber); + }); } }; } -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) { - { - warning( - 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" - ); +// Re-export dynamic flags from the fbsource version. +var _require = require("ReactFeatureFlags"); + +var enableGetDerivedStateFromCatch = _require.enableGetDerivedStateFromCatch; +var debugRenderPhaseSideEffects = _require.debugRenderPhaseSideEffects; +var debugRenderPhaseSideEffectsForStrictMode = + _require.debugRenderPhaseSideEffectsForStrictMode; +var warnAboutDeprecatedLifecycles = _require.warnAboutDeprecatedLifecycles; +var replayFailedUnitOfWorkWithInvokeGuardedCallback = + _require.replayFailedUnitOfWorkWithInvokeGuardedCallback; + +var enableUserTimingAPI = true; +var enableMutatingReconciler = true; +var enableNoopReconciler = false; +var enablePersistentReconciler = false; + +// Only used in www builds. + +function getCurrentFiberOwnerName() { + { + var fiber = ReactDebugCurrentFiber.current; + if (fiber === null) { + return null; } - // 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. - { - warning(false, "React DevTools encountered an error: %s.", err); + var owner = fiber._debugOwner; + if (owner !== null && typeof owner !== "undefined") { + return getComponentName(owner); } } - // DevTools exists - return true; + return null; } -function onCommitRoot(root) { - if (typeof onCommitFiberRoot === "function") { - onCommitFiberRoot(root); +function getCurrentFiberStackAddendum() { + { + var fiber = ReactDebugCurrentFiber.current; + if (fiber === null) { + return null; + } + // Safe because if current fiber exists, we are reconciling, + // and it is guaranteed to be the work-in-progress version. + return getStackAddendumByWorkInProgressFiber(fiber); } + return null; } -function onCommitUnmount(fiber) { - if (typeof onCommitFiberUnmount === "function") { - onCommitFiberUnmount(fiber); - } +function resetCurrentFiber() { + ReactDebugCurrentFrame.getCurrentStack = null; + ReactDebugCurrentFiber.current = null; + ReactDebugCurrentFiber.phase = null; } -/** - * 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() {}; +function setCurrentFiber(fiber) { + ReactDebugCurrentFrame.getCurrentStack = getCurrentFiberStackAddendum; + ReactDebugCurrentFiber.current = fiber; + ReactDebugCurrentFiber.phase = null; +} -{ - 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]; - } +function setCurrentPhase(phase) { + ReactDebugCurrentFiber.phase = phase; +} - 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) {} - }; +var ReactDebugCurrentFiber = { + current: null, + phase: null, + resetCurrentFiber: resetCurrentFiber, + setCurrentFiber: setCurrentFiber, + setCurrentPhase: setCurrentPhase, + getCurrentFiberOwnerName: getCurrentFiberOwnerName, + getCurrentFiberStackAddendum: getCurrentFiberStackAddendum +}; - lowPriorityWarning = function(condition, format) { - if (format === undefined) { - throw new Error( - "`warning(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]; - } +// 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"; - printWarning.apply(undefined, [format].concat(args)); - } - }; -} +// 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 lowPriorityWarning$1 = lowPriorityWarning; +var formatMarkName = function(markName) { + return reactEmoji + " " + markName; +}; -var ReactStrictModeWarnings = { - discardPendingWarnings: function() {}, - flushPendingDeprecationWarnings: function() {}, - flushPendingUnsafeLifecycleWarnings: function() {}, - recordDeprecationWarnings: function(fiber, instance) {}, - recordUnsafeLifecycleWarnings: function(fiber, instance) {} +var formatLabel = function(label, warning$$1) { + var prefix = warning$$1 ? warningEmoji + " " : reactEmoji + " "; + var suffix = warning$$1 ? " Warning: " + warning$$1 : ""; + return "" + prefix + label + suffix; }; -{ - var LIFECYCLE_SUGGESTIONS = { - UNSAFE_componentWillMount: "componentDidMount", - UNSAFE_componentWillReceiveProps: "static getDerivedStateFromProps", - UNSAFE_componentWillUpdate: "componentDidUpdate" - }; +var beginMark = function(markName) { + performance.mark(formatMarkName(markName)); +}; - var pendingComponentWillMountWarnings = []; - var pendingComponentWillReceivePropsWarnings = []; - var pendingComponentWillUpdateWarnings = []; - var pendingUnsafeLifecycleWarnings = new Map(); +var clearMark = function(markName) { + performance.clearMarks(formatMarkName(markName)); +}; - // Tracks components we have already warned about. - var didWarnAboutDeprecatedLifecycles = new Set(); - var didWarnAboutUnsafeLifecycles = new Set(); +var endMark = function(label, markName, warning$$1) { + var formattedMarkName = formatMarkName(markName); + var formattedLabel = formatLabel(label, warning$$1); + 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. - ReactStrictModeWarnings.discardPendingWarnings = function() { - pendingComponentWillMountWarnings = []; - pendingComponentWillReceivePropsWarnings = []; - pendingComponentWillUpdateWarnings = []; - pendingUnsafeLifecycleWarnings = new Map(); - }; + // Clear marks immediately to avoid growing buffer. + performance.clearMarks(formattedMarkName); + performance.clearMeasures(formattedLabel); +}; - ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = function() { - pendingUnsafeLifecycleWarnings.forEach(function( - lifecycleWarningsMap, - strictRoot - ) { - var lifecyclesWarningMesages = []; +var getFiberMarkName = function(label, debugID) { + return label + " (#" + debugID + ")"; +}; - 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) || "Component"); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); +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 formatted = lifecycle.replace("UNSAFE_", ""); - var suggestion = LIFECYCLE_SUGGESTIONS[lifecycle]; - var sortedComponentNames = Array.from(componentNames) - .sort() - .join(", "); +var beginFiberMark = function(fiber, phase) { + var componentName = getComponentName(fiber) || "Unknown"; + var debugID = fiber._debugID; + var isMounted = fiber.alternate !== null; + var label = getFiberLabel(componentName, isMounted, phase); - lifecyclesWarningMesages.push( - formatted + - ": Please update the following components to use " + - (suggestion + " instead: " + sortedComponentNames) - ); - } - }); + 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); - if (lifecyclesWarningMesages.length > 0) { - var strictRootComponentStack = getStackAddendumByWorkInProgressFiber( - strictRoot - ); + var markName = getFiberMarkName(label, debugID); + beginMark(markName); + return true; +}; - warning( - 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, - lifecyclesWarningMesages.join("\n\n") - ); - } - }); +var clearFiberMark = function(fiber, phase) { + var componentName = getComponentName(fiber) || "Unknown"; + var debugID = fiber._debugID; + var isMounted = fiber.alternate !== null; + var label = getFiberLabel(componentName, isMounted, phase); + var markName = getFiberMarkName(label, debugID); + clearMark(markName); +}; - pendingUnsafeLifecycleWarnings = new Map(); - }; +var endFiberMark = function(fiber, phase, warning$$1) { + var componentName = getComponentName(fiber) || "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$$1); +}; - var getStrictRoot = function(fiber) { - var maybeStrictRoot = null; +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 CallComponent: + case ReturnComponent: + case Fragment: + case ContextProvider: + case ContextConsumer: + return true; + default: + return false; + } +}; - while (fiber !== null) { - if (fiber.mode & StrictMode) { - maybeStrictRoot = fiber; - } +var clearPendingPhaseMeasurement = function() { + if (currentPhase !== null && currentPhaseFiber !== null) { + clearFiberMark(currentPhaseFiber, currentPhase); + } + currentPhaseFiber = null; + currentPhase = null; + hasScheduledUpdateInCurrentPhase = false; +}; - fiber = fiber["return"]; +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"]; + } +}; - return maybeStrictRoot; - }; - - ReactStrictModeWarnings.flushPendingDeprecationWarnings = function() { - if (pendingComponentWillMountWarnings.length > 0) { - var uniqueNames = new Set(); - pendingComponentWillMountWarnings.forEach(function(fiber) { - uniqueNames.add(getComponentName(fiber) || "Component"); - didWarnAboutDeprecatedLifecycles.add(fiber.type); - }); +var resumeTimersRecursively = function(fiber) { + if (fiber["return"] !== null) { + resumeTimersRecursively(fiber["return"]); + } + if (fiber._debugIsCurrentlyTiming) { + beginFiberMark(fiber, null); + } +}; - var sortedNames = Array.from(uniqueNames) - .sort() - .join(", "); +var resumeTimers = function() { + // Resumes all measurements that were active during the last deferred loop. + if (currentFiber !== null) { + resumeTimersRecursively(currentFiber); + } +}; - 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 - ); +function recordEffect() { + if (enableUserTimingAPI) { + effectCountInCurrentCommit++; + } +} - pendingComponentWillMountWarnings = []; +function recordScheduleUpdate() { + if (enableUserTimingAPI) { + if (isCommitting) { + hasScheduledUpdateInCurrentCommit = true; } + if ( + currentPhase !== null && + currentPhase !== "componentWillMount" && + currentPhase !== "componentWillReceiveProps" + ) { + hasScheduledUpdateInCurrentPhase = true; + } + } +} - if (pendingComponentWillReceivePropsWarnings.length > 0) { - var _uniqueNames = new Set(); - pendingComponentWillReceivePropsWarnings.forEach(function(fiber) { - _uniqueNames.add(getComponentName(fiber) || "Component"); - didWarnAboutDeprecatedLifecycles.add(fiber.type); - }); - - var _sortedNames = Array.from(_uniqueNames) - .sort() - .join(", "); +function startRequestCallbackTimer() { + if (enableUserTimingAPI) { + if (supportsUserTiming && !isWaitingForCallback) { + isWaitingForCallback = true; + beginMark("(Waiting for async callback...)"); + } + } +} - 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 +function stopRequestCallbackTimer(didExpire) { + if (enableUserTimingAPI) { + if (supportsUserTiming) { + isWaitingForCallback = false; + var warning$$1 = didExpire ? "React was blocked by main thread" : null; + endMark( + "(Waiting for async callback...)", + "(Waiting for async callback...)", + warning$$1 ); - - pendingComponentWillReceivePropsWarnings = []; } + } +} - if (pendingComponentWillUpdateWarnings.length > 0) { - var _uniqueNames2 = new Set(); - pendingComponentWillUpdateWarnings.forEach(function(fiber) { - _uniqueNames2.add(getComponentName(fiber) || "Component"); - didWarnAboutDeprecatedLifecycles.add(fiber.type); - }); - - var _sortedNames2 = Array.from(_uniqueNames2) - .sort() - .join(", "); +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; + } +} - 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 - ); +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); + } +} - pendingComponentWillUpdateWarnings = []; +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); + } +} - ReactStrictModeWarnings.recordDeprecationWarnings = function( - fiber, - instance - ) { - // Dedup strategy: Warn once per component. - if (didWarnAboutDeprecatedLifecycles.has(fiber.type)) { +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$$1 = "An error was thrown inside this error boundary"; + endFiberMark(fiber, null, warning$$1); + } +} - // Don't warn about react-lifecycles-compat polyfilled components. - if ( - typeof instance.componentWillMount === "function" && - instance.componentWillMount.__suppressDeprecationWarning !== true - ) { - pendingComponentWillMountWarnings.push(fiber); +function startPhaseTimer(fiber, phase) { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; } - if ( - typeof instance.componentWillReceiveProps === "function" && - instance.componentWillReceiveProps.__suppressDeprecationWarning !== true - ) { - pendingComponentWillReceivePropsWarnings.push(fiber); + clearPendingPhaseMeasurement(); + if (!beginFiberMark(fiber, phase)) { + return; } - if (typeof instance.componentWillUpdate === "function") { - pendingComponentWillUpdateWarnings.push(fiber); + currentPhaseFiber = fiber; + currentPhase = phase; + } +} + +function stopPhaseTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; } - }; + if (currentPhase !== null && currentPhaseFiber !== null) { + var warning$$1 = hasScheduledUpdateInCurrentPhase + ? "Scheduled a cascading update" + : null; + endFiberMark(currentPhaseFiber, currentPhase, warning$$1); + } + currentPhase = null; + currentPhaseFiber = null; + } +} - ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function( - fiber, - instance - ) { - var strictRoot = getStrictRoot(fiber); +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(); + } +} - // 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)) { +function stopWorkLoopTimer(interruptedBy) { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { return; } + var warning$$1 = null; + if (interruptedBy !== null) { + if (interruptedBy.tag === HostRoot) { + warning$$1 = "A top-level update interrupted the previous render"; + } else { + var componentName = getComponentName(interruptedBy) || "Unknown"; + warning$$1 = + "An update to " + componentName + " interrupted the previous render"; + } + } else if (commitCountInCurrentWorkLoop > 1) { + warning$$1 = "There were cascading updates"; + } + commitCountInCurrentWorkLoop = 0; + // Pause any measurements until the next loop. + pauseTimers(); + endMark( + "(React Tree Reconciliation)", + "(React Tree Reconciliation)", + warning$$1 + ); + } +} - // Don't warn about react-lifecycles-compat polyfilled components. - // Note that it is sufficient to check for the presence of a - // single lifecycle, componentWillMount, with the polyfill flag. - if ( - typeof instance.componentWillMount === "function" && - instance.componentWillMount.__suppressDeprecationWarning === true - ) { +function startCommitTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { return; } + isCommitting = true; + hasScheduledUpdateInCurrentCommit = false; + labelsInCurrentCommit.clear(); + beginMark("(Committing Changes)"); + } +} - var warningsForRoot = void 0; - if (!pendingUnsafeLifecycleWarnings.has(strictRoot)) { - warningsForRoot = { - UNSAFE_componentWillMount: [], - UNSAFE_componentWillReceiveProps: [], - UNSAFE_componentWillUpdate: [] - }; +function stopCommitTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } - pendingUnsafeLifecycleWarnings.set(strictRoot, warningsForRoot); - } else { - warningsForRoot = pendingUnsafeLifecycleWarnings.get(strictRoot); + var warning$$1 = null; + if (hasScheduledUpdateInCurrentCommit) { + warning$$1 = "Lifecycle hook scheduled a cascading update"; + } else if (commitCountInCurrentWorkLoop > 0) { + warning$$1 = "Caused by a cascading update in earlier commit"; } + hasScheduledUpdateInCurrentCommit = false; + commitCountInCurrentWorkLoop++; + isCommitting = false; + labelsInCurrentCommit.clear(); - var unsafeLifecycles = []; - if ( - typeof instance.componentWillMount === "function" || - typeof instance.UNSAFE_componentWillMount === "function" - ) { - unsafeLifecycles.push("UNSAFE_componentWillMount"); + endMark("(Committing Changes)", "(Committing Changes)", warning$$1); + } +} + +function startCommitHostEffectsTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; } - if ( - typeof instance.componentWillReceiveProps === "function" || - typeof instance.UNSAFE_componentWillReceiveProps === "function" - ) { - unsafeLifecycles.push("UNSAFE_componentWillReceiveProps"); + effectCountInCurrentCommit = 0; + beginMark("(Committing Host Effects)"); + } +} + +function stopCommitHostEffectsTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; } - if ( - typeof instance.componentWillUpdate === "function" || - typeof instance.UNSAFE_componentWillUpdate === "function" - ) { - unsafeLifecycles.push("UNSAFE_componentWillUpdate"); + 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)"); + } +} - if (unsafeLifecycles.length > 0) { - unsafeLifecycles.forEach(function(lifecycle) { - warningsForRoot[lifecycle].push(fiber); - }); +function stopCommitLifeCyclesTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; } - }; + var count = effectCountInCurrentCommit; + effectCountInCurrentCommit = 0; + endMark( + "(Calling Lifecycle Methods: " + count + " Total)", + "(Calling Lifecycle Methods)", + null + ); + } } var didWarnUpdateInsideUpdate = void 0; @@ -6430,12 +6105,20 @@ function callGetDerivedStateFromCatch(ctor, capturedValues) { } var ReactFiberClassComponent = function( + legacyContext, scheduleWork, computeExpirationForFiber, memoizeProps, memoizeState ) { + var cacheContext = legacyContext.cacheContext, + getMaskedContext = legacyContext.getMaskedContext, + getUnmaskedContext = legacyContext.getUnmaskedContext, + isContextConsumer = legacyContext.isContextConsumer, + hasContextChanged = legacyContext.hasContextChanged; + // Class component state updater + var updater = { isMounted: isMounted, enqueueSetState: function(instance, partialState, callback) { @@ -8568,84 +8251,19 @@ function cloneChildFibers(current, workInProgress) { 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 changedBitsStack = []; -var currentValueStack = []; -var stack = []; -var index$1 = -1; - -var rendererSigil = void 0; -{ - // Use this to detect multiple renderers using the same context - rendererSigil = {}; -} - -function pushProvider(providerFiber) { - var context = providerFiber.type.context; - index$1 += 1; - changedBitsStack[index$1] = context._changedBits; - currentValueStack[index$1] = context._currentValue; - stack[index$1] = providerFiber; - context._currentValue = providerFiber.pendingProps.value; - context._changedBits = providerFiber.stateNode; - - { - warning( - context._currentRenderer === null || - context._currentRenderer === rendererSigil, - "Detected multiple renderers concurrently rendering the " + - "same context provider. This is currently unsupported." - ); - context._currentRenderer = rendererSigil; - } -} - -function popProvider(providerFiber) { - { - warning( - index$1 > -1 && providerFiber === stack[index$1], - "Unexpected pop." - ); - } - var changedBits = changedBitsStack[index$1]; - var currentValue = currentValueStack[index$1]; - changedBitsStack[index$1] = null; - currentValueStack[index$1] = null; - stack[index$1] = null; - index$1 -= 1; - var context = providerFiber.type.context; - context._currentValue = currentValue; - context._changedBits = changedBits; -} + workInProgress.child = newChild; -function resetProviderStack() { - for (var i = index$1; i > -1; i--) { - var providerFiber = stack[i]; - var context = providerFiber.type.context; - context._currentValue = context._defaultValue; - context._changedBits = 0; - changedBitsStack[i] = null; - currentValueStack[i] = null; - stack[i] = null; - { - context._currentRenderer = null; - } + newChild["return"] = workInProgress; + while (currentChild.sibling !== null) { + currentChild = currentChild.sibling; + newChild = newChild.sibling = createWorkInProgress( + currentChild, + currentChild.pendingProps, + currentChild.expirationTime + ); + newChild["return"] = workInProgress; } - index$1 = -1; + newChild.sibling = null; } var didWarnAboutBadClass = void 0; @@ -8661,6 +8279,8 @@ var didWarnAboutStatelessRefs = void 0; var ReactFiberBeginWork = function( config, hostContext, + legacyContext, + newContext, hydrationContext, scheduleWork, computeExpirationForFiber @@ -8669,12 +8289,20 @@ var ReactFiberBeginWork = function( shouldDeprioritizeSubtree = config.shouldDeprioritizeSubtree; var pushHostContext = hostContext.pushHostContext, pushHostContainer = hostContext.pushHostContainer; + var pushProvider = newContext.pushProvider; + var getMaskedContext = legacyContext.getMaskedContext, + getUnmaskedContext = legacyContext.getUnmaskedContext, + hasLegacyContextChanged = legacyContext.hasContextChanged, + pushLegacyContextProvider = legacyContext.pushContextProvider, + pushTopLevelContextObject = legacyContext.pushTopLevelContextObject, + invalidateContextProvider = legacyContext.invalidateContextProvider; var enterHydrationState = hydrationContext.enterHydrationState, resetHydrationState = hydrationContext.resetHydrationState, tryToClaimNextHydratableInstance = hydrationContext.tryToClaimNextHydratableInstance; var _ReactFiberClassCompo = ReactFiberClassComponent( + legacyContext, scheduleWork, computeExpirationForFiber, memoizeProps, @@ -8742,7 +8370,7 @@ var ReactFiberBeginWork = function( function updateFragment(current, workInProgress) { var nextChildren = workInProgress.pendingProps; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // Normally we can bail out on props equality but if context has changed // we don't do the bailout and we have to reuse existing props instead. } else if (workInProgress.memoizedProps === nextChildren) { @@ -8755,7 +8383,7 @@ var ReactFiberBeginWork = function( function updateMode(current, workInProgress) { var nextChildren = workInProgress.pendingProps.children; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // Normally we can bail out on props equality but if context has changed // we don't do the bailout and we have to reuse existing props instead. } else if ( @@ -8784,7 +8412,7 @@ var ReactFiberBeginWork = function( var fn = workInProgress.type; var nextProps = workInProgress.pendingProps; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // Normally we can bail out on props equality but if context has changed // we don't do the bailout and we have to reuse existing props instead. } else { @@ -8817,7 +8445,7 @@ var ReactFiberBeginWork = function( // 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 = pushContextProvider(workInProgress); + var hasContext = pushLegacyContextProvider(workInProgress); var shouldUpdate = void 0; if (current === null) { if (workInProgress.stateNode === null) { @@ -9042,7 +8670,7 @@ var ReactFiberBeginWork = function( var nextProps = workInProgress.pendingProps; var prevProps = current !== null ? current.memoizedProps : null; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // Normally we can bail out on props equality but if context has changed // we don't do the bailout and we have to reuse existing props instead. } else if (memoizedProps === nextProps) { @@ -9177,7 +8805,7 @@ var ReactFiberBeginWork = function( // 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 = pushContextProvider(workInProgress); + var hasContext = pushLegacyContextProvider(workInProgress); adoptClassInstance(workInProgress, value); mountClassInstance(workInProgress, renderExpirationTime); return finishClassComponent( @@ -9250,7 +8878,7 @@ var ReactFiberBeginWork = function( function updateCallComponent(current, workInProgress, renderExpirationTime) { var nextProps = workInProgress.pendingProps; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // Normally we can bail out on props equality but if context has changed // we don't do the bailout and we have to reuse existing props instead. } else if (workInProgress.memoizedProps === nextProps) { @@ -9293,7 +8921,7 @@ var ReactFiberBeginWork = function( ) { pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); var nextChildren = workInProgress.pendingProps; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // Normally we can bail out on props equality but if context has changed // we don't do the bailout and we have to reuse existing props instead. } else if (workInProgress.memoizedProps === nextChildren) { @@ -9327,6 +8955,10 @@ var ReactFiberBeginWork = function( 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. @@ -9419,7 +9051,7 @@ var ReactFiberBeginWork = function( var newProps = workInProgress.pendingProps; var oldProps = workInProgress.memoizedProps; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // Normally we can bail out on props equality but if context has changed // we don't do the bailout and we have to reuse existing props instead. } else if (oldProps === newProps) { @@ -9515,7 +9147,7 @@ var ReactFiberBeginWork = function( var newValue = context._currentValue; var changedBits = context._changedBits; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // Normally we can bail out on props equality but if context has changed // we don't do the bailout and we have to reuse existing props instead. } else if (changedBits === 0 && oldProps === newProps) { @@ -9612,7 +9244,7 @@ var ReactFiberBeginWork = function( pushHostRootContext(workInProgress); break; case ClassComponent: - pushContextProvider(workInProgress); + pushLegacyContextProvider(workInProgress); break; case HostPortal: pushHostContainer( @@ -9725,7 +9357,13 @@ var ReactFiberBeginWork = function( }; }; -var ReactFiberCompleteWork = function(config, hostContext, hydrationContext) { +var ReactFiberCompleteWork = function( + config, + hostContext, + legacyContext, + newContext, + hydrationContext +) { var createInstance = config.createInstance, createTextInstance = config.createTextInstance, appendInitialChild = config.appendInitialChild, @@ -9737,6 +9375,9 @@ var ReactFiberCompleteWork = function(config, hostContext, hydrationContext) { popHostContext = hostContext.popHostContext, getHostContext = hostContext.getHostContext, popHostContainer = hostContext.popHostContainer; + var popLegacyContextProvider = legacyContext.popContextProvider, + popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject; + var popProvider = newContext.popProvider; var prepareToHydrateHostInstance = hydrationContext.prepareToHydrateHostInstance, prepareToHydrateHostTextInstance = @@ -10052,7 +9693,7 @@ var ReactFiberCompleteWork = function(config, hostContext, hydrationContext) { return null; case ClassComponent: { // We are leaving this subtree, so pop context if any. - popContextProvider(workInProgress); + popLegacyContextProvider(workInProgress); // If this component caught an error, schedule an error log effect. var instance = workInProgress.stateNode; @@ -10071,7 +9712,7 @@ var ReactFiberCompleteWork = function(config, hostContext, hydrationContext) { } case HostRoot: { popHostContainer(workInProgress); - popTopLevelContextObject(workInProgress); + popTopLevelLegacyContextObject(workInProgress); var fiberRoot = workInProgress.stateNode; if (fiberRoot.pendingContext) { fiberRoot.context = fiberRoot.pendingContext; @@ -10298,11 +9939,16 @@ function createCapturedValue(value, source) { var ReactFiberUnwindWork = function( hostContext, + legacyContext, + newContext, scheduleWork, isAlreadyFailedLegacyErrorBoundary ) { var popHostContainer = hostContext.popHostContainer, popHostContext = hostContext.popHostContext; + var popLegacyContextProvider = legacyContext.popContextProvider, + popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject; + var popProvider = newContext.popProvider; function throwException(returnFiber, sourceFiber, rawValue) { // The source fiber did not complete. @@ -10358,7 +10004,7 @@ var ReactFiberUnwindWork = function( function unwindWork(workInProgress) { switch (workInProgress.tag) { case ClassComponent: { - popContextProvider(workInProgress); + popLegacyContextProvider(workInProgress); var effectTag = workInProgress.effectTag; if (effectTag & ShouldCapture) { workInProgress.effectTag = (effectTag & ~ShouldCapture) | DidCapture; @@ -10368,7 +10014,7 @@ var ReactFiberUnwindWork = function( } case HostRoot: { popHostContainer(workInProgress); - popTopLevelContextObject(workInProgress); + popTopLevelLegacyContextObject(workInProgress); var _effectTag = workInProgress.effectTag; if (_effectTag & ShouldCapture) { workInProgress.effectTag = (_effectTag & ~ShouldCapture) | DidCapture; @@ -10390,9 +10036,37 @@ var ReactFiberUnwindWork = function( return null; } } + + function unwindInterruptedWork(interruptedWork) { + switch (interruptedWork.tag) { + case ClassComponent: { + popLegacyContextProvider(interruptedWork); + break; + } + case HostRoot: { + popHostContainer(interruptedWork); + popTopLevelLegacyContextObject(interruptedWork); + break; + } + case HostComponent: { + popHostContext(interruptedWork); + break; + } + case HostPortal: + popHostContainer(interruptedWork); + break; + case ContextProvider: + popProvider(interruptedWork); + break; + default: + break; + } + } + return { throwException: throwException, - unwindWork: unwindWork + unwindWork: unwindWork, + unwindInterruptedWork: unwindInterruptedWork }; }; @@ -10758,7 +10432,7 @@ var ReactFiberCommitWork = function( warning( false, "Unexpected ref object provided for %s. " + - "Use either a ref-setter function or Reacte.createRef().%s", + "Use either a ref-setter function or React.createRef().%s", getComponentName(finishedWork), getStackAddendumByWorkInProgressFiber(finishedWork) ); @@ -11264,9 +10938,12 @@ var ReactFiberCommitWork = function( var NO_CONTEXT = {}; -var ReactFiberHostContext = function(config) { +var ReactFiberHostContext = function(config, stack) { var getChildHostContext = config.getChildHostContext, getRootHostContext = config.getRootHostContext; + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop; var contextStackCursor = createCursor(NO_CONTEXT); var contextFiberStackCursor = createCursor(NO_CONTEXT); @@ -11337,19 +11014,13 @@ var ReactFiberHostContext = function(config) { pop(contextFiberStackCursor, fiber); } - function resetHostContainer() { - contextStackCursor.current = NO_CONTEXT; - rootInstanceStackCursor.current = NO_CONTEXT; - } - return { getHostContext: getHostContext, getRootHostContainer: getRootHostContainer, popHostContainer: popHostContainer, popHostContext: popHostContext, pushHostContainer: pushHostContainer, - pushHostContext: pushHostContext, - resetHostContainer: resetHostContainer + pushHostContext: pushHostContext }; }; @@ -11719,6 +11390,425 @@ var ReactFiberInstrumentation = { var ReactFiberInstrumentation_1 = ReactFiberInstrumentation; +var warnedAboutMissingGetChildContext = void 0; + +{ + warnedAboutMissingGetChildContext = {}; +} + +var ReactFiberLegacyContext = function(stack) { + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop; + + // A cursor to the current merged context object on the stack. + + var contextStackCursor = createCursor(emptyObject); + // 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 = emptyObject; + + function getUnmaskedContext(workInProgress) { + var hasOwnContext = isContextProvider(workInProgress); + if (hasOwnContext) { + // If the fiber is a context provider itself, when we read its context + // we 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 emptyObject; + } + + // 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(workInProgress) || "Unknown"; + checkPropTypes( + contextTypes, + context, + "context", + name, + ReactDebugCurrentFiber.getCurrentFiberStackAddendum + ); + } + + // 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 isContextConsumer(fiber) { + return fiber.tag === ClassComponent && fiber.type.contextTypes != null; + } + + function isContextProvider(fiber) { + return fiber.tag === ClassComponent && fiber.type.childContextTypes != null; + } + + function popContextProvider(fiber) { + if (!isContextProvider(fiber)) { + return; + } + + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); + } + + function popTopLevelContextObject(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); + } + + function pushTopLevelContextObject(fiber, context, didChange) { + invariant( + contextStackCursor.cursor == null, + "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, parentContext) { + var instance = fiber.stateNode; + var childContextTypes = fiber.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(fiber) || "Unknown"; + + if (!warnedAboutMissingGetChildContext[componentName]) { + warnedAboutMissingGetChildContext[componentName] = true; + warning( + 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; + { + ReactDebugCurrentFiber.setCurrentPhase("getChildContext"); + } + startPhaseTimer(fiber, "getChildContext"); + childContext = instance.getChildContext(); + stopPhaseTimer(); + { + ReactDebugCurrentFiber.setCurrentPhase(null); + } + for (var contextKey in childContext) { + invariant( + contextKey in childContextTypes, + '%s.getChildContext(): key "%s" is not defined in childContextTypes.', + getComponentName(fiber) || "Unknown", + contextKey + ); + } + { + var name = getComponentName(fiber) || "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. + ReactDebugCurrentFiber.getCurrentFiberStackAddendum + ); + } + + return Object.assign({}, parentContext, childContext); + } + + function pushContextProvider(workInProgress) { + if (!isContextProvider(workInProgress)) { + return false; + } + + 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) || + emptyObject; + + // 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, didChange) { + var instance = workInProgress.stateNode; + invariant( + instance, + "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, 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 + invariant( + isFiberMounted(fiber) && fiber.tag === ClassComponent, + "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; + while (node.tag !== HostRoot) { + if (isContextProvider(node)) { + return node.stateNode.__reactInternalMemoizedMergedChildContext; + } + var parent = node["return"]; + invariant( + parent, + "Found unexpected detached subtree parent. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + node = parent; + } + return node.stateNode.context; + } + + return { + getUnmaskedContext: getUnmaskedContext, + cacheContext: cacheContext, + getMaskedContext: getMaskedContext, + hasContextChanged: hasContextChanged, + isContextConsumer: isContextConsumer, + isContextProvider: isContextProvider, + popContextProvider: popContextProvider, + popTopLevelContextObject: popTopLevelContextObject, + pushTopLevelContextObject: pushTopLevelContextObject, + processChildContext: processChildContext, + pushContextProvider: pushContextProvider, + invalidateContextProvider: invalidateContextProvider, + findCurrentUnmaskedContext: findCurrentUnmaskedContext + }; +}; + +var ReactFiberNewContext = function(stack) { + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop; + + var providerCursor = createCursor(null); + var valueCursor = createCursor(null); + var changedBitsCursor = createCursor(0); + + var rendererSigil = void 0; + { + // Use this to detect multiple renderers using the same context + rendererSigil = {}; + } + + function pushProvider(providerFiber) { + var context = providerFiber.type.context; + + push(changedBitsCursor, context._changedBits, providerFiber); + push(valueCursor, context._currentValue, providerFiber); + push(providerCursor, providerFiber, providerFiber); + + context._currentValue = providerFiber.pendingProps.value; + context._changedBits = providerFiber.stateNode; + + { + warning( + context._currentRenderer === null || + context._currentRenderer === rendererSigil, + "Detected multiple renderers concurrently rendering the " + + "same context provider. This is currently unsupported." + ); + context._currentRenderer = rendererSigil; + } + } + + function popProvider(providerFiber) { + var changedBits = changedBitsCursor.current; + var currentValue = valueCursor.current; + + pop(providerCursor, providerFiber); + pop(valueCursor, providerFiber); + pop(changedBitsCursor, providerFiber); + + var context = providerFiber.type.context; + context._currentValue = currentValue; + context._changedBits = changedBits; + } + + return { + pushProvider: pushProvider, + popProvider: popProvider + }; +}; + +var ReactFiberStack = function() { + var valueStack = []; + + var fiberStack = void 0; + + { + fiberStack = []; + } + + var index = -1; + + function createCursor(defaultValue) { + return { + current: defaultValue + }; + } + + function isEmpty() { + return index === -1; + } + + function pop(cursor, fiber) { + if (index < 0) { + { + warning(false, "Unexpected pop."); + } + return; + } + + { + if (fiber !== fiberStack[index]) { + warning(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; + } + + function checkThatStackIsEmpty() { + { + if (index !== -1) { + warning( + false, + "Expected an empty stack. Something was not reset properly." + ); + } + } + } + + function resetStackAfterFatalErrorInDev() { + { + index = -1; + valueStack.length = 0; + fiberStack.length = 0; + } + } + + return { + createCursor: createCursor, + isEmpty: isEmpty, + pop: pop, + push: push, + checkThatStackIsEmpty: checkThatStackIsEmpty, + resetStackAfterFatalErrorInDev: resetStackAfterFatalErrorInDev + }; +}; + var invokeGuardedCallback$2 = ReactErrorUtils.invokeGuardedCallback; var hasCaughtError = ReactErrorUtils.hasCaughtError; var clearCaughtError = ReactErrorUtils.clearCaughtError; @@ -11779,16 +11869,23 @@ var warnAboutInvalidUpdates = void 0; } var ReactFiberScheduler = function(config) { - var hostContext = ReactFiberHostContext(config); + var stack = ReactFiberStack(); + var hostContext = ReactFiberHostContext(config, stack); + var legacyContext = ReactFiberLegacyContext(stack); + var newContext = ReactFiberNewContext(stack); var popHostContext = hostContext.popHostContext, popHostContainer = hostContext.popHostContainer; + var popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject, + popLegacyContextProvider = legacyContext.popContextProvider; + var popProvider = newContext.popProvider; var hydrationContext = ReactFiberHydrationContext(config); - var resetHostContainer = hostContext.resetHostContainer; var _ReactFiberBeginWork = ReactFiberBeginWork( config, hostContext, + legacyContext, + newContext, hydrationContext, scheduleWork, computeExpirationForFiber @@ -11798,17 +11895,22 @@ var ReactFiberScheduler = function(config) { var _ReactFiberCompleteWo = ReactFiberCompleteWork( config, hostContext, + legacyContext, + newContext, hydrationContext ), completeWork = _ReactFiberCompleteWo.completeWork; var _ReactFiberUnwindWork = ReactFiberUnwindWork( hostContext, + legacyContext, + newContext, scheduleWork, isAlreadyFailedLegacyErrorBoundary ), throwException = _ReactFiberUnwindWork.throwException, - unwindWork = _ReactFiberUnwindWork.unwindWork; + unwindWork = _ReactFiberUnwindWork.unwindWork, + unwindInterruptedWork = _ReactFiberUnwindWork.unwindInterruptedWork; var _ReactFiberCommitWork = ReactFiberCommitWork( config, @@ -11877,13 +11979,13 @@ var ReactFiberScheduler = function(config) { switch (failedUnitOfWork.tag) { case HostRoot: popHostContainer(failedUnitOfWork); - popTopLevelContextObject(failedUnitOfWork); + popTopLevelLegacyContextObject(failedUnitOfWork); break; case HostComponent: popHostContext(failedUnitOfWork); break; case ClassComponent: - popContextProvider(failedUnitOfWork); + popLegacyContextProvider(failedUnitOfWork); break; case HostPortal: popHostContainer(failedUnitOfWork); @@ -11903,18 +12005,18 @@ var ReactFiberScheduler = function(config) { }; } - function resetContextStack() { - // Reset the stack - reset(); - // Reset the cursors - resetContext(); - resetHostContainer(); - - // TODO: Unify new context implementation with other stacks - resetProviderStack(); + function resetStack() { + if (nextUnitOfWork !== null) { + var interruptedWork = nextUnitOfWork["return"]; + while (interruptedWork !== null) { + unwindInterruptedWork(interruptedWork); + interruptedWork = interruptedWork["return"]; + } + } { ReactStrictModeWarnings.discardPendingWarnings(); + stack.checkThatStackIsEmpty(); } nextRoot = null; @@ -12438,7 +12540,7 @@ var ReactFiberScheduler = function(config) { nextUnitOfWork === null ) { // Reset the stack and start working from the root. - resetContextStack(); + resetStack(); nextRoot = root; nextRenderExpirationTime = expirationTime; nextUnitOfWork = createWorkInProgress( @@ -12491,6 +12593,9 @@ var ReactFiberScheduler = function(config) { // Yield back to main thread. if (didFatal) { // There was a fatal error. + { + stack.resetStackAfterFatalErrorInDev(); + } return null; } else if (nextUnitOfWork === null) { // We reached the root. @@ -12691,7 +12796,7 @@ var ReactFiberScheduler = function(config) { ) { // This is an interruption. (Used for performance tracking.) interruptedBy = fiber; - resetContextStack(); + resetStack(); } if (nextRoot !== root || !isWorking) { requestWork(root, expirationTime); @@ -13262,7 +13367,8 @@ var ReactFiberScheduler = function(config) { syncUpdates: syncUpdates, interactiveUpdates: interactiveUpdates, flushInteractiveUpdates: flushInteractiveUpdates, - computeUniqueAsyncExpiration: computeUniqueAsyncExpiration + computeUniqueAsyncExpiration: computeUniqueAsyncExpiration, + legacyContext: legacyContext }; }; @@ -13275,18 +13381,6 @@ var didWarnAboutNestedUpdates = void 0; // 0 is PROD, 1 is DEV. // Might add PROFILE later. -function getContextForSubtree(parentComponent) { - if (!parentComponent) { - return emptyObject; - } - - var fiber = get(parentComponent); - var parentContext = findCurrentUnmaskedContext(fiber); - return isContextProvider(fiber) - ? processChildContext(fiber, parentContext) - : parentContext; -} - var ReactFiberReconciler$1 = function(config) { var getPublicInstance = config.getPublicInstance; @@ -13305,7 +13399,24 @@ var ReactFiberReconciler$1 = function(config) { deferredUpdates = _ReactFiberScheduler.deferredUpdates, syncUpdates = _ReactFiberScheduler.syncUpdates, interactiveUpdates = _ReactFiberScheduler.interactiveUpdates, - flushInteractiveUpdates = _ReactFiberScheduler.flushInteractiveUpdates; + flushInteractiveUpdates = _ReactFiberScheduler.flushInteractiveUpdates, + legacyContext = _ReactFiberScheduler.legacyContext; + + var findCurrentUnmaskedContext = legacyContext.findCurrentUnmaskedContext, + isContextProvider = legacyContext.isContextProvider, + processChildContext = legacyContext.processChildContext; + + function getContextForSubtree(parentComponent) { + if (!parentComponent) { + return emptyObject; + } + + var fiber = get(parentComponent); + var parentContext = findCurrentUnmaskedContext(fiber); + return isContextProvider(fiber) + ? processChildContext(fiber, parentContext) + : parentContext; + } function scheduleRootUpdate( current, diff --git a/Libraries/Renderer/ReactNativeRenderer-prod.js b/Libraries/Renderer/ReactNativeRenderer-prod.js index 258608b7f31a6b..f11aa6c82da4b1 100644 --- a/Libraries/Renderer/ReactNativeRenderer-prod.js +++ b/Libraries/Renderer/ReactNativeRenderer-prod.js @@ -1822,141 +1822,6 @@ function findCurrentHostFiberWithNoPortals(parent) { } return null; } -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; -} -function getStackAddendumByWorkInProgressFiber(workInProgress) { - var info = ""; - do { - a: switch (workInProgress.tag) { - case 0: - case 1: - case 2: - case 5: - var owner = workInProgress._debugOwner, - source = workInProgress._debugSource; - var JSCompiler_inline_result = getComponentName(workInProgress); - var ownerName = null; - owner && (ownerName = getComponentName(owner)); - owner = source; - JSCompiler_inline_result = - "\n in " + - (JSCompiler_inline_result || "Unknown") + - (owner - ? " (at " + - owner.fileName.replace(/^.*[\\\/]/, "") + - ":" + - owner.lineNumber + - ")" - : ownerName ? " (created by " + ownerName + ")" : ""); - break a; - default: - JSCompiler_inline_result = ""; - } - info += JSCompiler_inline_result; - workInProgress = workInProgress["return"]; - } while (workInProgress); - return info; -} -var _require = require("ReactFeatureFlags"), - enableGetDerivedStateFromCatch = _require.enableGetDerivedStateFromCatch, - debugRenderPhaseSideEffects = _require.debugRenderPhaseSideEffects, - debugRenderPhaseSideEffectsForStrictMode = - _require.debugRenderPhaseSideEffectsForStrictMode; -new Set(); -var contextStackCursor = { current: emptyObject }, - didPerformWorkStackCursor = { current: !1 }, - previousContext = emptyObject; -function getUnmaskedContext(workInProgress) { - return isContextProvider(workInProgress) - ? previousContext - : contextStackCursor.current; -} -function getMaskedContext(workInProgress, unmaskedContext) { - var contextTypes = workInProgress.type.contextTypes; - if (!contextTypes) return emptyObject; - 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(fiber) { - return 2 === fiber.tag && null != fiber.type.childContextTypes; -} -function popContextProvider(fiber) { - isContextProvider(fiber) && - (pop(didPerformWorkStackCursor, fiber), pop(contextStackCursor, fiber)); -} -function pushTopLevelContextObject(fiber, context, didChange) { - invariant( - null == contextStackCursor.cursor, - "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, parentContext) { - var instance = fiber.stateNode, - childContextTypes = fiber.type.childContextTypes; - if ("function" !== typeof instance.getChildContext) return parentContext; - instance = instance.getChildContext(); - for (var contextKey in instance) - invariant( - contextKey in childContextTypes, - '%s.getChildContext(): key "%s" is not defined in childContextTypes.', - getComponentName(fiber) || "Unknown", - contextKey - ); - return Object.assign({}, parentContext, instance); -} -function pushContextProvider(workInProgress) { - if (!isContextProvider(workInProgress)) return !1; - var instance = workInProgress.stateNode; - instance = - (instance && instance.__reactInternalMemoizedMergedChildContext) || - emptyObject; - previousContext = contextStackCursor.current; - push(contextStackCursor, instance, workInProgress); - push( - didPerformWorkStackCursor, - didPerformWorkStackCursor.current, - workInProgress - ); - return !0; -} -function invalidateContextProvider(workInProgress, didChange) { - var instance = workInProgress.stateNode; - invariant( - instance, - "Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue." - ); - if (didChange) { - var mergedContext = processChildContext(workInProgress, previousContext); - instance.__reactInternalMemoizedMergedChildContext = mergedContext; - pop(didPerformWorkStackCursor, workInProgress); - pop(contextStackCursor, workInProgress); - push(contextStackCursor, mergedContext, workInProgress); - } else pop(didPerformWorkStackCursor, workInProgress); - push(didPerformWorkStackCursor, didChange, workInProgress); -} function FiberNode(tag, pendingProps, key, mode) { this.tag = tag; this.key = key; @@ -2123,6 +1988,45 @@ function onCommitRoot(root) { function onCommitUnmount(fiber) { "function" === typeof onCommitFiberUnmount && onCommitFiberUnmount(fiber); } +function getStackAddendumByWorkInProgressFiber(workInProgress) { + var info = ""; + do { + a: switch (workInProgress.tag) { + case 0: + case 1: + case 2: + case 5: + var owner = workInProgress._debugOwner, + source = workInProgress._debugSource; + var JSCompiler_inline_result = getComponentName(workInProgress); + var ownerName = null; + owner && (ownerName = getComponentName(owner)); + owner = source; + JSCompiler_inline_result = + "\n in " + + (JSCompiler_inline_result || "Unknown") + + (owner + ? " (at " + + owner.fileName.replace(/^.*[\\\/]/, "") + + ":" + + owner.lineNumber + + ")" + : ownerName ? " (created by " + ownerName + ")" : ""); + break a; + default: + JSCompiler_inline_result = ""; + } + info += JSCompiler_inline_result; + workInProgress = workInProgress["return"]; + } while (workInProgress); + return info; +} +var _require = require("ReactFeatureFlags"), + enableGetDerivedStateFromCatch = _require.enableGetDerivedStateFromCatch, + debugRenderPhaseSideEffects = _require.debugRenderPhaseSideEffects, + debugRenderPhaseSideEffectsForStrictMode = + _require.debugRenderPhaseSideEffectsForStrictMode; +new Set(); function createUpdateQueue(baseState) { return { baseState: baseState, @@ -2294,6 +2198,7 @@ function callGetDerivedStateFromCatch(ctor, capturedValues) { return resultState; } function ReactFiberClassComponent( + legacyContext, scheduleWork, computeExpirationForFiber, memoizeProps, @@ -2360,62 +2265,66 @@ function ReactFiberClassComponent( ) ); } - var updater = { - isMounted: isMounted, - enqueueSetState: function(instance, partialState, callback) { - instance = instance._reactInternalFiber; - callback = void 0 === callback ? null : callback; - var expirationTime = computeExpirationForFiber(instance); - insertUpdateIntoFiber(instance, { - expirationTime: expirationTime, - partialState: partialState, - callback: callback, - isReplace: !1, - isForced: !1, - capturedValue: null, - next: null - }); - scheduleWork(instance, expirationTime); - }, - enqueueReplaceState: function(instance, state, callback) { - instance = instance._reactInternalFiber; - callback = void 0 === callback ? null : callback; - var expirationTime = computeExpirationForFiber(instance); - insertUpdateIntoFiber(instance, { - expirationTime: expirationTime, - partialState: state, - callback: callback, - isReplace: !0, - isForced: !1, - capturedValue: null, - next: null - }); - scheduleWork(instance, expirationTime); - }, - enqueueForceUpdate: function(instance, callback) { - instance = instance._reactInternalFiber; - callback = void 0 === callback ? null : callback; - var expirationTime = computeExpirationForFiber(instance); - insertUpdateIntoFiber(instance, { - expirationTime: expirationTime, - partialState: null, - callback: callback, - isReplace: !1, - isForced: !0, - capturedValue: null, - next: null - }); - scheduleWork(instance, expirationTime); - } - }; + var cacheContext = legacyContext.cacheContext, + getMaskedContext = legacyContext.getMaskedContext, + getUnmaskedContext = legacyContext.getUnmaskedContext, + isContextConsumer = legacyContext.isContextConsumer, + hasContextChanged = legacyContext.hasContextChanged, + updater = { + isMounted: isMounted, + enqueueSetState: function(instance, partialState, callback) { + instance = instance._reactInternalFiber; + callback = void 0 === callback ? null : callback; + var expirationTime = computeExpirationForFiber(instance); + insertUpdateIntoFiber(instance, { + expirationTime: expirationTime, + partialState: partialState, + callback: callback, + isReplace: !1, + isForced: !1, + capturedValue: null, + next: null + }); + scheduleWork(instance, expirationTime); + }, + enqueueReplaceState: function(instance, state, callback) { + instance = instance._reactInternalFiber; + callback = void 0 === callback ? null : callback; + var expirationTime = computeExpirationForFiber(instance); + insertUpdateIntoFiber(instance, { + expirationTime: expirationTime, + partialState: state, + callback: callback, + isReplace: !0, + isForced: !1, + capturedValue: null, + next: null + }); + scheduleWork(instance, expirationTime); + }, + enqueueForceUpdate: function(instance, callback) { + instance = instance._reactInternalFiber; + callback = void 0 === callback ? null : callback; + var expirationTime = computeExpirationForFiber(instance); + insertUpdateIntoFiber(instance, { + expirationTime: expirationTime, + partialState: null, + callback: callback, + isReplace: !1, + isForced: !0, + capturedValue: null, + next: null + }); + scheduleWork(instance, expirationTime); + } + }; return { adoptClassInstance: adoptClassInstance, callGetDerivedStateFromProps: callGetDerivedStateFromProps, constructClassInstance: function(workInProgress, props) { var ctor = workInProgress.type, unmaskedContext = getUnmaskedContext(workInProgress), - needsContext = - 2 === workInProgress.tag && null != workInProgress.type.contextTypes, + needsContext = isContextConsumer(workInProgress), context = needsContext ? getMaskedContext(workInProgress, unmaskedContext) : emptyObject; @@ -2436,10 +2345,7 @@ function ReactFiberClassComponent( workInProgress.memoizedState, props )); - needsContext && - ((workInProgress = workInProgress.stateNode), - (workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext), - (workInProgress.__reactInternalMemoizedMaskedChildContext = context)); + needsContext && cacheContext(workInProgress, unmaskedContext, context); return ctor; }, mountClassInstance: function(workInProgress, renderExpirationTime) { @@ -2539,7 +2445,7 @@ function ReactFiberClassComponent( !( oldProps !== newProps || oldState !== renderExpirationTime || - didPerformWorkStackCursor.current || + hasContextChanged() || (null !== workInProgress.updateQueue && workInProgress.updateQueue.hasForceUpdate) ) @@ -2643,7 +2549,7 @@ function ReactFiberClassComponent( !( oldProps !== newProps || oldContext !== renderExpirationTime || - didPerformWorkStackCursor.current || + hasContextChanged() || (null !== workInProgress.updateQueue && workInProgress.updateQueue.hasForceUpdate) ) @@ -3366,34 +3272,12 @@ function ChildReconciler(shouldTrackSideEffects) { }; } var reconcileChildFibers = ChildReconciler(!0), - mountChildFibers = ChildReconciler(!1), - changedBitsStack = [], - currentValueStack = [], - stack = [], - index$1 = -1; -function pushProvider(providerFiber) { - var context = providerFiber.type.context; - index$1 += 1; - changedBitsStack[index$1] = context._changedBits; - currentValueStack[index$1] = context._currentValue; - stack[index$1] = providerFiber; - context._currentValue = providerFiber.pendingProps.value; - context._changedBits = providerFiber.stateNode; -} -function popProvider(providerFiber) { - var changedBits = changedBitsStack[index$1], - currentValue = currentValueStack[index$1]; - changedBitsStack[index$1] = null; - currentValueStack[index$1] = null; - stack[index$1] = null; - --index$1; - providerFiber = providerFiber.type.context; - providerFiber._currentValue = currentValue; - providerFiber._changedBits = changedBits; -} + mountChildFibers = ChildReconciler(!1); function ReactFiberBeginWork( config, hostContext, + legacyContext, + newContext, hydrationContext, scheduleWork, computeExpirationForFiber @@ -3499,7 +3383,12 @@ function ReactFiberBeginWork( changedBits, renderExpirationTime ) { - for (var fiber = workInProgress.child; null !== fiber; ) { + var fiber = workInProgress.child; + for ( + null !== fiber && (fiber["return"] = workInProgress); + null !== fiber; + + ) { switch (fiber.tag) { case 12: var nextFiber = fiber.stateNode | 0; @@ -3558,7 +3447,7 @@ function ReactFiberBeginWork( var context = workInProgress.type.context, newProps = workInProgress.pendingProps, oldProps = workInProgress.memoizedProps; - if (!didPerformWorkStackCursor.current && oldProps === newProps) + if (!hasLegacyContextChanged() && oldProps === newProps) return ( (workInProgress.stateNode = 0), pushProvider(workInProgress), @@ -3645,11 +3534,19 @@ function ReactFiberBeginWork( shouldDeprioritizeSubtree = config.shouldDeprioritizeSubtree, pushHostContext = hostContext.pushHostContext, pushHostContainer = hostContext.pushHostContainer, + pushProvider = newContext.pushProvider, + getMaskedContext = legacyContext.getMaskedContext, + getUnmaskedContext = legacyContext.getUnmaskedContext, + hasLegacyContextChanged = legacyContext.hasContextChanged, + pushLegacyContextProvider = legacyContext.pushContextProvider, + pushTopLevelContextObject = legacyContext.pushTopLevelContextObject, + invalidateContextProvider = legacyContext.invalidateContextProvider, enterHydrationState = hydrationContext.enterHydrationState, resetHydrationState = hydrationContext.resetHydrationState, tryToClaimNextHydratableInstance = hydrationContext.tryToClaimNextHydratableInstance; config = ReactFiberClassComponent( + legacyContext, scheduleWork, computeExpirationForFiber, function(workInProgress, nextProps) { @@ -3676,7 +3573,7 @@ function ReactFiberBeginWork( pushHostRootContext(workInProgress); break; case 2: - pushContextProvider(workInProgress); + pushLegacyContextProvider(workInProgress); break; case 4: pushHostContainer( @@ -3722,7 +3619,7 @@ function ReactFiberBeginWork( workInProgress.memoizedState, props ))), - (props = pushContextProvider(workInProgress)), + (props = pushLegacyContextProvider(workInProgress)), adoptClassInstance(workInProgress, fn), mountClassInstance(workInProgress, renderExpirationTime), (current = finishClassComponent( @@ -3742,7 +3639,7 @@ function ReactFiberBeginWork( return ( (props = workInProgress.type), (renderExpirationTime = workInProgress.pendingProps), - didPerformWorkStackCursor.current || + hasLegacyContextChanged() || workInProgress.memoizedProps !== renderExpirationTime ? ((fn = getUnmaskedContext(workInProgress)), (fn = getMaskedContext(workInProgress, fn)), @@ -3758,7 +3655,7 @@ function ReactFiberBeginWork( current ); case 2: - props = pushContextProvider(workInProgress); + props = pushLegacyContextProvider(workInProgress); null === current ? null === workInProgress.stateNode ? (constructClassInstance( @@ -3840,7 +3737,7 @@ function ReactFiberBeginWork( updateQueue = workInProgress.memoizedProps; fn = workInProgress.pendingProps; unmaskedContext = null !== current ? current.memoizedProps : null; - if (!didPerformWorkStackCursor.current && updateQueue === fn) { + if (!hasLegacyContextChanged() && updateQueue === fn) { if ( (updateQueue = workInProgress.mode & 1 && @@ -3882,7 +3779,7 @@ function ReactFiberBeginWork( case 7: return ( (props = workInProgress.pendingProps), - didPerformWorkStackCursor.current || + hasLegacyContextChanged() || workInProgress.memoizedProps !== props || (props = workInProgress.memoizedProps), (fn = props.children), @@ -3912,8 +3809,7 @@ function ReactFiberBeginWork( workInProgress.stateNode.containerInfo ), (props = workInProgress.pendingProps), - didPerformWorkStackCursor.current || - workInProgress.memoizedProps !== props + hasLegacyContextChanged() || workInProgress.memoizedProps !== props ? (null === current ? (workInProgress.child = reconcileChildFibers( workInProgress, @@ -3944,7 +3840,7 @@ function ReactFiberBeginWork( case 10: return ( (renderExpirationTime = workInProgress.pendingProps), - didPerformWorkStackCursor.current || + hasLegacyContextChanged() || workInProgress.memoizedProps !== renderExpirationTime ? (reconcileChildren( current, @@ -3962,7 +3858,7 @@ function ReactFiberBeginWork( case 11: return ( (renderExpirationTime = workInProgress.pendingProps.children), - didPerformWorkStackCursor.current || + hasLegacyContextChanged() || (null !== renderExpirationTime && workInProgress.memoizedProps !== renderExpirationTime) ? (reconcileChildren( @@ -3992,7 +3888,7 @@ function ReactFiberBeginWork( props = fn._currentValue; var changedBits = fn._changedBits; if ( - didPerformWorkStackCursor.current || + hasLegacyContextChanged() || 0 !== changedBits || updateQueue !== unmaskedContext ) { @@ -4032,7 +3928,13 @@ function ReactFiberBeginWork( } }; } -function ReactFiberCompleteWork(config, hostContext, hydrationContext) { +function ReactFiberCompleteWork( + config, + hostContext, + legacyContext, + newContext, + hydrationContext +) { function markUpdate(workInProgress) { workInProgress.effectTag |= 4; } @@ -4046,6 +3948,9 @@ function ReactFiberCompleteWork(config, hostContext, hydrationContext) { popHostContext = hostContext.popHostContext, getHostContext = hostContext.getHostContext, popHostContainer = hostContext.popHostContainer, + popLegacyContextProvider = legacyContext.popContextProvider, + popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject, + popProvider = newContext.popProvider, prepareToHydrateHostInstance = hydrationContext.prepareToHydrateHostInstance, prepareToHydrateHostTextInstance = @@ -4074,7 +3979,7 @@ function ReactFiberCompleteWork(config, hostContext, hydrationContext) { return null; case 2: return ( - popContextProvider(workInProgress), + popLegacyContextProvider(workInProgress), (current = workInProgress.stateNode), (newProps = workInProgress.updateQueue), null !== newProps && @@ -4087,8 +3992,7 @@ function ReactFiberCompleteWork(config, hostContext, hydrationContext) { ); case 3: popHostContainer(workInProgress); - pop(didPerformWorkStackCursor, workInProgress); - pop(contextStackCursor, workInProgress); + popTopLevelLegacyContextObject(workInProgress); newProps = workInProgress.stateNode; newProps.pendingContext && ((newProps.context = newProps.pendingContext), @@ -4304,11 +4208,16 @@ function ReactFiberCompleteWork(config, hostContext, hydrationContext) { } function ReactFiberUnwindWork( hostContext, + legacyContext, + newContext, scheduleWork, isAlreadyFailedLegacyErrorBoundary ) { var popHostContainer = hostContext.popHostContainer, - popHostContext = hostContext.popHostContext; + popHostContext = hostContext.popHostContext, + popLegacyContextProvider = legacyContext.popContextProvider, + popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject, + popProvider = newContext.popProvider; return { throwException: function(returnFiber, sourceFiber, rawValue) { sourceFiber.effectTag |= 512; @@ -4352,7 +4261,7 @@ function ReactFiberUnwindWork( unwindWork: function(workInProgress) { switch (workInProgress.tag) { case 2: - popContextProvider(workInProgress); + popLegacyContextProvider(workInProgress); var effectTag = workInProgress.effectTag; return effectTag & 1024 ? ((workInProgress.effectTag = (effectTag & -1025) | 64), @@ -4361,8 +4270,7 @@ function ReactFiberUnwindWork( case 3: return ( popHostContainer(workInProgress), - pop(didPerformWorkStackCursor, workInProgress), - pop(contextStackCursor, workInProgress), + popTopLevelLegacyContextObject(workInProgress), (effectTag = workInProgress.effectTag), effectTag & 1024 ? ((workInProgress.effectTag = (effectTag & -1025) | 64), @@ -4378,6 +4286,25 @@ function ReactFiberUnwindWork( default: return null; } + }, + unwindInterruptedWork: function(interruptedWork) { + switch (interruptedWork.tag) { + case 2: + popLegacyContextProvider(interruptedWork); + break; + case 3: + popHostContainer(interruptedWork); + popTopLevelLegacyContextObject(interruptedWork); + break; + case 5: + popHostContext(interruptedWork); + break; + case 4: + popHostContainer(interruptedWork); + break; + case 13: + popProvider(interruptedWork); + } } }; } @@ -4819,7 +4746,7 @@ function ReactFiberCommitWork( }; } var NO_CONTEXT = {}; -function ReactFiberHostContext(config) { +function ReactFiberHostContext(config, stack) { function requiredContext(c) { invariant( c !== NO_CONTEXT, @@ -4828,10 +4755,13 @@ function ReactFiberHostContext(config) { return c; } var getChildHostContext = config.getChildHostContext, - getRootHostContext = config.getRootHostContext, - contextStackCursor = { current: NO_CONTEXT }, - contextFiberStackCursor = { current: NO_CONTEXT }, - rootInstanceStackCursor = { current: NO_CONTEXT }; + getRootHostContext = config.getRootHostContext; + config = stack.createCursor; + var push = stack.push, + pop = stack.pop, + contextStackCursor = config(NO_CONTEXT), + contextFiberStackCursor = config(NO_CONTEXT), + rootInstanceStackCursor = config(NO_CONTEXT); return { getHostContext: function() { return requiredContext(contextStackCursor.current); @@ -4861,10 +4791,6 @@ function ReactFiberHostContext(config) { context !== rootInstance && (push(contextFiberStackCursor, fiber, fiber), push(contextStackCursor, rootInstance, fiber)); - }, - resetHostContainer: function() { - contextStackCursor.current = NO_CONTEXT; - rootInstanceStackCursor.current = NO_CONTEXT; } }; } @@ -5024,22 +4950,198 @@ function ReactFiberHydrationContext(config) { } }; } -function ReactFiberScheduler(config) { - function resetContextStack() { - for (; -1 < index; ) (valueStack[index] = null), index--; +function ReactFiberLegacyContext(stack) { + function cacheContext(workInProgress, unmaskedContext, maskedContext) { + workInProgress = workInProgress.stateNode; + workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; + workInProgress.__reactInternalMemoizedMaskedChildContext = maskedContext; + } + function isContextProvider(fiber) { + return 2 === fiber.tag && null != fiber.type.childContextTypes; + } + function processChildContext(fiber, parentContext) { + var instance = fiber.stateNode, + childContextTypes = fiber.type.childContextTypes; + if ("function" !== typeof instance.getChildContext) return parentContext; + instance = instance.getChildContext(); + for (var contextKey in instance) + invariant( + contextKey in childContextTypes, + '%s.getChildContext(): key "%s" is not defined in childContextTypes.', + getComponentName(fiber) || "Unknown", + contextKey + ); + return Object.assign({}, parentContext, instance); + } + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop, + contextStackCursor = createCursor(emptyObject), + didPerformWorkStackCursor = createCursor(!1), previousContext = emptyObject; - contextStackCursor.current = emptyObject; - didPerformWorkStackCursor.current = !1; - resetHostContainer(); - for (var i = index$1; -1 < i; i--) { - var context = stack[i].type.context; - context._currentValue = context._defaultValue; - context._changedBits = 0; - changedBitsStack[i] = null; - currentValueStack[i] = null; - stack[i] = null; + return { + getUnmaskedContext: function(workInProgress) { + return isContextProvider(workInProgress) + ? previousContext + : contextStackCursor.current; + }, + cacheContext: cacheContext, + getMaskedContext: function(workInProgress, unmaskedContext) { + var contextTypes = workInProgress.type.contextTypes; + if (!contextTypes) return emptyObject; + var instance = workInProgress.stateNode; + if ( + instance && + instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext + ) + return instance.__reactInternalMemoizedMaskedChildContext; + var context = {}, + key; + for (key in contextTypes) context[key] = unmaskedContext[key]; + instance && cacheContext(workInProgress, unmaskedContext, context); + return context; + }, + hasContextChanged: function() { + return didPerformWorkStackCursor.current; + }, + isContextConsumer: function(fiber) { + return 2 === fiber.tag && null != fiber.type.contextTypes; + }, + isContextProvider: isContextProvider, + popContextProvider: function(fiber) { + isContextProvider(fiber) && + (pop(didPerformWorkStackCursor, fiber), pop(contextStackCursor, fiber)); + }, + popTopLevelContextObject: function(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); + }, + pushTopLevelContextObject: function(fiber, context, didChange) { + invariant( + null == contextStackCursor.cursor, + "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); + }, + processChildContext: processChildContext, + pushContextProvider: function(workInProgress) { + if (!isContextProvider(workInProgress)) return !1; + var instance = workInProgress.stateNode; + instance = + (instance && instance.__reactInternalMemoizedMergedChildContext) || + emptyObject; + previousContext = contextStackCursor.current; + push(contextStackCursor, instance, workInProgress); + push( + didPerformWorkStackCursor, + didPerformWorkStackCursor.current, + workInProgress + ); + return !0; + }, + invalidateContextProvider: function(workInProgress, didChange) { + var instance = workInProgress.stateNode; + invariant( + instance, + "Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue." + ); + if (didChange) { + var mergedContext = processChildContext( + workInProgress, + previousContext + ); + instance.__reactInternalMemoizedMergedChildContext = mergedContext; + pop(didPerformWorkStackCursor, workInProgress); + pop(contextStackCursor, workInProgress); + push(contextStackCursor, mergedContext, workInProgress); + } else pop(didPerformWorkStackCursor, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); + }, + findCurrentUnmaskedContext: function(fiber) { + for ( + invariant( + 2 === isFiberMountedImpl(fiber) && 2 === fiber.tag, + "Expected subtree parent to be a mounted class component. This error is likely caused by a bug in React. Please file an issue." + ); + 3 !== fiber.tag; + + ) { + if (isContextProvider(fiber)) + return fiber.stateNode.__reactInternalMemoizedMergedChildContext; + fiber = fiber["return"]; + invariant( + fiber, + "Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + return fiber.stateNode.context; } - index$1 = -1; + }; +} +function ReactFiberNewContext(stack) { + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop, + providerCursor = createCursor(null), + valueCursor = createCursor(null), + changedBitsCursor = createCursor(0); + return { + pushProvider: function(providerFiber) { + var context = providerFiber.type.context; + push(changedBitsCursor, context._changedBits, providerFiber); + push(valueCursor, context._currentValue, providerFiber); + push(providerCursor, providerFiber, providerFiber); + context._currentValue = providerFiber.pendingProps.value; + context._changedBits = providerFiber.stateNode; + }, + popProvider: function(providerFiber) { + var changedBits = changedBitsCursor.current, + currentValue = valueCursor.current; + pop(providerCursor, providerFiber); + pop(valueCursor, providerFiber); + pop(changedBitsCursor, providerFiber); + providerFiber = providerFiber.type.context; + providerFiber._currentValue = currentValue; + providerFiber._changedBits = changedBits; + } + }; +} +function ReactFiberStack() { + var valueStack = [], + index = -1; + return { + createCursor: function(defaultValue) { + return { current: defaultValue }; + }, + isEmpty: function() { + return -1 === index; + }, + pop: function(cursor) { + 0 > index || + ((cursor.current = valueStack[index]), + (valueStack[index] = null), + index--); + }, + push: function(cursor, value) { + index++; + valueStack[index] = cursor.current; + cursor.current = value; + }, + checkThatStackIsEmpty: function() {}, + resetStackAfterFatalErrorInDev: function() {} + }; +} +function ReactFiberScheduler(config) { + function resetStack() { + if (null !== nextUnitOfWork) + for ( + var interruptedWork = nextUnitOfWork["return"]; + null !== interruptedWork; + + ) + unwindInterruptedWork(interruptedWork), + (interruptedWork = interruptedWork["return"]); nextRoot = null; nextRenderExpirationTime = 0; nextUnitOfWork = null; @@ -5145,7 +5247,7 @@ function ReactFiberScheduler(config) { root !== nextRoot || null === nextUnitOfWork ) - resetContextStack(), + resetStack(), (nextRoot = root), (nextRenderExpirationTime = expirationTime), (nextUnitOfWork = createWorkInProgress( @@ -5275,7 +5377,7 @@ function ReactFiberScheduler(config) { !isWorking && 0 !== nextRenderExpirationTime && expirationTime < nextRenderExpirationTime && - resetContextStack(); + resetStack(); (nextRoot === root && isWorking) || requestWork(root, expirationTime); nestedUpdateCount > NESTED_UPDATE_LIMIT && @@ -5619,25 +5721,37 @@ function ReactFiberScheduler(config) { nextFlushedRoot.remainingExpirationTime = 0; hasUnhandledError || ((hasUnhandledError = !0), (unhandledError = error)); } - var hostContext = ReactFiberHostContext(config), - hydrationContext = ReactFiberHydrationContext(config), - resetHostContainer = hostContext.resetHostContainer, + var stack = ReactFiberStack(), + hostContext = ReactFiberHostContext(config, stack), + legacyContext = ReactFiberLegacyContext(stack); + stack = ReactFiberNewContext(stack); + var hydrationContext = ReactFiberHydrationContext(config), beginWork = ReactFiberBeginWork( config, hostContext, + legacyContext, + stack, hydrationContext, scheduleWork, computeExpirationForFiber ).beginWork, - completeWork = ReactFiberCompleteWork(config, hostContext, hydrationContext) - .completeWork; + completeWork = ReactFiberCompleteWork( + config, + hostContext, + legacyContext, + stack, + hydrationContext + ).completeWork; hostContext = ReactFiberUnwindWork( hostContext, + legacyContext, + stack, scheduleWork, isAlreadyFailedLegacyErrorBoundary ); var throwException = hostContext.throwException, - unwindWork = hostContext.unwindWork; + unwindWork = hostContext.unwindWork, + unwindInterruptedWork = hostContext.unwindInterruptedWork; hostContext = ReactFiberCommitWork( config, onCommitPhaseError, @@ -5796,7 +5910,8 @@ function ReactFiberScheduler(config) { result <= lastUniqueAsyncExpiration && (result = lastUniqueAsyncExpiration + 1); return (lastUniqueAsyncExpiration = result); - } + }, + legacyContext: legacyContext }; } function ReactFiberReconciler$1(config) { @@ -5811,27 +5926,7 @@ function ReactFiberReconciler$1(config) { currentTime = container.current; if (parentComponent) { parentComponent = parentComponent._reactInternalFiber; - var parentContext; - b: { - invariant( - 2 === isFiberMountedImpl(parentComponent) && - 2 === parentComponent.tag, - "Expected subtree parent to be a mounted class component. This error is likely caused by a bug in React. Please file an issue." - ); - for (parentContext = parentComponent; 3 !== parentContext.tag; ) { - if (isContextProvider(parentContext)) { - parentContext = - parentContext.stateNode.__reactInternalMemoizedMergedChildContext; - break b; - } - parentContext = parentContext["return"]; - invariant( - parentContext, - "Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue." - ); - } - parentContext = parentContext.stateNode.context; - } + var parentContext = findCurrentUnmaskedContext(parentComponent); parentComponent = isContextProvider(parentComponent) ? processChildContext(parentComponent, parentContext) : parentContext; @@ -5860,7 +5955,11 @@ function ReactFiberReconciler$1(config) { config = ReactFiberScheduler(config); var recalculateCurrentTime = config.recalculateCurrentTime, computeExpirationForFiber = config.computeExpirationForFiber, - scheduleWork = config.scheduleWork; + scheduleWork = config.scheduleWork, + legacyContext = config.legacyContext, + findCurrentUnmaskedContext = legacyContext.findCurrentUnmaskedContext, + isContextProvider = legacyContext.isContextProvider, + processChildContext = legacyContext.processChildContext; return { createContainer: function(containerInfo, isAsync, hydrate) { isAsync = new FiberNode(3, null, null, isAsync ? 3 : 0); diff --git a/Libraries/Renderer/shims/ReactFabric.js b/Libraries/Renderer/shims/ReactFabric.js index 4a396c224cd4ff..6ab336bf11f058 100644 --- a/Libraries/Renderer/shims/ReactFabric.js +++ b/Libraries/Renderer/shims/ReactFabric.js @@ -9,6 +9,8 @@ */ 'use strict'; +const BatchedBridge = require('BatchedBridge'); + // TODO @sema: Adjust types import type {ReactNativeType} from 'ReactNativeTypes'; @@ -20,4 +22,7 @@ if (__DEV__) { ReactFabric = require('ReactFabric-prod'); } +BatchedBridge.registerCallableModule('ReactFabric', ReactFabric); + module.exports = (ReactFabric: ReactNativeType); + From f68e04136c1af90a378e9f76607506edee63f906 Mon Sep 17 00:00:00 2001 From: Eli White Date: Tue, 20 Mar 2018 19:11:54 -0700 Subject: [PATCH 0099/1109] Move TypeForStyleKey from StyleSheetTypes to StyleSheet Reviewed By: yungsters Differential Revision: D7281362 fbshipit-source-id: 936d198e83dfbfc62449e82b5559a30bd57621c4 --- Libraries/StyleSheet/StyleSheet.js | 35 +++++++++++++++++++++++++ Libraries/StyleSheet/StyleSheetTypes.js | 25 +++--------------- Libraries/StyleSheet/flattenStyle.js | 6 +++-- 3 files changed, 42 insertions(+), 24 deletions(-) diff --git a/Libraries/StyleSheet/StyleSheet.js b/Libraries/StyleSheet/StyleSheet.js index f2552f3e66d1c4..db35fc8424afeb 100644 --- a/Libraries/StyleSheet/StyleSheet.js +++ b/Libraries/StyleSheet/StyleSheet.js @@ -20,6 +20,7 @@ const flatten = require('flattenStyle'); import type { ____StyleSheetInternalStyleIdentifier_Internal as StyleSheetInternalStyleIdentifier, ____Styles_Internal, + ____DangerouslyImpreciseStyle_Internal, ____DangerouslyImpreciseStyleProp_Internal, ____ViewStyleProp_Internal, ____TextStyleProp_Internal, @@ -66,6 +67,40 @@ export type ImageStyleProp = ____ImageStyleProp_Internal; */ export type DangerouslyImpreciseStyleProp = ____DangerouslyImpreciseStyleProp_Internal; +/** + * Utility type for getting the values for specific style keys. + * + * The following is bad because position is more restrictive than 'string': + * ``` + * type Props = {position: string}; + * ``` + * + * You should use the following instead: + * + * ``` + * type Props = {position: TypeForStyleKey<'position'>}; + * ``` + * + * This will correctly give you the type 'absolute' | 'relative' + */ +export type TypeForStyleKey< + +key: $Keys<____DangerouslyImpreciseStyle_Internal>, +> = $ElementType<____DangerouslyImpreciseStyle_Internal, key>; + +/** + * WARNING: You probably shouldn't be using this type. This type is an object + * with all possible style key's and their values. Note that this isn't + * a safe way to type a style prop for a component as results from + * StyleSheet.create return an internal identifier, not an object of styles. + * + * If you want to type the style prop of a function, consider using + * ViewStyleProp, TextStyleProp, or ImageStyleProp. + * + * This should only be used by very core utilities that operate on an object + * containing any possible style value. + */ +export type DangerouslyImpreciseStyle = ____DangerouslyImpreciseStyle_Internal; + let hairlineWidth = PixelRatio.roundToNearestPixel(0.4); if (hairlineWidth === 0) { hairlineWidth = 1 / PixelRatio.get(); diff --git a/Libraries/StyleSheet/StyleSheetTypes.js b/Libraries/StyleSheet/StyleSheetTypes.js index b9c3c59fd2d345..19b57c700c1844 100644 --- a/Libraries/StyleSheet/StyleSheetTypes.js +++ b/Libraries/StyleSheet/StyleSheetTypes.js @@ -213,7 +213,7 @@ export type ImageStyle = $ReadOnly<{| overlayColor?: string, |}>; -export type DangerouslyImpreciseStyle = { +export type ____DangerouslyImpreciseStyle_Internal = { ...$Exact, +resizeMode?: 'contain' | 'cover' | 'stretch' | 'center' | 'repeat', +tintColor?: ColorValue, @@ -231,7 +231,7 @@ type GenericStyleProp<+T> = | $ReadOnlyArray>; export type ____DangerouslyImpreciseStyleProp_Internal = GenericStyleProp< - $Shape, + $Shape<____DangerouslyImpreciseStyle_Internal>, >; export type ____ViewStyleProp_Internal = GenericStyleProp< $ReadOnly<$Shape>, @@ -244,24 +244,5 @@ export type ____ImageStyleProp_Internal = GenericStyleProp< >; export type ____Styles_Internal = { - +[key: string]: $Shape, + +[key: string]: $Shape<____DangerouslyImpreciseStyle_Internal>, }; - -/* -Utility type get non-nullable types for specific style keys. -Useful when a component requires values for certain Style Keys. -So Instead: -``` -type Props = {position: string}; -``` -You should use: -``` -type Props = {position: TypeForStyleKey<'position'>}; -``` - -This will correctly give you the type 'absolute' | 'relative' instead of the -weak type of just string; -*/ -export type TypeForStyleKey< - +key: $Keys, -> = $ElementType; diff --git a/Libraries/StyleSheet/flattenStyle.js b/Libraries/StyleSheet/flattenStyle.js index 37ac2d434a0fb4..3ef381d0b6a298 100644 --- a/Libraries/StyleSheet/flattenStyle.js +++ b/Libraries/StyleSheet/flattenStyle.js @@ -12,8 +12,10 @@ var ReactNativePropRegistry; -import type {DangerouslyImpreciseStyleProp} from 'StyleSheet'; -import type {DangerouslyImpreciseStyle} from 'StyleSheetTypes'; +import type { + DangerouslyImpreciseStyle, + DangerouslyImpreciseStyleProp, +} from 'StyleSheet'; function getStyle(style) { if (ReactNativePropRegistry === undefined) { From a0388f4adc693bfc11279a5c9513ca3ee1348ed0 Mon Sep 17 00:00:00 2001 From: Eli White Date: Tue, 20 Mar 2018 19:11:56 -0700 Subject: [PATCH 0100/1109] Move ViewStyle, TextStyle, ImageStyle from StyleSheetTypes to StyleSheet Reviewed By: yungsters Differential Revision: D7282491 fbshipit-source-id: d6b54d0a2e1fe1816b6a856b1b0b1245a655320a --- Libraries/StyleSheet/StyleSheet.js | 56 ++++++++++++++++++++++++- Libraries/StyleSheet/StyleSheetTypes.js | 18 ++++---- 2 files changed, 64 insertions(+), 10 deletions(-) diff --git a/Libraries/StyleSheet/StyleSheet.js b/Libraries/StyleSheet/StyleSheet.js index db35fc8424afeb..c2579f21a3612d 100644 --- a/Libraries/StyleSheet/StyleSheet.js +++ b/Libraries/StyleSheet/StyleSheet.js @@ -22,8 +22,11 @@ import type { ____Styles_Internal, ____DangerouslyImpreciseStyle_Internal, ____DangerouslyImpreciseStyleProp_Internal, + ____ViewStyle_Internal, ____ViewStyleProp_Internal, + ____TextStyle_Internal, ____TextStyleProp_Internal, + ____ImageStyle_Internal, ____ImageStyleProp_Internal, LayoutStyle, } from 'StyleSheetTypes'; @@ -87,9 +90,60 @@ export type TypeForStyleKey< +key: $Keys<____DangerouslyImpreciseStyle_Internal>, > = $ElementType<____DangerouslyImpreciseStyle_Internal, key>; +/** + * This type is an object of the different possible style + * properties that can be specified for View. + * + * Note that this isn't a safe way to type a style prop for a component as + * results from StyleSheet.create return an internal identifier, not + * an object of styles. + * + * If you want to type the style prop of a function, + * consider using ViewStyleProp. + * + * A reasonable usage of this type is for helper functions that return an + * object of styles to pass to a View that can't be precomputed with + * StyleSheet.create. + */ +export type ViewStyle = ____ViewStyle_Internal; + +/** + * This type is an object of the different possible style + * properties that can be specified for Text. + * + * Note that this isn't a safe way to type a style prop for a component as + * results from StyleSheet.create return an internal identifier, not + * an object of styles. + * + * If you want to type the style prop of a function, + * consider using TextStyleProp. + * + * A reasonable usage of this type is for helper functions that return an + * object of styles to pass to a Text that can't be precomputed with + * StyleSheet.create. + */ +export type TextStyle = ____TextStyle_Internal; + +/** + * This type is an object of the different possible style + * properties that can be specified for Image. + * + * Note that this isn't a safe way to type a style prop for a component as + * results from StyleSheet.create return an internal identifier, not + * an object of styles. + * + * If you want to type the style prop of a function, + * consider using ImageStyleProp. + * + * A reasonable usage of this type is for helper functions that return an + * object of styles to pass to an Image that can't be precomputed with + * StyleSheet.create. + */ +export type ImageStyle = ____ImageStyle_Internal; + /** * WARNING: You probably shouldn't be using this type. This type is an object - * with all possible style key's and their values. Note that this isn't + * with all possible style keys and their values. Note that this isn't * a safe way to type a style prop for a component as results from * StyleSheet.create return an internal identifier, not an object of styles. * diff --git a/Libraries/StyleSheet/StyleSheetTypes.js b/Libraries/StyleSheet/StyleSheetTypes.js index 19b57c700c1844..44688ef72087c9 100644 --- a/Libraries/StyleSheet/StyleSheetTypes.js +++ b/Libraries/StyleSheet/StyleSheetTypes.js @@ -126,7 +126,7 @@ export type ShadowStyle = $ReadOnly<{| shadowRadius?: number, |}>; -export type ViewStyle = $ReadOnly<{| +export type ____ViewStyle_Internal = $ReadOnly<{| ...$Exact, ...$Exact, ...$Exact, @@ -160,8 +160,8 @@ export type ViewStyle = $ReadOnly<{| elevation?: number, |}>; -export type TextStyle = $ReadOnly<{| - ...$Exact, +export type ____TextStyle_Internal = $ReadOnly<{| + ...$Exact<____ViewStyle_Internal>, color?: ColorValue, fontFamily?: string, fontSize?: number, @@ -206,15 +206,15 @@ export type TextStyle = $ReadOnly<{| writingDirection?: 'auto' | 'ltr' | 'rtl', |}>; -export type ImageStyle = $ReadOnly<{| - ...$Exact, +export type ____ImageStyle_Internal = $ReadOnly<{| + ...$Exact<____ViewStyle_Internal>, resizeMode?: 'contain' | 'cover' | 'stretch' | 'center' | 'repeat', tintColor?: ColorValue, overlayColor?: string, |}>; export type ____DangerouslyImpreciseStyle_Internal = { - ...$Exact, + ...$Exact<____TextStyle_Internal>, +resizeMode?: 'contain' | 'cover' | 'stretch' | 'center' | 'repeat', +tintColor?: ColorValue, +overlayColor?: string, @@ -234,13 +234,13 @@ export type ____DangerouslyImpreciseStyleProp_Internal = GenericStyleProp< $Shape<____DangerouslyImpreciseStyle_Internal>, >; export type ____ViewStyleProp_Internal = GenericStyleProp< - $ReadOnly<$Shape>, + $ReadOnly<$Shape<____ViewStyle_Internal>>, >; export type ____TextStyleProp_Internal = GenericStyleProp< - $ReadOnly<$Shape>, + $ReadOnly<$Shape<____TextStyle_Internal>>, >; export type ____ImageStyleProp_Internal = GenericStyleProp< - $ReadOnly<$Shape>, + $ReadOnly<$Shape<____ImageStyle_Internal>>, >; export type ____Styles_Internal = { From a3f1ca84afe4dca0c0255c68e84e0bcb8ad29c14 Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Tue, 20 Mar 2018 19:19:17 -0700 Subject: [PATCH 0101/1109] Bump metro@0.31.0 Reviewed By: mjesun Differential Revision: D7336904 fbshipit-source-id: 2132c77d07e52a91f09b6f905bee4806aaf7d23e --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index e7a8250c4d16e5..eb2c29584298d1 100644 --- a/package.json +++ b/package.json @@ -175,8 +175,8 @@ "graceful-fs": "^4.1.3", "inquirer": "^3.0.6", "lodash": "^4.17.5", - "metro": "^0.30.2", - "metro-core": "^0.30.2", + "metro": "^0.31.0", + "metro-core": "^0.31.0", "mime": "^1.3.4", "minimist": "^1.2.0", "mkdirp": "^0.5.1", From 657c1a45bd007f8c837237ee2c2c2e27a5d8ac11 Mon Sep 17 00:00:00 2001 From: "Andrew Chen (Eng)" Date: Tue, 20 Mar 2018 19:20:33 -0700 Subject: [PATCH 0102/1109] Add more debug logs to FabricReconciler Reviewed By: mdvacca Differential Revision: D7338946 fbshipit-source-id: 839de31ca26a8e45d3bb3271d3ab5a4f53f639b0 --- .../react/fabric/FabricReconciler.java | 45 +++++++++++-------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java index 3d7571e496b93c..eba24f2754ef13 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java @@ -59,12 +59,7 @@ private void manageChildren( if (prevNode.getReactTag() != newNode.getReactTag()) { break; } - - if (newNode.getNewProps() != null) { - uiViewOperationQueue.enqueueUpdateProperties( - newNode.getReactTag(), newNode.getViewClass(), newNode.getNewProps()); - } - + enqueueUpdateProperties(newNode); manageChildren(prevNode, prevNode.getChildrenList(), newNode.getChildrenList()); prevNode.setOriginalReactShadowNode(newNode); } @@ -79,10 +74,7 @@ private void manageChildren( for (int k = firstRemovedOrAddedViewIndex; k < newList.size(); k++) { ReactShadowNode newNode = newList.get(k); if (newNode.isVirtual()) continue; - if (newNode.getNewProps() != null) { - uiViewOperationQueue.enqueueUpdateProperties( - newNode.getReactTag(), newNode.getViewClass(), newNode.getNewProps()); - } + enqueueUpdateProperties(newNode); viewsToAdd.add(new ViewAtIndex(newNode.getReactTag(), k)); List previousChildrenList = newNode.getOriginalReactShadowNode() == null ? null : newNode.getOriginalReactShadowNode().getChildrenList(); manageChildren(newNode, previousChildrenList, newNode.getChildrenList()); @@ -113,19 +105,36 @@ private void manageChildren( int[] tagsToDeleteArray = ArrayUtils.copyListToArray(tagsToDelete); ViewAtIndex[] viewsToAddArray = viewsToAdd.toArray(new ViewAtIndex[viewsToAdd.size()]); - if (DEBUG) { - Log.d( - TAG, - "manageChildren.enqueueManageChildren parent: " + parent.getReactTag() + - "\n\tIndices2Remove: " + Arrays.toString(indicesToRemove) + - "\n\tViews2Add: " + Arrays.toString(viewsToAddArray) + - "\n\tTags2Delete: " + Arrays.toString(tagsToDeleteArray)); - } + // TODO (t27180994): Mutate views synchronously on main thread if (indicesToRemove.length > 0 || viewsToAddArray.length > 0 || tagsToDeleteArray.length > 0) { + if (DEBUG) { + Log.d( + TAG, + "manageChildren.enqueueManageChildren parent: " + parent.getReactTag() + + "\n\tIndices2Remove: " + Arrays.toString(indicesToRemove) + + "\n\tViews2Add: " + Arrays.toString(viewsToAddArray) + + "\n\tTags2Delete: " + Arrays.toString(tagsToDeleteArray)); + } uiViewOperationQueue.enqueueManageChildren( parent.getReactTag(), indicesToRemove, viewsToAddArray, tagsToDeleteArray); } } + private void enqueueUpdateProperties(ReactShadowNode node) { + if (node.getNewProps() == null) { + return; + } + if (DEBUG) { + Log.d( + TAG, + "manageChildren.enqueueUpdateProperties " + + "\n\ttag: " + node.getReactTag() + + "\n\tviewClass: " + node.getViewClass() + + "\n\tnewProps: " + node.getNewProps()); + } + uiViewOperationQueue.enqueueUpdateProperties( + node.getReactTag(), node.getViewClass(), node.getNewProps()); + } + } From b961ac3effec2e97db011cdea3e866891aa1d13a Mon Sep 17 00:00:00 2001 From: Peter van der Zee Date: Wed, 21 Mar 2018 09:27:25 -0700 Subject: [PATCH 0103/1109] Depend on local version of babel-plugin-react-transform Reviewed By: arcanis Differential Revision: D7337432 fbshipit-source-id: 3729359da0ccfd3161546ab3ea9331ad30fb6e8d --- babel-preset/configs/hmr.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/babel-preset/configs/hmr.js b/babel-preset/configs/hmr.js index 91cb9a356c654b..cdf5a022c202eb 100644 --- a/babel-preset/configs/hmr.js +++ b/babel-preset/configs/hmr.js @@ -7,7 +7,6 @@ 'use strict'; var path = require('path'); -var resolvePlugins = require('../lib/resolvePlugins'); var hmrTransform = 'react-transform-hmr/lib/index.js'; var transformPath = require.resolve(hmrTransform); @@ -23,9 +22,9 @@ module.exports = function(options, filename) { } return { - plugins: resolvePlugins([ + plugins: [ [ - 'react-transform', + require('metro-babel7-plugin-react-transform').default, { transforms: [{ transform: transform, @@ -34,6 +33,6 @@ module.exports = function(options, filename) { }] }, ] - ]) + ] }; }; From 0594a109d157843af9e95061e6f72ba847d5549c Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Wed, 21 Mar 2018 10:18:57 -0700 Subject: [PATCH 0104/1109] Removed unnecessary `intrinsicContentSize` implementation from `RCTSurfaceHostingProxyRootView` Summary: The base class already implements `intrinsicContentSize` (and it's a bit more complicated that that). (Not sure if this change anything visible.) Reviewed By: fkgozali Differential Revision: D7343567 fbshipit-source-id: 86f86715b0dacc3c2230289a13926f0520540089 --- .../SurfaceHostingView/RCTSurfaceHostingProxyRootView.mm | 5 ----- 1 file changed, 5 deletions(-) diff --git a/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingProxyRootView.mm b/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingProxyRootView.mm index 076773a58b567c..14466297473e5c 100644 --- a/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingProxyRootView.mm +++ b/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingProxyRootView.mm @@ -130,11 +130,6 @@ - (void)setAppProperties:(NSDictionary *)appProperties [super.surface setProperties:appProperties]; } -- (CGSize)intrinsicContentSize -{ - return super.surface.intrinsicSize; -} - - (UIView *)loadingView { return super.activityIndicatorViewFactory ? super.activityIndicatorViewFactory() : nil; From 909861ff058b7b6e458ac4f0786b11d9cf18f669 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Wed, 21 Mar 2018 10:18:59 -0700 Subject: [PATCH 0105/1109] Fixed race condition in RCTUIManager's mounting process Summary: See the comment in code. This picture also illustrates the problem: https://cl.ly/250z0D1B0c17. https://pxl.cl/ckBq Reviewed By: fkgozali Differential Revision: D7343566 fbshipit-source-id: e45a691add5e43434dea8708be4b76ff18e52131 --- React/Modules/RCTUIManager.m | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m index 5dcce46588ba58..4653e239ed3f76 100644 --- a/React/Modules/RCTUIManager.m +++ b/React/Modules/RCTUIManager.m @@ -69,6 +69,9 @@ @implementation RCTUIManager // Keyed by viewName NSDictionary *_componentDataByName; + + BOOL _isMountingInProgress; + BOOL _isRemountingNeeded; } @synthesize bridge = _bridge; @@ -1046,6 +1049,19 @@ - (void)batchDidComplete */ - (void)_layoutAndMount { + // Mounting is (usually, not always) an asynchronous process. + // So, we have to ensure that there is no any case of self-interleaving + // (when another mourning process is initiated before the previous + // one finishes) here. + if (_isMountingInProgress) { + // In a case when another mounting process hasn't completed yet, + // we have to run another pass right after it finishes. + _isRemountingNeeded = YES; + return; + } + + _isMountingInProgress = YES; + [self _dispatchPropsDidChangeEvents]; [self _dispatchChildrenDidChangeEvents]; @@ -1063,6 +1079,13 @@ - (void)_layoutAndMount [self flushUIBlocksWithCompletion:^{ [self->_observerCoordinator uiManagerDidPerformMounting:self]; + + self->_isMountingInProgress = NO; + + if (self->_isRemountingNeeded) { + self->_isRemountingNeeded = NO; + [self _layoutAndMount]; + } }]; } From c194c18126ab890657902e5fff0fec1d3b311633 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Wed, 21 Mar 2018 10:19:01 -0700 Subject: [PATCH 0106/1109] Fixed performance regression in `ShadowView`s layout process Summary: This fixes perf regression which was introduced by recent refactoring of the layout process. That is how it used to be: https://github.com/facebook/react-native/blob/114c258045ccca3a4433de206c7983b42d14c03b/React/Views/RCTShadowView.m#L160-L166 Note: We have to resert this flag in indication that we already applied those changes and we don't need to traverse this subtree until it is changed again. Reviewed By: fkgozali Differential Revision: D7343564 fbshipit-source-id: ba7e00bc5fe4992d777eed20ba0d959fd8f6c037 --- React/Views/RCTShadowView.m | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/React/Views/RCTShadowView.m b/React/Views/RCTShadowView.m index f29dbcbbd3631e..457117653900de 100644 --- a/React/Views/RCTShadowView.m +++ b/React/Views/RCTShadowView.m @@ -284,6 +284,8 @@ - (void)layoutWithMinimumSize:(CGSize)minimumSize return; } + YGNodeSetHasNewLayout(yogaNode, false); + RCTLayoutMetrics layoutMetrics = RCTLayoutMetricsFromYogaNode(yogaNode); layoutContext.absolutePosition.x += layoutMetrics.frame.origin.x; @@ -321,6 +323,8 @@ - (void)layoutSubviewsWithContext:(RCTLayoutContext)layoutContext continue; } + YGNodeSetHasNewLayout(childYogaNode, false); + RCTLayoutMetrics childLayoutMetrics = RCTLayoutMetricsFromYogaNode(childYogaNode); layoutContext.absolutePosition.x += childLayoutMetrics.frame.origin.x; From d50cefb1f25045bf676b52bcb5cbd169ff4069d0 Mon Sep 17 00:00:00 2001 From: Eli White Date: Wed, 21 Mar 2018 14:02:30 -0700 Subject: [PATCH 0107/1109] Moving remaining Style types from StyleSheetTypes to StyleSheet Reviewed By: yungsters Differential Revision: D7282831 fbshipit-source-id: ced44d79ad30b7abdda77a25b72493899c2108e4 --- Libraries/StyleSheet/StyleSheet.js | 13 ++++++++++++- Libraries/StyleSheet/StyleSheetTypes.js | 12 ++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/Libraries/StyleSheet/StyleSheet.js b/Libraries/StyleSheet/StyleSheet.js index c2579f21a3612d..ec20623d8a27e4 100644 --- a/Libraries/StyleSheet/StyleSheet.js +++ b/Libraries/StyleSheet/StyleSheet.js @@ -28,7 +28,9 @@ import type { ____TextStyleProp_Internal, ____ImageStyle_Internal, ____ImageStyleProp_Internal, - LayoutStyle, + ____LayoutStyle_Internal, + ____ShadowStyle_Internal, + ____TransformStyle_Internal, } from 'StyleSheetTypes'; /** @@ -155,6 +157,15 @@ export type ImageStyle = ____ImageStyle_Internal; */ export type DangerouslyImpreciseStyle = ____DangerouslyImpreciseStyle_Internal; +/** + * These types are simlilar to the style types above. They are objects of the + * possible style keys in that group. For example, ShadowStyle contains + * keys like `shadowColor` and `shadowRadius`. + */ +export type LayoutStyle = ____LayoutStyle_Internal; +export type ShadowStyle = ____ShadowStyle_Internal; +export type TransformStyle = ____TransformStyle_Internal; + let hairlineWidth = PixelRatio.roundToNearestPixel(0.4); if (hairlineWidth === 0) { hairlineWidth = 1 / PixelRatio.get(); diff --git a/Libraries/StyleSheet/StyleSheetTypes.js b/Libraries/StyleSheet/StyleSheetTypes.js index 44688ef72087c9..6ff412ce8a6798 100644 --- a/Libraries/StyleSheet/StyleSheetTypes.js +++ b/Libraries/StyleSheet/StyleSheetTypes.js @@ -18,7 +18,7 @@ export opaque type ____StyleSheetInternalStyleIdentifier_Internal: number = numb export type ColorValue = null | string; export type DimensionValue = null | number | string | AnimatedNode; -export type LayoutStyle = $ReadOnly<{| +export type ____LayoutStyle_Internal = $ReadOnly<{| display?: 'none' | 'flex', width?: DimensionValue, height?: DimensionValue, @@ -92,7 +92,7 @@ export type LayoutStyle = $ReadOnly<{| direction?: 'inherit' | 'ltr' | 'rtl', |}>; -export type TransformStyle = $ReadOnly<{| +export type ____TransformStyle_Internal = $ReadOnly<{| transform?: $ReadOnlyArray< | {|+perspective: number | AnimatedNode|} | {|+rotate: string|} @@ -116,7 +116,7 @@ export type TransformStyle = $ReadOnly<{| >, |}>; -export type ShadowStyle = $ReadOnly<{| +export type ____ShadowStyle_Internal = $ReadOnly<{| shadowColor?: ColorValue, shadowOffset?: $ReadOnly<{| width?: number, @@ -127,9 +127,9 @@ export type ShadowStyle = $ReadOnly<{| |}>; export type ____ViewStyle_Internal = $ReadOnly<{| - ...$Exact, - ...$Exact, - ...$Exact, + ...$Exact<____LayoutStyle_Internal>, + ...$Exact<____ShadowStyle_Internal>, + ...$Exact<____TransformStyle_Internal>, backfaceVisibility?: 'visible' | 'hidden', backgroundColor?: ColorValue, borderColor?: ColorValue, From cf036dbc7af16a8453c115372694dc51e8086fcf Mon Sep 17 00:00:00 2001 From: Orta Date: Wed, 21 Mar 2018 14:12:08 -0700 Subject: [PATCH 0108/1109] Updates Yoga to handle being in a Xcode framework project MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Updates the Yoga Podspec to work with Cocoa frameworks. Replicated a2's work over on Yoga https://github.com/facebook/yoga/pull/726 (Which should also get merged too please ❤️ ) Set it manually in my own project and tested 👍 Only https://github.com/facebook/yoga/pull/726 [IOS] [BUGFIX] [Yoga] - Fixes to yoga.podspec when integrating into an iOS app using Cocoa frameworks. Closes https://github.com/facebook/react-native/pull/18492 Differential Revision: D7355907 Pulled By: hramos fbshipit-source-id: 6986d2bc560a23bb7f0f20b80e88bb440079891a --- ReactCommon/yoga/yoga.podspec | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ReactCommon/yoga/yoga.podspec b/ReactCommon/yoga/yoga.podspec index c38f4c09796cb6..69144f9bb01bac 100644 --- a/ReactCommon/yoga/yoga.podspec +++ b/ReactCommon/yoga/yoga.podspec @@ -36,9 +36,13 @@ Pod::Spec.new do |spec| # Pinning to the same version as React.podspec. spec.platforms = { :ios => "8.0", :tvos => "9.2" } - # Set this environment variable when not using the `:path` option to install the pod. + # Set this environment variable when *not* using the `:path` option to install the pod. # E.g. when publishing this spec to a spec repo. source_files = 'yoga/**/*.{cpp,h}' source_files = File.join('ReactCommon/yoga', source_files) if ENV['INSTALL_YOGA_WITHOUT_PATH_OPTION'] spec.source_files = source_files + + header_files = 'yoga/{Yoga,YGEnums,YGMacros}.h' + header_files = File.join('ReactCommon/yoga', header_files) if ENV['INSTALL_YOGA_WITHOUT_PATH_OPTION'] + spec.public_header_files = header_files end From c0d27de37eec7b6860387e35dae4dfc455d4b6e2 Mon Sep 17 00:00:00 2001 From: "Andrew Chen (Eng)" Date: Wed, 21 Mar 2018 14:21:37 -0700 Subject: [PATCH 0109/1109] Fix removal of virtual nodes in FabricReconciler Reviewed By: mdvacca Differential Revision: D7338949 fbshipit-source-id: 31263c138689f9b3f59deb26851132df04b8a823 --- .../react/fabric/FabricReconciler.java | 19 +++++++++---------- .../facebook/react/uimanager/ViewAtIndex.java | 11 ++++++++++- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java index eba24f2754ef13..cc851c228fe281 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java @@ -89,12 +89,11 @@ private void manageChildren( // If a View is not re-ordered, then the ReactTag is deleted (ReactShadowNode and native View // are released from memory) List tagsToDelete = new LinkedList<>(); - int[] indicesToRemove = new int[prevList.size() - firstRemovedOrAddedViewIndex]; - int indicesToRemoveIndex = 0; - for (int j = firstRemovedOrAddedViewIndex; j < prevList.size(); j++) { + List indicesToRemove = new LinkedList<>(); + for (int j = prevList.size() - 1; j >= firstRemovedOrAddedViewIndex; j--) { ReactShadowNode nodeToRemove = prevList.get(j); if (nodeToRemove.isVirtual()) continue; - indicesToRemove[indicesToRemoveIndex++] = j; + indicesToRemove.add(0, j); if (!addedTags.contains(nodeToRemove.getReactTag())) { tagsToDelete.add(nodeToRemove.getReactTag()); // TODO: T26729293 since we are not cloning ReactShadowNode's we need to "manually" remove @@ -103,21 +102,21 @@ private void manageChildren( } } - int[] tagsToDeleteArray = ArrayUtils.copyListToArray(tagsToDelete); - ViewAtIndex[] viewsToAddArray = viewsToAdd.toArray(new ViewAtIndex[viewsToAdd.size()]); - // TODO (t27180994): Mutate views synchronously on main thread - if (indicesToRemove.length > 0 || viewsToAddArray.length > 0 || tagsToDeleteArray.length > 0) { + if (!(indicesToRemove.isEmpty() && viewsToAdd.isEmpty() && tagsToDelete.isEmpty())) { + int[] indicesToRemoveArray = ArrayUtils.copyListToArray(indicesToRemove); + ViewAtIndex[] viewsToAddArray = viewsToAdd.toArray(new ViewAtIndex[viewsToAdd.size()]); + int[] tagsToDeleteArray = ArrayUtils.copyListToArray(tagsToDelete); if (DEBUG) { Log.d( TAG, "manageChildren.enqueueManageChildren parent: " + parent.getReactTag() + - "\n\tIndices2Remove: " + Arrays.toString(indicesToRemove) + + "\n\tIndices2Remove: " + Arrays.toString(indicesToRemoveArray) + "\n\tViews2Add: " + Arrays.toString(viewsToAddArray) + "\n\tTags2Delete: " + Arrays.toString(tagsToDeleteArray)); } uiViewOperationQueue.enqueueManageChildren( - parent.getReactTag(), indicesToRemove, viewsToAddArray, tagsToDeleteArray); + parent.getReactTag(), indicesToRemoveArray, viewsToAddArray, tagsToDeleteArray); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewAtIndex.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewAtIndex.java index ef2a914d3cf358..c242d7c310ddf5 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewAtIndex.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewAtIndex.java @@ -29,8 +29,17 @@ public ViewAtIndex(int tag, int index) { mIndex = index; } + @Override + public boolean equals(Object obj) { + if (obj == null || obj.getClass() != getClass()) { + return false; + } + ViewAtIndex other = (ViewAtIndex) obj; + return mIndex == other.mIndex && mTag == other.mTag; + } + @Override public String toString() { - return "[" + mIndex + ", " + mTag + "]"; + return "[" + mTag + ", " + mIndex + "]"; } } From 0b085a80bdd8ac68347de9cd7610e0991cb4a85a Mon Sep 17 00:00:00 2001 From: Jonathan Dann Date: Wed, 21 Mar 2018 16:05:09 -0700 Subject: [PATCH 0110/1109] Pass-by-reference in YGNode::setStyle() ::setChildren() ::setLayout() Reviewed By: priteshrnandgaonkar Differential Revision: D7291096 fbshipit-source-id: 7a4025831811d622050adbb5f86608855b94d68e --- ReactCommon/yoga/yoga/YGNode.cpp | 6 +++--- ReactCommon/yoga/yoga/YGNode.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ReactCommon/yoga/yoga/YGNode.cpp b/ReactCommon/yoga/yoga/YGNode.cpp index 5a33c6e86e73ea..7a71058a7b8109 100644 --- a/ReactCommon/yoga/yoga/YGNode.cpp +++ b/ReactCommon/yoga/yoga/YGNode.cpp @@ -225,11 +225,11 @@ void YGNode::setDirtiedFunc(YGDirtiedFunc dirtiedFunc) { dirtied_ = dirtiedFunc; } -void YGNode::setStyle(YGStyle style) { +void YGNode::setStyle(const YGStyle& style) { style_ = style; } -void YGNode::setLayout(YGLayout layout) { +void YGNode::setLayout(const YGLayout& layout) { layout_ = layout; } @@ -241,7 +241,7 @@ void YGNode::setParent(YGNodeRef parent) { parent_ = parent; } -void YGNode::setChildren(YGVector children) { +void YGNode::setChildren(const YGVector& children) { children_ = children; } diff --git a/ReactCommon/yoga/yoga/YGNode.h b/ReactCommon/yoga/yoga/YGNode.h index 27a1ed68fac113..081bc235c2e309 100644 --- a/ReactCommon/yoga/yoga/YGNode.h +++ b/ReactCommon/yoga/yoga/YGNode.h @@ -106,13 +106,13 @@ struct YGNode { void setMeasureFunc(YGMeasureFunc measureFunc); void setBaseLineFunc(YGBaselineFunc baseLineFunc); void setDirtiedFunc(YGDirtiedFunc dirtiedFunc); - void setStyle(YGStyle style); + void setStyle(const YGStyle& style); void setStyleFlexDirection(YGFlexDirection direction); void setStyleAlignContent(YGAlign alignContent); - void setLayout(YGLayout layout); + void setLayout(const YGLayout& layout); void setLineIndex(uint32_t lineIndex); void setParent(YGNodeRef parent); - void setChildren(YGVector children); + void setChildren(const YGVector& children); void setNextChild(YGNodeRef nextChild); void setConfig(YGConfigRef config); void setDirty(bool isDirty); From ed0ba1bfc7ae4e213b1c4362f812da05f4e299ce Mon Sep 17 00:00:00 2001 From: Jonathan Dann Date: Wed, 21 Mar 2018 16:05:10 -0700 Subject: [PATCH 0111/1109] Pass some constructor argumetns by const-reference Reviewed By: priteshrnandgaonkar Differential Revision: D7291363 fbshipit-source-id: 22e606d0b3fa1133d7e0334c8cf9f5f1f32fe64b --- ReactCommon/yoga/yoga/YGNode.cpp | 4 ++-- ReactCommon/yoga/yoga/YGNode.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ReactCommon/yoga/yoga/YGNode.cpp b/ReactCommon/yoga/yoga/YGNode.cpp index 7a71058a7b8109..37b630426b774e 100644 --- a/ReactCommon/yoga/yoga/YGNode.cpp +++ b/ReactCommon/yoga/yoga/YGNode.cpp @@ -423,10 +423,10 @@ YGNode::YGNode( YGBaselineFunc baseline, YGDirtiedFunc dirtied, YGStyle style, - YGLayout layout, + const YGLayout& layout, uint32_t lineIndex, YGNodeRef parent, - YGVector children, + const YGVector& children, YGNodeRef nextChild, YGConfigRef config, bool isDirty, diff --git a/ReactCommon/yoga/yoga/YGNode.h b/ReactCommon/yoga/yoga/YGNode.h index 081bc235c2e309..c9c5599c09093b 100644 --- a/ReactCommon/yoga/yoga/YGNode.h +++ b/ReactCommon/yoga/yoga/YGNode.h @@ -47,10 +47,10 @@ struct YGNode { YGBaselineFunc baseline, YGDirtiedFunc dirtied, YGStyle style, - YGLayout layout, + const YGLayout& layout, uint32_t lineIndex, YGNodeRef parent, - YGVector children, + const YGVector& children, YGNodeRef nextChild, YGConfigRef config, bool isDirty, From cb3103ce0916ce1e7863fc3baa98f173c1d480aa Mon Sep 17 00:00:00 2001 From: Jonathan Dann Date: Wed, 21 Mar 2018 16:05:12 -0700 Subject: [PATCH 0112/1109] Mark more member functions as const Reviewed By: priteshrnandgaonkar Differential Revision: D7291364 fbshipit-source-id: 2e7d96cfe0345692ffa411bb21a80eb7a859880b --- ReactCommon/yoga/yoga/YGNode.cpp | 26 +++++++++++++------------- ReactCommon/yoga/yoga/YGNode.h | 26 +++++++++++++------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/ReactCommon/yoga/yoga/YGNode.cpp b/ReactCommon/yoga/yoga/YGNode.cpp index 37b630426b774e..8fcb44c39dcbb4 100644 --- a/ReactCommon/yoga/yoga/YGNode.cpp +++ b/ReactCommon/yoga/yoga/YGNode.cpp @@ -87,7 +87,7 @@ std::array YGNode::getResolvedDimensions() const { float YGNode::getLeadingPosition( const YGFlexDirection axis, - const float axisSize) { + const float axisSize) const { if (YGFlexDirectionIsRow(axis)) { const YGValue* leadingPosition = YGComputedEdgeValue(style_.position, YGEdgeStart, &YGValueUndefined); @@ -106,7 +106,7 @@ float YGNode::getLeadingPosition( float YGNode::getTrailingPosition( const YGFlexDirection axis, - const float axisSize) { + const float axisSize) const { if (YGFlexDirectionIsRow(axis)) { const YGValue* trailingPosition = YGComputedEdgeValue(style_.position, YGEdgeEnd, &YGValueUndefined); @@ -123,7 +123,7 @@ float YGNode::getTrailingPosition( : YGUnwrapFloatOptional(YGResolveValue(*trailingPosition, axisSize)); } -bool YGNode::isLeadingPositionDefined(const YGFlexDirection axis) { +bool YGNode::isLeadingPositionDefined(const YGFlexDirection axis) const { return (YGFlexDirectionIsRow(axis) && YGComputedEdgeValue(style_.position, YGEdgeStart, &YGValueUndefined) ->unit != YGUnitUndefined) || @@ -131,7 +131,7 @@ bool YGNode::isLeadingPositionDefined(const YGFlexDirection axis) { ->unit != YGUnitUndefined; } -bool YGNode::isTrailingPosDefined(const YGFlexDirection axis) { +bool YGNode::isTrailingPosDefined(const YGFlexDirection axis) const { return (YGFlexDirectionIsRow(axis) && YGComputedEdgeValue(style_.position, YGEdgeEnd, &YGValueUndefined) ->unit != YGUnitUndefined) || @@ -141,7 +141,7 @@ bool YGNode::isTrailingPosDefined(const YGFlexDirection axis) { float YGNode::getLeadingMargin( const YGFlexDirection axis, - const float widthSize) { + const float widthSize) const { if (YGFlexDirectionIsRow(axis) && style_.margin[YGEdgeStart].unit != YGUnitUndefined) { return YGResolveValueMargin(style_.margin[YGEdgeStart], widthSize); @@ -154,7 +154,7 @@ float YGNode::getLeadingMargin( float YGNode::getTrailingMargin( const YGFlexDirection axis, - const float widthSize) { + const float widthSize) const { if (YGFlexDirectionIsRow(axis) && style_.margin[YGEdgeEnd].unit != YGUnitUndefined) { return YGResolveValueMargin(style_.margin[YGEdgeEnd], widthSize); @@ -167,7 +167,7 @@ float YGNode::getTrailingMargin( float YGNode::getMarginForAxis( const YGFlexDirection axis, - const float widthSize) { + const float widthSize) const { return getLeadingMargin(axis, widthSize) + getTrailingMargin(axis, widthSize); } @@ -621,7 +621,7 @@ bool YGNode::isNodeFlexible() { (resolveFlexGrow() != 0 || resolveFlexShrink() != 0)); } -float YGNode::getLeadingBorder(const YGFlexDirection axis) { +float YGNode::getLeadingBorder(const YGFlexDirection axis) const { if (YGFlexDirectionIsRow(axis) && style_.border[YGEdgeStart].unit != YGUnitUndefined && !YGFloatIsUndefined(style_.border[YGEdgeStart].value) && @@ -634,7 +634,7 @@ float YGNode::getLeadingBorder(const YGFlexDirection axis) { return YGFloatMax(computedEdgeValue, 0.0f); } -float YGNode::getTrailingBorder(const YGFlexDirection flexDirection) { +float YGNode::getTrailingBorder(const YGFlexDirection flexDirection) const { if (YGFlexDirectionIsRow(flexDirection) && style_.border[YGEdgeEnd].unit != YGUnitUndefined && !YGFloatIsUndefined(style_.border[YGEdgeEnd].value) && @@ -650,7 +650,7 @@ float YGNode::getTrailingBorder(const YGFlexDirection flexDirection) { float YGNode::getLeadingPadding( const YGFlexDirection axis, - const float widthSize) { + const float widthSize) const { if (YGFlexDirectionIsRow(axis) && style_.padding[YGEdgeStart].unit != YGUnitUndefined && !YGResolveValue(style_.padding[YGEdgeStart], widthSize).isUndefined() && @@ -667,7 +667,7 @@ float YGNode::getLeadingPadding( float YGNode::getTrailingPadding( const YGFlexDirection axis, - const float widthSize) { + const float widthSize) const { if (YGFlexDirectionIsRow(axis) && style_.padding[YGEdgeEnd].unit != YGUnitUndefined && !YGResolveValue(style_.padding[YGEdgeEnd], widthSize).isUndefined() && @@ -685,13 +685,13 @@ float YGNode::getTrailingPadding( float YGNode::getLeadingPaddingAndBorder( const YGFlexDirection axis, - const float widthSize) { + const float widthSize) const { return getLeadingPadding(axis, widthSize) + getLeadingBorder(axis); } float YGNode::getTrailingPaddingAndBorder( const YGFlexDirection axis, - const float widthSize) { + const float widthSize) const { return getTrailingPadding(axis, widthSize) + getTrailingBorder(axis); } diff --git a/ReactCommon/yoga/yoga/YGNode.h b/ReactCommon/yoga/yoga/YGNode.h index c9c5599c09093b..0ed05d7e552138 100644 --- a/ReactCommon/yoga/yoga/YGNode.h +++ b/ReactCommon/yoga/yoga/YGNode.h @@ -80,23 +80,23 @@ struct YGNode { YGValue getResolvedDimension(int index); // Methods related to positions, margin, padding and border - float getLeadingPosition(const YGFlexDirection axis, const float axisSize); - bool isLeadingPositionDefined(const YGFlexDirection axis); - bool isTrailingPosDefined(const YGFlexDirection axis); - float getTrailingPosition(const YGFlexDirection axis, const float axisSize); - float getLeadingMargin(const YGFlexDirection axis, const float widthSize); - float getTrailingMargin(const YGFlexDirection axis, const float widthSize); - float getLeadingBorder(const YGFlexDirection flexDirection); - float getTrailingBorder(const YGFlexDirection flexDirection); - float getLeadingPadding(const YGFlexDirection axis, const float widthSize); - float getTrailingPadding(const YGFlexDirection axis, const float widthSize); + float getLeadingPosition(const YGFlexDirection axis, const float axisSize) const; + bool isLeadingPositionDefined(const YGFlexDirection axis) const; + bool isTrailingPosDefined(const YGFlexDirection axis) const; + float getTrailingPosition(const YGFlexDirection axis, const float axisSize) const; + float getLeadingMargin(const YGFlexDirection axis, const float widthSize) const; + float getTrailingMargin(const YGFlexDirection axis, const float widthSize) const; + float getLeadingBorder(const YGFlexDirection flexDirection) const; + float getTrailingBorder(const YGFlexDirection flexDirection) const; + float getLeadingPadding(const YGFlexDirection axis, const float widthSize) const; + float getTrailingPadding(const YGFlexDirection axis, const float widthSize) const; float getLeadingPaddingAndBorder( const YGFlexDirection axis, - const float widthSize); + const float widthSize) const; float getTrailingPaddingAndBorder( const YGFlexDirection axis, - const float widthSize); - float getMarginForAxis(const YGFlexDirection axis, const float widthSize); + const float widthSize) const; + float getMarginForAxis(const YGFlexDirection axis, const float widthSize) const; // Setters void setContext(void* context); From f015900d30321bc24ba850118746eb7a68d5d8fd Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Wed, 21 Mar 2018 16:38:41 -0700 Subject: [PATCH 0113/1109] fixed debug string formatting for structure Summary: Fixed minor issue: * use double spaces instead of a tab character for indentation * depth should increase by 1, not 2 Reviewed By: shergin Differential Revision: D7332803 fbshipit-source-id: 74fda2c7a4be4f509270d3074a7d71a3d4d32fe4 --- ReactCommon/fabric/debug/DebugStringConvertible.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ReactCommon/fabric/debug/DebugStringConvertible.cpp b/ReactCommon/fabric/debug/DebugStringConvertible.cpp index f669c1bd5ad230..ce2c91611af9c4 100644 --- a/ReactCommon/fabric/debug/DebugStringConvertible.cpp +++ b/ReactCommon/fabric/debug/DebugStringConvertible.cpp @@ -50,10 +50,10 @@ std::string DebugStringConvertible::getDebugPropsDescription(DebugStringConverti std::string DebugStringConvertible::getDebugDescription(DebugStringConvertibleOptions options, int depth) const { std::string nameString = getDebugName(); std::string valueString = getDebugValue(); - std::string childrenString = getDebugChildrenDescription(options, depth + 1); - std::string propsString = getDebugPropsDescription(options, depth /* The first-level props are considered as same-depth things. */); + std::string childrenString = getDebugChildrenDescription(options, depth); + std::string propsString = getDebugPropsDescription(options, depth); - std::string leading = options.format ? std::string(depth, '\t') : ""; + std::string leading = options.format ? std::string(depth * 2, ' ') : ""; std::string trailing = options.format ? "\n" : ""; return leading + "<" + nameString + From 6ae38feb654576054839d7b5b5741069a4e14a2f Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Wed, 21 Mar 2018 16:38:43 -0700 Subject: [PATCH 0114/1109] Added sample iOS unit test setup for fabric/debug target Summary: basic setup for unit testing Fabric impl Reviewed By: hramos Differential Revision: D7359239 fbshipit-source-id: ccaf36e775036f2fad4d8c882bce86bbbe06dd28 --- ReactCommon/fabric/debug/BUCK | 33 ++++++-- .../tests/DebugStringConvertibleTest.cpp | 77 +++++++++++++++++++ 2 files changed, 105 insertions(+), 5 deletions(-) create mode 100644 ReactCommon/fabric/debug/tests/DebugStringConvertibleTest.cpp diff --git a/ReactCommon/fabric/debug/BUCK b/ReactCommon/fabric/debug/BUCK index 5a021202ebb776..d17009730e1122 100644 --- a/ReactCommon/fabric/debug/BUCK +++ b/ReactCommon/fabric/debug/BUCK @@ -5,18 +5,18 @@ APPLE_COMPILER_FLAGS = [] if not IS_OSS_BUILD: load("@xplat//configurations/buck/apple:flag_defs.bzl", "get_static_library_ios_flags", "flags") - APPLE_COMPILER_FLAGS = flags.get_flag_value(get_static_library_ios_flags(), 'compiler_flags') + APPLE_COMPILER_FLAGS = flags.get_flag_value(get_static_library_ios_flags(), "compiler_flags") rn_xplat_cxx_library( name = "debug", srcs = glob( [ - "**/*.cpp", + "*.cpp", ], ), headers = glob( [ - "**/*.h", + "*.h", ], ), header_namespace = "", @@ -27,10 +27,10 @@ rn_xplat_cxx_library( prefix = "fabric/debug", ), compiler_flags = [ - "-std=c++14", - "-Wall", "-fexceptions", "-frtti", + "-std=c++14", + "-Wall", ], fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + APPLE_INSPECTOR_FLAGS, @@ -39,8 +39,31 @@ rn_xplat_cxx_library( "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", ], + tests = [ + ":tests", + ], visibility = ["PUBLIC"], deps = [ "xplat//folly:headers_only", ], ) + +if not IS_OSS_BUILD: + load("@xplat//configurations/buck:default_platform_defs.bzl", "APPLE") + + cxx_test( + name = "tests", + srcs = glob(["tests/**/*.cpp"]), + compiler_flags = [ + "-fexceptions", + "-frtti", + "-std=c++14", + "-Wall", + ], + platforms = APPLE, + deps = [ + "xplat//folly:molly", + "xplat//third-party/gmock:gtest", + ":debug", + ], + ) diff --git a/ReactCommon/fabric/debug/tests/DebugStringConvertibleTest.cpp b/ReactCommon/fabric/debug/tests/DebugStringConvertibleTest.cpp new file mode 100644 index 00000000000000..272255b39eb776 --- /dev/null +++ b/ReactCommon/fabric/debug/tests/DebugStringConvertibleTest.cpp @@ -0,0 +1,77 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 + +using namespace facebook::react; + +TEST(DebugStringConvertibleTest, handleSimpleNode) { + SharedDebugStringConvertibleList empty; + auto item = std::make_shared("View", "hello", empty, empty); + + ASSERT_STREQ(item->getDebugName().c_str(), "View"); + ASSERT_STREQ(item->getDebugValue().c_str(), "hello"); + ASSERT_STREQ(item->getDebugDescription().c_str(), "\n"); +} + +TEST(DebugStringConvertibleTest, handleSimpleNodeWithProps) { + SharedDebugStringConvertibleList empty; + SharedDebugStringConvertibleList props = { + std::make_shared("x", "1", empty, empty) + }; + auto item = std::make_shared("View", "hello", props, empty); + + ASSERT_STREQ(item->getDebugName().c_str(), "View"); + ASSERT_STREQ(item->getDebugValue().c_str(), "hello"); + ASSERT_STREQ(item->getDebugDescription().c_str(), "\n"); +} + +TEST(DebugStringConvertibleTest, handleSimpleNodeWithChildren) { + SharedDebugStringConvertibleList empty; + SharedDebugStringConvertibleList children = { + std::make_shared("Child", "a", empty, empty) + }; + auto item = std::make_shared("View", "hello", empty, children); + + ASSERT_STREQ(item->getDebugName().c_str(), "View"); + ASSERT_STREQ(item->getDebugValue().c_str(), "hello"); + ASSERT_STREQ(item->getDebugDescription().c_str(), "\n \n\n"); +} + +TEST(DebugStringConvertibleTest, handleNestedNode) { + SharedDebugStringConvertibleList empty; + SharedDebugStringConvertibleList props = { + std::make_shared("x", "1", empty, empty) + }; + SharedDebugStringConvertibleList children = { + std::make_shared("Child", "a", props, empty) + }; + auto item = std::make_shared("View", "hello", props, children); + + ASSERT_STREQ(item->getDebugName().c_str(), "View"); + ASSERT_STREQ(item->getDebugValue().c_str(), "hello"); + ASSERT_STREQ(item->getDebugDescription().c_str(), "\n \n\n"); +} + +TEST(DebugStringConvertibleTest, handleNodeWithComplexProps) { + SharedDebugStringConvertibleList empty; + SharedDebugStringConvertibleList subProps = { + std::make_shared("height", "100", empty, empty), + std::make_shared("width", "200", empty, empty) + }; + SharedDebugStringConvertibleList props = { + std::make_shared("x", "1", subProps, empty) + }; + auto item = std::make_shared("View", "hello", props, empty); + + ASSERT_STREQ(item->getDebugName().c_str(), "View"); + ASSERT_STREQ(item->getDebugValue().c_str(), "hello"); + ASSERT_STREQ(item->getDebugDescription().c_str(), "\n"); +} From 96daf677b7eda7e4344da7e674d3d6c298875913 Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Wed, 21 Mar 2018 17:40:46 -0700 Subject: [PATCH 0115/1109] Fix OSS Android test failure Reviewed By: fkgozali, hramos Differential Revision: D7358801 fbshipit-source-id: 6f7979489fd7f5c9f7d9e1d7461121b7ff9f3ab0 --- ReactNative/DEFS.bzl | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ReactNative/DEFS.bzl b/ReactNative/DEFS.bzl index b84007444e5e9c..135bacfbc93d2c 100644 --- a/ReactNative/DEFS.bzl +++ b/ReactNative/DEFS.bzl @@ -35,10 +35,16 @@ with allow_unsafe_import(): # Building is not supported in OSS right now def rn_xplat_cxx_library(name, **kwargs): - _ignore = kwargs + new_kwargs = { + k: v + for k, v in kwargs.items() + if k.startswith("exported_") + } + native.cxx_library( name=name, - visibility=kwargs.get("visibility", []) + visibility=kwargs.get("visibility", []), + **new_kwargs ) From 47910f0cadda30099bc6f5dfda03a69babd663a7 Mon Sep 17 00:00:00 2001 From: "Andrew Chen (Eng)" Date: Wed, 21 Mar 2018 17:43:11 -0700 Subject: [PATCH 0116/1109] Set measure function after YogaNode has been copied Reviewed By: mdvacca Differential Revision: D7338948 fbshipit-source-id: e805169e162a47d0c7c775a3decbe9013c27c0e4 --- .../react/uimanager/ReactShadowNodeImpl.java | 5 ----- .../react/views/text/ReactTextShadowNode.java | 16 +++++++++++++++- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java index 8d906c4bc29823..5f4ad868fe7751 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java @@ -1024,11 +1024,6 @@ public void setBaselineFunction(YogaBaselineFunction baselineFunction) { @Override public void setMeasureFunction(YogaMeasureFunction measureFunction) { - if ((measureFunction == null ^ mYogaNode.isMeasureDefined()) && getChildCount() != 0) { - throw new RuntimeException( - "Since a node with a measure function does not add any native yoga children, it's " - + "not safe to transition to/from having a measure function unless a node has no children"); - } mYogaNode.setMeasureFunction(measureFunction); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java index 37b13700fc3670..1cec7c690bcb3e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java @@ -18,6 +18,7 @@ import android.widget.TextView; import com.facebook.infer.annotation.Assertions; import com.facebook.react.uimanager.LayoutShadowNode; +import com.facebook.react.uimanager.ReactShadowNodeImpl; import com.facebook.react.uimanager.Spacing; import com.facebook.react.uimanager.UIViewOperationQueue; import com.facebook.yoga.YogaConstants; @@ -144,7 +145,6 @@ public ReactTextShadowNode() { private ReactTextShadowNode(ReactTextShadowNode node) { super(node); this.mPreparedSpannableText = node.mPreparedSpannableText; - initMeasureFunction(); } private void initMeasureFunction() { @@ -158,6 +158,20 @@ protected LayoutShadowNode copy() { return new ReactTextShadowNode(this); } + @Override + public ReactShadowNodeImpl mutableCopy() { + ReactTextShadowNode copy = (ReactTextShadowNode) super.mutableCopy(); + copy.initMeasureFunction(); + return copy; + } + + @Override + public ReactShadowNodeImpl mutableCopyWithNewChildren() { + ReactTextShadowNode copy = (ReactTextShadowNode) super.mutableCopyWithNewChildren(); + copy.initMeasureFunction(); + return copy; + } + // Return text alignment according to LTR or RTL style private int getTextAlign() { int textAlign = mTextAlign; From 8e065baad43a124a999d4f3c253b1081a3045a1a Mon Sep 17 00:00:00 2001 From: Andrew Jack Date: Wed, 21 Mar 2018 18:07:47 -0700 Subject: [PATCH 0117/1109] Update fresco to v1.8.1 Summary: The current version of fresco in use is [v1.3.0](https://github.com/facebook/fresco/releases/tag/v1.3.0) from April 2017. There has been a lot of [improvements](https://github.com/facebook/fresco/releases) since then. Fresco also depends on OkHttp 3.8.0 and soloader 0.3.0 so I have updated these too. Let me know if there's any reason either of these shouldn't be updated, however this will prevent Fresco from being updated. The latest version of OkHttp is 3.10.0, but I have kept it as low as possible to allow developers to choose the version. Test with local build. Check CI passes. [ANDROID] [ENHANCEMENT] [Fresco/OkHttp/SoLoader] - Updates Fresco to 1.8.1, OkHttp to 3.8.0, & SoLoader to 0.3.0 cc foghina Closes https://github.com/facebook/react-native/pull/18496 Differential Revision: D7361161 Pulled By: foghina fbshipit-source-id: 6d2c5afb94ce5ff8e621188c2ac60f1ca4b787a6 --- ReactAndroid/build.gradle | 10 ++++---- .../libraries/fresco/fresco-react-native/BUCK | 24 +++++++++---------- .../soloader/java/com/facebook/soloader/BUCK | 4 ++-- .../src/main/third-party/java/okhttp/BUCK | 8 +++---- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle index fdea9de2db7eb1..48c38722a16751 100644 --- a/ReactAndroid/build.gradle +++ b/ReactAndroid/build.gradle @@ -281,12 +281,12 @@ dependencies { compile 'javax.inject:javax.inject:1' compile 'com.android.support:appcompat-v7:23.0.1' compile 'com.facebook.fbui.textlayoutbuilder:textlayoutbuilder:1.0.0' - compile 'com.facebook.fresco:fresco:1.3.0' - compile 'com.facebook.fresco:imagepipeline-okhttp3:1.3.0' - compile 'com.facebook.soloader:soloader:0.1.0' + compile 'com.facebook.fresco:fresco:1.8.1' + compile 'com.facebook.fresco:imagepipeline-okhttp3:1.8.1' + compile 'com.facebook.soloader:soloader:0.3.0' compile 'com.google.code.findbugs:jsr305:3.0.0' - compile 'com.squareup.okhttp3:okhttp:3.6.0' - compile 'com.squareup.okhttp3:okhttp-urlconnection:3.6.0' + compile 'com.squareup.okhttp3:okhttp:3.8.0' + compile 'com.squareup.okhttp3:okhttp-urlconnection:3.8.0' compile 'com.squareup.okio:okio:1.13.0' compile 'org.webkit:android-jsc:r174650' diff --git a/ReactAndroid/src/main/libraries/fresco/fresco-react-native/BUCK b/ReactAndroid/src/main/libraries/fresco/fresco-react-native/BUCK index 06dca9bcc73f75..33ceb77095e719 100644 --- a/ReactAndroid/src/main/libraries/fresco/fresco-react-native/BUCK +++ b/ReactAndroid/src/main/libraries/fresco/fresco-react-native/BUCK @@ -8,8 +8,8 @@ rn_android_prebuilt_aar( remote_file( name = "fresco-binary-aar", - sha1 = "b6271dc58383b4ce119ecc05e2bcaedde0e74ad9", - url = "mvn:com.facebook.fresco:fresco:aar:1.3.0", + sha1 = "c6ed3f696ed47dca3b20d4ffbd0600c94b9119b2", + url = "mvn:com.facebook.fresco:fresco:aar:1.8.1", ) android_prebuilt_aar( @@ -20,8 +20,8 @@ android_prebuilt_aar( remote_file( name = "drawee-binary-aar", - sha1 = "c88fb84ed4ae8a4e0efe6fd3cad1a1d20c19ea69", - url = "mvn:com.facebook.fresco:drawee:aar:1.3.0", + sha1 = "6bc689901ddcac8f3df5ba4db1f8aabeb8e80107", + url = "mvn:com.facebook.fresco:drawee:aar:1.8.1", ) rn_android_library( @@ -42,8 +42,8 @@ rn_android_prebuilt_aar( remote_file( name = "imagepipeline-base-aar", - sha1 = "a43f1043fc684d2794438544f73f1968ec9cf21a", - url = "mvn:com.facebook.fresco:imagepipeline-base:aar:1.3.0", + sha1 = "42fd80c46a853850dfc0d71808b982fef401c841", + url = "mvn:com.facebook.fresco:imagepipeline-base:aar:1.8.1", ) rn_android_prebuilt_aar( @@ -54,8 +54,8 @@ rn_android_prebuilt_aar( remote_file( name = "imagepipeline-aar", - sha1 = "32c08122d47210d437f34eba5472e880b0f1e8b8", - url = "mvn:com.facebook.fresco:imagepipeline:aar:1.3.0", + sha1 = "06a2a4c3e1d9a7fb7d7f1ad14db63e2d32ef0b61", + url = "mvn:com.facebook.fresco:imagepipeline:aar:1.8.1", ) rn_prebuilt_jar( @@ -78,8 +78,8 @@ android_prebuilt_aar( remote_file( name = "fbcore-aar", - sha1 = "3b941157dd0c36fca9a19c22cae578f37deb97e5", - url = "mvn:com.facebook.fresco:fbcore:aar:1.3.0", + sha1 = "99b7a83946e16f037149e4cd3abfd6840a09445d", + url = "mvn:com.facebook.fresco:fbcore:aar:1.8.1", ) android_prebuilt_aar( @@ -90,6 +90,6 @@ android_prebuilt_aar( remote_file( name = "imagepipeline-okhttp3-binary-aar", - sha1 = "ac9b1a7c9906ed6be41c8df923a59f6952fce94c", - url = "mvn:com.facebook.fresco:imagepipeline-okhttp3:aar:1.3.0", + sha1 = "751f19412e1843b1c1e76eae46e388fb1deddbcc", + url = "mvn:com.facebook.fresco:imagepipeline-okhttp3:aar:1.8.1", ) diff --git a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/BUCK b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/BUCK index c91ded296895dc..3008da960a2329 100644 --- a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/BUCK +++ b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/BUCK @@ -6,6 +6,6 @@ android_prebuilt_aar( remote_file( name = "soloader-binary-aar", - sha1 = "918573465c94c6bc9bad48ef259f1e0cd6543c1b", - url = "mvn:com.facebook.soloader:soloader:aar:0.1.0", + sha1 = "5f4b28f3c401f3d9bb2d081af08f6ce784a02da5", + url = "mvn:com.facebook.soloader:soloader:aar:0.3.0", ) diff --git a/ReactAndroid/src/main/third-party/java/okhttp/BUCK b/ReactAndroid/src/main/third-party/java/okhttp/BUCK index b02f1486168b7c..84be571ad87c77 100644 --- a/ReactAndroid/src/main/third-party/java/okhttp/BUCK +++ b/ReactAndroid/src/main/third-party/java/okhttp/BUCK @@ -6,8 +6,8 @@ prebuilt_jar( remote_file( name = "okhttp3-binary-jar", - sha1 = "69edde9fc4b01c9fd51d25b83428837478c27254", - url = "mvn:com.squareup.okhttp3:okhttp:jar:3.6.0", + sha1 = "5a11f020cce2d11eb71ba916700600e18c4547e7", + url = "mvn:com.squareup.okhttp3:okhttp:jar:3.8.0", ) prebuilt_jar( @@ -18,6 +18,6 @@ prebuilt_jar( remote_file( name = "okhttp3-urlconnection-binary-jar", - sha1 = "3f9b16b774f2c36cfd86dd2053d0b3059531dacc", - url = "mvn:com.squareup.okhttp3:okhttp-urlconnection:jar:3.6.0", + sha1 = "265257b82f20bb0371a926cc8ceb5f7bb17c0df8", + url = "mvn:com.squareup.okhttp3:okhttp-urlconnection:jar:3.8.0", ) From ff1444e2151488b0cde612e5920bbbb300562331 Mon Sep 17 00:00:00 2001 From: Andrew Jack Date: Thu, 22 Mar 2018 09:51:29 -0700 Subject: [PATCH 0118/1109] Add fresco proguard rules Summary: Adds proguard rules, which I missed off from the #18496 PR. I've added the proguard rules as suggested in http://frescolib.org/docs/shipping.html, with the duplicates & unused libraries removed. CI passes. Build example project with proguard turned on. [ANDROID] [BREAKING] [proguard] - Update Proguard config in template. If upgrading make sure you update your project's proguard file. cc foghina & hramos Closes https://github.com/facebook/react-native/pull/18499 Differential Revision: D7366113 Pulled By: foghina fbshipit-source-id: 20864c34976bc3930d9fdcc9428f40f7a8d7a9b8 --- .../HelloWorld/android/app/proguard-rules.pro | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/local-cli/templates/HelloWorld/android/app/proguard-rules.pro b/local-cli/templates/HelloWorld/android/app/proguard-rules.pro index d8ec99250e54b6..b30112461f0e74 100644 --- a/local-cli/templates/HelloWorld/android/app/proguard-rules.pro +++ b/local-cli/templates/HelloWorld/android/app/proguard-rules.pro @@ -54,6 +54,25 @@ # See libs/proxy/src/main/java/com/facebook/fbui/textlayoutbuilder/proxy for details. -dontwarn android.text.StaticLayout +# Fresco +# Keep our interfaces so they can be used by other ProGuard rules. +# See http://sourceforge.net/p/proguard/bugs/466/ +-keep,allowobfuscation @interface com.facebook.soloader.DoNotOptimize + +# Do not strip any method/class that is annotated with @DoNotOptimize +-keep @com.facebook.soloader.DoNotOptimize class * +-keepclassmembers class * { + @com.facebook.soloader.DoNotOptimize *; +} + +# Keep native methods +-keepclassmembers class * { + native ; +} + +-dontwarn javax.annotation.** +-dontwarn com.facebook.infer.** + # okhttp -keepattributes Signature From 10c95a25ccd55c0dc60484b30e4db75930bb31e9 Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Thu, 22 Mar 2018 10:37:25 -0700 Subject: [PATCH 0119/1109] fixed contacts for the test target Reviewed By: mdvacca Differential Revision: D7366977 fbshipit-source-id: 93341f8964da71a7e23049fc5d2324a0da376746 --- ReactCommon/fabric/debug/BUCK | 1 + 1 file changed, 1 insertion(+) diff --git a/ReactCommon/fabric/debug/BUCK b/ReactCommon/fabric/debug/BUCK index d17009730e1122..6ce9e7f29e3d66 100644 --- a/ReactCommon/fabric/debug/BUCK +++ b/ReactCommon/fabric/debug/BUCK @@ -54,6 +54,7 @@ if not IS_OSS_BUILD: cxx_test( name = "tests", srcs = glob(["tests/**/*.cpp"]), + contacts = ["oncall+react_native@xmail.facebook.com"], compiler_flags = [ "-fexceptions", "-frtti", From 15fa2250fdd0865ce1d0c6ac13b817e7b2c7757a Mon Sep 17 00:00:00 2001 From: Eric Samelson Date: Thu, 22 Mar 2018 10:47:40 -0700 Subject: [PATCH 0120/1109] fix ReadableNativeMap.toHashMap() for nested maps and arrays Summary: Commit https://github.com/facebook/react-native/commit/7891805d22e3fdc821961ff0ccc5c450c3d625c8 broke the previous behavior of `ReadableNativeMap.toHashMap()` for nested maps and arrays. Previously, all nested `ReadableNativeMap`s and `ReadableNativeArray`s were recursively converted to `HashMap`s and `ArrayList`s, but this is lost when only `getLocalMap()` is returned. Call `ReadableNativeMap.toHashMap()` on a map with values of type `ReadableNativeMap` and `ReadableNativeArray`. Verify the returned hash map has these converted to `HashMap` and `ArrayList`, respectively. [ANDROID] [BUGFIX] [ReadableNativeMap] - Fix toHashMap() for nested maps and arrays Closes https://github.com/facebook/react-native/pull/18455 Reviewed By: kathryngray Differential Revision: D7347344 Pulled By: mdvacca fbshipit-source-id: af2bca9dec6c0cb8a7da099b6757434fcc3ac785 --- .../react/bridge/ReadableNativeMap.java | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableNativeMap.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableNativeMap.java index 82f7f20a0229dd..0cb9c10ef1c6f5 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableNativeMap.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableNativeMap.java @@ -11,6 +11,7 @@ import com.facebook.proguard.annotations.DoNotStrip; import java.util.HashMap; +import java.util.Iterator; import com.facebook.infer.annotation.Assertions; import javax.annotation.Nullable; @@ -248,7 +249,31 @@ public HashMap toHashMap() { } return hashMap; } - return getLocalMap(); + + // we can almost just return getLocalMap(), but we need to convert nested arrays and maps to the + // correct types first + HashMap hashMap = new HashMap<>(getLocalMap()); + Iterator iterator = hashMap.keySet().iterator(); + + while (iterator.hasNext()) { + String key = (String) iterator.next(); + switch (getType(key)) { + case Null: + case Boolean: + case Number: + case String: + break; + case Map: + hashMap.put(key, Assertions.assertNotNull(getMap(key)).toHashMap()); + break; + case Array: + hashMap.put(key, Assertions.assertNotNull(getArray(key)).toArrayList()); + break; + default: + throw new IllegalArgumentException("Could not convert object with key: " + key + "."); + } + } + return hashMap; } /** From cf642c9b1d0856200936882d5e08cae171520c7a Mon Sep 17 00:00:00 2001 From: Shoaib Meenai Date: Thu, 22 Mar 2018 16:19:01 -0700 Subject: [PATCH 0121/1109] Mark global variable as extern "C" Reviewed By: mnovakovic Differential Revision: D7369214 fbshipit-source-id: 710d817b4bf74b5ca0621645dd5c005b778d7171 --- React/Base/RCTRootView.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/React/Base/RCTRootView.h b/React/Base/RCTRootView.h index daab13efbe8c21..35561f68a8e45d 100644 --- a/React/Base/RCTRootView.h +++ b/React/Base/RCTRootView.h @@ -30,7 +30,12 @@ typedef NS_ENUM(NSInteger, RCTRootViewSizeFlexibility) { * after the application has loaded. This is used to hide the `loadingView`, and * is a good indicator that the application is ready to use. */ -extern NSString *const RCTContentDidAppearNotification; +#if defined(__cplusplus) +extern "C" +#else +extern +#endif +NSString *const RCTContentDidAppearNotification; /** * Native view used to host React-managed views within the app. Can be used just From 0376baf4b365c345ca0a607a80aaf7f4c4deeaf2 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Thu, 22 Mar 2018 17:32:08 -0700 Subject: [PATCH 0122/1109] Revert D7343566: [RN] Fixed race condition in RCTUIManager's mounting process Differential Revision: D7343566 Original commit changeset: e45a691add5e fbshipit-source-id: 08ec04538c07dc3cd630240da8bb42a932a23b6f --- React/Modules/RCTUIManager.m | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m index 4653e239ed3f76..5dcce46588ba58 100644 --- a/React/Modules/RCTUIManager.m +++ b/React/Modules/RCTUIManager.m @@ -69,9 +69,6 @@ @implementation RCTUIManager // Keyed by viewName NSDictionary *_componentDataByName; - - BOOL _isMountingInProgress; - BOOL _isRemountingNeeded; } @synthesize bridge = _bridge; @@ -1049,19 +1046,6 @@ - (void)batchDidComplete */ - (void)_layoutAndMount { - // Mounting is (usually, not always) an asynchronous process. - // So, we have to ensure that there is no any case of self-interleaving - // (when another mourning process is initiated before the previous - // one finishes) here. - if (_isMountingInProgress) { - // In a case when another mounting process hasn't completed yet, - // we have to run another pass right after it finishes. - _isRemountingNeeded = YES; - return; - } - - _isMountingInProgress = YES; - [self _dispatchPropsDidChangeEvents]; [self _dispatchChildrenDidChangeEvents]; @@ -1079,13 +1063,6 @@ - (void)_layoutAndMount [self flushUIBlocksWithCompletion:^{ [self->_observerCoordinator uiManagerDidPerformMounting:self]; - - self->_isMountingInProgress = NO; - - if (self->_isRemountingNeeded) { - self->_isRemountingNeeded = NO; - [self _layoutAndMount]; - } }]; } From 046d4cee8b468bcc67be7fb9cae9737908833296 Mon Sep 17 00:00:00 2001 From: "Andrew Chen (Eng)" Date: Thu, 22 Mar 2018 22:06:01 -0700 Subject: [PATCH 0123/1109] Assert root node isn't null in createView Reviewed By: mdvacca Differential Revision: D7374406 fbshipit-source-id: 534e58e7867a9fa8e395abd587e2c808c9c7843d --- .../main/java/com/facebook/react/uimanager/UIImplementation.java | 1 + 1 file changed, 1 insertion(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java index 46353bc28fc390..f33ab605700f29 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java @@ -276,6 +276,7 @@ public Map getProfiledBatchPerfCounters() { public void createView(int tag, String className, int rootViewTag, ReadableMap props) { ReactShadowNode cssNode = createShadowNode(className); ReactShadowNode rootNode = mShadowNodeRegistry.getNode(rootViewTag); + Assertions.assertNotNull(rootNode, "Root node with tag " + rootViewTag + " doesn't exist"); cssNode.setReactTag(tag); cssNode.setViewClassName(className); cssNode.setRootNode(rootNode); From cbb7c7c193ff3ba183e3c2243ec16e196d290996 Mon Sep 17 00:00:00 2001 From: "Andrew Chen (Eng)" Date: Fri, 23 Mar 2018 09:03:45 -0700 Subject: [PATCH 0124/1109] Pass fabric flag from native to JS Reviewed By: mdvacca Differential Revision: D7373722 fbshipit-source-id: 3cd051f38677900693f3da797effa11f9161df37 --- Libraries/Components/View/TestFabricView.js | 24 ------------ .../Components/View/requireFabricView.js | 25 ++++++++++++ Libraries/ReactNative/AppRegistry.js | 5 +-- Libraries/ReactNative/renderFabricSurface.js | 2 +- Libraries/Text/TestFabricText.js | 24 ------------ .../testing/ReactInstrumentationTest.java | 7 +--- .../testing/fabric/FabricTestModule.java | 39 ------------------- .../com/facebook/react/ReactRootView.java | 3 ++ 8 files changed, 31 insertions(+), 98 deletions(-) delete mode 100644 Libraries/Components/View/TestFabricView.js create mode 100644 Libraries/Components/View/requireFabricView.js delete mode 100644 Libraries/Text/TestFabricText.js delete mode 100644 ReactAndroid/src/androidTest/java/com/facebook/react/testing/fabric/FabricTestModule.java diff --git a/Libraries/Components/View/TestFabricView.js b/Libraries/Components/View/TestFabricView.js deleted file mode 100644 index 01e0e4897b2bcc..00000000000000 --- a/Libraries/Components/View/TestFabricView.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule TestFabricView - * @flow - * @format - */ -'use strict'; - -/** - * This is a switch on the correct View to use for Fabric testing purposes - */ -let TestFabricView; -const FabricTestModule = require('NativeModules').FabricTestModule; -if (FabricTestModule && FabricTestModule.IS_FABRIC_ENABLED) { - TestFabricView = require('FabricView'); -} else { - TestFabricView = require('View'); -} - -module.exports = TestFabricView; diff --git a/Libraries/Components/View/requireFabricView.js b/Libraries/Components/View/requireFabricView.js new file mode 100644 index 00000000000000..55a7c40f4da0f6 --- /dev/null +++ b/Libraries/Components/View/requireFabricView.js @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @providesModule requireFabricView + * @flow + * @format + */ +'use strict'; + +/** + * This is a switch on the correct view to use for Fabric + */ +module.exports = (name: string, fabric: boolean) => { + switch (name) { + case 'View': + return fabric ? require('FabricView') : require('View'); + case 'Text': + return fabric ? require('FabricText') : require('Text'); + default: + throw new Error(name + ' is not supported by Fabric yet'); + } +}; diff --git a/Libraries/ReactNative/AppRegistry.js b/Libraries/ReactNative/AppRegistry.js index 21fdca68a43d56..8ddfb64118d043 100644 --- a/Libraries/ReactNative/AppRegistry.js +++ b/Libraries/ReactNative/AppRegistry.js @@ -35,7 +35,6 @@ export type AppConfig = { component?: ComponentProvider, run?: Function, section?: boolean, - fabric?: boolean, }; export type Runnable = { component?: ComponentProvider, @@ -85,7 +84,6 @@ const AppRegistry = { appConfig.appKey, appConfig.component, appConfig.section, - appConfig.fabric, ); } }); @@ -100,13 +98,12 @@ const AppRegistry = { appKey: string, componentProvider: ComponentProvider, section?: boolean, - fabric?: boolean, ): string { runnables[appKey] = { componentProvider, run: appParameters => { let renderFunc = renderApplication; - if (fabric) { + if (appParameters.fabric) { invariant( fabricRendererProvider != null, 'A Fabric renderer provider must be set to render Fabric components', diff --git a/Libraries/ReactNative/renderFabricSurface.js b/Libraries/ReactNative/renderFabricSurface.js index 0279f1759926d6..46536a755ce5a3 100644 --- a/Libraries/ReactNative/renderFabricSurface.js +++ b/Libraries/ReactNative/renderFabricSurface.js @@ -34,7 +34,7 @@ function renderFabricSurface( fabric={true} rootTag={rootTag} WrapperComponent={WrapperComponent}> - + ); diff --git a/Libraries/Text/TestFabricText.js b/Libraries/Text/TestFabricText.js deleted file mode 100644 index cdedcc3177ca64..00000000000000 --- a/Libraries/Text/TestFabricText.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule TestFabricText - * @flow - * @format - */ -'use strict'; - -/** - * This is a switch on the correct Text to use for Fabric testing purposes - */ -let TestFabricText; -const FabricTestModule = require('NativeModules').FabricTestModule; -if (FabricTestModule && FabricTestModule.IS_FABRIC_ENABLED) { - TestFabricText = require('FabricText'); -} else { - TestFabricText = require('Text'); -} - -module.exports = TestFabricText; diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactInstrumentationTest.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactInstrumentationTest.java index 7544395157c665..3f0a7e250bfa72 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactInstrumentationTest.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactInstrumentationTest.java @@ -13,7 +13,6 @@ import android.view.ViewGroup; import com.facebook.react.bridge.JavaScriptModule; import com.facebook.react.bridge.ReactContext; -import com.facebook.react.testing.fabric.FabricTestModule; import com.facebook.react.testing.idledetection.IdleWaiter; /** @@ -116,11 +115,7 @@ protected T getJSModule(Class jsInterface) { * Override this method to provide extra native modules to be loaded before the app starts */ protected ReactInstanceSpecForTest createReactInstanceSpecForTest() { - ReactInstanceSpecForTest instanceSpec = new ReactInstanceSpecForTest(); - if (isFabricTest()) { - instanceSpec.addNativeModule(new FabricTestModule(isFabricTest())); - } - return instanceSpec; + return new ReactInstanceSpecForTest(); } /** diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/fabric/FabricTestModule.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/fabric/FabricTestModule.java deleted file mode 100644 index 0e4fe05b099ab8..00000000000000 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/fabric/FabricTestModule.java +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. - * - * 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.testing.fabric; - -import com.facebook.react.common.MapBuilder; -import java.util.Map; -import javax.annotation.Nullable; - -import com.facebook.react.bridge.BaseJavaModule; -import com.facebook.react.bridge.ReactMethod; -import com.facebook.react.bridge.ReadableArray; -import com.facebook.react.bridge.ReadableMap; - -/** - * Module to indicate if a test is using Fabric - */ -public final class FabricTestModule extends BaseJavaModule { - - private final boolean mIsFabricEnabled; - - public FabricTestModule(boolean isFabricEnabled) { - mIsFabricEnabled = isFabricEnabled; - } - - @Override - public String getName() { - return "FabricTestModule"; - } - - @Override - public Map getConstants() { - return MapBuilder.of("IS_FABRIC_ENABLED", mIsFabricEnabled); - } -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java index 5d4a88bc5025c1..5b8e3c53947ebb 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java @@ -490,6 +490,9 @@ private void defaultJSEntryPoint() { if (appProperties != null) { appParams.putMap("initialProps", Arguments.fromBundle(appProperties)); } + if (isFabric()) { + appParams.putBoolean("fabric", true); + } mShouldLogContentAppeared = true; From dd479a93772c3a52561fc32ee84b25ce822a30fa Mon Sep 17 00:00:00 2001 From: Danny Cochran Date: Fri, 23 Mar 2018 14:45:59 -0700 Subject: [PATCH 0125/1109] Pass invertStickyHeaders to ScrollView Summary: invertStickyHeaders was being set to "this.props.inverted" -- it should just inherit from the props of VirtualizedList instead, per discussion in https://github.com/facebook/react-native/issues/18471 Fixes #18471 Pass "invertStickyHeaders: false" to a SectionList (or FlatList), and expect that your sticky headers stick to the bottom of the ScrollView, instead of the top. none [ANDROID] [BUGFIX] [SectionList] - invertStickyHeaders can now be set from SectionList or FlatList. Closes https://github.com/facebook/react-native/pull/18524 Differential Revision: D7386163 Pulled By: hramos fbshipit-source-id: 3b66dfca280e657303f69f98c5a8bc0df033f9f7 --- Libraries/Lists/VirtualizedList.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Libraries/Lists/VirtualizedList.js b/Libraries/Lists/VirtualizedList.js index 4c7a83b19d77fb..928050f7682fa4 100644 --- a/Libraries/Lists/VirtualizedList.js +++ b/Libraries/Lists/VirtualizedList.js @@ -893,7 +893,9 @@ class VirtualizedList extends React.PureComponent { onScrollEndDrag: this._onScrollEndDrag, onMomentumScrollEnd: this._onMomentumScrollEnd, scrollEventThrottle: this.props.scrollEventThrottle, // TODO: Android support - invertStickyHeaders: this.props.inverted, + invertStickyHeaders: this.props.invertStickyHeaders !== undefined + ? this.props.invertStickyHeaders + : this.props.inverted, stickyHeaderIndices, }; if (inversionStyle) { From 8c0070c706c42cf21a0f55050a1bd718dad47298 Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Fri, 23 Mar 2018 16:46:07 -0700 Subject: [PATCH 0126/1109] iOS: added fabric/core primitives tests Summary: basic tests for fabric core primitives Reviewed By: shergin Differential Revision: D7373952 fbshipit-source-id: e2d9b3c15716c16b1aab698883817e670dcb7a57 --- ReactCommon/fabric/core/BUCK | 34 +++++++++++++--- .../fabric/core/tests/PrimitivesTest.cpp | 40 +++++++++++++++++++ 2 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 ReactCommon/fabric/core/tests/PrimitivesTest.cpp diff --git a/ReactCommon/fabric/core/BUCK b/ReactCommon/fabric/core/BUCK index f566a70f6ee7b0..f394579fc09aeb 100644 --- a/ReactCommon/fabric/core/BUCK +++ b/ReactCommon/fabric/core/BUCK @@ -10,14 +10,12 @@ if not IS_OSS_BUILD: rn_xplat_cxx_library( name = "core", srcs = glob( - [ - "**/*.cpp", - ], + ["**/*.cpp"], + excludes = glob(["tests/**/*.cpp"]), ), headers = glob( - [ - "**/*.h", - ], + ["**/*.h"], + excludes = glob(["tests/**/*.h"]), ), header_namespace = "", exported_headers = subdir_glob( @@ -42,6 +40,9 @@ rn_xplat_cxx_library( "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", ], + tests = [ + ":tests", + ], visibility = ["PUBLIC"], deps = [ "xplat//fbsystrace:fbsystrace", @@ -53,3 +54,24 @@ rn_xplat_cxx_library( react_native_xplat_target("fabric/graphics:graphics"), ], ) + +if not IS_OSS_BUILD: + load("@xplat//configurations/buck:default_platform_defs.bzl", "APPLE") + + cxx_test( + name = "tests", + srcs = glob(["tests/**/*.cpp"]), + contacts = ["oncall+react_native@xmail.facebook.com"], + compiler_flags = [ + "-fexceptions", + "-frtti", + "-std=c++14", + "-Wall", + ], + platforms = APPLE, + deps = [ + "xplat//folly:molly", + "xplat//third-party/gmock:gtest", + ":core", + ], + ) diff --git a/ReactCommon/fabric/core/tests/PrimitivesTest.cpp b/ReactCommon/fabric/core/tests/PrimitivesTest.cpp new file mode 100644 index 00000000000000..99ecae6bfc2827 --- /dev/null +++ b/ReactCommon/fabric/core/tests/PrimitivesTest.cpp @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 + +using namespace facebook::react; + +TEST(SealableTest, sealObjectCorrectly) { + Sealable obj; + ASSERT_FALSE(obj.getSealed()); + + obj.seal(); + ASSERT_TRUE(obj.getSealed()); +} + +TEST(SealableTest, handleAssignmentsCorrectly) { + Sealable obj; + Sealable other; + EXPECT_NO_THROW(obj = other); + + // Assignment after getting sealed is not allowed. + obj.seal(); + Sealable other2; + EXPECT_THROW(obj = other2, std::runtime_error); + + // It doesn't matter if the other object is also sealed, it's still not allowed. + other2.seal(); + EXPECT_THROW(obj = other2, std::runtime_error); + + // Fresh creation off other Sealable is still unsealed. + Sealable other3(obj); + ASSERT_FALSE(other3.getSealed()); +} From e254474d4cbaebdb38ef5fdb5e69ca45257ce6ef Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Fri, 23 Mar 2018 16:46:09 -0700 Subject: [PATCH 0127/1109] iOS: added fabric/core ShadowNode tests Summary: basic tests for shadow nodes and props for fabric Reviewed By: shergin Differential Revision: D7377867 fbshipit-source-id: dc8e5bb369aeb32b4790fd8b56f333376bc1578c --- ReactCommon/fabric/core/shadownode/Props.cpp | 4 + ReactCommon/fabric/core/shadownode/Props.h | 2 + .../fabric/core/shadownode/ShadowNode.cpp | 8 ++ .../fabric/core/shadownode/ShadowNode.h | 2 + .../fabric/core/tests/ShadowNodeTest.cpp | 115 ++++++++++++++++++ 5 files changed, 131 insertions(+) create mode 100644 ReactCommon/fabric/core/tests/ShadowNodeTest.cpp diff --git a/ReactCommon/fabric/core/shadownode/Props.cpp b/ReactCommon/fabric/core/shadownode/Props.cpp index fb527d62be9589..cd5655ee588a58 100644 --- a/ReactCommon/fabric/core/shadownode/Props.cpp +++ b/ReactCommon/fabric/core/shadownode/Props.cpp @@ -25,5 +25,9 @@ void Props::apply(const RawProps &rawProps) { } } +const std::string &Props::getNativeId() const { + return nativeId_; +} + } // namespace react } // namespace facebook diff --git a/ReactCommon/fabric/core/shadownode/Props.h b/ReactCommon/fabric/core/shadownode/Props.h index 8a6a738348792f..5760f34916787f 100644 --- a/ReactCommon/fabric/core/shadownode/Props.h +++ b/ReactCommon/fabric/core/shadownode/Props.h @@ -32,6 +32,8 @@ class Props: virtual void apply(const RawProps &rawProps); + const std::string &getNativeId() const; + private: std::string nativeId_ {""}; }; diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp index 3f7aee7be56b63..0dfb51e1eba236 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp @@ -58,6 +58,14 @@ Tag ShadowNode::getTag() const { return tag_; } +Tag ShadowNode::getRootTag() const { + return rootTag_; +} + +InstanceHandle ShadowNode::getInstanceHandle() const { + return instanceHandle_; +} + SharedShadowNode ShadowNode::getSourceNode() const { return sourceNode_; } diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.h b/ReactCommon/fabric/core/shadownode/ShadowNode.h index 7fcb9d04cfa08e..1deb4d520790f3 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.h +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.h @@ -55,6 +55,8 @@ class ShadowNode: SharedShadowNodeSharedList getChildren() const; SharedProps getProps() const; Tag getTag() const; + Tag getRootTag() const; + InstanceHandle getInstanceHandle() const; SharedShadowNode getSourceNode() const; void sealRecursive() const; diff --git a/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp b/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp new file mode 100644 index 00000000000000..75bc82e8039d0e --- /dev/null +++ b/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp @@ -0,0 +1,115 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 + +using namespace facebook::react; + +class TestProps : public Props { +public: + TestProps() { + RawProps raw; + raw["nativeID"] = "testNativeID"; + apply(raw); + } +}; +using SharedTestProps = std::shared_ptr; + +class TestShadowNode; +using SharedTestShadowNode = std::shared_ptr; +class TestShadowNode : public ConcreteShadowNode { +public: + using ConcreteShadowNode::ConcreteShadowNode; + + ComponentName getComponentName() const override { + return ComponentName("Test"); + } +}; + +TEST(ShadowNodeTest, handleProps) { + RawProps raw; + raw["nativeID"] = "abc"; + + auto props = std::make_shared(); + props->apply(raw); + + // Props are not sealed after applying raw props. + ASSERT_FALSE(props->getSealed()); + + ASSERT_STREQ(props->getNativeId().c_str(), "abc"); +} + +TEST(ShadowNodeTest, handleShadowNodeCreation) { + auto node = std::make_shared(9, 1, (void *)NULL); + + ASSERT_FALSE(node->getSealed()); + ASSERT_STREQ(node->getComponentName().c_str(), "Test"); + ASSERT_EQ(node->getTag(), 9); + ASSERT_EQ(node->getRootTag(), 1); + ASSERT_EQ(node->getInstanceHandle(), (void *)NULL); + TestShadowNode *nodePtr = node.get(); + ASSERT_EQ(node->getComponentHandle(), typeid(*nodePtr).hash_code()); + ASSERT_EQ(node->getSourceNode(), nullptr); + ASSERT_EQ(node->getChildren()->size(), 0); + + // TODO(#27369757): getProps() doesn't work + // ASSERT_STREQ(node->getProps()->getNativeId().c_str(), "testNativeID"); + + node->sealRecursive(); + ASSERT_TRUE(node->getSealed()); + + // TODO(#27369757): verify Props are also sealed. + // ASSERT_TRUE(node->getProps()->getSealed()); +} + +TEST(ShadowNodeTest, handleShadowNodeSimpleCloning) { + auto node = std::make_shared(9, 1, (void *)NULL); + auto node2 = std::make_shared(node); + + ASSERT_STREQ(node->getComponentName().c_str(), "Test"); + ASSERT_EQ(node->getTag(), 9); + ASSERT_EQ(node->getRootTag(), 1); + ASSERT_EQ(node->getInstanceHandle(), (void *)NULL); + ASSERT_EQ(node2->getSourceNode(), node); +} + +TEST(ShadowNodeTest, handleShadowNodeMutation) { + auto node1 = std::make_shared(1, 1, (void *)NULL); + auto node2 = std::make_shared(2, 1, (void *)NULL); + auto node3 = std::make_shared(3, 1, (void *)NULL); + + node1->appendChild(node2); + node1->appendChild(node3); + SharedShadowNodeSharedList node1Children = node1->getChildren(); + ASSERT_EQ(node1Children->size(), 2); + ASSERT_EQ(node1Children->at(0), node2); + ASSERT_EQ(node1Children->at(1), node3); + + auto node4 = std::make_shared(node2); + node1->replaceChild(node2, node4); + node1Children = node1->getChildren(); + ASSERT_EQ(node1Children->size(), 2); + ASSERT_EQ(node1Children->at(0), node4); + ASSERT_EQ(node1Children->at(1), node3); + + // Seal the entire tree. + node1->sealRecursive(); + ASSERT_TRUE(node1->getSealed()); + ASSERT_TRUE(node3->getSealed()); + ASSERT_TRUE(node4->getSealed()); + + // No more mutation after sealing. + EXPECT_THROW(node4->clearSourceNode(), std::runtime_error); + + auto node5 = std::make_shared(node4); + node5->clearSourceNode(); + ASSERT_EQ(node5->getSourceNode(), nullptr); +} From 408a5f264b4f67873e6763c3a718bafe40fd48b3 Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Fri, 23 Mar 2018 16:46:10 -0700 Subject: [PATCH 0128/1109] iOS: added fabric/core ComponentDescriptor tests Summary: Basic test for ComponentDescriptor mechanism. Reviewed By: shergin Differential Revision: D7388297 fbshipit-source-id: 3b0c625656e31df03d71a2e036388621a5e2e21d --- ReactCommon/fabric/core/BUCK | 1 + .../ConcreteComponentDescriptor.h | 3 +- .../fabric/core/shadownode/ShadowNode.cpp | 1 + .../core/tests/ComponentDescriptorTest.cpp | 66 +++++++++++++++++++ .../fabric/core/tests/ShadowNodeTest.cpp | 23 +------ ReactCommon/fabric/core/tests/TestComponent.h | 50 ++++++++++++++ 6 files changed, 122 insertions(+), 22 deletions(-) create mode 100644 ReactCommon/fabric/core/tests/ComponentDescriptorTest.cpp create mode 100644 ReactCommon/fabric/core/tests/TestComponent.h diff --git a/ReactCommon/fabric/core/BUCK b/ReactCommon/fabric/core/BUCK index f394579fc09aeb..d9ee58fae8b50b 100644 --- a/ReactCommon/fabric/core/BUCK +++ b/ReactCommon/fabric/core/BUCK @@ -61,6 +61,7 @@ if not IS_OSS_BUILD: cxx_test( name = "tests", srcs = glob(["tests/**/*.cpp"]), + headers = glob(["tests/**/*.h"]), contacts = ["oncall+react_native@xmail.facebook.com"], compiler_flags = [ "-fexceptions", diff --git a/ReactCommon/fabric/core/componentdescriptor/ConcreteComponentDescriptor.h b/ReactCommon/fabric/core/componentdescriptor/ConcreteComponentDescriptor.h index 0a521bd4999452..95de5e17534dc7 100644 --- a/ReactCommon/fabric/core/componentdescriptor/ConcreteComponentDescriptor.h +++ b/ReactCommon/fabric/core/componentdescriptor/ConcreteComponentDescriptor.h @@ -9,8 +9,9 @@ #include -#include +#include #include +#include namespace facebook { namespace react { diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp index 0dfb51e1eba236..04fb5d30f86f4b 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp @@ -39,6 +39,7 @@ ShadowNode::ShadowNode( SharedShadowNodeSharedList children ): tag_(shadowNode->tag_), + rootTag_(shadowNode->rootTag_), instanceHandle_(shadowNode->instanceHandle_), props_(props ? props : shadowNode->props_), children_(children ? children : shadowNode->children_), diff --git a/ReactCommon/fabric/core/tests/ComponentDescriptorTest.cpp b/ReactCommon/fabric/core/tests/ComponentDescriptorTest.cpp new file mode 100644 index 00000000000000..699642ce7f2d34 --- /dev/null +++ b/ReactCommon/fabric/core/tests/ComponentDescriptorTest.cpp @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include "TestComponent.h" + +using namespace facebook::react; + +TEST(ComponentDescriptorTest, createShadowNode) { + SharedComponentDescriptor descriptor = std::make_shared(); + + ASSERT_EQ(descriptor->getComponentHandle(), typeid(TestShadowNode).hash_code()); + ASSERT_STREQ(descriptor->getComponentName().c_str(), "Test"); + + RawProps raw; + raw["nativeID"] = "abc"; + SharedShadowNode node = descriptor->createShadowNode(9, 1, (void *)NULL, raw); + + ASSERT_EQ(node->getComponentHandle(), typeid(TestShadowNode).hash_code()); + ASSERT_STREQ(node->getComponentName().c_str(), "Test"); + ASSERT_EQ(node->getTag(), 9); + ASSERT_EQ(node->getRootTag(), 1); + + // TODO(#27369757): getProps() doesn't work + // ASSERT_STREQ(node->getProps()->getNativeId().c_str(), "testNativeID"); +} + +TEST(ComponentDescriptorTest, cloneShadowNode) { + SharedComponentDescriptor descriptor = std::make_shared(); + + RawProps raw; + raw["nativeID"] = "abc"; + SharedShadowNode node = descriptor->createShadowNode(9, 1, (void *)NULL, raw); + SharedShadowNode cloned = descriptor->cloneShadowNode(node); + + ASSERT_EQ(cloned->getComponentHandle(), typeid(TestShadowNode).hash_code()); + ASSERT_STREQ(cloned->getComponentName().c_str(), "Test"); + ASSERT_EQ(cloned->getTag(), 9); + ASSERT_EQ(cloned->getRootTag(), 1); + + // TODO(#27369757): getProps() doesn't work + // ASSERT_STREQ(cloned->getProps()->getNativeId().c_str(), "testNativeID"); +} + +TEST(ComponentDescriptorTest, appendChild) { + SharedComponentDescriptor descriptor = std::make_shared(); + + RawProps raw; + raw["nativeID"] = "abc"; + SharedShadowNode node1 = descriptor->createShadowNode(1, 1, (void *)NULL, raw); + SharedShadowNode node2 = descriptor->createShadowNode(2, 1, (void *)NULL, raw); + SharedShadowNode node3 = descriptor->createShadowNode(3, 1, (void *)NULL, raw); + + descriptor->appendChild(node1, node2); + descriptor->appendChild(node1, node3); + + SharedShadowNodeSharedList node1Children = node1->getChildren(); + ASSERT_EQ(node1Children->size(), 2); + ASSERT_EQ(node1Children->at(0), node2); + ASSERT_EQ(node1Children->at(1), node3); +} diff --git a/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp b/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp index 75bc82e8039d0e..418938a497e1ab 100644 --- a/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp +++ b/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp @@ -11,28 +11,9 @@ #include #include -using namespace facebook::react; +#include "TestComponent.h" -class TestProps : public Props { -public: - TestProps() { - RawProps raw; - raw["nativeID"] = "testNativeID"; - apply(raw); - } -}; -using SharedTestProps = std::shared_ptr; - -class TestShadowNode; -using SharedTestShadowNode = std::shared_ptr; -class TestShadowNode : public ConcreteShadowNode { -public: - using ConcreteShadowNode::ConcreteShadowNode; - - ComponentName getComponentName() const override { - return ComponentName("Test"); - } -}; +using namespace facebook::react; TEST(ShadowNodeTest, handleProps) { RawProps raw; diff --git a/ReactCommon/fabric/core/tests/TestComponent.h b/ReactCommon/fabric/core/tests/TestComponent.h new file mode 100644 index 00000000000000..18890daeb03dd5 --- /dev/null +++ b/ReactCommon/fabric/core/tests/TestComponent.h @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 + +using namespace facebook::react; + +/** + * This defines a set of TestComponent classes: Props, ShadowNode, ComponentDescriptor. + * To be used for testing purpose. + */ + +class TestProps : public Props { +public: + TestProps() { + RawProps raw; + raw["nativeID"] = "testNativeID"; + apply(raw); + } +}; +using SharedTestProps = std::shared_ptr; + +class TestShadowNode; +using SharedTestShadowNode = std::shared_ptr; +class TestShadowNode : public ConcreteShadowNode { +public: + using ConcreteShadowNode::ConcreteShadowNode; + + ComponentName getComponentName() const override { + return ComponentName("Test"); + } +}; + +class TestComponentDescriptor: public ConcreteComponentDescriptor { +public: + // TODO (shergin): Why does this gets repeated here and the shadow node class? + ComponentName getComponentName() const override { + return "Test"; + } +}; From 1acef4597747cc3068ae25bd22c26d500a228f3b Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Fri, 23 Mar 2018 22:09:11 -0700 Subject: [PATCH 0129/1109] iOS: added placeholder test setup for fabric graphics/uimanager/view targets Reviewed By: shergin Differential Revision: D7390366 fbshipit-source-id: d49fcc335fc03d52402676341f1da24177c6084b --- ReactCommon/fabric/debug/BUCK | 11 ++-- ReactCommon/fabric/graphics/BUCK | 35 ++++++++++--- .../fabric/graphics/tests/GraphicsTest.cpp | 17 +++++++ ReactCommon/fabric/uimanager/BUCK | 35 ++++++++++--- .../uimanager/tests/FabricUIManagerTest.cpp | 17 +++++++ ReactCommon/fabric/view/BUCK | 50 +++++++++++++++---- ReactCommon/fabric/view/tests/ViewTest.cpp | 17 +++++++ 7 files changed, 153 insertions(+), 29 deletions(-) create mode 100644 ReactCommon/fabric/graphics/tests/GraphicsTest.cpp create mode 100644 ReactCommon/fabric/uimanager/tests/FabricUIManagerTest.cpp create mode 100644 ReactCommon/fabric/view/tests/ViewTest.cpp diff --git a/ReactCommon/fabric/debug/BUCK b/ReactCommon/fabric/debug/BUCK index 6ce9e7f29e3d66..d22caf8f955691 100644 --- a/ReactCommon/fabric/debug/BUCK +++ b/ReactCommon/fabric/debug/BUCK @@ -10,14 +10,12 @@ if not IS_OSS_BUILD: rn_xplat_cxx_library( name = "debug", srcs = glob( - [ - "*.cpp", - ], + ["**/*.cpp"], + excludes = glob(["tests/**/*.cpp"]), ), headers = glob( - [ - "*.h", - ], + ["**/*.h"], + excludes = glob(["tests/**/*.h"]), ), header_namespace = "", exported_headers = subdir_glob( @@ -54,6 +52,7 @@ if not IS_OSS_BUILD: cxx_test( name = "tests", srcs = glob(["tests/**/*.cpp"]), + headers = glob(["tests/**/*.h"]), contacts = ["oncall+react_native@xmail.facebook.com"], compiler_flags = [ "-fexceptions", diff --git a/ReactCommon/fabric/graphics/BUCK b/ReactCommon/fabric/graphics/BUCK index e1a020d730b4a9..967f33aafc9b69 100644 --- a/ReactCommon/fabric/graphics/BUCK +++ b/ReactCommon/fabric/graphics/BUCK @@ -10,14 +10,12 @@ if not IS_OSS_BUILD: rn_xplat_cxx_library( name = "graphics", srcs = glob( - [ - "**/*.cpp", - ], + ["**/*.cpp"], + excludes = glob(["tests/**/*.cpp"]), ), headers = glob( - [ - "**/*.h", - ], + ["**/*.h"], + excludes = glob(["tests/**/*.h"]), ), header_namespace = "", exported_headers = subdir_glob( @@ -39,6 +37,9 @@ rn_xplat_cxx_library( "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", ], + tests = [ + ":tests", + ], visibility = ["PUBLIC"], deps = [ "xplat//fbsystrace:fbsystrace", @@ -48,3 +49,25 @@ rn_xplat_cxx_library( "xplat//third-party/glog:glog", ], ) + +if not IS_OSS_BUILD: + load("@xplat//configurations/buck:default_platform_defs.bzl", "APPLE") + + cxx_test( + name = "tests", + srcs = glob(["tests/**/*.cpp"]), + headers = glob(["tests/**/*.h"]), + contacts = ["oncall+react_native@xmail.facebook.com"], + compiler_flags = [ + "-fexceptions", + "-frtti", + "-std=c++14", + "-Wall", + ], + platforms = APPLE, + deps = [ + "xplat//folly:molly", + "xplat//third-party/gmock:gtest", + ":graphics", + ], + ) diff --git a/ReactCommon/fabric/graphics/tests/GraphicsTest.cpp b/ReactCommon/fabric/graphics/tests/GraphicsTest.cpp new file mode 100644 index 00000000000000..3b88ac8a423dee --- /dev/null +++ b/ReactCommon/fabric/graphics/tests/GraphicsTest.cpp @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 + +using namespace facebook::react; + +TEST(GraphicsTest, testSomething) { + // TODO +} diff --git a/ReactCommon/fabric/uimanager/BUCK b/ReactCommon/fabric/uimanager/BUCK index dc7939377d9713..ca7700e5c44bb3 100644 --- a/ReactCommon/fabric/uimanager/BUCK +++ b/ReactCommon/fabric/uimanager/BUCK @@ -10,14 +10,12 @@ if not IS_OSS_BUILD: rn_xplat_cxx_library( name = "uimanager", srcs = glob( - [ - "**/*.cpp", - ], + ["**/*.cpp"], + excludes = glob(["tests/**/*.cpp"]), ), headers = glob( - [ - "**/*.h", - ], + ["**/*.h"], + excludes = glob(["tests/**/*.h"]), ), header_namespace = "", exported_headers = subdir_glob( @@ -39,6 +37,9 @@ rn_xplat_cxx_library( "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", ], + tests = [ + ":tests", + ], visibility = ["PUBLIC"], deps = [ "xplat//fbsystrace:fbsystrace", @@ -51,3 +52,25 @@ rn_xplat_cxx_library( react_native_xplat_target("fabric/view:view"), ], ) + +if not IS_OSS_BUILD: + load("@xplat//configurations/buck:default_platform_defs.bzl", "APPLE") + + cxx_test( + name = "tests", + srcs = glob(["tests/**/*.cpp"]), + headers = glob(["tests/**/*.h"]), + contacts = ["oncall+react_native@xmail.facebook.com"], + compiler_flags = [ + "-fexceptions", + "-frtti", + "-std=c++14", + "-Wall", + ], + platforms = APPLE, + deps = [ + "xplat//folly:molly", + "xplat//third-party/gmock:gtest", + ":uimanager", + ], + ) diff --git a/ReactCommon/fabric/uimanager/tests/FabricUIManagerTest.cpp b/ReactCommon/fabric/uimanager/tests/FabricUIManagerTest.cpp new file mode 100644 index 00000000000000..d22ed7f946314e --- /dev/null +++ b/ReactCommon/fabric/uimanager/tests/FabricUIManagerTest.cpp @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 + +using namespace facebook::react; + +TEST(FabricUIManagerTest, testSomething) { + // TODO +} diff --git a/ReactCommon/fabric/view/BUCK b/ReactCommon/fabric/view/BUCK index 3db0dd82bf72df..5716485f77e51e 100644 --- a/ReactCommon/fabric/view/BUCK +++ b/ReactCommon/fabric/view/BUCK @@ -2,22 +2,21 @@ load("//configurations/buck/apple:flag_defs.bzl", "get_application_ios_flags", " load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "rn_xplat_cxx_library", "APPLE_INSPECTOR_FLAGS") load("//ReactNative:DEFS.bzl", "react_native_xplat_target") -CXX_LIBRARY_COMPILER_FLAGS = [ - "-std=c++14", - "-Wall", -] +APPLE_COMPILER_FLAGS = [] + +if not IS_OSS_BUILD: + load("@xplat//configurations/buck/apple:flag_defs.bzl", "get_static_library_ios_flags", "flags") + APPLE_COMPILER_FLAGS = flags.get_flag_value(get_static_library_ios_flags(), 'compiler_flags') rn_xplat_cxx_library( name = "view", srcs = glob( - [ - "**/*.cpp", - ], + ["**/*.cpp"], + excludes = glob(["tests/**/*.cpp"]), ), headers = glob( - [ - "**/*.h", - ], + ["**/*.h"], + excludes = glob(["tests/**/*.h"]), ), header_namespace = "", exported_headers = subdir_glob( @@ -28,15 +27,22 @@ rn_xplat_cxx_library( ], prefix = "fabric/view", ), - compiler_flags = CXX_LIBRARY_COMPILER_FLAGS + [ + compiler_flags = [ "-fexceptions", "-frtti", + "-std=c++14", + "-Wall", ], + fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, + fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + APPLE_INSPECTOR_FLAGS, force_static = True, preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", ], + tests = [ + ":tests", + ], visibility = ["PUBLIC"], deps = [ "xplat//fbsystrace:fbsystrace", @@ -50,3 +56,25 @@ rn_xplat_cxx_library( react_native_xplat_target("fabric/graphics:graphics"), ], ) + +if not IS_OSS_BUILD: + load("@xplat//configurations/buck:default_platform_defs.bzl", "APPLE") + + cxx_test( + name = "tests", + srcs = glob(["tests/**/*.cpp"]), + headers = glob(["tests/**/*.h"]), + contacts = ["oncall+react_native@xmail.facebook.com"], + compiler_flags = [ + "-fexceptions", + "-frtti", + "-std=c++14", + "-Wall", + ], + platforms = APPLE, + deps = [ + "xplat//folly:molly", + "xplat//third-party/gmock:gtest", + ":view", + ], + ) diff --git a/ReactCommon/fabric/view/tests/ViewTest.cpp b/ReactCommon/fabric/view/tests/ViewTest.cpp new file mode 100644 index 00000000000000..6ea577d8fa52bf --- /dev/null +++ b/ReactCommon/fabric/view/tests/ViewTest.cpp @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 + +using namespace facebook::react; + +TEST(ViewTest, testSomething) { + // TODO +} From 228f5c83f9f2459b119ff388d0abd8e2f852c6c7 Mon Sep 17 00:00:00 2001 From: Jake Date: Sat, 24 Mar 2018 23:04:41 -0700 Subject: [PATCH 0130/1109] use correct delegate queue in RCTRSWebSocket Summary: This commit makes the websocket's delegate dispatch queue use `RCTWebSocketModule`'s method queue. This fixes a bug where didReceiveMessage was called on the wrong queue, which is especially harmful if the websocket has a contentHandler expects to be running on the RCTWebSocketModule's method queue. This also fixes the race condition where `_contentHandlers` and `_sockets` can be mutated from the main dispatch queue (the default in `RCTRSWebSocket`) and `RCTWebSocketModule`'s method queue. Websockets still work, and hopefully crash less now. - [iOS][BUGFIX][WebSocket] fix crashes caused by a race condition in websocket delegates. Closes https://github.com/facebook/react-native/pull/18530 Differential Revision: D7394298 Pulled By: hramos fbshipit-source-id: 230466ccb47ea532ced15cd7603256a19077b32b --- Libraries/WebSocket/RCTWebSocketModule.m | 1 + 1 file changed, 1 insertion(+) diff --git a/Libraries/WebSocket/RCTWebSocketModule.m b/Libraries/WebSocket/RCTWebSocketModule.m index 425ff9873643b9..bc79dcd16c3040 100644 --- a/Libraries/WebSocket/RCTWebSocketModule.m +++ b/Libraries/WebSocket/RCTWebSocketModule.m @@ -82,6 +82,7 @@ - (void)invalidate }]; RCTSRWebSocket *webSocket = [[RCTSRWebSocket alloc] initWithURLRequest:request protocols:protocols]; + [webSocket setDelegateDispatchQueue:_methodQueue]; webSocket.delegate = self; webSocket.reactTag = socketID; if (!_sockets) { From 2cc75f7d4781a7ec7b5f4566964b988435859e5e Mon Sep 17 00:00:00 2001 From: Jonathan Dann Date: Sun, 25 Mar 2018 13:56:13 -0700 Subject: [PATCH 0131/1109] Add YGNodeSetChildren(), YGNodeTraversePreOrder() Reviewed By: Woody17 Differential Revision: D7360203 fbshipit-source-id: 32df8e1213ead03bc0a026ec4bf453bc799bb9ce --- ReactCommon/yoga/yoga/Yoga.cpp | 61 ++++++++++++++++++++++++++++++++-- ReactCommon/yoga/yoga/Yoga.h | 13 ++++++++ 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index 570f7ab964e157..1600b1b05fa0b4 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -295,8 +295,8 @@ static YGNodeRef YGNodeDeepClone(YGNodeRef oldNode) { } void YGNodeFree(const YGNodeRef node) { - if (node->getParent()) { - node->getParent()->removeChild(node); + if (YGNodeRef parent = node->getParent()) { + parent->removeChild(node); node->setParent(nullptr); } @@ -477,6 +477,48 @@ void YGNodeRemoveAllChildren(const YGNodeRef parent) { parent->markDirtyAndPropogate(); } +static void YGNodeSetChildrenInternal(YGNodeRef const parent, const std::vector &children) +{ + if (!parent) { + return; + } + if (children.size() == 0) { + if (YGNodeGetChildCount(parent) > 0) { + for (YGNodeRef const child : parent->getChildren()) { + child->setLayout(YGLayout()); + child->setParent(nullptr); + } + parent->setChildren(YGVector()); + parent->markDirtyAndPropogate(); + } + } else { + if (YGNodeGetChildCount(parent) > 0) { + for (YGNodeRef const oldChild : parent->getChildren()) { + // Our new children may have nodes in common with the old children. We don't reset these common nodes. + if (std::find(children.begin(), children.end(), oldChild) == children.end()) { + oldChild->setLayout(YGLayout()); + oldChild->setParent(nullptr); + } + } + } + parent->setChildren(children); + for (YGNodeRef child : children) { + child->setParent(parent); + } + parent->markDirtyAndPropogate(); + } +} + +void YGNodeSetChildren(YGNodeRef const parent, const YGNodeRef c[], const uint32_t count) { + const YGVector children = {c, c + count}; + YGNodeSetChildrenInternal(parent, children); +} + +void YGNodeSetChildren(YGNodeRef const parent, const std::vector &children) +{ + YGNodeSetChildrenInternal(parent, children); +} + YGNodeRef YGNodeGetChild(const YGNodeRef node, const uint32_t index) { if (index < node->getChildren().size()) { return node->getChild(index); @@ -3925,3 +3967,18 @@ void *YGConfigGetContext(const YGConfigRef config) { void YGConfigSetNodeClonedFunc(const YGConfigRef config, const YGNodeClonedFunc callback) { config->cloneNodeCallback = callback; } + +static void YGTraverseChildrenPreOrder(const YGVector& children, const std::function& f) { + for (YGNodeRef node : children) { + f(node); + YGTraverseChildrenPreOrder(node->getChildren(), f); + } +} + +void YGTraversePreOrder(YGNodeRef const node, std::function&& f) { + if (!node) { + return; + } + f(node); + YGTraverseChildrenPreOrder(node->getChildren(), f); +} diff --git a/ReactCommon/yoga/yoga/Yoga.h b/ReactCommon/yoga/yoga/Yoga.h index 2ec6a687ee742f..1a985fa56317d9 100644 --- a/ReactCommon/yoga/yoga/Yoga.h +++ b/ReactCommon/yoga/yoga/Yoga.h @@ -84,6 +84,7 @@ WIN_EXPORT void YGNodeRemoveAllChildren(const YGNodeRef node); WIN_EXPORT YGNodeRef YGNodeGetChild(const YGNodeRef node, const uint32_t index); WIN_EXPORT YGNodeRef YGNodeGetParent(const YGNodeRef node); WIN_EXPORT uint32_t YGNodeGetChildCount(const YGNodeRef node); +WIN_EXPORT void YGNodeSetChildren(YGNodeRef const parent, const YGNodeRef children[], const uint32_t count); WIN_EXPORT void YGNodeCalculateLayout(const YGNodeRef node, const float availableWidth, @@ -298,3 +299,15 @@ WIN_EXPORT float YGRoundValueToPixelGrid( const bool forceFloor); YG_EXTERN_C_END + +#ifdef __cplusplus + +#include +#include + +// Calls f on each node in the tree including the given node argument. +extern void YGTraversePreOrder(YGNodeRef const node, std::function&& f); + +extern void YGNodeSetChildren(YGNodeRef const parent, const std::vector &children); + +#endif From 8b9b3f605ed9691728872e74dd555a0b1792c47a Mon Sep 17 00:00:00 2001 From: Gustavo Gard Date: Sun, 25 Mar 2018 19:46:13 -0700 Subject: [PATCH 0132/1109] Correct AnimatedValueXY URL Summary: Correct URL Closes https://github.com/facebook/react-native/pull/18556 Differential Revision: D7396357 Pulled By: mdvacca fbshipit-source-id: f8ff6c9b037fe733cf3be8d1b889d1dcd9c94afb --- Libraries/Animated/src/AnimatedImplementation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/Animated/src/AnimatedImplementation.js b/Libraries/Animated/src/AnimatedImplementation.js index 69a96ba1d3e6ba..e13aef1e723550 100644 --- a/Libraries/Animated/src/AnimatedImplementation.js +++ b/Libraries/Animated/src/AnimatedImplementation.js @@ -521,7 +521,7 @@ module.exports = { /** * 2D value class for driving 2D animations, such as pan gestures. * - * See https://facebook.github.io/react-native/releases/next/docs/animatedvaluexy.html + * See https://facebook.github.io/react-native/docs/animatedvaluexy.html */ ValueXY: AnimatedValueXY, /** From 85e33aaf908996e99220bff4a2bdbbdf7c0d12b0 Mon Sep 17 00:00:00 2001 From: Tadeu Valentt Date: Sun, 25 Mar 2018 20:39:22 -0700 Subject: [PATCH 0133/1109] Prevents android crash due to unsupported ellipsize mode Summary: Fixes #18474 This allows use clip as ellipsize mode for truncated text on android Added a test to RNTester, so it can be tested from there: 1. Run RNTester project 2. Navigate to `` tests 3. Scroll down to "Ellipsize mode" examples 4. Check the default behavior being applied when the value is set to "clip" [ANDROID] [BUGFIX] [Text] - Prevents android crash due to unsupported "clip" ellipsize mode Closes https://github.com/facebook/react-native/pull/18540 Differential Revision: D7396379 Pulled By: mdvacca fbshipit-source-id: 6c4b223731143c5081b3d12a3c740d1e375bd586 --- RNTester/js/TextExample.android.js | 3 +++ .../facebook/react/views/text/ReactTextAnchorViewManager.java | 2 ++ 2 files changed, 5 insertions(+) diff --git a/RNTester/js/TextExample.android.js b/RNTester/js/TextExample.android.js index 0b0bf195f68fb7..b912337827a279 100644 --- a/RNTester/js/TextExample.android.js +++ b/RNTester/js/TextExample.android.js @@ -453,6 +453,9 @@ class TextExample extends React.Component<{}> { This very long text should be truncated with dots in the beginning. + + This very long text should be clipped and this will not be visible. + diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextAnchorViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextAnchorViewManager.java index 71ba5eef46095f..776bce7ccdc565 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextAnchorViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextAnchorViewManager.java @@ -52,6 +52,8 @@ public void setEllipsizeMode(ReactTextView view, @Nullable String ellipsizeMode) view.setEllipsizeLocation(TextUtils.TruncateAt.START); } else if (ellipsizeMode.equals("middle")) { view.setEllipsizeLocation(TextUtils.TruncateAt.MIDDLE); + } else if (ellipsizeMode.equals("clip")) { + view.setEllipsizeLocation(null); } else { throw new JSApplicationIllegalArgumentException("Invalid ellipsizeMode: " + ellipsizeMode); } From 226bff3ed0772ff3b9d69ea45fb57f3c0c930029 Mon Sep 17 00:00:00 2001 From: Dulmandakh Date: Sun, 25 Mar 2018 20:56:27 -0700 Subject: [PATCH 0134/1109] Android: include error types in getCurrentPosition error Summary: Thank you for sending the PR! We appreciate you spending the time to work on these changes. Help us understand your motivation by explaining why you decided to make this change. Include geolocation error types in error, and provide feature parity with iOS. If error occurs when you call getCurrentPosition, then error object includes PERMISSION_DENIED, POSITION_UNAVAILABLE, TIMEOUT keys with error codes. It should be used to compare with error.code value. This is minor fix that provides feature parity with iOS. Closes https://github.com/facebook/react-native/pull/18533 Differential Revision: D7396586 Pulled By: mdvacca fbshipit-source-id: bd698b80a3d075456738a3d4e48b572ae819ee3d --- .../facebook/react/modules/location/PositionError.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/location/PositionError.java b/ReactAndroid/src/main/java/com/facebook/react/modules/location/PositionError.java index 82f7d0dc801544..f8dffa5850ae07 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/location/PositionError.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/location/PositionError.java @@ -35,9 +35,17 @@ public class PositionError { public static WritableMap buildError(int code, String message) { WritableMap error = Arguments.createMap(); error.putInt("code", code); + if (message != null) { error.putString("message", message); } + + /** + * Provide error types in error message. Feature parity with iOS + */ + error.putInt("PERMISSION_DENIED", PERMISSION_DENIED); + error.putInt("POSITION_UNAVAILABLE", POSITION_UNAVAILABLE); + error.putInt("TIMEOUT", TIMEOUT); return error; } } From ca20fcd47d55585e66f429e698afda49abdc339c Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Sun, 25 Mar 2018 22:00:11 -0700 Subject: [PATCH 0135/1109] Use afterEvaluate to make gradle bundle task work with configureondemand Summary: The js bundle task does not run when `org.gradle.configureondemand` is set to true. This uses `afterEvaluate` instead of `gradle.projectsEvaluated` which is executed properly. Add `org.gradle.configureondemand=true`, run RNTester in release mode and make sure the bundle task is run. [ANDROID] [BUGFIX] [LOCATION] - Fix release bundle task when org.gradle.configureondemand=true Closes https://github.com/facebook/react-native/pull/18557 Differential Revision: D7396744 Pulled By: mdvacca fbshipit-source-id: 9ea134cb49e8a087cec16f82b990cd19af76785a --- RNTester/android/app/gradle.properties | 2 ++ react.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/RNTester/android/app/gradle.properties b/RNTester/android/app/gradle.properties index 74027349d96fa2..04cbf4f74219c9 100644 --- a/RNTester/android/app/gradle.properties +++ b/RNTester/android/app/gradle.properties @@ -1,4 +1,6 @@ android.useDeprecatedNdk=true +org.gradle.parallel=true +org.gradle.configureondemand=true MYAPP_RELEASE_STORE_FILE=my-release-key.keystore MYAPP_RELEASE_KEY_ALIAS=my-key-alias MYAPP_RELEASE_STORE_PASSWORD=***** diff --git a/react.gradle b/react.gradle index 64b2f02f8cbf26..bdf392ad9a717b 100644 --- a/react.gradle +++ b/react.gradle @@ -23,7 +23,7 @@ void runBefore(String dependentTaskName, Task task) { } } -gradle.projectsEvaluated { +afterEvaluate { // Grab all build types and product flavors def buildTypes = android.buildTypes.collect { type -> type.name } def productFlavors = android.productFlavors.collect { flavor -> flavor.name } From 53782eafc96d9f0564e25c668c57a60321ccc2ec Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Sun, 25 Mar 2018 22:43:26 -0700 Subject: [PATCH 0136/1109] Fabric: Source shadow node is now stored as a weak pointer Summary: We use shource nodes only in the diffing alogorithm. It implies that we have strong pointers to those nodes in trees we compare against. Using weak_ptr's allows to avoid memory leaks. Reviewed By: mdvacca Differential Revision: D7376348 fbshipit-source-id: 34e5f58f18a00475f6bcdfbea3996b41c84dff62 --- ReactCommon/fabric/core/shadownode/ShadowNode.cpp | 9 +++++---- ReactCommon/fabric/core/shadownode/ShadowNode.h | 3 ++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp index 04fb5d30f86f4b..e1394cccca717d 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp @@ -68,7 +68,7 @@ InstanceHandle ShadowNode::getInstanceHandle() const { } SharedShadowNode ShadowNode::getSourceNode() const { - return sourceNode_; + return sourceNode_.lock(); } void ShadowNode::sealRecursive() const { @@ -111,7 +111,7 @@ void ShadowNode::replaceChild(const SharedShadowNode &oldChild, const SharedShad void ShadowNode::clearSourceNode() { ensureUnsealed(); - sourceNode_ = nullptr; + sourceNode_.reset(); } #pragma mark - DebugStringConvertible @@ -146,10 +146,11 @@ SharedDebugStringConvertibleList ShadowNode::getDebugProps() const { list.push_back(std::make_shared("handle", std::to_string((size_t)instanceHandle_))); } - if (sourceNode_) { + SharedShadowNode sourceNode = getSourceNode(); + if (sourceNode) { list.push_back(std::make_shared( "source", - sourceNode_->getDebugDescription({.maximumDepth = 1, .format = false}) + sourceNode->getDebugDescription({.maximumDepth = 1, .format = false}) )); } diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.h b/ReactCommon/fabric/core/shadownode/ShadowNode.h index 1deb4d520790f3..aa68556f9ce3a9 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.h +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.h @@ -24,6 +24,7 @@ using SharedShadowNode = std::shared_ptr; using SharedShadowNodeList = std::vector>; using SharedShadowNodeSharedList = std::shared_ptr; using SharedShadowNodeUnsharedList = std::shared_ptr; +using WeakShadowNode = std::weak_ptr; class ShadowNode: public virtual Sealable, @@ -79,7 +80,7 @@ class ShadowNode: InstanceHandle instanceHandle_; SharedProps props_; SharedShadowNodeSharedList children_; - SharedShadowNode sourceNode_; + WeakShadowNode sourceNode_; }; } // namespace react From 1bb6db36bef1c5018c06ada5763554b23312060f Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Sun, 25 Mar 2018 22:43:28 -0700 Subject: [PATCH 0137/1109] Fabric: Removed unused copy constructor YogaLayoutableShadowNode() Summary: Trivial. We don't use it, and it shouldn't be exist by desing. Reviewed By: mdvacca Differential Revision: D7376351 fbshipit-source-id: 22f03af2b3596c274a22bab1fab6d8af854a7374 --- ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp | 7 ------- ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.h | 1 - 2 files changed, 8 deletions(-) diff --git a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp index 09301f35b50afa..f53d63f70eeaad 100644 --- a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp +++ b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp @@ -31,13 +31,6 @@ SharedYogaConfig YogaLayoutableShadowNode::suitableYogaConfig() { return sharedYogaConfig; } -YogaLayoutableShadowNode::YogaLayoutableShadowNode() { - auto yogaNode = std::make_shared(); - yogaNode->markDirtyAndPropogate(); - yogaNode->setConfig(suitableYogaConfig().get()); - yogaNode->setContext(this); - yogaNode_ = yogaNode; -} YogaLayoutableShadowNode::YogaLayoutableShadowNode( const SharedYogaStylableProps &props, diff --git a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.h b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.h index cba25fe87d2b0d..e07acc8598cf91 100644 --- a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.h +++ b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.h @@ -40,7 +40,6 @@ class YogaLayoutableShadowNode: public: #pragma mark - Constructors - YogaLayoutableShadowNode(); YogaLayoutableShadowNode( const SharedYogaStylableProps &props, From 8f9212b83922e3adeb3dcdd20d239ebab7a1fcda Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Sun, 25 Mar 2018 22:43:30 -0700 Subject: [PATCH 0138/1109] Fabric: Fixed lost YogaNode's context in YogaLayoutableShadowNode Summary: We replace yogaNode with newly creaded (by Yoga) one. So, we have to set up context. Reviewed By: mdvacca Differential Revision: D7376345 fbshipit-source-id: 7926a10e3f057fc385e7731c354827aeb8245760 --- ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp index f53d63f70eeaad..376f092367c968 100644 --- a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp +++ b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp @@ -31,7 +31,6 @@ SharedYogaConfig YogaLayoutableShadowNode::suitableYogaConfig() { return sharedYogaConfig; } - YogaLayoutableShadowNode::YogaLayoutableShadowNode( const SharedYogaStylableProps &props, const SharedShadowNodeSharedList &children @@ -198,6 +197,7 @@ void YogaLayoutableShadowNode::yogaNodeCloneCallbackConnector(YGNode *oldYogaNod assert(newShadowNode); // And finally, we have to replace underline yoga node with the new one provided by Yoga. + newYogaNode->setContext((void *)newShadowNode.get()); newShadowNode->yogaNode_ = std::shared_ptr(newYogaNode); } From ee0cc6bbe7b4597ebbb27b6975b6b77ae64da9a8 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Sun, 25 Mar 2018 22:43:33 -0700 Subject: [PATCH 0139/1109] Fabric: Implementing cloneAndReplaceChild() for ViewShadowNode Summary: First, LayoutableShadowNode::cloneAndReplaceChild() is now pure virtual. The default implementation was useless and confusing. Second, cloneAndReplaceChild() is now fully implemented for ViewShadowNode, so fancy Yoga Concurrent layout *should* work now. Reviewed By: mdvacca Differential Revision: D7376352 fbshipit-source-id: 1199a37e64535c8592a2a5480e60139f61d02006 --- .../core/layout/LayoutableShadowNode.cpp | 4 --- .../fabric/core/layout/LayoutableShadowNode.h | 3 +-- ReactCommon/fabric/view/ViewShadowNode.cpp | 27 +++++++++++++++++++ ReactCommon/fabric/view/ViewShadowNode.h | 1 + 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp b/ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp index ea2de415cdfed2..8148f00dff002b 100644 --- a/ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp +++ b/ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp @@ -93,9 +93,5 @@ void LayoutableShadowNode::layoutChildren(LayoutContext layoutContext) { // Default implementation does nothing. } -SharedLayoutableShadowNode LayoutableShadowNode::cloneAndReplaceChild(const SharedLayoutableShadowNode &child) { - return child; -} - } // namespace react } // namespace facebook diff --git a/ReactCommon/fabric/core/layout/LayoutableShadowNode.h b/ReactCommon/fabric/core/layout/LayoutableShadowNode.h index e59df8bc9ab4b7..e3176f1f3572ae 100644 --- a/ReactCommon/fabric/core/layout/LayoutableShadowNode.h +++ b/ReactCommon/fabric/core/layout/LayoutableShadowNode.h @@ -93,9 +93,8 @@ class LayoutableShadowNode: /* * In case layout algorithm needs to mutate this (probably sealed) node, * it has to clone and replace it in the hierarchy before to do so. - * Default implementation does nothing and returns `child`. */ - virtual SharedLayoutableShadowNode cloneAndReplaceChild(const SharedLayoutableShadowNode &child); + virtual SharedLayoutableShadowNode cloneAndReplaceChild(const SharedLayoutableShadowNode &child) = 0; /* * Sets layout metrics for the shadow node. diff --git a/ReactCommon/fabric/view/ViewShadowNode.cpp b/ReactCommon/fabric/view/ViewShadowNode.cpp index 7b07fec22775ca..8bb5f33fdb83a4 100644 --- a/ReactCommon/fabric/view/ViewShadowNode.cpp +++ b/ReactCommon/fabric/view/ViewShadowNode.cpp @@ -7,6 +7,8 @@ #include "ViewShadowNode.h" +#include + #include namespace facebook { @@ -87,6 +89,31 @@ SharedLayoutableShadowNodeList ViewShadowNode::getChildren() const { return sharedLayoutableShadowNodeList; } +SharedLayoutableShadowNode ViewShadowNode::cloneAndReplaceChild(const SharedLayoutableShadowNode &child) { + ensureUnsealed(); + + // We cannot mutate `children_` in place here because it is a *shared* + // data structure which means other `ShadowNodes` might refer to its old value. + // So, we have to clone this and only then mutate. + auto nonConstChildrenCopy = SharedShadowNodeList(*children_); + + auto viewShadowNodeChild = std::dynamic_pointer_cast(child); + assert(viewShadowNodeChild); + + auto viewShadowNodeChildClone = std::make_shared(viewShadowNodeChild); + + std::replace( + nonConstChildrenCopy.begin(), + nonConstChildrenCopy.end(), + std::static_pointer_cast(viewShadowNodeChild), + std::static_pointer_cast(viewShadowNodeChildClone) + ); + + children_ = std::make_shared(nonConstChildrenCopy); + + return std::static_pointer_cast(viewShadowNodeChildClone); +} + #pragma mark - DebugStringConvertible SharedDebugStringConvertibleList ViewShadowNode::getDebugProps() const { diff --git a/ReactCommon/fabric/view/ViewShadowNode.h b/ReactCommon/fabric/view/ViewShadowNode.h index fffaaa20c98a3e..4ac446556d77df 100644 --- a/ReactCommon/fabric/view/ViewShadowNode.h +++ b/ReactCommon/fabric/view/ViewShadowNode.h @@ -57,6 +57,7 @@ class ViewShadowNode: #pragma mark - LayoutableShadowNode SharedLayoutableShadowNodeList getChildren() const override; + SharedLayoutableShadowNode cloneAndReplaceChild(const SharedLayoutableShadowNode &child) override; }; } // namespace react From 5642514aa52e3b1afc2a59e9bf4bba604a9aaa16 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Sun, 25 Mar 2018 22:43:36 -0700 Subject: [PATCH 0140/1109] Fabric: Detailed looging in FabricUIManager Summary: Apparently, we need this. Reviewed By: mdvacca Differential Revision: D7376350 fbshipit-source-id: 11d8ad54c7439e6c19a739ae1ac31af90d37166a --- .../fabric/uimanager/FabricUIManager.cpp | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/ReactCommon/fabric/uimanager/FabricUIManager.cpp b/ReactCommon/fabric/uimanager/FabricUIManager.cpp index 14adad47c8cea1..997a5a91b9b7bb 100644 --- a/ReactCommon/fabric/uimanager/FabricUIManager.cpp +++ b/ReactCommon/fabric/uimanager/FabricUIManager.cpp @@ -45,51 +45,69 @@ FabricUIManager::FabricUIManager(const std::shared_ptr " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}); return shadowNode; } SharedShadowNode FabricUIManager::cloneNode(const SharedShadowNode &shadowNode) { + LOG(INFO) << "FabricUIManager::cloneNode(shadowNode: " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ")"; ComponentDescriptor &componentDescriptor = *_registry[shadowNode]; - return componentDescriptor.cloneShadowNode(shadowNode); + SharedShadowNode clonnedShadowNode = componentDescriptor.cloneShadowNode(shadowNode); + LOG(INFO) << "FabricUIManager::cloneNode() -> " << clonnedShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}); + return clonnedShadowNode; } SharedShadowNode FabricUIManager::cloneNodeWithNewChildren(const SharedShadowNode &shadowNode) { + LOG(INFO) << "FabricUIManager::cloneNodeWithNewChildren(shadowNode: " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ")"; // Assuming semantic: Cloning with same props but empty children. ComponentDescriptor &componentDescriptor = *_registry[shadowNode]; - return componentDescriptor.cloneShadowNode(shadowNode, nullptr, {}); + SharedShadowNode clonnedShadowNode = componentDescriptor.cloneShadowNode(shadowNode, nullptr, {}); + LOG(INFO) << "FabricUIManager::cloneNodeWithNewChildren() -> " << clonnedShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}); + return clonnedShadowNode; } SharedShadowNode FabricUIManager::cloneNodeWithNewProps(const SharedShadowNode &shadowNode, folly::dynamic props) { + LOG(INFO) << "FabricUIManager::cloneNodeWithNewProps(shadowNode: " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ", props: " << props << ")"; // Assuming semantic: Cloning with same children and specified props. ComponentDescriptor &componentDescriptor = *_registry[shadowNode]; RawProps rawProps = rawPropsFromDynamic(props); - return componentDescriptor.cloneShadowNode(shadowNode, std::make_shared(rawProps), nullptr); + SharedShadowNode clonnedShadowNode = componentDescriptor.cloneShadowNode(shadowNode, std::make_shared(rawProps), nullptr); + LOG(INFO) << "FabricUIManager::cloneNodeWithNewProps() -> " << clonnedShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}); + return clonnedShadowNode; } SharedShadowNode FabricUIManager::cloneNodeWithNewChildrenAndProps(const SharedShadowNode &shadowNode, folly::dynamic props) { + LOG(INFO) << "FabricUIManager::cloneNodeWithNewChildrenAndProps(shadowNode: " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ", props: " << props << ")"; // Assuming semantic: Cloning with empty children and specified props. ComponentDescriptor &componentDescriptor = *_registry[shadowNode]; RawProps rawProps = rawPropsFromDynamic(props); - return componentDescriptor.cloneShadowNode(shadowNode, std::make_shared(rawProps), {}); + SharedShadowNode clonnedShadowNode = componentDescriptor.cloneShadowNode(shadowNode, std::make_shared(rawProps), {}); + LOG(INFO) << "FabricUIManager::cloneNodeWithNewChildrenAndProps() -> " << clonnedShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}); + return clonnedShadowNode; } void FabricUIManager::appendChild(const SharedShadowNode &parentShadowNode, const SharedShadowNode &childShadowNode) { + LOG(INFO) << "FabricUIManager::appendChild(parentShadowNode: " << parentShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ", childShadowNode: " << childShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ")"; ComponentDescriptor &componentDescriptor = *_registry[parentShadowNode]; componentDescriptor.appendChild(parentShadowNode, childShadowNode); } SharedShadowNodeUnsharedList FabricUIManager::createChildSet(int rootTag) { + LOG(INFO) << "FabricUIManager::createChildSet(rootTag: " << rootTag << ")"; return std::make_shared(SharedShadowNodeList({})); } void FabricUIManager::appendChildToSet(const SharedShadowNodeUnsharedList &shadowNodeList, const SharedShadowNode &shadowNode) { + LOG(INFO) << "FabricUIManager::appendChildToSet(shadowNodeList: " << shadowNodeList << ", shadowNode: " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ")"; shadowNodeList->push_back(shadowNode); } void FabricUIManager::completeRoot(int rootTag, const SharedShadowNodeUnsharedList &children) { + LOG(INFO) << "FabricUIManager::appendChildToSet(rootTag: " << rootTag << ", shadowNodeList: " << children << ")"; ComponentDescriptor &componentDescriptor = *_registry["View"]; SharedShadowNode previousRootShadowNode = componentDescriptor.createShadowNode(rootTag, rootTag, nullptr, {}); auto childrenCopy = std::make_shared(SharedShadowNodeList(*children)); From 53dfbcc81c6d8623c7e9d9febf67416c6cdd2cdf Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Sun, 25 Mar 2018 22:43:38 -0700 Subject: [PATCH 0141/1109] Fabric: Fixed bug in node management in FabricUIManager Summary: Suddenly, `{}` means `{nullptr}`, not `empty list`. Reviewed By: mdvacca Differential Revision: D7376347 fbshipit-source-id: 76f81eebe046ae592f0a42be7bcaa0587732c2a9 --- ReactCommon/fabric/uimanager/FabricUIManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ReactCommon/fabric/uimanager/FabricUIManager.cpp b/ReactCommon/fabric/uimanager/FabricUIManager.cpp index 997a5a91b9b7bb..0da19722a252c9 100644 --- a/ReactCommon/fabric/uimanager/FabricUIManager.cpp +++ b/ReactCommon/fabric/uimanager/FabricUIManager.cpp @@ -65,7 +65,7 @@ SharedShadowNode FabricUIManager::cloneNodeWithNewChildren(const SharedShadowNod LOG(INFO) << "FabricUIManager::cloneNodeWithNewChildren(shadowNode: " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ")"; // Assuming semantic: Cloning with same props but empty children. ComponentDescriptor &componentDescriptor = *_registry[shadowNode]; - SharedShadowNode clonnedShadowNode = componentDescriptor.cloneShadowNode(shadowNode, nullptr, {}); + SharedShadowNode clonnedShadowNode = componentDescriptor.cloneShadowNode(shadowNode, nullptr, ShadowNode::emptySharedShadowNodeSharedList()); LOG(INFO) << "FabricUIManager::cloneNodeWithNewChildren() -> " << clonnedShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}); return clonnedShadowNode; } @@ -85,7 +85,7 @@ SharedShadowNode FabricUIManager::cloneNodeWithNewChildrenAndProps(const SharedS // Assuming semantic: Cloning with empty children and specified props. ComponentDescriptor &componentDescriptor = *_registry[shadowNode]; RawProps rawProps = rawPropsFromDynamic(props); - SharedShadowNode clonnedShadowNode = componentDescriptor.cloneShadowNode(shadowNode, std::make_shared(rawProps), {}); + SharedShadowNode clonnedShadowNode = componentDescriptor.cloneShadowNode(shadowNode, std::make_shared(rawProps), ShadowNode::emptySharedShadowNodeSharedList()); LOG(INFO) << "FabricUIManager::cloneNodeWithNewChildrenAndProps() -> " << clonnedShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}); return clonnedShadowNode; } From 6f17e3b328f61a8c75ceb07fc95231636db4ecc7 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Sun, 25 Mar 2018 22:43:40 -0700 Subject: [PATCH 0142/1109] Fabric: Introducing `TreeMutationInstruction` Summary: The Great Diffing algorithm is coming. Reviewed By: fkgozali Differential Revision: D7376528 fbshipit-source-id: bdfef69551980136cfd1717a11ae376d5eef126b --- .../uimanager/TreeMutationInstruction.cpp | 150 ++++++++++++++++++ .../uimanager/TreeMutationInstruction.h | 109 +++++++++++++ 2 files changed, 259 insertions(+) create mode 100644 ReactCommon/fabric/uimanager/TreeMutationInstruction.cpp create mode 100644 ReactCommon/fabric/uimanager/TreeMutationInstruction.h diff --git a/ReactCommon/fabric/uimanager/TreeMutationInstruction.cpp b/ReactCommon/fabric/uimanager/TreeMutationInstruction.cpp new file mode 100644 index 00000000000000..da60fb83cf0153 --- /dev/null +++ b/ReactCommon/fabric/uimanager/TreeMutationInstruction.cpp @@ -0,0 +1,150 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "TreeMutationInstruction.h" + +#include + +namespace facebook { +namespace react { + +const TreeMutationInstruction TreeMutationInstruction::Insert( + SharedShadowNode parentNode, + SharedShadowNode childNode, + int index +) { + assert(parentNode); + assert(childNode); + assert(index != -1); + + return TreeMutationInstruction( + Inserting, + parentNode, + nullptr, + childNode, + index + ); +} + +const TreeMutationInstruction TreeMutationInstruction::Delete( + SharedShadowNode parentNode, + SharedShadowNode childNode, + int index +) { + assert(parentNode); + assert(childNode); + assert(index != -1); + + return TreeMutationInstruction( + Deleting, + parentNode, + childNode, + nullptr, + index + ); +} + +const TreeMutationInstruction TreeMutationInstruction::Update( + SharedShadowNode parentNode, + SharedShadowNode oldChildNode, + SharedShadowNode newChildNode, + int index +) { + assert(parentNode); + assert(oldChildNode); + assert(newChildNode); + assert(index != -1); + + return TreeMutationInstruction( + Updating, + parentNode, + oldChildNode, + newChildNode, + index + ); +} + +TreeMutationInstruction::TreeMutationInstruction( + Type type, + SharedShadowNode parentNode, + SharedShadowNode oldChildNode, + SharedShadowNode newChildNode, + int index +): + type_(type), + parentNode_(parentNode), + oldChildNode_(oldChildNode), + newChildNode_(newChildNode), + index_(index) {}; + +#pragma mark - Getters + +TreeMutationInstruction::Type TreeMutationInstruction::getType() const { + return type_; +} + +SharedShadowNode TreeMutationInstruction::getParentNode() const { + assert(parentNode_); + return parentNode_; +} + +SharedShadowNode TreeMutationInstruction::getOldChildNode() const { + assert(oldChildNode_); + return oldChildNode_; +} + +SharedShadowNode TreeMutationInstruction::getNewChildNode() const { + assert(newChildNode_); + return newChildNode_; +} + +int TreeMutationInstruction::getIndex() const { + assert(index_ != -1); + return index_; +} + +#pragma mark - DebugStringConvertible + +std::string TreeMutationInstruction::getDebugName() const { + switch (type_) { + case Inserting: + return "Insert"; + case Deleting: + return "Delete"; + case Updating: + return "Update"; + } +}; + +SharedDebugStringConvertibleList TreeMutationInstruction::getDebugProps() const { + DebugStringConvertibleOptions options = {.maximumDepth = 1, .format = false}; + + switch (type_) { + case Inserting: + return SharedDebugStringConvertibleList { + std::make_shared("parentNode", parentNode_->getDebugDescription(options)), + std::make_shared("childNode", newChildNode_->getDebugDescription(options)), + std::make_shared("index", std::to_string(index_)) + }; + case Deleting: + return SharedDebugStringConvertibleList { + std::make_shared("parentNode", parentNode_->getDebugDescription(options)), + std::make_shared("childNode", oldChildNode_->getDebugDescription(options)), + std::make_shared("index", std::to_string(index_)) + }; + case Updating: + return SharedDebugStringConvertibleList { + std::make_shared("parentNode", parentNode_->getDebugDescription(options)), + std::make_shared("oldChildNode", oldChildNode_->getDebugDescription(options)), + std::make_shared("newChildNode", newChildNode_->getDebugDescription(options)), + std::make_shared("index", std::to_string(index_)) + }; + } +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/uimanager/TreeMutationInstruction.h b/ReactCommon/fabric/uimanager/TreeMutationInstruction.h new file mode 100644 index 00000000000000..f0e09c17d35b8b --- /dev/null +++ b/ReactCommon/fabric/uimanager/TreeMutationInstruction.h @@ -0,0 +1,109 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 + +namespace facebook { +namespace react { + +class TreeMutationInstruction; + +using TreeMutationInstructionList = std::vector; + +/* + * Describes single native views tree mutation instruction which may contain + * pointers to an old shadow node, a new shadow node, a parent shadow node and + * final index of inserted or updated node. + * The relationship between native view instances and shadow node instances is + * defined by `tag` value. + */ +class TreeMutationInstruction: + public DebugStringConvertible { +public: + +#pragma mark - Designated Initializers + + /* + * Creates and returns an *Insert* instruction with following semantic: + * 1. Create a native view for the shadow node if needed; + * 2. Unmount the native view from a previous superview if needed; + * 3. Mount the native view to the new superview. + */ + static const TreeMutationInstruction Insert( + SharedShadowNode parentNode, + SharedShadowNode childNode, + int index + ); + + /* + * Creates and returns a *Delete* instruction with following semantic: + * 1. Unmount the native view from a previous superview if needed; + * 2. Destroy (or return to a recycle pool) the native view. + */ + static const TreeMutationInstruction Delete( + SharedShadowNode parentNode, + SharedShadowNode childNode, + int index + ); + + /* + * Creates and returns an *Update* instruction with following semantic: + * 1. Update the presentation of a native view based on the new shadow node; + * 2. The exact set of changes are not specified but might contain + * new props and/or new layout (or might be empty). + */ + static const TreeMutationInstruction Update( + SharedShadowNode parentNode, + SharedShadowNode oldChildNode, + SharedShadowNode newChildNode, + int index + ); + +#pragma mark - Type + + enum Type { + Inserting, + Deleting, + Updating + }; + +#pragma mark - Getters + + Type getType() const; + SharedShadowNode getParentNode() const; + SharedShadowNode getOldChildNode() const; + SharedShadowNode getNewChildNode() const; + int getIndex() const; + +#pragma mark - DebugStringConvertible + + std::string getDebugName() const override; + SharedDebugStringConvertibleList getDebugProps() const override; + +private: + TreeMutationInstruction( + Type type, + SharedShadowNode parentNode, + SharedShadowNode oldChildNode, + SharedShadowNode newChildNode, + int index + ); + + Type type_ {Inserting}; + SharedShadowNode parentNode_ {nullptr}; + SharedShadowNode oldChildNode_ {nullptr}; + SharedShadowNode newChildNode_ {nullptr}; + int index_ {-1}; +}; + +} // namespace react +} // namespace facebook From cb7a7f3b93cbee1621a190f4c5dedfb31ac35744 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Sun, 25 Mar 2018 22:43:42 -0700 Subject: [PATCH 0143/1109] Fabric: Deleted virtual default destructor from Props Summary: Trivial. We don't need this because we already have another virtual method. Reviewed By: fkgozali Differential Revision: D7388964 fbshipit-source-id: 5ea6eb33ece72796d8cde2cc4b12c1240447d22a --- ReactCommon/fabric/core/shadownode/Props.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/ReactCommon/fabric/core/shadownode/Props.h b/ReactCommon/fabric/core/shadownode/Props.h index 5760f34916787f..d7ecea7426c61f 100644 --- a/ReactCommon/fabric/core/shadownode/Props.h +++ b/ReactCommon/fabric/core/shadownode/Props.h @@ -28,8 +28,6 @@ class Props: public virtual DebugStringConvertible { public: - virtual ~Props() = default; - virtual void apply(const RawProps &rawProps); const std::string &getNativeId() const; From 99e9c6e798e21b83d4bf664ca12286c57d6b104d Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Sun, 25 Mar 2018 22:43:43 -0700 Subject: [PATCH 0144/1109] Fabric: Collecting and printing ShadowNode's revision/generation Summary: It drastically simplifies reading logs. Reviewed By: fkgozali Differential Revision: D7388963 fbshipit-source-id: 7849c803f295719918c20ddf8c082e5a5780116f --- ReactCommon/fabric/core/shadownode/ShadowNode.cpp | 8 +++++--- ReactCommon/fabric/core/shadownode/ShadowNode.h | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp index e1394cccca717d..2313be859eef83 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp @@ -31,7 +31,8 @@ ShadowNode::ShadowNode( rootTag_(rootTag), instanceHandle_(instanceHandle), props_(props), - children_(children) {} + children_(children), + revision_(1) {} ShadowNode::ShadowNode( SharedShadowNode shadowNode, @@ -43,7 +44,8 @@ ShadowNode::ShadowNode( instanceHandle_(shadowNode->instanceHandle_), props_(props ? props : shadowNode->props_), children_(children ? children : shadowNode->children_), - sourceNode_(shadowNode) {} + sourceNode_(shadowNode), + revision_(shadowNode->revision_ + 1) {} #pragma mark - Getters @@ -121,7 +123,7 @@ std::string ShadowNode::getDebugName() const { } std::string ShadowNode::getDebugValue() const { - return getSealed() ? "sealed" : ""; + return "r" + std::to_string(revision_) + (getSealed() ? "/sealed" : ""); } SharedDebugStringConvertibleList ShadowNode::getDebugChildren() const { diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.h b/ReactCommon/fabric/core/shadownode/ShadowNode.h index aa68556f9ce3a9..4045be8462e6df 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.h +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.h @@ -81,6 +81,7 @@ class ShadowNode: SharedProps props_; SharedShadowNodeSharedList children_; WeakShadowNode sourceNode_; + int revision_; }; } // namespace react From 2ff8b7024ec7b8db71dcc600adc87b7ce5a9d81c Mon Sep 17 00:00:00 2001 From: Taras Tsugrii Date: Mon, 26 Mar 2018 12:12:53 -0700 Subject: [PATCH 0145/1109] Replace android_library with fb_android_library. Reviewed By: adamjernst Differential Revision: D7393004 fbshipit-source-id: 99060333267dd6e81a41e9da52002e05152e7ccb --- ReactNative/DEFS.bzl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ReactNative/DEFS.bzl b/ReactNative/DEFS.bzl index 135bacfbc93d2c..13402b1bc87897 100644 --- a/ReactNative/DEFS.bzl +++ b/ReactNative/DEFS.bzl @@ -183,3 +183,7 @@ def cxx_library(allow_jni_merging=None, **kwargs): if not (k.startswith("fbandroid_") or k.startswith("fbobjc_")) } native.cxx_library(**args) + + +def fb_android_library(**kwargs): + native.android_library(**kwargs) From de1040fcff558a58e2a616efebaf55d9bf5332b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Tue, 27 Mar 2018 09:15:54 -0700 Subject: [PATCH 0146/1109] Cache apt dependencies in test_android Summary: Closes https://github.com/facebook/react-native/pull/18576 Differential Revision: D7415216 Pulled By: hramos fbshipit-source-id: 9b7199fe5fb91a26ba0881e426a85395b2923f26 --- .circleci/config.yml | 46 ++++++++++++++++++++---- scripts/circleci/apt-get-android-deps.sh | 25 +++++++++++++ 2 files changed, 65 insertions(+), 6 deletions(-) create mode 100755 scripts/circleci/apt-get-android-deps.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index 675aeb4e0b07f5..196d3d3e6edf3d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -38,6 +38,31 @@ aliases: - /opt/android/sdk key: v1-android-sdkmanager-packages-{{ arch }}-{{ .Branch }}-api-26-alpha-{{ checksum "scripts/circle-ci-android-setup.sh" }} + - &restore-cache-gradle + keys: + - v1-gradle-{{ arch }}-{{ .Branch }}-{{ checksum "build.gradle" }}-{{ checksum "ReactAndroid/build.gradle" }} + # Fallback in case checksum fails + - v1-gradle-{{ arch }}-{{ .Branch }}-{{ checksum "build.gradle" }}- + - v1-gradle-{{ arch }}-{{ .Branch }}- + # Fallback in case this is a first-time run on a fork + - v1-gradle-{{ arch }}-master- + - &save-cache-gradle + paths: + - ~/.gradle + key: v1-gradle-{{ arch }}-{{ .Branch }}-{{ checksum "build.gradle" }}-{{ checksum "ReactAndroid/build.gradle" }} + + - &restore-cache-apt + keys: + - v1-apt-{{ arch }}-{{ .Branch }}-{{ checksum "scripts/circleci/apt-get-android-deps.sh" }} + # Fallback in case checksum fails + - v1-apt-{{ arch }}-{{ .Branch }}- + # Fallback in case this is a first-time run on a fork + - v1-apt-{{ arch }}-master- + - &save-cache-apt + paths: + - ~/vendor/apt + key: v1-apt-{{ arch }}-{{ .Branch }}-{{ checksum "scripts/circleci/apt-get-android-deps.sh" }} + - &restore-cache-ndk keys: - v2-android-ndk-{{ arch }}-r10e-32-64-{{ checksum "scripts/circle-ci-android-setup.sh" }} @@ -97,7 +122,8 @@ aliases: yarn install --non-interactive --cache-folder ~/.cache/yarn - &install-yarn - | + name: Install Yarn + command: | curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list sudo apt-get update && sudo apt-get install yarn @@ -107,7 +133,8 @@ aliases: npm install --no-package-lock --no-spin --no-progress - &install-buck - | + name: Install BUCK + command: | if [[ ! -e ~/buck ]]; then git clone https://github.com/facebook/buck.git ~/buck --branch v2018.02.16.01 --depth=1 fi @@ -115,7 +142,8 @@ aliases: buck --version - &install-node - | + name: Install Node + command: | curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash - sudo apt-get install -y nodejs @@ -141,9 +169,7 @@ aliases: - &install-android-build-dependencies name: Install Android Build Dependencies - command: | - sudo apt-get update -y - sudo apt-get install ant autoconf automake g++ gcc libqt5widgets5 lib32z1 lib32stdc++6 make maven python-dev python3-dev qml-module-qtquick-controls qtdeclarative5-dev file -y + command: ./scripts/circleci/apt-get-android-deps.sh - &validate-android-sdk name: Validate Android SDK Install @@ -400,6 +426,7 @@ jobs: # Configure Android SDK and related dependencies - run: *configure-android-path - run: *install-android-build-dependencies + - restore-cache: *restore-cache-android-packages - run: *install-android-packages - save-cache: *save-cache-android-packages @@ -450,7 +477,10 @@ jobs: # Configure Android SDK and related dependencies - run: *configure-android-path + - restore-cache: *restore-cache-apt - run: *install-android-build-dependencies + - save-cache: *save-cache-apt + - restore-cache: *restore-cache-android-packages - run: *install-android-packages - save-cache: *save-cache-android-packages @@ -481,7 +511,11 @@ jobs: - run: buck fetch ReactAndroid/src/main/java/com/facebook/react/shell - run: buck fetch ReactAndroid/src/test/... - run: buck fetch ReactAndroid/src/androidTest/... + + # Gradle + - restore-cache: *restore-cache-gradle - run: ./gradlew :ReactAndroid:downloadBoost :ReactAndroid:downloadDoubleConversion :ReactAndroid:downloadFolly :ReactAndroid:downloadGlog :ReactAndroid:downloadJSCHeaders + - save-cache: *save-cache-gradle # Build and compile - run: *build-android-app diff --git a/scripts/circleci/apt-get-android-deps.sh b/scripts/circleci/apt-get-android-deps.sh new file mode 100755 index 00000000000000..6463de83d0465e --- /dev/null +++ b/scripts/circleci/apt-get-android-deps.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +set -e + +echo "Downloading package lists..." +sudo apt-get update -y + +if ! [[ -d ~/vendor/apt ]]; then + mkdir -p ~/vendor/apt +fi + +# First check for archives cache +if ! [[ -d ~/vendor/apt/archives ]]; then + # It doesn't so download the packages + echo "Downloading build dependencies..." + sudo apt-get install --download-only ant autoconf automake g++ gcc libqt5widgets5 lib32z1 lib32stdc++6 make maven python-dev python3-dev qml-module-qtquick-controls qtdeclarative5-dev file -y + # Then move them to our cache directory + sudo cp -R /var/cache/apt ~/vendor/ + # Making sure our user has ownership, in order to cache + sudo chown -R ${USER:=$(/usr/bin/id -run)}:$USER ~/vendor/apt +fi + +# Install all packages in the cache +echo "Installing build dependencies..." +sudo dpkg -i ~/vendor/apt/archives/*.deb \ No newline at end of file From f5207ba9c764f33ef83fa897f6014d67193be0e2 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Tue, 27 Mar 2018 10:34:09 -0700 Subject: [PATCH 0147/1109] Fix blob response parsing for empty body on iOS Summary: We currently handle empty body poorly in the iOS blob implementation, this happens because of an early return that cause the blob response to not be processed by the blob module, resulting in an empty string as the body instead of a blob object. We also need to make sure to create an empty blob object when data is nil (empty body) as per the XMLHttpRequest spec. The Android implementation was already handling this properly. Fixes #18223 Send a HEAD request ```js fetch('https://apipre.monkimun.com/whoami', { body: null, method: 'HEAD', headers: { Accept: 'application/json', 'Content-Type': 'application/json', }, }) ``` [IOS][BUGFIX][Blob] - Fix blob response parsing for empty body Closes https://github.com/facebook/react-native/pull/18547 Differential Revision: D7415950 Pulled By: hramos fbshipit-source-id: 56860532c6171255869f02a0960f55d155184a46 --- Libraries/Blob/RCTBlobManager.mm | 3 +++ Libraries/Network/RCTNetworking.mm | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Libraries/Blob/RCTBlobManager.mm b/Libraries/Blob/RCTBlobManager.mm index 56235ee04b6dfe..7c0cbb8673f064 100755 --- a/Libraries/Blob/RCTBlobManager.mm +++ b/Libraries/Blob/RCTBlobManager.mm @@ -258,6 +258,9 @@ - (BOOL)canHandleNetworkingResponse:(NSString *)responseType - (id)handleNetworkingResponse:(NSURLResponse *)response data:(NSData *)data { + // An empty body will have nil for data, in this case we need to return + // an empty blob as per the XMLHttpRequest spec. + data = data ?: [NSData new]; return @{ @"blobId": [self store:data], @"offset": @0, diff --git a/Libraries/Network/RCTNetworking.mm b/Libraries/Network/RCTNetworking.mm index fe86d31e67e0ff..f8de23abf0127f 100644 --- a/Libraries/Network/RCTNetworking.mm +++ b/Libraries/Network/RCTNetworking.mm @@ -439,10 +439,6 @@ - (void)sendData:(NSData *)data { RCTAssertThread(_methodQueue, @"sendData: must be called on method queue"); - if (data.length == 0) { - return; - } - id responseData = nil; for (id handler in _responseHandlers) { if ([handler canHandleNetworkingResponse:responseType]) { @@ -452,6 +448,10 @@ - (void)sendData:(NSData *)data } if (!responseData) { + if (data.length == 0) { + return; + } + if ([responseType isEqualToString:@"text"]) { // No carry storage is required here because the entire data has been loaded. responseData = [RCTNetworking decodeTextData:data fromResponse:task.response withCarryData:nil]; From 0150a0c85b06c4159729bac5aedd1696b4776e99 Mon Sep 17 00:00:00 2001 From: Riley Dulin Date: Tue, 27 Mar 2018 10:43:27 -0700 Subject: [PATCH 0148/1109] Add nativeLoggingHook to JSIExecutor Reviewed By: danzimm Differential Revision: D7203114 fbshipit-source-id: 2f4640d19267dc4d75f6d6c8a7876c92abc22276 --- ReactAndroid/src/main/jni/react/jni/BUCK | 1 + .../src/main/jni/react/jni/JSLogging.cpp | 24 +++++++++++++++---- .../src/main/jni/react/jni/JSLogging.h | 16 +++++++++++-- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/ReactAndroid/src/main/jni/react/jni/BUCK b/ReactAndroid/src/main/jni/react/jni/BUCK index 7673ad3bdfd348..dc0f2a76d55cf0 100644 --- a/ReactAndroid/src/main/jni/react/jni/BUCK +++ b/ReactAndroid/src/main/jni/react/jni/BUCK @@ -8,6 +8,7 @@ EXPORTED_HEADERS = [ "JavaModuleWrapper.h", "JavaScriptExecutorHolder.h", "JSLoader.h", + "JSLogging.h", "MethodInvoker.h", "ModuleRegistryBuilder.h", "NativeArray.h", diff --git a/ReactAndroid/src/main/jni/react/jni/JSLogging.cpp b/ReactAndroid/src/main/jni/react/jni/JSLogging.cpp index 5fdc9a8b273dea..e178542157e07f 100644 --- a/ReactAndroid/src/main/jni/react/jni/JSLogging.cpp +++ b/ReactAndroid/src/main/jni/react/jni/JSLogging.cpp @@ -2,9 +2,8 @@ #include "JSLogging.h" -#include -#include #include +#include #include @@ -16,7 +15,8 @@ JSValueRef nativeLoggingHook( JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, - const JSValueRef arguments[], JSValueRef *exception) { + const JSValueRef arguments[], + JSValueRef* exception) { android_LogPriority logLevel = ANDROID_LOG_DEBUG; if (argumentCount > 1) { int level = (int)Value(ctx, arguments[1]).asNumber(); @@ -28,9 +28,23 @@ JSValueRef nativeLoggingHook( } if (argumentCount > 0) { String message = Value(ctx, arguments[0]).toString(); - FBLOG_PRI(logLevel, "ReactNativeJS", "%s", message.str().c_str()); + reactAndroidLoggingHook(message.str(), logLevel); } return Value::makeUndefined(ctx); } -}}; +void reactAndroidLoggingHook( + const std::string& message, + android_LogPriority logLevel) { + FBLOG_PRI(logLevel, "ReactNativeJS", "%s", message.c_str()); +} + +void reactAndroidLoggingHook( + const std::string& message, + unsigned int logLevel) { + reactAndroidLoggingHook( + message, static_cast(logLevel + ANDROID_LOG_DEBUG)); +} + +} // namespace react +} // namespace facebook diff --git a/ReactAndroid/src/main/jni/react/jni/JSLogging.h b/ReactAndroid/src/main/jni/react/jni/JSLogging.h index 2a38aaf3137cb9..5e4e99143a2991 100644 --- a/ReactAndroid/src/main/jni/react/jni/JSLogging.h +++ b/ReactAndroid/src/main/jni/react/jni/JSLogging.h @@ -2,6 +2,9 @@ #pragma once +#include +#include + #include namespace facebook { @@ -12,6 +15,15 @@ JSValueRef nativeLoggingHook( JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, - const JSValueRef arguments[], JSValueRef *exception); + const JSValueRef arguments[], + JSValueRef* exception); + +void reactAndroidLoggingHook( + const std::string& message, + android_LogPriority logLevel); +void reactAndroidLoggingHook( + const std::string& message, + unsigned int logLevel); -}} +} // namespace react +} // namespace facebook From 45abbf36d67fb50ddf5f74f8d7912a35bf7c1dad Mon Sep 17 00:00:00 2001 From: David Vacca Date: Tue, 27 Mar 2018 10:44:15 -0700 Subject: [PATCH 0149/1109] Support multiple Fabric ReactRootView running at the same time Reviewed By: achen1 Differential Revision: D7409472 fbshipit-source-id: 9525e610f3bce49cae8d3c5e4427f99a48c32091 --- .../react/fabric/FabricUIManager.java | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) 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 81a60435097896..47359b44fa761b 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -50,7 +50,6 @@ public class FabricUIManager implements UIManager { private final ViewManagerRegistry mViewManagerRegistry; private final UIViewOperationQueue mUIViewOperationQueue; private volatile int mCurrentBatch = 0; - private ReactShadowNode mCurrentRootShadowNode; private FabricReconciler mFabricReconciler; public FabricUIManager( @@ -246,32 +245,32 @@ public synchronized void completeRoot(int rootTag, List childLi Log.d(TAG, "completeRoot rootTag: " + rootTag + ", childList: " + childList); } try { - ReactShadowNode rootNode = getRootNode(rootTag); + ReactShadowNode currentRootShadowNode = getRootNode(rootTag); Assertions.assertNotNull( - rootNode, + currentRootShadowNode, "Root view with tag " + rootTag + " must be added before completeRoot is called"); - rootNode = calculateDiffingAndCreateNewRootNode(rootNode, childList); + currentRootShadowNode = calculateDiffingAndCreateNewRootNode(currentRootShadowNode, childList); if (DEBUG) { - Log.d(TAG, "ReactShadowNodeHierarchy after diffing: " + rootNode.getHierarchyInfo()); + Log.d(TAG, "ReactShadowNodeHierarchy after diffing: " + currentRootShadowNode.getHierarchyInfo()); } - notifyOnBeforeLayoutRecursive(rootNode); - rootNode.calculateLayout(); + notifyOnBeforeLayoutRecursive(currentRootShadowNode); + currentRootShadowNode.calculateLayout(); if (DEBUG) { Log.d( TAG, - "ReactShadowNodeHierarchy after calculate Layout: " + rootNode.getHierarchyInfo()); + "ReactShadowNodeHierarchy after calculate Layout: " + currentRootShadowNode.getHierarchyInfo()); } - applyUpdatesRecursive(rootNode, 0, 0); + applyUpdatesRecursive(currentRootShadowNode, 0, 0); mUIViewOperationQueue.dispatchViewUpdates( mCurrentBatch++, System.currentTimeMillis(), System.currentTimeMillis()); - mCurrentRootShadowNode = rootNode; + mRootShadowNodeRegistry.addNode(currentRootShadowNode); } catch (Exception e) { handleException(getRootNode(rootTag), e); } @@ -294,7 +293,7 @@ private ReactShadowNode calculateDiffingAndCreateNewRootNode( appendChild(newRootShadowNode, child); } - mFabricReconciler.manageChildren(mCurrentRootShadowNode, newRootShadowNode); + mFabricReconciler.manageChildren(currentRootShadowNode, newRootShadowNode); return newRootShadowNode; } @@ -321,7 +320,7 @@ private void applyUpdatesRecursive(ReactShadowNode node, float absoluteX, float } @Override - public int addRootView( + public synchronized int addRootView( final T rootView) { int rootTag = ReactRootViewTagGenerator.getNextRootViewTag(); ThemedReactContext themedRootContext = From 56971bbb152babb0ee745d7abd55f5a5d35ae004 Mon Sep 17 00:00:00 2001 From: Himabindu Gadupudi Date: Tue, 27 Mar 2018 11:49:02 -0700 Subject: [PATCH 0150/1109] RN: Fix rounded Image Background (Android) Reviewed By: achen1 Differential Revision: D7384113 fbshipit-source-id: 348bdbc54a3e5923e012cb4cbc32da83145f04b4 --- .../react/views/image/ReactImageView.java | 134 ++++++++++-------- 1 file changed, 77 insertions(+), 57 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java index 9396cac1c5c1f2..9ab9c8884e800c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java @@ -29,6 +29,8 @@ import com.facebook.drawee.controller.ControllerListener; import com.facebook.drawee.controller.ForwardingControllerListener; import com.facebook.drawee.drawable.AutoRotateDrawable; +import com.facebook.drawee.drawable.RoundedColorDrawable; + import com.facebook.drawee.drawable.ScalingUtils; import com.facebook.drawee.generic.GenericDraweeHierarchy; import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; @@ -91,25 +93,25 @@ private class RoundedCornerPostprocessor extends BasePostprocessor { void getRadii(Bitmap source, float[] computedCornerRadii, float[] mappedRadii) { mScaleType.getTransform( - sMatrix, - new Rect(0, 0, source.getWidth(), source.getHeight()), - source.getWidth(), - source.getHeight(), - 0.0f, - 0.0f); - sMatrix.invert(sInverse); + sMatrix, + new Rect(0, 0, source.getWidth(), source.getHeight()), + source.getWidth(), + source.getHeight(), + 0.0f, + 0.0f); + sMatrix.invert(sInverse); - mappedRadii[0] = sInverse.mapRadius(computedCornerRadii[0]); - mappedRadii[1] = mappedRadii[0]; + mappedRadii[0] = sInverse.mapRadius(computedCornerRadii[0]); + mappedRadii[1] = mappedRadii[0]; - mappedRadii[2] = sInverse.mapRadius(computedCornerRadii[1]); - mappedRadii[3] = mappedRadii[2]; + mappedRadii[2] = sInverse.mapRadius(computedCornerRadii[1]); + mappedRadii[3] = mappedRadii[2]; - mappedRadii[4] = sInverse.mapRadius(computedCornerRadii[2]); - mappedRadii[5] = mappedRadii[4]; + mappedRadii[4] = sInverse.mapRadius(computedCornerRadii[2]); + mappedRadii[5] = mappedRadii[4]; - mappedRadii[6] = sInverse.mapRadius(computedCornerRadii[3]); - mappedRadii[7] = mappedRadii[6]; + mappedRadii[6] = sInverse.mapRadius(computedCornerRadii[3]); + mappedRadii[7] = mappedRadii[6]; } @Override @@ -118,9 +120,9 @@ public void process(Bitmap output, Bitmap source) { output.setHasAlpha(true); if (FloatUtil.floatsEqual(sComputedCornerRadii[0], 0f) && - FloatUtil.floatsEqual(sComputedCornerRadii[1], 0f) && - FloatUtil.floatsEqual(sComputedCornerRadii[2], 0f) && - FloatUtil.floatsEqual(sComputedCornerRadii[3], 0f)) { + FloatUtil.floatsEqual(sComputedCornerRadii[1], 0f) && + FloatUtil.floatsEqual(sComputedCornerRadii[2], 0f) && + FloatUtil.floatsEqual(sComputedCornerRadii[3], 0f)) { super.process(output, source); return; } @@ -136,9 +138,9 @@ public void process(Bitmap output, Bitmap source) { Path pathForBorderRadius = new Path(); pathForBorderRadius.addRoundRect( - new RectF(0, 0, source.getWidth(), source.getHeight()), - radii, - Path.Direction.CW); + new RectF(0, 0, source.getWidth(), source.getHeight()), + radii, + Path.Direction.CW); canvas.drawPath(pathForBorderRadius, paint); } @@ -183,6 +185,8 @@ public CloseableReference process(Bitmap source, PlatformBitmapFactory b private @Nullable ImageSource mImageSource; private @Nullable ImageSource mCachedImageSource; private @Nullable Drawable mLoadingImageDrawable; + private @Nullable RoundedColorDrawable mBackgroundImageDrawable; + private int mBackgroundColor = 0x00000000; private int mBorderColor; private int mOverlayColor; private float mBorderWidth; @@ -206,15 +210,15 @@ public CloseableReference process(Bitmap source, PlatformBitmapFactory b // We can't specify rounding in XML, so have to do so here private static GenericDraweeHierarchy buildHierarchy(Context context) { return new GenericDraweeHierarchyBuilder(context.getResources()) - .setRoundingParams(RoundingParams.fromCornersRadius(0)) - .build(); + .setRoundingParams(RoundingParams.fromCornersRadius(0)) + .build(); } public ReactImageView( - Context context, - AbstractDraweeControllerBuilder draweeControllerBuilder, - @Nullable GlobalImageLoadListener globalImageLoadListener, - @Nullable Object callerContext) { + Context context, + AbstractDraweeControllerBuilder draweeControllerBuilder, + @Nullable GlobalImageLoadListener globalImageLoadListener, + @Nullable Object callerContext) { super(context, buildHierarchy(context)); mScaleType = ImageResizeMode.defaultValue(); mDraweeControllerBuilder = draweeControllerBuilder; @@ -230,20 +234,20 @@ public void setShouldNotifyLoadEvents(boolean shouldNotify) { mControllerListener = null; } else { final EventDispatcher mEventDispatcher = ((ReactContext) getContext()). - getNativeModule(UIManagerModule.class).getEventDispatcher(); + getNativeModule(UIManagerModule.class).getEventDispatcher(); mControllerListener = new BaseControllerListener() { @Override public void onSubmit(String id, Object callerContext) { mEventDispatcher.dispatchEvent( - new ImageLoadEvent(getId(), ImageLoadEvent.ON_LOAD_START)); + new ImageLoadEvent(getId(), ImageLoadEvent.ON_LOAD_START)); } @Override public void onFinalImageSet( - String id, - @Nullable final ImageInfo imageInfo, - @Nullable Animatable animatable) { + String id, + @Nullable final ImageInfo imageInfo, + @Nullable Animatable animatable) { if (imageInfo != null) { mEventDispatcher.dispatchEvent( new ImageLoadEvent(getId(), ImageLoadEvent.ON_LOAD, @@ -276,6 +280,15 @@ public void setBlurRadius(float blurRadius) { mIsDirty = true; } + @Override + public void setBackgroundColor(int backgroundColor) { + if(mBackgroundColor != backgroundColor) { + mBackgroundColor = backgroundColor; + mBackgroundImageDrawable = new RoundedColorDrawable(backgroundColor); + mIsDirty = true; + } + } + public void setBorderColor(int borderColor) { mBorderColor = borderColor; mIsDirty = true; @@ -342,10 +355,10 @@ public void setSource(@Nullable ReadableArray sources) { ReadableMap source = sources.getMap(idx); String uri = source.getString("uri"); ImageSource imageSource = new ImageSource( - getContext(), - uri, - source.getDouble("width"), - source.getDouble("height")); + getContext(), + uri, + source.getDouble("width"), + source.getDouble("height")); mSources.add(imageSource); if (Uri.EMPTY.equals(imageSource.getUri())) { warnImageSource(uri); @@ -359,7 +372,7 @@ public void setSource(@Nullable ReadableArray sources) { public void setLoadingIndicatorSource(@Nullable String name) { Drawable drawable = ResourceDrawableIdHelper.getInstance().getResourceDrawable(getContext(), name); mLoadingImageDrawable = - drawable != null ? (Drawable) new AutoRotateDrawable(drawable, 1000) : null; + drawable != null ? (Drawable) new AutoRotateDrawable(drawable, 1000) : null; mIsDirty = true; } @@ -420,31 +433,37 @@ public void maybeUpdateView() { } boolean usePostprocessorScaling = - mScaleType != ScalingUtils.ScaleType.CENTER_CROP && + mScaleType != ScalingUtils.ScaleType.CENTER_CROP && mScaleType != ScalingUtils.ScaleType.FOCUS_CROP; RoundingParams roundingParams = hierarchy.getRoundingParams(); + cornerRadii(sComputedCornerRadii); + + roundingParams.setCornersRadii(sComputedCornerRadii[0], sComputedCornerRadii[1], sComputedCornerRadii[2], sComputedCornerRadii[3]); + + if (mBackgroundImageDrawable != null) { + mBackgroundImageDrawable.setBorder(mBorderColor, mBorderWidth); + mBackgroundImageDrawable.setRadii(roundingParams.getCornersRadii()); + hierarchy.setBackgroundImage(mBackgroundImageDrawable); + } + if (usePostprocessorScaling) { roundingParams.setCornersRadius(0); - } else { - cornerRadii(sComputedCornerRadii); - - roundingParams.setCornersRadii(sComputedCornerRadii[0], sComputedCornerRadii[1], sComputedCornerRadii[2], sComputedCornerRadii[3]); } roundingParams.setBorder(mBorderColor, mBorderWidth); if (mOverlayColor != Color.TRANSPARENT) { - roundingParams.setOverlayColor(mOverlayColor); + roundingParams.setOverlayColor(mOverlayColor); } else { - // make sure the default rounding method is used. - roundingParams.setRoundingMethod(RoundingParams.RoundingMethod.BITMAP_ONLY); + // make sure the default rounding method is used. + roundingParams.setRoundingMethod(RoundingParams.RoundingMethod.BITMAP_ONLY); } hierarchy.setRoundingParams(roundingParams); hierarchy.setFadeDuration( - mFadeDurationMs >= 0 - ? mFadeDurationMs - : mImageSource.isResource() ? 0 : REMOTE_IMAGE_FADE_DURATION_MS); + mFadeDurationMs >= 0 + ? mFadeDurationMs + : mImageSource.isResource() ? 0 : REMOTE_IMAGE_FADE_DURATION_MS); List postprocessors = new LinkedList<>(); if (usePostprocessorScaling) { @@ -461,10 +480,10 @@ public void maybeUpdateView() { ResizeOptions resizeOptions = doResize ? new ResizeOptions(getWidth(), getHeight()) : null; ImageRequestBuilder imageRequestBuilder = ImageRequestBuilder.newBuilderWithSource(mImageSource.getUri()) - .setPostprocessor(postprocessor) - .setResizeOptions(resizeOptions) - .setAutoRotateEnabled(true) - .setProgressiveRenderingEnabled(mProgressiveRenderingEnabled); + .setPostprocessor(postprocessor) + .setResizeOptions(resizeOptions) + .setAutoRotateEnabled(true) + .setProgressiveRenderingEnabled(mProgressiveRenderingEnabled); ImageRequest imageRequest = ReactNetworkImageRequest.fromBuilderWithHeaders(imageRequestBuilder, mHeaders); @@ -476,10 +495,10 @@ public void maybeUpdateView() { mDraweeControllerBuilder.reset(); mDraweeControllerBuilder - .setAutoPlayAnimations(true) - .setCallerContext(mCallerContext) - .setOldController(getController()) - .setImageRequest(imageRequest); + .setAutoPlayAnimations(true) + .setCallerContext(mCallerContext) + .setOldController(getController()) + .setImageRequest(imageRequest); if (mCachedImageSource != null) { ImageRequest cachedImageRequest = @@ -566,7 +585,7 @@ private boolean shouldResize(ImageSource imageSource) { if (mResizeMethod == ImageResizeMethod.AUTO) { return UriUtil.isLocalContentUri(imageSource.getUri()) || - UriUtil.isLocalFileUri(imageSource.getUri()); + UriUtil.isLocalFileUri(imageSource.getUri()); } else if (mResizeMethod == ImageResizeMethod.RESIZE) { return true; } else { @@ -583,3 +602,4 @@ private void warnImageSource(String uri) { } } } + From 2ebd55f879c3d1d0aa608b84f36158c5bafac6ec Mon Sep 17 00:00:00 2001 From: Miguel Jimenez Esun Date: Tue, 27 Mar 2018 12:27:32 -0700 Subject: [PATCH 0151/1109] Upgrade Jest to 23.0.0-alpha.4 Reviewed By: cpojer Differential Revision: D7397960 fbshipit-source-id: 40984ff1ebfccdcba58f898abf8c52e2ed337221 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index eb2c29584298d1..c9793054ddc54a 100644 --- a/package.json +++ b/package.json @@ -216,7 +216,7 @@ "eslint-plugin-prettier": "2.6.0", "eslint-plugin-react": "7.6.1", "flow-bin": "^0.68.0", - "jest": "22.4.2", + "jest": "23.0.0-alpha.4", "jest-junit": "3.6.0", "prettier": "1.9.1", "react": "^16.3.0-alpha.2", From 15b25d854a01642530c1e5f7a2016f6dba41a714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= <165856+hramos@users.noreply.github.com> Date: Tue, 27 Mar 2018 14:31:42 -0700 Subject: [PATCH 0152/1109] Cache C++ downloads Summary: Closes https://github.com/facebook/react-native/pull/18595 Differential Revision: D7419532 Pulled By: hramos fbshipit-source-id: 0b64763f91efea8300c4cde4703e8496dbda8c49 --- .circleci/config.yml | 71 +++++++++++++----------- scripts/circleci/gradle_download_deps.sh | 5 ++ 2 files changed, 44 insertions(+), 32 deletions(-) create mode 100755 scripts/circleci/gradle_download_deps.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index 196d3d3e6edf3d..bb9570bf32274d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,42 +1,33 @@ aliases: # Cache Management - - &restore-yarn-cache + - &restore-cache-yarn keys: - - v1-yarn-{{ arch }}-{{ .Branch }}-{{ checksum "package.json" }} - # Fallback in case checksum fails - - v1-yarn-{{ arch }}-{{ .Branch }}- - # Fallback in case this is a first-time run on a fork - - v1-yarn-{{ arch }}-master- - - &save-yarn-cache + - v1-yarn-{{ arch }}-{{ checksum "package.json" }} + - v1-yarn-{{ arch }}- + - &save-cache-yarn paths: - node_modules - ~/.cache/yarn - key: v1-yarn-{{ arch }}-{{ .Branch }}-{{ checksum "package.json" }} + key: v1-yarn-{{ arch }}-{{ checksum "package.json" }} - &restore-cache-analysis keys: - - v1-analysis-dependencies-{{ arch }}-{{ .Branch }}-{{ checksum "package.json" }}{{ checksum "bots/package.json" }} - # Fallback in case checksum fails - - v1-analysis-dependencies-{{ arch }}-{{ .Branch }}- - # Fallback in case this is a first-time run on a fork - - v1-analysis-dependencies-{{ arch }}-master- + - v1-analysis-dependencies-{{ arch }}-{{ checksum "package.json" }}{{ checksum "bots/package.json" }} + - v1-analysis-dependencies-{{ arch }}- - &save-cache-analysis paths: - bots/node_modules - node_modules - key: v1-analysis-dependencies-{{ arch }}-{{ .Branch }}-{{ checksum "package.json" }}{{ checksum "bots/package.json" }} + key: v1-analysis-dependencies-{{ arch }}-{{ checksum "package.json" }}{{ checksum "bots/package.json" }} - &restore-cache-android-packages keys: - - v1-android-sdkmanager-packages-{{ arch }}-{{ .Branch }}-api-26-alpha-{{ checksum "scripts/circle-ci-android-setup.sh" }} - # Fallback in case checksum fails - - v1-android-sdkmanager-packages-{{ arch }}-{{ .Branch }}-api-26-alpha- - # Fallback in case this is a first-time run on a fork - - v1-android-sdkmanager-packages-{{ arch }}-master-api-26-alpha- + - v1-android-sdkmanager-packages-{{ arch }}-api-26-alpha-{{ checksum "scripts/circle-ci-android-setup.sh" }} + - v1-android-sdkmanager-packages-{{ arch }}-api-26-alpha- - &save-cache-android-packages paths: - /opt/android/sdk - key: v1-android-sdkmanager-packages-{{ arch }}-{{ .Branch }}-api-26-alpha-{{ checksum "scripts/circle-ci-android-setup.sh" }} + key: v1-android-sdkmanager-packages-{{ arch }}-api-26-alpha-{{ checksum "scripts/circle-ci-android-setup.sh" }} - &restore-cache-gradle keys: @@ -66,7 +57,6 @@ aliases: - &restore-cache-ndk keys: - v2-android-ndk-{{ arch }}-r10e-32-64-{{ checksum "scripts/circle-ci-android-setup.sh" }} - # Fallback in case checksum fails - v2-android-ndk-{{ arch }}-r10e-32-64- - &save-cache-ndk paths: @@ -89,6 +79,17 @@ aliases: - ~/watchman key: v1-watchman-{{ arch }}-v4.9.0 + - &restore-cache-gradle-downloads + keys: + - v1-gradle-{{ arch }}-{{ checksum "ReactAndroid/build.gradle" }}-{{ checksum "scripts/circleci/gradle_download_deps.sh" }} + - v1-gradle-{{ arch }}- + - &save-cache-gradle-downloads + paths: + - ~/.gradle + - ReactAndroid/build/downloads + - ReactAndroid/build/third-party-ndk + key: v1-gradle-{{ arch }}-{{ checksum "ReactAndroid/build.gradle" }}-{{ checksum "scripts/circleci/gradle_download_deps.sh" }} + # Branch Filtering - &filter-only-master-stable branches: @@ -201,6 +202,10 @@ aliases: ./scripts/circleci/check_license.sh ./scripts/circleci/check_cache.sh when: always + + - &gradle-download-deps + name: Download C++ Dependencies + command: ./scripts/circleci/gradle_download_deps.sh - &build-android-app name: Build Android App @@ -309,9 +314,9 @@ jobs: - checkout - run: *setup-artifacts - - restore-cache: *restore-yarn-cache + - restore-cache: *restore-cache-yarn - run: *yarn - - save-cache: *save-yarn-cache + - save-cache: *save-cache-yarn # Basic checks against the checkout, cache... - run: *run-sanity-checks @@ -357,9 +362,9 @@ jobs: - checkout - run: *setup-artifacts - - restore-cache: *restore-yarn-cache + - restore-cache: *restore-cache-yarn - run: *yarn - - save-cache: *save-yarn-cache + - save-cache: *save-cache-yarn - run: *run-js-tests @@ -447,13 +452,16 @@ jobs: - run: buck fetch ReactAndroid/src/main/java/com/facebook/react/shell - run: buck fetch ReactAndroid/src/test/... - run: buck fetch ReactAndroid/src/androidTest/... - - run: ./gradlew :ReactAndroid:downloadBoost :ReactAndroid:downloadDoubleConversion :ReactAndroid:downloadFolly :ReactAndroid:downloadGlog :ReactAndroid:downloadJSCHeaders + + - restore-cache: *restore-cache-gradle-downloads + - run: *gradle-download-deps + - save-cache: *save-cache-gradle-downloads - run: *install-node - run: *install-yarn - - restore-cache: *restore-yarn-cache + - restore-cache: *restore-cache-yarn - run: *yarn - - save-cache: *save-yarn-cache + - save-cache: *save-cache-yarn - run: name: Publish React Native Package @@ -512,10 +520,9 @@ jobs: - run: buck fetch ReactAndroid/src/test/... - run: buck fetch ReactAndroid/src/androidTest/... - # Gradle - - restore-cache: *restore-cache-gradle - - run: ./gradlew :ReactAndroid:downloadBoost :ReactAndroid:downloadDoubleConversion :ReactAndroid:downloadFolly :ReactAndroid:downloadGlog :ReactAndroid:downloadJSCHeaders - - save-cache: *save-cache-gradle + - restore-cache: *restore-cache-gradle-downloads + - run: *gradle-download-deps + - save-cache: *save-cache-gradle-downloads # Build and compile - run: *build-android-app diff --git a/scripts/circleci/gradle_download_deps.sh b/scripts/circleci/gradle_download_deps.sh new file mode 100755 index 00000000000000..1e093de55a0b7f --- /dev/null +++ b/scripts/circleci/gradle_download_deps.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +set -e + +./gradlew :ReactAndroid:downloadBoost :ReactAndroid:downloadDoubleConversion :ReactAndroid:downloadFolly :ReactAndroid:downloadGlog :ReactAndroid:downloadJSCHeaders \ No newline at end of file From e3941a18b184fe3b31051da1eccc21de14a5fc02 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Tue, 27 Mar 2018 15:04:07 -0700 Subject: [PATCH 0153/1109] Native Animated - Support border radius Summary: Border radius already works properly with native animated but was not in the whitelisted props. Tested in an app that animating border radius with native animated actually works. [GENERAL] [ENHANCEMENT] [NativeAnimated] - Support border radius Closes https://github.com/facebook/react-native/pull/18574 Differential Revision: D7415956 Pulled By: hramos fbshipit-source-id: 6dd46bcdcb10c6a1956dd1f526212f33a4f44425 --- Libraries/Animated/src/NativeAnimatedHelper.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Libraries/Animated/src/NativeAnimatedHelper.js b/Libraries/Animated/src/NativeAnimatedHelper.js index 5765dcfc63b829..68bf4563fa9597 100644 --- a/Libraries/Animated/src/NativeAnimatedHelper.js +++ b/Libraries/Animated/src/NativeAnimatedHelper.js @@ -145,6 +145,15 @@ const API = { const STYLES_WHITELIST = { opacity: true, transform: true, + borderRadius: true, + borderBottomEndRadius: true, + borderBottomLeftRadius: true, + borderBottomRightRadius: true, + borderBottomStartRadius: true, + borderTopEndRadius: true, + borderTopLeftRadius: true, + borderTopRightRadius: true, + borderTopStartRadius: true, /* ios styles */ shadowOpacity: true, shadowRadius: true, From 979c01ed2d3ebfc338fafac1014d1ed5c8f1882b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Tue, 27 Mar 2018 15:12:11 -0700 Subject: [PATCH 0154/1109] Build yoga in OSS Differential Revision: D7417644 fbshipit-source-id: 2641c1abc1083db83cbb304f8dcc7b781e329041 --- ReactCommon/yoga/BUCK | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ReactCommon/yoga/BUCK b/ReactCommon/yoga/BUCK index aa6308d384f6ea..43ac549233609d 100644 --- a/ReactCommon/yoga/BUCK +++ b/ReactCommon/yoga/BUCK @@ -1,6 +1,6 @@ -load("//ReactNative:DEFS.bzl", "rn_xplat_cxx_library") +load("//ReactNative:DEFS.bzl", "cxx_library") -rn_xplat_cxx_library( +cxx_library( name = "yoga", srcs = glob(["yoga/*.cpp"]), header_namespace = "", From f96d7ae6486eb245496c0fef07239ae0480e88b6 Mon Sep 17 00:00:00 2001 From: Peter Argany Date: Tue, 27 Mar 2018 17:56:05 -0700 Subject: [PATCH 0155/1109] Bridged FBPullToRefresh to JS Reviewed By: shergin Differential Revision: D6875099 fbshipit-source-id: 00bbad7569ff047a77f198ad2bf4d77fccbaa2e9 --- React/Views/ScrollView/RCTScrollView.m | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/React/Views/ScrollView/RCTScrollView.m b/React/Views/ScrollView/RCTScrollView.m index f146ba0d2369a0..f2d4da1ecff5e9 100644 --- a/React/Views/ScrollView/RCTScrollView.m +++ b/React/Views/ScrollView/RCTScrollView.m @@ -443,6 +443,11 @@ - (void)insertReactSubview:(UIView *)view atIndex:(NSInteger)atIndex #if !TARGET_OS_TV if ([view isKindOfClass:[RCTRefreshControl class]]) { [_scrollView setRctRefreshControl:(RCTRefreshControl *)view]; + } + else if ([view conformsToProtocol:@protocol(UIScrollViewDelegate)]) { + [self addScrollListener:(UIView *)view]; + [_scrollView addSubview:view]; + [_scrollView sendSubviewToBack:view]; } else #endif { @@ -459,6 +464,9 @@ - (void)removeReactSubview:(UIView *)subview #if !TARGET_OS_TV if ([subview isKindOfClass:[RCTRefreshControl class]]) { [_scrollView setRctRefreshControl:nil]; + } else if ([subview conformsToProtocol:@protocol(UIScrollViewDelegate)]) { + [self removeScrollListener:(UIView *)subview]; + [subview removeFromSuperview]; } else #endif { From fd4bc72512d548700759212b0d65926c98e7ba49 Mon Sep 17 00:00:00 2001 From: Peter Argany Date: Tue, 27 Mar 2018 17:56:06 -0700 Subject: [PATCH 0156/1109] Add custom RefreshControl support to VirtualizedList Reviewed By: TheSavior, mmmulani Differential Revision: D7388137 fbshipit-source-id: 8a1448e5fc526b45773fe4a4f123a179d4a8bee9 --- Libraries/Lists/VirtualizedList.js | 33 +++++++++++++++++++----------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/Libraries/Lists/VirtualizedList.js b/Libraries/Lists/VirtualizedList.js index 928050f7682fa4..e03750e106ab55 100644 --- a/Libraries/Lists/VirtualizedList.js +++ b/Libraries/Lists/VirtualizedList.js @@ -173,6 +173,12 @@ type OptionalProps = { * @platform android */ progressViewOffset?: number, + /** + * A custom refresh control element. When set, it overrides the default + * component built internally. The onRefresh and refreshing + * props are also ignored. Only works for vertical VirtualizedList. + */ + refreshControl?: ?React.Element, /** * Set this true while waiting for new data from a refresh. */ @@ -893,9 +899,10 @@ class VirtualizedList extends React.PureComponent { onScrollEndDrag: this._onScrollEndDrag, onMomentumScrollEnd: this._onMomentumScrollEnd, scrollEventThrottle: this.props.scrollEventThrottle, // TODO: Android support - invertStickyHeaders: this.props.invertStickyHeaders !== undefined - ? this.props.invertStickyHeaders - : this.props.inverted, + invertStickyHeaders: + this.props.invertStickyHeaders !== undefined + ? this.props.invertStickyHeaders + : this.props.inverted, stickyHeaderIndices, }; if (inversionStyle) { @@ -990,9 +997,10 @@ class VirtualizedList extends React.PureComponent { } _defaultRenderScrollComponent = props => { + const onRefresh = props.onRefresh; if (this._isNestedWithSameOrientation()) { return ; - } else if (props.onRefresh) { + } else if (onRefresh) { invariant( typeof props.refreshing === 'boolean', '`refreshing` prop must be set as a boolean in order to use `onRefresh`, but got `' + @@ -1003,14 +1011,15 @@ class VirtualizedList extends React.PureComponent { =0.53.0 site=react_native_fb,react_native_oss) This - * comment suppresses an error when upgrading Flow's support for - * React. To see the error delete this comment and run Flow. */ - + props.refreshControl == null ? ( + + ) : ( + props.refreshControl + ) } /> ); From 9c805062e780b323a08747568a1efda367cbec13 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Tue, 27 Mar 2018 18:27:13 -0700 Subject: [PATCH 0157/1109] Refactor RootShadowNodeRegistry to make it ThreadSafe Reviewed By: achen1 Differential Revision: D7417965 fbshipit-source-id: 90fa007242d2f00a315a4db25d2b6a0949e4b0d3 --- .../react/fabric/FabricUIManager.java | 6 ++--- .../react/fabric/RootShadowNodeRegistry.java | 26 +++++++++++++------ 2 files changed, 21 insertions(+), 11 deletions(-) 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 47359b44fa761b..6959c275ff5916 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -270,7 +270,7 @@ public synchronized void completeRoot(int rootTag, List childLi mUIViewOperationQueue.dispatchViewUpdates( mCurrentBatch++, System.currentTimeMillis(), System.currentTimeMillis()); - mRootShadowNodeRegistry.addNode(currentRootShadowNode); + mRootShadowNodeRegistry.replaceNode(currentRootShadowNode); } catch (Exception e) { handleException(getRootNode(rootTag), e); } @@ -320,7 +320,7 @@ private void applyUpdatesRecursive(ReactShadowNode node, float absoluteX, float } @Override - public synchronized int addRootView( + public int addRootView( final T rootView) { int rootTag = ReactRootViewTagGenerator.getNextRootViewTag(); ThemedReactContext themedRootContext = @@ -332,7 +332,7 @@ public synchronized int heightMeasureSpec = rootView.getHeightMeasureSpec(); updateRootView(rootShadowNode, widthMeasureSpec, heightMeasureSpec); - mRootShadowNodeRegistry.addNode(rootShadowNode); + mRootShadowNodeRegistry.registerNode(rootShadowNode); mUIViewOperationQueue.addRootView(rootTag, rootView, themedRootContext); return rootTag; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/RootShadowNodeRegistry.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/RootShadowNodeRegistry.java index 49884cfc1f243e..1d66d4b500e6d3 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/RootShadowNodeRegistry.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/RootShadowNodeRegistry.java @@ -7,30 +7,40 @@ package com.facebook.react.fabric; -import android.util.SparseArray; import com.facebook.react.uimanager.ReactShadowNode; +import java.util.concurrent.ConcurrentHashMap; +import javax.annotation.concurrent.ThreadSafe; /** * Simple container class to keep track of {@link ReactShadowNode}s that represents the Root - * Shadow Nodes of a {@link FabricUIManager} + * Shadow Nodes of a {@link FabricUIManager}. */ +@ThreadSafe public class RootShadowNodeRegistry { - private final SparseArray mTagsToRootNodes; + private final ConcurrentHashMap mTagsToRootNodes = new ConcurrentHashMap<>(); - public RootShadowNodeRegistry() { - mTagsToRootNodes = new SparseArray<>(); + /** + * Registers the {@link ReactShadowNode} received as a parameter as a RootShadowNode. + */ + public synchronized void registerNode(ReactShadowNode node) { + mTagsToRootNodes.put(node.getReactTag(), node); } - public void addNode(ReactShadowNode node) { - mTagsToRootNodes.put(node.getReactTag(), node); + /** + * Register the {@link ReactShadowNode} received as a parameter as a RootShadowNode, replacing + * the previous RootShadowNode associated for the {@link ReactShadowNode#getReactTag()} + */ + public void replaceNode(ReactShadowNode node) { + mTagsToRootNodes.replace(node.getReactTag(), node); } - public void removeNode(int tag) { + public void removeNode(Integer tag) { mTagsToRootNodes.remove(tag); } public ReactShadowNode getNode(int tag) { return mTagsToRootNodes.get(tag); } + } From bd134ce6af6f247ab72f5cdc5b36a6b44ad84811 Mon Sep 17 00:00:00 2001 From: Miguel Jimenez Esun Date: Wed, 28 Mar 2018 04:38:59 -0700 Subject: [PATCH 0158/1109] Increase timeouts to 15, 10 Reviewed By: javache Differential Revision: D7415558 fbshipit-source-id: 76912d22b8e330845fcca3fa27aab6ed28256a94 --- Libraries/WebSocket/RCTWebSocketExecutor.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Libraries/WebSocket/RCTWebSocketExecutor.m b/Libraries/WebSocket/RCTWebSocketExecutor.m index 14f53a43c2daab..2544772829a2aa 100644 --- a/Libraries/WebSocket/RCTWebSocketExecutor.m +++ b/Libraries/WebSocket/RCTWebSocketExecutor.m @@ -103,7 +103,7 @@ - (BOOL)connectToProxy { _socketOpenSemaphore = dispatch_semaphore_create(0); [_socket open]; - long connected = dispatch_semaphore_wait(_socketOpenSemaphore, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 10)); + long connected = dispatch_semaphore_wait(_socketOpenSemaphore, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 15)); return connected == 0 && _socket.readyState == RCTSR_OPEN; } @@ -115,7 +115,7 @@ - (BOOL)prepareJSRuntime initError = error; dispatch_semaphore_signal(s); }]; - long runtimeIsReady = dispatch_semaphore_wait(s, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 5)); + long runtimeIsReady = dispatch_semaphore_wait(s, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 10)); if (initError) { RCTLogInfo(@"Websocket runtime setup failed: %@", initError); } From 88ba7ebcc77e5ff0a38954d298b6478960d0702a Mon Sep 17 00:00:00 2001 From: Peter van der Zee Date: Wed, 28 Mar 2018 10:10:57 -0700 Subject: [PATCH 0159/1109] Fix "function statements" in strict mode builds Reviewed By: davidaurelio Differential Revision: D7427473 fbshipit-source-id: 130d0653c100c4a12b2a01aa3489b780febf6d8e --- Libraries/polyfills/console.js | 180 ++++++++++++++++----------------- 1 file changed, 90 insertions(+), 90 deletions(-) diff --git a/Libraries/polyfills/console.js b/Libraries/polyfills/console.js index 37a92b1a62fe1f..794a89c4f49f97 100644 --- a/Libraries/polyfills/console.js +++ b/Libraries/polyfills/console.js @@ -401,108 +401,108 @@ INSPECTOR_LEVELS[LOG_LEVELS.error] = 'error'; // strip method printing to originalConsole. const INSPECTOR_FRAMES_TO_SKIP = __DEV__ ? 2 : 1; -if (global.nativeLoggingHook) { - function getNativeLogFunction(level) { - return function() { - let str; - if (arguments.length === 1 && typeof arguments[0] === 'string') { - str = arguments[0]; - } else { - str = Array.prototype.map - .call(arguments, function(arg) { - return inspect(arg, {depth: 10}); - }) - .join(', '); - } - - let logLevel = level; - if (str.slice(0, 9) === 'Warning: ' && logLevel >= LOG_LEVELS.error) { - // React warnings use console.error so that a stack trace is shown, - // but we don't (currently) want these to show a redbox - // (Note: Logic duplicated in ExceptionsManager.js.) - logLevel = LOG_LEVELS.warn; - } - if (global.__inspectorLog) { - global.__inspectorLog( - INSPECTOR_LEVELS[logLevel], - str, - [].slice.call(arguments), - INSPECTOR_FRAMES_TO_SKIP, - ); - } - global.nativeLoggingHook(str, logLevel); - }; - } - - function repeat(element, n) { - return Array.apply(null, Array(n)).map(function() { - return element; - }); - } +function getNativeLogFunction(level) { + return function() { + let str; + if (arguments.length === 1 && typeof arguments[0] === 'string') { + str = arguments[0]; + } else { + str = Array.prototype.map + .call(arguments, function(arg) { + return inspect(arg, {depth: 10}); + }) + .join(', '); + } - function consoleTablePolyfill(rows) { - // convert object -> array - if (!Array.isArray(rows)) { - var data = rows; - rows = []; - for (var key in data) { - if (data.hasOwnProperty(key)) { - var row = data[key]; - row[OBJECT_COLUMN_NAME] = key; - rows.push(row); - } - } + let logLevel = level; + if (str.slice(0, 9) === 'Warning: ' && logLevel >= LOG_LEVELS.error) { + // React warnings use console.error so that a stack trace is shown, + // but we don't (currently) want these to show a redbox + // (Note: Logic duplicated in ExceptionsManager.js.) + logLevel = LOG_LEVELS.warn; } - if (rows.length === 0) { - global.nativeLoggingHook('', LOG_LEVELS.info); - return; + if (global.__inspectorLog) { + global.__inspectorLog( + INSPECTOR_LEVELS[logLevel], + str, + [].slice.call(arguments), + INSPECTOR_FRAMES_TO_SKIP, + ); } + global.nativeLoggingHook(str, logLevel); + }; +} - var columns = Object.keys(rows[0]).sort(); - var stringRows = []; - var columnWidths = []; - - // Convert each cell to a string. Also - // figure out max cell width for each column - columns.forEach(function(k, i) { - columnWidths[i] = k.length; - for (var j = 0; j < rows.length; j++) { - var cellStr = (rows[j][k] || '?').toString(); - stringRows[j] = stringRows[j] || []; - stringRows[j][i] = cellStr; - columnWidths[i] = Math.max(columnWidths[i], cellStr.length); - } - }); +function repeat(element, n) { + return Array.apply(null, Array(n)).map(function() { + return element; + }); +} - // Join all elements in the row into a single string with | separators - // (appends extra spaces to each cell to make separators | aligned) - function joinRow(row, space) { - var cells = row.map(function(cell, i) { - var extraSpaces = repeat(' ', columnWidths[i] - cell.length).join(''); - return cell + extraSpaces; - }); - space = space || ' '; - return cells.join(space + '|' + space); +function consoleTablePolyfill(rows) { + // convert object -> array + if (!Array.isArray(rows)) { + var data = rows; + rows = []; + for (var key in data) { + if (data.hasOwnProperty(key)) { + var row = data[key]; + row[OBJECT_COLUMN_NAME] = key; + rows.push(row); + } } + } + if (rows.length === 0) { + global.nativeLoggingHook('', LOG_LEVELS.info); + return; + } - var separators = columnWidths.map(function(columnWidth) { - return repeat('-', columnWidth).join(''); + var columns = Object.keys(rows[0]).sort(); + var stringRows = []; + var columnWidths = []; + + // Convert each cell to a string. Also + // figure out max cell width for each column + columns.forEach(function(k, i) { + columnWidths[i] = k.length; + for (var j = 0; j < rows.length; j++) { + var cellStr = (rows[j][k] || '?').toString(); + stringRows[j] = stringRows[j] || []; + stringRows[j][i] = cellStr; + columnWidths[i] = Math.max(columnWidths[i], cellStr.length); + } + }); + + // Join all elements in the row into a single string with | separators + // (appends extra spaces to each cell to make separators | aligned) + function joinRow(row, space) { + var cells = row.map(function(cell, i) { + var extraSpaces = repeat(' ', columnWidths[i] - cell.length).join(''); + return cell + extraSpaces; }); - var separatorRow = joinRow(separators, '-'); - var header = joinRow(columns); - var table = [header, separatorRow]; + space = space || ' '; + return cells.join(space + '|' + space); + } - for (var i = 0; i < rows.length; i++) { - table.push(joinRow(stringRows[i])); - } + var separators = columnWidths.map(function(columnWidth) { + return repeat('-', columnWidth).join(''); + }); + var separatorRow = joinRow(separators, '-'); + var header = joinRow(columns); + var table = [header, separatorRow]; - // Notice extra empty line at the beginning. - // Native logging hook adds "RCTLog >" at the front of every - // logged string, which would shift the header and screw up - // the table - global.nativeLoggingHook('\n' + table.join('\n'), LOG_LEVELS.info); + for (var i = 0; i < rows.length; i++) { + table.push(joinRow(stringRows[i])); } + // Notice extra empty line at the beginning. + // Native logging hook adds "RCTLog >" at the front of every + // logged string, which would shift the header and screw up + // the table + global.nativeLoggingHook('\n' + table.join('\n'), LOG_LEVELS.info); +} + +if (global.nativeLoggingHook) { const originalConsole = global.console; global.console = { error: getNativeLogFunction(LOG_LEVELS.error), From 7cbb222cd53b6cc49ec848827104ccf497f33de2 Mon Sep 17 00:00:00 2001 From: Dmitry Zakharov Date: Wed, 28 Mar 2018 12:52:20 -0700 Subject: [PATCH 0160/1109] Remove class-loading experiment for View Managers. Reviewed By: fkgozali Differential Revision: D7418876 fbshipit-source-id: 52f8dce29a509233b9545a564c4f0d390fa81f13 --- .../java/com/facebook/react/CompositeReactPackage.java | 10 ++++------ .../java/com/facebook/react/ReactInstanceManager.java | 7 ++----- .../facebook/react/ReactInstanceManagerBuilder.java | 8 -------- .../react/ViewManagerOnDemandReactPackage.java | 9 ++------- 4 files changed, 8 insertions(+), 26 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/CompositeReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/CompositeReactPackage.java index ab82f0d9643264..7aff02cfccfef3 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/CompositeReactPackage.java +++ b/ReactAndroid/src/main/java/com/facebook/react/CompositeReactPackage.java @@ -98,14 +98,13 @@ public List createViewManagers(ReactApplicationContext reactContext /** {@inheritDoc} */ @Override - public List getViewManagerNames( - ReactApplicationContext reactContext, boolean loadClasses) { + public List getViewManagerNames(ReactApplicationContext reactContext) { Set uniqueNames = new HashSet<>(); for (ReactPackage reactPackage : mChildReactPackages) { if (reactPackage instanceof ViewManagerOnDemandReactPackage) { List names = ((ViewManagerOnDemandReactPackage) reactPackage) - .getViewManagerNames(reactContext, loadClasses); + .getViewManagerNames(reactContext); if (names != null) { uniqueNames.addAll(names); } @@ -116,15 +115,14 @@ public List getViewManagerNames( /** {@inheritDoc} */ @Override - public @Nullable ViewManager createViewManager( - ReactApplicationContext reactContext, String viewManagerName, boolean loadClasses) { + public @Nullable ViewManager createViewManager(ReactApplicationContext reactContext, String viewManagerName) { ListIterator iterator = mChildReactPackages.listIterator(mChildReactPackages.size()); while (iterator.hasPrevious()) { ReactPackage reactPackage = iterator.previous(); if (reactPackage instanceof ViewManagerOnDemandReactPackage) { ViewManager viewManager = ((ViewManagerOnDemandReactPackage) reactPackage) - .createViewManager(reactContext, viewManagerName, loadClasses); + .createViewManager(reactContext, viewManagerName); if (viewManager != null) { return viewManager; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java index 1d2731a71c856b..d2dbda4dd6d9e0 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java @@ -156,7 +156,6 @@ public interface ReactInstanceEventListener { private final MemoryPressureRouter mMemoryPressureRouter; private final @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler; private final boolean mLazyNativeModulesEnabled; - private final boolean mDelayViewManagerClassLoadsEnabled; private final @Nullable JSIModulesProvider mJSIModulesProvider; private List mViewManagers; @@ -203,7 +202,6 @@ public static ReactInstanceManagerBuilder builder() { @Nullable RedBoxHandler redBoxHandler, boolean lazyNativeModulesEnabled, boolean lazyViewManagersEnabled, - boolean delayViewManagerClassLoadsEnabled, @Nullable DevBundleDownloadListener devBundleDownloadListener, int minNumShakes, int minTimeLeftInFrameForNonBatchedOperationMs, @@ -235,7 +233,6 @@ public static ReactInstanceManagerBuilder builder() { mMemoryPressureRouter = new MemoryPressureRouter(applicationContext); mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler; mLazyNativeModulesEnabled = lazyNativeModulesEnabled; - mDelayViewManagerClassLoadsEnabled = delayViewManagerClassLoadsEnabled; synchronized (mPackages) { PrinterHolder.getPrinter() .logMessage(ReactDebugOverlayTags.RN_CORE, "RNCore: Use Split Packages"); @@ -780,7 +777,7 @@ public List getOrCreateViewManagers( if (reactPackage instanceof ViewManagerOnDemandReactPackage) { ViewManager viewManager = ((ViewManagerOnDemandReactPackage) reactPackage) - .createViewManager(context, viewManagerName, !mDelayViewManagerClassLoadsEnabled); + .createViewManager(context, viewManagerName); if (viewManager != null) { return viewManager; } @@ -805,7 +802,7 @@ public List getOrCreateViewManagers( if (reactPackage instanceof ViewManagerOnDemandReactPackage) { List names = ((ViewManagerOnDemandReactPackage) reactPackage) - .getViewManagerNames(context, !mDelayViewManagerClassLoadsEnabled); + .getViewManagerNames(context); if (names != null) { uniqueNames.addAll(names); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.java index 75792d83db3bea..a0f4438330e644 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.java @@ -44,7 +44,6 @@ public class ReactInstanceManagerBuilder { private @Nullable RedBoxHandler mRedBoxHandler; private boolean mLazyNativeModulesEnabled; private boolean mLazyViewManagersEnabled; - private boolean mDelayViewManagerClassLoadsEnabled; private @Nullable DevBundleDownloadListener mDevBundleDownloadListener; private @Nullable JavaScriptExecutorFactory mJavaScriptExecutorFactory; private int mMinNumShakes = 1; @@ -209,12 +208,6 @@ public ReactInstanceManagerBuilder setLazyViewManagersEnabled(boolean lazyViewMa return this; } - public ReactInstanceManagerBuilder setDelayViewManagerClassLoadsEnabled( - boolean delayViewManagerClassLoadsEnabled) { - mDelayViewManagerClassLoadsEnabled = delayViewManagerClassLoadsEnabled; - return this; - } - public ReactInstanceManagerBuilder setDevBundleDownloadListener( @Nullable DevBundleDownloadListener listener) { mDevBundleDownloadListener = listener; @@ -285,7 +278,6 @@ public ReactInstanceManager build() { mRedBoxHandler, mLazyNativeModulesEnabled, mLazyViewManagersEnabled, - mDelayViewManagerClassLoadsEnabled, mDevBundleDownloadListener, mMinNumShakes, mMinTimeLeftInFrameForNonBatchedOperationMs, diff --git a/ReactAndroid/src/main/java/com/facebook/react/ViewManagerOnDemandReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/ViewManagerOnDemandReactPackage.java index 7f17809ffbb19a..c28f91f60ee859 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ViewManagerOnDemandReactPackage.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ViewManagerOnDemandReactPackage.java @@ -16,17 +16,12 @@ public interface ViewManagerOnDemandReactPackage { /** * Provides a list of names of ViewManagers with which these modules can be accessed from JS. * Typically, this is ViewManager.getName(). - * - * @param loadClasses defines if View Managers classes should be loaded or be avoided. */ - @Nullable List getViewManagerNames(ReactApplicationContext reactContext, boolean loadClasses); + @Nullable List getViewManagerNames(ReactApplicationContext reactContext); /** * Creates and returns a ViewManager with a specific name {@param viewManagerName}. It's up to an * implementing package how to interpret the name. - * - * @param loadClasses defines if View Managers classes should be loaded or be avoided. */ @Nullable - ViewManager createViewManager( - ReactApplicationContext reactContext, String viewManagerName, boolean loadClasses); + ViewManager createViewManager(ReactApplicationContext reactContext, String viewManagerName); } From b531612b2c917e1f2bd6bb37bf854fe51e658b36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= <165856+hramos@users.noreply.github.com> Date: Wed, 28 Mar 2018 12:53:08 -0700 Subject: [PATCH 0161/1109] Collect unit test results in test_android job Summary: Explicitly generate a XML file with unit test results, and convert this file to JUnit format for display in Circle. Run in Circle: https://circleci.com/gh/hramos/react-native/1869 ![screen shot 2018-03-28 at 12 07 15 pm](https://user-images.githubusercontent.com/165856/38050644-9712b6c6-3280-11e8-953c-a2eb722edf39.png) [INTERNAL] [MINOR] [.circleci] - Collect, process, and display Android unit test results on Circle Closes https://github.com/facebook/react-native/pull/18608 Differential Revision: D7433151 Pulled By: hramos fbshipit-source-id: 7c18b552d7790b238b4c2a720fb316dff8fd7ec3 --- .circleci/config.yml | 38 ++++++++++++++++++------------ scripts/circle-ci-android-setup.sh | 5 +--- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index bb9570bf32274d..7452d4bd43a7b2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -56,20 +56,21 @@ aliases: - &restore-cache-ndk keys: - - v2-android-ndk-{{ arch }}-r10e-32-64-{{ checksum "scripts/circle-ci-android-setup.sh" }} - - v2-android-ndk-{{ arch }}-r10e-32-64- + - v3-android-ndk-{{ arch }}-r10e-{{ checksum "scripts/circle-ci-android-setup.sh" }} + - v3-android-ndk-{{ arch }}-r10e- - &save-cache-ndk paths: - /opt/ndk - key: v2-android-ndk-{{ arch }}-r10e-32-64-{{ checksum "scripts/circle-ci-android-setup.sh" }} + key: v3-android-ndk-{{ arch }}-r10e-{{ checksum "scripts/circle-ci-android-setup.sh" }} - &restore-cache-buck keys: - - v2-buck-{{ arch }}-v2018.02.16.01 + - v3-buck-{{ arch }}-v2018.02.16.01 - &save-cache-buck paths: - ~/buck - key: v2-buck-{{ arch }}-v2018.02.16.01 + - ~/okbuck + key: v3-buck-{{ arch }}-v2018.02.16.01 - &restore-cache-watchman keys: @@ -141,6 +142,13 @@ aliases: fi cd ~/buck && ant 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/. + - &install-node name: Install Node @@ -237,7 +245,7 @@ aliases: - &run-android-unit-tests name: Run Unit Tests - command: buck test ReactAndroid/src/test/... --config build.threads=$BUILD_THREADS + command: buck test ReactAndroid/src/test/... --config build.threads=$BUILD_THREADS --xml ~/react-native/reports/buck/all-results-raw.xml - &run-android-instrumentation-tests name: Run Instrumentation Tests @@ -250,15 +258,19 @@ aliases: - &collect-android-test-results name: Collect Test Results command: | - find . -type f -regex ".*/build/test-results/debug/.*xml" -exec cp {} ~/react-native/reports/junit/ \; - find . -type f -regex ".*/outputs/androidTest-results/connected/.*xml" -exec cp {} ~/react-native/reports/junit/ \; - find . -type f -regex ".*/buck-out/gen/ReactAndroid/src/test/.*/.*xml" -exec cp {} ~/react-native/reports/junit/ \; + 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 when: always - &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/ - &run-objc-ios-tests name: iOS Test Suite @@ -289,7 +301,7 @@ js_defaults: &js_defaults android_defaults: &android_defaults <<: *defaults docker: - - image: circleci/android:api-26-alpha + - image: circleci/android:api-26-node8-alpha resource_class: "large" environment: - TERM: "dumb" @@ -457,8 +469,6 @@ jobs: - run: *gradle-download-deps - save-cache: *save-cache-gradle-downloads - - run: *install-node - - run: *install-yarn - restore-cache: *restore-cache-yarn - run: *yarn - save-cache: *save-cache-yarn @@ -529,7 +539,6 @@ jobs: - run: *compile-native-libs # Build JavaScript Bundle for instrumentation tests - - run: *install-node - run: *build-js-bundle # Wait for AVD to finish booting before running tests @@ -539,12 +548,11 @@ jobs: - run: *run-android-unit-tests - run: *run-android-instrumentation-tests - # post (always runs) + # Collect Results - run: *collect-android-test-results - store_test_results: path: ~/react-native/reports/junit - # Analyze pull request and raise any lint/flow issues. # Issues will be posted to the PR itself via GitHub bots. # This workflow should only fail if the bots fail to run. diff --git a/scripts/circle-ci-android-setup.sh b/scripts/circle-ci-android-setup.sh index c5a0a1f31b52b7..35421a598a0313 100644 --- a/scripts/circle-ci-android-setup.sh +++ b/scripts/circle-ci-android-setup.sh @@ -41,14 +41,11 @@ function getAndroidNDK { if [ ! -e $DEPS ]; then cd $NDK_HOME echo "Downloading NDK..." - curl -o ndk.zip https://dl.google.com/android/repository/android-ndk-r10e-linux-x86.zip - curl -o ndk_64.zip https://dl.google.com/android/repository/android-ndk-r10e-linux-x86_64.zip + curl -o ndk.zip https://dl.google.com/android/repository/android-ndk-r10e-linux-x86_64.zip unzip -o -q ndk.zip - unzip -o -q ndk_64.zip echo "Installed Android NDK at $NDK_HOME" touch $DEPS rm ndk.zip - rm ndk_64.zip fi } From e88f1286089aad05f8c3932c87913f30a64f1be6 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Wed, 28 Mar 2018 23:17:32 -0700 Subject: [PATCH 0162/1109] Refactor ReactShadowNode.SetRootNode() -> ReactShadowNode.setRootTag() Reviewed By: achen1 Differential Revision: D7419566 fbshipit-source-id: 6be790972e88b879fe690acd4f23d0caa27964a4 --- .../com/facebook/react/fabric/FabricUIManager.java | 2 +- .../react/uimanager/NativeViewHierarchyOptimizer.java | 2 +- .../com/facebook/react/uimanager/ReactShadowNode.java | 4 ++-- .../facebook/react/uimanager/ReactShadowNodeImpl.java | 11 +++++------ .../facebook/react/uimanager/UIImplementation.java | 4 ++-- 5 files changed, 11 insertions(+), 12 deletions(-) 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 6959c275ff5916..2cadd153c3f1a7 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -77,7 +77,7 @@ public ReactShadowNode createNode( ViewManager viewManager = mViewManagerRegistry.get(viewName); ReactShadowNode node = viewManager.createShadowNodeInstance(mReactApplicationContext); ReactShadowNode rootNode = getRootNode(rootTag); - node.setRootNode(rootNode); + node.setRootTag(rootNode.getReactTag()); node.setViewClassName(viewName); node.setReactTag(reactTag); node.setThemedContext(rootNode.getThemedContext()); diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyOptimizer.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyOptimizer.java index de23eeaa1cce25..b6562779875f19 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyOptimizer.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyOptimizer.java @@ -407,7 +407,7 @@ private void transitionLayoutOnlyViewToNativeView( // Create the view since it doesn't exist in the native hierarchy yet mUIViewOperationQueue.enqueueCreateView( - node.getRootNode().getThemedContext(), + node.getThemedContext(), node.getReactTag(), node.getViewClass(), props); diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java index dbf64b1355b84b..7790a49ddf61eb 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java @@ -139,9 +139,9 @@ public interface ReactShadowNode { void setReactTag(int reactTag); - T getRootNode(); + int getRootTag(); - void setRootNode(T rootNode); + void setRootTag(int rootTag); void setViewClassName(String viewClassName); diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java index 5f4ad868fe7751..e6b4a901227120 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java @@ -78,7 +78,6 @@ public void onNodeCloned(YogaNode oldYogaNode, private int mReactTag; private @Nullable String mViewClassName; - private @Nullable ReactShadowNodeImpl mRootNode; private int mRootTag; private @Nullable ThemedReactContext mThemedContext; private boolean mShouldNotifyOnLayout; @@ -118,7 +117,6 @@ protected ReactShadowNodeImpl(ReactShadowNodeImpl original) { mReactTag = original.mReactTag; mRootTag = original.mRootTag; mViewClassName = original.mViewClassName; - mRootNode = original.mRootNode; mThemedContext = original.mThemedContext; mShouldNotifyOnLayout = original.mShouldNotifyOnLayout; mNodeUpdated = original.mNodeUpdated; @@ -493,13 +491,14 @@ public void setReactTag(int reactTag) { } @Override - public final ReactShadowNodeImpl getRootNode() { - return Assertions.assertNotNull(mRootNode); + public final int getRootTag() { + Assertions.assertCondition(mRootTag != 0); + return mRootTag; } @Override - public final void setRootNode(ReactShadowNodeImpl rootNode) { - mRootNode = rootNode; + public final void setRootTag(int rootTag) { + mRootTag = rootTag; } @Override diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java index f33ab605700f29..186a4d4357c325 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java @@ -279,7 +279,7 @@ public void createView(int tag, String className, int rootViewTag, ReadableMap p Assertions.assertNotNull(rootNode, "Root node with tag " + rootViewTag + " doesn't exist"); cssNode.setReactTag(tag); cssNode.setViewClassName(className); - cssNode.setRootNode(rootNode); + cssNode.setRootTag(rootNode.getReactTag()); cssNode.setThemedContext(rootNode.getThemedContext()); mShadowNodeRegistry.addNode(cssNode); @@ -1008,7 +1008,7 @@ public int resolveRootTagFromReactTag(int reactTag) { ReactShadowNode node = resolveShadowNode(reactTag); int rootTag = 0; if (node != null) { - rootTag = node.getRootNode().getReactTag(); + rootTag = node.getRootTag(); } else { FLog.w( ReactConstants.TAG, From ff2260b0220faf124c43df9746e1394882fa4d71 Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Thu, 29 Mar 2018 05:24:29 -0700 Subject: [PATCH 0163/1109] Add `JByteBuffer::rewind()` Summary: Adds a `rewind()` method to `JByteBuffer`, which maps to `java.nio.Buffer#rewind()`. This is useful if a `ByteBuffer` is reused for calls between Java and C++. Differential Revision: D7435171 fbshipit-source-id: 488131d6ad2d5abb1b86a5efabc2f39ba0ab16cd --- .../main/jni/first-party/fb/include/fb/fbjni/ByteBuffer.h | 7 +++++++ .../src/main/jni/first-party/fb/jni/ByteBuffer.cpp | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/ByteBuffer.h b/ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/ByteBuffer.h index 21d17a27ad8e33..1e31d76cf8cca9 100644 --- a/ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/ByteBuffer.h +++ b/ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/ByteBuffer.h @@ -15,6 +15,13 @@ namespace facebook { namespace jni { +class JBuffer : public JavaClass { +public: + static constexpr const char* kJavaDescriptor = "Ljava/nio/Buffer;"; + + void rewind() const; +}; + // JNI's NIO support has some awkward preconditions and error reporting. This // class provides much more user-friendly access. class FBEXPORT JByteBuffer : public JavaClass { diff --git a/ReactAndroid/src/main/jni/first-party/fb/jni/ByteBuffer.cpp b/ReactAndroid/src/main/jni/first-party/fb/jni/ByteBuffer.cpp index 5a5317f9f2b15c..8060930275c5d8 100644 --- a/ReactAndroid/src/main/jni/first-party/fb/jni/ByteBuffer.cpp +++ b/ReactAndroid/src/main/jni/first-party/fb/jni/ByteBuffer.cpp @@ -22,6 +22,11 @@ local_ref createEmpty() { } } +void JBuffer::rewind() const { + static auto meth = javaClassStatic()->getMethod()>("rewind"); + meth(self()); +} + local_ref JByteBuffer::wrapBytes(uint8_t* data, size_t size) { // env->NewDirectByteBuffer requires that size is positive. Android's // dalvik returns an invalid result and Android's art aborts if size == 0. From f3ef227904acef4f0525839e84f407d6cf5d7a0c Mon Sep 17 00:00:00 2001 From: "glevi@fb.com" Date: Thu, 29 Mar 2018 06:24:04 -0700 Subject: [PATCH 0164/1109] Upgrade to Flow v0.69.0 Reviewed By: panagosg7 Differential Revision: D7437630 fbshipit-source-id: db9627afed89049c07a121296fbd52e2bfbf39bf --- .flowconfig | 2 +- local-cli/bundle/buildBundle.js | 1 - local-cli/server/runServer.js | 1 - local-cli/server/server.js | 2 +- local-cli/templates/HelloWorld/_flowconfig | 2 +- package.json | 2 +- 6 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.flowconfig b/.flowconfig index 182bf0f089e611..f67339eee78487 100644 --- a/.flowconfig +++ b/.flowconfig @@ -52,4 +52,4 @@ suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError [version] -^0.68.0 +^0.69.0 diff --git a/local-cli/bundle/buildBundle.js b/local-cli/bundle/buildBundle.js index 51427aa8f3a3d4..ebebc09c6ebf0d 100644 --- a/local-cli/bundle/buildBundle.js +++ b/local-cli/bundle/buildBundle.js @@ -13,7 +13,6 @@ const log = require('../util/log').out('bundle'); /* $FlowFixMe(site=react_native_oss) */ const Server = require('metro/src/Server'); const {Terminal} = require('metro-core'); -/* $FlowFixMe(site=react_native_oss) */ const TerminalReporter = require('metro/src/lib/TerminalReporter'); /* $FlowFixMe(site=react_native_oss) */ const TransformCaching = require('metro/src/lib/TransformCaching'); diff --git a/local-cli/server/runServer.js b/local-cli/server/runServer.js index a9ba1557ddc7d1..768fbaf0d3676a 100644 --- a/local-cli/server/runServer.js +++ b/local-cli/server/runServer.js @@ -48,7 +48,6 @@ const TransformCaching = require('metro/src/lib/TransformCaching'); const {ASSET_REGISTRY_PATH} = require('../core/Constants'); -/* $FlowFixMe(site=react_native_oss) */ import type {ConfigT} from 'metro'; /* $FlowFixMe(site=react_native_oss) */ import type {Reporter} from 'metro/src/lib/reporting'; diff --git a/local-cli/server/server.js b/local-cli/server/server.js index f188a3e82dd48d..7711e8590afcec 100644 --- a/local-cli/server/server.js +++ b/local-cli/server/server.js @@ -47,7 +47,7 @@ function server(argv: mixed, config: RNConfig, allArgs: Object) { }); }; const runServerArgs: RunServerArgs = args; - /* $FlowFixMe: ConfigT shouldn't be extendable. */ + /* $FlowFixMe(site=react_native_fb) ConfigT shouldn't be extendable. */ const configT: ConfigT = config; runServer(runServerArgs, configT, startedCallback, readyCallback); } diff --git a/local-cli/templates/HelloWorld/_flowconfig b/local-cli/templates/HelloWorld/_flowconfig index 3813ec4a1011c9..159649f1348ef7 100644 --- a/local-cli/templates/HelloWorld/_flowconfig +++ b/local-cli/templates/HelloWorld/_flowconfig @@ -51,4 +51,4 @@ suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError [version] -^0.68.0 +^0.69.0 diff --git a/package.json b/package.json index c9793054ddc54a..5c9215a2c22803 100644 --- a/package.json +++ b/package.json @@ -215,7 +215,7 @@ "eslint-plugin-jest": "21.8.0", "eslint-plugin-prettier": "2.6.0", "eslint-plugin-react": "7.6.1", - "flow-bin": "^0.68.0", + "flow-bin": "^0.69.0", "jest": "23.0.0-alpha.4", "jest-junit": "3.6.0", "prettier": "1.9.1", From 24b5721fb4a7c7c3a5994649c4e8bf78e647fce9 Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Thu, 29 Mar 2018 07:58:16 -0700 Subject: [PATCH 0165/1109] Fix `ByteBuffer.h` Reviewed By: mjesun Differential Revision: D7443482 fbshipit-source-id: aa765d54149fd81f785dbca7252342ed9b3c236d --- .../src/main/jni/first-party/fb/include/fb/fbjni/ByteBuffer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/ByteBuffer.h b/ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/ByteBuffer.h index 1e31d76cf8cca9..2f160839f5b44b 100644 --- a/ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/ByteBuffer.h +++ b/ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/ByteBuffer.h @@ -24,7 +24,7 @@ class JBuffer : public JavaClass { // JNI's NIO support has some awkward preconditions and error reporting. This // class provides much more user-friendly access. -class FBEXPORT JByteBuffer : public JavaClass { +class FBEXPORT JByteBuffer : public JavaClass { public: static constexpr const char* kJavaDescriptor = "Ljava/nio/ByteBuffer;"; From 6be7b396ecd5f10a8c08cd5f6428eeccbf986a7d Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Thu, 29 Mar 2018 11:02:04 -0700 Subject: [PATCH 0166/1109] Update okio Summary: Update okio dependency from 1.13.0 to 1.14.0. The interesting feature is `BufferedSource` extending `java.nio.ReadableByteChannel`, allowing to bridge with `java.nio` more easily and integrating with the latest fbjni additions. Reviewed By: emilsjolander Differential Revision: D7443269 fbshipit-source-id: e397d7a0436e3fc59ade1f4357f30190ca7bbe35 --- ReactAndroid/build.gradle | 4 ++-- ReactAndroid/src/main/third-party/java/okio/BUCK | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle index 48c38722a16751..25ba9d2c1b2816 100644 --- a/ReactAndroid/build.gradle +++ b/ReactAndroid/build.gradle @@ -287,7 +287,7 @@ dependencies { compile 'com.google.code.findbugs:jsr305:3.0.0' compile 'com.squareup.okhttp3:okhttp:3.8.0' compile 'com.squareup.okhttp3:okhttp-urlconnection:3.8.0' - compile 'com.squareup.okio:okio:1.13.0' + compile 'com.squareup.okio:okio:1.14.0' compile 'org.webkit:android-jsc:r174650' testCompile "junit:junit:${JUNIT_VERSION}" @@ -297,7 +297,7 @@ dependencies { testCompile "org.mockito:mockito-core:${MOCKITO_CORE_VERSION}" testCompile "org.easytesting:fest-assert-core:${FEST_ASSERT_CORE_VERSION}" testCompile "org.robolectric:robolectric:${ROBOLECTRIC_VERSION}" - + androidTestCompile fileTree(dir: 'src/main/third-party/java/buck-android-support/', include: ['*.jar']) androidTestCompile 'com.android.support.test:runner:0.3' androidTestCompile "org.mockito:mockito-core:${MOCKITO_CORE_VERSION}" diff --git a/ReactAndroid/src/main/third-party/java/okio/BUCK b/ReactAndroid/src/main/third-party/java/okio/BUCK index 45955117a0379c..eef6fb6cc50b24 100644 --- a/ReactAndroid/src/main/third-party/java/okio/BUCK +++ b/ReactAndroid/src/main/third-party/java/okio/BUCK @@ -6,6 +6,6 @@ prebuilt_jar( remote_file( name = "okio-binary-jar", - sha1 = "a9283170b7305c8d92d25aff02a6ab7e45d06cbe", - url = "mvn:com.squareup.okio:okio:jar:1.13.0", + sha1 = "102d7be47241d781ef95f1581d414b0943053130", + url = "mvn:com.squareup.okio:okio:jar:1.14.0", ) From 9bdc31069addb9df468d551357724d9a2fc5f9b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Thu, 29 Mar 2018 11:29:09 -0700 Subject: [PATCH 0167/1109] Update Android Docker images Summary: yarn docker-build-android-base yarn docker-build-android [INTERNAL] [MINOR] [ContainerShip] - Bump versions in Dockerfiles Closes https://github.com/facebook/react-native/pull/18597 Differential Revision: D7433542 Pulled By: hramos fbshipit-source-id: 5ec7496c84203a0ed20ef3875ac3d367914a0e80 --- ContainerShip/Dockerfile.android | 11 +++++++---- ContainerShip/Dockerfile.android-base | 17 +++-------------- package.json | 14 +++++++------- 3 files changed, 17 insertions(+), 25 deletions(-) diff --git a/ContainerShip/Dockerfile.android b/ContainerShip/Dockerfile.android index adb361ab58f79c..f7a207aea3e557 100644 --- a/ContainerShip/Dockerfile.android +++ b/ContainerShip/Dockerfile.android @@ -9,6 +9,7 @@ ADD .buckconfig /app/.buckconfig ADD .buckjavaargs /app/.buckjavaargs ADD ReactAndroid /app/ReactAndroid ADD ReactCommon /app/ReactCommon +ADD ReactNative /app/ReactNative ADD keystores /app/keystores # set workdir @@ -41,10 +42,12 @@ RUN ./gradlew :ReactAndroid:packageReactNdkLibsForBuck -Pjobs=1 -Pcom.android.bu ADD . /app WORKDIR /app -# https://github.com/npm/npm/issues/13306 -RUN cd $(npm root -g)/npm && npm install fs-extra && sed -i -e s/graceful-fs/fs-extra/ -e s/fs.rename/fs.move/ ./lib/utils/rename.js - # build node dependencies -RUN npm install +RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - +RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list +RUN apt-get install apt-transport-https +RUN apt-get update +RUN apt-get install yarn +RUN yarn WORKDIR /app diff --git a/ContainerShip/Dockerfile.android-base b/ContainerShip/Dockerfile.android-base index 05caa480f3c827..93a1aafa811787 100644 --- a/ContainerShip/Dockerfile.android-base +++ b/ContainerShip/Dockerfile.android-base @@ -2,10 +2,10 @@ FROM library/ubuntu:16.04 # set default build arguments ARG ANDROID_TOOLS_VERSION=25.2.5 -ARG BUCK_VERSION=v2017.11.16.01 +ARG BUCK_VERSION=v2018.02.16.01 ARG NDK_VERSION=10e -ARG NODE_VERSION=6.2.0 -ARG WATCHMAN_VERSION=4.7.0 +ARG NODE_VERSION=8.10.0 +ARG WATCHMAN_VERSION=4.9.0 # set default environment variables ENV ADB_INSTALL_TIMEOUT=10 @@ -34,17 +34,6 @@ WORKDIR /opt/buck # build buck RUN ant -# download watchman -RUN git clone https://github.com/facebook/watchman.git /opt/watchman -WORKDIR /opt/watchman -RUN git checkout v$WATCHMAN_VERSION - -# build watchman -RUN ./autogen.sh -RUN ./configure -RUN make -RUN make install - # Full reference at https://dl.google.com/android/repository/repository2-1.xml # download and unpack android RUN mkdir /opt/android diff --git a/package.json b/package.json index 5c9215a2c22803..d15a462f15e1bf 100644 --- a/package.json +++ b/package.json @@ -127,16 +127,16 @@ "lint": "eslint .", "prettier": "find . -name node_modules -prune -or -name '*.js' -print | xargs prettier --write", "start": "/usr/bin/env bash -c './scripts/packager.sh \"$@\" || true' --", - "test-android-setup": "docker pull hramos/android-base:latest", - "test-android-build-base": "docker build -t hramos/android-base -f ContainerShip/Dockerfile.android-base .", - "test-android-build": "docker build -t react/android -f ContainerShip/Dockerfile.android .", + "docker-setup-android": "docker pull hramos/android-base:latest", + "docker-build-android-base": "docker build -t hramos/android-base -f ContainerShip/Dockerfile.android-base .", + "docker-build-android": "docker build -t react/android -f ContainerShip/Dockerfile.android .", "test-android-run-instrumentation": "docker run --cap-add=SYS_ADMIN -it react/android bash ContainerShip/scripts/run-android-docker-instrumentation-tests.sh", "test-android-run-unit": "docker run --cap-add=SYS_ADMIN -it react/android bash ContainerShip/scripts/run-android-docker-unit-tests.sh", "test-android-run-e2e": "docker run --privileged -it react/android bash ContainerShip/scripts/run-ci-e2e-tests.sh --android --js", - "test-android-all": "npm run test-android-build && npm run test-android-run-unit && npm run test-android-run-instrumentation && npm run test-android-run-e2e", - "test-android-instrumentation": "npm run test-android-build && npm run test-android-run-instrumentation", - "test-android-unit": "npm run test-android-build && npm run test-android-run-unit", - "test-android-e2e": "npm run test-android-build && npm run test-android-run-e2e" + "test-android-all": "yarn run docker-build-android && yarn run test-android-run-unit && yarn run test-android-run-instrumentation && yarn run test-android-run-e2e", + "test-android-instrumentation": "yarn run docker-build-android && yarn run test-android-run-instrumentation", + "test-android-unit": "yarn run docker-build-android && yarn run test-android-run-unit", + "test-android-e2e": "yarn run docker-build-android && yarn run test-android-run-e2e" }, "bin": { "react-native": "local-cli/wrong-react-native.js" From ee0c69dfa66de2a5dd320a85c6d9294f38733352 Mon Sep 17 00:00:00 2001 From: Ram N Date: Thu, 29 Mar 2018 16:05:10 -0700 Subject: [PATCH 0168/1109] Keep nativeIDs immutable in ReactFindViewUtil Reviewed By: mdvacca Differential Revision: D7430144 fbshipit-source-id: c8e8242c1c3216258e4b8c27623160338e2578d8 --- .../uimanager/util/ReactFindViewUtil.java | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/util/ReactFindViewUtil.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/util/ReactFindViewUtil.java index 1d0d41d82c8379..cd3104ae37264f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/util/ReactFindViewUtil.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/util/ReactFindViewUtil.java @@ -129,19 +129,11 @@ public static void notifyViewRendered(View view) { } } - Iterator>> - viewIterator = mOnMultipleViewsFoundListener.entrySet().iterator(); - while (viewIterator.hasNext()) { - Map.Entry> entry = - viewIterator.next(); - Set nativeIds = entry.getValue(); - if (nativeIds.contains(nativeId)) { - entry.getKey().onViewFound(view, nativeId); - nativeIds.remove(nativeId); // remove it from list of NativeIds to search for. - } - if (nativeIds.isEmpty()) { - viewIterator.remove(); - } + for (Map.Entry> entry : mOnMultipleViewsFoundListener.entrySet()) { + Set nativeIds = entry.getValue(); + if (nativeIds != null && nativeIds.contains(nativeId)) { + entry.getKey().onViewFound(view, nativeId); + } } } From 1020ac9481b5fedc2cc6aa31f757501f7ef556df Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Thu, 29 Mar 2018 20:59:47 -0700 Subject: [PATCH 0169/1109] OSS: add gradle wrapper helper to prepare offline gradle caches Summary: This is to help build offline module caches for gradle builds. allow-large-files Reviewed By: hramos Differential Revision: D7441450 fbshipit-source-id: 37ceb070223f0de06720f5c104ecfce2ad6cedfd --- ReactAndroid/build.gradle | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle index 25ba9d2c1b2816..fa1be07afa74a2 100644 --- a/ReactAndroid/build.gradle +++ b/ReactAndroid/build.gradle @@ -13,7 +13,8 @@ import org.apache.tools.ant.filters.ReplaceTokens // We then copy both the downloaded code and our custom makefiles and headers into third-party-ndk. // After that we build native code from src/main/jni with module path pointing at third-party-ndk. -def downloadsDir = new File("$buildDir/downloads") +def customDownloadsDir = System.getenv("REACT_NATIVE_DOWNLOADS_DIR") +def downloadsDir = customDownloadsDir ? new File(customDownloadsDir) : new File("$buildDir/downloads") def thirdPartyNdkDir = new File("$buildDir/third-party-ndk") // You need to have following folders in this directory: @@ -145,6 +146,16 @@ task prepareJSC(dependsOn: dependenciesPath ? [] : [downloadJSCHeaders]) << { } } +task downloadNdkBuildDependencies { + if (!boostPath) { + dependsOn downloadBoost + } + dependsOn downloadDoubleConversion + dependsOn downloadFolly + dependsOn downloadGlog + dependsOn downloadJSCHeaders +} + def getNdkBuildName() { if (Os.isFamily(Os.FAMILY_WINDOWS)) { return "ndk-build.cmd" From 550339c71b8d647cf63e6282a961caff9887f9d7 Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Thu, 29 Mar 2018 22:48:44 -0700 Subject: [PATCH 0170/1109] Add `JReadableByteChannel` Summary: Adds `JReadableByteChannel`, which maps to `java.nio.ReadableByteChannel`. This class is useful to stream data from Java to C++ memory (in conjunction with `JByteBuffer`). Differential Revision: D7437312 fbshipit-source-id: 4979706148f0e20228f0f52341fb340497c24a8b --- .../src/main/jni/first-party/fb/Android.mk | 1 + .../fb/include/fb/fbjni/ReadableByteChannel.h | 23 +++++++++++++++++++ .../fb/jni/ReadableByteChannel.cpp | 21 +++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/ReadableByteChannel.h create mode 100644 ReactAndroid/src/main/jni/first-party/fb/jni/ReadableByteChannel.cpp diff --git a/ReactAndroid/src/main/jni/first-party/fb/Android.mk b/ReactAndroid/src/main/jni/first-party/fb/Android.mk index aaf198bce73ff1..4540eef1d60210 100644 --- a/ReactAndroid/src/main/jni/first-party/fb/Android.mk +++ b/ReactAndroid/src/main/jni/first-party/fb/Android.mk @@ -13,6 +13,7 @@ LOCAL_SRC_FILES:= \ jni/jni_helpers.cpp \ jni/LocalString.cpp \ jni/OnLoad.cpp \ + jni/ReadableByteChannel.cpp \ jni/References.cpp \ jni/WeakReference.cpp \ log.cpp \ diff --git a/ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/ReadableByteChannel.h b/ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/ReadableByteChannel.h new file mode 100644 index 00000000000000..f895a3e6ff6573 --- /dev/null +++ b/ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/ReadableByteChannel.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2016-present, Facebook, Inc. + * + * 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 jni { + +class JReadableByteChannel : public JavaClass { +public: + static constexpr const char* kJavaDescriptor = "Ljava/nio/channels/ReadableByteChannel;"; + + int read(alias_ref dest) const; +}; + +}} diff --git a/ReactAndroid/src/main/jni/first-party/fb/jni/ReadableByteChannel.cpp b/ReactAndroid/src/main/jni/first-party/fb/jni/ReadableByteChannel.cpp new file mode 100644 index 00000000000000..9c67df3fa923a3 --- /dev/null +++ b/ReactAndroid/src/main/jni/first-party/fb/jni/ReadableByteChannel.cpp @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2016-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +namespace facebook { +namespace jni { + +int JReadableByteChannel::read(alias_ref dest) const { + if (!self()) { + throwNewJavaException("java/lang/NullPointerException", "java.lang.NullPointerException"); + } + static auto method = javaClassStatic()->getMethod)>("read"); + return method(self(), dest); +} + +}} From 1f27098a1aacea3d10a34738b3a5ff1ca9902743 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Fri, 30 Mar 2018 11:43:18 -0700 Subject: [PATCH 0171/1109] Fabric: Proper Yoga node dirting in YogaLayoutableShadowNode Summary: Any change must be propagate upwards. Reviewed By: mdvacca Differential Revision: D7389058 fbshipit-source-id: 09c74640d0e9607d2e17bdd31d7ce69df8565f72 --- ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp index 376f092367c968..d7974ae0fed360 100644 --- a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp +++ b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp @@ -215,7 +215,7 @@ void YogaLayoutableShadowNode::setYogaNodeChildrenBasedOnShadowNodeChildren(YGNo } yogaNode.setChildren(yogaNodeChildren); - yogaNode.setDirty(true); + yogaNode.markDirtyAndPropogate(); } } // namespace react From 4906f8d28cdbaf1b432494b473a4c61c1e193881 Mon Sep 17 00:00:00 2001 From: Vladislav Pilgasov Date: Fri, 30 Mar 2018 20:57:42 -0700 Subject: [PATCH 0172/1109] Add an implementation of Animated.subtract Summary: Fixes #18451 I've added another example to NativeAnimationsExample, which makes use of `Animated.substract()`, let me know if the example is not desired / doesn't add much value. Below two GIFs of the new method working on iOS and Android: https://github.com/facebook/react-native-website/pull/276 [GENERAL] [ENHANCEMENT] [Animated] - Implemented Animated.subtract Closes https://github.com/facebook/react-native/pull/18630 Differential Revision: D7462867 Pulled By: hramos fbshipit-source-id: 4cb0b8af08bb0c841e44ea2099889b8c02a22a4a --- .../Animated/src/AnimatedImplementation.js | 16 +++++ .../src/__tests__/AnimatedNative-test.js | 32 ++++++++++ .../Animated/src/nodes/AnimatedSubtraction.js | 63 +++++++++++++++++++ .../Nodes/RCTSubtractionAnimatedNode.h | 13 ++++ .../Nodes/RCTSubtractionAnimatedNode.m | 27 ++++++++ .../RCTAnimation.xcodeproj/project.pbxproj | 6 ++ .../RCTNativeAnimatedNodesManager.m | 2 + RNTester/js/NativeAnimationsExample.js | 42 +++++++++++++ .../animated/NativeAnimatedNodesManager.java | 2 + .../animated/SubtractionAnimatedNode.java | 51 +++++++++++++++ 10 files changed, 254 insertions(+) create mode 100644 Libraries/Animated/src/nodes/AnimatedSubtraction.js create mode 100644 Libraries/NativeAnimation/Nodes/RCTSubtractionAnimatedNode.h create mode 100644 Libraries/NativeAnimation/Nodes/RCTSubtractionAnimatedNode.m create mode 100644 ReactAndroid/src/main/java/com/facebook/react/animated/SubtractionAnimatedNode.java diff --git a/Libraries/Animated/src/AnimatedImplementation.js b/Libraries/Animated/src/AnimatedImplementation.js index e13aef1e723550..9291a7956531e3 100644 --- a/Libraries/Animated/src/AnimatedImplementation.js +++ b/Libraries/Animated/src/AnimatedImplementation.js @@ -20,6 +20,7 @@ const AnimatedModulo = require('./nodes/AnimatedModulo'); const AnimatedMultiplication = require('./nodes/AnimatedMultiplication'); const AnimatedNode = require('./nodes/AnimatedNode'); const AnimatedProps = require('./nodes/AnimatedProps'); +const AnimatedSubtraction = require('./nodes/AnimatedSubtraction'); const AnimatedTracking = require('./nodes/AnimatedTracking'); const AnimatedValue = require('./nodes/AnimatedValue'); const AnimatedValueXY = require('./nodes/AnimatedValueXY'); @@ -54,6 +55,13 @@ const add = function( return new AnimatedAddition(a, b); }; +const subtract = function( + a: AnimatedNode | number, + b: AnimatedNode | number, +): AnimatedSubtraction { + return new AnimatedSubtraction(a, b); +}; + const divide = function( a: AnimatedNode | number, b: AnimatedNode | number, @@ -568,6 +576,14 @@ module.exports = { */ add, + /** + * Creates a new Animated value composed by subtracting the second Animated + * value from the first Animated value. + * + * See http://facebook.github.io/react-native/docs/animated.html#subtract + */ + subtract, + /** * Creates a new Animated value composed by dividing the first Animated value * by the second Animated value. diff --git a/Libraries/Animated/src/__tests__/AnimatedNative-test.js b/Libraries/Animated/src/__tests__/AnimatedNative-test.js index 1c6700e4dc0652..f04d5afb1429a3 100644 --- a/Libraries/Animated/src/__tests__/AnimatedNative-test.js +++ b/Libraries/Animated/src/__tests__/AnimatedNative-test.js @@ -333,6 +333,38 @@ describe('Native Animated', () => { .toBeCalledWith(additionCall[1].input[1], {type: 'value', value: 2, offset: 0}); }); + it('sends a valid graph description for Animated.subtract nodes', () => { + const first = new Animated.Value(2); + const second = new Animated.Value(1); + first.__makeNative(); + second.__makeNative(); + + createAndMountComponent(Animated.View, { + style: { + opacity: Animated.subtract(first, second), + }, + }); + + expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith( + expect.any(Number), + {type: 'subtraction', input: expect.any(Array)}, + ); + const subtractionCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter( + (call) => call[1].type === 'subtraction' + ); + expect(subtractionCalls.length).toBe(1); + const subtractionCall = subtractionCalls[0]; + const subtractionNodeTag = subtractionCall[0]; + const subtractionConnectionCalls = nativeAnimatedModule.connectAnimatedNodes.mock.calls.filter( + (call) => call[1] === subtractionNodeTag + ); + expect(subtractionConnectionCalls.length).toBe(2); + expect(nativeAnimatedModule.createAnimatedNode) + .toBeCalledWith(subtractionCall[1].input[0], {type: 'value', value: 2, offset: 0}); + expect(nativeAnimatedModule.createAnimatedNode) + .toBeCalledWith(subtractionCall[1].input[1], {type: 'value', value: 1, offset: 0}); + }); + it('sends a valid graph description for Animated.multiply nodes', () => { const first = new Animated.Value(2); const second = new Animated.Value(1); diff --git a/Libraries/Animated/src/nodes/AnimatedSubtraction.js b/Libraries/Animated/src/nodes/AnimatedSubtraction.js new file mode 100644 index 00000000000000..610fc226eb65a8 --- /dev/null +++ b/Libraries/Animated/src/nodes/AnimatedSubtraction.js @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @providesModule AnimatedSubtraction + * @flow + * @format + */ +'use strict'; + +const AnimatedInterpolation = require('./AnimatedInterpolation'); +const AnimatedNode = require('./AnimatedNode'); +const AnimatedValue = require('./AnimatedValue'); +const AnimatedWithChildren = require('./AnimatedWithChildren'); + +import type {InterpolationConfigType} from './AnimatedInterpolation'; + +class AnimatedSubtraction extends AnimatedWithChildren { + _a: AnimatedNode; + _b: AnimatedNode; + + constructor(a: AnimatedNode | number, b: AnimatedNode | number) { + super(); + this._a = typeof a === 'number' ? new AnimatedValue(a) : a; + this._b = typeof b === 'number' ? new AnimatedValue(b) : b; + } + + __makeNative() { + this._a.__makeNative(); + this._b.__makeNative(); + super.__makeNative(); + } + + __getValue(): number { + return this._a.__getValue() - this._b.__getValue(); + } + + interpolate(config: InterpolationConfigType): AnimatedInterpolation { + return new AnimatedInterpolation(this, config); + } + + __attach(): void { + this._a.__addChild(this); + this._b.__addChild(this); + } + + __detach(): void { + this._a.__removeChild(this); + this._b.__removeChild(this); + super.__detach(); + } + + __getNativeConfig(): any { + return { + type: 'subtraction', + input: [this._a.__getNativeTag(), this._b.__getNativeTag()], + }; + } +} + +module.exports = AnimatedSubtraction; diff --git a/Libraries/NativeAnimation/Nodes/RCTSubtractionAnimatedNode.h b/Libraries/NativeAnimation/Nodes/RCTSubtractionAnimatedNode.h new file mode 100644 index 00000000000000..45524b69d02591 --- /dev/null +++ b/Libraries/NativeAnimation/Nodes/RCTSubtractionAnimatedNode.h @@ -0,0 +1,13 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTValueAnimatedNode.h" + +@interface RCTSubtractionAnimatedNode : RCTValueAnimatedNode + +@end + diff --git a/Libraries/NativeAnimation/Nodes/RCTSubtractionAnimatedNode.m b/Libraries/NativeAnimation/Nodes/RCTSubtractionAnimatedNode.m new file mode 100644 index 00000000000000..91688c9aec51a6 --- /dev/null +++ b/Libraries/NativeAnimation/Nodes/RCTSubtractionAnimatedNode.m @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTSubtractionAnimatedNode.h" + +@implementation RCTSubtractionAnimatedNode + +- (void)performUpdate +{ + [super performUpdate]; + NSArray *inputNodes = self.config[@"input"]; + if (inputNodes.count > 1) { + RCTValueAnimatedNode *parent1 = (RCTValueAnimatedNode *)[self.parentNodes objectForKey:inputNodes[0]]; + RCTValueAnimatedNode *parent2 = (RCTValueAnimatedNode *)[self.parentNodes objectForKey:inputNodes[1]]; + if ([parent1 isKindOfClass:[RCTValueAnimatedNode class]] && + [parent2 isKindOfClass:[RCTValueAnimatedNode class]]) { + self.value = parent1.value - parent2.value; + } + } +} + +@end + diff --git a/Libraries/NativeAnimation/RCTAnimation.xcodeproj/project.pbxproj b/Libraries/NativeAnimation/RCTAnimation.xcodeproj/project.pbxproj index 0ba2446271568a..08a629eaeccac2 100644 --- a/Libraries/NativeAnimation/RCTAnimation.xcodeproj/project.pbxproj +++ b/Libraries/NativeAnimation/RCTAnimation.xcodeproj/project.pbxproj @@ -111,6 +111,7 @@ 2D3B5EFE1D9B0B4800451313 /* RCTStyleAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501E31D07A6C9005F35D8 /* RCTStyleAnimatedNode.m */; }; 2D3B5EFF1D9B0B4800451313 /* RCTTransformAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501E51D07A6C9005F35D8 /* RCTTransformAnimatedNode.m */; }; 2D3B5F001D9B0B4800451313 /* RCTValueAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501E71D07A6C9005F35D8 /* RCTValueAnimatedNode.m */; }; + 2EC00631206EA19300586E91 /* RCTSubtractionAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 2EC00630206EA19300586E91 /* RCTSubtractionAnimatedNode.m */; }; 44DB7D942024F74200588FCD /* RCTTrackingAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 44DB7D932024F74200588FCD /* RCTTrackingAnimatedNode.h */; }; 44DB7D952024F74200588FCD /* RCTTrackingAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 44DB7D932024F74200588FCD /* RCTTrackingAnimatedNode.h */; }; 44DB7D972024F75100588FCD /* RCTTrackingAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 44DB7D962024F75100588FCD /* RCTTrackingAnimatedNode.m */; }; @@ -213,6 +214,8 @@ 19F00F201DC8847500113FEE /* RCTEventAnimation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTEventAnimation.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 19F00F211DC8847500113FEE /* RCTEventAnimation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTEventAnimation.m; sourceTree = ""; }; 2D2A28201D9B03D100D4039D /* libRCTAnimation.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTAnimation.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 2EC0062F206EA15F00586E91 /* RCTSubtractionAnimatedNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTSubtractionAnimatedNode.h; sourceTree = ""; }; + 2EC00630206EA19300586E91 /* RCTSubtractionAnimatedNode.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCTSubtractionAnimatedNode.m; sourceTree = ""; }; 44DB7D932024F74200588FCD /* RCTTrackingAnimatedNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTTrackingAnimatedNode.h; sourceTree = ""; }; 44DB7D962024F75100588FCD /* RCTTrackingAnimatedNode.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCTTrackingAnimatedNode.m; sourceTree = ""; }; 5C9894931D999639008027DB /* RCTDivisionAnimatedNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTDivisionAnimatedNode.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; @@ -246,6 +249,8 @@ 193F64F31D776EC6004D1CAA /* RCTDiffClampAnimatedNode.m */, 13E501D61D07A6C9005F35D8 /* RCTAdditionAnimatedNode.h */, 13E501D71D07A6C9005F35D8 /* RCTAdditionAnimatedNode.m */, + 2EC0062F206EA15F00586E91 /* RCTSubtractionAnimatedNode.h */, + 2EC00630206EA19300586E91 /* RCTSubtractionAnimatedNode.m */, 13E501D81D07A6C9005F35D8 /* RCTAnimatedNode.h */, 13E501D91D07A6C9005F35D8 /* RCTAnimatedNode.m */, 13E501DC1D07A6C9005F35D8 /* RCTInterpolationAnimatedNode.h */, @@ -483,6 +488,7 @@ 5C9894951D999639008027DB /* RCTDivisionAnimatedNode.m in Sources */, 13E501EF1D07A6C9005F35D8 /* RCTTransformAnimatedNode.m in Sources */, 194804EE1E975D8E00623005 /* RCTDecayAnimation.m in Sources */, + 2EC00631206EA19300586E91 /* RCTSubtractionAnimatedNode.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Libraries/NativeAnimation/RCTNativeAnimatedNodesManager.m b/Libraries/NativeAnimation/RCTNativeAnimatedNodesManager.m index e05286decf9eb2..e649020d5f301f 100644 --- a/Libraries/NativeAnimation/RCTNativeAnimatedNodesManager.m +++ b/Libraries/NativeAnimation/RCTNativeAnimatedNodesManager.m @@ -23,6 +23,7 @@ #import "RCTPropsAnimatedNode.h" #import "RCTSpringAnimation.h" #import "RCTStyleAnimatedNode.h" +#import "RCTSubtractionAnimatedNode.h" #import "RCTTransformAnimatedNode.h" #import "RCTValueAnimatedNode.h" #import "RCTTrackingAnimatedNode.h" @@ -66,6 +67,7 @@ - (void)createAnimatedNode:(nonnull NSNumber *)tag @"division" : [RCTDivisionAnimatedNode class], @"multiplication" : [RCTMultiplicationAnimatedNode class], @"modulus" : [RCTModuloAnimatedNode class], + @"subtraction" : [RCTSubtractionAnimatedNode class], @"transform" : [RCTTransformAnimatedNode class], @"tracking" : [RCTTrackingAnimatedNode class]}; }); diff --git a/RNTester/js/NativeAnimationsExample.js b/RNTester/js/NativeAnimationsExample.js index 983b0c9d290fe0..5a6e5df55e84e2 100644 --- a/RNTester/js/NativeAnimationsExample.js +++ b/RNTester/js/NativeAnimationsExample.js @@ -429,6 +429,48 @@ exports.examples = [ ); }, }, + { + title: 'Multistage With Subtract', + render: function() { + return ( + + {anim => ( + + )} + + ); + }, + }, { title: 'Scale interpolation with clamping', render: function() { diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedNodesManager.java b/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedNodesManager.java index 1fad4e52d3cd4f..07357fd7eea998 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedNodesManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedNodesManager.java @@ -93,6 +93,8 @@ public void createAnimatedNode(int tag, ReadableMap config) { node = new InterpolationAnimatedNode(config); } else if ("addition".equals(type)) { node = new AdditionAnimatedNode(config, this); + } else if ("subtraction".equals(type)) { + node = new SubtractionAnimatedNode(config, this); } else if ("division".equals(type)) { node = new DivisionAnimatedNode(config, this); } else if ("multiplication".equals(type)) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/SubtractionAnimatedNode.java b/ReactAndroid/src/main/java/com/facebook/react/animated/SubtractionAnimatedNode.java new file mode 100644 index 00000000000000..4a8ecd8ce736a7 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/animated/SubtractionAnimatedNode.java @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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.animated; + +import com.facebook.react.bridge.JSApplicationCausedNativeException; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.bridge.ReadableMap; + +/** + * Animated node that plays a role of value aggregator. It takes two or more value nodes as an input + * and outputs a difference of values outputted by those nodes. + */ +/*package*/ class SubtractionAnimatedNode extends ValueAnimatedNode { + + private final NativeAnimatedNodesManager mNativeAnimatedNodesManager; + private final int[] mInputNodes; + + public SubtractionAnimatedNode( + ReadableMap config, + NativeAnimatedNodesManager nativeAnimatedNodesManager) { + mNativeAnimatedNodesManager = nativeAnimatedNodesManager; + ReadableArray inputNodes = config.getArray("input"); + mInputNodes = new int[inputNodes.size()]; + for (int i = 0; i < mInputNodes.length; i++) { + mInputNodes[i] = inputNodes.getInt(i); + } + } + + @Override + public void update() { + for (int i = 0; i < mInputNodes.length; i++) { + AnimatedNode animatedNode = mNativeAnimatedNodesManager.getNodeById(mInputNodes[i]); + if (animatedNode != null && animatedNode instanceof ValueAnimatedNode) { + double value = ((ValueAnimatedNode) animatedNode).getValue(); + if (i == 0) { + mValue = value; + continue; + } + mValue -= ((ValueAnimatedNode) animatedNode).getValue(); + } else { + throw new JSApplicationCausedNativeException("Illegal node ID set as an input for " + + "Animated.subtract node"); + } + } + } +} From d58ba8242b02b58ae2ac2c59fe3082d259c8c4db Mon Sep 17 00:00:00 2001 From: David Vacca Date: Sat, 31 Mar 2018 23:20:52 -0700 Subject: [PATCH 0173/1109] Avoid app crashing when a StackOverflowError is thrown when rendering deep RN view hierarcy Reviewed By: achen1 Differential Revision: D7400906 fbshipit-source-id: faaf701a88440f89390518f00e6a35f19e9203db --- .../com/facebook/react/views/view/ReactViewGroup.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java index 3641d120dab333..1915b6eb48fb26 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java @@ -21,6 +21,7 @@ import android.view.ViewGroup; import android.view.animation.Animation; import com.facebook.infer.annotation.Assertions; +import com.facebook.react.bridge.ReactContext; import com.facebook.react.common.annotations.VisibleForTesting; import com.facebook.react.modules.i18nmanager.I18nUtil; import com.facebook.react.touch.OnInterceptTouchEventListener; @@ -668,7 +669,12 @@ protected void dispatchDraw(Canvas canvas) { if (rootView != null) { rootView.handleException(e); } else { - throw e; + if (getContext() instanceof ReactContext) { + ReactContext reactContext = (ReactContext) getContext(); + reactContext.handleException(new IllegalViewOperationException("StackOverflowException", this, e)); + } else { + throw e; + } } } } From aff5a75d8ee1e1ffe12406c1c0d741832455a6a3 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Sun, 1 Apr 2018 18:27:04 -0700 Subject: [PATCH 0174/1109] Refactor cloning of YogaNode Reviewed By: priteshrnandgaonkar Differential Revision: D7339832 fbshipit-source-id: 2de6f47ae7601ac083d3b9fbe10ffaf6307ae760 --- .../react/uimanager/ReactShadowNodeImpl.java | 25 +++++---- .../java/com/facebook/yoga/YogaConfig.java | 15 +++--- .../main/java/com/facebook/yoga/YogaNode.java | 14 +++++ ...nction.java => YogaNodeCloneFunction.java} | 4 +- .../jni/first-party/yogajni/jni/YGJNI.cpp | 54 +++++++++++-------- .../view/yoga/YogaLayoutableShadowNode.cpp | 2 +- ReactCommon/yoga/yoga/YGNode.cpp | 13 +++-- ReactCommon/yoga/yoga/Yoga-internal.h | 2 +- ReactCommon/yoga/yoga/Yoga.cpp | 16 +++--- ReactCommon/yoga/yoga/Yoga.h | 7 ++- 10 files changed, 94 insertions(+), 58 deletions(-) rename ReactAndroid/src/main/java/com/facebook/yoga/{YogaNodeClonedFunction.java => YogaNodeCloneFunction.java} (69%) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java index e6b4a901227120..ebf8e6ae639315 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java @@ -10,6 +10,7 @@ import com.facebook.infer.annotation.Assertions; import com.facebook.react.uimanager.annotations.ReactPropertyHolder; +import com.facebook.yoga.YogaNodeCloneFunction; import com.facebook.yoga.YogaAlign; import com.facebook.yoga.YogaBaselineFunction; import com.facebook.yoga.YogaConfig; @@ -21,7 +22,6 @@ import com.facebook.yoga.YogaJustify; import com.facebook.yoga.YogaMeasureFunction; import com.facebook.yoga.YogaNode; -import com.facebook.yoga.YogaNodeClonedFunction; import com.facebook.yoga.YogaOverflow; import com.facebook.yoga.YogaPositionType; import com.facebook.yoga.YogaValue; @@ -61,17 +61,19 @@ public class ReactShadowNodeImpl implements ReactShadowNode private static final YogaConfig sYogaConfig; static { sYogaConfig = ReactYogaConfigProvider.get(); - sYogaConfig.setOnNodeCloned(new YogaNodeClonedFunction() { + sYogaConfig.setOnCloneNode(new YogaNodeCloneFunction() { @Override - public void onNodeCloned(YogaNode oldYogaNode, - YogaNode newYogaNode, + public YogaNode cloneNode(YogaNode oldYogaNode, YogaNode parent, int childIndex) { - ReactShadowNode parentReactShadowNode = (ReactShadowNode) parent.getData(); + ReactShadowNodeImpl parentReactShadowNode = (ReactShadowNodeImpl) parent.getData(); Assertions.assertNotNull(parentReactShadowNode); - - ReactShadowNode newReactShadowNode = (ReactShadowNode) newYogaNode.getData(); + ReactShadowNodeImpl newReactShadowNode = (ReactShadowNodeImpl) oldYogaNode.getData(); Assertions.assertNotNull(newReactShadowNode); + + ReactShadowNodeImpl newNode = newReactShadowNode.mutableCopy(); + parentReactShadowNode.replaceChild(newNode, childIndex); + return newNode.mYogaNode; } }); } @@ -133,6 +135,11 @@ protected ReactShadowNodeImpl(ReactShadowNodeImpl original) { mOriginalReactShadowNode = original; } + private void replaceChild(ReactShadowNodeImpl newNode, int childIndex) { + mChildren.remove(childIndex); + mChildren.add(childIndex, newNode); + } + /** * @return a copy of this object (no including copy of its children or the underlying yogaNode). */ @@ -145,7 +152,7 @@ public ReactShadowNodeImpl mutableCopy() { ReactShadowNodeImpl copy = copy(); copy.mYogaNode = mYogaNode; // TODO: T26729293 clone YogaNode instead of reusing the same instance - //mYogaNode = original.mYogaNode.clone(); + //copy.mYogaNode = mYogaNode.clone(); copy.mNativeChildren = mNativeChildren == null ? null : new ArrayList<>(mNativeChildren); copy.mTotalNativeChildren = mTotalNativeChildren; copy.mChildren = mChildren == null ? null : new ArrayList<>(mChildren); @@ -165,7 +172,7 @@ public ReactShadowNodeImpl mutableCopyWithNewChildren() { ReactShadowNodeImpl copy = copy(); copy.mYogaNode = mYogaNode; // TODO: T26729293 clone YogaNode instead of reusing the same instance - //mYogaNode = original.mYogaNode.cloneWithNewChildren(); + //copy.mYogaNode = mYogaNode.clone(); copy.mNativeChildren = null; copy.mChildren = null; copy.mTotalNativeChildren = 0; diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfig.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfig.java index 2d90eec9de9dca..ebb64aaff5a88b 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfig.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfig.java @@ -25,7 +25,7 @@ public class YogaConfig { long mNativePointer; private YogaLogger mLogger; - private YogaNodeClonedFunction mNodeClonedFunction; + private YogaNodeCloneFunction mYogaNodeCloneFunction; private native long jni_YGConfigNew(); public YogaConfig() { @@ -97,16 +97,15 @@ public YogaLogger getLogger() { return mLogger; } - private native void jni_YGConfigSetHasNodeClonedFunc(long nativePointer, boolean hasClonedFunc); + private native void jni_YGConfigSetHasCloneNodeFunc(long nativePointer, boolean hasClonedFunc); - public void setOnNodeCloned(YogaNodeClonedFunction nodeClonedFunction) { - mNodeClonedFunction = nodeClonedFunction; - jni_YGConfigSetHasNodeClonedFunc(mNativePointer, nodeClonedFunction != null); + public void setOnCloneNode(YogaNodeCloneFunction cloneYogaNodeFunction) { + mYogaNodeCloneFunction = cloneYogaNodeFunction; + jni_YGConfigSetHasCloneNodeFunc(mNativePointer, cloneYogaNodeFunction != null); } @DoNotStrip - public final void onNodeCloned( - YogaNode oldNode, YogaNode newNode, YogaNode parent, int childIndex) { - mNodeClonedFunction.onNodeCloned(oldNode, newNode, parent, childIndex); + private final YogaNode cloneNode(YogaNode oldNode, YogaNode parent, int childIndex) { + return mYogaNodeCloneFunction.cloneNode(oldNode, parent, childIndex); } } diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java index 1c6e67a55eb9e5..577ee3fb05cd88 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java @@ -697,4 +697,18 @@ public Object getData() { public void print() { jni_YGNodePrint(mNativePointer); } + + /** + * This method replaces the child at childIndex position with the newNode received by parameter. + * This is different than calling removeChildAt and addChildAt because this method ONLY replaces + * the child in the mChildren datastructure. @DoNotStrip: called from JNI + * + * @return the nativePointer of the newNode {@linl YogaNode} + */ + @DoNotStrip + private final long replaceChild(YogaNode newNode, int childIndex) { + mChildren.remove(childIndex); + mChildren.add(childIndex, newNode); + return newNode.mNativePointer; + } } diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeClonedFunction.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeCloneFunction.java similarity index 69% rename from ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeClonedFunction.java rename to ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeCloneFunction.java index f469546495f855..0733776a7e3761 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeClonedFunction.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeCloneFunction.java @@ -10,8 +10,8 @@ import com.facebook.proguard.annotations.DoNotStrip; @DoNotStrip -public interface YogaNodeClonedFunction { +public interface YogaNodeCloneFunction { @DoNotStrip - void onNodeCloned(YogaNode oldNode, YogaNode newNode, YogaNode parent, int childIndex); + YogaNode cloneNode(YogaNode oldNode, YogaNode parent, int childIndex); } 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 cc75df96a15131..7f92ba8e06df86 100644 --- a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp +++ b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp @@ -142,31 +142,49 @@ static float YGJNIBaselineFunc(YGNodeRef node, float width, float height) { } } -static void YGJNIOnNodeClonedFunc( +static inline YGNodeRef _jlong2YGNodeRef(jlong addr) { + return reinterpret_cast(static_cast(addr)); +} + +static inline YGConfigRef _jlong2YGConfigRef(jlong addr) { + return reinterpret_cast(static_cast(addr)); +} + +static YGNodeRef YGJNIOnNodeClonedFunc( YGNodeRef oldNode, - YGNodeRef newNode, YGNodeRef parent, int childIndex) { auto config = oldNode->getConfig(); if (!config) { - return; + return nullptr; } + static auto onNodeClonedFunc = findClassStatic("com/facebook/yoga/YogaConfig") - ->getMethodgetMethod( local_ref, local_ref, - local_ref, - jint)>("onNodeCloned"); + jint)>("cloneNode"); auto context = reinterpret_cast(YGConfigGetContext(config)); auto javaConfig = context->config; - onNodeClonedFunc( + auto newNode = onNodeClonedFunc( javaConfig->get(), YGNodeJobject(oldNode)->lockLocal(), - YGNodeJobject(newNode)->lockLocal(), YGNodeJobject(parent)->lockLocal(), childIndex); + + static auto replaceChild = findClassStatic("com/facebook/yoga/YogaNode") + ->getMethod, + jint)>("replaceChild"); + + jlong newNodeNativePointer = replaceChild( + YGNodeJobject(parent)->lockLocal(), + newNode, + childIndex); + + return _jlong2YGNodeRef(newNodeNativePointer); } static YGSize YGJNIMeasureFunc( @@ -234,14 +252,6 @@ static int YGJNILogFunc(const YGConfigRef config, return result; } -static inline YGNodeRef _jlong2YGNodeRef(jlong addr) { - return reinterpret_cast(static_cast(addr)); -} - -static inline YGConfigRef _jlong2YGConfigRef(jlong addr) { - return reinterpret_cast(static_cast(addr)); -} - jlong jni_YGNodeNew(alias_ref thiz) { const YGNodeRef node = YGNodeNew(); node->setContext(new weak_ref(make_weak(thiz))); @@ -506,10 +516,10 @@ void jni_YGConfigSetUseLegacyStretchBehaviour(alias_ref, YGConfigSetUseLegacyStretchBehaviour(config, useLegacyStretchBehaviour); } -void jni_YGConfigSetHasNodeClonedFunc( +void jni_YGConfigSetHasCloneNodeFunc( alias_ref thiz, jlong nativePointer, - jboolean hasNodeClonedFunc) { + jboolean hasCloneNodeFunc) { const YGConfigRef config = _jlong2YGConfigRef(nativePointer); auto context = reinterpret_cast(YGConfigGetContext(config)); if (context && context->config) { @@ -517,15 +527,15 @@ void jni_YGConfigSetHasNodeClonedFunc( context->config = nullptr; } - if (hasNodeClonedFunc) { + if (hasCloneNodeFunc) { if (!context) { context = new YGConfigContext(); YGConfigSetContext(config, context); } context->config = new global_ref(make_global(thiz)); - YGConfigSetNodeClonedFunc(config, YGJNIOnNodeClonedFunc); + YGConfigSetCloneNodeFunc(config, YGJNIOnNodeClonedFunc); } else { - YGConfigSetNodeClonedFunc(config, nullptr); + YGConfigSetCloneNodeFunc(config, nullptr); } } @@ -652,7 +662,7 @@ jint JNI_OnLoad(JavaVM *vm, void *) { YGMakeNativeMethod(jni_YGConfigSetPointScaleFactor), YGMakeNativeMethod(jni_YGConfigSetUseLegacyStretchBehaviour), YGMakeNativeMethod(jni_YGConfigSetLogger), - YGMakeNativeMethod(jni_YGConfigSetHasNodeClonedFunc), + YGMakeNativeMethod(jni_YGConfigSetHasCloneNodeFunc), YGMakeNativeMethod( jni_YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour), }); diff --git a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp index d7974ae0fed360..60586c9249e551 100644 --- a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp +++ b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp @@ -24,7 +24,7 @@ SharedYogaConfig YogaLayoutableShadowNode::suitableYogaConfig() { if (!sharedYogaConfig) { sharedYogaConfig = std::make_shared(YGConfig({ - .cloneNodeCallback = YogaLayoutableShadowNode::yogaNodeCloneCallbackConnector + // .cloneNodeCallback = YogaLayoutableShadowNode::yogaNodeCloneCallbackConnector })); } diff --git a/ReactCommon/yoga/yoga/YGNode.cpp b/ReactCommon/yoga/yoga/YGNode.cpp index 8fcb44c39dcbb4..f15105f26fe9d5 100644 --- a/ReactCommon/yoga/yoga/YGNode.cpp +++ b/ReactCommon/yoga/yoga/YGNode.cpp @@ -558,15 +558,18 @@ void YGNode::cloneChildrenIfNeeded() { return; } - const YGNodeClonedFunc cloneNodeCallback = config_->cloneNodeCallback; + const YGCloneNodeFunc cloneNodeCallback = config_->cloneNodeCallback; for (uint32_t i = 0; i < childCount; ++i) { const YGNodeRef oldChild = children_[i]; - const YGNodeRef newChild = YGNodeClone(oldChild); - replaceChild(newChild, i); - newChild->setParent(this); + YGNodeRef newChild = nullptr; if (cloneNodeCallback) { - cloneNodeCallback(oldChild, newChild, this, i); + newChild = cloneNodeCallback(oldChild, this, i); + } + if (newChild == nullptr) { + newChild = YGNodeClone(oldChild); } + replaceChild(newChild, i); + newChild->setParent(this); } } diff --git a/ReactCommon/yoga/yoga/Yoga-internal.h b/ReactCommon/yoga/yoga/Yoga-internal.h index 56078d6c3f06bc..d11f8c29d938c5 100644 --- a/ReactCommon/yoga/yoga/Yoga-internal.h +++ b/ReactCommon/yoga/yoga/Yoga-internal.h @@ -94,7 +94,7 @@ struct YGConfig { bool shouldDiffLayoutWithoutLegacyStretchBehaviour; float pointScaleFactor; YGLogger logger; - YGNodeClonedFunc cloneNodeCallback; + YGCloneNodeFunc cloneNodeCallback; void* context; }; diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index 1600b1b05fa0b4..b597727bc4cee7 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -428,7 +428,7 @@ void YGNodeRemoveChild(const YGNodeRef parent, const YGNodeRef excludedChild) { // Otherwise we have to clone the node list except for the child we're trying to delete. // We don't want to simply clone all children, because then the host will need to free // the clone of the child that was just deleted. - const YGNodeClonedFunc cloneNodeCallback = + const YGCloneNodeFunc cloneNodeCallback = parent->getConfig()->cloneNodeCallback; uint32_t nextInsertIndex = 0; for (uint32_t i = 0; i < childCount; i++) { @@ -440,12 +440,16 @@ void YGNodeRemoveChild(const YGNodeRef parent, const YGNodeRef excludedChild) { parent->markDirtyAndPropogate(); continue; } - const YGNodeRef newChild = YGNodeClone(oldChild); - parent->replaceChild(newChild, nextInsertIndex); - newChild->setParent(parent); + YGNodeRef newChild = nullptr; if (cloneNodeCallback) { - cloneNodeCallback(oldChild, newChild, parent, nextInsertIndex); + newChild = cloneNodeCallback(oldChild, parent, nextInsertIndex); + } + if (newChild == nullptr) { + newChild = YGNodeClone(oldChild); } + parent->replaceChild(newChild, nextInsertIndex); + newChild->setParent(parent); + nextInsertIndex++; } while (nextInsertIndex < childCount) { @@ -3964,7 +3968,7 @@ void *YGConfigGetContext(const YGConfigRef config) { return config->context; } -void YGConfigSetNodeClonedFunc(const YGConfigRef config, const YGNodeClonedFunc callback) { +void YGConfigSetCloneNodeFunc(const YGConfigRef config, const YGCloneNodeFunc callback) { config->cloneNodeCallback = callback; } diff --git a/ReactCommon/yoga/yoga/Yoga.h b/ReactCommon/yoga/yoga/Yoga.h index 1a985fa56317d9..73e7c7fdb1a28e 100644 --- a/ReactCommon/yoga/yoga/Yoga.h +++ b/ReactCommon/yoga/yoga/Yoga.h @@ -62,8 +62,7 @@ typedef int (*YGLogger)(const YGConfigRef config, YGLogLevel level, const char *format, va_list args); -typedef void (*YGNodeClonedFunc)(YGNodeRef oldNode, - YGNodeRef newNode, +typedef YGNodeRef (*YGCloneNodeFunc)(YGNodeRef oldNode, YGNodeRef parent, int childIndex); @@ -283,8 +282,8 @@ WIN_EXPORT bool YGConfigIsExperimentalFeatureEnabled(const YGConfigRef config, WIN_EXPORT void YGConfigSetUseWebDefaults(const YGConfigRef config, const bool enabled); WIN_EXPORT bool YGConfigGetUseWebDefaults(const YGConfigRef config); -WIN_EXPORT void YGConfigSetNodeClonedFunc(const YGConfigRef config, - const YGNodeClonedFunc callback); +WIN_EXPORT void YGConfigSetCloneNodeFunc(const YGConfigRef config, + const YGCloneNodeFunc callback); // Export only for C# WIN_EXPORT YGConfigRef YGConfigGetDefault(void); From 29ff30c539469bf2928fe90bdc31d1c3b2c19356 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Sun, 1 Apr 2018 18:27:06 -0700 Subject: [PATCH 0175/1109] Rename YogaNode.parent -> YogaNode.owner Reviewed By: priteshrnandgaonkar Differential Revision: D7352778 fbshipit-source-id: dcf1af5e72bfc3063b5c4bda197d7952a9194768 --- .../react/uimanager/ReactShadowNodeImpl.java | 2 +- .../main/java/com/facebook/yoga/YogaNode.java | 20 +- .../jni/first-party/yogajni/jni/YGJNI.cpp | 6 +- .../view/yoga/YogaLayoutableShadowNode.cpp | 2 +- ReactCommon/yoga/yoga/Utils.h | 10 +- ReactCommon/yoga/yoga/YGLayout.cpp | 4 +- ReactCommon/yoga/yoga/YGLayout.h | 2 +- ReactCommon/yoga/yoga/YGNode.cpp | 54 +-- ReactCommon/yoga/yoga/YGNode.h | 19 +- ReactCommon/yoga/yoga/Yoga.cpp | 458 +++++++++--------- ReactCommon/yoga/yoga/Yoga.h | 4 +- 11 files changed, 297 insertions(+), 284 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java index ebf8e6ae639315..53a27c440b76ec 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java @@ -301,7 +301,7 @@ public void addChildAt(ReactShadowNodeImpl child, int i) { + "')"); } // TODO: T26729293 This is a temporary code that will be replaced as part of T26729293. - YogaNode parent = childYogaNode.getParent(); + YogaNode parent = childYogaNode.getOwner(); if (parent != null) { for (int k = 0; k < parent.getChildCount(); k++) { if (parent.getChildAt(k) == childYogaNode) { diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java index 577ee3fb05cd88..ae5165e6384485 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java @@ -29,7 +29,7 @@ public class YogaNode implements Cloneable { */ static native int jni_YGNodeGetInstanceCount(); - private YogaNode mParent; + private YogaNode mOwner; private List mChildren; private YogaMeasureFunction mMeasureFunction; private YogaBaselineFunction mBaselineFunction; @@ -152,7 +152,7 @@ public YogaNode getChildAt(int i) { private native void jni_YGNodeInsertChild(long nativePointer, long childPointer, int index); public void addChildAt(YogaNode child, int i) { - if (child.mParent != null) { + if (child.mOwner != null) { throw new IllegalStateException("Child already has a parent, it must be removed first."); } @@ -160,7 +160,7 @@ public void addChildAt(YogaNode child, int i) { mChildren = new ArrayList<>(4); } mChildren.add(i, child); - child.mParent = this; + child.mOwner = this; jni_YGNodeInsertChild(mNativePointer, child.mNativePointer, i); } @@ -180,15 +180,23 @@ public YogaNode clone() throws CloneNotSupportedException { public YogaNode removeChildAt(int i) { final YogaNode child = mChildren.remove(i); - child.mParent = null; + child.mOwner = null; jni_YGNodeRemoveChild(mNativePointer, child.mNativePointer); return child; } + /** + * @returns the {@link YogaNode} that owns this {@link YogaNode}. + * The owner is used to identify the YogaTree that a {@link YogaNode} belongs + * to. + * This method will return the parent of the {@link YogaNode} when the + * {@link YogaNode} only belongs to one YogaTree or null when the + * {@link YogaNode} is shared between two or more YogaTrees. + */ @Nullable public - YogaNode getParent() { - return mParent; + YogaNode getOwner() { + return mOwner; } public int indexOf(YogaNode child) { 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 7f92ba8e06df86..b303ce223a92ff 100644 --- a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp +++ b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp @@ -152,7 +152,7 @@ static inline YGConfigRef _jlong2YGConfigRef(jlong addr) { static YGNodeRef YGJNIOnNodeClonedFunc( YGNodeRef oldNode, - YGNodeRef parent, + YGNodeRef owner, int childIndex) { auto config = oldNode->getConfig(); if (!config) { @@ -171,7 +171,7 @@ static YGNodeRef YGJNIOnNodeClonedFunc( auto newNode = onNodeClonedFunc( javaConfig->get(), YGNodeJobject(oldNode)->lockLocal(), - YGNodeJobject(parent)->lockLocal(), + YGNodeJobject(owner)->lockLocal(), childIndex); static auto replaceChild = findClassStatic("com/facebook/yoga/YogaNode") @@ -180,7 +180,7 @@ static YGNodeRef YGJNIOnNodeClonedFunc( jint)>("replaceChild"); jlong newNodeNativePointer = replaceChild( - YGNodeJobject(parent)->lockLocal(), + YGNodeJobject(owner)->lockLocal(), newNode, childIndex); diff --git a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp index 60586c9249e551..6ad453100e8f0e 100644 --- a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp +++ b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp @@ -54,7 +54,7 @@ YogaLayoutableShadowNode::YogaLayoutableShadowNode( ) { auto yogaNode = std::make_shared(*shadowNode->yogaNode_); yogaNode->setContext(this); - yogaNode->setParent(nullptr); + yogaNode->setOwner(nullptr); if (props) { yogaNode->setStyle(props->getYogaStyle()); diff --git a/ReactCommon/yoga/yoga/Utils.h b/ReactCommon/yoga/yoga/Utils.h index 7190fd7ff2495c..34284d2c3513a1 100644 --- a/ReactCommon/yoga/yoga/Utils.h +++ b/ReactCommon/yoga/yoga/Utils.h @@ -45,7 +45,7 @@ struct YGCollectFlexItemsRowValues { float remainingFreeSpace; // The size of the mainDim for the row after considering size, padding, margin // and border of flex items. This is used to calculate maxLineDim after going - // through all the rows to decide on the main axis size of parent. + // through all the rows to decide on the main axis size of owner. float mainDim; // The size of the crossDim for the row after considering size, padding, // margin and border of flex items. Used for calculating containers crossSize. @@ -109,7 +109,7 @@ inline bool YGFlexDirectionIsRow(const YGFlexDirection flexDirection) { flexDirection == YGFlexDirectionRowReverse; } -inline YGFloatOptional YGResolveValue(const YGValue value, const float parentSize) { +inline YGFloatOptional YGResolveValue(const YGValue value, const float ownerSize) { switch (value.unit) { case YGUnitUndefined: case YGUnitAuto: @@ -118,7 +118,7 @@ inline YGFloatOptional YGResolveValue(const YGValue value, const float parentSiz return YGFloatOptional(value.value); case YGUnitPercent: return YGFloatOptional( - static_cast(value.value * parentSize * 0.01)); + static_cast(value.value * ownerSize * 0.01)); } return YGFloatOptional(); } @@ -144,6 +144,6 @@ inline YGFlexDirection YGResolveFlexDirection( static inline float YGResolveValueMargin( const YGValue value, - const float parentSize) { - return value.unit == YGUnitAuto ? 0 : YGUnwrapFloatOptional(YGResolveValue(value, parentSize)); + const float ownerSize) { + return value.unit == YGUnitAuto ? 0 : YGUnwrapFloatOptional(YGResolveValue(value, ownerSize)); } diff --git a/ReactCommon/yoga/yoga/YGLayout.cpp b/ReactCommon/yoga/yoga/YGLayout.cpp index 4d798476ab18f6..117638d7a15f0c 100644 --- a/ReactCommon/yoga/yoga/YGLayout.cpp +++ b/ReactCommon/yoga/yoga/YGLayout.cpp @@ -22,7 +22,7 @@ YGLayout::YGLayout() computedFlexBasis(YGUndefined), hadOverflow(false), generationCount(0), - lastParentDirection((YGDirection)-1), + lastOwnerDirection((YGDirection)-1), nextCachedMeasurementsIndex(0), cachedMeasurements(), measuredDimensions(kYGDefaultDimensionValues), @@ -37,7 +37,7 @@ bool YGLayout::operator==(YGLayout layout) const { YGFloatArrayEqual(border, layout.border) && YGFloatArrayEqual(padding, layout.padding) && direction == layout.direction && hadOverflow == layout.hadOverflow && - lastParentDirection == layout.lastParentDirection && + lastOwnerDirection == layout.lastOwnerDirection && nextCachedMeasurementsIndex == layout.nextCachedMeasurementsIndex && cachedLayout == layout.cachedLayout; diff --git a/ReactCommon/yoga/yoga/YGLayout.h b/ReactCommon/yoga/yoga/YGLayout.h index cfe559f64bc170..81cc66317a5a1e 100644 --- a/ReactCommon/yoga/yoga/YGLayout.h +++ b/ReactCommon/yoga/yoga/YGLayout.h @@ -23,7 +23,7 @@ struct YGLayout { // Instead of recomputing the entire layout every single time, we // cache some information to break early when nothing changed uint32_t generationCount; - YGDirection lastParentDirection; + YGDirection lastOwnerDirection; uint32_t nextCachedMeasurementsIndex; std::array diff --git a/ReactCommon/yoga/yoga/YGNode.cpp b/ReactCommon/yoga/yoga/YGNode.cpp index f15105f26fe9d5..01be3a7c032879 100644 --- a/ReactCommon/yoga/yoga/YGNode.cpp +++ b/ReactCommon/yoga/yoga/YGNode.cpp @@ -49,8 +49,8 @@ uint32_t YGNode::getLineIndex() const { return lineIndex_; } -YGNodeRef YGNode::getParent() const { - return parent_; +YGNodeRef YGNode::getOwner() const { + return owner_; } YGVector YGNode::getChildren() const { @@ -237,8 +237,8 @@ void YGNode::setLineIndex(uint32_t lineIndex) { lineIndex_ = lineIndex; } -void YGNode::setParent(YGNodeRef parent) { - parent_ = parent; +void YGNode::setOwner(YGNodeRef owner) { + owner_ = owner; } void YGNode::setChildren(const YGVector& children) { @@ -305,8 +305,8 @@ void YGNode::setLayoutPadding(float padding, int index) { layout_.padding[index] = padding; } -void YGNode::setLayoutLastParentDirection(YGDirection direction) { - layout_.lastParentDirection = direction; +void YGNode::setLayoutLastOwnerDirection(YGDirection direction) { + layout_.lastOwnerDirection = direction; } void YGNode::setLayoutComputedFlexBasis(float computedFlexBasis) { @@ -347,11 +347,11 @@ void YGNode::setPosition( const YGDirection direction, const float mainSize, const float crossSize, - const float parentWidth) { + const float ownerWidth) { /* Root nodes should be always layouted as LTR, so we don't return negative * values. */ const YGDirection directionRespectingRoot = - parent_ != nullptr ? direction : YGDirectionLTR; + owner_ != nullptr ? direction : YGDirectionLTR; const YGFlexDirection mainAxis = YGResolveFlexDirection(style_.flexDirection, directionRespectingRoot); const YGFlexDirection crossAxis = @@ -361,16 +361,16 @@ void YGNode::setPosition( const float relativePositionCross = relativePosition(crossAxis, crossSize); setLayoutPosition( - getLeadingMargin(mainAxis, parentWidth) + relativePositionMain, + getLeadingMargin(mainAxis, ownerWidth) + relativePositionMain, leading[mainAxis]); setLayoutPosition( - getTrailingMargin(mainAxis, parentWidth) + relativePositionMain, + getTrailingMargin(mainAxis, ownerWidth) + relativePositionMain, trailing[mainAxis]); setLayoutPosition( - getLeadingMargin(crossAxis, parentWidth) + relativePositionCross, + getLeadingMargin(crossAxis, ownerWidth) + relativePositionCross, leading[crossAxis]); setLayoutPosition( - getTrailingMargin(crossAxis, parentWidth) + relativePositionCross, + getTrailingMargin(crossAxis, ownerWidth) + relativePositionCross, trailing[crossAxis]); } @@ -385,7 +385,7 @@ YGNode::YGNode() style_(YGStyle()), layout_(YGLayout()), lineIndex_(0), - parent_(nullptr), + owner_(nullptr), children_(YGVector()), nextChild_(nullptr), config_(nullptr), @@ -403,7 +403,7 @@ YGNode::YGNode(const YGNode& node) style_(node.style_), layout_(node.layout_), lineIndex_(node.lineIndex_), - parent_(node.parent_), + owner_(node.owner_), children_(node.children_), nextChild_(node.nextChild_), config_(node.config_), @@ -425,7 +425,7 @@ YGNode::YGNode( YGStyle style, const YGLayout& layout, uint32_t lineIndex, - YGNodeRef parent, + YGNodeRef owner, const YGVector& children, YGNodeRef nextChild, YGConfigRef config, @@ -441,7 +441,7 @@ YGNode::YGNode( style_(style), layout_(layout), lineIndex_(lineIndex), - parent_(parent), + owner_(owner), children_(children), nextChild_(nextChild), config_(config), @@ -467,7 +467,7 @@ YGNode& YGNode::operator=(const YGNode& node) { style_ = node.style_; layout_ = node.layout_; lineIndex_ = node.getLineIndex(); - parent_ = node.getParent(); + owner_ = node.getOwner(); children_ = node.getChildren(); nextChild_ = node.getNextChild(); config_ = node.getConfig(); @@ -518,9 +518,9 @@ void YGNode::resolveDimension() { } } -YGDirection YGNode::resolveDirection(const YGDirection parentDirection) { +YGDirection YGNode::resolveDirection(const YGDirection ownerDirection) { if (style_.direction == YGDirectionInherit) { - return parentDirection > YGDirectionInherit ? parentDirection + return ownerDirection > YGDirectionInherit ? ownerDirection : YGDirectionLTR; } else { return style_.direction; @@ -550,10 +550,10 @@ void YGNode::cloneChildrenIfNeeded() { } const YGNodeRef firstChild = children_.front(); - if (firstChild->getParent() == this) { - // If the first child has this node as its parent, we assume that it is + if (firstChild->getOwner() == this) { + // If the first child has this node as its owner, we assume that it is // already unique. We can do this because if we have it has a child, that - // means that its parent was at some point cloned which made that subtree + // means that its owner was at some point cloned which made that subtree // immutable. We also assume that all its sibling are cloned as well. return; } @@ -569,7 +569,7 @@ void YGNode::cloneChildrenIfNeeded() { newChild = YGNodeClone(oldChild); } replaceChild(newChild, i); - newChild->setParent(this); + newChild->setOwner(this); } } @@ -577,8 +577,8 @@ void YGNode::markDirtyAndPropogate() { if (!isDirty_) { setDirty(true); setLayoutComputedFlexBasis(YGUndefined); - if (parent_) { - parent_->markDirtyAndPropogate(); + if (owner_) { + owner_->markDirtyAndPropogate(); } } } @@ -592,7 +592,7 @@ void YGNode::markDirtyAndPropogateDownwards() { float YGNode::resolveFlexGrow() { // Root nodes flexGrow should always be 0 - if (parent_ == nullptr) { + if (owner_ == nullptr) { return 0.0; } if (!style_.flexGrow.isUndefined()) { @@ -605,7 +605,7 @@ float YGNode::resolveFlexGrow() { } float YGNode::resolveFlexShrink() { - if (parent_ == nullptr) { + if (owner_ == nullptr) { return 0.0; } if (!style_.flexShrink.isUndefined()) { diff --git a/ReactCommon/yoga/yoga/YGNode.h b/ReactCommon/yoga/yoga/YGNode.h index 0ed05d7e552138..02afb830e8b419 100644 --- a/ReactCommon/yoga/yoga/YGNode.h +++ b/ReactCommon/yoga/yoga/YGNode.h @@ -23,7 +23,7 @@ struct YGNode { YGStyle style_; YGLayout layout_; uint32_t lineIndex_; - YGNodeRef parent_; + YGNodeRef owner_; YGVector children_; YGNodeRef nextChild_; YGConfigRef config_; @@ -49,7 +49,7 @@ struct YGNode { YGStyle style, const YGLayout& layout, uint32_t lineIndex, - YGNodeRef parent, + YGNodeRef owner, const YGVector& children, YGNodeRef nextChild, YGConfigRef config, @@ -69,7 +69,12 @@ struct YGNode { // For Performance reasons passing as reference. YGLayout& getLayout(); uint32_t getLineIndex() const; - YGNodeRef getParent() const; + // returns the YGNodeRef that owns this YGNode. An owner is used to identify + // the YogaTree that a YGNode belongs to. + // This method will return the parent of the YGNode when a YGNode only belongs + // to one YogaTree or nullptr when the YGNode is shared between two or more + // YogaTrees. + YGNodeRef getOwner() const; YGVector getChildren() const; uint32_t getChildrenCount() const; YGNodeRef getChild(uint32_t index) const; @@ -111,12 +116,12 @@ struct YGNode { void setStyleAlignContent(YGAlign alignContent); void setLayout(const YGLayout& layout); void setLineIndex(uint32_t lineIndex); - void setParent(YGNodeRef parent); + void setOwner(YGNodeRef owner); void setChildren(const YGVector& children); void setNextChild(YGNodeRef nextChild); void setConfig(YGConfigRef config); void setDirty(bool isDirty); - void setLayoutLastParentDirection(YGDirection direction); + void setLayoutLastOwnerDirection(YGDirection direction); void setLayoutComputedFlexBasis(float computedFlexBasis); void setLayoutComputedFlexBasisGeneration( uint32_t computedFlexBasisGeneration); @@ -132,7 +137,7 @@ struct YGNode { const YGDirection direction, const float mainSize, const float crossSize, - const float parentWidth); + const float ownerWidth); void setAndPropogateUseLegacyFlag(bool useLegacyFlag); void setLayoutDoesLegacyFlagAffectsLayout(bool doesLegacyFlagAffectsLayout); void setLayoutDidUseLegacyFlag(bool didUseLegacyFlag); @@ -143,7 +148,7 @@ struct YGNode { YGValue marginTrailingValue(const YGFlexDirection axis) const; YGValue resolveFlexBasisPtr() const; void resolveDimension(); - YGDirection resolveDirection(const YGDirection parentDirection); + YGDirection resolveDirection(const YGDirection ownerDirection); void clearChildren(); /// Replaces the occurrences of oldChild with newChild void replaceChild(YGNodeRef oldChild, YGNodeRef newChild); diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index b597727bc4cee7..2e5979a2dd0f91 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -257,7 +257,7 @@ YGNodeRef YGNodeClone(YGNodeRef oldNode) { node != nullptr, "Could not allocate memory for node"); gNodeInstanceCount++; - node->setParent(nullptr); + node->setOwner(nullptr); return node; } @@ -278,7 +278,7 @@ static YGNodeRef YGNodeDeepClone(YGNodeRef oldNode) { YGNodeRef childNode = nullptr; for (auto& item : oldNode->getChildren()) { childNode = YGNodeDeepClone(item); - childNode->setParent(node); + childNode->setOwner(node); vec.push_back(childNode); } node->setChildren(vec); @@ -295,15 +295,15 @@ static YGNodeRef YGNodeDeepClone(YGNodeRef oldNode) { } void YGNodeFree(const YGNodeRef node) { - if (YGNodeRef parent = node->getParent()) { - parent->removeChild(node); - node->setParent(nullptr); + if (YGNodeRef owner = node->getOwner()) { + owner->removeChild(node); + node->setOwner(nullptr); } const uint32_t childCount = YGNodeGetChildCount(node); for (uint32_t i = 0; i < childCount; i++) { const YGNodeRef child = YGNodeGetChild(node, i); - child->setParent(nullptr); + child->setOwner(nullptr); } node->clearChildren(); @@ -325,7 +325,7 @@ static void YGConfigFreeRecursive(const YGNodeRef root) { void YGNodeFreeRecursive(const YGNodeRef root) { while (YGNodeGetChildCount(root) > 0) { const YGNodeRef child = YGNodeGetChild(root, 0); - if (child->getParent() != root) { + if (child->getOwner() != root) { // Don't free shared nodes that we don't own. break; } @@ -341,8 +341,8 @@ void YGNodeReset(const YGNodeRef node) { "Cannot reset a node which still has children attached"); YGAssertWithNode( node, - node->getParent() == nullptr, - "Cannot reset a node still attached to a parent"); + node->getOwner() == nullptr, + "Cannot reset a node still attached to a owner"); node->clearChildren(); @@ -391,8 +391,8 @@ void YGConfigCopy(const YGConfigRef dest, const YGConfigRef src) { void YGNodeInsertChild(const YGNodeRef node, const YGNodeRef child, const uint32_t index) { YGAssertWithNode( node, - child->getParent() == nullptr, - "Child already has a parent, it must be removed first."); + child->getOwner() == nullptr, + "Child already has a owner, it must be removed first."); YGAssertWithNode( node, node->getMeasure() == nullptr, @@ -400,28 +400,28 @@ void YGNodeInsertChild(const YGNodeRef node, const YGNodeRef child, const uint32 node->cloneChildrenIfNeeded(); node->insertChild(child, index); - child->setParent(node); + child->setOwner(node); node->markDirtyAndPropogate(); } -void YGNodeRemoveChild(const YGNodeRef parent, const YGNodeRef excludedChild) { +void YGNodeRemoveChild(const YGNodeRef owner, const YGNodeRef excludedChild) { // This algorithm is a forked variant from cloneChildrenIfNeeded in YGNode // that excludes a child. - const uint32_t childCount = YGNodeGetChildCount(parent); + const uint32_t childCount = YGNodeGetChildCount(owner); if (childCount == 0) { // This is an empty set. Nothing to remove. return; } - const YGNodeRef firstChild = YGNodeGetChild(parent, 0); - if (firstChild->getParent() == parent) { - // If the first child has this node as its parent, we assume that it is already unique. + const YGNodeRef firstChild = YGNodeGetChild(owner, 0); + if (firstChild->getOwner() == owner) { + // If the first child has this node as its owner, we assume that it is already unique. // We can now try to delete a child in this list. - if (parent->removeChild(excludedChild)) { + if (owner->removeChild(excludedChild)) { excludedChild->setLayout( YGNode().getLayout()); // layout is no longer valid - excludedChild->setParent(nullptr); - parent->markDirtyAndPropogate(); + excludedChild->setOwner(nullptr); + owner->markDirtyAndPropogate(); } return; } @@ -429,98 +429,98 @@ void YGNodeRemoveChild(const YGNodeRef parent, const YGNodeRef excludedChild) { // We don't want to simply clone all children, because then the host will need to free // the clone of the child that was just deleted. const YGCloneNodeFunc cloneNodeCallback = - parent->getConfig()->cloneNodeCallback; + owner->getConfig()->cloneNodeCallback; uint32_t nextInsertIndex = 0; for (uint32_t i = 0; i < childCount; i++) { - const YGNodeRef oldChild = parent->getChild(i); + const YGNodeRef oldChild = owner->getChild(i); if (excludedChild == oldChild) { - // Ignore the deleted child. Don't reset its layout or parent since it is still valid - // in the other parent. However, since this parent has now changed, we need to mark it + // Ignore the deleted child. Don't reset its layout or owner since it is still valid + // in the other owner. However, since this owner has now changed, we need to mark it // as dirty. - parent->markDirtyAndPropogate(); + owner->markDirtyAndPropogate(); continue; } YGNodeRef newChild = nullptr; if (cloneNodeCallback) { - newChild = cloneNodeCallback(oldChild, parent, nextInsertIndex); + newChild = cloneNodeCallback(oldChild, owner, nextInsertIndex); } if (newChild == nullptr) { newChild = YGNodeClone(oldChild); } - parent->replaceChild(newChild, nextInsertIndex); - newChild->setParent(parent); + owner->replaceChild(newChild, nextInsertIndex); + newChild->setOwner(owner); nextInsertIndex++; } while (nextInsertIndex < childCount) { - parent->removeChild(nextInsertIndex); + owner->removeChild(nextInsertIndex); nextInsertIndex++; } } -void YGNodeRemoveAllChildren(const YGNodeRef parent) { - const uint32_t childCount = YGNodeGetChildCount(parent); +void YGNodeRemoveAllChildren(const YGNodeRef owner) { + const uint32_t childCount = YGNodeGetChildCount(owner); if (childCount == 0) { // This is an empty set already. Nothing to do. return; } - const YGNodeRef firstChild = YGNodeGetChild(parent, 0); - if (firstChild->getParent() == parent) { - // If the first child has this node as its parent, we assume that this child set is unique. + const YGNodeRef firstChild = YGNodeGetChild(owner, 0); + if (firstChild->getOwner() == owner) { + // If the first child has this node as its owner, we assume that this child set is unique. for (uint32_t i = 0; i < childCount; i++) { - const YGNodeRef oldChild = YGNodeGetChild(parent, i); + const YGNodeRef oldChild = YGNodeGetChild(owner, i); oldChild->setLayout(YGNode().getLayout()); // layout is no longer valid - oldChild->setParent(nullptr); + oldChild->setOwner(nullptr); } - parent->clearChildren(); - parent->markDirtyAndPropogate(); + owner->clearChildren(); + owner->markDirtyAndPropogate(); return; } // Otherwise, we are not the owner of the child set. We don't have to do anything to clear it. - parent->setChildren(YGVector()); - parent->markDirtyAndPropogate(); + owner->setChildren(YGVector()); + owner->markDirtyAndPropogate(); } -static void YGNodeSetChildrenInternal(YGNodeRef const parent, const std::vector &children) +static void YGNodeSetChildrenInternal(YGNodeRef const owner, const std::vector &children) { - if (!parent) { + if (!owner) { return; } if (children.size() == 0) { - if (YGNodeGetChildCount(parent) > 0) { - for (YGNodeRef const child : parent->getChildren()) { + if (YGNodeGetChildCount(owner) > 0) { + for (YGNodeRef const child : owner->getChildren()) { child->setLayout(YGLayout()); - child->setParent(nullptr); + child->setOwner(nullptr); } - parent->setChildren(YGVector()); - parent->markDirtyAndPropogate(); + owner->setChildren(YGVector()); + owner->markDirtyAndPropogate(); } } else { - if (YGNodeGetChildCount(parent) > 0) { - for (YGNodeRef const oldChild : parent->getChildren()) { + if (YGNodeGetChildCount(owner) > 0) { + for (YGNodeRef const oldChild : owner->getChildren()) { // Our new children may have nodes in common with the old children. We don't reset these common nodes. if (std::find(children.begin(), children.end(), oldChild) == children.end()) { oldChild->setLayout(YGLayout()); - oldChild->setParent(nullptr); + oldChild->setOwner(nullptr); } } } - parent->setChildren(children); + owner->setChildren(children); for (YGNodeRef child : children) { - child->setParent(parent); + child->setOwner(owner); } - parent->markDirtyAndPropogate(); + owner->markDirtyAndPropogate(); } } -void YGNodeSetChildren(YGNodeRef const parent, const YGNodeRef c[], const uint32_t count) { +void YGNodeSetChildren(YGNodeRef const owner, const YGNodeRef c[], const uint32_t count) { const YGVector children = {c, c + count}; - YGNodeSetChildrenInternal(parent, children); + YGNodeSetChildrenInternal(owner, children); } -void YGNodeSetChildren(YGNodeRef const parent, const std::vector &children) +void YGNodeSetChildren(YGNodeRef const owner, const std::vector &children) { - YGNodeSetChildrenInternal(parent, children); + YGNodeSetChildrenInternal(owner, children); } YGNodeRef YGNodeGetChild(const YGNodeRef node, const uint32_t index) { @@ -534,8 +534,8 @@ uint32_t YGNodeGetChildCount(const YGNodeRef node) { return static_cast(node->getChildren().size()); } -YGNodeRef YGNodeGetParent(const YGNodeRef node) { - return node->getParent(); +YGNodeRef YGNodeGetOwner(const YGNodeRef node) { + return node->getOwner(); } void YGNodeMarkDirty(const YGNodeRef node) { @@ -947,11 +947,11 @@ uint32_t gCurrentGenerationCount = 0; bool YGLayoutNodeInternal(const YGNodeRef node, const float availableWidth, const float availableHeight, - const YGDirection parentDirection, + const YGDirection ownerDirection, const YGMeasureMode widthMeasureMode, const YGMeasureMode heightMeasureMode, - const float parentWidth, - const float parentHeight, + const float ownerWidth, + const float ownerHeight, const bool performLayout, const char *reason, const YGConfigRef config); @@ -1069,7 +1069,7 @@ static inline float YGNodeDimWithMargin(const YGNodeRef node, static inline bool YGNodeIsStyleDimDefined(const YGNodeRef node, const YGFlexDirection axis, - const float parentSize) { + const float ownerSize) { bool isUndefined = YGFloatIsUndefined(node->getResolvedDimension(dim[axis]).value); return !( @@ -1080,7 +1080,7 @@ static inline bool YGNodeIsStyleDimDefined(const YGNodeRef node, (node->getResolvedDimension(dim[axis]).unit == YGUnitPercent && !isUndefined && (node->getResolvedDimension(dim[axis]).value < 0.0f || - YGFloatIsUndefined(parentSize)))); + YGFloatIsUndefined(ownerSize)))); } static inline bool YGNodeIsLayoutDimDefined(const YGNodeRef node, const YGFlexDirection axis) { @@ -1145,14 +1145,14 @@ static void YGNodeSetChildTrailingPosition(const YGNodeRef node, static void YGConstrainMaxSizeForMode(const YGNodeRef node, const enum YGFlexDirection axis, - const float parentAxisSize, - const float parentWidth, + const float ownerAxisSize, + const float ownerWidth, YGMeasureMode *mode, float *size) { const float maxSize = YGUnwrapFloatOptional(YGResolveValue( - node->getStyle().maxDimensions[dim[axis]], parentAxisSize)) + - node->getMarginForAxis(axis, parentWidth); + node->getStyle().maxDimensions[dim[axis]], ownerAxisSize)) + + node->getMarginForAxis(axis, ownerWidth); switch (*mode) { case YGMeasureModeExactly: case YGMeasureModeAtMost: @@ -1172,8 +1172,8 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node, const float width, const YGMeasureMode widthMode, const float height, - const float parentWidth, - const float parentHeight, + const float ownerWidth, + const float ownerHeight, const YGMeasureMode heightMode, const YGDirection direction, const YGConfigRef config) { @@ -1181,7 +1181,7 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node, YGResolveFlexDirection(node->getStyle().flexDirection, direction); const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis); const float mainAxisSize = isMainAxisRow ? width : height; - const float mainAxisParentSize = isMainAxisRow ? parentWidth : parentHeight; + const float mainAxisownerSize = isMainAxisRow ? ownerWidth : ownerHeight; float childWidth; float childHeight; @@ -1189,10 +1189,10 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node, YGMeasureMode childHeightMeasureMode; const float resolvedFlexBasis = - YGUnwrapFloatOptional(YGResolveValue(child->resolveFlexBasisPtr(), mainAxisParentSize)); - const bool isRowStyleDimDefined = YGNodeIsStyleDimDefined(child, YGFlexDirectionRow, parentWidth); + YGUnwrapFloatOptional(YGResolveValue(child->resolveFlexBasisPtr(), mainAxisownerSize)); + const bool isRowStyleDimDefined = YGNodeIsStyleDimDefined(child, YGFlexDirectionRow, ownerWidth); const bool isColumnStyleDimDefined = - YGNodeIsStyleDimDefined(child, YGFlexDirectionColumn, parentHeight); + YGNodeIsStyleDimDefined(child, YGFlexDirectionColumn, ownerHeight); if (!YGFloatIsUndefined(resolvedFlexBasis) && !YGFloatIsUndefined(mainAxisSize)) { if (YGFloatIsUndefined(child->getLayout().computedFlexBasis) || @@ -1202,21 +1202,21 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node, gCurrentGenerationCount)) { child->setLayoutComputedFlexBasis(YGFloatMax( resolvedFlexBasis, - YGNodePaddingAndBorderForAxis(child, mainAxis, parentWidth))); + YGNodePaddingAndBorderForAxis(child, mainAxis, ownerWidth))); } } else if (isMainAxisRow && isRowStyleDimDefined) { // The width is definite, so use that as the flex basis. child->setLayoutComputedFlexBasis(YGFloatMax( YGUnwrapFloatOptional(YGResolveValue( - child->getResolvedDimension(YGDimensionWidth), parentWidth)), - YGNodePaddingAndBorderForAxis(child, YGFlexDirectionRow, parentWidth))); + child->getResolvedDimension(YGDimensionWidth), ownerWidth)), + YGNodePaddingAndBorderForAxis(child, YGFlexDirectionRow, ownerWidth))); } else if (!isMainAxisRow && isColumnStyleDimDefined) { // The height is definite, so use that as the flex basis. child->setLayoutComputedFlexBasis(YGFloatMax( YGUnwrapFloatOptional(YGResolveValue( - child->getResolvedDimension(YGDimensionHeight), parentHeight)), + child->getResolvedDimension(YGDimensionHeight), ownerHeight)), YGNodePaddingAndBorderForAxis( - child, YGFlexDirectionColumn, parentWidth))); + child, YGFlexDirectionColumn, ownerWidth))); } else { // Compute the flex basis and hypothetical main size (i.e. the clamped // flex basis). @@ -1226,21 +1226,21 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node, childHeightMeasureMode = YGMeasureModeUndefined; const float marginRow = - child->getMarginForAxis(YGFlexDirectionRow, parentWidth); + child->getMarginForAxis(YGFlexDirectionRow, ownerWidth); const float marginColumn = - child->getMarginForAxis(YGFlexDirectionColumn, parentWidth); + child->getMarginForAxis(YGFlexDirectionColumn, ownerWidth); if (isRowStyleDimDefined) { childWidth = YGUnwrapFloatOptional(YGResolveValue( - child->getResolvedDimension(YGDimensionWidth), parentWidth)) + + child->getResolvedDimension(YGDimensionWidth), ownerWidth)) + marginRow; childWidthMeasureMode = YGMeasureModeExactly; } if (isColumnStyleDimDefined) { childHeight = YGUnwrapFloatOptional(YGResolveValue( - child->getResolvedDimension(YGDimensionHeight), parentHeight)) + + child->getResolvedDimension(YGDimensionHeight), ownerHeight)) + marginColumn; childHeightMeasureMode = YGMeasureModeExactly; } @@ -1306,11 +1306,11 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node, } YGConstrainMaxSizeForMode( - child, YGFlexDirectionRow, parentWidth, parentWidth, &childWidthMeasureMode, &childWidth); + child, YGFlexDirectionRow, ownerWidth, ownerWidth, &childWidthMeasureMode, &childWidth); YGConstrainMaxSizeForMode(child, YGFlexDirectionColumn, - parentHeight, - parentWidth, + ownerHeight, + ownerWidth, &childHeightMeasureMode, &childHeight); @@ -1321,15 +1321,15 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node, direction, childWidthMeasureMode, childHeightMeasureMode, - parentWidth, - parentHeight, + ownerWidth, + ownerHeight, false, "measure", config); child->setLayoutComputedFlexBasis(YGFloatMax( child->getLayout().measuredDimensions[dim[mainAxis]], - YGNodePaddingAndBorderForAxis(child, mainAxis, parentWidth))); + YGNodePaddingAndBorderForAxis(child, mainAxis, ownerWidth))); } child->setLayoutComputedFlexBasisGeneration(gCurrentGenerationCount); } @@ -1414,8 +1414,8 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, childHeightMeasureMode = YGFloatIsUndefined(childHeight) ? YGMeasureModeUndefined : YGMeasureModeExactly; - // If the size of the parent is defined then try to constrain the absolute child to that size - // as well. This allows text within the absolute child to wrap to the size of its parent. + // If the size of the owner is defined then try to constrain the absolute child to that size + // as well. This allows text within the absolute child to wrap to the size of its owner. // This is the same behavior as many browsers implement. if (!isMainAxisRow && YGFloatIsUndefined(childWidth) && widthMode != YGMeasureModeUndefined && !YGFloatIsUndefined(width) && @@ -1515,8 +1515,8 @@ static void YGNodeWithMeasureFuncSetMeasuredDimensions(const YGNodeRef node, const float availableHeight, const YGMeasureMode widthMeasureMode, const YGMeasureMode heightMeasureMode, - const float parentWidth, - const float parentHeight) { + const float ownerWidth, + const float ownerHeight) { YGAssertWithNode( node, node->getMeasure() != nullptr, @@ -1548,16 +1548,16 @@ static void YGNodeWithMeasureFuncSetMeasuredDimensions(const YGNodeRef node, node, YGFlexDirectionRow, availableWidth - marginAxisRow, - parentWidth, - parentWidth), + ownerWidth, + ownerWidth), YGDimensionWidth); node->setLayoutMeasuredDimension( YGNodeBoundAxis( node, YGFlexDirectionColumn, availableHeight - marginAxisColumn, - parentHeight, - parentWidth), + ownerHeight, + ownerWidth), YGDimensionHeight); } else { // Measure the text under the current constraints. @@ -1572,8 +1572,8 @@ static void YGNodeWithMeasureFuncSetMeasuredDimensions(const YGNodeRef node, widthMeasureMode == YGMeasureModeAtMost) ? measuredSize.width + paddingAndBorderAxisRow : availableWidth - marginAxisRow, - parentWidth, - parentWidth), + ownerWidth, + ownerWidth), YGDimensionWidth); node->setLayoutMeasuredDimension( @@ -1584,8 +1584,8 @@ static void YGNodeWithMeasureFuncSetMeasuredDimensions(const YGNodeRef node, heightMeasureMode == YGMeasureModeAtMost) ? measuredSize.height + paddingAndBorderAxisColumn : availableHeight - marginAxisColumn, - parentHeight, - parentWidth), + ownerHeight, + ownerWidth), YGDimensionHeight); } } @@ -1597,16 +1597,16 @@ static void YGNodeEmptyContainerSetMeasuredDimensions(const YGNodeRef node, const float availableHeight, const YGMeasureMode widthMeasureMode, const YGMeasureMode heightMeasureMode, - const float parentWidth, - const float parentHeight) { + const float ownerWidth, + const float ownerHeight) { const float paddingAndBorderAxisRow = - YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, parentWidth); + YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, ownerWidth); const float paddingAndBorderAxisColumn = - YGNodePaddingAndBorderForAxis(node, YGFlexDirectionColumn, parentWidth); + YGNodePaddingAndBorderForAxis(node, YGFlexDirectionColumn, ownerWidth); const float marginAxisRow = - node->getMarginForAxis(YGFlexDirectionRow, parentWidth); + node->getMarginForAxis(YGFlexDirectionRow, ownerWidth); const float marginAxisColumn = - node->getMarginForAxis(YGFlexDirectionColumn, parentWidth); + node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth); node->setLayoutMeasuredDimension( YGNodeBoundAxis( @@ -1616,8 +1616,8 @@ static void YGNodeEmptyContainerSetMeasuredDimensions(const YGNodeRef node, widthMeasureMode == YGMeasureModeAtMost) ? paddingAndBorderAxisRow : availableWidth - marginAxisRow, - parentWidth, - parentWidth), + ownerWidth, + ownerWidth), YGDimensionWidth); node->setLayoutMeasuredDimension( @@ -1628,8 +1628,8 @@ static void YGNodeEmptyContainerSetMeasuredDimensions(const YGNodeRef node, heightMeasureMode == YGMeasureModeAtMost) ? paddingAndBorderAxisColumn : availableHeight - marginAxisColumn, - parentHeight, - parentWidth), + ownerHeight, + ownerWidth), YGDimensionHeight); } @@ -1638,8 +1638,8 @@ static bool YGNodeFixedSizeSetMeasuredDimensions(const YGNodeRef node, const float availableHeight, const YGMeasureMode widthMeasureMode, const YGMeasureMode heightMeasureMode, - const float parentWidth, - const float parentHeight) { + const float ownerWidth, + const float ownerHeight) { if ((!YGFloatIsUndefined(availableWidth) && widthMeasureMode == YGMeasureModeAtMost && availableWidth <= 0.0f) || (!YGFloatIsUndefined(availableHeight) && @@ -1647,9 +1647,9 @@ static bool YGNodeFixedSizeSetMeasuredDimensions(const YGNodeRef node, (widthMeasureMode == YGMeasureModeExactly && heightMeasureMode == YGMeasureModeExactly)) { const float marginAxisColumn = - node->getMarginForAxis(YGFlexDirectionColumn, parentWidth); + node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth); const float marginAxisRow = - node->getMarginForAxis(YGFlexDirectionRow, parentWidth); + node->getMarginForAxis(YGFlexDirectionRow, ownerWidth); node->setLayoutMeasuredDimension( YGNodeBoundAxis( @@ -1660,8 +1660,8 @@ static bool YGNodeFixedSizeSetMeasuredDimensions(const YGNodeRef node, availableWidth < 0.0f) ? 0.0f : availableWidth - marginAxisRow, - parentWidth, - parentWidth), + ownerWidth, + ownerWidth), YGDimensionWidth); node->setLayoutMeasuredDimension( @@ -1673,8 +1673,8 @@ static bool YGNodeFixedSizeSetMeasuredDimensions(const YGNodeRef node, availableHeight < 0.0f) ? 0.0f : availableHeight - marginAxisColumn, - parentHeight, - parentWidth), + ownerHeight, + ownerWidth), YGDimensionHeight); return true; } @@ -1697,15 +1697,15 @@ static float YGNodeCalculateAvailableInnerDim( const YGNodeRef node, YGFlexDirection axis, float availableDim, - float parentDim) { + float ownerDim) { YGFlexDirection direction = YGFlexDirectionIsRow(axis) ? YGFlexDirectionRow : YGFlexDirectionColumn; YGDimension dimension = YGFlexDirectionIsRow(axis) ? YGDimensionWidth : YGDimensionHeight; - const float margin = node->getMarginForAxis(direction, parentDim); + const float margin = node->getMarginForAxis(direction, ownerDim); const float paddingAndBorder = - YGNodePaddingAndBorderForAxis(node, direction, parentDim); + YGNodePaddingAndBorderForAxis(node, direction, ownerDim); float availableInnerDim = availableDim - margin - paddingAndBorder; // Max dimension overrides predefined dimension value; Min dimension in turn @@ -1713,12 +1713,12 @@ static float YGNodeCalculateAvailableInnerDim( if (!YGFloatIsUndefined(availableInnerDim)) { // We want to make sure our available height does not violate min and max // constraints - const YGFloatOptional minDimensionOptional = YGResolveValue(node->getStyle().minDimensions[dimension], parentDim); + const YGFloatOptional minDimensionOptional = YGResolveValue(node->getStyle().minDimensions[dimension], ownerDim); const float minInnerDim = minDimensionOptional.isUndefined() ? 0.0f : minDimensionOptional.getValue() - paddingAndBorder; - const YGFloatOptional maxDimensionOptional = YGResolveValue(node->getStyle().maxDimensions[dimension], parentDim) ; + const YGFloatOptional maxDimensionOptional = YGResolveValue(node->getStyle().maxDimensions[dimension], ownerDim) ; const float maxInnerDim = maxDimensionOptional.isUndefined() ? FLT_MAX @@ -1773,7 +1773,7 @@ static void YGNodeComputeFlexBasisForChildren( continue; } if (performLayout) { - // Set the initial position (relative to the parent). + // Set the initial position (relative to the owner). const YGDirection childDirection = child->resolveDirection(direction); const float mainDim = YGFlexDirectionIsRow(mainAxis) ? availableInnerWidth @@ -1816,8 +1816,8 @@ static void YGNodeComputeFlexBasisForChildren( // This function calculates YGCollectFlexItemsRowMeasurement static YGCollectFlexItemsRowValues YGCalculateCollectFlexItemsRowValues( const YGNodeRef& node, - const YGDirection parentDirection, - const float mainAxisParentSize, + const YGDirection ownerDirection, + const float mainAxisownerSize, const float availableInnerWidth, const float availableInnerMainDim, const uint32_t startOfLineIndex, @@ -1827,7 +1827,7 @@ static YGCollectFlexItemsRowValues YGCalculateCollectFlexItemsRowValues( float sizeConsumedOnCurrentLineIncludingMinConstraint = 0; const YGFlexDirection mainAxis = YGResolveFlexDirection( - node->getStyle().flexDirection, node->resolveDirection(parentDirection)); + node->getStyle().flexDirection, node->resolveDirection(ownerDirection)); const bool isNodeFlexWrap = node->getStyle().flexWrap != YGWrapNoWrap; // Add items to the current line until it's full or we run out of items. @@ -1846,7 +1846,7 @@ static YGCollectFlexItemsRowValues YGCalculateCollectFlexItemsRowValues( child, mainAxis, child->getLayout().computedFlexBasis, - mainAxisParentSize); + mainAxisownerSize); // If this is a multi-line flow and this item pushes us over the // available size, we've @@ -1901,7 +1901,7 @@ static float YGDistributeFreeSpaceSecondPass( const YGNodeRef node, const YGFlexDirection mainAxis, const YGFlexDirection crossAxis, - const float mainAxisParentSize, + const float mainAxisownerSize, const float availableInnerMainDim, const float availableInnerCrossDim, const float availableInnerWidth, @@ -1922,7 +1922,7 @@ static float YGDistributeFreeSpaceSecondPass( currentRelativeChild, mainAxis, currentRelativeChild->getLayout().computedFlexBasis, - mainAxisParentSize); + mainAxisownerSize); float updatedMainSize = childFlexBasis; if (!YGFloatIsUndefined(collectedFlexItemsValues.remainingFreeSpace) && @@ -2083,7 +2083,7 @@ static float YGDistributeFreeSpaceSecondPass( static void YGDistributeFreeSpaceFirstPass( YGCollectFlexItemsRowValues& collectedFlexItemsValues, const YGFlexDirection mainAxis, - const float mainAxisParentSize, + const float mainAxisownerSize, const float availableInnerMainDim, const float availableInnerWidth) { float flexShrinkScaledFactor = 0; @@ -2097,7 +2097,7 @@ static void YGDistributeFreeSpaceFirstPass( currentRelativeChild, mainAxis, currentRelativeChild->getLayout().computedFlexBasis, - mainAxisParentSize); + mainAxisownerSize); if (collectedFlexItemsValues.remainingFreeSpace < 0) { flexShrinkScaledFactor = @@ -2195,7 +2195,7 @@ static void YGResolveFlexibleLength( YGCollectFlexItemsRowValues& collectedFlexItemsValues, const YGFlexDirection mainAxis, const YGFlexDirection crossAxis, - const float mainAxisParentSize, + const float mainAxisownerSize, const float availableInnerMainDim, const float availableInnerCrossDim, const float availableInnerWidth, @@ -2209,7 +2209,7 @@ static void YGResolveFlexibleLength( YGDistributeFreeSpaceFirstPass( collectedFlexItemsValues, mainAxis, - mainAxisParentSize, + mainAxisownerSize, availableInnerMainDim, availableInnerWidth); @@ -2219,7 +2219,7 @@ static void YGResolveFlexibleLength( node, mainAxis, crossAxis, - mainAxisParentSize, + mainAxisownerSize, availableInnerMainDim, availableInnerCrossDim, availableInnerWidth, @@ -2241,8 +2241,8 @@ static void YGJustifyMainAxis( const YGFlexDirection& crossAxis, const YGMeasureMode& measureModeMainDim, const YGMeasureMode& measureModeCrossDim, - const float& mainAxisParentSize, - const float& parentWidth, + const float& mainAxisownerSize, + const float& ownerWidth, const float& availableInnerMainDim, const float& availableInnerCrossDim, const float& availableInnerWidth, @@ -2254,12 +2254,12 @@ static void YGJustifyMainAxis( if (measureModeMainDim == YGMeasureModeAtMost && collectedFlexItemsValues.remainingFreeSpace > 0) { if (style.minDimensions[dim[mainAxis]].unit != YGUnitUndefined && - !YGResolveValue(style.minDimensions[dim[mainAxis]], mainAxisParentSize) + !YGResolveValue(style.minDimensions[dim[mainAxis]], mainAxisownerSize) .isUndefined()) { collectedFlexItemsValues.remainingFreeSpace = YGFloatMax( 0, YGUnwrapFloatOptional(YGResolveValue( - style.minDimensions[dim[mainAxis]], mainAxisParentSize)) - + style.minDimensions[dim[mainAxis]], mainAxisownerSize)) - (availableInnerMainDim - collectedFlexItemsValues.remainingFreeSpace)); } else { @@ -2324,7 +2324,7 @@ static void YGJustifyMainAxis( } const float leadingPaddingAndBorderMain = - node->getLeadingPaddingAndBorder(mainAxis, parentWidth); + node->getLeadingPaddingAndBorder(mainAxis, ownerWidth); collectedFlexItemsValues.mainDim = leadingPaddingAndBorderMain + leadingMainDim; collectedFlexItemsValues.crossDim = 0; @@ -2405,7 +2405,7 @@ static void YGJustifyMainAxis( } } collectedFlexItemsValues.mainDim += - node->getTrailingPaddingAndBorder(mainAxis, parentWidth); + node->getTrailingPaddingAndBorder(mainAxis, ownerWidth); } // @@ -2451,7 +2451,7 @@ static void YGJustifyMainAxis( // or YGUndefined if the size is not available; interpretation depends on // layout // flags -// - parentDirection: the inline (text) direction within the parent +// - ownerDirection: the inline (text) direction within the owner // (left-to-right or // right-to-left) // - widthMeasureMode: indicates the sizing rules for the width (see below @@ -2497,11 +2497,11 @@ static void YGJustifyMainAxis( static void YGNodelayoutImpl(const YGNodeRef node, const float availableWidth, const float availableHeight, - const YGDirection parentDirection, + const YGDirection ownerDirection, const YGMeasureMode widthMeasureMode, const YGMeasureMode heightMeasureMode, - const float parentWidth, - const float parentHeight, + const float ownerWidth, + const float ownerHeight, const bool performLayout, const YGConfigRef config) { YGAssertWithNode(node, @@ -2516,7 +2516,7 @@ static void YGNodelayoutImpl(const YGNodeRef node, "YGMeasureModeUndefined"); // Set the resolved resolution in the node's layout. - const YGDirection direction = node->resolveDirection(parentDirection); + const YGDirection direction = node->resolveDirection(ownerDirection); node->setLayoutDirection(direction); const YGFlexDirection flexRowDirection = YGResolveFlexDirection(YGFlexDirectionRow, direction); @@ -2524,13 +2524,13 @@ static void YGNodelayoutImpl(const YGNodeRef node, YGResolveFlexDirection(YGFlexDirectionColumn, direction); node->setLayoutMargin( - node->getLeadingMargin(flexRowDirection, parentWidth), YGEdgeStart); + node->getLeadingMargin(flexRowDirection, ownerWidth), YGEdgeStart); node->setLayoutMargin( - node->getTrailingMargin(flexRowDirection, parentWidth), YGEdgeEnd); + node->getTrailingMargin(flexRowDirection, ownerWidth), YGEdgeEnd); node->setLayoutMargin( - node->getLeadingMargin(flexColumnDirection, parentWidth), YGEdgeTop); + node->getLeadingMargin(flexColumnDirection, ownerWidth), YGEdgeTop); node->setLayoutMargin( - node->getTrailingMargin(flexColumnDirection, parentWidth), YGEdgeBottom); + node->getTrailingMargin(flexColumnDirection, ownerWidth), YGEdgeBottom); node->setLayoutBorder(node->getLeadingBorder(flexRowDirection), YGEdgeStart); node->setLayoutBorder(node->getTrailingBorder(flexRowDirection), YGEdgeEnd); @@ -2539,13 +2539,13 @@ static void YGNodelayoutImpl(const YGNodeRef node, node->getTrailingBorder(flexColumnDirection), YGEdgeBottom); node->setLayoutPadding( - node->getLeadingPadding(flexRowDirection, parentWidth), YGEdgeStart); + node->getLeadingPadding(flexRowDirection, ownerWidth), YGEdgeStart); node->setLayoutPadding( - node->getTrailingPadding(flexRowDirection, parentWidth), YGEdgeEnd); + node->getTrailingPadding(flexRowDirection, ownerWidth), YGEdgeEnd); node->setLayoutPadding( - node->getLeadingPadding(flexColumnDirection, parentWidth), YGEdgeTop); + node->getLeadingPadding(flexColumnDirection, ownerWidth), YGEdgeTop); node->setLayoutPadding( - node->getTrailingPadding(flexColumnDirection, parentWidth), YGEdgeBottom); + node->getTrailingPadding(flexColumnDirection, ownerWidth), YGEdgeBottom); if (node->getMeasure() != nullptr) { YGNodeWithMeasureFuncSetMeasuredDimensions(node, @@ -2553,8 +2553,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, availableHeight, widthMeasureMode, heightMeasureMode, - parentWidth, - parentHeight); + ownerWidth, + ownerHeight); return; } @@ -2565,8 +2565,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, availableHeight, widthMeasureMode, heightMeasureMode, - parentWidth, - parentHeight); + ownerWidth, + ownerHeight); return; } @@ -2577,8 +2577,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, availableHeight, widthMeasureMode, heightMeasureMode, - parentWidth, - parentHeight)) { + ownerWidth, + ownerHeight)) { return; } @@ -2594,14 +2594,14 @@ static void YGNodelayoutImpl(const YGNodeRef node, const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis); const bool isNodeFlexWrap = node->getStyle().flexWrap != YGWrapNoWrap; - const float mainAxisParentSize = isMainAxisRow ? parentWidth : parentHeight; - const float crossAxisParentSize = isMainAxisRow ? parentHeight : parentWidth; + const float mainAxisownerSize = isMainAxisRow ? ownerWidth : ownerHeight; + const float crossAxisownerSize = isMainAxisRow ? ownerHeight : ownerWidth; const float leadingPaddingAndBorderCross = - node->getLeadingPaddingAndBorder(crossAxis, parentWidth); - const float paddingAndBorderAxisMain = YGNodePaddingAndBorderForAxis(node, mainAxis, parentWidth); + node->getLeadingPaddingAndBorder(crossAxis, ownerWidth); + const float paddingAndBorderAxisMain = YGNodePaddingAndBorderForAxis(node, mainAxis, ownerWidth); const float paddingAndBorderAxisCross = - YGNodePaddingAndBorderForAxis(node, crossAxis, parentWidth); + YGNodePaddingAndBorderForAxis(node, crossAxis, ownerWidth); YGMeasureMode measureModeMainDim = isMainAxisRow ? widthMeasureMode : heightMeasureMode; YGMeasureMode measureModeCrossDim = isMainAxisRow ? heightMeasureMode : widthMeasureMode; @@ -2612,22 +2612,22 @@ static void YGNodelayoutImpl(const YGNodeRef node, isMainAxisRow ? paddingAndBorderAxisCross : paddingAndBorderAxisMain; const float marginAxisRow = - node->getMarginForAxis(YGFlexDirectionRow, parentWidth); + node->getMarginForAxis(YGFlexDirectionRow, ownerWidth); const float marginAxisColumn = - node->getMarginForAxis(YGFlexDirectionColumn, parentWidth); + node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth); const float minInnerWidth = - YGUnwrapFloatOptional(YGResolveValue(node->getStyle().minDimensions[YGDimensionWidth], parentWidth)) - + YGUnwrapFloatOptional(YGResolveValue(node->getStyle().minDimensions[YGDimensionWidth], ownerWidth)) - paddingAndBorderAxisRow; const float maxInnerWidth = - YGUnwrapFloatOptional(YGResolveValue(node->getStyle().maxDimensions[YGDimensionWidth], parentWidth)) - + YGUnwrapFloatOptional(YGResolveValue(node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth)) - paddingAndBorderAxisRow; const float minInnerHeight = - YGUnwrapFloatOptional(YGResolveValue(node->getStyle().minDimensions[YGDimensionHeight], parentHeight)) - + YGUnwrapFloatOptional(YGResolveValue(node->getStyle().minDimensions[YGDimensionHeight], ownerHeight)) - paddingAndBorderAxisColumn; const float maxInnerHeight = YGUnwrapFloatOptional(YGResolveValue( - node->getStyle().maxDimensions[YGDimensionHeight], parentHeight)) - + node->getStyle().maxDimensions[YGDimensionHeight], ownerHeight)) - paddingAndBorderAxisColumn; const float minInnerMainDim = isMainAxisRow ? minInnerWidth : minInnerHeight; @@ -2636,9 +2636,9 @@ static void YGNodelayoutImpl(const YGNodeRef node, // STEP 2: DETERMINE AVAILABLE SIZE IN MAIN AND CROSS DIRECTIONS float availableInnerWidth = YGNodeCalculateAvailableInnerDim( - node, YGFlexDirectionRow, availableWidth, parentWidth); + node, YGFlexDirectionRow, availableWidth, ownerWidth); float availableInnerHeight = YGNodeCalculateAvailableInnerDim( - node, YGFlexDirectionColumn, availableHeight, parentHeight); + node, YGFlexDirectionColumn, availableHeight, ownerHeight); float availableInnerMainDim = isMainAxisRow ? availableInnerWidth : availableInnerHeight; @@ -2687,8 +2687,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, lineCount++, startOfLineIndex = endOfLineIndex) { collectedFlexItemsValues = YGCalculateCollectFlexItemsRowValues( node, - parentDirection, - mainAxisParentSize, + ownerDirection, + mainAxisownerSize, availableInnerWidth, availableInnerMainDim, startOfLineIndex, @@ -2756,7 +2756,7 @@ static void YGNodelayoutImpl(const YGNodeRef node, collectedFlexItemsValues, mainAxis, crossAxis, - mainAxisParentSize, + mainAxisownerSize, availableInnerMainDim, availableInnerCrossDim, availableInnerWidth, @@ -2788,8 +2788,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, crossAxis, measureModeMainDim, measureModeCrossDim, - mainAxisParentSize, - parentWidth, + mainAxisownerSize, + ownerWidth, availableInnerMainDim, availableInnerCrossDim, availableInnerWidth, @@ -2804,8 +2804,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, node, crossAxis, collectedFlexItemsValues.crossDim + paddingAndBorderAxisCross, - crossAxisParentSize, - parentWidth) - + crossAxisownerSize, + ownerWidth) - paddingAndBorderAxisCross; } @@ -2820,8 +2820,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, node, crossAxis, collectedFlexItemsValues.crossDim + paddingAndBorderAxisCross, - crossAxisParentSize, - parentWidth) - + crossAxisownerSize, + ownerWidth) - paddingAndBorderAxisCross; // STEP 7: CROSS-AXIS ALIGNMENT @@ -2856,7 +2856,7 @@ static void YGNodelayoutImpl(const YGNodeRef node, } else { float leadingCrossDim = leadingPaddingAndBorderCross; - // For a relative children, we're either using alignItems (parent) or + // For a relative children, we're either using alignItems (owner) or // alignSelf (child) in order to determine the position in the cross // axis const YGAlign alignItem = YGNodeAlignItem(node, child); @@ -3083,7 +3083,7 @@ static void YGNodelayoutImpl(const YGNodeRef node, pos[crossAxis]); // Remeasure child with the line height as it as been only measured with the - // parents height yet. + // owners height yet. if (!YGNodeIsStyleDimDefined(child, crossAxis, availableInnerCrossDim)) { const float childWidth = isMainAxisRow ? (child->getLayout() @@ -3150,8 +3150,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, node, YGFlexDirectionRow, availableWidth - marginAxisRow, - parentWidth, - parentWidth), + ownerWidth, + ownerWidth), YGDimensionWidth); node->setLayoutMeasuredDimension( @@ -3159,8 +3159,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, node, YGFlexDirectionColumn, availableHeight - marginAxisColumn, - parentHeight, - parentWidth), + ownerHeight, + ownerWidth), YGDimensionHeight); // If the user didn't specify a width or height for the node, set the @@ -3172,7 +3172,7 @@ static void YGNodelayoutImpl(const YGNodeRef node, // doesn't go below the padding and border amount. node->setLayoutMeasuredDimension( YGNodeBoundAxis( - node, mainAxis, maxLineMainDim, mainAxisParentSize, parentWidth), + node, mainAxis, maxLineMainDim, mainAxisownerSize, ownerWidth), dim[mainAxis]); } else if ( @@ -3183,7 +3183,7 @@ static void YGNodelayoutImpl(const YGNodeRef node, YGFloatMin( availableInnerMainDim + paddingAndBorderAxisMain, YGNodeBoundAxisWithinMinAndMax( - node, mainAxis, maxLineMainDim, mainAxisParentSize)), + node, mainAxis, maxLineMainDim, mainAxisownerSize)), paddingAndBorderAxisMain), dim[mainAxis]); } @@ -3199,8 +3199,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, node, crossAxis, totalLineCrossDim + paddingAndBorderAxisCross, - crossAxisParentSize, - parentWidth), + crossAxisownerSize, + ownerWidth), dim[crossAxis]); } else if ( @@ -3214,7 +3214,7 @@ static void YGNodelayoutImpl(const YGNodeRef node, node, crossAxis, totalLineCrossDim + paddingAndBorderAxisCross, - crossAxisParentSize)), + crossAxisownerSize)), paddingAndBorderAxisCross), dim[crossAxis]); } @@ -3435,11 +3435,11 @@ bool YGNodeCanUseCachedMeasurement(const YGMeasureMode widthMode, bool YGLayoutNodeInternal(const YGNodeRef node, const float availableWidth, const float availableHeight, - const YGDirection parentDirection, + const YGDirection ownerDirection, const YGMeasureMode widthMeasureMode, const YGMeasureMode heightMeasureMode, - const float parentWidth, - const float parentHeight, + const float ownerWidth, + const float ownerHeight, const bool performLayout, const char *reason, const YGConfigRef config) { @@ -3449,7 +3449,7 @@ bool YGLayoutNodeInternal(const YGNodeRef node, const bool needToVisitNode = (node->isDirty() && layout->generationCount != gCurrentGenerationCount) || - layout->lastParentDirection != parentDirection; + layout->lastOwnerDirection != ownerDirection; if (needToVisitNode) { // Invalidate the cached results. @@ -3476,9 +3476,9 @@ bool YGLayoutNodeInternal(const YGNodeRef node, // all possible. if (node->getMeasure() != nullptr) { const float marginAxisRow = - node->getMarginForAxis(YGFlexDirectionRow, parentWidth); + node->getMarginForAxis(YGFlexDirectionRow, ownerWidth); const float marginAxisColumn = - node->getMarginForAxis(YGFlexDirectionColumn, parentWidth); + node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth); // First, try to use the layout cache. if (YGNodeCanUseCachedMeasurement(widthMeasureMode, @@ -3582,11 +3582,11 @@ bool YGLayoutNodeInternal(const YGNodeRef node, YGNodelayoutImpl(node, availableWidth, availableHeight, - parentDirection, + ownerDirection, widthMeasureMode, heightMeasureMode, - parentWidth, - parentHeight, + ownerWidth, + ownerHeight, performLayout, config); @@ -3612,7 +3612,7 @@ bool YGLayoutNodeInternal(const YGNodeRef node, reason); } - layout->lastParentDirection = parentDirection; + layout->lastOwnerDirection = ownerDirection; if (cachedResults == nullptr) { if (layout->nextCachedMeasurementsIndex == YG_MAX_CACHED_RESULT_COUNT) { @@ -3742,9 +3742,9 @@ static void YGRoundToPixelGrid(const YGNodeRef node, void YGNodeCalculateLayout( const YGNodeRef node, - const float parentWidth, - const float parentHeight, - const YGDirection parentDirection) { + const float ownerWidth, + const float ownerHeight, + const YGDirection ownerDirection) { // Increment the generation count. This will force the recursive routine to // visit // all dirty nodes at least once. Subsequent visits will be skipped if the @@ -3754,40 +3754,40 @@ void YGNodeCalculateLayout( node->resolveDimension(); float width = YGUndefined; YGMeasureMode widthMeasureMode = YGMeasureModeUndefined; - if (YGNodeIsStyleDimDefined(node, YGFlexDirectionRow, parentWidth)) { + if (YGNodeIsStyleDimDefined(node, YGFlexDirectionRow, ownerWidth)) { width = YGUnwrapFloatOptional(YGResolveValue( - node->getResolvedDimension(dim[YGFlexDirectionRow]), parentWidth)) + - node->getMarginForAxis(YGFlexDirectionRow, parentWidth); + node->getResolvedDimension(dim[YGFlexDirectionRow]), ownerWidth)) + + node->getMarginForAxis(YGFlexDirectionRow, ownerWidth); widthMeasureMode = YGMeasureModeExactly; } else if (!YGResolveValue( - node->getStyle().maxDimensions[YGDimensionWidth], parentWidth) + node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth) .isUndefined()) { width = YGUnwrapFloatOptional(YGResolveValue( - node->getStyle().maxDimensions[YGDimensionWidth], parentWidth)); + node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth)); widthMeasureMode = YGMeasureModeAtMost; } else { - width = parentWidth; + width = ownerWidth; widthMeasureMode = YGFloatIsUndefined(width) ? YGMeasureModeUndefined : YGMeasureModeExactly; } float height = YGUndefined; YGMeasureMode heightMeasureMode = YGMeasureModeUndefined; - if (YGNodeIsStyleDimDefined(node, YGFlexDirectionColumn, parentHeight)) { + if (YGNodeIsStyleDimDefined(node, YGFlexDirectionColumn, ownerHeight)) { height = YGUnwrapFloatOptional(YGResolveValue( node->getResolvedDimension(dim[YGFlexDirectionColumn]), - parentHeight)) + - node->getMarginForAxis(YGFlexDirectionColumn, parentWidth); + ownerHeight)) + + node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth); heightMeasureMode = YGMeasureModeExactly; } else if (!YGResolveValue( node->getStyle().maxDimensions[YGDimensionHeight], - parentHeight) + ownerHeight) .isUndefined()) { - height = YGUnwrapFloatOptional(YGResolveValue(node->getStyle().maxDimensions[YGDimensionHeight], parentHeight)); + height = YGUnwrapFloatOptional(YGResolveValue(node->getStyle().maxDimensions[YGDimensionHeight], ownerHeight)); heightMeasureMode = YGMeasureModeAtMost; } else { - height = parentHeight; + height = ownerHeight; heightMeasureMode = YGFloatIsUndefined(height) ? YGMeasureModeUndefined : YGMeasureModeExactly; } @@ -3795,16 +3795,16 @@ void YGNodeCalculateLayout( node, width, height, - parentDirection, + ownerDirection, widthMeasureMode, heightMeasureMode, - parentWidth, - parentHeight, + ownerWidth, + ownerHeight, true, "initial", node->getConfig())) { node->setPosition( - node->getLayout().direction, parentWidth, parentHeight, parentWidth); + node->getLayout().direction, ownerWidth, ownerHeight, ownerWidth); YGRoundToPixelGrid(node, node->getConfig()->pointScaleFactor, 0.0f, 0.0f); if (gPrintTree) { @@ -3836,19 +3836,19 @@ void YGNodeCalculateLayout( originalNode, width, height, - parentDirection, + ownerDirection, widthMeasureMode, heightMeasureMode, - parentWidth, - parentHeight, + ownerWidth, + ownerHeight, true, "initial", originalNode->getConfig())) { originalNode->setPosition( originalNode->getLayout().direction, - parentWidth, - parentHeight, - parentWidth); + ownerWidth, + ownerHeight, + ownerWidth); YGRoundToPixelGrid( originalNode, originalNode->getConfig()->pointScaleFactor, diff --git a/ReactCommon/yoga/yoga/Yoga.h b/ReactCommon/yoga/yoga/Yoga.h index 73e7c7fdb1a28e..445c0b065d55f0 100644 --- a/ReactCommon/yoga/yoga/Yoga.h +++ b/ReactCommon/yoga/yoga/Yoga.h @@ -81,14 +81,14 @@ WIN_EXPORT void YGNodeInsertChild(const YGNodeRef node, WIN_EXPORT void YGNodeRemoveChild(const YGNodeRef node, const YGNodeRef child); WIN_EXPORT void YGNodeRemoveAllChildren(const YGNodeRef node); WIN_EXPORT YGNodeRef YGNodeGetChild(const YGNodeRef node, const uint32_t index); -WIN_EXPORT YGNodeRef YGNodeGetParent(const YGNodeRef node); +WIN_EXPORT YGNodeRef YGNodeGetOwner(const YGNodeRef node); WIN_EXPORT uint32_t YGNodeGetChildCount(const YGNodeRef node); WIN_EXPORT void YGNodeSetChildren(YGNodeRef const parent, const YGNodeRef children[], const uint32_t count); WIN_EXPORT void YGNodeCalculateLayout(const YGNodeRef node, const float availableWidth, const float availableHeight, - const YGDirection parentDirection); + const YGDirection ownerDirection); // Mark a node as dirty. Only valid for nodes with a custom measure function // set. From 5be4ff026162e342a4457d1df9750216ce84ac3c Mon Sep 17 00:00:00 2001 From: David Vacca Date: Sun, 1 Apr 2018 18:27:08 -0700 Subject: [PATCH 0176/1109] Extend Yoga to be able clone Yoga Node with new children Reviewed By: emilsjolander Differential Revision: D7245421 fbshipit-source-id: 72578c8261f29e4a12fc6c72a91f2f891cd58d48 --- .../main/java/com/facebook/yoga/YogaNode.java | 66 ++++++++++++++++--- .../jni/first-party/yogajni/jni/YGJNI.cpp | 16 +++++ ReactCommon/yoga/yoga/Yoga.cpp | 19 ++++-- ReactCommon/yoga/yoga/Yoga.h | 25 +++++-- 4 files changed, 108 insertions(+), 18 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java index ae5165e6384485..69bb3348b396cb 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java @@ -30,7 +30,7 @@ public class YogaNode implements Cloneable { static native int jni_YGNodeGetInstanceCount(); private YogaNode mOwner; - private List mChildren; + @Nullable private List mChildren; private YogaMeasureFunction mMeasureFunction; private YogaBaselineFunction mBaselineFunction; private long mNativePointer; @@ -147,6 +147,9 @@ public int getChildCount() { } public YogaNode getChildAt(int i) { + if (mChildren == null) { + throw new IllegalStateException("YogaNode does not have children"); + } return mChildren.get(i); } @@ -164,21 +167,62 @@ public void addChildAt(YogaNode child, int i) { jni_YGNodeInsertChild(mNativePointer, child.mNativePointer, i); } + private native void jni_YGNodeInsertSharedChild(long nativePointer, long childPointer, int index); + + public void addSharedChildAt(YogaNode child, int i) { + if (mChildren == null) { + mChildren = new ArrayList<>(4); + } + mChildren.add(i, child); + child.mOwner = null; + jni_YGNodeInsertSharedChild(mNativePointer, child.mNativePointer, i); + } + private native long jni_YGNodeClone(long nativePointer, Object newNode); @Override - public YogaNode clone() throws CloneNotSupportedException { - YogaNode clonedYogaNode = (YogaNode) super.clone(); - long clonedNativePointer = jni_YGNodeClone(mNativePointer, clonedYogaNode); - clonedYogaNode.mNativePointer = clonedNativePointer; - clonedYogaNode.mChildren = - mChildren != null ? (List) ((ArrayList) mChildren).clone() : null; - return clonedYogaNode; + public YogaNode clone() { + try { + YogaNode clonedYogaNode = (YogaNode) super.clone(); + long clonedNativePointer = jni_YGNodeClone(mNativePointer, clonedYogaNode); + clonedYogaNode.mNativePointer = clonedNativePointer; + clonedYogaNode.mOwner = null; + clonedYogaNode.mChildren = + mChildren != null ? (List) ((ArrayList) mChildren).clone() : null; + return clonedYogaNode; + } catch (CloneNotSupportedException ex) { + // This class implements Cloneable, this should not happen + throw new RuntimeException(ex); + } + } + + public YogaNode cloneWithNewChildren() { + try { + YogaNode clonedYogaNode = (YogaNode) super.clone(); + long clonedNativePointer = jni_YGNodeClone(mNativePointer, clonedYogaNode); + clonedYogaNode.mOwner = null; + clonedYogaNode.mNativePointer = clonedNativePointer; + clonedYogaNode.clearChildren(); + return clonedYogaNode; + } catch (CloneNotSupportedException ex) { + // This class implements Cloneable, this should not happen + throw new RuntimeException(ex); + } + } + + private native void jni_YGNodeClearChildren(long nativePointer); + + private void clearChildren() { + mChildren = null; + jni_YGNodeClearChildren(mNativePointer); } private native void jni_YGNodeRemoveChild(long nativePointer, long childPointer); public YogaNode removeChildAt(int i) { - + if (mChildren == null) { + throw new IllegalStateException( + "Trying to remove a child of a YogaNode that does not have children"); + } final YogaNode child = mChildren.remove(i); child.mOwner = null; jni_YGNodeRemoveChild(mNativePointer, child.mNativePointer); @@ -715,8 +759,12 @@ public void print() { */ @DoNotStrip private final long replaceChild(YogaNode newNode, int childIndex) { + if (mChildren == null) { + throw new IllegalStateException("Cannot replace child. YogaNode does not have children"); + } mChildren.remove(childIndex); mChildren.add(childIndex, newNode); + newNode.mOwner = this; return newNode.mNativePointer; } } 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 b303ce223a92ff..69cbb38115c4d9 100644 --- a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp +++ b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp @@ -284,6 +284,11 @@ void jni_YGNodeFree(alias_ref thiz, jlong nativePointer) { YGNodeFree(node); } +void jni_YGNodeClearChildren(alias_ref thiz, jlong nativePointer) { + const YGNodeRef node = _jlong2YGNodeRef(nativePointer); + node->clearChildren(); +} + void jni_YGNodeReset(alias_ref thiz, jlong nativePointer) { const YGNodeRef node = _jlong2YGNodeRef(nativePointer); void* context = node->getContext(); @@ -303,6 +308,15 @@ void jni_YGNodeInsertChild(alias_ref, jlong nativePointer, jlong childP YGNodeInsertChild(_jlong2YGNodeRef(nativePointer), _jlong2YGNodeRef(childPointer), index); } +void jni_YGNodeInsertSharedChild( + alias_ref, + jlong nativePointer, + jlong childPointer, + jint index) { + YGNodeInsertSharedChild( + _jlong2YGNodeRef(nativePointer), _jlong2YGNodeRef(childPointer), index); +} + void jni_YGNodeRemoveChild(alias_ref, jlong nativePointer, jlong childPointer) { YGNodeRemoveChild(_jlong2YGNodeRef(nativePointer), _jlong2YGNodeRef(childPointer)); } @@ -577,7 +591,9 @@ jint JNI_OnLoad(JavaVM *vm, void *) { YGMakeNativeMethod(jni_YGNodeNewWithConfig), YGMakeNativeMethod(jni_YGNodeFree), YGMakeNativeMethod(jni_YGNodeReset), + YGMakeNativeMethod(jni_YGNodeClearChildren), YGMakeNativeMethod(jni_YGNodeInsertChild), + YGMakeNativeMethod(jni_YGNodeInsertSharedChild), YGMakeNativeMethod(jni_YGNodeRemoveChild), YGMakeNativeMethod(jni_YGNodeCalculateLayout), YGMakeNativeMethod(jni_YGNodeMarkDirty), diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index 2e5979a2dd0f91..7518e858603ac5 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -391,16 +391,27 @@ void YGConfigCopy(const YGConfigRef dest, const YGConfigRef src) { void YGNodeInsertChild(const YGNodeRef node, const YGNodeRef child, const uint32_t index) { YGAssertWithNode( node, - child->getOwner() == nullptr, - "Child already has a owner, it must be removed first."); + node->getMeasure() == nullptr, + "Cannot add child: Nodes with measure functions cannot have children."); + + node->cloneChildrenIfNeeded(); + node->insertChild(child, index); + YGNodeRef owner = child->getOwner() ? nullptr : node; + child->setOwner(owner); + node->markDirtyAndPropogate(); +} + +void YGNodeInsertSharedChild( + const YGNodeRef node, + const YGNodeRef child, + const uint32_t index) { YGAssertWithNode( node, node->getMeasure() == nullptr, "Cannot add child: Nodes with measure functions cannot have children."); - node->cloneChildrenIfNeeded(); node->insertChild(child, index); - child->setOwner(node); + child->setOwner(nullptr); node->markDirtyAndPropogate(); } diff --git a/ReactCommon/yoga/yoga/Yoga.h b/ReactCommon/yoga/yoga/Yoga.h index 445c0b065d55f0..25eb0eb6f5a821 100644 --- a/ReactCommon/yoga/yoga/Yoga.h +++ b/ReactCommon/yoga/yoga/Yoga.h @@ -62,9 +62,8 @@ typedef int (*YGLogger)(const YGConfigRef config, YGLogLevel level, const char *format, va_list args); -typedef YGNodeRef (*YGCloneNodeFunc)(YGNodeRef oldNode, - YGNodeRef parent, - int childIndex); +typedef YGNodeRef ( + *YGCloneNodeFunc)(YGNodeRef oldNode, YGNodeRef owner, int childIndex); // YGNode WIN_EXPORT YGNodeRef YGNodeNew(void); @@ -78,12 +77,26 @@ WIN_EXPORT int32_t YGNodeGetInstanceCount(void); WIN_EXPORT void YGNodeInsertChild(const YGNodeRef node, const YGNodeRef child, const uint32_t index); + +// This function inserts the child YGNodeRef as a children of the node received +// by parameter and set the Owner of the child object to null. This function is +// expected to be called when using Yoga in persistent mode in order to share a +// YGNodeRef object as a child of two different Yoga trees. The child YGNodeRef +// is expected to be referenced from its original owner and from a clone of its +// original owner. +WIN_EXPORT void YGNodeInsertSharedChild( + const YGNodeRef node, + const YGNodeRef child, + const uint32_t index); WIN_EXPORT void YGNodeRemoveChild(const YGNodeRef node, const YGNodeRef child); WIN_EXPORT void YGNodeRemoveAllChildren(const YGNodeRef node); WIN_EXPORT YGNodeRef YGNodeGetChild(const YGNodeRef node, const uint32_t index); WIN_EXPORT YGNodeRef YGNodeGetOwner(const YGNodeRef node); WIN_EXPORT uint32_t YGNodeGetChildCount(const YGNodeRef node); -WIN_EXPORT void YGNodeSetChildren(YGNodeRef const parent, const YGNodeRef children[], const uint32_t count); +WIN_EXPORT void YGNodeSetChildren( + YGNodeRef const owner, + const YGNodeRef children[], + const uint32_t count); WIN_EXPORT void YGNodeCalculateLayout(const YGNodeRef node, const float availableWidth, @@ -307,6 +320,8 @@ YG_EXTERN_C_END // Calls f on each node in the tree including the given node argument. extern void YGTraversePreOrder(YGNodeRef const node, std::function&& f); -extern void YGNodeSetChildren(YGNodeRef const parent, const std::vector &children); +extern void YGNodeSetChildren( + YGNodeRef const owner, + const std::vector& children); #endif From 8a99241f8134e7f58fe14557f0d70fcb6a96d226 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Sun, 1 Apr 2018 18:27:11 -0700 Subject: [PATCH 0177/1109] Re-enable Yoga cloning in React Shadow Node Reviewed By: achen1 Differential Revision: D7435365 fbshipit-source-id: 3e04b3252945112cf0c7206b0e6fb63535499eb9 --- .../java/com/facebook/react/fabric/FabricReconciler.java | 3 --- .../com/facebook/react/uimanager/ReactShadowNodeImpl.java | 8 ++------ 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java index cc851c228fe281..3e8eca9cabeb73 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java @@ -96,9 +96,6 @@ private void manageChildren( indicesToRemove.add(0, j); if (!addedTags.contains(nodeToRemove.getReactTag())) { tagsToDelete.add(nodeToRemove.getReactTag()); - // TODO: T26729293 since we are not cloning ReactShadowNode's we need to "manually" remove - // from the ReactShadowTree when one of the nodes is deleted in JS. - nodeToRemove.getParent().removeChildAt(j); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java index 53a27c440b76ec..c5727e664e4c1b 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java @@ -150,9 +150,7 @@ protected ReactShadowNodeImpl copy() { @Override public ReactShadowNodeImpl mutableCopy() { ReactShadowNodeImpl copy = copy(); - copy.mYogaNode = mYogaNode; - // TODO: T26729293 clone YogaNode instead of reusing the same instance - //copy.mYogaNode = mYogaNode.clone(); + copy.mYogaNode = mYogaNode.clone(); copy.mNativeChildren = mNativeChildren == null ? null : new ArrayList<>(mNativeChildren); copy.mTotalNativeChildren = mTotalNativeChildren; copy.mChildren = mChildren == null ? null : new ArrayList<>(mChildren); @@ -170,9 +168,7 @@ public ReactShadowNodeImpl mutableCopy() { @Override public ReactShadowNodeImpl mutableCopyWithNewChildren() { ReactShadowNodeImpl copy = copy(); - copy.mYogaNode = mYogaNode; - // TODO: T26729293 clone YogaNode instead of reusing the same instance - //copy.mYogaNode = mYogaNode.clone(); + copy.mYogaNode = mYogaNode.cloneWithNewChildren(); copy.mNativeChildren = null; copy.mChildren = null; copy.mTotalNativeChildren = 0; From d4fb87b0b873f035872eca1eccf737d509838250 Mon Sep 17 00:00:00 2001 From: Christian Brevik Date: Mon, 2 Apr 2018 02:31:16 -0700 Subject: [PATCH 0178/1109] Add iOS 10 textContentType for TextInput Summary: Setting `textContentType` will provide the keyboard and system with semantic meaning for inputs. Should enable password/username autofill in apps running on iOS 11+ as demonstrated here: https://developer.apple.com/videos/play/wwdc2017/206/ Also gives you the ability to disable autofill by setting `textContentType="none"`: https://stackoverflow.com/questions/48489479/react-native-disable-password-autofill-option-on-ios-keyboard Adding `textContentType` equal to `username` or `password` should give you an autofill-bar over the keyboard which will let you fill in values from the device Keychain: ![image](https://user-images.githubusercontent.com/4932625/37848513-b2170490-2ed4-11e8-85bf-895823d4f98a.png) Setting the appropriate `textContentType` will fill in the correct value in the `TextInput`. I have only been able to get this to work on device, and not simulator. Usage: ```jsx ``` ```jsx ``` To disable: ```jsx ``` This will set `textContentType` to an empty string: https://stackoverflow.com/a/46474180/5703116 Docs PR coming up. [IOS] [MINOR] [TextInput] - Added `textContentType` prop for iOS 10+. Will enable password autofill for iOS 11+. Closes https://github.com/facebook/react-native/pull/18526 Differential Revision: D7469630 Pulled By: hramos fbshipit-source-id: 852a9749be98d477ecd82154c0a65a7c084521c1 --- Libraries/Components/TextInput/TextInput.js | 33 +++++++++++++++++++ .../Text/TextInput/RCTBaseTextInputView.m | 11 +++++++ .../TextInput/RCTBaseTextInputViewManager.m | 1 + 3 files changed, 45 insertions(+) diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js index 2c6c4f8ef19b2e..eb838174f15184 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -605,6 +605,39 @@ const TextInput = createReactClass({ * @platform ios */ inputAccessoryViewID: PropTypes.string, + /** + * Give the keyboard and the system information about the + * expected semantic meaning for the content that users enter. + * @platform ios + */ + textContentType: PropTypes.oneOf([ + 'none', + 'URL', + 'addressCity', + 'addressCityAndState', + 'addressState', + 'countryName', + 'creditCardNumber', + 'emailAddress', + 'familyName', + 'fullStreetAddress', + 'givenName', + 'jobTitle', + 'location', + 'middleName', + 'name', + 'namePrefix', + 'nameSuffix', + 'nickname', + 'organizationName', + 'postalCode', + 'streetAddressLine1', + 'streetAddressLine2', + 'sublocality', + 'telephoneNumber', + 'username', + 'password', + ]), }, getDefaultProps(): Object { return { diff --git a/Libraries/Text/TextInput/RCTBaseTextInputView.m b/Libraries/Text/TextInput/RCTBaseTextInputView.m index 64a3a865c6d7e7..cbfa24d1ab4f8d 100644 --- a/Libraries/Text/TextInput/RCTBaseTextInputView.m +++ b/Libraries/Text/TextInput/RCTBaseTextInputView.m @@ -167,6 +167,17 @@ - (void)setSelection:(RCTTextSelection *)selection } } +- (void)setTextContentType:(NSString *)type +{ + #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0 + if (@available(iOS 10.0, *)) { + // Setting textContentType to an empty string will disable any + // default behaviour, like the autofill bar for password inputs + self.backedTextInputView.textContentType = [type isEqualToString:@"none"] ? @"" : type; + } + #endif +} + #pragma mark - RCTBackedTextInputDelegate - (BOOL)textInputShouldBeginEditing diff --git a/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m b/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m index aaead20b0b9c1c..42266eacfb91a4 100644 --- a/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m +++ b/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m @@ -55,6 +55,7 @@ @implementation RCTBaseTextInputViewManager RCT_EXPORT_VIEW_PROPERTY(selectTextOnFocus, BOOL) RCT_EXPORT_VIEW_PROPERTY(selection, RCTTextSelection) RCT_EXPORT_VIEW_PROPERTY(inputAccessoryViewID, NSString) +RCT_EXPORT_VIEW_PROPERTY(textContentType, NSString) RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock) RCT_EXPORT_VIEW_PROPERTY(onSelectionChange, RCTDirectEventBlock) From 201e74f9b7bc2814a4ecdba16fd425e999798532 Mon Sep 17 00:00:00 2001 From: Douglas Lowder Date: Mon, 2 Apr 2018 22:20:34 -0700 Subject: [PATCH 0179/1109] Fix tvOS build breakage in RCTAnimation Xcode project Summary: `RCTSubtractionAnimatedNode.m` was not added to the tvOS build of RCTAnimation... this PR fixes the issue. tvOS CI should succeed after this change. [TVOS] [BUGFIX] [RCTAnimation] Fix build breakage Closes https://github.com/facebook/react-native/pull/18663 Differential Revision: D7483586 Pulled By: hramos fbshipit-source-id: 521152d829b064b7002dc8651a0558373c5505f8 --- .../NativeAnimation/RCTAnimation.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Libraries/NativeAnimation/RCTAnimation.xcodeproj/project.pbxproj b/Libraries/NativeAnimation/RCTAnimation.xcodeproj/project.pbxproj index 08a629eaeccac2..b55c034809b462 100644 --- a/Libraries/NativeAnimation/RCTAnimation.xcodeproj/project.pbxproj +++ b/Libraries/NativeAnimation/RCTAnimation.xcodeproj/project.pbxproj @@ -111,6 +111,7 @@ 2D3B5EFE1D9B0B4800451313 /* RCTStyleAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501E31D07A6C9005F35D8 /* RCTStyleAnimatedNode.m */; }; 2D3B5EFF1D9B0B4800451313 /* RCTTransformAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501E51D07A6C9005F35D8 /* RCTTransformAnimatedNode.m */; }; 2D3B5F001D9B0B4800451313 /* RCTValueAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501E71D07A6C9005F35D8 /* RCTValueAnimatedNode.m */; }; + 2D65C80020732E4700C62FDF /* RCTSubtractionAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 2EC00630206EA19300586E91 /* RCTSubtractionAnimatedNode.m */; }; 2EC00631206EA19300586E91 /* RCTSubtractionAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 2EC00630206EA19300586E91 /* RCTSubtractionAnimatedNode.m */; }; 44DB7D942024F74200588FCD /* RCTTrackingAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 44DB7D932024F74200588FCD /* RCTTrackingAnimatedNode.h */; }; 44DB7D952024F74200588FCD /* RCTTrackingAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 44DB7D932024F74200588FCD /* RCTTrackingAnimatedNode.h */; }; @@ -462,6 +463,7 @@ 944244D11DB962DC0032A02B /* RCTSpringAnimation.m in Sources */, 9476E8EC1DC9232D005D5CD1 /* RCTNativeAnimatedNodesManager.m in Sources */, 194804F21E977DDB00623005 /* RCTDecayAnimation.m in Sources */, + 2D65C80020732E4700C62FDF /* RCTSubtractionAnimatedNode.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From 976712afa3e350f3e8d18287b8292f63d274702e Mon Sep 17 00:00:00 2001 From: Paco Estevez Garcia Date: Tue, 3 Apr 2018 05:59:07 -0700 Subject: [PATCH 0180/1109] Replace RN exception handling override with new version Reviewed By: Hypuk Differential Revision: D7385541 fbshipit-source-id: 287d3f4d681046f740ed0552e00a2249c3803a0b --- Libraries/BatchedBridge/BatchedBridge.js | 15 +---- Libraries/BatchedBridge/MessageQueue.js | 54 ++++++++-------- .../__tests__/MessageQueue-test.js | 64 +++++-------------- 3 files changed, 43 insertions(+), 90 deletions(-) diff --git a/Libraries/BatchedBridge/BatchedBridge.js b/Libraries/BatchedBridge/BatchedBridge.js index bfc6862cb83551..516c2ac1e22339 100644 --- a/Libraries/BatchedBridge/BatchedBridge.js +++ b/Libraries/BatchedBridge/BatchedBridge.js @@ -11,20 +11,7 @@ const MessageQueue = require('MessageQueue'); -// MessageQueue can install a global handler to catch all exceptions where JS users can register their own behavior -// This handler makes all exceptions to be handled inside MessageQueue rather than by the VM at its origin -// This makes stacktraces to be placed at MessageQueue rather than at where they were launched -// The parameter __fbUninstallRNGlobalErrorHandler is passed to MessageQueue to prevent the handler from being installed -// -// __fbUninstallRNGlobalErrorHandler is conditionally set by the Inspector while the VM is paused for initialization -// If the Inspector isn't present it defaults to undefined and the global error handler is installed -// The Inspector can still call MessageQueue#uninstallGlobalErrorHandler to uninstalled on attach - -const BatchedBridge = new MessageQueue( - // $FlowFixMe - typeof __fbUninstallRNGlobalErrorHandler !== 'undefined' && - __fbUninstallRNGlobalErrorHandler === true, // eslint-disable-line no-undef -); +const BatchedBridge = new MessageQueue(); // Wire up the batched bridge on the global object so that we can call into it. // Ideally, this would be the inverse relationship. I.e. the native environment diff --git a/Libraries/BatchedBridge/MessageQueue.js b/Libraries/BatchedBridge/MessageQueue.js index 98662c28cc6dfb..ef689333917db1 100644 --- a/Libraries/BatchedBridge/MessageQueue.js +++ b/Libraries/BatchedBridge/MessageQueue.js @@ -57,9 +57,7 @@ class MessageQueue { __spy: ?(data: SpyData) => void; - __guard: (() => void) => void; - - constructor(shouldUninstallGlobalErrorHandler: boolean = false) { + constructor() { this._lazyCallableModules = {}; this._queue = [[], [], [], 0]; this._successCallbacks = {}; @@ -67,11 +65,6 @@ class MessageQueue { this._callID = 0; this._lastFlush = 0; this._eventLoopStartTime = new Date().getTime(); - if (shouldUninstallGlobalErrorHandler) { - this.uninstallGlobalErrorHandler(); - } else { - this.installGlobalErrorHandler(); - } if (__DEV__) { this._debugInfo = {}; @@ -289,34 +282,39 @@ class MessageQueue { } } - uninstallGlobalErrorHandler() { - this.__guard = this.__guardUnsafe; - } - - installGlobalErrorHandler() { - this.__guard = this.__guardSafe; - } - /** * Private methods */ - // Lets exceptions propagate to be handled by the VM at the origin - __guardUnsafe(fn: () => void) { + __guard(fn: () => void) { this._inCall++; - fn(); + if (this.__shouldPauseOnThrow()) { + fn(); + } else { + try { + fn(); + } catch (error) { + ErrorUtils.reportFatalError(error); + } + } this._inCall--; } - __guardSafe(fn: () => void) { - this._inCall++; - try { - fn(); - } catch (error) { - ErrorUtils.reportFatalError(error); - } finally { - this._inCall--; - } + // MessageQueue installs a global handler to catch all exceptions where JS users can register their own behavior + // This handler makes all exceptions to be propagated from inside MessageQueue rather than by the VM at their origin + // This makes stacktraces to be placed at MessageQueue rather than at where they were launched + // The parameter DebuggerInternal.shouldPauseOnThrow is used to check before catching all exceptions and + // can be configured by the VM or any Inspector + __shouldPauseOnThrow() { + return ( + // $FlowFixMe + (typeof DebuggerInternal !== 'undefined' && + DebuggerInternal.shouldPauseOnThrow === true) || // eslint-disable-line no-undef + // FIXME(festevezga) Remove once T24034309 is rolled out internally + // $FlowFixMe + (typeof __fbUninstallRNGlobalErrorHandler !== 'undefined' && + __fbUninstallRNGlobalErrorHandler === true) // eslint-disable-line no-undef + ); } __callImmediates() { diff --git a/Libraries/BatchedBridge/__tests__/MessageQueue-test.js b/Libraries/BatchedBridge/__tests__/MessageQueue-test.js index ecf60bcd0455cc..555a9e2053be33 100644 --- a/Libraries/BatchedBridge/__tests__/MessageQueue-test.js +++ b/Libraries/BatchedBridge/__tests__/MessageQueue-test.js @@ -125,59 +125,27 @@ describe('MessageQueue', function() { expect(factory).toHaveBeenCalledTimes(1); }); - it('should catch all exceptions if the global error handler is installed', () => { - const errorMessage = 'intentional error'; - const errorModule = { - explode: function() { - throw new Error(errorMessage); - }, + it('should check if the global error handler is not overriden by the DebuggerInternal object', () => { + const dummyModule = { + dummy: function() {}, }; - const name = 'errorModuleName'; - const factory = jest.fn(() => errorModule); - queue.__guardSafe = jest.fn(() => {}); - queue.__guardUnsafe = jest.fn(() => {}); - queue.installGlobalErrorHandler(); - queue.registerLazyCallableModule(name, factory); - queue.callFunctionReturnFlushedQueue(name, 'explode', []); - expect(queue.__guardUnsafe).toHaveBeenCalledTimes(0); - expect(queue.__guardSafe).toHaveBeenCalledTimes(2); - }); - - it('should propagate exceptions if the global error handler is uninstalled', () => { - queue.uninstallGlobalErrorHandler(); - const errorMessage = 'intentional error'; - const errorModule = { - explode: function() { - throw new Error(errorMessage); - }, - }; - const name = 'errorModuleName'; - const factory = jest.fn(() => errorModule); - queue.__guardUnsafe = jest.fn(() => {}); - queue.__guardSafe = jest.fn(() => {}); + const name = 'emptyModuleName'; + const factory = jest.fn(() => dummyModule); + queue.__shouldPauseOnThrow = jest.fn(() => false); queue.registerLazyCallableModule(name, factory); - queue.uninstallGlobalErrorHandler(); - queue.callFunctionReturnFlushedQueue(name, 'explode'); - expect(queue.__guardUnsafe).toHaveBeenCalledTimes(2); - expect(queue.__guardSafe).toHaveBeenCalledTimes(0); + queue.callFunctionReturnFlushedQueue(name, 'dummy', []); + expect(queue.__shouldPauseOnThrow).toHaveBeenCalledTimes(2); }); - it('should catch all exceptions if the global error handler is re-installed', () => { - const errorMessage = 'intentional error'; - const errorModule = { - explode: function() { - throw new Error(errorMessage); - }, + it('should check if the global error handler is overriden by the DebuggerInternal object', () => { + const dummyModule = { + dummy: function() {}, }; - const name = 'errorModuleName'; - const factory = jest.fn(() => errorModule); - queue.__guardUnsafe = jest.fn(() => {}); - queue.__guardSafe = jest.fn(() => {}); + const name = 'emptyModuleName'; + const factory = jest.fn(() => dummyModule); + queue.__shouldPauseOnThrow = jest.fn(() => true); queue.registerLazyCallableModule(name, factory); - queue.uninstallGlobalErrorHandler(); - queue.installGlobalErrorHandler(); - queue.callFunctionReturnFlushedQueue(name, 'explode'); - expect(queue.__guardUnsafe).toHaveBeenCalledTimes(0); - expect(queue.__guardSafe).toHaveBeenCalledTimes(2); + queue.callFunctionReturnFlushedQueue(name, 'dummy', []); + expect(queue.__shouldPauseOnThrow).toHaveBeenCalledTimes(2); }); }); From e5a4d59244caaae64a08575b0f928033edcd661f Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Tue, 3 Apr 2018 14:56:27 -0700 Subject: [PATCH 0181/1109] Remove the usage of YGUndefined for kYGValueAuto and fix setter and getter of dimensions Reviewed By: emilsjolander Differential Revision: D7302453 fbshipit-source-id: e002a1ddd75bfc6fe142a7275e7913c064972e16 --- ReactCommon/yoga/yoga/YGStyle.cpp | 4 ++-- ReactCommon/yoga/yoga/Yoga.cpp | 28 ++++++++++++++++------------ 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/ReactCommon/yoga/yoga/YGStyle.cpp b/ReactCommon/yoga/yoga/YGStyle.cpp index 437b682d614607..66e4d04ccccfc3 100644 --- a/ReactCommon/yoga/yoga/YGStyle.cpp +++ b/ReactCommon/yoga/yoga/YGStyle.cpp @@ -9,7 +9,7 @@ const YGValue kYGValueUndefined = {0, YGUnitUndefined}; -const YGValue kYGValueAuto = {YGUndefined, YGUnitAuto}; +const YGValue kYGValueAuto = {0, YGUnitAuto}; const std::array kYGDefaultEdgeValuesUnit = { {kYGValueUndefined, @@ -42,7 +42,7 @@ YGStyle::YGStyle() flex(YGFloatOptional()), flexGrow(YGFloatOptional()), flexShrink(YGFloatOptional()), - flexBasis({0, YGUnitAuto}), + flexBasis(kYGValueAuto), margin(kYGDefaultEdgeValuesUnit), position(kYGDefaultEdgeValuesUnit), padding(kYGDefaultEdgeValuesUnit), diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index 7518e858603ac5..b13b28e1cbbeab 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -629,7 +629,7 @@ float YGNodeStyleGetFlexShrink(const YGNodeRef node) { type, name, paramName, instanceName) \ void YGNodeStyleSet##name(const YGNodeRef node, const type paramName) { \ YGValue value = { \ - .value = paramName, \ + .value = YGFloatSanitize(paramName), \ .unit = YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \ }; \ if ((node->getStyle().instanceName.value != value.value && \ @@ -644,10 +644,10 @@ float YGNodeStyleGetFlexShrink(const YGNodeRef node) { \ void YGNodeStyleSet##name##Percent( \ const YGNodeRef node, const type paramName) { \ - if (node->getStyle().instanceName.value != paramName || \ + if (node->getStyle().instanceName.value != YGFloatSanitize(paramName) || \ node->getStyle().instanceName.unit != YGUnitPercent) { \ YGStyle style = node->getStyle(); \ - style.instanceName.value = paramName; \ + style.instanceName.value = YGFloatSanitize(paramName); \ style.instanceName.unit = \ YGFloatIsUndefined(paramName) ? YGUnitAuto : YGUnitPercent; \ node->setStyle(style); \ @@ -658,7 +658,7 @@ float YGNodeStyleGetFlexShrink(const YGNodeRef node) { void YGNodeStyleSet##name##Auto(const YGNodeRef node) { \ if (node->getStyle().instanceName.unit != YGUnitAuto) { \ YGStyle style = node->getStyle(); \ - style.instanceName.value = YGUndefined; \ + style.instanceName.value = 0; \ style.instanceName.unit = YGUnitAuto; \ node->setStyle(style); \ node->markDirtyAndPropogate(); \ @@ -678,19 +678,23 @@ float YGNodeStyleGetFlexShrink(const YGNodeRef node) { \ type YGNodeStyleGet##name(const YGNodeRef node) { \ YGValue value = node->getStyle().instanceName; \ - if (value.unit == YGUndefined || value.unit == YGUnitAuto) { \ + if (value.unit == YGUnitUndefined || value.unit == YGUnitAuto) { \ value.value = YGUndefined; \ } \ return value; \ } -#define YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL( \ - type, name, paramName, instanceName) \ - YG_NODE_STYLE_PROPERTY_SETTER_UNIT_AUTO_IMPL( \ - float, name, paramName, instanceName) \ - \ - type YGNodeStyleGet##name(const YGNodeRef node) { \ - return node->getStyle().instanceName; \ +#define YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL( \ + type, name, paramName, instanceName) \ + YG_NODE_STYLE_PROPERTY_SETTER_UNIT_AUTO_IMPL( \ + float, name, paramName, instanceName) \ + \ + type YGNodeStyleGet##name(const YGNodeRef node) { \ + YGValue value = node->getStyle().instanceName; \ + if (value.unit == YGUnitUndefined || value.unit == YGUnitAuto) { \ + value.value = YGUndefined; \ + } \ + return value; \ } #define YG_NODE_STYLE_EDGE_PROPERTY_UNIT_AUTO_IMPL(type, name, instanceName) \ From bcd12f1e87634343efe238691a535eabfcc21260 Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Tue, 3 Apr 2018 14:56:29 -0700 Subject: [PATCH 0182/1109] Change the type of aspect Ratio to YGFloatOptional Reviewed By: emilsjolander Differential Revision: D7302651 fbshipit-source-id: 53e3b4c9627207a379f927b1f3485e36a9c70601 --- .../fabric/view/yoga/YogaStylableProps.cpp | 4 +- ReactCommon/yoga/yoga/YGStyle.cpp | 9 ++- ReactCommon/yoga/yoga/YGStyle.h | 2 +- ReactCommon/yoga/yoga/Yoga.cpp | 62 ++++++++++++------- 4 files changed, 47 insertions(+), 30 deletions(-) diff --git a/ReactCommon/fabric/view/yoga/YogaStylableProps.cpp b/ReactCommon/fabric/view/yoga/YogaStylableProps.cpp index 24a2ca5682da69..c13e3462dfce93 100644 --- a/ReactCommon/fabric/view/yoga/YogaStylableProps.cpp +++ b/ReactCommon/fabric/view/yoga/YogaStylableProps.cpp @@ -95,7 +95,7 @@ void YogaStylableProps::apply(const RawProps &rawProps) { YOGA_STYLE_PREFIXED_EDGE_PROPERTY(padding) YOGA_STYLE_PREFIXED_EDGE_PROPERTY(border) - YOGA_STYLE_SIMPLE_FLOAT_PROPERTY(aspectRatio) + YOGA_STYLE_OPTIONAL_FLOAT_PROPERTY(aspectRatio) } } @@ -139,7 +139,7 @@ SharedDebugStringConvertibleList YogaStylableProps::getDebugProps() const { YOGA_STYLE_PROPS_ADD_TO_SET(minSize, minDimensions, , stringFromYogaStyleDimensions) YOGA_STYLE_PROPS_ADD_TO_SET(maxSize, maxDimensions, , stringFromYogaStyleDimensions) - YOGA_STYLE_PROPS_ADD_TO_SET(aspectRatio, aspectRatio, , folly::to) + YOGA_STYLE_PROPS_ADD_TO_SET(aspectRatio, aspectRatio, , stringFromYogaStyleOptionalFloat) return list; } diff --git a/ReactCommon/yoga/yoga/YGStyle.cpp b/ReactCommon/yoga/yoga/YGStyle.cpp index 66e4d04ccccfc3..7664dcf8e59cb3 100644 --- a/ReactCommon/yoga/yoga/YGStyle.cpp +++ b/ReactCommon/yoga/yoga/YGStyle.cpp @@ -50,7 +50,7 @@ YGStyle::YGStyle() dimensions(kYGDefaultDimensionValuesAutoUnit), minDimensions(kYGDefaultDimensionValuesUnit), maxDimensions(kYGDefaultDimensionValuesUnit), - aspectRatio(YGUndefined) {} + aspectRatio(YGFloatOptional()) {} // Yoga specific properties, not compatible with flexbox specification bool YGStyle::operator==(const YGStyle& style) { @@ -91,10 +91,9 @@ bool YGStyle::operator==(const YGStyle& style) { flexShrink.getValue() == style.flexShrink.getValue(); } - if (!(YGFloatIsUndefined(aspectRatio) && - YGFloatIsUndefined(style.aspectRatio))) { - areNonFloatValuesEqual = - areNonFloatValuesEqual && aspectRatio == style.aspectRatio; + if (!(aspectRatio.isUndefined() && style.aspectRatio.isUndefined())) { + areNonFloatValuesEqual = areNonFloatValuesEqual && + aspectRatio.getValue() == style.aspectRatio.getValue(); } return areNonFloatValuesEqual; diff --git a/ReactCommon/yoga/yoga/YGStyle.h b/ReactCommon/yoga/yoga/YGStyle.h index 7a7f519a5f9b67..f0f97bd8faf1f0 100644 --- a/ReactCommon/yoga/yoga/YGStyle.h +++ b/ReactCommon/yoga/yoga/YGStyle.h @@ -32,7 +32,7 @@ struct YGStyle { std::array dimensions; std::array minDimensions; std::array maxDimensions; - float aspectRatio; + YGFloatOptional aspectRatio; YGStyle(); // Yoga specific properties, not compatible with flexbox specification diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index b13b28e1cbbeab..f00133e2fe8961 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -930,16 +930,30 @@ float YGNodeStyleGetBorder(const YGNodeRef node, const YGEdge edge) { return node->getStyle().border[edge].value; } +// Yoga specific properties, not compatible with flexbox specification + +// TODO(T26792433): Change the API to accept YGFloatOptional. +float YGNodeStyleGetAspectRatio(const YGNodeRef node) { + const YGFloatOptional op = node->getStyle().aspectRatio; + return op.isUndefined() ? YGUndefined : op.getValue(); +} + +// TODO(T26792433): Change the API to accept YGFloatOptional. +void YGNodeStyleSetAspectRatio(const YGNodeRef node, const float aspectRatio) { + if (!YGFloatOptionalFloatEquals(node->getStyle().aspectRatio, aspectRatio)) { + YGStyle style = node->getStyle(); + style.aspectRatio = YGFloatOptional(aspectRatio); + node->setStyle(style); + node->markDirtyAndPropogate(); + } +} + YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(YGValue, Width, width, dimensions[YGDimensionWidth]); YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(YGValue, Height, height, dimensions[YGDimensionHeight]); YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, MinWidth, minWidth, minDimensions[YGDimensionWidth]); YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, MinHeight, minHeight, minDimensions[YGDimensionHeight]); YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, MaxWidth, maxWidth, maxDimensions[YGDimensionWidth]); YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, MaxHeight, maxHeight, maxDimensions[YGDimensionHeight]); - -// Yoga specific properties, not compatible with flexbox specification -YG_NODE_STYLE_PROPERTY_IMPL(float, AspectRatio, aspectRatio, aspectRatio); - YG_NODE_LAYOUT_PROPERTY_IMPL(float, Left, position[YGEdgeLeft]); YG_NODE_LAYOUT_PROPERTY_IMPL(float, Top, position[YGEdgeTop]); YG_NODE_LAYOUT_PROPERTY_IMPL(float, Right, position[YGEdgeRight]); @@ -1278,14 +1292,15 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node, } } - if (!YGFloatIsUndefined(child->getStyle().aspectRatio)) { + if (!child->getStyle().aspectRatio.isUndefined()) { if (!isMainAxisRow && childWidthMeasureMode == YGMeasureModeExactly) { childHeight = marginColumn + - (childWidth - marginRow) / child->getStyle().aspectRatio; + (childWidth - marginRow) / child->getStyle().aspectRatio.getValue(); childHeightMeasureMode = YGMeasureModeExactly; } else if (isMainAxisRow && childHeightMeasureMode == YGMeasureModeExactly) { childWidth = marginRow + - (childHeight - marginColumn) * child->getStyle().aspectRatio; + (childHeight - marginColumn) * + child->getStyle().aspectRatio.getValue(); childWidthMeasureMode = YGMeasureModeExactly; } } @@ -1300,8 +1315,9 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node, if (!isMainAxisRow && !isRowStyleDimDefined && hasExactWidth && childWidthStretch) { childWidth = width; childWidthMeasureMode = YGMeasureModeExactly; - if (!YGFloatIsUndefined(child->getStyle().aspectRatio)) { - childHeight = (childWidth - marginRow) / child->getStyle().aspectRatio; + if (!child->getStyle().aspectRatio.isUndefined()) { + childHeight = + (childWidth - marginRow) / child->getStyle().aspectRatio.getValue(); childHeightMeasureMode = YGMeasureModeExactly; } } @@ -1313,9 +1329,9 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node, childHeight = height; childHeightMeasureMode = YGMeasureModeExactly; - if (!YGFloatIsUndefined(child->getStyle().aspectRatio)) { - childWidth = - (childHeight - marginColumn) * child->getStyle().aspectRatio; + if (!child->getStyle().aspectRatio.isUndefined()) { + childWidth = (childHeight - marginColumn) * + child->getStyle().aspectRatio.getValue(); childWidthMeasureMode = YGMeasureModeExactly; } } @@ -1411,13 +1427,14 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, // Exactly one dimension needs to be defined for us to be able to do aspect ratio // calculation. One dimension being the anchor and the other being flexible. if (YGFloatIsUndefined(childWidth) ^ YGFloatIsUndefined(childHeight)) { - if (!YGFloatIsUndefined(child->getStyle().aspectRatio)) { + if (!child->getStyle().aspectRatio.isUndefined()) { if (YGFloatIsUndefined(childWidth)) { childWidth = marginRow + - (childHeight - marginColumn) * child->getStyle().aspectRatio; + (childHeight - marginColumn) * + child->getStyle().aspectRatio.getValue(); } else if (YGFloatIsUndefined(childHeight)) { childHeight = marginColumn + - (childWidth - marginRow) / child->getStyle().aspectRatio; + (childWidth - marginRow) / child->getStyle().aspectRatio.getValue(); } } } @@ -1997,11 +2014,11 @@ static float YGDistributeFreeSpaceSecondPass( YGMeasureMode childCrossMeasureMode; YGMeasureMode childMainMeasureMode = YGMeasureModeExactly; - if (!YGFloatIsUndefined(currentRelativeChild->getStyle().aspectRatio)) { + if (!currentRelativeChild->getStyle().aspectRatio.isUndefined()) { childCrossSize = isMainAxisRow ? (childMainSize - marginMain) / - currentRelativeChild->getStyle().aspectRatio + currentRelativeChild->getStyle().aspectRatio.getValue() : (childMainSize - marginMain) * - currentRelativeChild->getStyle().aspectRatio; + currentRelativeChild->getStyle().aspectRatio.getValue(); childCrossMeasureMode = YGMeasureModeExactly; childCrossSize += marginCross; @@ -2889,11 +2906,12 @@ static void YGNodelayoutImpl(const YGNodeRef node, float childMainSize = child->getLayout().measuredDimensions[dim[mainAxis]]; float childCrossSize = - !YGFloatIsUndefined(child->getStyle().aspectRatio) + !child->getStyle().aspectRatio.isUndefined() ? ((child->getMarginForAxis(crossAxis, availableInnerWidth) + - (isMainAxisRow - ? childMainSize / child->getStyle().aspectRatio - : childMainSize * child->getStyle().aspectRatio))) + (isMainAxisRow ? childMainSize / + child->getStyle().aspectRatio.getValue() + : childMainSize * + child->getStyle().aspectRatio.getValue()))) : collectedFlexItemsValues.crossDim; childMainSize += From 63c073d994322a55a421a085dc9055deb16b9f27 Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Tue, 3 Apr 2018 14:56:31 -0700 Subject: [PATCH 0183/1109] Move equaltiy function from utils to an operator on YGFloatOptional Reviewed By: emilsjolander Differential Revision: D7303460 fbshipit-source-id: 41ec0076ace621ec1a5bdbab00b72eea57780fff --- ReactCommon/yoga/yoga/Utils.cpp | 6 ------ ReactCommon/yoga/yoga/Utils.h | 6 ------ ReactCommon/yoga/yoga/YGFloatOptional.cpp | 23 +++++++++++++++++++++++ ReactCommon/yoga/yoga/YGFloatOptional.h | 6 ++++++ ReactCommon/yoga/yoga/Yoga.cpp | 8 ++++---- 5 files changed, 33 insertions(+), 16 deletions(-) diff --git a/ReactCommon/yoga/yoga/Utils.cpp b/ReactCommon/yoga/yoga/Utils.cpp index aec7564fb66b89..5c670c31db269e 100644 --- a/ReactCommon/yoga/yoga/Utils.cpp +++ b/ReactCommon/yoga/yoga/Utils.cpp @@ -57,9 +57,3 @@ float YGFloatSanitize(const float& val) { float YGUnwrapFloatOptional(const YGFloatOptional& op) { return op.isUndefined() ? YGUndefined : op.getValue(); } - -bool YGFloatOptionalFloatEquals( - const YGFloatOptional& optional, - const float& val) { - return YGUnwrapFloatOptional(optional) == val; -} diff --git a/ReactCommon/yoga/yoga/Utils.h b/ReactCommon/yoga/yoga/Utils.h index 34284d2c3513a1..328ccef71057a7 100644 --- a/ReactCommon/yoga/yoga/Utils.h +++ b/ReactCommon/yoga/yoga/Utils.h @@ -94,12 +94,6 @@ float YGFloatSanitize(const float& val); // TODO: Get rid off this function float YGUnwrapFloatOptional(const YGFloatOptional& op); -// This function returns true if val and optional both are undefined or if val -// and optional.val is true, otherwise its false. -bool YGFloatOptionalFloatEquals( - const YGFloatOptional& optional, - const float& val); - YGFlexDirection YGFlexDirectionCross( const YGFlexDirection flexDirection, const YGDirection direction); diff --git a/ReactCommon/yoga/yoga/YGFloatOptional.cpp b/ReactCommon/yoga/yoga/YGFloatOptional.cpp index af9a6fc42ad786..380e7880cefdf0 100644 --- a/ReactCommon/yoga/yoga/YGFloatOptional.cpp +++ b/ReactCommon/yoga/yoga/YGFloatOptional.cpp @@ -8,6 +8,7 @@ #include "YGFloatOptional.h" #include #include +#include "Yoga.h" YGFloatOptional::YGFloatOptional(const float& value) : value_(value), isUndefined_(false) {} @@ -30,3 +31,25 @@ void YGFloatOptional::setValue(const float& val) { bool YGFloatOptional::isUndefined() const { return isUndefined_; } + +bool YGFloatOptional::operator==(const YGFloatOptional& op) const { + if (isUndefined_ == op.isUndefined()) { + return isUndefined_ ? true : value_ == op.getValue(); + } + return false; +} + +bool YGFloatOptional::operator!=(const YGFloatOptional& op) const { + return !(*this == op); +} + +bool YGFloatOptional::operator==(const float& val) const { + if (YGFloatIsUndefined(val) == isUndefined_) { + return isUndefined_ ? true : val == value_; + } + return false; +} + +bool YGFloatOptional::operator!=(const float& val) const { + return !(*this == val); +} diff --git a/ReactCommon/yoga/yoga/YGFloatOptional.h b/ReactCommon/yoga/yoga/YGFloatOptional.h index d82230be3ff714..1f633c3656d802 100644 --- a/ReactCommon/yoga/yoga/YGFloatOptional.h +++ b/ReactCommon/yoga/yoga/YGFloatOptional.h @@ -23,4 +23,10 @@ struct YGFloatOptional { void setValue(const float& val); bool isUndefined() const; + + bool operator==(const YGFloatOptional& op) const; + bool operator!=(const YGFloatOptional& op) const; + + bool operator==(const float& val) const; + bool operator!=(const float& val) const; }; diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index f00133e2fe8961..af5b2b41071796 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -801,7 +801,7 @@ YG_NODE_STYLE_PROPERTY_IMPL(YGDisplay, Display, display, display); // TODO(T26792433): Change the API to accept YGFloatOptional. void YGNodeStyleSetFlex(const YGNodeRef node, const float flex) { - if (!YGFloatOptionalFloatEquals(node->getStyle().flex, flex)) { + if (node->getStyle().flex != flex) { YGStyle style = node->getStyle(); if (YGFloatIsUndefined(flex)) { style.flex = YGFloatOptional(); @@ -821,7 +821,7 @@ float YGNodeStyleGetFlex(const YGNodeRef node) { // TODO(T26792433): Change the API to accept YGFloatOptional. void YGNodeStyleSetFlexGrow(const YGNodeRef node, const float flexGrow) { - if (!YGFloatOptionalFloatEquals(node->getStyle().flexGrow, flexGrow)) { + if (node->getStyle().flexGrow != flexGrow) { YGStyle style = node->getStyle(); if (YGFloatIsUndefined(flexGrow)) { style.flexGrow = YGFloatOptional(); @@ -835,7 +835,7 @@ void YGNodeStyleSetFlexGrow(const YGNodeRef node, const float flexGrow) { // TODO(T26792433): Change the API to accept YGFloatOptional. void YGNodeStyleSetFlexShrink(const YGNodeRef node, const float flexShrink) { - if (!YGFloatOptionalFloatEquals(node->getStyle().flexShrink, flexShrink)) { + if (node->getStyle().flexShrink != flexShrink) { YGStyle style = node->getStyle(); if (YGFloatIsUndefined(flexShrink)) { style.flexShrink = YGFloatOptional(); @@ -940,7 +940,7 @@ float YGNodeStyleGetAspectRatio(const YGNodeRef node) { // TODO(T26792433): Change the API to accept YGFloatOptional. void YGNodeStyleSetAspectRatio(const YGNodeRef node, const float aspectRatio) { - if (!YGFloatOptionalFloatEquals(node->getStyle().aspectRatio, aspectRatio)) { + if (node->getStyle().aspectRatio != aspectRatio) { YGStyle style = node->getStyle(); style.aspectRatio = YGFloatOptional(aspectRatio); node->setStyle(style); From f84f4fd04a96d0af2a4c4b9ba45a5a3543a64f9a Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Tue, 3 Apr 2018 14:56:34 -0700 Subject: [PATCH 0184/1109] Changed the return type of YGResolveValueMargin to YGFloatOptional Reviewed By: emilsjolander Differential Revision: D7304090 fbshipit-source-id: cbec03a9367cf34976d083ad475d4da0b736e6d2 --- ReactCommon/yoga/yoga/Utils.h | 5 +++-- ReactCommon/yoga/yoga/YGNode.cpp | 14 ++++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/ReactCommon/yoga/yoga/Utils.h b/ReactCommon/yoga/yoga/Utils.h index 328ccef71057a7..1de614ce885203 100644 --- a/ReactCommon/yoga/yoga/Utils.h +++ b/ReactCommon/yoga/yoga/Utils.h @@ -136,8 +136,9 @@ inline YGFlexDirection YGResolveFlexDirection( return flexDirection; } -static inline float YGResolveValueMargin( +static inline YGFloatOptional YGResolveValueMargin( const YGValue value, const float ownerSize) { - return value.unit == YGUnitAuto ? 0 : YGUnwrapFloatOptional(YGResolveValue(value, ownerSize)); + return value.unit == YGUnitAuto ? YGFloatOptional(0) + : YGResolveValue(value, ownerSize); } diff --git a/ReactCommon/yoga/yoga/YGNode.cpp b/ReactCommon/yoga/yoga/YGNode.cpp index 01be3a7c032879..87a92b394d36fe 100644 --- a/ReactCommon/yoga/yoga/YGNode.cpp +++ b/ReactCommon/yoga/yoga/YGNode.cpp @@ -144,12 +144,13 @@ float YGNode::getLeadingMargin( const float widthSize) const { if (YGFlexDirectionIsRow(axis) && style_.margin[YGEdgeStart].unit != YGUnitUndefined) { - return YGResolveValueMargin(style_.margin[YGEdgeStart], widthSize); + return YGUnwrapFloatOptional( + YGResolveValueMargin(style_.margin[YGEdgeStart], widthSize)); } - return YGResolveValueMargin( + return YGUnwrapFloatOptional(YGResolveValueMargin( *YGComputedEdgeValue(style_.margin, leading[axis], &YGValueZero), - widthSize); + widthSize)); } float YGNode::getTrailingMargin( @@ -157,12 +158,13 @@ float YGNode::getTrailingMargin( const float widthSize) const { if (YGFlexDirectionIsRow(axis) && style_.margin[YGEdgeEnd].unit != YGUnitUndefined) { - return YGResolveValueMargin(style_.margin[YGEdgeEnd], widthSize); + return YGUnwrapFloatOptional( + YGResolveValueMargin(style_.margin[YGEdgeEnd], widthSize)); } - return YGResolveValueMargin( + return YGUnwrapFloatOptional(YGResolveValueMargin( *YGComputedEdgeValue(style_.margin, trailing[axis], &YGValueZero), - widthSize); + widthSize)); } float YGNode::getMarginForAxis( From 746945824a426a6f16555df0f12f92d836d5cc18 Mon Sep 17 00:00:00 2001 From: Kyle Roach Date: Tue, 3 Apr 2018 16:13:58 -0700 Subject: [PATCH 0185/1109] fix(RCTImageLoader): Adds `requiresMainQueueSetup` to fix v0.52 Summary: In react-native v0.52 this warning shows: ``` "RCTImageLoader requires main queue setup since it overrides `init` but doesn't implement `requiresMainQueueSetup`". ``` This removes the warning by implementing `requiresMainQueueSetup` on RCTImageLoader * Create new react-native project * Enable Remote JS Debugging * Should see no warning regarding RCTImageLoader requiring main queue setup [IOS] [BUGFIX] [Libraries/Image/RCTImageLoader.m] - Implements `requiresMainQueueSetup` Closes https://github.com/facebook/react-native/pull/17679 Reviewed By: shergin Differential Revision: D7159601 Pulled By: fkgozali fbshipit-source-id: e17bae67f4005d2c9ddd0d3701506521f3cac152 --- Libraries/Image/RCTImageLoader.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Libraries/Image/RCTImageLoader.m b/Libraries/Image/RCTImageLoader.m index bc50fb03a0eaca..775e53e95f7a08 100644 --- a/Libraries/Image/RCTImageLoader.m +++ b/Libraries/Image/RCTImageLoader.m @@ -58,6 +58,11 @@ - (instancetype)init return [self initWithRedirectDelegate:nil]; } ++ (BOOL)requiresMainQueueSetup +{ + return NO; +} + - (instancetype)initWithRedirectDelegate:(id)redirectDelegate { if (self = [super init]) { From cdfc34609268327fd8842753b829143f42c8c72e Mon Sep 17 00:00:00 2001 From: Sunny Luo Date: Tue, 3 Apr 2018 19:22:38 -0700 Subject: [PATCH 0186/1109] Fix wrong root path in RNTester gradle config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Currrent(0.54-stable) root path in RNTester gradle config would cause a failure when trying to compile a release version for RNTester: ``` module.js:545 throw err; ^ Error: Cannot find module ’TheParentDirectoryOfCurrentRepo/local-cli/cli.js' at Function.Module._resolveFilename (module.js:543:15) at Function.Module._load (module.js:470:25) at Function.Module.runMain (module.js:690:10) at startup (bootstrap_node.js:194:16) at bootstrap_node.js:666:3 :RNTester:android:app:bundleReleaseJsAndAssets FAILED ``` [ANDROID] [INTERNAL] [RNTester] - Fix wrong root path in RNTester gradle config Closes https://github.com/facebook/react-native/pull/18553 Differential Revision: D7488301 Pulled By: mdvacca fbshipit-source-id: b49a01820957eb77daeca9c0949f662b668f2bd1 --- RNTester/android/app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RNTester/android/app/build.gradle b/RNTester/android/app/build.gradle index 95d02acb788a99..bc001b26aca508 100644 --- a/RNTester/android/app/build.gradle +++ b/RNTester/android/app/build.gradle @@ -60,7 +60,7 @@ import com.android.build.OutputFile project.ext.react = [ bundleAssetName: "RNTesterApp.android.bundle", entryFile: file("../../js/RNTesterApp.android.js"), - root: "../../../../", + root: "../../../", inputExcludes: ["android/**", "./**"] ] From d4add3fc1c3af80239e0f27663f359f2a1665d37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20W=C3=B6hrl?= Date: Wed, 4 Apr 2018 06:42:36 -0700 Subject: [PATCH 0187/1109] Fix float type mismatch on endOfLineIndex and inside rounding Summary: This PR fixes a type mismatch on `endOfLineIndex` where it should be of type `uint32_t` while it is of type `float` Additonally it fixes some `double` casting in the rounding methods. Closes https://github.com/facebook/yoga/pull/745 Differential Revision: D7494519 Pulled By: emilsjolander fbshipit-source-id: 30a86574ce163458a6888f61a902d0640c1874fb --- ReactCommon/yoga/yoga/Utils.h | 2 +- ReactCommon/yoga/yoga/Yoga.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ReactCommon/yoga/yoga/Utils.h b/ReactCommon/yoga/yoga/Utils.h index 1de614ce885203..ce45e348b548d5 100644 --- a/ReactCommon/yoga/yoga/Utils.h +++ b/ReactCommon/yoga/yoga/Utils.h @@ -40,7 +40,7 @@ struct YGCollectFlexItemsRowValues { float sizeConsumedOnCurrentLine; float totalFlexGrowFactors; float totalFlexShrinkScaledFactors; - float endOfLineIndex; + uint32_t endOfLineIndex; std::vector relativeChildren; float remainingFreeSpace; // The size of the mainDim for the row after considering size, padding, margin diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index af5b2b41071796..0dba65651357a7 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -3368,12 +3368,12 @@ float YGRoundValueToPixelGrid(const float value, const bool forceCeil, const bool forceFloor) { float scaledValue = value * pointScaleFactor; - float fractial = fmodf(scaledValue, 1.0); + float fractial = fmodf(scaledValue, 1.0f); if (YGFloatsEqual(fractial, 0)) { // First we check if the value is already rounded scaledValue = scaledValue - fractial; - } else if (YGFloatsEqual(fractial, 1.0)) { - scaledValue = scaledValue - fractial + 1.0; + } else if (YGFloatsEqual(fractial, 1.0f)) { + scaledValue = scaledValue - fractial + 1.0f; } else if (forceCeil) { // Next we check if we need to use forced rounding scaledValue = scaledValue - fractial + 1.0f; From 2ace555972a1a09e919e914431e9399111d43671 Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Wed, 4 Apr 2018 07:55:23 -0700 Subject: [PATCH 0188/1109] Made the acccessors method to return const references Reviewed By: emilsjolander Differential Revision: D7321801 fbshipit-source-id: 9fc4da724bc2f58a0d95824ca3c0b5bf1690bccf --- ReactCommon/yoga/yoga/YGFloatOptional.cpp | 4 ++-- ReactCommon/yoga/yoga/YGFloatOptional.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ReactCommon/yoga/yoga/YGFloatOptional.cpp b/ReactCommon/yoga/yoga/YGFloatOptional.cpp index 380e7880cefdf0..1947e9f1755a91 100644 --- a/ReactCommon/yoga/yoga/YGFloatOptional.cpp +++ b/ReactCommon/yoga/yoga/YGFloatOptional.cpp @@ -14,7 +14,7 @@ YGFloatOptional::YGFloatOptional(const float& value) : value_(value), isUndefined_(false) {} YGFloatOptional::YGFloatOptional() : value_(0), isUndefined_(true) {} -float YGFloatOptional::getValue() const { +const float& YGFloatOptional::getValue() const { if (isUndefined_) { // Abort, accessing a value of an undefined float optional std::cerr << "Tried to get value of an undefined YGFloatOptional\n"; @@ -28,7 +28,7 @@ void YGFloatOptional::setValue(const float& val) { isUndefined_ = false; } -bool YGFloatOptional::isUndefined() const { +const bool& YGFloatOptional::isUndefined() const { return isUndefined_; } diff --git a/ReactCommon/yoga/yoga/YGFloatOptional.h b/ReactCommon/yoga/yoga/YGFloatOptional.h index 1f633c3656d802..9894e40eb7d7e9 100644 --- a/ReactCommon/yoga/yoga/YGFloatOptional.h +++ b/ReactCommon/yoga/yoga/YGFloatOptional.h @@ -17,12 +17,12 @@ struct YGFloatOptional { // Program will terminate if the value of an undefined is accessed. Please // make sure to check if the optional is defined before calling this function. // To check if float optional is defined, use `isUndefined()`. - float getValue() const; + const float& getValue() const; // Sets the value of float optional, and thus isUndefined is assigned false. void setValue(const float& val); - bool isUndefined() const; + const bool& isUndefined() const; bool operator==(const YGFloatOptional& op) const; bool operator!=(const YGFloatOptional& op) const; From dbb2c6b0fdc3c00fb4a2190c6aa6a1e3d708ff06 Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Wed, 4 Apr 2018 07:55:25 -0700 Subject: [PATCH 0189/1109] Remove the use of YGUnwrapOptional from YGConstrainedMaxSizeForMode Reviewed By: emilsjolander Differential Revision: D7322743 fbshipit-source-id: d825c60bcdc9ecdc0c784a215dc6b1b8a7a7860e --- ReactCommon/yoga/yoga/YGFloatOptional.cpp | 19 +++++++++++++++++-- ReactCommon/yoga/yoga/YGFloatOptional.h | 1 + ReactCommon/yoga/yoga/YGNode.cpp | 1 + ReactCommon/yoga/yoga/Yoga.cpp | 16 +++++++++------- 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/ReactCommon/yoga/yoga/YGFloatOptional.cpp b/ReactCommon/yoga/yoga/YGFloatOptional.cpp index 1947e9f1755a91..5982c307025a06 100644 --- a/ReactCommon/yoga/yoga/YGFloatOptional.cpp +++ b/ReactCommon/yoga/yoga/YGFloatOptional.cpp @@ -10,8 +10,16 @@ #include #include "Yoga.h" -YGFloatOptional::YGFloatOptional(const float& value) - : value_(value), isUndefined_(false) {} +YGFloatOptional::YGFloatOptional(const float& value) { + if (YGFloatIsUndefined(value)) { + isUndefined_ = true; + value_ = 0; + } else { + value_ = value; + isUndefined_ = false; + } +} + YGFloatOptional::YGFloatOptional() : value_(0), isUndefined_(true) {} const float& YGFloatOptional::getValue() const { @@ -53,3 +61,10 @@ bool YGFloatOptional::operator==(const float& val) const { bool YGFloatOptional::operator!=(const float& val) const { return !(*this == val); } + +YGFloatOptional YGFloatOptional::operator+(const YGFloatOptional& op) { + if (!isUndefined_ && !op.isUndefined_) { + return YGFloatOptional(value_ + op.value_); + } + return YGFloatOptional(); +} diff --git a/ReactCommon/yoga/yoga/YGFloatOptional.h b/ReactCommon/yoga/yoga/YGFloatOptional.h index 9894e40eb7d7e9..06ae8f15ade482 100644 --- a/ReactCommon/yoga/yoga/YGFloatOptional.h +++ b/ReactCommon/yoga/yoga/YGFloatOptional.h @@ -24,6 +24,7 @@ struct YGFloatOptional { const bool& isUndefined() const; + YGFloatOptional operator+(const YGFloatOptional& op); bool operator==(const YGFloatOptional& op) const; bool operator!=(const YGFloatOptional& op) const; diff --git a/ReactCommon/yoga/yoga/YGNode.cpp b/ReactCommon/yoga/yoga/YGNode.cpp index 87a92b394d36fe..d10f19414d8eee 100644 --- a/ReactCommon/yoga/yoga/YGNode.cpp +++ b/ReactCommon/yoga/yoga/YGNode.cpp @@ -167,6 +167,7 @@ float YGNode::getTrailingMargin( widthSize)); } +// TODO: Make its return type to YGFloatOptional float YGNode::getMarginForAxis( const YGFlexDirection axis, const float widthSize) const { diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index 0dba65651357a7..e10136e7806f24 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -1178,19 +1178,21 @@ static void YGConstrainMaxSizeForMode(const YGNodeRef node, const float ownerWidth, YGMeasureMode *mode, float *size) { - const float maxSize = - YGUnwrapFloatOptional(YGResolveValue( - node->getStyle().maxDimensions[dim[axis]], ownerAxisSize)) + - node->getMarginForAxis(axis, ownerWidth); + const YGFloatOptional maxSize = + YGResolveValue( + node->getStyle().maxDimensions[dim[axis]], ownerAxisSize) + + YGFloatOptional(node->getMarginForAxis(axis, ownerWidth)); switch (*mode) { case YGMeasureModeExactly: case YGMeasureModeAtMost: - *size = (YGFloatIsUndefined(maxSize) || *size < maxSize) ? *size : maxSize; + *size = (maxSize.isUndefined() || *size < maxSize.getValue()) + ? *size + : maxSize.getValue(); break; case YGMeasureModeUndefined: - if (!YGFloatIsUndefined(maxSize)) { + if (!maxSize.isUndefined()) { *mode = YGMeasureModeAtMost; - *size = maxSize; + *size = maxSize.getValue(); } break; } From 20e5193207fe0c060eedf9e685f347de245aa9c7 Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Wed, 4 Apr 2018 07:55:28 -0700 Subject: [PATCH 0190/1109] Make the return type of YGNodeBoundAxisWithinMinAndMax to YGFloatOptional Reviewed By: emilsjolander Differential Revision: D7323382 fbshipit-source-id: 8e3eb4f3744b5f3f9e2b353f56184905f7557191 --- ReactCommon/yoga/yoga/YGFloatOptional.cpp | 22 ++++++++ ReactCommon/yoga/yoga/YGFloatOptional.h | 4 ++ ReactCommon/yoga/yoga/Yoga.cpp | 64 +++++++++++------------ 3 files changed, 58 insertions(+), 32 deletions(-) diff --git a/ReactCommon/yoga/yoga/YGFloatOptional.cpp b/ReactCommon/yoga/yoga/YGFloatOptional.cpp index 5982c307025a06..00bfc71e2df29c 100644 --- a/ReactCommon/yoga/yoga/YGFloatOptional.cpp +++ b/ReactCommon/yoga/yoga/YGFloatOptional.cpp @@ -68,3 +68,25 @@ YGFloatOptional YGFloatOptional::operator+(const YGFloatOptional& op) { } return YGFloatOptional(); } + +bool YGFloatOptional::operator>(const YGFloatOptional& op) const { + if (isUndefined_ || op.isUndefined_) { + return false; + } + return value_ > op.value_; +} + +bool YGFloatOptional::operator<(const YGFloatOptional& op) const { + if (isUndefined_ || op.isUndefined_) { + return false; + } + return value_ < op.value_; +} + +bool YGFloatOptional::operator>=(const YGFloatOptional& op) const { + return *this == op ? true : *this > op; +} + +bool YGFloatOptional::operator<=(const YGFloatOptional& op) const { + return *this == op ? true : *this < op; +} diff --git a/ReactCommon/yoga/yoga/YGFloatOptional.h b/ReactCommon/yoga/yoga/YGFloatOptional.h index 06ae8f15ade482..9ecad46f3fc55b 100644 --- a/ReactCommon/yoga/yoga/YGFloatOptional.h +++ b/ReactCommon/yoga/yoga/YGFloatOptional.h @@ -25,6 +25,10 @@ struct YGFloatOptional { const bool& isUndefined() const; YGFloatOptional operator+(const YGFloatOptional& op); + bool operator>(const YGFloatOptional& op) const; + bool operator<(const YGFloatOptional& op) const; + bool operator>=(const YGFloatOptional& op) const; + bool operator<=(const YGFloatOptional& op) const; bool operator==(const YGFloatOptional& op) const; bool operator!=(const YGFloatOptional& op) const; diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index e10136e7806f24..271eff3a27e0ce 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -1117,36 +1117,35 @@ static inline bool YGNodeIsLayoutDimDefined(const YGNodeRef node, const YGFlexDi return !YGFloatIsUndefined(value) && value >= 0.0f; } -static float YGNodeBoundAxisWithinMinAndMax(const YGNodeRef node, - const YGFlexDirection axis, - const float value, - const float axisSize) { - float min = YGUndefined; - float max = YGUndefined; +static YGFloatOptional YGNodeBoundAxisWithinMinAndMax( + const YGNodeRef node, + const YGFlexDirection& axis, + const float& value, + const float& axisSize) { + YGFloatOptional min; + YGFloatOptional max; if (YGFlexDirectionIsColumn(axis)) { - min = YGUnwrapFloatOptional(YGResolveValue( - node->getStyle().minDimensions[YGDimensionHeight], axisSize)); - max = YGUnwrapFloatOptional(YGResolveValue( - node->getStyle().maxDimensions[YGDimensionHeight], axisSize)); + min = YGResolveValue( + node->getStyle().minDimensions[YGDimensionHeight], axisSize); + max = YGResolveValue( + node->getStyle().maxDimensions[YGDimensionHeight], axisSize); } else if (YGFlexDirectionIsRow(axis)) { - min = YGUnwrapFloatOptional(YGResolveValue( - node->getStyle().minDimensions[YGDimensionWidth], axisSize)); - max = YGUnwrapFloatOptional(YGResolveValue( - node->getStyle().maxDimensions[YGDimensionWidth], axisSize)); + min = YGResolveValue( + node->getStyle().minDimensions[YGDimensionWidth], axisSize); + max = YGResolveValue( + node->getStyle().maxDimensions[YGDimensionWidth], axisSize); } - float boundValue = value; - - if (!YGFloatIsUndefined(max) && max >= 0.0f && boundValue > max) { - boundValue = max; + if (!max.isUndefined() && max.getValue() >= 0 && value > max.getValue()) { + return max; } - if (!YGFloatIsUndefined(min) && min >= 0.0f && boundValue < min) { - boundValue = min; + if (!min.isUndefined() && min.getValue() >= 0 && value < min.getValue()) { + return min; } - return boundValue; + return YGFloatOptional(value); } // Like YGNodeBoundAxisWithinMinAndMax but also ensures that the value doesn't go @@ -1158,7 +1157,8 @@ static inline float YGNodeBoundAxis(const YGNodeRef node, const float axisSize, const float widthSize) { return YGFloatMax( - YGNodeBoundAxisWithinMinAndMax(node, axis, value, axisSize), + YGUnwrapFloatOptional( + YGNodeBoundAxisWithinMinAndMax(node, axis, value, axisSize)), YGNodePaddingAndBorderForAxis(node, axis, widthSize)); } @@ -1876,11 +1876,11 @@ static YGCollectFlexItemsRowValues YGCalculateCollectFlexItemsRowValues( const float childMarginMainAxis = child->getMarginForAxis(mainAxis, availableInnerWidth); const float flexBasisWithMinAndMaxConstraints = - YGNodeBoundAxisWithinMinAndMax( + YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax( child, mainAxis, child->getLayout().computedFlexBasis, - mainAxisownerSize); + mainAxisownerSize)); // If this is a multi-line flow and this item pushes us over the // available size, we've @@ -1952,11 +1952,11 @@ static float YGDistributeFreeSpaceSecondPass( const bool isNodeFlexWrap = node->getStyle().flexWrap != YGWrapNoWrap; for (auto currentRelativeChild : collectedFlexItemsValues.relativeChildren) { - childFlexBasis = YGNodeBoundAxisWithinMinAndMax( + childFlexBasis = YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax( currentRelativeChild, mainAxis, currentRelativeChild->getLayout().computedFlexBasis, - mainAxisownerSize); + mainAxisownerSize)); float updatedMainSize = childFlexBasis; if (!YGFloatIsUndefined(collectedFlexItemsValues.remainingFreeSpace) && @@ -2127,11 +2127,11 @@ static void YGDistributeFreeSpaceFirstPass( float deltaFreeSpace = 0; for (auto currentRelativeChild : collectedFlexItemsValues.relativeChildren) { - float childFlexBasis = YGNodeBoundAxisWithinMinAndMax( + float childFlexBasis = YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax( currentRelativeChild, mainAxis, currentRelativeChild->getLayout().computedFlexBasis, - mainAxisownerSize); + mainAxisownerSize)); if (collectedFlexItemsValues.remainingFreeSpace < 0) { flexShrinkScaledFactor = @@ -3217,8 +3217,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, YGFloatMax( YGFloatMin( availableInnerMainDim + paddingAndBorderAxisMain, - YGNodeBoundAxisWithinMinAndMax( - node, mainAxis, maxLineMainDim, mainAxisownerSize)), + YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax( + node, mainAxis, maxLineMainDim, mainAxisownerSize))), paddingAndBorderAxisMain), dim[mainAxis]); } @@ -3245,11 +3245,11 @@ static void YGNodelayoutImpl(const YGNodeRef node, YGFloatMax( YGFloatMin( availableInnerCrossDim + paddingAndBorderAxisCross, - YGNodeBoundAxisWithinMinAndMax( + YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax( node, crossAxis, totalLineCrossDim + paddingAndBorderAxisCross, - crossAxisownerSize)), + crossAxisownerSize))), paddingAndBorderAxisCross), dim[crossAxis]); } From 51f5cd4810c1d33023177b9fbd7c1e61060388d4 Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Wed, 4 Apr 2018 07:55:30 -0700 Subject: [PATCH 0191/1109] Updated the implementation of leading padding Reviewed By: emilsjolander Differential Revision: D7336690 fbshipit-source-id: b2a2f010026f26fc2cc9fb35ad921da8f7017c9f --- ReactCommon/yoga/yoga/Utils.cpp | 9 +++++++++ ReactCommon/yoga/yoga/Utils.h | 4 ++++ ReactCommon/yoga/yoga/YGNode.cpp | 23 ++++++++++++----------- ReactCommon/yoga/yoga/YGNode.h | 4 +++- ReactCommon/yoga/yoga/Yoga.cpp | 8 ++++++-- 5 files changed, 34 insertions(+), 14 deletions(-) diff --git a/ReactCommon/yoga/yoga/Utils.cpp b/ReactCommon/yoga/yoga/Utils.cpp index 5c670c31db269e..6fa8df823ba32f 100644 --- a/ReactCommon/yoga/yoga/Utils.cpp +++ b/ReactCommon/yoga/yoga/Utils.cpp @@ -57,3 +57,12 @@ float YGFloatSanitize(const float& val) { float YGUnwrapFloatOptional(const YGFloatOptional& op) { return op.isUndefined() ? YGUndefined : op.getValue(); } + +YGFloatOptional YGFloatOptionalMax( + const YGFloatOptional& op1, + const YGFloatOptional& op2) { + if (!op1.isUndefined() && !op2.isUndefined()) { + return op1.getValue() > op2.getValue() ? op1 : op2; + } + return op1.isUndefined() ? op2 : op1; +} diff --git a/ReactCommon/yoga/yoga/Utils.h b/ReactCommon/yoga/yoga/Utils.h index ce45e348b548d5..6c95b1e7aaf772 100644 --- a/ReactCommon/yoga/yoga/Utils.h +++ b/ReactCommon/yoga/yoga/Utils.h @@ -65,6 +65,10 @@ bool YGFloatsEqual(const float a, const float b); // compiler flag. float YGFloatMax(const float a, const float b); +YGFloatOptional YGFloatOptionalMax( + const YGFloatOptional& op1, + const YGFloatOptional& op2); + // We need custom min function, since we want that, if one argument is // YGUndefined then the min funtion should return the other argument as the min // value. We wouldn't have needed a custom min function if YGUndefined was NAN diff --git a/ReactCommon/yoga/yoga/YGNode.cpp b/ReactCommon/yoga/yoga/YGNode.cpp index d10f19414d8eee..913ec329ecbb61 100644 --- a/ReactCommon/yoga/yoga/YGNode.cpp +++ b/ReactCommon/yoga/yoga/YGNode.cpp @@ -654,21 +654,21 @@ float YGNode::getTrailingBorder(const YGFlexDirection flexDirection) const { return YGFloatMax(computedEdgeValue, 0.0f); } -float YGNode::getLeadingPadding( - const YGFlexDirection axis, - const float widthSize) const { +YGFloatOptional YGNode::getLeadingPadding( + const YGFlexDirection& axis, + const float& widthSize) const { + const YGFloatOptional& paddingEdgeStart = + YGResolveValue(style_.padding[YGEdgeStart], widthSize); if (YGFlexDirectionIsRow(axis) && style_.padding[YGEdgeStart].unit != YGUnitUndefined && - !YGResolveValue(style_.padding[YGEdgeStart], widthSize).isUndefined() && - YGUnwrapFloatOptional( - YGResolveValue(style_.padding[YGEdgeStart], widthSize)) > 0.0f) { - return YGUnwrapFloatOptional(YGResolveValue(style_.padding[YGEdgeStart], widthSize)); + !paddingEdgeStart.isUndefined() && paddingEdgeStart.getValue() > 0.0f) { + return paddingEdgeStart; } - float resolvedValue = YGUnwrapFloatOptional(YGResolveValue( + YGFloatOptional resolvedValue = YGResolveValue( *YGComputedEdgeValue(style_.padding, leading[axis], &YGValueZero), - widthSize)); - return YGFloatMax(resolvedValue, 0.0f); + widthSize); + return YGFloatOptionalMax(resolvedValue, YGFloatOptional(0.0f)); } float YGNode::getTrailingPadding( @@ -692,7 +692,8 @@ float YGNode::getTrailingPadding( float YGNode::getLeadingPaddingAndBorder( const YGFlexDirection axis, const float widthSize) const { - return getLeadingPadding(axis, widthSize) + getLeadingBorder(axis); + return YGUnwrapFloatOptional(getLeadingPadding(axis, widthSize)) + + getLeadingBorder(axis); } float YGNode::getTrailingPaddingAndBorder( diff --git a/ReactCommon/yoga/yoga/YGNode.h b/ReactCommon/yoga/yoga/YGNode.h index 02afb830e8b419..cdb6fae47c3a19 100644 --- a/ReactCommon/yoga/yoga/YGNode.h +++ b/ReactCommon/yoga/yoga/YGNode.h @@ -93,7 +93,9 @@ struct YGNode { float getTrailingMargin(const YGFlexDirection axis, const float widthSize) const; float getLeadingBorder(const YGFlexDirection flexDirection) const; float getTrailingBorder(const YGFlexDirection flexDirection) const; - float getLeadingPadding(const YGFlexDirection axis, const float widthSize) const; + YGFloatOptional getLeadingPadding( + const YGFlexDirection& axis, + const float& widthSize) const; float getTrailingPadding(const YGFlexDirection axis, const float widthSize) const; float getLeadingPaddingAndBorder( const YGFlexDirection axis, diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index 271eff3a27e0ce..12f8facb1ee899 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -2573,11 +2573,15 @@ static void YGNodelayoutImpl(const YGNodeRef node, node->getTrailingBorder(flexColumnDirection), YGEdgeBottom); node->setLayoutPadding( - node->getLeadingPadding(flexRowDirection, ownerWidth), YGEdgeStart); + YGUnwrapFloatOptional( + node->getLeadingPadding(flexRowDirection, ownerWidth)), + YGEdgeStart); node->setLayoutPadding( node->getTrailingPadding(flexRowDirection, ownerWidth), YGEdgeEnd); node->setLayoutPadding( - node->getLeadingPadding(flexColumnDirection, ownerWidth), YGEdgeTop); + YGUnwrapFloatOptional( + node->getLeadingPadding(flexColumnDirection, ownerWidth)), + YGEdgeTop); node->setLayoutPadding( node->getTrailingPadding(flexColumnDirection, ownerWidth), YGEdgeBottom); From ee0d621d2aa8c2cb2edb345c84b25e95fe404d57 Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Wed, 4 Apr 2018 07:55:34 -0700 Subject: [PATCH 0192/1109] Changed the return type of trailing padding to YGFloatOptional Reviewed By: emilsjolander Differential Revision: D7339712 fbshipit-source-id: 483c5886838c14b17cb731c81abb9fc80f519956 --- ReactCommon/yoga/yoga/YGNode.cpp | 20 ++++++++++---------- ReactCommon/yoga/yoga/YGNode.h | 4 +++- ReactCommon/yoga/yoga/Yoga.cpp | 8 ++++++-- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/ReactCommon/yoga/yoga/YGNode.cpp b/ReactCommon/yoga/yoga/YGNode.cpp index 913ec329ecbb61..9f6c6a2a871108 100644 --- a/ReactCommon/yoga/yoga/YGNode.cpp +++ b/ReactCommon/yoga/yoga/YGNode.cpp @@ -671,22 +671,21 @@ YGFloatOptional YGNode::getLeadingPadding( return YGFloatOptionalMax(resolvedValue, YGFloatOptional(0.0f)); } -float YGNode::getTrailingPadding( - const YGFlexDirection axis, - const float widthSize) const { +YGFloatOptional YGNode::getTrailingPadding( + const YGFlexDirection& axis, + const float& widthSize) const { if (YGFlexDirectionIsRow(axis) && style_.padding[YGEdgeEnd].unit != YGUnitUndefined && !YGResolveValue(style_.padding[YGEdgeEnd], widthSize).isUndefined() && - YGUnwrapFloatOptional( - YGResolveValue(style_.padding[YGEdgeEnd], widthSize)) >= 0.0f) { - return YGUnwrapFloatOptional(YGResolveValue(style_.padding[YGEdgeEnd], widthSize)); + YGResolveValue(style_.padding[YGEdgeEnd], widthSize).getValue() >= 0.0f) { + return YGResolveValue(style_.padding[YGEdgeEnd], widthSize); } - float resolvedValue = YGUnwrapFloatOptional(YGResolveValue( + YGFloatOptional resolvedValue = YGResolveValue( *YGComputedEdgeValue(style_.padding, trailing[axis], &YGValueZero), - widthSize)); + widthSize); - return YGFloatMax(resolvedValue, 0.0f); + return YGFloatOptionalMax(resolvedValue, YGFloatOptional(0.0f)); } float YGNode::getLeadingPaddingAndBorder( @@ -699,7 +698,8 @@ float YGNode::getLeadingPaddingAndBorder( float YGNode::getTrailingPaddingAndBorder( const YGFlexDirection axis, const float widthSize) const { - return getTrailingPadding(axis, widthSize) + getTrailingBorder(axis); + return YGUnwrapFloatOptional(getTrailingPadding(axis, widthSize)) + + getTrailingBorder(axis); } bool YGNode::didUseLegacyFlag() { diff --git a/ReactCommon/yoga/yoga/YGNode.h b/ReactCommon/yoga/yoga/YGNode.h index cdb6fae47c3a19..010b0dc7acb3b5 100644 --- a/ReactCommon/yoga/yoga/YGNode.h +++ b/ReactCommon/yoga/yoga/YGNode.h @@ -96,7 +96,9 @@ struct YGNode { YGFloatOptional getLeadingPadding( const YGFlexDirection& axis, const float& widthSize) const; - float getTrailingPadding(const YGFlexDirection axis, const float widthSize) const; + YGFloatOptional getTrailingPadding( + const YGFlexDirection& axis, + const float& widthSize) const; float getLeadingPaddingAndBorder( const YGFlexDirection axis, const float widthSize) const; diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index 12f8facb1ee899..8740c6667b2076 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -2577,13 +2577,17 @@ static void YGNodelayoutImpl(const YGNodeRef node, node->getLeadingPadding(flexRowDirection, ownerWidth)), YGEdgeStart); node->setLayoutPadding( - node->getTrailingPadding(flexRowDirection, ownerWidth), YGEdgeEnd); + YGUnwrapFloatOptional( + node->getTrailingPadding(flexRowDirection, ownerWidth)), + YGEdgeEnd); node->setLayoutPadding( YGUnwrapFloatOptional( node->getLeadingPadding(flexColumnDirection, ownerWidth)), YGEdgeTop); node->setLayoutPadding( - node->getTrailingPadding(flexColumnDirection, ownerWidth), YGEdgeBottom); + YGUnwrapFloatOptional( + node->getTrailingPadding(flexColumnDirection, ownerWidth)), + YGEdgeBottom); if (node->getMeasure() != nullptr) { YGNodeWithMeasureFuncSetMeasuredDimensions(node, From fe3a9d4013009fe499cf58313643172694a91040 Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Wed, 4 Apr 2018 07:55:37 -0700 Subject: [PATCH 0193/1109] Fixed types of getLeadingPaddingAndBorder and getTrailingPaddingAndBorder to YGFloatOptional Reviewed By: emilsjolander Differential Revision: D7339998 fbshipit-source-id: aa24335c2db1cd895b9711214b72195add718c32 --- ReactCommon/yoga/yoga/YGNode.cpp | 24 ++++++++++++------------ ReactCommon/yoga/yoga/YGNode.h | 16 ++++++++-------- ReactCommon/yoga/yoga/Yoga.cpp | 17 +++++++++-------- 3 files changed, 29 insertions(+), 28 deletions(-) diff --git a/ReactCommon/yoga/yoga/YGNode.cpp b/ReactCommon/yoga/yoga/YGNode.cpp index 9f6c6a2a871108..06a583951f9790 100644 --- a/ReactCommon/yoga/yoga/YGNode.cpp +++ b/ReactCommon/yoga/yoga/YGNode.cpp @@ -627,7 +627,7 @@ bool YGNode::isNodeFlexible() { (resolveFlexGrow() != 0 || resolveFlexShrink() != 0)); } -float YGNode::getLeadingBorder(const YGFlexDirection axis) const { +float YGNode::getLeadingBorder(const YGFlexDirection& axis) const { if (YGFlexDirectionIsRow(axis) && style_.border[YGEdgeStart].unit != YGUnitUndefined && !YGFloatIsUndefined(style_.border[YGEdgeStart].value) && @@ -640,7 +640,7 @@ float YGNode::getLeadingBorder(const YGFlexDirection axis) const { return YGFloatMax(computedEdgeValue, 0.0f); } -float YGNode::getTrailingBorder(const YGFlexDirection flexDirection) const { +float YGNode::getTrailingBorder(const YGFlexDirection& flexDirection) const { if (YGFlexDirectionIsRow(flexDirection) && style_.border[YGEdgeEnd].unit != YGUnitUndefined && !YGFloatIsUndefined(style_.border[YGEdgeEnd].value) && @@ -688,18 +688,18 @@ YGFloatOptional YGNode::getTrailingPadding( return YGFloatOptionalMax(resolvedValue, YGFloatOptional(0.0f)); } -float YGNode::getLeadingPaddingAndBorder( - const YGFlexDirection axis, - const float widthSize) const { - return YGUnwrapFloatOptional(getLeadingPadding(axis, widthSize)) + - getLeadingBorder(axis); +YGFloatOptional YGNode::getLeadingPaddingAndBorder( + const YGFlexDirection& axis, + const float& widthSize) const { + return getLeadingPadding(axis, widthSize) + + YGFloatOptional(getLeadingBorder(axis)); } -float YGNode::getTrailingPaddingAndBorder( - const YGFlexDirection axis, - const float widthSize) const { - return YGUnwrapFloatOptional(getTrailingPadding(axis, widthSize)) + - getTrailingBorder(axis); +YGFloatOptional YGNode::getTrailingPaddingAndBorder( + const YGFlexDirection& axis, + const float& widthSize) const { + return getTrailingPadding(axis, widthSize) + + YGFloatOptional(getTrailingBorder(axis)); } bool YGNode::didUseLegacyFlag() { diff --git a/ReactCommon/yoga/yoga/YGNode.h b/ReactCommon/yoga/yoga/YGNode.h index 010b0dc7acb3b5..d65b0b71dc53f9 100644 --- a/ReactCommon/yoga/yoga/YGNode.h +++ b/ReactCommon/yoga/yoga/YGNode.h @@ -91,20 +91,20 @@ struct YGNode { float getTrailingPosition(const YGFlexDirection axis, const float axisSize) const; float getLeadingMargin(const YGFlexDirection axis, const float widthSize) const; float getTrailingMargin(const YGFlexDirection axis, const float widthSize) const; - float getLeadingBorder(const YGFlexDirection flexDirection) const; - float getTrailingBorder(const YGFlexDirection flexDirection) const; + float getLeadingBorder(const YGFlexDirection& flexDirection) const; + float getTrailingBorder(const YGFlexDirection& flexDirection) const; YGFloatOptional getLeadingPadding( const YGFlexDirection& axis, const float& widthSize) const; YGFloatOptional getTrailingPadding( const YGFlexDirection& axis, const float& widthSize) const; - float getLeadingPaddingAndBorder( - const YGFlexDirection axis, - const float widthSize) const; - float getTrailingPaddingAndBorder( - const YGFlexDirection axis, - const float widthSize) const; + YGFloatOptional getLeadingPaddingAndBorder( + const YGFlexDirection& axis, + const float& widthSize) const; + YGFloatOptional getTrailingPaddingAndBorder( + const YGFlexDirection& axis, + const float& widthSize) const; float getMarginForAxis(const YGFlexDirection axis, const float widthSize) const; // Setters diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index 8740c6667b2076..19cb30df15edd6 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -1014,8 +1014,9 @@ static const std::array dim = { static inline float YGNodePaddingAndBorderForAxis(const YGNodeRef node, const YGFlexDirection axis, const float widthSize) { - return node->getLeadingPaddingAndBorder(axis, widthSize) + - node->getTrailingPaddingAndBorder(axis, widthSize); + return YGUnwrapFloatOptional( + node->getLeadingPaddingAndBorder(axis, widthSize) + + node->getTrailingPaddingAndBorder(axis, widthSize)); } static inline YGAlign YGNodeAlignItem(const YGNodeRef node, const YGNodeRef child) { @@ -2357,8 +2358,8 @@ static void YGJustifyMainAxis( } } - const float leadingPaddingAndBorderMain = - node->getLeadingPaddingAndBorder(mainAxis, ownerWidth); + const float leadingPaddingAndBorderMain = YGUnwrapFloatOptional( + node->getLeadingPaddingAndBorder(mainAxis, ownerWidth)); collectedFlexItemsValues.mainDim = leadingPaddingAndBorderMain + leadingMainDim; collectedFlexItemsValues.crossDim = 0; @@ -2438,8 +2439,8 @@ static void YGJustifyMainAxis( } } } - collectedFlexItemsValues.mainDim += - node->getTrailingPaddingAndBorder(mainAxis, ownerWidth); + collectedFlexItemsValues.mainDim += YGUnwrapFloatOptional( + node->getTrailingPaddingAndBorder(mainAxis, ownerWidth)); } // @@ -2639,8 +2640,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, const float mainAxisownerSize = isMainAxisRow ? ownerWidth : ownerHeight; const float crossAxisownerSize = isMainAxisRow ? ownerHeight : ownerWidth; - const float leadingPaddingAndBorderCross = - node->getLeadingPaddingAndBorder(crossAxis, ownerWidth); + const float leadingPaddingAndBorderCross = YGUnwrapFloatOptional( + node->getLeadingPaddingAndBorder(crossAxis, ownerWidth)); const float paddingAndBorderAxisMain = YGNodePaddingAndBorderForAxis(node, mainAxis, ownerWidth); const float paddingAndBorderAxisCross = YGNodePaddingAndBorderForAxis(node, crossAxis, ownerWidth); From 0186ccf0068579e6f7c5864c4cf41973d6d8dff1 Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Wed, 4 Apr 2018 07:55:39 -0700 Subject: [PATCH 0194/1109] Changed the type of computedFlexBasis to YGFloatOptional in YGLayout Reviewed By: emilsjolander Differential Revision: D7340413 fbshipit-source-id: 39247b2b582a682e602f49f58b4bbd2bf0c995af --- ReactCommon/yoga/yoga/YGFloatOptional.h | 6 ++- ReactCommon/yoga/yoga/YGLayout.cpp | 9 ++-- ReactCommon/yoga/yoga/YGLayout.h | 3 +- ReactCommon/yoga/yoga/YGNode.cpp | 5 ++- ReactCommon/yoga/yoga/YGNode.h | 2 +- ReactCommon/yoga/yoga/Yoga.cpp | 60 ++++++++++++++----------- 6 files changed, 48 insertions(+), 37 deletions(-) diff --git a/ReactCommon/yoga/yoga/YGFloatOptional.h b/ReactCommon/yoga/yoga/YGFloatOptional.h index 9ecad46f3fc55b..21af2a806198d0 100644 --- a/ReactCommon/yoga/yoga/YGFloatOptional.h +++ b/ReactCommon/yoga/yoga/YGFloatOptional.h @@ -5,14 +5,16 @@ * LICENSE file in the root directory of this source tree. */ +#pragma once + struct YGFloatOptional { private: float value_; bool isUndefined_; public: - YGFloatOptional(const float& value); - YGFloatOptional(); + explicit YGFloatOptional(const float& value); + explicit YGFloatOptional(); // Program will terminate if the value of an undefined is accessed. Please // make sure to check if the optional is defined before calling this function. diff --git a/ReactCommon/yoga/yoga/YGLayout.cpp b/ReactCommon/yoga/yoga/YGLayout.cpp index 117638d7a15f0c..6e367bd50a9b03 100644 --- a/ReactCommon/yoga/yoga/YGLayout.cpp +++ b/ReactCommon/yoga/yoga/YGLayout.cpp @@ -19,7 +19,7 @@ YGLayout::YGLayout() padding(), direction(YGDirectionInherit), computedFlexBasisGeneration(0), - computedFlexBasis(YGUndefined), + computedFlexBasis(YGFloatOptional()), hadOverflow(false), generationCount(0), lastOwnerDirection((YGDirection)-1), @@ -39,16 +39,13 @@ bool YGLayout::operator==(YGLayout layout) const { direction == layout.direction && hadOverflow == layout.hadOverflow && lastOwnerDirection == layout.lastOwnerDirection && nextCachedMeasurementsIndex == layout.nextCachedMeasurementsIndex && - cachedLayout == layout.cachedLayout; + cachedLayout == layout.cachedLayout && + computedFlexBasis == layout.computedFlexBasis; for (uint32_t i = 0; i < YG_MAX_CACHED_RESULT_COUNT && isEqual; ++i) { isEqual = isEqual && cachedMeasurements[i] == layout.cachedMeasurements[i]; } - if (!YGFloatIsUndefined(computedFlexBasis) || - !YGFloatIsUndefined(layout.computedFlexBasis)) { - isEqual = isEqual && (computedFlexBasis == layout.computedFlexBasis); - } if (!YGFloatIsUndefined(measuredDimensions[0]) || !YGFloatIsUndefined(layout.measuredDimensions[0])) { isEqual = diff --git a/ReactCommon/yoga/yoga/YGLayout.h b/ReactCommon/yoga/yoga/YGLayout.h index 81cc66317a5a1e..46ca130d29bf46 100644 --- a/ReactCommon/yoga/yoga/YGLayout.h +++ b/ReactCommon/yoga/yoga/YGLayout.h @@ -6,6 +6,7 @@ */ #pragma once +#include "YGFloatOptional.h" #include "Yoga-internal.h" struct YGLayout { @@ -17,7 +18,7 @@ struct YGLayout { YGDirection direction; uint32_t computedFlexBasisGeneration; - float computedFlexBasis; + YGFloatOptional computedFlexBasis; bool hadOverflow; // Instead of recomputing the entire layout every single time, we diff --git a/ReactCommon/yoga/yoga/YGNode.cpp b/ReactCommon/yoga/yoga/YGNode.cpp index 06a583951f9790..eb840ef1dde9bc 100644 --- a/ReactCommon/yoga/yoga/YGNode.cpp +++ b/ReactCommon/yoga/yoga/YGNode.cpp @@ -312,7 +312,8 @@ void YGNode::setLayoutLastOwnerDirection(YGDirection direction) { layout_.lastOwnerDirection = direction; } -void YGNode::setLayoutComputedFlexBasis(float computedFlexBasis) { +void YGNode::setLayoutComputedFlexBasis( + const YGFloatOptional& computedFlexBasis) { layout_.computedFlexBasis = computedFlexBasis; } @@ -579,7 +580,7 @@ void YGNode::cloneChildrenIfNeeded() { void YGNode::markDirtyAndPropogate() { if (!isDirty_) { setDirty(true); - setLayoutComputedFlexBasis(YGUndefined); + setLayoutComputedFlexBasis(YGFloatOptional()); if (owner_) { owner_->markDirtyAndPropogate(); } diff --git a/ReactCommon/yoga/yoga/YGNode.h b/ReactCommon/yoga/yoga/YGNode.h index d65b0b71dc53f9..fe24fa037f645e 100644 --- a/ReactCommon/yoga/yoga/YGNode.h +++ b/ReactCommon/yoga/yoga/YGNode.h @@ -126,7 +126,7 @@ struct YGNode { void setConfig(YGConfigRef config); void setDirty(bool isDirty); void setLayoutLastOwnerDirection(YGDirection direction); - void setLayoutComputedFlexBasis(float computedFlexBasis); + void setLayoutComputedFlexBasis(const YGFloatOptional& computedFlexBasis); void setLayoutComputedFlexBasisGeneration( uint32_t computedFlexBasisGeneration); void setLayoutMeasuredDimension(float measuredDimension, int index); diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index 19cb30df15edd6..3b117243e709f3 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -1220,35 +1220,41 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node, YGMeasureMode childWidthMeasureMode; YGMeasureMode childHeightMeasureMode; - const float resolvedFlexBasis = - YGUnwrapFloatOptional(YGResolveValue(child->resolveFlexBasisPtr(), mainAxisownerSize)); + const YGFloatOptional resolvedFlexBasis = + YGResolveValue(child->resolveFlexBasisPtr(), mainAxisownerSize); const bool isRowStyleDimDefined = YGNodeIsStyleDimDefined(child, YGFlexDirectionRow, ownerWidth); const bool isColumnStyleDimDefined = YGNodeIsStyleDimDefined(child, YGFlexDirectionColumn, ownerHeight); - if (!YGFloatIsUndefined(resolvedFlexBasis) && !YGFloatIsUndefined(mainAxisSize)) { - if (YGFloatIsUndefined(child->getLayout().computedFlexBasis) || + if (!resolvedFlexBasis.isUndefined() && !YGFloatIsUndefined(mainAxisSize)) { + if (child->getLayout().computedFlexBasis.isUndefined() || (YGConfigIsExperimentalFeatureEnabled( child->getConfig(), YGExperimentalFeatureWebFlexBasis) && child->getLayout().computedFlexBasisGeneration != gCurrentGenerationCount)) { - child->setLayoutComputedFlexBasis(YGFloatMax( - resolvedFlexBasis, - YGNodePaddingAndBorderForAxis(child, mainAxis, ownerWidth))); + const YGFloatOptional& paddingAndBorder = YGFloatOptional( + YGNodePaddingAndBorderForAxis(child, mainAxis, ownerWidth)); + child->setLayoutComputedFlexBasis( + YGFloatOptionalMax(resolvedFlexBasis, paddingAndBorder)); } } else if (isMainAxisRow && isRowStyleDimDefined) { // The width is definite, so use that as the flex basis. - child->setLayoutComputedFlexBasis(YGFloatMax( - YGUnwrapFloatOptional(YGResolveValue( - child->getResolvedDimension(YGDimensionWidth), ownerWidth)), - YGNodePaddingAndBorderForAxis(child, YGFlexDirectionRow, ownerWidth))); + const YGFloatOptional& paddingAndBorder = YGFloatOptional( + YGNodePaddingAndBorderForAxis(child, YGFlexDirectionRow, ownerWidth)); + + child->setLayoutComputedFlexBasis(YGFloatOptionalMax( + YGResolveValue( + child->getResolvedDimension(YGDimensionWidth), ownerWidth), + paddingAndBorder)); } else if (!isMainAxisRow && isColumnStyleDimDefined) { // The height is definite, so use that as the flex basis. - child->setLayoutComputedFlexBasis(YGFloatMax( - YGUnwrapFloatOptional(YGResolveValue( - child->getResolvedDimension(YGDimensionHeight), ownerHeight)), - YGNodePaddingAndBorderForAxis( - child, YGFlexDirectionColumn, ownerWidth))); + const YGFloatOptional& paddingAndBorder = + YGFloatOptional(YGNodePaddingAndBorderForAxis( + child, YGFlexDirectionColumn, ownerWidth)); + child->setLayoutComputedFlexBasis(YGFloatOptionalMax( + YGResolveValue( + child->getResolvedDimension(YGDimensionHeight), ownerHeight), + paddingAndBorder)); } else { // Compute the flex basis and hypothetical main size (i.e. the clamped // flex basis). @@ -1361,9 +1367,9 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node, "measure", config); - child->setLayoutComputedFlexBasis(YGFloatMax( + child->setLayoutComputedFlexBasis(YGFloatOptional(YGFloatMax( child->getLayout().measuredDimensions[dim[mainAxis]], - YGNodePaddingAndBorderForAxis(child, mainAxis, ownerWidth))); + YGNodePaddingAndBorderForAxis(child, mainAxis, ownerWidth)))); } child->setLayoutComputedFlexBasisGeneration(gCurrentGenerationCount); } @@ -1825,7 +1831,7 @@ static void YGNodeComputeFlexBasisForChildren( } if (child == singleFlexChild) { child->setLayoutComputedFlexBasisGeneration(gCurrentGenerationCount); - child->setLayoutComputedFlexBasis(0); + child->setLayoutComputedFlexBasis(YGFloatOptional(0)); } else { YGNodeComputeFlexBasisForChild( node, @@ -1840,7 +1846,8 @@ static void YGNodeComputeFlexBasisForChildren( config); } - totalOuterFlexBasis += child->getLayout().computedFlexBasis + + totalOuterFlexBasis += + YGUnwrapFloatOptional(child->getLayout().computedFlexBasis) + child->getMarginForAxis(mainAxis, availableInnerWidth); } } @@ -1880,7 +1887,7 @@ static YGCollectFlexItemsRowValues YGCalculateCollectFlexItemsRowValues( YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax( child, mainAxis, - child->getLayout().computedFlexBasis, + YGUnwrapFloatOptional(child->getLayout().computedFlexBasis), mainAxisownerSize)); // If this is a multi-line flow and this item pushes us over the @@ -1906,7 +1913,8 @@ static YGCollectFlexItemsRowValues YGCalculateCollectFlexItemsRowValues( // Unlike the grow factor, the shrink factor is scaled relative to the // child dimension. flexAlgoRowMeasurement.totalFlexShrinkScaledFactors += - -child->resolveFlexShrink() * child->getLayout().computedFlexBasis; + -child->resolveFlexShrink() * + YGUnwrapFloatOptional(child->getLayout().computedFlexBasis); } flexAlgoRowMeasurement.relativeChildren.push_back(child); @@ -1956,7 +1964,8 @@ static float YGDistributeFreeSpaceSecondPass( childFlexBasis = YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax( currentRelativeChild, mainAxis, - currentRelativeChild->getLayout().computedFlexBasis, + YGUnwrapFloatOptional( + currentRelativeChild->getLayout().computedFlexBasis), mainAxisownerSize)); float updatedMainSize = childFlexBasis; @@ -2131,7 +2140,8 @@ static void YGDistributeFreeSpaceFirstPass( float childFlexBasis = YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax( currentRelativeChild, mainAxis, - currentRelativeChild->getLayout().computedFlexBasis, + YGUnwrapFloatOptional( + currentRelativeChild->getLayout().computedFlexBasis), mainAxisownerSize)); if (collectedFlexItemsValues.remainingFreeSpace < 0) { @@ -2417,7 +2427,7 @@ static void YGJustifyMainAxis( // YGNodeDimWithMargin. collectedFlexItemsValues.mainDim += betweenMainDim + child->getMarginForAxis(mainAxis, availableInnerWidth) + - childLayout.computedFlexBasis; + YGUnwrapFloatOptional(childLayout.computedFlexBasis); collectedFlexItemsValues.crossDim = availableInnerCrossDim; } else { // The main dimension is the sum of all the elements dimension plus From f3c2ab306c360d79c8d8784cacc78b650858aaf3 Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Wed, 4 Apr 2018 07:55:42 -0700 Subject: [PATCH 0195/1109] Changed the type of return value of getLeadingPosition to YGFloatOptional Reviewed By: emilsjolander Differential Revision: D7344367 fbshipit-source-id: 0f5a667ca357b2ce056c86763aa3e9e4c54b82f0 --- ReactCommon/yoga/yoga/YGNode.cpp | 17 +++++++++-------- ReactCommon/yoga/yoga/YGNode.h | 3 ++- ReactCommon/yoga/yoga/Yoga.cpp | 16 ++++++++++------ 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/ReactCommon/yoga/yoga/YGNode.cpp b/ReactCommon/yoga/yoga/YGNode.cpp index eb840ef1dde9bc..3d1729cda73eb2 100644 --- a/ReactCommon/yoga/yoga/YGNode.cpp +++ b/ReactCommon/yoga/yoga/YGNode.cpp @@ -85,14 +85,14 @@ std::array YGNode::getResolvedDimensions() const { return resolvedDimensions_; } -float YGNode::getLeadingPosition( - const YGFlexDirection axis, - const float axisSize) const { +YGFloatOptional YGNode::getLeadingPosition( + const YGFlexDirection& axis, + const float& axisSize) const { if (YGFlexDirectionIsRow(axis)) { const YGValue* leadingPosition = YGComputedEdgeValue(style_.position, YGEdgeStart, &YGValueUndefined); if (leadingPosition->unit != YGUnitUndefined) { - return YGUnwrapFloatOptional(YGResolveValue(*leadingPosition, axisSize)); + return YGResolveValue(*leadingPosition, axisSize); } } @@ -100,8 +100,8 @@ float YGNode::getLeadingPosition( YGComputedEdgeValue(style_.position, leading[axis], &YGValueUndefined); return leadingPosition->unit == YGUnitUndefined - ? 0.0f - : YGUnwrapFloatOptional(YGResolveValue(*leadingPosition, axisSize)); + ? YGFloatOptional(0) + : YGResolveValue(*leadingPosition, axisSize); } float YGNode::getTrailingPosition( @@ -343,8 +343,9 @@ void YGNode::setLayoutDimension(float dimension, int index) { float YGNode::relativePosition( const YGFlexDirection axis, const float axisSize) { - return isLeadingPositionDefined(axis) ? getLeadingPosition(axis, axisSize) - : -getTrailingPosition(axis, axisSize); + return isLeadingPositionDefined(axis) + ? YGUnwrapFloatOptional(getLeadingPosition(axis, axisSize)) + : -getTrailingPosition(axis, axisSize); } void YGNode::setPosition( diff --git a/ReactCommon/yoga/yoga/YGNode.h b/ReactCommon/yoga/yoga/YGNode.h index fe24fa037f645e..8fb55d6def43f7 100644 --- a/ReactCommon/yoga/yoga/YGNode.h +++ b/ReactCommon/yoga/yoga/YGNode.h @@ -85,7 +85,8 @@ struct YGNode { YGValue getResolvedDimension(int index); // Methods related to positions, margin, padding and border - float getLeadingPosition(const YGFlexDirection axis, const float axisSize) const; + YGFloatOptional getLeadingPosition(const YGFlexDirection& axis, + const float& axisSize) const; bool isLeadingPositionDefined(const YGFlexDirection axis) const; bool isTrailingPosDefined(const YGFlexDirection axis) const; float getTrailingPosition(const YGFlexDirection axis, const float axisSize) const; diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index 3b117243e709f3..fbb37ee4d54647 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -1408,7 +1408,8 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, childWidth = node->getLayout().measuredDimensions[YGDimensionWidth] - (node->getLeadingBorder(YGFlexDirectionRow) + node->getTrailingBorder(YGFlexDirectionRow)) - - (child->getLeadingPosition(YGFlexDirectionRow, width) + + (YGUnwrapFloatOptional( + child->getLeadingPosition(YGFlexDirectionRow, width)) + child->getTrailingPosition(YGFlexDirectionRow, width)); childWidth = YGNodeBoundAxis(child, YGFlexDirectionRow, childWidth, width, width); } @@ -1427,7 +1428,8 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, childHeight = node->getLayout().measuredDimensions[YGDimensionHeight] - (node->getLeadingBorder(YGFlexDirectionColumn) + node->getTrailingBorder(YGFlexDirectionColumn)) - - (child->getLeadingPosition(YGFlexDirectionColumn, height) + + (YGUnwrapFloatOptional( + child->getLeadingPosition(YGFlexDirectionColumn, height)) + child->getTrailingPosition(YGFlexDirectionColumn, height)); childHeight = YGNodeBoundAxis(child, YGFlexDirectionColumn, childHeight, height, width); } @@ -2390,7 +2392,8 @@ static void YGJustifyMainAxis( // defined, we override the position to whatever the user said // (and margin/border). child->setLayoutPosition( - child->getLeadingPosition(mainAxis, availableInnerMainDim) + + YGUnwrapFloatOptional( + child->getLeadingPosition(mainAxis, availableInnerMainDim)) + node->getLeadingBorder(mainAxis) + child->getLeadingMargin(mainAxis, availableInnerWidth), pos[mainAxis]); @@ -2893,7 +2896,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, child->isLeadingPositionDefined(crossAxis); if (isChildLeadingPosDefined) { child->setLayoutPosition( - child->getLeadingPosition(crossAxis, availableInnerCrossDim) + + YGUnwrapFloatOptional(child->getLeadingPosition( + crossAxis, availableInnerCrossDim)) + node->getLeadingBorder(crossAxis) + child->getLeadingMargin(crossAxis, availableInnerWidth), pos[crossAxis]); @@ -3178,8 +3182,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, case YGAlignBaseline: { child->setLayoutPosition( currentLead + maxAscentForCurrentLine - YGBaseline(child) + - child->getLeadingPosition( - YGFlexDirectionColumn, availableInnerCrossDim), + YGUnwrapFloatOptional(child->getLeadingPosition( + YGFlexDirectionColumn, availableInnerCrossDim)), YGEdgeTop); break; From de70bc74d598f534fd80588aa79c7861483d72f8 Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Wed, 4 Apr 2018 07:55:44 -0700 Subject: [PATCH 0196/1109] Change the type of getTrailingPosition to YGFloatOptional Reviewed By: emilsjolander Differential Revision: D7344710 fbshipit-source-id: eb4c422b6e0f55d90b083221aa8ff1ab797d58a8 --- ReactCommon/yoga/yoga/YGNode.cpp | 14 +++++++------- ReactCommon/yoga/yoga/YGNode.h | 4 +++- ReactCommon/yoga/yoga/Yoga.cpp | 23 ++++++++++++----------- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/ReactCommon/yoga/yoga/YGNode.cpp b/ReactCommon/yoga/yoga/YGNode.cpp index 3d1729cda73eb2..68d7b10400f5f6 100644 --- a/ReactCommon/yoga/yoga/YGNode.cpp +++ b/ReactCommon/yoga/yoga/YGNode.cpp @@ -104,14 +104,14 @@ YGFloatOptional YGNode::getLeadingPosition( : YGResolveValue(*leadingPosition, axisSize); } -float YGNode::getTrailingPosition( - const YGFlexDirection axis, - const float axisSize) const { +YGFloatOptional YGNode::getTrailingPosition( + const YGFlexDirection& axis, + const float& axisSize) const { if (YGFlexDirectionIsRow(axis)) { const YGValue* trailingPosition = YGComputedEdgeValue(style_.position, YGEdgeEnd, &YGValueUndefined); if (trailingPosition->unit != YGUnitUndefined) { - return YGUnwrapFloatOptional(YGResolveValue(*trailingPosition, axisSize)); + return YGResolveValue(*trailingPosition, axisSize); } } @@ -119,8 +119,8 @@ float YGNode::getTrailingPosition( YGComputedEdgeValue(style_.position, trailing[axis], &YGValueUndefined); return trailingPosition->unit == YGUnitUndefined - ? 0.0f - : YGUnwrapFloatOptional(YGResolveValue(*trailingPosition, axisSize)); + ? YGFloatOptional(0) + : YGResolveValue(*trailingPosition, axisSize); } bool YGNode::isLeadingPositionDefined(const YGFlexDirection axis) const { @@ -345,7 +345,7 @@ float YGNode::relativePosition( const float axisSize) { return isLeadingPositionDefined(axis) ? YGUnwrapFloatOptional(getLeadingPosition(axis, axisSize)) - : -getTrailingPosition(axis, axisSize); + : -YGUnwrapFloatOptional(getTrailingPosition(axis, axisSize)); } void YGNode::setPosition( diff --git a/ReactCommon/yoga/yoga/YGNode.h b/ReactCommon/yoga/yoga/YGNode.h index 8fb55d6def43f7..87637991570f25 100644 --- a/ReactCommon/yoga/yoga/YGNode.h +++ b/ReactCommon/yoga/yoga/YGNode.h @@ -89,7 +89,9 @@ struct YGNode { const float& axisSize) const; bool isLeadingPositionDefined(const YGFlexDirection axis) const; bool isTrailingPosDefined(const YGFlexDirection axis) const; - float getTrailingPosition(const YGFlexDirection axis, const float axisSize) const; + YGFloatOptional getTrailingPosition( + const YGFlexDirection& axis, + const float& axisSize) const; float getLeadingMargin(const YGFlexDirection axis, const float widthSize) const; float getTrailingMargin(const YGFlexDirection axis, const float widthSize) const; float getLeadingBorder(const YGFlexDirection& flexDirection) const; diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index fbb37ee4d54647..2805e7f6c89614 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -1408,9 +1408,9 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, childWidth = node->getLayout().measuredDimensions[YGDimensionWidth] - (node->getLeadingBorder(YGFlexDirectionRow) + node->getTrailingBorder(YGFlexDirectionRow)) - - (YGUnwrapFloatOptional( - child->getLeadingPosition(YGFlexDirectionRow, width)) + - child->getTrailingPosition(YGFlexDirectionRow, width)); + YGUnwrapFloatOptional( + child->getLeadingPosition(YGFlexDirectionRow, width) + + child->getTrailingPosition(YGFlexDirectionRow, width)); childWidth = YGNodeBoundAxis(child, YGFlexDirectionRow, childWidth, width, width); } } @@ -1425,12 +1425,13 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, // offsets if they're defined. if (child->isLeadingPositionDefined(YGFlexDirectionColumn) && child->isTrailingPosDefined(YGFlexDirectionColumn)) { - childHeight = node->getLayout().measuredDimensions[YGDimensionHeight] - + childHeight = + node->getLayout().measuredDimensions[YGDimensionHeight] - (node->getLeadingBorder(YGFlexDirectionColumn) + node->getTrailingBorder(YGFlexDirectionColumn)) - - (YGUnwrapFloatOptional( - child->getLeadingPosition(YGFlexDirectionColumn, height)) + - child->getTrailingPosition(YGFlexDirectionColumn, height)); + YGUnwrapFloatOptional( + child->getLeadingPosition(YGFlexDirectionColumn, height) + + child->getTrailingPosition(YGFlexDirectionColumn, height)); childHeight = YGNodeBoundAxis(child, YGFlexDirectionColumn, childHeight, height, width); } } @@ -1503,8 +1504,8 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, child->getLayout().measuredDimensions[dim[mainAxis]] - node->getTrailingBorder(mainAxis) - child->getTrailingMargin(mainAxis, width) - - child->getTrailingPosition( - mainAxis, isMainAxisRow ? width : height), + YGUnwrapFloatOptional(child->getTrailingPosition( + mainAxis, isMainAxisRow ? width : height)), leading[mainAxis]); } else if ( !child->isLeadingPositionDefined(mainAxis) && @@ -1530,8 +1531,8 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, child->getLayout().measuredDimensions[dim[crossAxis]] - node->getTrailingBorder(crossAxis) - child->getTrailingMargin(crossAxis, width) - - child->getTrailingPosition( - crossAxis, isMainAxisRow ? height : width), + YGUnwrapFloatOptional(child->getTrailingPosition( + crossAxis, isMainAxisRow ? height : width)), leading[crossAxis]); } else if ( From f0490d121737c8acc59e2ce181cf92915621f678 Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Wed, 4 Apr 2018 07:55:46 -0700 Subject: [PATCH 0197/1109] Refactored relativePosition private method to YGFloatOptional return type Reviewed By: emilsjolander Differential Revision: D7344939 fbshipit-source-id: 72443d38426a211d3e84be814e6a61baf4d26703 --- ReactCommon/yoga/yoga/YGNode.cpp | 40 +++++++++++++++++++++----------- ReactCommon/yoga/yoga/YGNode.h | 8 ++++--- 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/ReactCommon/yoga/yoga/YGNode.cpp b/ReactCommon/yoga/yoga/YGNode.cpp index 68d7b10400f5f6..7d29caf0431c8c 100644 --- a/ReactCommon/yoga/yoga/YGNode.cpp +++ b/ReactCommon/yoga/yoga/YGNode.cpp @@ -123,7 +123,7 @@ YGFloatOptional YGNode::getTrailingPosition( : YGResolveValue(*trailingPosition, axisSize); } -bool YGNode::isLeadingPositionDefined(const YGFlexDirection axis) const { +bool YGNode::isLeadingPositionDefined(const YGFlexDirection& axis) const { return (YGFlexDirectionIsRow(axis) && YGComputedEdgeValue(style_.position, YGEdgeStart, &YGValueUndefined) ->unit != YGUnitUndefined) || @@ -131,7 +131,7 @@ bool YGNode::isLeadingPositionDefined(const YGFlexDirection axis) const { ->unit != YGUnitUndefined; } -bool YGNode::isTrailingPosDefined(const YGFlexDirection axis) const { +bool YGNode::isTrailingPosDefined(const YGFlexDirection& axis) const { return (YGFlexDirectionIsRow(axis) && YGComputedEdgeValue(style_.position, YGEdgeEnd, &YGValueUndefined) ->unit != YGUnitUndefined) || @@ -340,12 +340,18 @@ void YGNode::setLayoutDimension(float dimension, int index) { // If both left and right are defined, then use left. Otherwise return // +left or -right depending on which is defined. -float YGNode::relativePosition( - const YGFlexDirection axis, - const float axisSize) { - return isLeadingPositionDefined(axis) - ? YGUnwrapFloatOptional(getLeadingPosition(axis, axisSize)) - : -YGUnwrapFloatOptional(getTrailingPosition(axis, axisSize)); +YGFloatOptional YGNode::relativePosition( + const YGFlexDirection& axis, + const float& axisSize) const { + if (isLeadingPositionDefined(axis)) { + return getLeadingPosition(axis, axisSize); + } + + YGFloatOptional trailingPosition = getTrailingPosition(axis, axisSize); + if (!trailingPosition.isUndefined()) { + trailingPosition.setValue(-1 * trailingPosition.getValue()); + } + return trailingPosition; } void YGNode::setPosition( @@ -362,20 +368,26 @@ void YGNode::setPosition( const YGFlexDirection crossAxis = YGFlexDirectionCross(mainAxis, directionRespectingRoot); - const float relativePositionMain = relativePosition(mainAxis, mainSize); - const float relativePositionCross = relativePosition(crossAxis, crossSize); + const YGFloatOptional relativePositionMain = + relativePosition(mainAxis, mainSize); + const YGFloatOptional relativePositionCross = + relativePosition(crossAxis, crossSize); setLayoutPosition( - getLeadingMargin(mainAxis, ownerWidth) + relativePositionMain, + getLeadingMargin(mainAxis, ownerWidth) + + YGUnwrapFloatOptional(relativePositionMain), leading[mainAxis]); setLayoutPosition( - getTrailingMargin(mainAxis, ownerWidth) + relativePositionMain, + getTrailingMargin(mainAxis, ownerWidth) + + YGUnwrapFloatOptional(relativePositionMain), trailing[mainAxis]); setLayoutPosition( - getLeadingMargin(crossAxis, ownerWidth) + relativePositionCross, + getLeadingMargin(crossAxis, ownerWidth) + + YGUnwrapFloatOptional(relativePositionCross), leading[crossAxis]); setLayoutPosition( - getTrailingMargin(crossAxis, ownerWidth) + relativePositionCross, + getTrailingMargin(crossAxis, ownerWidth) + + YGUnwrapFloatOptional(relativePositionCross), trailing[crossAxis]); } diff --git a/ReactCommon/yoga/yoga/YGNode.h b/ReactCommon/yoga/yoga/YGNode.h index 87637991570f25..95fac7214b307a 100644 --- a/ReactCommon/yoga/yoga/YGNode.h +++ b/ReactCommon/yoga/yoga/YGNode.h @@ -30,7 +30,9 @@ struct YGNode { bool isDirty_; std::array resolvedDimensions_; - float relativePosition(const YGFlexDirection axis, const float axisSize); + YGFloatOptional relativePosition( + const YGFlexDirection& axis, + const float& axisSize) const; public: YGNode(); @@ -87,8 +89,8 @@ struct YGNode { // Methods related to positions, margin, padding and border YGFloatOptional getLeadingPosition(const YGFlexDirection& axis, const float& axisSize) const; - bool isLeadingPositionDefined(const YGFlexDirection axis) const; - bool isTrailingPosDefined(const YGFlexDirection axis) const; + bool isLeadingPositionDefined(const YGFlexDirection& axis) const; + bool isTrailingPosDefined(const YGFlexDirection& axis) const; YGFloatOptional getTrailingPosition( const YGFlexDirection& axis, const float& axisSize) const; From 1024e98b9533bc0094ace2e324ed36876b19de9e Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Wed, 4 Apr 2018 07:55:49 -0700 Subject: [PATCH 0198/1109] Changed the return type of getLeadingMargin to YGFloatOptional Reviewed By: emilsjolander Differential Revision: D7349907 fbshipit-source-id: b20894fbc33fd5b29a28f3c9174d1b5f406774ab --- ReactCommon/yoga/yoga/YGNode.cpp | 24 ++++++++++++------------ ReactCommon/yoga/yoga/YGNode.h | 4 +++- ReactCommon/yoga/yoga/Yoga.cpp | 29 +++++++++++++++++++---------- 3 files changed, 34 insertions(+), 23 deletions(-) diff --git a/ReactCommon/yoga/yoga/YGNode.cpp b/ReactCommon/yoga/yoga/YGNode.cpp index 7d29caf0431c8c..f388f91dd4e930 100644 --- a/ReactCommon/yoga/yoga/YGNode.cpp +++ b/ReactCommon/yoga/yoga/YGNode.cpp @@ -139,18 +139,17 @@ bool YGNode::isTrailingPosDefined(const YGFlexDirection& axis) const { ->unit != YGUnitUndefined; } -float YGNode::getLeadingMargin( - const YGFlexDirection axis, - const float widthSize) const { +YGFloatOptional YGNode::getLeadingMargin( + const YGFlexDirection& axis, + const float& widthSize) const { if (YGFlexDirectionIsRow(axis) && style_.margin[YGEdgeStart].unit != YGUnitUndefined) { - return YGUnwrapFloatOptional( - YGResolveValueMargin(style_.margin[YGEdgeStart], widthSize)); + return YGResolveValueMargin(style_.margin[YGEdgeStart], widthSize); } - return YGUnwrapFloatOptional(YGResolveValueMargin( + return YGResolveValueMargin( *YGComputedEdgeValue(style_.margin, leading[axis], &YGValueZero), - widthSize)); + widthSize); } float YGNode::getTrailingMargin( @@ -171,7 +170,8 @@ float YGNode::getTrailingMargin( float YGNode::getMarginForAxis( const YGFlexDirection axis, const float widthSize) const { - return getLeadingMargin(axis, widthSize) + getTrailingMargin(axis, widthSize); + return YGUnwrapFloatOptional(getLeadingMargin(axis, widthSize)) + + getTrailingMargin(axis, widthSize); } // Setters @@ -374,16 +374,16 @@ void YGNode::setPosition( relativePosition(crossAxis, crossSize); setLayoutPosition( - getLeadingMargin(mainAxis, ownerWidth) + - YGUnwrapFloatOptional(relativePositionMain), + YGUnwrapFloatOptional( + getLeadingMargin(mainAxis, ownerWidth) + relativePositionMain), leading[mainAxis]); setLayoutPosition( getTrailingMargin(mainAxis, ownerWidth) + YGUnwrapFloatOptional(relativePositionMain), trailing[mainAxis]); setLayoutPosition( - getLeadingMargin(crossAxis, ownerWidth) + - YGUnwrapFloatOptional(relativePositionCross), + YGUnwrapFloatOptional( + getLeadingMargin(crossAxis, ownerWidth) + relativePositionCross), leading[crossAxis]); setLayoutPosition( getTrailingMargin(crossAxis, ownerWidth) + diff --git a/ReactCommon/yoga/yoga/YGNode.h b/ReactCommon/yoga/yoga/YGNode.h index 95fac7214b307a..7b2275ea227405 100644 --- a/ReactCommon/yoga/yoga/YGNode.h +++ b/ReactCommon/yoga/yoga/YGNode.h @@ -94,7 +94,9 @@ struct YGNode { YGFloatOptional getTrailingPosition( const YGFlexDirection& axis, const float& axisSize) const; - float getLeadingMargin(const YGFlexDirection axis, const float widthSize) const; + YGFloatOptional getLeadingMargin( + const YGFlexDirection& axis, + const float& widthSize) const; float getTrailingMargin(const YGFlexDirection axis, const float widthSize) const; float getLeadingBorder(const YGFlexDirection& flexDirection) const; float getTrailingBorder(const YGFlexDirection& flexDirection) const; diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index 2805e7f6c89614..1bcb4a205298e5 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -1093,7 +1093,7 @@ static inline float YGNodeDimWithMargin(const YGNodeRef node, const YGFlexDirection axis, const float widthSize) { return node->getLayout().measuredDimensions[dim[axis]] + - node->getLeadingMargin(axis, widthSize) + + YGUnwrapFloatOptional(node->getLeadingMargin(axis, widthSize)) + node->getTrailingMargin(axis, widthSize); } @@ -2396,7 +2396,8 @@ static void YGJustifyMainAxis( YGUnwrapFloatOptional( child->getLeadingPosition(mainAxis, availableInnerMainDim)) + node->getLeadingBorder(mainAxis) + - child->getLeadingMargin(mainAxis, availableInnerWidth), + YGUnwrapFloatOptional( + child->getLeadingMargin(mainAxis, availableInnerWidth)), pos[mainAxis]); } } else { @@ -2573,11 +2574,15 @@ static void YGNodelayoutImpl(const YGNodeRef node, YGResolveFlexDirection(YGFlexDirectionColumn, direction); node->setLayoutMargin( - node->getLeadingMargin(flexRowDirection, ownerWidth), YGEdgeStart); + YGUnwrapFloatOptional( + node->getLeadingMargin(flexRowDirection, ownerWidth)), + YGEdgeStart); node->setLayoutMargin( node->getTrailingMargin(flexRowDirection, ownerWidth), YGEdgeEnd); node->setLayoutMargin( - node->getLeadingMargin(flexColumnDirection, ownerWidth), YGEdgeTop); + YGUnwrapFloatOptional( + node->getLeadingMargin(flexColumnDirection, ownerWidth)), + YGEdgeTop); node->setLayoutMargin( node->getTrailingMargin(flexColumnDirection, ownerWidth), YGEdgeBottom); @@ -2900,7 +2905,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, YGUnwrapFloatOptional(child->getLeadingPosition( crossAxis, availableInnerCrossDim)) + node->getLeadingBorder(crossAxis) + - child->getLeadingMargin(crossAxis, availableInnerWidth), + YGUnwrapFloatOptional(child->getLeadingMargin( + crossAxis, availableInnerWidth)), pos[crossAxis]); } // If leading position is not defined or calculations result in Nan, default to border + margin @@ -2908,7 +2914,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, YGFloatIsUndefined(child->getLayout().position[pos[crossAxis]])) { child->setLayoutPosition( node->getLeadingBorder(crossAxis) + - child->getLeadingMargin(crossAxis, availableInnerWidth), + YGUnwrapFloatOptional(child->getLeadingMargin( + crossAxis, availableInnerWidth)), pos[crossAxis]); } } else { @@ -3083,8 +3090,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, } if (YGNodeAlignItem(node, child) == YGAlignBaseline) { const float ascent = YGBaseline(child) + - child->getLeadingMargin( - YGFlexDirectionColumn, availableInnerWidth); + YGUnwrapFloatOptional(child->getLeadingMargin( + YGFlexDirectionColumn, availableInnerWidth)); const float descent = child->getLayout().measuredDimensions[YGDimensionHeight] + child->getMarginForAxis( @@ -3113,7 +3120,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, case YGAlignFlexStart: { child->setLayoutPosition( currentLead + - child->getLeadingMargin(crossAxis, availableInnerWidth), + YGUnwrapFloatOptional(child->getLeadingMargin( + crossAxis, availableInnerWidth)), pos[crossAxis]); break; } @@ -3138,7 +3146,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, case YGAlignStretch: { child->setLayoutPosition( currentLead + - child->getLeadingMargin(crossAxis, availableInnerWidth), + YGUnwrapFloatOptional(child->getLeadingMargin( + crossAxis, availableInnerWidth)), pos[crossAxis]); // Remeasure child with the line height as it as been only measured with the From 3a65fa56c50cec118b5bd044edd760cd81b79d72 Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Wed, 4 Apr 2018 07:55:51 -0700 Subject: [PATCH 0199/1109] Change the return type of getTrailingMargin to YGFloatOptional Reviewed By: emilsjolander Differential Revision: D7350221 fbshipit-source-id: 61a67364c1975ec6dd1883bc2cb4968b830c73df --- ReactCommon/yoga/yoga/YGNode.cpp | 25 ++++++++++++------------- ReactCommon/yoga/yoga/YGNode.h | 4 +++- ReactCommon/yoga/yoga/Yoga.cpp | 21 +++++++++++++-------- 3 files changed, 28 insertions(+), 22 deletions(-) diff --git a/ReactCommon/yoga/yoga/YGNode.cpp b/ReactCommon/yoga/yoga/YGNode.cpp index f388f91dd4e930..b3115c18a9df5f 100644 --- a/ReactCommon/yoga/yoga/YGNode.cpp +++ b/ReactCommon/yoga/yoga/YGNode.cpp @@ -152,26 +152,25 @@ YGFloatOptional YGNode::getLeadingMargin( widthSize); } -float YGNode::getTrailingMargin( - const YGFlexDirection axis, - const float widthSize) const { +YGFloatOptional YGNode::getTrailingMargin( + const YGFlexDirection& axis, + const float& widthSize) const { if (YGFlexDirectionIsRow(axis) && style_.margin[YGEdgeEnd].unit != YGUnitUndefined) { - return YGUnwrapFloatOptional( - YGResolveValueMargin(style_.margin[YGEdgeEnd], widthSize)); + return YGResolveValueMargin(style_.margin[YGEdgeEnd], widthSize); } - return YGUnwrapFloatOptional(YGResolveValueMargin( + return YGResolveValueMargin( *YGComputedEdgeValue(style_.margin, trailing[axis], &YGValueZero), - widthSize)); + widthSize); } // TODO: Make its return type to YGFloatOptional float YGNode::getMarginForAxis( const YGFlexDirection axis, const float widthSize) const { - return YGUnwrapFloatOptional(getLeadingMargin(axis, widthSize)) + - getTrailingMargin(axis, widthSize); + return YGUnwrapFloatOptional( + getLeadingMargin(axis, widthSize) + getTrailingMargin(axis, widthSize)); } // Setters @@ -378,16 +377,16 @@ void YGNode::setPosition( getLeadingMargin(mainAxis, ownerWidth) + relativePositionMain), leading[mainAxis]); setLayoutPosition( - getTrailingMargin(mainAxis, ownerWidth) + - YGUnwrapFloatOptional(relativePositionMain), + YGUnwrapFloatOptional( + getTrailingMargin(mainAxis, ownerWidth) + relativePositionMain), trailing[mainAxis]); setLayoutPosition( YGUnwrapFloatOptional( getLeadingMargin(crossAxis, ownerWidth) + relativePositionCross), leading[crossAxis]); setLayoutPosition( - getTrailingMargin(crossAxis, ownerWidth) + - YGUnwrapFloatOptional(relativePositionCross), + YGUnwrapFloatOptional( + getTrailingMargin(crossAxis, ownerWidth) + relativePositionCross), trailing[crossAxis]); } diff --git a/ReactCommon/yoga/yoga/YGNode.h b/ReactCommon/yoga/yoga/YGNode.h index 7b2275ea227405..5c628a6f5827ce 100644 --- a/ReactCommon/yoga/yoga/YGNode.h +++ b/ReactCommon/yoga/yoga/YGNode.h @@ -97,7 +97,9 @@ struct YGNode { YGFloatOptional getLeadingMargin( const YGFlexDirection& axis, const float& widthSize) const; - float getTrailingMargin(const YGFlexDirection axis, const float widthSize) const; + YGFloatOptional getTrailingMargin( + const YGFlexDirection& axis, + const float& widthSize) const; float getLeadingBorder(const YGFlexDirection& flexDirection) const; float getTrailingBorder(const YGFlexDirection& flexDirection) const; YGFloatOptional getLeadingPadding( diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index 1bcb4a205298e5..efb09e4439daeb 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -1093,8 +1093,9 @@ static inline float YGNodeDimWithMargin(const YGNodeRef node, const YGFlexDirection axis, const float widthSize) { return node->getLayout().measuredDimensions[dim[axis]] + - YGUnwrapFloatOptional(node->getLeadingMargin(axis, widthSize)) + - node->getTrailingMargin(axis, widthSize); + YGUnwrapFloatOptional( + node->getLeadingMargin(axis, widthSize) + + node->getTrailingMargin(axis, widthSize)); } static inline bool YGNodeIsStyleDimDefined(const YGNodeRef node, @@ -1503,7 +1504,7 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, node->getLayout().measuredDimensions[dim[mainAxis]] - child->getLayout().measuredDimensions[dim[mainAxis]] - node->getTrailingBorder(mainAxis) - - child->getTrailingMargin(mainAxis, width) - + YGUnwrapFloatOptional(child->getTrailingMargin(mainAxis, width)) - YGUnwrapFloatOptional(child->getTrailingPosition( mainAxis, isMainAxisRow ? width : height)), leading[mainAxis]); @@ -1530,7 +1531,7 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, node->getLayout().measuredDimensions[dim[crossAxis]] - child->getLayout().measuredDimensions[dim[crossAxis]] - node->getTrailingBorder(crossAxis) - - child->getTrailingMargin(crossAxis, width) - + YGUnwrapFloatOptional(child->getTrailingMargin(crossAxis, width)) - YGUnwrapFloatOptional(child->getTrailingPosition( crossAxis, isMainAxisRow ? height : width)), leading[crossAxis]); @@ -2578,13 +2579,17 @@ static void YGNodelayoutImpl(const YGNodeRef node, node->getLeadingMargin(flexRowDirection, ownerWidth)), YGEdgeStart); node->setLayoutMargin( - node->getTrailingMargin(flexRowDirection, ownerWidth), YGEdgeEnd); + YGUnwrapFloatOptional( + node->getTrailingMargin(flexRowDirection, ownerWidth)), + YGEdgeEnd); node->setLayoutMargin( YGUnwrapFloatOptional( node->getLeadingMargin(flexColumnDirection, ownerWidth)), YGEdgeTop); node->setLayoutMargin( - node->getTrailingMargin(flexColumnDirection, ownerWidth), YGEdgeBottom); + YGUnwrapFloatOptional( + node->getTrailingMargin(flexColumnDirection, ownerWidth)), + YGEdgeBottom); node->setLayoutBorder(node->getLeadingBorder(flexRowDirection), YGEdgeStart); node->setLayoutBorder(node->getTrailingBorder(flexRowDirection), YGEdgeEnd); @@ -3128,8 +3133,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, case YGAlignFlexEnd: { child->setLayoutPosition( currentLead + lineHeight - - child->getTrailingMargin( - crossAxis, availableInnerWidth) - + YGUnwrapFloatOptional(child->getTrailingMargin( + crossAxis, availableInnerWidth)) - child->getLayout().measuredDimensions[dim[crossAxis]], pos[crossAxis]); break; From 4841aed82cdea084428754aea6d86e45d6754d4f Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Wed, 4 Apr 2018 07:55:54 -0700 Subject: [PATCH 0200/1109] Change the return type of getMarginForAxis to YGFloatOptional Reviewed By: emilsjolander Differential Revision: D7350337 fbshipit-source-id: dd1ee2fcd295ccd14f7d414ab0c24090b24e91e0 --- ReactCommon/yoga/yoga/YGNode.cpp | 10 +-- ReactCommon/yoga/yoga/YGNode.h | 4 +- ReactCommon/yoga/yoga/Yoga.cpp | 123 +++++++++++++++++-------------- 3 files changed, 73 insertions(+), 64 deletions(-) diff --git a/ReactCommon/yoga/yoga/YGNode.cpp b/ReactCommon/yoga/yoga/YGNode.cpp index b3115c18a9df5f..64a47d356a373f 100644 --- a/ReactCommon/yoga/yoga/YGNode.cpp +++ b/ReactCommon/yoga/yoga/YGNode.cpp @@ -165,12 +165,10 @@ YGFloatOptional YGNode::getTrailingMargin( widthSize); } -// TODO: Make its return type to YGFloatOptional -float YGNode::getMarginForAxis( - const YGFlexDirection axis, - const float widthSize) const { - return YGUnwrapFloatOptional( - getLeadingMargin(axis, widthSize) + getTrailingMargin(axis, widthSize)); +YGFloatOptional YGNode::getMarginForAxis( + const YGFlexDirection& axis, + const float& widthSize) const { + return getLeadingMargin(axis, widthSize) + getTrailingMargin(axis, widthSize); } // Setters diff --git a/ReactCommon/yoga/yoga/YGNode.h b/ReactCommon/yoga/yoga/YGNode.h index 5c628a6f5827ce..5f7038f44fc786 100644 --- a/ReactCommon/yoga/yoga/YGNode.h +++ b/ReactCommon/yoga/yoga/YGNode.h @@ -114,7 +114,9 @@ struct YGNode { YGFloatOptional getTrailingPaddingAndBorder( const YGFlexDirection& axis, const float& widthSize) const; - float getMarginForAxis(const YGFlexDirection axis, const float widthSize) const; + YGFloatOptional getMarginForAxis( + const YGFlexDirection& axis, + const float& widthSize) const; // Setters void setContext(void* context); diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index efb09e4439daeb..11c0fddd73783f 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -1264,10 +1264,10 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node, childWidthMeasureMode = YGMeasureModeUndefined; childHeightMeasureMode = YGMeasureModeUndefined; - const float marginRow = - child->getMarginForAxis(YGFlexDirectionRow, ownerWidth); - const float marginColumn = - child->getMarginForAxis(YGFlexDirectionColumn, ownerWidth); + const float& marginRow = YGUnwrapFloatOptional( + child->getMarginForAxis(YGFlexDirectionRow, ownerWidth)); + const float& marginColumn = YGUnwrapFloatOptional( + child->getMarginForAxis(YGFlexDirectionColumn, ownerWidth)); if (isRowStyleDimDefined) { childWidth = @@ -1392,9 +1392,10 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, YGMeasureMode childWidthMeasureMode = YGMeasureModeUndefined; YGMeasureMode childHeightMeasureMode = YGMeasureModeUndefined; - const float marginRow = child->getMarginForAxis(YGFlexDirectionRow, width); - const float marginColumn = - child->getMarginForAxis(YGFlexDirectionColumn, width); + const float& marginRow = + YGUnwrapFloatOptional(child->getMarginForAxis(YGFlexDirectionRow, width)); + const float& marginColumn = YGUnwrapFloatOptional( + child->getMarginForAxis(YGFlexDirectionColumn, width)); if (YGNodeIsStyleDimDefined(child, YGFlexDirectionRow, width)) { childWidth = @@ -1481,9 +1482,11 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, "abs-measure", config); childWidth = child->getLayout().measuredDimensions[YGDimensionWidth] + - child->getMarginForAxis(YGFlexDirectionRow, width); + YGUnwrapFloatOptional( + child->getMarginForAxis(YGFlexDirectionRow, width)); childHeight = child->getLayout().measuredDimensions[YGDimensionHeight] + - child->getMarginForAxis(YGFlexDirectionColumn, width); + YGUnwrapFloatOptional( + child->getMarginForAxis(YGFlexDirectionColumn, width)); } YGLayoutNodeInternal(child, @@ -1571,10 +1574,10 @@ static void YGNodeWithMeasureFuncSetMeasuredDimensions(const YGNodeRef node, YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, availableWidth); const float paddingAndBorderAxisColumn = YGNodePaddingAndBorderForAxis(node, YGFlexDirectionColumn, availableWidth); - const float marginAxisRow = - node->getMarginForAxis(YGFlexDirectionRow, availableWidth); - const float marginAxisColumn = - node->getMarginForAxis(YGFlexDirectionColumn, availableWidth); + const float marginAxisRow = YGUnwrapFloatOptional( + node->getMarginForAxis(YGFlexDirectionRow, availableWidth)); + const float marginAxisColumn = YGUnwrapFloatOptional( + node->getMarginForAxis(YGFlexDirectionColumn, availableWidth)); // We want to make sure we don't call measure with negative size const float innerWidth = YGFloatIsUndefined(availableWidth) @@ -1648,10 +1651,10 @@ static void YGNodeEmptyContainerSetMeasuredDimensions(const YGNodeRef node, YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, ownerWidth); const float paddingAndBorderAxisColumn = YGNodePaddingAndBorderForAxis(node, YGFlexDirectionColumn, ownerWidth); - const float marginAxisRow = - node->getMarginForAxis(YGFlexDirectionRow, ownerWidth); - const float marginAxisColumn = - node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth); + const float marginAxisRow = YGUnwrapFloatOptional( + node->getMarginForAxis(YGFlexDirectionRow, ownerWidth)); + const float marginAxisColumn = YGUnwrapFloatOptional( + node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth)); node->setLayoutMeasuredDimension( YGNodeBoundAxis( @@ -1691,10 +1694,10 @@ static bool YGNodeFixedSizeSetMeasuredDimensions(const YGNodeRef node, heightMeasureMode == YGMeasureModeAtMost && availableHeight <= 0.0f) || (widthMeasureMode == YGMeasureModeExactly && heightMeasureMode == YGMeasureModeExactly)) { - const float marginAxisColumn = - node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth); - const float marginAxisRow = - node->getMarginForAxis(YGFlexDirectionRow, ownerWidth); + const float& marginAxisColumn = YGUnwrapFloatOptional( + node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth)); + const float& marginAxisRow = YGUnwrapFloatOptional( + node->getMarginForAxis(YGFlexDirectionRow, ownerWidth)); node->setLayoutMeasuredDimension( YGNodeBoundAxis( @@ -1748,7 +1751,8 @@ static float YGNodeCalculateAvailableInnerDim( YGDimension dimension = YGFlexDirectionIsRow(axis) ? YGDimensionWidth : YGDimensionHeight; - const float margin = node->getMarginForAxis(direction, ownerDim); + const float margin = + YGUnwrapFloatOptional(node->getMarginForAxis(direction, ownerDim)); const float paddingAndBorder = YGNodePaddingAndBorderForAxis(node, direction, ownerDim); @@ -1850,9 +1854,9 @@ static void YGNodeComputeFlexBasisForChildren( config); } - totalOuterFlexBasis += - YGUnwrapFloatOptional(child->getLayout().computedFlexBasis) + - child->getMarginForAxis(mainAxis, availableInnerWidth); + totalOuterFlexBasis += YGUnwrapFloatOptional( + child->getLayout().computedFlexBasis + + child->getMarginForAxis(mainAxis, availableInnerWidth)); } } @@ -1885,8 +1889,8 @@ static YGCollectFlexItemsRowValues YGCalculateCollectFlexItemsRowValues( continue; } child->setLineIndex(lineCount); - const float childMarginMainAxis = - child->getMarginForAxis(mainAxis, availableInnerWidth); + const float childMarginMainAxis = YGUnwrapFloatOptional( + child->getMarginForAxis(mainAxis, availableInnerWidth)); const float flexBasisWithMinAndMaxConstraints = YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax( child, @@ -2020,10 +2024,10 @@ static float YGDistributeFreeSpaceSecondPass( deltaFreeSpace += updatedMainSize - childFlexBasis; - const float marginMain = - currentRelativeChild->getMarginForAxis(mainAxis, availableInnerWidth); - const float marginCross = - currentRelativeChild->getMarginForAxis(crossAxis, availableInnerWidth); + const float marginMain = YGUnwrapFloatOptional( + currentRelativeChild->getMarginForAxis(mainAxis, availableInnerWidth)); + const float marginCross = YGUnwrapFloatOptional( + currentRelativeChild->getMarginForAxis(crossAxis, availableInnerWidth)); float childCrossSize; float childMainSize = updatedMainSize + marginMain; @@ -2432,7 +2436,8 @@ static void YGJustifyMainAxis( // they weren't computed. This means we can't call // YGNodeDimWithMargin. collectedFlexItemsValues.mainDim += betweenMainDim + - child->getMarginForAxis(mainAxis, availableInnerWidth) + + YGUnwrapFloatOptional(child->getMarginForAxis( + mainAxis, availableInnerWidth)) + YGUnwrapFloatOptional(childLayout.computedFlexBasis); collectedFlexItemsValues.crossDim = availableInnerCrossDim; } else { @@ -2678,10 +2683,10 @@ static void YGNodelayoutImpl(const YGNodeRef node, const float paddingAndBorderAxisColumn = isMainAxisRow ? paddingAndBorderAxisCross : paddingAndBorderAxisMain; - const float marginAxisRow = - node->getMarginForAxis(YGFlexDirectionRow, ownerWidth); - const float marginAxisColumn = - node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth); + const float marginAxisRow = YGUnwrapFloatOptional( + node->getMarginForAxis(YGFlexDirectionRow, ownerWidth)); + const float marginAxisColumn = YGUnwrapFloatOptional( + node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth)); const float minInnerWidth = YGUnwrapFloatOptional(YGResolveValue(node->getStyle().minDimensions[YGDimensionWidth], ownerWidth)) - @@ -2945,15 +2950,16 @@ static void YGNodelayoutImpl(const YGNodeRef node, child->getLayout().measuredDimensions[dim[mainAxis]]; float childCrossSize = !child->getStyle().aspectRatio.isUndefined() - ? ((child->getMarginForAxis(crossAxis, availableInnerWidth) + + ? ((YGUnwrapFloatOptional(child->getMarginForAxis( + crossAxis, availableInnerWidth)) + (isMainAxisRow ? childMainSize / child->getStyle().aspectRatio.getValue() : childMainSize * child->getStyle().aspectRatio.getValue()))) : collectedFlexItemsValues.crossDim; - childMainSize += - child->getMarginForAxis(mainAxis, availableInnerWidth); + childMainSize += YGUnwrapFloatOptional( + child->getMarginForAxis(mainAxis, availableInnerWidth)); YGMeasureMode childMainMeasureMode = YGMeasureModeExactly; YGMeasureMode childCrossMeasureMode = YGMeasureModeExactly; @@ -3091,7 +3097,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, lineHeight = YGFloatMax( lineHeight, child->getLayout().measuredDimensions[dim[crossAxis]] + - child->getMarginForAxis(crossAxis, availableInnerWidth)); + YGUnwrapFloatOptional(child->getMarginForAxis( + crossAxis, availableInnerWidth))); } if (YGNodeAlignItem(node, child) == YGAlignBaseline) { const float ascent = YGBaseline(child) + @@ -3099,8 +3106,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, YGFlexDirectionColumn, availableInnerWidth)); const float descent = child->getLayout().measuredDimensions[YGDimensionHeight] + - child->getMarginForAxis( - YGFlexDirectionColumn, availableInnerWidth) - + YGUnwrapFloatOptional(child->getMarginForAxis( + YGFlexDirectionColumn, availableInnerWidth)) - ascent; maxAscentForCurrentLine = YGFloatMax(maxAscentForCurrentLine, ascent); @@ -3161,14 +3168,15 @@ static void YGNodelayoutImpl(const YGNodeRef node, const float childWidth = isMainAxisRow ? (child->getLayout() .measuredDimensions[YGDimensionWidth] + - child->getMarginForAxis(mainAxis, availableInnerWidth)) + YGUnwrapFloatOptional(child->getMarginForAxis( + mainAxis, availableInnerWidth))) : lineHeight; const float childHeight = !isMainAxisRow ? (child->getLayout() .measuredDimensions[YGDimensionHeight] + - child->getMarginForAxis( - crossAxis, availableInnerWidth)) + YGUnwrapFloatOptional(child->getMarginForAxis( + crossAxis, availableInnerWidth))) : lineHeight; if (!(YGFloatsEqual( @@ -3548,10 +3556,10 @@ bool YGLayoutNodeInternal(const YGNodeRef node, // expensive to measure, so it's worth avoiding redundant measurements if at // all possible. if (node->getMeasure() != nullptr) { - const float marginAxisRow = - node->getMarginForAxis(YGFlexDirectionRow, ownerWidth); - const float marginAxisColumn = - node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth); + const float marginAxisRow = YGUnwrapFloatOptional( + node->getMarginForAxis(YGFlexDirectionRow, ownerWidth)); + const float marginAxisColumn = YGUnwrapFloatOptional( + node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth)); // First, try to use the layout cache. if (YGNodeCanUseCachedMeasurement(widthMeasureMode, @@ -3828,10 +3836,10 @@ void YGNodeCalculateLayout( float width = YGUndefined; YGMeasureMode widthMeasureMode = YGMeasureModeUndefined; if (YGNodeIsStyleDimDefined(node, YGFlexDirectionRow, ownerWidth)) { - width = - YGUnwrapFloatOptional(YGResolveValue( - node->getResolvedDimension(dim[YGFlexDirectionRow]), ownerWidth)) + - node->getMarginForAxis(YGFlexDirectionRow, ownerWidth); + width = YGUnwrapFloatOptional( + YGResolveValue( + node->getResolvedDimension(dim[YGFlexDirectionRow]), ownerWidth) + + node->getMarginForAxis(YGFlexDirectionRow, ownerWidth)); widthMeasureMode = YGMeasureModeExactly; } else if (!YGResolveValue( node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth) @@ -3848,10 +3856,11 @@ void YGNodeCalculateLayout( float height = YGUndefined; YGMeasureMode heightMeasureMode = YGMeasureModeUndefined; if (YGNodeIsStyleDimDefined(node, YGFlexDirectionColumn, ownerHeight)) { - height = YGUnwrapFloatOptional(YGResolveValue( - node->getResolvedDimension(dim[YGFlexDirectionColumn]), - ownerHeight)) + - node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth); + height = YGUnwrapFloatOptional( + YGResolveValue( + node->getResolvedDimension(dim[YGFlexDirectionColumn]), + ownerHeight) + + node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth)); heightMeasureMode = YGMeasureModeExactly; } else if (!YGResolveValue( node->getStyle().maxDimensions[YGDimensionHeight], From c041c9fd628a9a216a52f6ffce2bf4b98a66cb29 Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Wed, 4 Apr 2018 08:17:04 -0700 Subject: [PATCH 0201/1109] clean up experimental setup and keep using ffast-math flag Reviewed By: emilsjolander Differential Revision: D7414228 fbshipit-source-id: 320e1b1953f6af867b13e617af7872eb8999160e --- ReactAndroid/src/main/java/com/facebook/yoga/YogaConfig.java | 4 ---- .../src/main/java/com/facebook/yoga/YogaConstants.java | 2 -- ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java | 4 ---- 3 files changed, 10 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfig.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfig.java index ebb64aaff5a88b..12aa0d8e4a27d7 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfig.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfig.java @@ -16,11 +16,7 @@ public class YogaConfig { public static int SPACING_TYPE = 1; static { - if (YogaConstants.shouldUseFastMath) { - SoLoader.loadLibrary("yogafastmath"); - } else { SoLoader.loadLibrary("yoga"); - } } long mNativePointer; diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaConstants.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaConstants.java index f235cfdeef6a7c..4e081ce49a0e7d 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaConstants.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaConstants.java @@ -18,8 +18,6 @@ public class YogaConstants { */ public static final float UNDEFINED = (float) (10E20); - public static boolean shouldUseFastMath = false; - public static boolean isUndefined(float value) { // Value of a float in the case of it being not defined is 10.1E20. Earlier it used to be NAN, // the benefit of which diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java index 69bb3348b396cb..59a14d242088b8 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java @@ -17,11 +17,7 @@ public class YogaNode implements Cloneable { static { - if (YogaConstants.shouldUseFastMath) { - SoLoader.loadLibrary("yogafastmath"); - } else { SoLoader.loadLibrary("yoga"); - } } /** From 24f574032aae903a5bffd0033d45dc9fb5907ea0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20W=C3=B6hrl?= Date: Wed, 4 Apr 2018 09:24:34 -0700 Subject: [PATCH 0202/1109] Fix compilation on MSVC by moving YGConfig to C++ Summary: This PR fixes the compilation on MSVC. I moved the `YGConfig` creation to a C++ constructor. Addionally it removes the "dot" notation on `YGValue`, I didn't want to change that type to a C++ constructor, because I think this will break the ABI. Closes https://github.com/facebook/yoga/pull/746 Differential Revision: D7498141 Pulled By: emilsjolander fbshipit-source-id: 5f5308ff838dcd803065785ddc08b2404524acb9 --- ReactCommon/yoga/yoga/YGConfig.cpp | 19 ++ ReactCommon/yoga/yoga/YGConfig.h | 23 +++ ReactCommon/yoga/yoga/YGNode.h | 1 + ReactCommon/yoga/yoga/Yoga-internal.h | 10 - ReactCommon/yoga/yoga/Yoga.cpp | 281 ++++++++++++-------------- 5 files changed, 173 insertions(+), 161 deletions(-) create mode 100644 ReactCommon/yoga/yoga/YGConfig.cpp create mode 100644 ReactCommon/yoga/yoga/YGConfig.h diff --git a/ReactCommon/yoga/yoga/YGConfig.cpp b/ReactCommon/yoga/yoga/YGConfig.cpp new file mode 100644 index 00000000000000..5cee527852fc90 --- /dev/null +++ b/ReactCommon/yoga/yoga/YGConfig.cpp @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "YGConfig.h" + +const std::array + kYGDefaultExperimentalFeatures = {{false}}; + +YGConfig::YGConfig(YGLogger logger) + : experimentalFeatures(kYGDefaultExperimentalFeatures), + useWebDefaults(false), + useLegacyStretchBehaviour(false), + shouldDiffLayoutWithoutLegacyStretchBehaviour(false), + pointScaleFactor(1.0f), logger(logger), cloneNodeCallback(nullptr), + context(nullptr) {} diff --git a/ReactCommon/yoga/yoga/YGConfig.h b/ReactCommon/yoga/yoga/YGConfig.h new file mode 100644 index 00000000000000..0f655d1be3e6a1 --- /dev/null +++ b/ReactCommon/yoga/yoga/YGConfig.h @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * + * 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 "Yoga-internal.h" +#include "Yoga.h" + +struct YGConfig { + std::array experimentalFeatures; + bool useWebDefaults; + bool useLegacyStretchBehaviour; + bool shouldDiffLayoutWithoutLegacyStretchBehaviour; + float pointScaleFactor; + YGLogger logger; + YGCloneNodeFunc cloneNodeCallback; + void* context; + + YGConfig(YGLogger logger); +}; diff --git a/ReactCommon/yoga/yoga/YGNode.h b/ReactCommon/yoga/yoga/YGNode.h index 5f7038f44fc786..96541a575eeb20 100644 --- a/ReactCommon/yoga/yoga/YGNode.h +++ b/ReactCommon/yoga/yoga/YGNode.h @@ -7,6 +7,7 @@ #pragma once #include +#include "YGConfig.h" #include "YGLayout.h" #include "YGStyle.h" #include "Yoga-internal.h" diff --git a/ReactCommon/yoga/yoga/Yoga-internal.h b/ReactCommon/yoga/yoga/Yoga-internal.h index d11f8c29d938c5..be1d96325b95be 100644 --- a/ReactCommon/yoga/yoga/Yoga-internal.h +++ b/ReactCommon/yoga/yoga/Yoga-internal.h @@ -87,16 +87,6 @@ struct YGCachedMeasurement { // layouts should not require more than 16 entries to fit within the cache. #define YG_MAX_CACHED_RESULT_COUNT 16 -struct YGConfig { - bool experimentalFeatures[YGExperimentalFeatureCount + 1]; - bool useWebDefaults; - bool useLegacyStretchBehaviour; - bool shouldDiffLayoutWithoutLegacyStretchBehaviour; - float pointScaleFactor; - YGLogger logger; - YGCloneNodeFunc cloneNodeCallback; - void* context; -}; static const float kDefaultFlexGrow = 0.0f; static const float kDefaultFlexShrink = 0.0f; diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index 11c0fddd73783f..ca0b834b08fb52 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -41,25 +41,7 @@ static int YGDefaultLog(const YGConfigRef config, va_list args); #endif -static YGConfig gYGConfigDefaults = { - .experimentalFeatures = - { - [YGExperimentalFeatureWebFlexBasis] = false, - }, - .useWebDefaults = false, - .useLegacyStretchBehaviour = false, - .shouldDiffLayoutWithoutLegacyStretchBehaviour = false, - .pointScaleFactor = 1.0f, -#ifdef ANDROID - .logger = &YGAndroidLog, -#else - .logger = &YGDefaultLog, -#endif - .cloneNodeCallback = nullptr, - .context = nullptr, -}; - -const YGValue YGValueZero = {.value = 0, .unit = YGUnitPoint}; +const YGValue YGValueZero = {0, YGUnitPoint}; const YGValue YGValueUndefined = {YGUndefined, YGUnitUndefined}; const YGValue YGValueAuto = {YGUndefined, YGUnitAuto}; @@ -246,8 +228,13 @@ WIN_EXPORT YGNodeRef YGNodeNewWithConfig(const YGConfigRef config) { return node; } +YGConfigRef YGConfigGetDefault() { + static YGConfigRef defaultConfig = YGConfigNew(); + return defaultConfig; +} + YGNodeRef YGNodeNew(void) { - return YGNodeNewWithConfig(&gYGConfigDefaults); + return YGNodeNewWithConfig(YGConfigGetDefault()); } YGNodeRef YGNodeClone(YGNodeRef oldNode) { @@ -363,19 +350,13 @@ int32_t YGConfigGetInstanceCount(void) { return gConfigInstanceCount; } -// Export only for C# -YGConfigRef YGConfigGetDefault() { - return &gYGConfigDefaults; -} - YGConfigRef YGConfigNew(void) { - const YGConfigRef config = (const YGConfigRef)malloc(sizeof(YGConfig)); - YGAssert(config != nullptr, "Could not allocate memory for config"); - if (config == nullptr) { - abort(); - } + #ifdef ANDROID + const YGConfigRef config = new YGConfig(YGAndroidLog); + #else + const YGConfigRef config = new YGConfig(YGDefaultLog); + #endif gConfigInstanceCount++; - memcpy(config, &gYGConfigDefaults, sizeof(YGConfig)); return config; } @@ -590,79 +571,78 @@ float YGNodeStyleGetFlexShrink(const YGNodeRef node) { } \ } -#define YG_NODE_STYLE_PROPERTY_SETTER_UNIT_IMPL( \ - type, name, paramName, instanceName) \ - void YGNodeStyleSet##name(const YGNodeRef node, const type paramName) { \ - YGValue value = { \ - .value = YGFloatSanitize(paramName), \ - .unit = YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \ - }; \ - if ((node->getStyle().instanceName.value != value.value && \ - value.unit != YGUnitUndefined) || \ - node->getStyle().instanceName.unit != value.unit) { \ - YGStyle style = node->getStyle(); \ - style.instanceName = value; \ - node->setStyle(style); \ - node->markDirtyAndPropogate(); \ - } \ - } \ - \ - void YGNodeStyleSet##name##Percent( \ - const YGNodeRef node, const type paramName) { \ - YGValue value = { \ - .value = YGFloatSanitize(paramName), \ - .unit = \ - YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPercent, \ - }; \ - if ((node->getStyle().instanceName.value != value.value && \ - value.unit != YGUnitUndefined) || \ - node->getStyle().instanceName.unit != value.unit) { \ - YGStyle style = node->getStyle(); \ - \ - style.instanceName = value; \ - node->setStyle(style); \ - node->markDirtyAndPropogate(); \ - } \ - } - -#define YG_NODE_STYLE_PROPERTY_SETTER_UNIT_AUTO_IMPL( \ - type, name, paramName, instanceName) \ - void YGNodeStyleSet##name(const YGNodeRef node, const type paramName) { \ - YGValue value = { \ - .value = YGFloatSanitize(paramName), \ - .unit = YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \ - }; \ - if ((node->getStyle().instanceName.value != value.value && \ - value.unit != YGUnitUndefined) || \ - node->getStyle().instanceName.unit != value.unit) { \ - YGStyle style = node->getStyle(); \ - style.instanceName = value; \ - node->setStyle(style); \ - node->markDirtyAndPropogate(); \ - } \ - } \ - \ - void YGNodeStyleSet##name##Percent( \ - const YGNodeRef node, const type paramName) { \ - if (node->getStyle().instanceName.value != YGFloatSanitize(paramName) || \ - node->getStyle().instanceName.unit != YGUnitPercent) { \ - YGStyle style = node->getStyle(); \ - style.instanceName.value = YGFloatSanitize(paramName); \ - style.instanceName.unit = \ - YGFloatIsUndefined(paramName) ? YGUnitAuto : YGUnitPercent; \ - node->setStyle(style); \ - node->markDirtyAndPropogate(); \ - } \ - } \ - \ - void YGNodeStyleSet##name##Auto(const YGNodeRef node) { \ - if (node->getStyle().instanceName.unit != YGUnitAuto) { \ - YGStyle style = node->getStyle(); \ - style.instanceName.value = 0; \ - style.instanceName.unit = YGUnitAuto; \ - node->setStyle(style); \ - node->markDirtyAndPropogate(); \ - } \ +#define YG_NODE_STYLE_PROPERTY_SETTER_UNIT_IMPL( \ + type, name, paramName, instanceName) \ + void YGNodeStyleSet##name(const YGNodeRef node, const type paramName) { \ + YGValue value = { \ + YGFloatSanitize(paramName), \ + YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \ + }; \ + if ((node->getStyle().instanceName.value != value.value && \ + value.unit != YGUnitUndefined) || \ + node->getStyle().instanceName.unit != value.unit) { \ + YGStyle style = node->getStyle(); \ + style.instanceName = value; \ + node->setStyle(style); \ + node->markDirtyAndPropogate(); \ + } \ + } \ + \ + void YGNodeStyleSet##name##Percent( \ + const YGNodeRef node, const type paramName) { \ + YGValue value = { \ + YGFloatSanitize(paramName), \ + YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPercent, \ + }; \ + if ((node->getStyle().instanceName.value != value.value && \ + value.unit != YGUnitUndefined) || \ + node->getStyle().instanceName.unit != value.unit) { \ + YGStyle style = node->getStyle(); \ + \ + style.instanceName = value; \ + node->setStyle(style); \ + node->markDirtyAndPropogate(); \ + } \ + } + +#define YG_NODE_STYLE_PROPERTY_SETTER_UNIT_AUTO_IMPL( \ + type, name, paramName, instanceName) \ + void YGNodeStyleSet##name(const YGNodeRef node, const type paramName) { \ + YGValue value = { \ + YGFloatSanitize(paramName), \ + YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \ + }; \ + if ((node->getStyle().instanceName.value != value.value && \ + value.unit != YGUnitUndefined) || \ + node->getStyle().instanceName.unit != value.unit) { \ + YGStyle style = node->getStyle(); \ + style.instanceName = value; \ + node->setStyle(style); \ + node->markDirtyAndPropogate(); \ + } \ + } \ + \ + void YGNodeStyleSet##name##Percent( \ + const YGNodeRef node, const type paramName) { \ + if (node->getStyle().instanceName.value != YGFloatSanitize(paramName) || \ + node->getStyle().instanceName.unit != YGUnitPercent) { \ + YGStyle style = node->getStyle(); \ + style.instanceName.value = YGFloatSanitize(paramName); \ + style.instanceName.unit = \ + YGFloatIsUndefined(paramName) ? YGUnitAuto : YGUnitPercent; \ + node->setStyle(style); \ + node->markDirtyAndPropogate(); \ + } \ + } \ + \ + void YGNodeStyleSet##name##Auto(const YGNodeRef node) { \ + if (node->getStyle().instanceName.unit != YGUnitAuto) { \ + YGStyle style = node->getStyle(); \ + style.instanceName.value = 0; \ + style.instanceName.unit = YGUnitAuto; \ + node->setStyle(style); \ + node->markDirtyAndPropogate(); \ + } \ } #define YG_NODE_STYLE_PROPERTY_IMPL(type, name, paramName, instanceName) \ @@ -708,48 +688,47 @@ float YGNodeStyleGetFlexShrink(const YGNodeRef node) { } \ } -#define YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL( \ - type, name, paramName, instanceName) \ - void YGNodeStyleSet##name( \ - const YGNodeRef node, const YGEdge edge, const float paramName) { \ - YGValue value = { \ - .value = YGFloatSanitize(paramName), \ - .unit = YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \ - }; \ - if ((node->getStyle().instanceName[edge].value != value.value && \ - value.unit != YGUnitUndefined) || \ - node->getStyle().instanceName[edge].unit != value.unit) { \ - YGStyle style = node->getStyle(); \ - style.instanceName[edge] = value; \ - node->setStyle(style); \ - node->markDirtyAndPropogate(); \ - } \ - } \ - \ - void YGNodeStyleSet##name##Percent( \ - const YGNodeRef node, const YGEdge edge, const float paramName) { \ - YGValue value = { \ - .value = YGFloatSanitize(paramName), \ - .unit = \ - YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPercent, \ - }; \ - if ((node->getStyle().instanceName[edge].value != value.value && \ - value.unit != YGUnitUndefined) || \ - node->getStyle().instanceName[edge].unit != value.unit) { \ - YGStyle style = node->getStyle(); \ - style.instanceName[edge] = value; \ - node->setStyle(style); \ - node->markDirtyAndPropogate(); \ - } \ - } \ - \ - WIN_STRUCT(type) \ - YGNodeStyleGet##name(const YGNodeRef node, const YGEdge edge) { \ - YGValue value = node->getStyle().instanceName[edge]; \ - if (value.unit == YGUnitUndefined || value.unit == YGUnitAuto) { \ - value.value = YGUndefined; \ - } \ - return WIN_STRUCT_REF(value); \ +#define YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL( \ + type, name, paramName, instanceName) \ + void YGNodeStyleSet##name( \ + const YGNodeRef node, const YGEdge edge, const float paramName) { \ + YGValue value = { \ + YGFloatSanitize(paramName), \ + YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \ + }; \ + if ((node->getStyle().instanceName[edge].value != value.value && \ + value.unit != YGUnitUndefined) || \ + node->getStyle().instanceName[edge].unit != value.unit) { \ + YGStyle style = node->getStyle(); \ + style.instanceName[edge] = value; \ + node->setStyle(style); \ + node->markDirtyAndPropogate(); \ + } \ + } \ + \ + void YGNodeStyleSet##name##Percent( \ + const YGNodeRef node, const YGEdge edge, const float paramName) { \ + YGValue value = { \ + YGFloatSanitize(paramName), \ + YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPercent, \ + }; \ + if ((node->getStyle().instanceName[edge].value != value.value && \ + value.unit != YGUnitUndefined) || \ + node->getStyle().instanceName[edge].unit != value.unit) { \ + YGStyle style = node->getStyle(); \ + style.instanceName[edge] = value; \ + node->setStyle(style); \ + node->markDirtyAndPropogate(); \ + } \ + } \ + \ + WIN_STRUCT(type) \ + YGNodeStyleGet##name(const YGNodeRef node, const YGEdge edge) { \ + YGValue value = node->getStyle().instanceName[edge]; \ + if (value.unit == YGUnitUndefined || value.unit == YGUnitAuto) { \ + value.value = YGUndefined; \ + } \ + return WIN_STRUCT_REF(value); \ } #define YG_NODE_LAYOUT_PROPERTY_IMPL(type, name, instanceName) \ @@ -858,8 +837,8 @@ YGValue YGNodeStyleGetFlexBasis(const YGNodeRef node) { void YGNodeStyleSetFlexBasis(const YGNodeRef node, const float flexBasis) { YGValue value = { - .value = YGFloatSanitize(flexBasis), - .unit = YGFloatIsUndefined(flexBasis) ? YGUnitUndefined : YGUnitPoint, + YGFloatSanitize(flexBasis), + YGFloatIsUndefined(flexBasis) ? YGUnitUndefined : YGUnitPoint, }; if ((node->getStyle().flexBasis.value != value.value && value.unit != YGUnitUndefined) || @@ -906,8 +885,8 @@ void YGNodeStyleSetBorder( const YGEdge edge, const float border) { YGValue value = { - .value = YGFloatSanitize(border), - .unit = YGFloatIsUndefined(border) ? YGUnitUndefined : YGUnitPoint, + YGFloatSanitize(border), + YGFloatIsUndefined(border) ? YGUnitUndefined : YGUnitPoint, }; if ((node->getStyle().border[edge].value != value.value && value.unit != YGUnitUndefined) || @@ -3977,7 +3956,7 @@ static void YGVLog(const YGConfigRef config, YGLogLevel level, const char *format, va_list args) { - const YGConfigRef logConfig = config != nullptr ? config : &gYGConfigDefaults; + const YGConfigRef logConfig = config != nullptr ? config : YGConfigGetDefault(); logConfig->logger(logConfig, node, level, format, args); if (level == YGLogLevelFatal) { From 3cd2b4342653d0cc6edfc9e7d436d73bfb4f139f Mon Sep 17 00:00:00 2001 From: David Vacca Date: Wed, 4 Apr 2018 10:30:16 -0700 Subject: [PATCH 0203/1109] [yoga re-add assertion to check for owner reference before adding child. Reviewed By: emilsjolander Differential Revision: D7495417 fbshipit-source-id: b81174aeea3f2796d76ccdae4a8eddd0beace0aa --- ReactCommon/yoga/yoga/Yoga.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index ca0b834b08fb52..a927ef556c4734 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -370,6 +370,11 @@ void YGConfigCopy(const YGConfigRef dest, const YGConfigRef src) { } void YGNodeInsertChild(const YGNodeRef node, const YGNodeRef child, const uint32_t index) { + YGAssertWithNode( + node, + child->getOwner() == nullptr, + "Child already has a owner, it must be removed first."); + YGAssertWithNode( node, node->getMeasure() == nullptr, From 0b4f33c2d006190a2443a58d583f294a4183587e Mon Sep 17 00:00:00 2001 From: Dominik Wienand Date: Wed, 4 Apr 2018 12:02:55 -0700 Subject: [PATCH 0204/1109] Use .includes instead of .startsWith for checking ignored YellowBox warnings Summary: Some warnings don't have a good prefix that can be targeted using .startsWith, e.g. "Module $modulename requires main queue setup". It would be helpful to be able to select this warning using the much more specific middle part of the string ("requires main queue setup since it overrides `constantsToExport`) so I want to change this check from startsWith to includes to enable that. Changing from .startsWith -> .includes should be completely backward compatible. Reviewed By: TheSavior Differential Revision: D7445309 fbshipit-source-id: 2c91dbe5ee3c3aa74be1bca091b20d294e64e853 --- Libraries/ReactNative/YellowBox.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/ReactNative/YellowBox.js b/Libraries/ReactNative/YellowBox.js index 26749987affb41..8c3eb1f2cb714b 100644 --- a/Libraries/ReactNative/YellowBox.js +++ b/Libraries/ReactNative/YellowBox.js @@ -172,7 +172,7 @@ function ensureSymbolicatedWarning(warning: string): void { function isWarningIgnored(warning: string): boolean { const isIgnored = IGNORED_WARNINGS.some((ignoredWarning: string) => - warning.startsWith(ignoredWarning), + warning.includes(ignoredWarning), ); if (isIgnored) { From c787e0e25216d04a76ce2e3c0c88218ab9db3545 Mon Sep 17 00:00:00 2001 From: Gustav Ahlberg Date: Wed, 4 Apr 2018 13:20:35 -0700 Subject: [PATCH 0205/1109] exclude React/Fabric/ from core Summary: Thank you for sending the PR! We appreciate you spending the time to work on these changes. Help us understand your motivation by explaining why you decided to make this change. React native does not build on iOS when using Podspec environment. I tried the solution proposed in https://github.com/facebook/react-native/issues/18683 and got it to build. Fixes https://github.com/facebook/react-native/issues/18683 [IOS] [BUGFIX] [React.podspec] - Exclude `React/Fabric/*` from Core subspec Closes https://github.com/facebook/react-native/pull/18688 Differential Revision: D7505267 Pulled By: hramos fbshipit-source-id: 8e7138ee966d08209a74193e418feaecceefb86a --- React.podspec | 1 + 1 file changed, 1 insertion(+) diff --git a/React.podspec b/React.podspec index 9d222499f38414..a9a4de5a523e3d 100644 --- a/React.podspec +++ b/React.podspec @@ -51,6 +51,7 @@ Pod::Spec.new do |s| "React/Inspector/*", "ReactCommon/yoga/*", "React/Cxx*/*", + "React/Fabric/*", ss.ios.exclude_files = "React/**/RCTTV*.*" ss.tvos.exclude_files = "React/Modules/RCTClipboard*", "React/Views/RCTDatePicker*", From e574b85db6cdd73457c10d21f9be68f8fa44927d Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Wed, 4 Apr 2018 15:11:21 -0700 Subject: [PATCH 0206/1109] React sync for revisions 9d484ed...1c2876d Reviewed By: gaearon Differential Revision: D7500761 fbshipit-source-id: 8dc1cda879942fc4990b23144a616039fdbe6dc0 --- Libraries/Renderer/REVISION | 2 +- Libraries/Renderer/ReactFabric-dev.js | 1186 ++++++++++++----- Libraries/Renderer/ReactFabric-prod.js | 313 +++-- Libraries/Renderer/ReactNativeRenderer-dev.js | 1185 +++++++++++----- .../Renderer/ReactNativeRenderer-prod.js | 369 +++-- Libraries/Renderer/shims/ReactFabric.js | 1 - Libraries/Renderer/shims/ReactTypes.js | 4 +- package.json | 6 +- 8 files changed, 2091 insertions(+), 975 deletions(-) diff --git a/Libraries/Renderer/REVISION b/Libraries/Renderer/REVISION index 7e989de9720393..fc81a7c7f28c85 100644 --- a/Libraries/Renderer/REVISION +++ b/Libraries/Renderer/REVISION @@ -1 +1 @@ -9d484edc4b64160cb335a23a2cb21667fb2cdf4c \ No newline at end of file +1c2876d5b558b8591feb335d8d7204bc46f7da8a \ No newline at end of file diff --git a/Libraries/Renderer/ReactFabric-dev.js b/Libraries/Renderer/ReactFabric-dev.js index 22c77f2e072d9c..0b7a78516c11ba 100644 --- a/Libraries/Renderer/ReactFabric-dev.js +++ b/Libraries/Renderer/ReactFabric-dev.js @@ -509,11 +509,13 @@ var injection$1 = { getNodeFromInstance = Injected.getNodeFromInstance; { - warning( - getNodeFromInstance && getInstanceFromNode, - "EventPluginUtils.injection.injectComponentTree(...): Injected " + - "module is missing getNodeFromInstance or getInstanceFromNode." - ); + !(getNodeFromInstance && getInstanceFromNode) + ? warning( + false, + "EventPluginUtils.injection.injectComponentTree(...): Injected " + + "module is missing getNodeFromInstance or getInstanceFromNode." + ) + : void 0; } } }; @@ -549,10 +551,9 @@ var validateEventDispatches = void 0; ? dispatchInstances.length : dispatchInstances ? 1 : 0; - warning( - instancesIsArr === listenersIsArr && instancesLen === listenersLen, - "EventPluginUtils: Invalid `event`." - ); + !(instancesIsArr === listenersIsArr && instancesLen === listenersLen) + ? warning(false, "EventPluginUtils: Invalid `event`.") + : void 0; }; } @@ -939,7 +940,7 @@ function listenerAtPhase(inst, event, propagationPhase) { */ function accumulateDirectionalDispatches(inst, phase, event) { { - warning(inst, "Dispatching inst must not be null"); + !inst ? warning(false, "Dispatching inst must not be null") : void 0; } var listener = listenerAtPhase(inst, event, phase); if (listener) { @@ -1258,13 +1259,15 @@ SyntheticEvent.extend = function(Interface) { !target.constructor.Interface.hasOwnProperty(prop) && shouldBeReleasedProperties.indexOf(prop) === -1 ) { - warning( - didWarnForAddedNewProperty || target.isPersistent(), - "This synthetic event is reused for performance reasons. If you're " + - "seeing this, you're adding a new property in the synthetic event object. " + - "The property is never released. See " + - "https://fb.me/react-event-pooling for more information." - ); + !(didWarnForAddedNewProperty || target.isPersistent()) + ? warning( + false, + "This synthetic event is reused for performance reasons. If you're " + + "seeing this, you're adding a new property in the synthetic event object. " + + "The property is never released. See " + + "https://fb.me/react-event-pooling for more information." + ) + : void 0; didWarnForAddedNewProperty = true; } target[prop] = value; @@ -1311,16 +1314,18 @@ function getPooledWarningPropertyDefinition(propName, getVal) { function warn(action, result) { var warningCondition = false; - warning( - warningCondition, - "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 - ); + !warningCondition + ? warning( + 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; } } @@ -1438,13 +1443,15 @@ function getTouchIdentifier(_ref) { invariant(identifier != null, "Touch object is missing identifier."); { - warning( - identifier <= MAX_TOUCH_BANK, - "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 - ); + !(identifier <= MAX_TOUCH_BANK) + ? warning( + 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; } @@ -1543,10 +1550,9 @@ var ResponderTouchHistoryStore = { } { var activeRecord = touchBank[touchHistory.indexOfSingleActiveTouch]; - warning( - activeRecord != null && activeRecord.touchActive, - "Cannot find single active touch." - ); + !(activeRecord != null && activeRecord.touchActive) + ? warning(false, "Cannot find single active touch.") + : void 0; } } } @@ -2641,7 +2647,7 @@ var TouchHistoryMath = { // TODO: this is special because it gets imported during build. -var ReactVersion = "16.3.0-alpha.2"; +var ReactVersion = "16.3.1"; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { @@ -3311,15 +3317,17 @@ function findNodeHandle(componentOrHandle) { { var owner = ReactCurrentOwner.current; if (owner !== null && owner.stateNode !== null) { - warning( - owner.stateNode._warnedAboutRefsInRender, - "%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) || "A component" - ); + !owner.stateNode._warnedAboutRefsInRender + ? warning( + 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) || "A component" + ) + : void 0; owner.stateNode._warnedAboutRefsInRender = true; } @@ -3777,7 +3785,8 @@ var frameDeadline = 0; var frameDeadlineObject = { timeRemaining: function() { return frameDeadline - now(); - } + }, + didTimeout: false }; function setTimeoutCallback() { @@ -3865,9 +3874,10 @@ var Callback = /* */ 32; var DidCapture = /* */ 64; var Ref = /* */ 128; var ErrLog = /* */ 256; +var Snapshot = /* */ 2048; // Union of all host effects -var HostEffectMask = /* */ 511; +var HostEffectMask = /* */ 2559; var Incomplete = /* */ 512; var ShouldCapture = /* */ 1024; @@ -3915,15 +3925,17 @@ function isMounted(component) { if (owner !== null && owner.tag === ClassComponent) { var ownerFiber = owner; var instance = ownerFiber.stateNode; - warning( - instance._warnedAboutRefsInRender, - "%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) || "A component" - ); + !instance._warnedAboutRefsInRender + ? warning( + 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) || "A component" + ) + : void 0; instance._warnedAboutRefsInRender = true; } } @@ -4476,6 +4488,47 @@ function createFiberFromPortal(portal, mode, expirationTime) { 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.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.mode = source.mode; + target.effectTag = source.effectTag; + target.nextEffect = source.nextEffect; + target.firstEffect = source.firstEffect; + target.lastEffect = source.lastEffect; + target.expirationTime = source.expirationTime; + target.alternate = source.alternate; + target._debugID = source._debugID; + target._debugSource = source._debugSource; + target._debugOwner = source._debugOwner; + target._debugIsCurrentlyTiming = source._debugIsCurrentlyTiming; + return target; +} + // TODO: This should be lifted into the renderer. function createFiberRoot(containerInfo, isAsync, hydrate) { @@ -4881,7 +4934,10 @@ var ReactStrictModeWarnings = { ) { pendingComponentWillReceivePropsWarnings.push(fiber); } - if (typeof instance.componentWillUpdate === "function") { + if ( + typeof instance.componentWillUpdate === "function" && + instance.componentWillUpdate.__suppressDeprecationWarning !== true + ) { pendingComponentWillUpdateWarnings.push(fiber); } }; @@ -4954,7 +5010,6 @@ var ReactStrictModeWarnings = { var debugRenderPhaseSideEffects = false; var debugRenderPhaseSideEffectsForStrictMode = false; - var enableUserTimingAPI = true; var enableGetDerivedStateFromCatch = false; var warnAboutDeprecatedLifecycles = false; @@ -5223,13 +5278,15 @@ function startRequestCallbackTimer() { } } -function stopRequestCallbackTimer(didExpire) { +function stopRequestCallbackTimer(didExpire, expirationTime) { if (enableUserTimingAPI) { if (supportsUserTiming) { isWaitingForCallback = false; var warning$$1 = didExpire ? "React was blocked by main thread" : null; endMark( - "(Waiting for async callback...)", + "(Waiting for async callback... will force flush in " + + expirationTime + + " ms)", "(Waiting for async callback...)", warning$$1 ); @@ -5339,7 +5396,7 @@ function startWorkLoopTimer(nextUnitOfWork) { } } -function stopWorkLoopTimer(interruptedBy) { +function stopWorkLoopTimer(interruptedBy, didCompleteRoot) { if (enableUserTimingAPI) { if (!supportsUserTiming) { return; @@ -5357,13 +5414,12 @@ function stopWorkLoopTimer(interruptedBy) { warning$$1 = "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( - "(React Tree Reconciliation)", - "(React Tree Reconciliation)", - warning$$1 - ); + endMark(label, "(React Tree Reconciliation)", warning$$1); } } @@ -5400,6 +5456,31 @@ function stopCommitTimer() { } } +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) { @@ -5784,23 +5865,26 @@ var isArray = Array.isArray; var didWarnAboutStateAssignmentForComponent = void 0; var didWarnAboutUndefinedDerivedState = void 0; var didWarnAboutUninitializedState = void 0; -var didWarnAboutWillReceivePropsAndDerivedState = void 0; +var didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = void 0; +var didWarnAboutLegacyLifecyclesAndDerivedState = void 0; var warnOnInvalidCallback = void 0; { - didWarnAboutStateAssignmentForComponent = {}; - didWarnAboutUndefinedDerivedState = {}; - didWarnAboutUninitializedState = {}; - didWarnAboutWillReceivePropsAndDerivedState = {}; + didWarnAboutStateAssignmentForComponent = new Set(); + didWarnAboutUndefinedDerivedState = new Set(); + didWarnAboutUninitializedState = new Set(); + didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = new Set(); + didWarnAboutLegacyLifecyclesAndDerivedState = new Set(); - var didWarnOnInvalidCallback = {}; + var didWarnOnInvalidCallback = new Set(); warnOnInvalidCallback = function(callback, callerName) { if (callback === null || typeof callback === "function") { return; } var key = callerName + "_" + callback; - if (!didWarnOnInvalidCallback[key]) { + if (!didWarnOnInvalidCallback.has(key)) { + didWarnOnInvalidCallback.add(key); warning( false, "%s(...): Expected the last optional `callback` argument to be a " + @@ -5808,7 +5892,6 @@ var warnOnInvalidCallback = void 0; callerName, callback ); - didWarnOnInvalidCallback[key] = true; } }; @@ -5951,12 +6034,14 @@ var ReactFiberClassComponent = function( stopPhaseTimer(); { - warning( - shouldUpdate !== undefined, - "%s.shouldComponentUpdate(): Returned undefined instead of a " + - "boolean value. Make sure to return true or false.", - getComponentName(workInProgress) || "Unknown" - ); + !(shouldUpdate !== undefined) + ? warning( + false, + "%s.shouldComponentUpdate(): Returned undefined instead of a " + + "boolean value. Make sure to return true or false.", + getComponentName(workInProgress) || "Component" + ) + : void 0; } return shouldUpdate; @@ -5975,7 +6060,7 @@ var ReactFiberClassComponent = function( var instance = workInProgress.stateNode; var type = workInProgress.type; { - var name = getComponentName(workInProgress); + var name = getComponentName(workInProgress) || "Component"; var renderPresent = instance.render; if (!renderPresent) { @@ -6000,47 +6085,57 @@ var ReactFiberClassComponent = function( !instance.getInitialState || instance.getInitialState.isReactClassApproved || instance.state; - warning( - noGetInitialStateOnES6, - "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 - ); + !noGetInitialStateOnES6 + ? warning( + 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; - warning( - noGetDefaultPropsOnES6, - "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 - ); + !noGetDefaultPropsOnES6 + ? warning( + 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; - warning( - noInstancePropTypes, - "propTypes was defined as an instance property on %s. Use a static " + - "property to define propTypes instead.", - name - ); + !noInstancePropTypes + ? warning( + false, + "propTypes was defined as an instance property on %s. Use a static " + + "property to define propTypes instead.", + name + ) + : void 0; var noInstanceContextTypes = !instance.contextTypes; - warning( - noInstanceContextTypes, - "contextTypes was defined as an instance property on %s. Use a static " + - "property to define contextTypes instead.", - name - ); + !noInstanceContextTypes + ? warning( + false, + "contextTypes was defined as an instance property on %s. Use a static " + + "property to define contextTypes instead.", + name + ) + : void 0; var noComponentShouldUpdate = typeof instance.componentShouldUpdate !== "function"; - warning( - noComponentShouldUpdate, - "%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 - ); + !noComponentShouldUpdate + ? warning( + 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 ( type.prototype && type.prototype.isPureReactComponent && @@ -6056,73 +6151,128 @@ var ReactFiberClassComponent = function( } var noComponentDidUnmount = typeof instance.componentDidUnmount !== "function"; - warning( - noComponentDidUnmount, - "%s has a method called " + - "componentDidUnmount(). But there is no such lifecycle method. " + - "Did you mean componentWillUnmount()?", - name - ); + !noComponentDidUnmount + ? warning( + 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"; - warning( - noComponentDidReceiveProps, - "%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 - ); + !noComponentDidReceiveProps + ? warning( + 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"; - warning( - noComponentWillRecieveProps, - "%s has a method called " + - "componentWillRecieveProps(). Did you mean componentWillReceiveProps()?", - name - ); + !noComponentWillRecieveProps + ? warning( + false, + "%s has a method called " + + "componentWillRecieveProps(). Did you mean componentWillReceiveProps()?", + name + ) + : void 0; var noUnsafeComponentWillRecieveProps = typeof instance.UNSAFE_componentWillRecieveProps !== "function"; - warning( - noUnsafeComponentWillRecieveProps, - "%s has a method called " + - "UNSAFE_componentWillRecieveProps(). Did you mean UNSAFE_componentWillReceiveProps()?", - name - ); + !noUnsafeComponentWillRecieveProps + ? warning( + false, + "%s has a method called " + + "UNSAFE_componentWillRecieveProps(). Did you mean UNSAFE_componentWillReceiveProps()?", + name + ) + : void 0; var hasMutatedProps = instance.props !== workInProgress.pendingProps; - warning( - instance.props === undefined || !hasMutatedProps, - "%s(...): When calling super() in `%s`, make sure to pass " + - "up the same props that your component's constructor was passed.", - name, - name - ); + !(instance.props === undefined || !hasMutatedProps) + ? warning( + 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; - warning( - noInstanceDefaultProps, - "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 - ); - } + !noInstanceDefaultProps + ? warning( + 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; - var state = instance.state; - if (state && (typeof state !== "object" || isArray(state))) { - warning( - false, - "%s.state: must be set to an object or null", - getComponentName(workInProgress) - ); - } - if (typeof instance.getChildContext === "function") { - warning( - typeof type.childContextTypes === "object", - "%s.getChildContext(): childContextTypes must be defined in order to " + - "use getChildContext().", - getComponentName(workInProgress) - ); + if ( + typeof instance.getSnapshotBeforeUpdate === "function" && + typeof instance.componentDidUpdate !== "function" && + typeof instance.componentDidUpdate !== "function" && + !didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.has(type) + ) { + didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.add(type); + warning( + false, + "%s: getSnapshotBeforeUpdate() should be used with componentDidUpdate(). " + + "This component defines getSnapshotBeforeUpdate() only.", + getComponentName(workInProgress) + ); + } + + var noInstanceGetDerivedStateFromProps = + typeof instance.getDerivedStateFromProps !== "function"; + !noInstanceGetDerivedStateFromProps + ? warning( + 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.getDerivedStateFromCatch !== "function"; + !noInstanceGetDerivedStateFromCatch + ? warning( + false, + "%s: getDerivedStateFromCatch() is defined as an instance method " + + "and will be ignored. Instead, declare it as a static method.", + name + ) + : void 0; + var noStaticGetSnapshotBeforeUpdate = + typeof type.getSnapshotBeforeUpdate !== "function"; + !noStaticGetSnapshotBeforeUpdate + ? warning( + 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(_state))) { + warning(false, "%s.state: must be set to an object or null", name); + } + if (typeof instance.getChildContext === "function") { + !(typeof type.childContextTypes === "object") + ? warning( + false, + "%s.getChildContext(): childContextTypes must be defined in order to " + + "use getChildContext().", + name + ) + : void 0; + } } } @@ -6170,8 +6320,9 @@ var ReactFiberClassComponent = function( typeof ctor.getDerivedStateFromProps === "function" && state === null ) { - var componentName = getComponentName(workInProgress) || "Unknown"; - if (!didWarnAboutUninitializedState[componentName]) { + var componentName = getComponentName(workInProgress) || "Component"; + if (!didWarnAboutUninitializedState.has(componentName)) { + didWarnAboutUninitializedState.add(componentName); warning( false, "%s: Did not properly initialize state during construction. " + @@ -6179,7 +6330,75 @@ var ReactFiberClassComponent = function( componentName, instance.state === null ? "null" : "undefined" ); - didWarnAboutUninitializedState[componentName] = true; + } + } + + // 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(workInProgress) || "Component"; + var newApiName = + typeof ctor.getDerivedStateFromProps === "function" + ? "getDerivedStateFromProps()" + : "getSnapshotBeforeUpdate()"; + if ( + !didWarnAboutLegacyLifecyclesAndDerivedState.has(_componentName) + ) { + didWarnAboutLegacyLifecyclesAndDerivedState.add(_componentName); + warning( + 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 : "" + ); + } } } } @@ -6189,7 +6408,8 @@ var ReactFiberClassComponent = function( var partialState = callGetDerivedStateFromProps( workInProgress, instance, - props + props, + state ); if (partialState !== null && partialState !== undefined) { @@ -6232,7 +6452,7 @@ var ReactFiberClassComponent = function( "%s.componentWillMount(): Assigning directly to this.state is " + "deprecated (except inside a component's " + "constructor). Use setState instead.", - getComponentName(workInProgress) + getComponentName(workInProgress) || "Component" ); } updater.enqueueReplaceState(instance, instance.state, null); @@ -6258,7 +6478,8 @@ var ReactFiberClassComponent = function( if (instance.state !== oldState) { { var componentName = getComponentName(workInProgress) || "Component"; - if (!didWarnAboutStateAssignmentForComponent[componentName]) { + if (!didWarnAboutStateAssignmentForComponent.has(componentName)) { + didWarnAboutStateAssignmentForComponent.add(componentName); warning( false, "%s.componentWillReceiveProps(): Assigning directly to " + @@ -6266,69 +6487,47 @@ var ReactFiberClassComponent = function( "constructor). Use setState instead.", componentName ); - didWarnAboutStateAssignmentForComponent[componentName] = true; } } updater.enqueueReplaceState(instance, instance.state, null); } } - function callGetDerivedStateFromProps(workInProgress, instance, props) { + function callGetDerivedStateFromProps( + workInProgress, + instance, + nextProps, + prevState + ) { var type = workInProgress.type; if (typeof type.getDerivedStateFromProps === "function") { - { - // Don't warn about react-lifecycles-compat polyfilled components - if ( - (typeof instance.componentWillReceiveProps === "function" && - instance.componentWillReceiveProps.__suppressDeprecationWarning !== - true) || - typeof instance.UNSAFE_componentWillReceiveProps === "function" - ) { - var componentName = getComponentName(workInProgress) || "Unknown"; - if (!didWarnAboutWillReceivePropsAndDerivedState[componentName]) { - warning( - false, - "%s: Defines both componentWillReceiveProps() and static " + - "getDerivedStateFromProps() methods. We recommend using " + - "only getDerivedStateFromProps().", - componentName - ); - didWarnAboutWillReceivePropsAndDerivedState[componentName] = true; - } - } - } - if ( debugRenderPhaseSideEffects || (debugRenderPhaseSideEffectsForStrictMode && workInProgress.mode & StrictMode) ) { // Invoke method an extra time to help detect side-effects. - type.getDerivedStateFromProps.call( - null, - props, - workInProgress.memoizedState - ); + type.getDerivedStateFromProps.call(null, nextProps, prevState); } var partialState = type.getDerivedStateFromProps.call( null, - props, - workInProgress.memoizedState + nextProps, + prevState ); { if (partialState === undefined) { - var _componentName = getComponentName(workInProgress) || "Unknown"; - if (!didWarnAboutUndefinedDerivedState[_componentName]) { + var componentName = getComponentName(workInProgress) || "Component"; + if (!didWarnAboutUndefinedDerivedState.has(componentName)) { + didWarnAboutUndefinedDerivedState.add(componentName); warning( false, "%s.getDerivedStateFromProps(): A valid state object (or null) must be returned. " + "You have returned undefined.", - _componentName + componentName ); - didWarnAboutUndefinedDerivedState[_componentName] = _componentName; } } } @@ -6372,11 +6571,12 @@ var ReactFiberClassComponent = function( } // In order to support react-lifecycles-compat polyfilled components, - // Unsafe lifecycles should not be invoked for any component with the new gDSFP. + // 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") && - typeof ctor.getDerivedStateFromProps !== "function" + typeof instance.componentWillMount === "function") ) { callComponentWillMount(workInProgress, instance); // If we had additional state updates during this life-cycle, let's @@ -6409,16 +6609,20 @@ var ReactFiberClassComponent = function( var newUnmaskedContext = getUnmaskedContext(workInProgress); var newContext = getMaskedContext(workInProgress, newUnmaskedContext); + var hasNewLifecycles = + typeof ctor.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 any component with the new gDSFP. + // Unsafe lifecycles should not be invoked for components using the new APIs. if ( + !hasNewLifecycles && (typeof instance.UNSAFE_componentWillReceiveProps === "function" || - typeof instance.componentWillReceiveProps === "function") && - typeof ctor.getDerivedStateFromProps !== "function" + typeof instance.componentWillReceiveProps === "function") ) { if (oldProps !== newProps || oldContext !== newContext) { callComponentWillReceiveProps( @@ -6430,15 +6634,6 @@ var ReactFiberClassComponent = function( } } - var derivedStateFromProps = void 0; - if (oldProps !== newProps) { - derivedStateFromProps = callGetDerivedStateFromProps( - workInProgress, - instance, - newProps - ); - } - // Compute the next state using the memoized state and the update queue. var oldState = workInProgress.memoizedState; // TODO: Previous state can be null. @@ -6475,6 +6670,18 @@ var ReactFiberClassComponent = function( newState = oldState; } + var derivedStateFromProps = void 0; + if (oldProps !== newProps) { + // The prevState parameter should be the partially updated state. + // Otherwise, spreading state in return values could override updates. + derivedStateFromProps = callGetDerivedStateFromProps( + workInProgress, + instance, + newProps, + newState + ); + } + if (derivedStateFromProps !== null && derivedStateFromProps !== undefined) { // Render-phase updates (like this) should not be added to the update queue, // So that multiple render passes do not enqueue multiple updates. @@ -6483,6 +6690,17 @@ var ReactFiberClassComponent = function( newState === null || newState === undefined ? derivedStateFromProps : Object.assign({}, newState, derivedStateFromProps); + + // Update the base state of the update queue. + // FIXME: This is getting ridiculous. Refactor plz! + var _updateQueue = workInProgress.updateQueue; + if (_updateQueue !== null) { + _updateQueue.baseState = Object.assign( + {}, + _updateQueue.baseState, + derivedStateFromProps + ); + } } if (derivedStateFromCatch !== null && derivedStateFromCatch !== undefined) { // Render-phase updates (like this) should not be added to the update queue, @@ -6492,6 +6710,17 @@ var ReactFiberClassComponent = function( newState === null || newState === undefined ? derivedStateFromCatch : Object.assign({}, newState, derivedStateFromCatch); + + // Update the base state of the update queue. + // FIXME: This is getting ridiculous. Refactor plz! + var _updateQueue2 = workInProgress.updateQueue; + if (_updateQueue2 !== null) { + _updateQueue2.baseState = Object.assign( + {}, + _updateQueue2.baseState, + derivedStateFromCatch + ); + } } if ( @@ -6522,11 +6751,11 @@ var ReactFiberClassComponent = function( if (shouldUpdate) { // In order to support react-lifecycles-compat polyfilled components, - // Unsafe lifecycles should not be invoked for any component with the new gDSFP. + // Unsafe lifecycles should not be invoked for components using the new APIs. if ( + !hasNewLifecycles && (typeof instance.UNSAFE_componentWillMount === "function" || - typeof instance.componentWillMount === "function") && - typeof ctor.getDerivedStateFromProps !== "function" + typeof instance.componentWillMount === "function") ) { startPhaseTimer(workInProgress, "componentWillMount"); if (typeof instance.componentWillMount === "function") { @@ -6574,16 +6803,20 @@ var ReactFiberClassComponent = function( var newUnmaskedContext = getUnmaskedContext(workInProgress); var newContext = getMaskedContext(workInProgress, newUnmaskedContext); + var hasNewLifecycles = + typeof ctor.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 any component with the new gDSFP. + // Unsafe lifecycles should not be invoked for components using the new APIs. if ( + !hasNewLifecycles && (typeof instance.UNSAFE_componentWillReceiveProps === "function" || - typeof instance.componentWillReceiveProps === "function") && - typeof ctor.getDerivedStateFromProps !== "function" + typeof instance.componentWillReceiveProps === "function") ) { if (oldProps !== newProps || oldContext !== newContext) { callComponentWillReceiveProps( @@ -6595,20 +6828,12 @@ var ReactFiberClassComponent = function( } } - var derivedStateFromProps = void 0; - if (oldProps !== newProps) { - derivedStateFromProps = callGetDerivedStateFromProps( - workInProgress, - instance, - newProps - ); - } - // Compute the next state using the memoized state and the update queue. var oldState = workInProgress.memoizedState; // TODO: Previous state can be null. var newState = void 0; var derivedStateFromCatch = void 0; + if (workInProgress.updateQueue !== null) { newState = processUpdateQueue( current, @@ -6640,6 +6865,18 @@ var ReactFiberClassComponent = function( newState = oldState; } + var derivedStateFromProps = void 0; + if (oldProps !== newProps) { + // The prevState parameter should be the partially updated state. + // Otherwise, spreading state in return values could override updates. + derivedStateFromProps = callGetDerivedStateFromProps( + workInProgress, + instance, + newProps, + newState + ); + } + if (derivedStateFromProps !== null && derivedStateFromProps !== undefined) { // Render-phase updates (like this) should not be added to the update queue, // So that multiple render passes do not enqueue multiple updates. @@ -6648,6 +6885,17 @@ var ReactFiberClassComponent = function( newState === null || newState === undefined ? derivedStateFromProps : Object.assign({}, newState, derivedStateFromProps); + + // Update the base state of the update queue. + // FIXME: This is getting ridiculous. Refactor plz! + var _updateQueue3 = workInProgress.updateQueue; + if (_updateQueue3 !== null) { + _updateQueue3.baseState = Object.assign( + {}, + _updateQueue3.baseState, + derivedStateFromProps + ); + } } if (derivedStateFromCatch !== null && derivedStateFromCatch !== undefined) { // Render-phase updates (like this) should not be added to the update queue, @@ -6657,6 +6905,17 @@ var ReactFiberClassComponent = function( newState === null || newState === undefined ? derivedStateFromCatch : Object.assign({}, newState, derivedStateFromCatch); + + // Update the base state of the update queue. + // FIXME: This is getting ridiculous. Refactor plz! + var _updateQueue4 = workInProgress.updateQueue; + if (_updateQueue4 !== null) { + _updateQueue4.baseState = Object.assign( + {}, + _updateQueue4.baseState, + derivedStateFromCatch + ); + } } if ( @@ -6678,6 +6937,14 @@ var ReactFiberClassComponent = function( workInProgress.effectTag |= Update; } } + if (typeof instance.getSnapshotBeforeUpdate === "function") { + if ( + oldProps !== current.memoizedProps || + oldState !== current.memoizedState + ) { + workInProgress.effectTag |= Snapshot; + } + } return false; } @@ -6692,11 +6959,11 @@ var ReactFiberClassComponent = function( if (shouldUpdate) { // In order to support react-lifecycles-compat polyfilled components, - // Unsafe lifecycles should not be invoked for any component with the new gDSFP. + // Unsafe lifecycles should not be invoked for components using the new APIs. if ( + !hasNewLifecycles && (typeof instance.UNSAFE_componentWillUpdate === "function" || - typeof instance.componentWillUpdate === "function") && - typeof ctor.getDerivedStateFromProps !== "function" + typeof instance.componentWillUpdate === "function") ) { startPhaseTimer(workInProgress, "componentWillUpdate"); if (typeof instance.componentWillUpdate === "function") { @@ -6710,6 +6977,9 @@ var ReactFiberClassComponent = function( 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. @@ -6721,6 +6991,14 @@ var ReactFiberClassComponent = function( 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. @@ -7560,13 +7838,15 @@ function ChildReconciler(shouldTrackSideEffects) { if (typeof newChildrenIterable.entries === "function") { var possibleMap = newChildrenIterable; if (possibleMap.entries === iteratorFn) { - warning( - didWarnAboutMaps, - "Using Maps as children is unsupported and will likely yield " + - "unexpected results. Convert it to a sequence/iterable of keyed " + - "ReactElements instead.%s", - getCurrentFiberStackAddendum$1() - ); + !didWarnAboutMaps + ? warning( + false, + "Using Maps as children is unsupported and will likely yield " + + "unexpected results. Convert it to a sequence/iterable of keyed " + + "ReactElements instead.%s", + getCurrentFiberStackAddendum$1() + ) + : void 0; didWarnAboutMaps = true; } } @@ -8532,7 +8812,8 @@ var ReactFiberBeginWork = function( var partialState = callGetDerivedStateFromProps( workInProgress, value, - props + props, + workInProgress.memoizedState ); if (partialState !== null && partialState !== undefined) { @@ -8565,11 +8846,13 @@ var ReactFiberBeginWork = function( var _Component = workInProgress.type; if (_Component) { - warning( - !_Component.childContextTypes, - "%s(...): childContextTypes cannot be defined on a functional component.", - _Component.displayName || _Component.name || "Component" - ); + !!_Component.childContextTypes + ? warning( + false, + "%s(...): childContextTypes cannot be defined on a functional component.", + _Component.displayName || _Component.name || "Component" + ) + : void 0; } if (workInProgress.ref !== null) { var info = ""; @@ -8788,7 +9071,7 @@ var ReactFiberBeginWork = function( renderExpirationTime ) { var providerType = workInProgress.type; - var context = providerType.context; + var context = providerType._context; var newProps = workInProgress.pendingProps; var oldProps = workInProgress.memoizedProps; @@ -8841,12 +9124,14 @@ var ReactFiberBeginWork = function( ? context._calculateChangedBits(oldValue, newValue) : MAX_SIGNED_31_BIT_INT; { - warning( - (changedBits & MAX_SIGNED_31_BIT_INT) === changedBits, - "calculateChangedBits: Expected the return value to be a " + - "31-bit integer. Instead received: %s", - changedBits - ); + !((changedBits & MAX_SIGNED_31_BIT_INT) === changedBits) + ? warning( + false, + "calculateChangedBits: Expected the return value to be a " + + "31-bit integer. Instead received: %s", + changedBits + ) + : void 0; } changedBits |= 0; @@ -8914,21 +9199,23 @@ var ReactFiberBeginWork = function( changedBits, renderExpirationTime ); - } else if (oldProps !== null && oldProps.children === newProps.children) { - // No change. Bailout early if children are the same. - return bailoutOnAlreadyFinishedWork(current, workInProgress); } + // There is no bailout on `children` equality because we expect people + // to often pass a bound method as a child, but it may reference + // `this.state` or `this.props` (and thus needs to re-render on `setState`). var render = newProps.children; { - warning( - typeof render === "function", - "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." - ); + !(typeof render === "function") + ? warning( + 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; } var newChildren = render(newValue); @@ -9883,6 +10170,11 @@ var invokeGuardedCallback$3 = ReactErrorUtils.invokeGuardedCallback; var hasCaughtError$1 = ReactErrorUtils.hasCaughtError; var clearCaughtError$1 = ReactErrorUtils.clearCaughtError; +var didWarnAboutUndefinedSnapshotBeforeUpdate = null; +{ + didWarnAboutUndefinedSnapshotBeforeUpdate = new Set(); +} + function logError(boundary, errorInfo) { var source = errorInfo.source; var stack = errorInfo.stack; @@ -9892,21 +10184,19 @@ function logError(boundary, errorInfo) { var capturedError = { componentName: source !== null ? getComponentName(source) : null, - error: errorInfo.value, - errorBoundary: boundary, componentStack: stack !== null ? stack : "", + error: errorInfo.value, + errorBoundary: null, errorBoundaryName: null, errorBoundaryFound: false, willRetry: false }; - if (boundary !== null) { + if (boundary !== null && boundary.tag === ClassComponent) { + capturedError.errorBoundary = boundary.stateNode; capturedError.errorBoundaryName = getComponentName(boundary); - capturedError.errorBoundaryFound = capturedError.willRetry = - boundary.tag === ClassComponent; - } else { - capturedError.errorBoundaryName = null; - capturedError.errorBoundaryFound = capturedError.willRetry = false; + capturedError.errorBoundaryFound = true; + capturedError.willRetry = true; } try { @@ -9975,6 +10265,58 @@ var ReactFiberCommitWork = function( } } + function commitBeforeMutationLifeCycles(current, finishedWork) { + switch (finishedWork.tag) { + case ClassComponent: { + if (finishedWork.effectTag & Snapshot) { + if (current !== null) { + var prevProps = current.memoizedProps; + var prevState = current.memoizedState; + startPhaseTimer(finishedWork, "getSnapshotBeforeUpdate"); + var _instance = finishedWork.stateNode; + _instance.props = finishedWork.memoizedProps; + _instance.state = finishedWork.memoizedState; + var snapshot = _instance.getSnapshotBeforeUpdate( + prevProps, + prevState + ); + { + var didWarnSet = didWarnAboutUndefinedSnapshotBeforeUpdate; + if ( + snapshot === undefined && + !didWarnSet.has(finishedWork.type) + ) { + didWarnSet.add(finishedWork.type); + warning( + false, + "%s.getSnapshotBeforeUpdate(): A snapshot value (or null) " + + "must be returned. You have returned undefined.", + getComponentName(finishedWork) + ); + } + } + _instance.__reactInternalSnapshotBeforeUpdate = snapshot; + stopPhaseTimer(); + } + } + return; + } + case HostRoot: + case HostComponent: + case HostText: + case HostPortal: + // Nothing to do for these component types + return; + default: { + invariant( + false, + "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 commitLifeCycles( finishedRoot, current, @@ -9984,50 +10326,54 @@ var ReactFiberCommitWork = function( ) { switch (finishedWork.tag) { case ClassComponent: { - var _instance = finishedWork.stateNode; + var _instance2 = finishedWork.stateNode; if (finishedWork.effectTag & Update) { if (current === null) { startPhaseTimer(finishedWork, "componentDidMount"); - _instance.props = finishedWork.memoizedProps; - _instance.state = finishedWork.memoizedState; - _instance.componentDidMount(); + _instance2.props = finishedWork.memoizedProps; + _instance2.state = finishedWork.memoizedState; + _instance2.componentDidMount(); stopPhaseTimer(); } else { var prevProps = current.memoizedProps; var prevState = current.memoizedState; startPhaseTimer(finishedWork, "componentDidUpdate"); - _instance.props = finishedWork.memoizedProps; - _instance.state = finishedWork.memoizedState; - _instance.componentDidUpdate(prevProps, prevState); + _instance2.props = finishedWork.memoizedProps; + _instance2.state = finishedWork.memoizedState; + _instance2.componentDidUpdate( + prevProps, + prevState, + _instance2.__reactInternalSnapshotBeforeUpdate + ); stopPhaseTimer(); } } var updateQueue = finishedWork.updateQueue; if (updateQueue !== null) { - commitCallbacks(updateQueue, _instance); + commitCallbacks(updateQueue, _instance2); } return; } case HostRoot: { var _updateQueue = finishedWork.updateQueue; if (_updateQueue !== null) { - var _instance2 = null; + var _instance3 = null; if (finishedWork.child !== null) { switch (finishedWork.child.tag) { case HostComponent: - _instance2 = getPublicInstance(finishedWork.child.stateNode); + _instance3 = getPublicInstance(finishedWork.child.stateNode); break; case ClassComponent: - _instance2 = finishedWork.child.stateNode; + _instance3 = finishedWork.child.stateNode; break; } } - commitCallbacks(_updateQueue, _instance2); + commitCallbacks(_updateQueue, _instance3); } return; } case HostComponent: { - var _instance3 = finishedWork.stateNode; + var _instance4 = 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). @@ -10036,7 +10382,7 @@ var ReactFiberCommitWork = function( if (current === null && finishedWork.effectTag & Update) { var type = finishedWork.type; var props = finishedWork.memoizedProps; - commitMount(_instance3, type, props, finishedWork); + commitMount(_instance4, type, props, finishedWork); } return; @@ -10064,7 +10410,7 @@ var ReactFiberCommitWork = function( case ClassComponent: { var ctor = finishedWork.type; - var _instance4 = finishedWork.stateNode; + var _instance5 = finishedWork.stateNode; var updateQueue = finishedWork.updateQueue; invariant( updateQueue !== null && updateQueue.capturedValues !== null, @@ -10081,16 +10427,19 @@ var ReactFiberCommitWork = function( // This gets reset before we yield back to the browser. // TODO: Warn in strict mode if getDerivedStateFromCatch is // not defined. - markLegacyErrorBoundaryAsFailed(_instance4); + markLegacyErrorBoundaryAsFailed(_instance5); } - _instance4.props = finishedWork.memoizedProps; - _instance4.state = finishedWork.memoizedState; + _instance5.props = finishedWork.memoizedProps; + _instance5.state = finishedWork.memoizedState; for (var i = 0; i < capturedErrors.length; i++) { var errorInfo = capturedErrors[i]; var _error = errorInfo.value; + var stack = errorInfo.stack; logError(finishedWork, errorInfo); - _instance4.componentDidCatch(_error); + _instance5.componentDidCatch(_error, { + componentStack: stack !== null ? stack : "" + }); } } break; @@ -10123,14 +10472,14 @@ var ReactFiberCommitWork = function( function commitAttachRef(finishedWork) { var ref = finishedWork.ref; if (ref !== null) { - var _instance5 = finishedWork.stateNode; + var _instance6 = finishedWork.stateNode; var instanceToUse = void 0; switch (finishedWork.tag) { case HostComponent: - instanceToUse = getPublicInstance(_instance5); + instanceToUse = getPublicInstance(_instance6); break; default: - instanceToUse = _instance5; + instanceToUse = _instance6; } if (typeof ref === "function") { ref(instanceToUse); @@ -10174,9 +10523,9 @@ var ReactFiberCommitWork = function( switch (current.tag) { case ClassComponent: { safelyDetachRef(current); - var _instance6 = current.stateNode; - if (typeof _instance6.componentWillUnmount === "function") { - safelyCallComponentWillUnmount(current, _instance6); + var _instance7 = current.stateNode; + if (typeof _instance7.componentWillUnmount === "function") { + safelyCallComponentWillUnmount(current, _instance7); } return; } @@ -10313,6 +10662,7 @@ var ReactFiberCommitWork = function( }, commitLifeCycles: commitLifeCycles, + commitBeforeMutationLifeCycles: commitBeforeMutationLifeCycles, commitErrorLogging: commitErrorLogging, commitAttachRef: commitAttachRef, commitDetachRef: commitDetachRef @@ -10571,8 +10921,8 @@ var ReactFiberCommitWork = function( return; } case HostComponent: { - var _instance7 = finishedWork.stateNode; - if (_instance7 != null) { + var _instance8 = finishedWork.stateNode; + if (_instance8 != null) { // Commit the work prepared earlier. var newProps = finishedWork.memoizedProps; // For hydration we reuse the update path but we treat the oldProps @@ -10585,7 +10935,7 @@ var ReactFiberCommitWork = function( finishedWork.updateQueue = null; if (updatePayload !== null) { commitUpdate( - _instance7, + _instance8, updatePayload, type, oldProps, @@ -10630,6 +10980,7 @@ var ReactFiberCommitWork = function( if (enableMutatingReconciler) { return { + commitBeforeMutationLifeCycles: commitBeforeMutationLifeCycles, commitResetTextContent: commitResetTextContent, commitPlacement: commitPlacement, commitDeletion: commitDeletion, @@ -10675,12 +11026,19 @@ var ReactFiberHostContext = function(config, stack) { // Push current root instance onto the stack; // This allows us to reset root when portals are popped. push(rootInstanceStackCursor, nextRootInstance, fiber); - - var nextRootContext = getRootHostContext(nextRootInstance); - // 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, NO_CONTEXT, fiber); + var nextRootContext = getRootHostContext(nextRootInstance); + // Now that we know this function doesn't throw, replace it. + pop(contextStackCursor, fiber); push(contextStackCursor, nextRootContext, fiber); } @@ -11391,7 +11749,7 @@ var ReactFiberNewContext = function(stack) { } function pushProvider(providerFiber) { - var context = providerFiber.type.context; + var context = providerFiber.type._context; push(changedBitsCursor, context._changedBits, providerFiber); push(valueCursor, context._currentValue, providerFiber); @@ -11401,12 +11759,16 @@ var ReactFiberNewContext = function(stack) { context._changedBits = providerFiber.stateNode; { - warning( + !( context._currentRenderer === null || - context._currentRenderer === rendererSigil, - "Detected multiple renderers concurrently rendering the " + - "same context provider. This is currently unsupported." - ); + context._currentRenderer === rendererSigil + ) + ? warning( + false, + "Detected multiple renderers concurrently rendering the " + + "same context provider. This is currently unsupported." + ) + : void 0; context._currentRenderer = rendererSigil; } } @@ -11419,7 +11781,7 @@ var ReactFiberNewContext = function(stack) { pop(valueCursor, providerFiber); pop(changedBitsCursor, providerFiber); - var context = providerFiber.type.context; + var context = providerFiber.type._context; context._currentValue = currentValue; context._changedBits = changedBits; } @@ -11532,17 +11894,19 @@ var warnAboutInvalidUpdates = void 0; var didWarnStateUpdateForUnmountedComponent = {}; warnAboutUpdateOnUnmounted = function(fiber) { + // 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) || "ReactClass"; if (didWarnStateUpdateForUnmountedComponent[componentName]) { return; } warning( false, - "Can only update a mounted or mounting " + - "component. This usually means you called setState, replaceState, " + - "or forceUpdate on an unmounted component. This is a no-op.\n\nPlease " + - "check the code for the %s component.", - componentName + "Can't call setState (or forceUpdate) 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 the " + + "componentWillUnmount method.%s", + getStackAddendumByWorkInProgressFiber(fiber) ); didWarnStateUpdateForUnmountedComponent[componentName] = true; }; @@ -11628,6 +11992,8 @@ var ReactFiberScheduler = function(config) { markLegacyErrorBoundaryAsFailed, recalculateCurrentTime ), + commitBeforeMutationLifeCycles = + _ReactFiberCommitWork.commitBeforeMutationLifeCycles, commitResetTextContent = _ReactFiberCommitWork.commitResetTextContent, commitPlacement = _ReactFiberCommitWork.commitPlacement, commitDeletion = _ReactFiberCommitWork.commitDeletion, @@ -11679,11 +12045,19 @@ var ReactFiberScheduler = function(config) { var stashedWorkInProgressProperties = void 0; var replayUnitOfWork = void 0; + var isReplayingFailedUnitOfWork = void 0; + var originalReplayError = void 0; + var rethrowOriginalError = void 0; if (true && replayFailedUnitOfWorkWithInvokeGuardedCallback) { stashedWorkInProgressProperties = null; - replayUnitOfWork = function(failedUnitOfWork, isAsync) { - // Retore the original state of the work-in-progress - Object.assign(failedUnitOfWork, stashedWorkInProgressProperties); + isReplayingFailedUnitOfWork = false; + originalReplayError = null; + replayUnitOfWork = function(failedUnitOfWork, error, isAsync) { + // Restore the original state of the work-in-progress + assignFiberPropertiesInDEV( + failedUnitOfWork, + stashedWorkInProgressProperties + ); switch (failedUnitOfWork.tag) { case HostRoot: popHostContainer(failedUnitOfWork); @@ -11703,14 +12077,22 @@ var ReactFiberScheduler = function(config) { break; } // Replay the begin phase. + isReplayingFailedUnitOfWork = true; + originalReplayError = error; invokeGuardedCallback$2(null, workLoop, null, isAsync); + isReplayingFailedUnitOfWork = false; + originalReplayError = null; if (hasCaughtError()) { clearCaughtError(); } else { - // This should be unreachable because the render phase is - // idempotent + // If the begin phase did not fail the second time, set this pointer + // back to the original value. + nextUnitOfWork = failedUnitOfWork; } }; + rethrowOriginalError = function() { + throw originalReplayError; + }; } function resetStack() { @@ -11742,6 +12124,7 @@ var ReactFiberScheduler = function(config) { recordEffect(); var effectTag = nextEffect.effectTag; + if (effectTag & ContentReset) { commitResetTextContent(nextEffect); } @@ -11799,6 +12182,22 @@ var ReactFiberScheduler = function(config) { } } + function commitBeforeMutationLifecycles() { + while (nextEffect !== null) { + var effectTag = nextEffect.effectTag; + + if (effectTag & Snapshot) { + recordEffect(); + var current = nextEffect.alternate; + commitBeforeMutationLifeCycles(current, nextEffect); + } + + // Don't cleanup effects yet; + // This will be done by commitAllLifeCycles() + nextEffect = nextEffect.nextEffect; + } + } + function commitAllLifeCycles( finishedRoot, currentTime, @@ -11906,16 +12305,14 @@ var ReactFiberScheduler = function(config) { prepareForCommit(root.containerInfo); - // Commit all the side-effects within a tree. We'll do this in two passes. - // The first pass performs all the host insertions, updates, deletions and - // ref unmounts. + // Invoke instances of getSnapshotBeforeUpdate before mutation. nextEffect = firstEffect; - startCommitHostEffectsTimer(); + startCommitSnapshotEffectsTimer(); while (nextEffect !== null) { var didError = false; var error = void 0; { - invokeGuardedCallback$2(null, commitAllHostEffects, null); + invokeGuardedCallback$2(null, commitBeforeMutationLifecycles, null); if (hasCaughtError()) { didError = true; error = clearCaughtError(); @@ -11934,6 +12331,36 @@ var ReactFiberScheduler = function(config) { } } } + stopCommitSnapshotEffectsTimer(); + + // Commit all the side-effects within a tree. We'll do this in two passes. + // The first pass performs all the host insertions, updates, deletions and + // ref unmounts. + nextEffect = firstEffect; + startCommitHostEffectsTimer(); + while (nextEffect !== null) { + var _didError = false; + var _error = void 0; + { + invokeGuardedCallback$2(null, commitAllHostEffects, null); + if (hasCaughtError()) { + _didError = true; + _error = clearCaughtError(); + } + } + if (_didError) { + invariant( + nextEffect !== null, + "Should have next effect. This error is likely caused by a bug " + + "in React. Please file an issue." + ); + onCommitPhaseError(nextEffect, _error); + // Clean-up + if (nextEffect !== null) { + nextEffect = nextEffect.nextEffect; + } + } + } stopCommitHostEffectsTimer(); resetAfterCommit(root.containerInfo); @@ -11951,8 +12378,8 @@ var ReactFiberScheduler = function(config) { nextEffect = firstEffect; startCommitLifeCyclesTimer(); while (nextEffect !== null) { - var _didError = false; - var _error = void 0; + var _didError2 = false; + var _error2 = void 0; { invokeGuardedCallback$2( null, @@ -11963,17 +12390,17 @@ var ReactFiberScheduler = function(config) { committedExpirationTime ); if (hasCaughtError()) { - _didError = true; - _error = clearCaughtError(); + _didError2 = true; + _error2 = clearCaughtError(); } } - if (_didError) { + if (_didError2) { invariant( nextEffect !== null, "Should have next effect. This error is likely caused by a bug " + "in React. Please file an issue." ); - onCommitPhaseError(nextEffect, _error); + onCommitPhaseError(nextEffect, _error2); if (nextEffect !== null) { nextEffect = nextEffect.nextEffect; } @@ -12197,12 +12624,21 @@ var ReactFiberScheduler = function(config) { } if (true && replayFailedUnitOfWorkWithInvokeGuardedCallback) { - stashedWorkInProgressProperties = Object.assign({}, workInProgress); + stashedWorkInProgressProperties = assignFiberPropertiesInDEV( + stashedWorkInProgressProperties, + workInProgress + ); } var next = beginWork(current, workInProgress, nextRenderExpirationTime); - { ReactDebugCurrentFiber.resetCurrentFiber(); + if (isReplayingFailedUnitOfWork) { + // Currently replaying a failed unit of work. This should be unreachable, + // because the render phase is meant to be idempotent, and it should + // have thrown again. Since it didn't, rethrow the original error, so + // React's internal stack is not misaligned. + rethrowOriginalError(); + } } if (true && ReactFiberInstrumentation_1.debugTool) { ReactFiberInstrumentation_1.debugTool.onBeginWork(workInProgress); @@ -12276,13 +12712,18 @@ var ReactFiberScheduler = function(config) { if (true && replayFailedUnitOfWorkWithInvokeGuardedCallback) { var failedUnitOfWork = nextUnitOfWork; - replayUnitOfWork(failedUnitOfWork, isAsync); + replayUnitOfWork(failedUnitOfWork, thrownValue, isAsync); } var sourceFiber = nextUnitOfWork; var returnFiber = sourceFiber["return"]; if (returnFiber === null) { - // This is a fatal error. + // This is the root. The root could capture its own errors. However, + // we don't know if it errors before or after we pushed the host + // context. This information is needed to avoid a stack mismatch. + // Because we're not sure, treat this as a fatal error. We could track + // which phase it fails in, but doesn't seem worth it. At least + // for now. didFatal = true; onUncaughtError(thrownValue); break; @@ -12294,12 +12735,13 @@ var ReactFiberScheduler = function(config) { } while (true); // We're done performing work. Time to clean up. - stopWorkLoopTimer(interruptedBy); - interruptedBy = null; + var didCompleteRoot = false; isWorking = false; // Yield back to main thread. if (didFatal) { + stopWorkLoopTimer(interruptedBy, didCompleteRoot); + interruptedBy = null; // There was a fatal error. { stack.resetStackAfterFatalErrorInDev(); @@ -12308,12 +12750,17 @@ var ReactFiberScheduler = function(config) { } else if (nextUnitOfWork === null) { // We reached the root. if (isRootReadyForCommit) { + didCompleteRoot = true; + stopWorkLoopTimer(interruptedBy, didCompleteRoot); + interruptedBy = null; // The root successfully completed. It's ready for commit. root.pendingCommitExpirationTime = expirationTime; var finishedWork = root.current.alternate; return finishedWork; } else { // The root did not complete. + stopWorkLoopTimer(interruptedBy, didCompleteRoot); + interruptedBy = null; invariant( false, "Expired work should have completed. This error is likely caused " + @@ -12321,6 +12768,8 @@ var ReactFiberScheduler = function(config) { ); } } else { + stopWorkLoopTimer(interruptedBy, didCompleteRoot); + interruptedBy = null; // There's more work to do, but we ran out of time. Yield back to // the renderer. return null; @@ -12506,7 +12955,15 @@ var ReactFiberScheduler = function(config) { interruptedBy = fiber; resetStack(); } - if (nextRoot !== root || !isWorking) { + if ( + // If we're in the render phase, we don't need to schedule this root + // for an update, because we'll do it before we exit... + !isWorking || + isCommitting || + // ...unless this is a different root than the one we're rendering. + nextRoot !== root + ) { + // Add this root to the root schedule. requestWork(root, expirationTime); } if (nestedUpdateCount > NESTED_UPDATE_LIMIT) { @@ -12766,7 +13223,8 @@ var ReactFiberScheduler = function(config) { if (enableUserTimingAPI && deadline !== null) { var didExpire = nextFlushedExpirationTime < recalculateCurrentTime(); - stopRequestCallbackTimer(didExpire); + var timeout = expirationTimeToMs(nextFlushedExpirationTime); + stopRequestCallbackTimer(didExpire, timeout); } if (isAsync) { @@ -12826,7 +13284,11 @@ var ReactFiberScheduler = function(config) { // Perform work on root as if the given expiration time is the current time. // This has the effect of synchronously flushing all work up to and // including the given time. + nextFlushedRoot = root; + nextFlushedExpirationTime = expirationTime; performWorkOnRoot(root, expirationTime, false); + // Flush any sync work that was scheduled by lifecycles + performSyncWork(); finishRendering(); } @@ -13153,12 +13615,14 @@ var ReactFiberReconciler$1 = function(config) { callback = callback === undefined ? null : callback; { - warning( - callback === null || typeof callback === "function", - "render(...): Expected the last optional `callback` argument to be a " + - "function. Instead received: %s.", - callback - ); + !(callback === null || typeof callback === "function") + ? warning( + false, + "render(...): Expected the last optional `callback` argument to be a " + + "function. Instead received: %s.", + callback + ) + : void 0; } var update = { diff --git a/Libraries/Renderer/ReactFabric-prod.js b/Libraries/Renderer/ReactFabric-prod.js index 08f112c70d4570..c12ebd601c84d0 100644 --- a/Libraries/Renderer/ReactFabric-prod.js +++ b/Libraries/Renderer/ReactFabric-prod.js @@ -1494,7 +1494,8 @@ var ReactNativeComponent = (function(_React$Component) { frameDeadlineObject = { timeRemaining: function() { return frameDeadline - now(); - } + }, + didTimeout: !1 }; function setTimeoutCallback() { frameDeadline = now() + 5; @@ -2036,13 +2037,18 @@ function ReactFiberClassComponent( instance.state !== workInProgress && updater.enqueueReplaceState(instance, instance.state, null); } - function callGetDerivedStateFromProps(workInProgress, instance, props) { - instance = workInProgress.type; - if ("function" === typeof instance.getDerivedStateFromProps) - return instance.getDerivedStateFromProps.call( + function callGetDerivedStateFromProps( + workInProgress, + instance, + nextProps, + prevState + ) { + workInProgress = workInProgress.type; + if ("function" === typeof workInProgress.getDerivedStateFromProps) + return workInProgress.getDerivedStateFromProps.call( null, - props, - workInProgress.memoizedState + nextProps, + prevState ); } var cacheContext = legacyContext.cacheContext, @@ -2113,7 +2119,7 @@ function ReactFiberClassComponent( null !== ctor.state && void 0 !== ctor.state ? ctor.state : null; adoptClassInstance(workInProgress, ctor); workInProgress.memoizedState = state; - props = callGetDerivedStateFromProps(workInProgress, ctor, props); + props = callGetDerivedStateFromProps(workInProgress, ctor, props, state); null !== props && void 0 !== props && (workInProgress.memoizedState = Object.assign( @@ -2134,9 +2140,10 @@ function ReactFiberClassComponent( instance.state = workInProgress.memoizedState; instance.refs = emptyObject; instance.context = getMaskedContext(workInProgress, unmaskedContext); - ("function" !== typeof instance.UNSAFE_componentWillMount && - "function" !== typeof instance.componentWillMount) || - "function" === typeof ctor.getDerivedStateFromProps || + "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(), @@ -2167,9 +2174,11 @@ function ReactFiberClassComponent( oldContext = instance.context, newUnmaskedContext = getUnmaskedContext(workInProgress); newUnmaskedContext = getMaskedContext(workInProgress, newUnmaskedContext); - ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && - "function" !== typeof instance.componentWillReceiveProps) || + (ctor = "function" === typeof ctor.getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate) || + ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && + "function" !== typeof instance.componentWillReceiveProps) || ((oldProps !== newProps || oldContext !== newUnmaskedContext) && callComponentWillReceiveProps( workInProgress, @@ -2177,14 +2186,7 @@ function ReactFiberClassComponent( newProps, newUnmaskedContext )); - oldContext = void 0; - oldProps !== newProps && - (oldContext = callGetDerivedStateFromProps( - workInProgress, - instance, - newProps - )); - var oldState = workInProgress.memoizedState; + oldContext = workInProgress.memoizedState; renderExpirationTime = null !== workInProgress.updateQueue ? processUpdateQueue( @@ -2195,17 +2197,32 @@ function ReactFiberClassComponent( newProps, renderExpirationTime ) - : oldState; - null !== oldContext && - void 0 !== oldContext && - (renderExpirationTime = + : oldContext; + var derivedStateFromProps = void 0; + oldProps !== newProps && + (derivedStateFromProps = callGetDerivedStateFromProps( + workInProgress, + instance, + newProps, + renderExpirationTime + )); + if (null !== derivedStateFromProps && void 0 !== derivedStateFromProps) { + renderExpirationTime = null === renderExpirationTime || void 0 === renderExpirationTime - ? oldContext - : Object.assign({}, renderExpirationTime, oldContext)); + ? derivedStateFromProps + : Object.assign({}, renderExpirationTime, derivedStateFromProps); + var _updateQueue = workInProgress.updateQueue; + null !== _updateQueue && + (_updateQueue.baseState = Object.assign( + {}, + _updateQueue.baseState, + derivedStateFromProps + )); + } if ( !( oldProps !== newProps || - oldState !== renderExpirationTime || + oldContext !== renderExpirationTime || hasContextChanged() || (null !== workInProgress.updateQueue && workInProgress.updateQueue.hasForceUpdate) @@ -2220,13 +2237,13 @@ function ReactFiberClassComponent( workInProgress, oldProps, newProps, - oldState, + oldContext, renderExpirationTime, newUnmaskedContext )) - ? (("function" !== typeof instance.UNSAFE_componentWillMount && - "function" !== typeof instance.componentWillMount) || - "function" === typeof ctor.getDerivedStateFromProps || + ? (ctor || + ("function" !== typeof instance.UNSAFE_componentWillMount && + "function" !== typeof instance.componentWillMount) || ("function" === typeof instance.componentWillMount && instance.componentWillMount(), "function" === typeof instance.UNSAFE_componentWillMount && @@ -2256,9 +2273,11 @@ function ReactFiberClassComponent( oldContext = instance.context, newUnmaskedContext = getUnmaskedContext(workInProgress); newUnmaskedContext = getMaskedContext(workInProgress, newUnmaskedContext); - ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && - "function" !== typeof instance.componentWillReceiveProps) || + (ctor = "function" === typeof ctor.getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate) || + ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && + "function" !== typeof instance.componentWillReceiveProps) || ((oldProps !== newProps || oldContext !== newUnmaskedContext) && callComponentWillReceiveProps( workInProgress, @@ -2266,13 +2285,6 @@ function ReactFiberClassComponent( newProps, newUnmaskedContext )); - var derivedStateFromProps = void 0; - oldProps !== newProps && - (derivedStateFromProps = callGetDerivedStateFromProps( - workInProgress, - instance, - newProps - )); oldContext = workInProgress.memoizedState; renderExpirationTime = null !== workInProgress.updateQueue @@ -2285,12 +2297,27 @@ function ReactFiberClassComponent( renderExpirationTime ) : oldContext; - null !== derivedStateFromProps && - void 0 !== derivedStateFromProps && - (renderExpirationTime = + var derivedStateFromProps = void 0; + oldProps !== newProps && + (derivedStateFromProps = callGetDerivedStateFromProps( + workInProgress, + instance, + newProps, + renderExpirationTime + )); + if (null !== derivedStateFromProps && void 0 !== derivedStateFromProps) { + renderExpirationTime = null === renderExpirationTime || void 0 === renderExpirationTime ? derivedStateFromProps - : Object.assign({}, renderExpirationTime, derivedStateFromProps)); + : Object.assign({}, renderExpirationTime, derivedStateFromProps); + var _updateQueue3 = workInProgress.updateQueue; + null !== _updateQueue3 && + (_updateQueue3.baseState = Object.assign( + {}, + _updateQueue3.baseState, + derivedStateFromProps + )); + } if ( !( oldProps !== newProps || @@ -2305,6 +2332,10 @@ function ReactFiberClassComponent( (oldProps === current.memoizedProps && oldContext === current.memoizedState) || (workInProgress.effectTag |= 4), + "function" !== typeof instance.getSnapshotBeforeUpdate || + (oldProps === current.memoizedProps && + oldContext === current.memoizedState) || + (workInProgress.effectTag |= 2048), !1 ); (derivedStateFromProps = checkShouldComponentUpdate( @@ -2315,9 +2346,9 @@ function ReactFiberClassComponent( renderExpirationTime, newUnmaskedContext )) - ? (("function" !== typeof instance.UNSAFE_componentWillUpdate && - "function" !== typeof instance.componentWillUpdate) || - "function" === typeof ctor.getDerivedStateFromProps || + ? (ctor || + ("function" !== typeof instance.UNSAFE_componentWillUpdate && + "function" !== typeof instance.componentWillUpdate) || ("function" === typeof instance.componentWillUpdate && instance.componentWillUpdate( newProps, @@ -2331,11 +2362,17 @@ function ReactFiberClassComponent( newUnmaskedContext )), "function" === typeof instance.componentDidUpdate && - (workInProgress.effectTag |= 4)) + (workInProgress.effectTag |= 4), + "function" === typeof instance.getSnapshotBeforeUpdate && + (workInProgress.effectTag |= 2048)) : ("function" !== typeof instance.componentDidUpdate || (oldProps === current.memoizedProps && oldContext === current.memoizedState) || (workInProgress.effectTag |= 4), + "function" !== typeof instance.getSnapshotBeforeUpdate || + (oldProps === current.memoizedProps && + oldContext === current.memoizedState) || + (workInProgress.effectTag |= 2048), memoizeProps(workInProgress, newProps), memoizeState(workInProgress, renderExpirationTime)); instance.props = newProps; @@ -3181,7 +3218,7 @@ function ReactFiberBeginWork( workInProgress, renderExpirationTime ) { - var context = workInProgress.type.context, + var context = workInProgress.type._context, newProps = workInProgress.pendingProps, oldProps = workInProgress.memoizedProps; if (!hasLegacyContextChanged() && oldProps === newProps) @@ -3347,7 +3384,8 @@ function ReactFiberBeginWork( ((props = callGetDerivedStateFromProps( workInProgress, fn, - props + props, + workInProgress.memoizedState )), null !== props && void 0 !== props && @@ -3618,43 +3656,33 @@ function ReactFiberBeginWork( renderExpirationTime ); case 12: - a: { - fn = workInProgress.type; - unmaskedContext = workInProgress.pendingProps; - updateQueue = workInProgress.memoizedProps; - props = fn._currentValue; - var changedBits = fn._changedBits; - if ( - hasLegacyContextChanged() || - 0 !== changedBits || - updateQueue !== unmaskedContext - ) { - workInProgress.memoizedProps = unmaskedContext; - var observedBits = unmaskedContext.unstable_observedBits; - if (void 0 === observedBits || null === observedBits) - observedBits = 1073741823; - workInProgress.stateNode = observedBits; - if (0 !== (changedBits & observedBits)) - propagateContextChange( - workInProgress, - fn, - changedBits, - renderExpirationTime - ); - else if ( - null !== updateQueue && - updateQueue.children === unmaskedContext.children - ) { - current = bailoutOnAlreadyFinishedWork(current, workInProgress); - break a; - } - renderExpirationTime = unmaskedContext.children; - renderExpirationTime = renderExpirationTime(props); - reconcileChildren(current, workInProgress, renderExpirationTime); - current = workInProgress.child; - } else - current = bailoutOnAlreadyFinishedWork(current, workInProgress); - } + fn = workInProgress.type; + unmaskedContext = workInProgress.pendingProps; + var oldProps = workInProgress.memoizedProps; + props = fn._currentValue; + updateQueue = fn._changedBits; + if ( + hasLegacyContextChanged() || + 0 !== updateQueue || + oldProps !== unmaskedContext + ) { + workInProgress.memoizedProps = unmaskedContext; + oldProps = unmaskedContext.unstable_observedBits; + if (void 0 === oldProps || null === oldProps) oldProps = 1073741823; + workInProgress.stateNode = oldProps; + 0 !== (updateQueue & oldProps) && + propagateContextChange( + workInProgress, + fn, + updateQueue, + renderExpirationTime + ); + renderExpirationTime = unmaskedContext.children; + renderExpirationTime = renderExpirationTime(props); + reconcileChildren(current, workInProgress, renderExpirationTime); + current = workInProgress.child; + } else + current = bailoutOnAlreadyFinishedWork(current, workInProgress); return current; default: invariant( @@ -4105,7 +4133,7 @@ function logError(boundary, errorInfo) { null === errorInfo.stack && getStackAddendumByWorkInProgressFiber(source); null !== source && getComponentName(source); errorInfo = errorInfo.value; - null !== boundary && getComponentName(boundary); + null !== boundary && 2 === boundary.tag && getComponentName(boundary); try { (errorInfo && errorInfo.suppressReactErrorLogging) || console.error(errorInfo); @@ -4131,6 +4159,31 @@ function ReactFiberCommitWork( } else ref.current = null; } + function commitBeforeMutationLifeCycles(current, finishedWork) { + switch (finishedWork.tag) { + case 2: + if (finishedWork.effectTag & 2048 && null !== current) { + var prevProps = current.memoizedProps, + prevState = current.memoizedState; + current = finishedWork.stateNode; + current.props = finishedWork.memoizedProps; + current.state = finishedWork.memoizedState; + finishedWork = current.getSnapshotBeforeUpdate(prevProps, prevState); + current.__reactInternalSnapshotBeforeUpdate = finishedWork; + } + break; + case 3: + case 5: + case 6: + case 4: + break; + default: + invariant( + !1, + "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 commitLifeCycles(finishedRoot, current, finishedWork) { switch (finishedWork.tag) { case 2: @@ -4145,7 +4198,11 @@ function ReactFiberCommitWork( current = current.memoizedState; finishedRoot.props = finishedWork.memoizedProps; finishedRoot.state = finishedWork.memoizedState; - finishedRoot.componentDidUpdate(prevProps, current); + finishedRoot.componentDidUpdate( + prevProps, + current, + finishedRoot.__reactInternalSnapshotBeforeUpdate + ); } finishedWork = finishedWork.updateQueue; null !== finishedWork && commitCallbacks(finishedWork, finishedRoot); @@ -4205,9 +4262,12 @@ function ReactFiberCommitWork( onUncaughtError.state = finishedWork.memoizedState; for (ctor = 0; ctor < capturedErrors.length; ctor++) { updateQueue = capturedErrors[ctor]; - var _error = updateQueue.value; + var _error = updateQueue.value, + stack = updateQueue.stack; logError(finishedWork, updateQueue); - onUncaughtError.componentDidCatch(_error); + onUncaughtError.componentDidCatch(_error, { + componentStack: null !== stack ? stack : "" + }); } break; case 3: @@ -4233,13 +4293,13 @@ function ReactFiberCommitWork( function commitAttachRef(finishedWork) { var ref = finishedWork.ref; if (null !== ref) { - var _instance5 = finishedWork.stateNode; + var _instance6 = finishedWork.stateNode; switch (finishedWork.tag) { case 5: - finishedWork = getPublicInstance(_instance5); + finishedWork = getPublicInstance(_instance6); break; default: - finishedWork = _instance5; + finishedWork = _instance6; } "function" === typeof ref ? ref(finishedWork) @@ -4260,12 +4320,12 @@ function ReactFiberCommitWork( switch (current.tag) { case 2: safelyDetachRef(current); - var _instance6 = current.stateNode; - if ("function" === typeof _instance6.componentWillUnmount) + var _instance7 = current.stateNode; + if ("function" === typeof _instance7.componentWillUnmount) try { - (_instance6.props = current.memoizedProps), - (_instance6.state = current.memoizedState), - _instance6.componentWillUnmount(); + (_instance7.props = current.memoizedProps), + (_instance7.state = current.memoizedState), + _instance7.componentWillUnmount(); } catch (unmountError) { captureError(current, unmountError); } @@ -4343,6 +4403,7 @@ function ReactFiberCommitWork( commitContainer(finishedWork); }, commitLifeCycles: commitLifeCycles, + commitBeforeMutationLifeCycles: commitBeforeMutationLifeCycles, commitErrorLogging: commitErrorLogging, commitAttachRef: commitAttachRef, commitDetachRef: commitDetachRef @@ -4386,8 +4447,10 @@ function ReactFiberHostContext(config, stack) { }, pushHostContainer: function(fiber, nextRootInstance) { push(rootInstanceStackCursor, nextRootInstance, fiber); - nextRootInstance = getRootHostContext(nextRootInstance); push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor, NO_CONTEXT, fiber); + nextRootInstance = getRootHostContext(nextRootInstance); + pop(contextStackCursor, fiber); push(contextStackCursor, nextRootInstance, fiber); }, pushHostContext: function(fiber) { @@ -4694,7 +4757,7 @@ function ReactFiberNewContext(stack) { changedBitsCursor = createCursor(0); return { pushProvider: function(providerFiber) { - var context = providerFiber.type.context; + var context = providerFiber.type._context; push(changedBitsCursor, context._changedBits, providerFiber); push(valueCursor, context._currentValue, providerFiber); push(providerCursor, providerFiber, providerFiber); @@ -4707,7 +4770,7 @@ function ReactFiberNewContext(stack) { pop(providerCursor, providerFiber); pop(valueCursor, providerFiber); pop(changedBitsCursor, providerFiber); - providerFiber = providerFiber.type.context; + providerFiber = providerFiber.type._context; providerFiber._currentValue = currentValue; providerFiber._changedBits = changedBits; } @@ -4820,7 +4883,7 @@ function ReactFiberScheduler(config) { workInProgress$jscomp$0 = unwindWork(workInProgress$jscomp$0); if (null !== workInProgress$jscomp$0) return ( - (workInProgress$jscomp$0.effectTag &= 511), workInProgress$jscomp$0 + (workInProgress$jscomp$0.effectTag &= 2559), workInProgress$jscomp$0 ); null !== returnFiber && ((returnFiber.firstEffect = returnFiber.lastEffect = null), @@ -4984,7 +5047,7 @@ function ReactFiberScheduler(config) { 0 !== nextRenderExpirationTime && expirationTime < nextRenderExpirationTime && resetStack(); - (nextRoot === root && isWorking) || + (isWorking && !isCommitting && nextRoot === root) || requestWork(root, expirationTime); nestedUpdateCount > NESTED_UPDATE_LIMIT && invariant( @@ -5048,7 +5111,7 @@ function ReactFiberScheduler(config) { (nextFlushedExpirationTime = 1), performWorkOnRoot(root, 1, !1)) : 1 === expirationTime - ? performWork(1, !1, null) + ? performSyncWork() : scheduleCallbackWithExpiration(expirationTime)); } function findHighestPriorityRoot() { @@ -5108,6 +5171,9 @@ function ReactFiberScheduler(config) { function performAsyncWork(dl) { performWork(0, !0, dl); } + function performSyncWork() { + performWork(1, !1, null); + } function performWork(minExpirationTime, isAsync, dl) { deadline = dl; findHighestPriorityRoot(); @@ -5230,6 +5296,25 @@ function ReactFiberScheduler(config) { for (nextEffect = firstEffect; null !== nextEffect; ) { var didError = !1, error = void 0; + try { + for (; null !== nextEffect; ) + nextEffect.effectTag & 2048 && + commitBeforeMutationLifeCycles(nextEffect.alternate, nextEffect), + (nextEffect = nextEffect.nextEffect); + } catch (e) { + (didError = !0), (error = e); + } + didError && + (invariant( + null !== nextEffect, + "Should have next effect. This error is likely caused by a bug in React. Please file an issue." + ), + onCommitPhaseError(nextEffect, error), + null !== nextEffect && (nextEffect = nextEffect.nextEffect)); + } + for (nextEffect = firstEffect; null !== nextEffect; ) { + didError = !1; + error = void 0; try { for (; null !== nextEffect; ) { var effectTag = nextEffect.effectTag; @@ -5370,7 +5455,9 @@ function ReactFiberScheduler(config) { }, recalculateCurrentTime ); - var commitResetTextContent = hostContext.commitResetTextContent, + var commitBeforeMutationLifeCycles = + hostContext.commitBeforeMutationLifeCycles, + commitResetTextContent = hostContext.commitResetTextContent, commitPlacement = hostContext.commitPlacement, commitDeletion = hostContext.commitDeletion, commitWork = hostContext.commitWork, @@ -5425,7 +5512,10 @@ function ReactFiberScheduler(config) { !isRendering, "work.commit(): Cannot commit while already rendering. This likely means you attempted to commit from inside a lifecycle method." ); + nextFlushedRoot = root; + nextFlushedExpirationTime = expirationTime; performWorkOnRoot(root, expirationTime, !1); + performSyncWork(); finishRendering(); }, batchedUpdates: function(fn, a) { @@ -5436,7 +5526,7 @@ function ReactFiberScheduler(config) { } finally { (isBatchingUpdates = previousIsBatchingUpdates) || isRendering || - performWork(1, !1, null); + performSyncWork(); } }, unbatchedUpdates: function(fn, a) { @@ -5460,8 +5550,7 @@ function ReactFiberScheduler(config) { try { return syncUpdates(fn, a); } finally { - (isBatchingUpdates = previousIsBatchingUpdates), - performWork(1, !1, null); + (isBatchingUpdates = previousIsBatchingUpdates), performSyncWork(); } }, flushControlled: function(fn) { @@ -5502,7 +5591,7 @@ function ReactFiberScheduler(config) { (isBatchingInteractiveUpdates = previousIsBatchingInteractiveUpdates), (isBatchingUpdates = previousIsBatchingUpdates) || isRendering || - performWork(1, !1, null); + performSyncWork(); } }, flushInteractiveUpdates: function() { @@ -6003,7 +6092,7 @@ ReactFabricRenderer.injectIntoDevTools({ findFiberByHostInstance: getInstanceFromTag, getInspectorDataForViewTag: getInspectorDataForViewTag, bundleType: 0, - version: "16.3.0-alpha.2", + version: "16.3.1", rendererPackageName: "react-native-renderer" }); var ReactFabric$2 = Object.freeze({ default: ReactFabric }), diff --git a/Libraries/Renderer/ReactNativeRenderer-dev.js b/Libraries/Renderer/ReactNativeRenderer-dev.js index 8ea8bcf85094fd..7fd62f11ca6ae4 100644 --- a/Libraries/Renderer/ReactNativeRenderer-dev.js +++ b/Libraries/Renderer/ReactNativeRenderer-dev.js @@ -510,11 +510,13 @@ var injection$1 = { getNodeFromInstance = Injected.getNodeFromInstance; { - warning( - getNodeFromInstance && getInstanceFromNode, - "EventPluginUtils.injection.injectComponentTree(...): Injected " + - "module is missing getNodeFromInstance or getInstanceFromNode." - ); + !(getNodeFromInstance && getInstanceFromNode) + ? warning( + false, + "EventPluginUtils.injection.injectComponentTree(...): Injected " + + "module is missing getNodeFromInstance or getInstanceFromNode." + ) + : void 0; } } }; @@ -550,10 +552,9 @@ var validateEventDispatches = void 0; ? dispatchInstances.length : dispatchInstances ? 1 : 0; - warning( - instancesIsArr === listenersIsArr && instancesLen === listenersLen, - "EventPluginUtils: Invalid `event`." - ); + !(instancesIsArr === listenersIsArr && instancesLen === listenersLen) + ? warning(false, "EventPluginUtils: Invalid `event`.") + : void 0; }; } @@ -1094,7 +1095,7 @@ function listenerAtPhase(inst, event, propagationPhase) { */ function accumulateDirectionalDispatches(inst, phase, event) { { - warning(inst, "Dispatching inst must not be null"); + !inst ? warning(false, "Dispatching inst must not be null") : void 0; } var listener = listenerAtPhase(inst, event, phase); if (listener) { @@ -1413,13 +1414,15 @@ SyntheticEvent.extend = function(Interface) { !target.constructor.Interface.hasOwnProperty(prop) && shouldBeReleasedProperties.indexOf(prop) === -1 ) { - warning( - didWarnForAddedNewProperty || target.isPersistent(), - "This synthetic event is reused for performance reasons. If you're " + - "seeing this, you're adding a new property in the synthetic event object. " + - "The property is never released. See " + - "https://fb.me/react-event-pooling for more information." - ); + !(didWarnForAddedNewProperty || target.isPersistent()) + ? warning( + false, + "This synthetic event is reused for performance reasons. If you're " + + "seeing this, you're adding a new property in the synthetic event object. " + + "The property is never released. See " + + "https://fb.me/react-event-pooling for more information." + ) + : void 0; didWarnForAddedNewProperty = true; } target[prop] = value; @@ -1466,16 +1469,18 @@ function getPooledWarningPropertyDefinition(propName, getVal) { function warn(action, result) { var warningCondition = false; - warning( - warningCondition, - "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 - ); + !warningCondition + ? warning( + 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; } } @@ -1593,13 +1598,15 @@ function getTouchIdentifier(_ref) { invariant(identifier != null, "Touch object is missing identifier."); { - warning( - identifier <= MAX_TOUCH_BANK, - "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 - ); + !(identifier <= MAX_TOUCH_BANK) + ? warning( + 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; } @@ -1698,10 +1705,9 @@ var ResponderTouchHistoryStore = { } { var activeRecord = touchBank[touchHistory.indexOfSingleActiveTouch]; - warning( - activeRecord != null && activeRecord.touchActive, - "Cannot find single active touch." - ); + !(activeRecord != null && activeRecord.touchActive) + ? warning(false, "Cannot find single active touch.") + : void 0; } } } @@ -2987,7 +2993,7 @@ var TouchHistoryMath = { // TODO: this is special because it gets imported during build. -var ReactVersion = "16.3.0-alpha.2"; +var ReactVersion = "16.3.1"; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { @@ -3657,15 +3663,17 @@ function findNodeHandle(componentOrHandle) { { var owner = ReactCurrentOwner.current; if (owner !== null && owner.stateNode !== null) { - warning( - owner.stateNode._warnedAboutRefsInRender, - "%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) || "A component" - ); + !owner.stateNode._warnedAboutRefsInRender + ? warning( + 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) || "A component" + ) + : void 0; owner.stateNode._warnedAboutRefsInRender = true; } @@ -4120,9 +4128,10 @@ var Callback = /* */ 32; var DidCapture = /* */ 64; var Ref = /* */ 128; var ErrLog = /* */ 256; +var Snapshot = /* */ 2048; // Union of all host effects -var HostEffectMask = /* */ 511; +var HostEffectMask = /* */ 2559; var Incomplete = /* */ 512; var ShouldCapture = /* */ 1024; @@ -4170,15 +4179,17 @@ function isMounted(component) { if (owner !== null && owner.tag === ClassComponent) { var ownerFiber = owner; var instance = ownerFiber.stateNode; - warning( - instance._warnedAboutRefsInRender, - "%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) || "A component" - ); + !instance._warnedAboutRefsInRender + ? warning( + 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) || "A component" + ) + : void 0; instance._warnedAboutRefsInRender = true; } } @@ -4731,6 +4742,47 @@ function createFiberFromPortal(portal, mode, expirationTime) { 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.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.mode = source.mode; + target.effectTag = source.effectTag; + target.nextEffect = source.nextEffect; + target.firstEffect = source.firstEffect; + target.lastEffect = source.lastEffect; + target.expirationTime = source.expirationTime; + target.alternate = source.alternate; + target._debugID = source._debugID; + target._debugSource = source._debugSource; + target._debugOwner = source._debugOwner; + target._debugIsCurrentlyTiming = source._debugIsCurrentlyTiming; + return target; +} + // TODO: This should be lifted into the renderer. function createFiberRoot(containerInfo, isAsync, hydrate) { @@ -5136,7 +5188,10 @@ var ReactStrictModeWarnings = { ) { pendingComponentWillReceivePropsWarnings.push(fiber); } - if (typeof instance.componentWillUpdate === "function") { + if ( + typeof instance.componentWillUpdate === "function" && + instance.componentWillUpdate.__suppressDeprecationWarning !== true + ) { pendingComponentWillUpdateWarnings.push(fiber); } }; @@ -5481,13 +5536,15 @@ function startRequestCallbackTimer() { } } -function stopRequestCallbackTimer(didExpire) { +function stopRequestCallbackTimer(didExpire, expirationTime) { if (enableUserTimingAPI) { if (supportsUserTiming) { isWaitingForCallback = false; var warning$$1 = didExpire ? "React was blocked by main thread" : null; endMark( - "(Waiting for async callback...)", + "(Waiting for async callback... will force flush in " + + expirationTime + + " ms)", "(Waiting for async callback...)", warning$$1 ); @@ -5597,7 +5654,7 @@ function startWorkLoopTimer(nextUnitOfWork) { } } -function stopWorkLoopTimer(interruptedBy) { +function stopWorkLoopTimer(interruptedBy, didCompleteRoot) { if (enableUserTimingAPI) { if (!supportsUserTiming) { return; @@ -5615,13 +5672,12 @@ function stopWorkLoopTimer(interruptedBy) { warning$$1 = "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( - "(React Tree Reconciliation)", - "(React Tree Reconciliation)", - warning$$1 - ); + endMark(label, "(React Tree Reconciliation)", warning$$1); } } @@ -5658,6 +5714,31 @@ function stopCommitTimer() { } } +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) { @@ -6042,23 +6123,26 @@ var isArray = Array.isArray; var didWarnAboutStateAssignmentForComponent = void 0; var didWarnAboutUndefinedDerivedState = void 0; var didWarnAboutUninitializedState = void 0; -var didWarnAboutWillReceivePropsAndDerivedState = void 0; +var didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = void 0; +var didWarnAboutLegacyLifecyclesAndDerivedState = void 0; var warnOnInvalidCallback = void 0; { - didWarnAboutStateAssignmentForComponent = {}; - didWarnAboutUndefinedDerivedState = {}; - didWarnAboutUninitializedState = {}; - didWarnAboutWillReceivePropsAndDerivedState = {}; + didWarnAboutStateAssignmentForComponent = new Set(); + didWarnAboutUndefinedDerivedState = new Set(); + didWarnAboutUninitializedState = new Set(); + didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = new Set(); + didWarnAboutLegacyLifecyclesAndDerivedState = new Set(); - var didWarnOnInvalidCallback = {}; + var didWarnOnInvalidCallback = new Set(); warnOnInvalidCallback = function(callback, callerName) { if (callback === null || typeof callback === "function") { return; } var key = callerName + "_" + callback; - if (!didWarnOnInvalidCallback[key]) { + if (!didWarnOnInvalidCallback.has(key)) { + didWarnOnInvalidCallback.add(key); warning( false, "%s(...): Expected the last optional `callback` argument to be a " + @@ -6066,7 +6150,6 @@ var warnOnInvalidCallback = void 0; callerName, callback ); - didWarnOnInvalidCallback[key] = true; } }; @@ -6209,12 +6292,14 @@ var ReactFiberClassComponent = function( stopPhaseTimer(); { - warning( - shouldUpdate !== undefined, - "%s.shouldComponentUpdate(): Returned undefined instead of a " + - "boolean value. Make sure to return true or false.", - getComponentName(workInProgress) || "Unknown" - ); + !(shouldUpdate !== undefined) + ? warning( + false, + "%s.shouldComponentUpdate(): Returned undefined instead of a " + + "boolean value. Make sure to return true or false.", + getComponentName(workInProgress) || "Component" + ) + : void 0; } return shouldUpdate; @@ -6233,7 +6318,7 @@ var ReactFiberClassComponent = function( var instance = workInProgress.stateNode; var type = workInProgress.type; { - var name = getComponentName(workInProgress); + var name = getComponentName(workInProgress) || "Component"; var renderPresent = instance.render; if (!renderPresent) { @@ -6258,47 +6343,57 @@ var ReactFiberClassComponent = function( !instance.getInitialState || instance.getInitialState.isReactClassApproved || instance.state; - warning( - noGetInitialStateOnES6, - "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 - ); + !noGetInitialStateOnES6 + ? warning( + 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; - warning( - noGetDefaultPropsOnES6, - "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 - ); + !noGetDefaultPropsOnES6 + ? warning( + 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; - warning( - noInstancePropTypes, - "propTypes was defined as an instance property on %s. Use a static " + - "property to define propTypes instead.", - name - ); + !noInstancePropTypes + ? warning( + false, + "propTypes was defined as an instance property on %s. Use a static " + + "property to define propTypes instead.", + name + ) + : void 0; var noInstanceContextTypes = !instance.contextTypes; - warning( - noInstanceContextTypes, - "contextTypes was defined as an instance property on %s. Use a static " + - "property to define contextTypes instead.", - name - ); + !noInstanceContextTypes + ? warning( + false, + "contextTypes was defined as an instance property on %s. Use a static " + + "property to define contextTypes instead.", + name + ) + : void 0; var noComponentShouldUpdate = typeof instance.componentShouldUpdate !== "function"; - warning( - noComponentShouldUpdate, - "%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 - ); + !noComponentShouldUpdate + ? warning( + 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 ( type.prototype && type.prototype.isPureReactComponent && @@ -6314,73 +6409,128 @@ var ReactFiberClassComponent = function( } var noComponentDidUnmount = typeof instance.componentDidUnmount !== "function"; - warning( - noComponentDidUnmount, - "%s has a method called " + - "componentDidUnmount(). But there is no such lifecycle method. " + - "Did you mean componentWillUnmount()?", - name - ); + !noComponentDidUnmount + ? warning( + 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"; - warning( - noComponentDidReceiveProps, - "%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 - ); + !noComponentDidReceiveProps + ? warning( + 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"; - warning( - noComponentWillRecieveProps, - "%s has a method called " + - "componentWillRecieveProps(). Did you mean componentWillReceiveProps()?", - name - ); + !noComponentWillRecieveProps + ? warning( + false, + "%s has a method called " + + "componentWillRecieveProps(). Did you mean componentWillReceiveProps()?", + name + ) + : void 0; var noUnsafeComponentWillRecieveProps = typeof instance.UNSAFE_componentWillRecieveProps !== "function"; - warning( - noUnsafeComponentWillRecieveProps, - "%s has a method called " + - "UNSAFE_componentWillRecieveProps(). Did you mean UNSAFE_componentWillReceiveProps()?", - name - ); + !noUnsafeComponentWillRecieveProps + ? warning( + false, + "%s has a method called " + + "UNSAFE_componentWillRecieveProps(). Did you mean UNSAFE_componentWillReceiveProps()?", + name + ) + : void 0; var hasMutatedProps = instance.props !== workInProgress.pendingProps; - warning( - instance.props === undefined || !hasMutatedProps, - "%s(...): When calling super() in `%s`, make sure to pass " + - "up the same props that your component's constructor was passed.", - name, - name - ); + !(instance.props === undefined || !hasMutatedProps) + ? warning( + 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; - warning( - noInstanceDefaultProps, - "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 - ); - } + !noInstanceDefaultProps + ? warning( + 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; - var state = instance.state; - if (state && (typeof state !== "object" || isArray(state))) { - warning( - false, - "%s.state: must be set to an object or null", - getComponentName(workInProgress) - ); - } - if (typeof instance.getChildContext === "function") { - warning( - typeof type.childContextTypes === "object", - "%s.getChildContext(): childContextTypes must be defined in order to " + - "use getChildContext().", - getComponentName(workInProgress) - ); + if ( + typeof instance.getSnapshotBeforeUpdate === "function" && + typeof instance.componentDidUpdate !== "function" && + typeof instance.componentDidUpdate !== "function" && + !didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.has(type) + ) { + didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.add(type); + warning( + false, + "%s: getSnapshotBeforeUpdate() should be used with componentDidUpdate(). " + + "This component defines getSnapshotBeforeUpdate() only.", + getComponentName(workInProgress) + ); + } + + var noInstanceGetDerivedStateFromProps = + typeof instance.getDerivedStateFromProps !== "function"; + !noInstanceGetDerivedStateFromProps + ? warning( + 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.getDerivedStateFromCatch !== "function"; + !noInstanceGetDerivedStateFromCatch + ? warning( + false, + "%s: getDerivedStateFromCatch() is defined as an instance method " + + "and will be ignored. Instead, declare it as a static method.", + name + ) + : void 0; + var noStaticGetSnapshotBeforeUpdate = + typeof type.getSnapshotBeforeUpdate !== "function"; + !noStaticGetSnapshotBeforeUpdate + ? warning( + 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(_state))) { + warning(false, "%s.state: must be set to an object or null", name); + } + if (typeof instance.getChildContext === "function") { + !(typeof type.childContextTypes === "object") + ? warning( + false, + "%s.getChildContext(): childContextTypes must be defined in order to " + + "use getChildContext().", + name + ) + : void 0; + } } } @@ -6428,8 +6578,9 @@ var ReactFiberClassComponent = function( typeof ctor.getDerivedStateFromProps === "function" && state === null ) { - var componentName = getComponentName(workInProgress) || "Unknown"; - if (!didWarnAboutUninitializedState[componentName]) { + var componentName = getComponentName(workInProgress) || "Component"; + if (!didWarnAboutUninitializedState.has(componentName)) { + didWarnAboutUninitializedState.add(componentName); warning( false, "%s: Did not properly initialize state during construction. " + @@ -6437,7 +6588,75 @@ var ReactFiberClassComponent = function( componentName, instance.state === null ? "null" : "undefined" ); - didWarnAboutUninitializedState[componentName] = true; + } + } + + // 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(workInProgress) || "Component"; + var newApiName = + typeof ctor.getDerivedStateFromProps === "function" + ? "getDerivedStateFromProps()" + : "getSnapshotBeforeUpdate()"; + if ( + !didWarnAboutLegacyLifecyclesAndDerivedState.has(_componentName) + ) { + didWarnAboutLegacyLifecyclesAndDerivedState.add(_componentName); + warning( + 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 : "" + ); + } } } } @@ -6447,7 +6666,8 @@ var ReactFiberClassComponent = function( var partialState = callGetDerivedStateFromProps( workInProgress, instance, - props + props, + state ); if (partialState !== null && partialState !== undefined) { @@ -6490,7 +6710,7 @@ var ReactFiberClassComponent = function( "%s.componentWillMount(): Assigning directly to this.state is " + "deprecated (except inside a component's " + "constructor). Use setState instead.", - getComponentName(workInProgress) + getComponentName(workInProgress) || "Component" ); } updater.enqueueReplaceState(instance, instance.state, null); @@ -6516,7 +6736,8 @@ var ReactFiberClassComponent = function( if (instance.state !== oldState) { { var componentName = getComponentName(workInProgress) || "Component"; - if (!didWarnAboutStateAssignmentForComponent[componentName]) { + if (!didWarnAboutStateAssignmentForComponent.has(componentName)) { + didWarnAboutStateAssignmentForComponent.add(componentName); warning( false, "%s.componentWillReceiveProps(): Assigning directly to " + @@ -6524,69 +6745,47 @@ var ReactFiberClassComponent = function( "constructor). Use setState instead.", componentName ); - didWarnAboutStateAssignmentForComponent[componentName] = true; } } updater.enqueueReplaceState(instance, instance.state, null); } } - function callGetDerivedStateFromProps(workInProgress, instance, props) { + function callGetDerivedStateFromProps( + workInProgress, + instance, + nextProps, + prevState + ) { var type = workInProgress.type; if (typeof type.getDerivedStateFromProps === "function") { - { - // Don't warn about react-lifecycles-compat polyfilled components - if ( - (typeof instance.componentWillReceiveProps === "function" && - instance.componentWillReceiveProps.__suppressDeprecationWarning !== - true) || - typeof instance.UNSAFE_componentWillReceiveProps === "function" - ) { - var componentName = getComponentName(workInProgress) || "Unknown"; - if (!didWarnAboutWillReceivePropsAndDerivedState[componentName]) { - warning( - false, - "%s: Defines both componentWillReceiveProps() and static " + - "getDerivedStateFromProps() methods. We recommend using " + - "only getDerivedStateFromProps().", - componentName - ); - didWarnAboutWillReceivePropsAndDerivedState[componentName] = true; - } - } - } - if ( debugRenderPhaseSideEffects || (debugRenderPhaseSideEffectsForStrictMode && workInProgress.mode & StrictMode) ) { // Invoke method an extra time to help detect side-effects. - type.getDerivedStateFromProps.call( - null, - props, - workInProgress.memoizedState - ); + type.getDerivedStateFromProps.call(null, nextProps, prevState); } var partialState = type.getDerivedStateFromProps.call( null, - props, - workInProgress.memoizedState + nextProps, + prevState ); { if (partialState === undefined) { - var _componentName = getComponentName(workInProgress) || "Unknown"; - if (!didWarnAboutUndefinedDerivedState[_componentName]) { + var componentName = getComponentName(workInProgress) || "Component"; + if (!didWarnAboutUndefinedDerivedState.has(componentName)) { + didWarnAboutUndefinedDerivedState.add(componentName); warning( false, "%s.getDerivedStateFromProps(): A valid state object (or null) must be returned. " + "You have returned undefined.", - _componentName + componentName ); - didWarnAboutUndefinedDerivedState[_componentName] = _componentName; } } } @@ -6630,11 +6829,12 @@ var ReactFiberClassComponent = function( } // In order to support react-lifecycles-compat polyfilled components, - // Unsafe lifecycles should not be invoked for any component with the new gDSFP. + // 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") && - typeof ctor.getDerivedStateFromProps !== "function" + typeof instance.componentWillMount === "function") ) { callComponentWillMount(workInProgress, instance); // If we had additional state updates during this life-cycle, let's @@ -6667,16 +6867,20 @@ var ReactFiberClassComponent = function( var newUnmaskedContext = getUnmaskedContext(workInProgress); var newContext = getMaskedContext(workInProgress, newUnmaskedContext); + var hasNewLifecycles = + typeof ctor.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 any component with the new gDSFP. + // Unsafe lifecycles should not be invoked for components using the new APIs. if ( + !hasNewLifecycles && (typeof instance.UNSAFE_componentWillReceiveProps === "function" || - typeof instance.componentWillReceiveProps === "function") && - typeof ctor.getDerivedStateFromProps !== "function" + typeof instance.componentWillReceiveProps === "function") ) { if (oldProps !== newProps || oldContext !== newContext) { callComponentWillReceiveProps( @@ -6688,15 +6892,6 @@ var ReactFiberClassComponent = function( } } - var derivedStateFromProps = void 0; - if (oldProps !== newProps) { - derivedStateFromProps = callGetDerivedStateFromProps( - workInProgress, - instance, - newProps - ); - } - // Compute the next state using the memoized state and the update queue. var oldState = workInProgress.memoizedState; // TODO: Previous state can be null. @@ -6733,6 +6928,18 @@ var ReactFiberClassComponent = function( newState = oldState; } + var derivedStateFromProps = void 0; + if (oldProps !== newProps) { + // The prevState parameter should be the partially updated state. + // Otherwise, spreading state in return values could override updates. + derivedStateFromProps = callGetDerivedStateFromProps( + workInProgress, + instance, + newProps, + newState + ); + } + if (derivedStateFromProps !== null && derivedStateFromProps !== undefined) { // Render-phase updates (like this) should not be added to the update queue, // So that multiple render passes do not enqueue multiple updates. @@ -6741,6 +6948,17 @@ var ReactFiberClassComponent = function( newState === null || newState === undefined ? derivedStateFromProps : Object.assign({}, newState, derivedStateFromProps); + + // Update the base state of the update queue. + // FIXME: This is getting ridiculous. Refactor plz! + var _updateQueue = workInProgress.updateQueue; + if (_updateQueue !== null) { + _updateQueue.baseState = Object.assign( + {}, + _updateQueue.baseState, + derivedStateFromProps + ); + } } if (derivedStateFromCatch !== null && derivedStateFromCatch !== undefined) { // Render-phase updates (like this) should not be added to the update queue, @@ -6750,6 +6968,17 @@ var ReactFiberClassComponent = function( newState === null || newState === undefined ? derivedStateFromCatch : Object.assign({}, newState, derivedStateFromCatch); + + // Update the base state of the update queue. + // FIXME: This is getting ridiculous. Refactor plz! + var _updateQueue2 = workInProgress.updateQueue; + if (_updateQueue2 !== null) { + _updateQueue2.baseState = Object.assign( + {}, + _updateQueue2.baseState, + derivedStateFromCatch + ); + } } if ( @@ -6780,11 +7009,11 @@ var ReactFiberClassComponent = function( if (shouldUpdate) { // In order to support react-lifecycles-compat polyfilled components, - // Unsafe lifecycles should not be invoked for any component with the new gDSFP. + // Unsafe lifecycles should not be invoked for components using the new APIs. if ( + !hasNewLifecycles && (typeof instance.UNSAFE_componentWillMount === "function" || - typeof instance.componentWillMount === "function") && - typeof ctor.getDerivedStateFromProps !== "function" + typeof instance.componentWillMount === "function") ) { startPhaseTimer(workInProgress, "componentWillMount"); if (typeof instance.componentWillMount === "function") { @@ -6832,16 +7061,20 @@ var ReactFiberClassComponent = function( var newUnmaskedContext = getUnmaskedContext(workInProgress); var newContext = getMaskedContext(workInProgress, newUnmaskedContext); + var hasNewLifecycles = + typeof ctor.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 any component with the new gDSFP. + // Unsafe lifecycles should not be invoked for components using the new APIs. if ( + !hasNewLifecycles && (typeof instance.UNSAFE_componentWillReceiveProps === "function" || - typeof instance.componentWillReceiveProps === "function") && - typeof ctor.getDerivedStateFromProps !== "function" + typeof instance.componentWillReceiveProps === "function") ) { if (oldProps !== newProps || oldContext !== newContext) { callComponentWillReceiveProps( @@ -6853,20 +7086,12 @@ var ReactFiberClassComponent = function( } } - var derivedStateFromProps = void 0; - if (oldProps !== newProps) { - derivedStateFromProps = callGetDerivedStateFromProps( - workInProgress, - instance, - newProps - ); - } - // Compute the next state using the memoized state and the update queue. var oldState = workInProgress.memoizedState; // TODO: Previous state can be null. var newState = void 0; var derivedStateFromCatch = void 0; + if (workInProgress.updateQueue !== null) { newState = processUpdateQueue( current, @@ -6898,6 +7123,18 @@ var ReactFiberClassComponent = function( newState = oldState; } + var derivedStateFromProps = void 0; + if (oldProps !== newProps) { + // The prevState parameter should be the partially updated state. + // Otherwise, spreading state in return values could override updates. + derivedStateFromProps = callGetDerivedStateFromProps( + workInProgress, + instance, + newProps, + newState + ); + } + if (derivedStateFromProps !== null && derivedStateFromProps !== undefined) { // Render-phase updates (like this) should not be added to the update queue, // So that multiple render passes do not enqueue multiple updates. @@ -6906,6 +7143,17 @@ var ReactFiberClassComponent = function( newState === null || newState === undefined ? derivedStateFromProps : Object.assign({}, newState, derivedStateFromProps); + + // Update the base state of the update queue. + // FIXME: This is getting ridiculous. Refactor plz! + var _updateQueue3 = workInProgress.updateQueue; + if (_updateQueue3 !== null) { + _updateQueue3.baseState = Object.assign( + {}, + _updateQueue3.baseState, + derivedStateFromProps + ); + } } if (derivedStateFromCatch !== null && derivedStateFromCatch !== undefined) { // Render-phase updates (like this) should not be added to the update queue, @@ -6915,6 +7163,17 @@ var ReactFiberClassComponent = function( newState === null || newState === undefined ? derivedStateFromCatch : Object.assign({}, newState, derivedStateFromCatch); + + // Update the base state of the update queue. + // FIXME: This is getting ridiculous. Refactor plz! + var _updateQueue4 = workInProgress.updateQueue; + if (_updateQueue4 !== null) { + _updateQueue4.baseState = Object.assign( + {}, + _updateQueue4.baseState, + derivedStateFromCatch + ); + } } if ( @@ -6936,6 +7195,14 @@ var ReactFiberClassComponent = function( workInProgress.effectTag |= Update; } } + if (typeof instance.getSnapshotBeforeUpdate === "function") { + if ( + oldProps !== current.memoizedProps || + oldState !== current.memoizedState + ) { + workInProgress.effectTag |= Snapshot; + } + } return false; } @@ -6950,11 +7217,11 @@ var ReactFiberClassComponent = function( if (shouldUpdate) { // In order to support react-lifecycles-compat polyfilled components, - // Unsafe lifecycles should not be invoked for any component with the new gDSFP. + // Unsafe lifecycles should not be invoked for components using the new APIs. if ( + !hasNewLifecycles && (typeof instance.UNSAFE_componentWillUpdate === "function" || - typeof instance.componentWillUpdate === "function") && - typeof ctor.getDerivedStateFromProps !== "function" + typeof instance.componentWillUpdate === "function") ) { startPhaseTimer(workInProgress, "componentWillUpdate"); if (typeof instance.componentWillUpdate === "function") { @@ -6968,6 +7235,9 @@ var ReactFiberClassComponent = function( 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. @@ -6979,6 +7249,14 @@ var ReactFiberClassComponent = function( 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. @@ -7818,13 +8096,15 @@ function ChildReconciler(shouldTrackSideEffects) { if (typeof newChildrenIterable.entries === "function") { var possibleMap = newChildrenIterable; if (possibleMap.entries === iteratorFn) { - warning( - didWarnAboutMaps, - "Using Maps as children is unsupported and will likely yield " + - "unexpected results. Convert it to a sequence/iterable of keyed " + - "ReactElements instead.%s", - getCurrentFiberStackAddendum$1() - ); + !didWarnAboutMaps + ? warning( + false, + "Using Maps as children is unsupported and will likely yield " + + "unexpected results. Convert it to a sequence/iterable of keyed " + + "ReactElements instead.%s", + getCurrentFiberStackAddendum$1() + ) + : void 0; didWarnAboutMaps = true; } } @@ -8790,7 +9070,8 @@ var ReactFiberBeginWork = function( var partialState = callGetDerivedStateFromProps( workInProgress, value, - props + props, + workInProgress.memoizedState ); if (partialState !== null && partialState !== undefined) { @@ -8823,11 +9104,13 @@ var ReactFiberBeginWork = function( var _Component = workInProgress.type; if (_Component) { - warning( - !_Component.childContextTypes, - "%s(...): childContextTypes cannot be defined on a functional component.", - _Component.displayName || _Component.name || "Component" - ); + !!_Component.childContextTypes + ? warning( + false, + "%s(...): childContextTypes cannot be defined on a functional component.", + _Component.displayName || _Component.name || "Component" + ) + : void 0; } if (workInProgress.ref !== null) { var info = ""; @@ -9046,7 +9329,7 @@ var ReactFiberBeginWork = function( renderExpirationTime ) { var providerType = workInProgress.type; - var context = providerType.context; + var context = providerType._context; var newProps = workInProgress.pendingProps; var oldProps = workInProgress.memoizedProps; @@ -9099,12 +9382,14 @@ var ReactFiberBeginWork = function( ? context._calculateChangedBits(oldValue, newValue) : MAX_SIGNED_31_BIT_INT; { - warning( - (changedBits & MAX_SIGNED_31_BIT_INT) === changedBits, - "calculateChangedBits: Expected the return value to be a " + - "31-bit integer. Instead received: %s", - changedBits - ); + !((changedBits & MAX_SIGNED_31_BIT_INT) === changedBits) + ? warning( + false, + "calculateChangedBits: Expected the return value to be a " + + "31-bit integer. Instead received: %s", + changedBits + ) + : void 0; } changedBits |= 0; @@ -9172,21 +9457,23 @@ var ReactFiberBeginWork = function( changedBits, renderExpirationTime ); - } else if (oldProps !== null && oldProps.children === newProps.children) { - // No change. Bailout early if children are the same. - return bailoutOnAlreadyFinishedWork(current, workInProgress); } + // There is no bailout on `children` equality because we expect people + // to often pass a bound method as a child, but it may reference + // `this.state` or `this.props` (and thus needs to re-render on `setState`). var render = newProps.children; { - warning( - typeof render === "function", - "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." - ); + !(typeof render === "function") + ? warning( + 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; } var newChildren = render(newValue); @@ -10175,6 +10462,11 @@ var invokeGuardedCallback$3 = ReactErrorUtils.invokeGuardedCallback; var hasCaughtError$1 = ReactErrorUtils.hasCaughtError; var clearCaughtError$1 = ReactErrorUtils.clearCaughtError; +var didWarnAboutUndefinedSnapshotBeforeUpdate = null; +{ + didWarnAboutUndefinedSnapshotBeforeUpdate = new Set(); +} + function logError(boundary, errorInfo) { var source = errorInfo.source; var stack = errorInfo.stack; @@ -10184,21 +10476,19 @@ function logError(boundary, errorInfo) { var capturedError = { componentName: source !== null ? getComponentName(source) : null, - error: errorInfo.value, - errorBoundary: boundary, componentStack: stack !== null ? stack : "", + error: errorInfo.value, + errorBoundary: null, errorBoundaryName: null, errorBoundaryFound: false, willRetry: false }; - if (boundary !== null) { + if (boundary !== null && boundary.tag === ClassComponent) { + capturedError.errorBoundary = boundary.stateNode; capturedError.errorBoundaryName = getComponentName(boundary); - capturedError.errorBoundaryFound = capturedError.willRetry = - boundary.tag === ClassComponent; - } else { - capturedError.errorBoundaryName = null; - capturedError.errorBoundaryFound = capturedError.willRetry = false; + capturedError.errorBoundaryFound = true; + capturedError.willRetry = true; } try { @@ -10267,6 +10557,58 @@ var ReactFiberCommitWork = function( } } + function commitBeforeMutationLifeCycles(current, finishedWork) { + switch (finishedWork.tag) { + case ClassComponent: { + if (finishedWork.effectTag & Snapshot) { + if (current !== null) { + var prevProps = current.memoizedProps; + var prevState = current.memoizedState; + startPhaseTimer(finishedWork, "getSnapshotBeforeUpdate"); + var _instance = finishedWork.stateNode; + _instance.props = finishedWork.memoizedProps; + _instance.state = finishedWork.memoizedState; + var snapshot = _instance.getSnapshotBeforeUpdate( + prevProps, + prevState + ); + { + var didWarnSet = didWarnAboutUndefinedSnapshotBeforeUpdate; + if ( + snapshot === undefined && + !didWarnSet.has(finishedWork.type) + ) { + didWarnSet.add(finishedWork.type); + warning( + false, + "%s.getSnapshotBeforeUpdate(): A snapshot value (or null) " + + "must be returned. You have returned undefined.", + getComponentName(finishedWork) + ); + } + } + _instance.__reactInternalSnapshotBeforeUpdate = snapshot; + stopPhaseTimer(); + } + } + return; + } + case HostRoot: + case HostComponent: + case HostText: + case HostPortal: + // Nothing to do for these component types + return; + default: { + invariant( + false, + "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 commitLifeCycles( finishedRoot, current, @@ -10276,50 +10618,54 @@ var ReactFiberCommitWork = function( ) { switch (finishedWork.tag) { case ClassComponent: { - var _instance = finishedWork.stateNode; + var _instance2 = finishedWork.stateNode; if (finishedWork.effectTag & Update) { if (current === null) { startPhaseTimer(finishedWork, "componentDidMount"); - _instance.props = finishedWork.memoizedProps; - _instance.state = finishedWork.memoizedState; - _instance.componentDidMount(); + _instance2.props = finishedWork.memoizedProps; + _instance2.state = finishedWork.memoizedState; + _instance2.componentDidMount(); stopPhaseTimer(); } else { var prevProps = current.memoizedProps; var prevState = current.memoizedState; startPhaseTimer(finishedWork, "componentDidUpdate"); - _instance.props = finishedWork.memoizedProps; - _instance.state = finishedWork.memoizedState; - _instance.componentDidUpdate(prevProps, prevState); + _instance2.props = finishedWork.memoizedProps; + _instance2.state = finishedWork.memoizedState; + _instance2.componentDidUpdate( + prevProps, + prevState, + _instance2.__reactInternalSnapshotBeforeUpdate + ); stopPhaseTimer(); } } var updateQueue = finishedWork.updateQueue; if (updateQueue !== null) { - commitCallbacks(updateQueue, _instance); + commitCallbacks(updateQueue, _instance2); } return; } case HostRoot: { var _updateQueue = finishedWork.updateQueue; if (_updateQueue !== null) { - var _instance2 = null; + var _instance3 = null; if (finishedWork.child !== null) { switch (finishedWork.child.tag) { case HostComponent: - _instance2 = getPublicInstance(finishedWork.child.stateNode); + _instance3 = getPublicInstance(finishedWork.child.stateNode); break; case ClassComponent: - _instance2 = finishedWork.child.stateNode; + _instance3 = finishedWork.child.stateNode; break; } } - commitCallbacks(_updateQueue, _instance2); + commitCallbacks(_updateQueue, _instance3); } return; } case HostComponent: { - var _instance3 = finishedWork.stateNode; + var _instance4 = 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). @@ -10328,7 +10674,7 @@ var ReactFiberCommitWork = function( if (current === null && finishedWork.effectTag & Update) { var type = finishedWork.type; var props = finishedWork.memoizedProps; - commitMount(_instance3, type, props, finishedWork); + commitMount(_instance4, type, props, finishedWork); } return; @@ -10356,7 +10702,7 @@ var ReactFiberCommitWork = function( case ClassComponent: { var ctor = finishedWork.type; - var _instance4 = finishedWork.stateNode; + var _instance5 = finishedWork.stateNode; var updateQueue = finishedWork.updateQueue; invariant( updateQueue !== null && updateQueue.capturedValues !== null, @@ -10373,16 +10719,19 @@ var ReactFiberCommitWork = function( // This gets reset before we yield back to the browser. // TODO: Warn in strict mode if getDerivedStateFromCatch is // not defined. - markLegacyErrorBoundaryAsFailed(_instance4); + markLegacyErrorBoundaryAsFailed(_instance5); } - _instance4.props = finishedWork.memoizedProps; - _instance4.state = finishedWork.memoizedState; + _instance5.props = finishedWork.memoizedProps; + _instance5.state = finishedWork.memoizedState; for (var i = 0; i < capturedErrors.length; i++) { var errorInfo = capturedErrors[i]; var _error = errorInfo.value; + var stack = errorInfo.stack; logError(finishedWork, errorInfo); - _instance4.componentDidCatch(_error); + _instance5.componentDidCatch(_error, { + componentStack: stack !== null ? stack : "" + }); } } break; @@ -10415,14 +10764,14 @@ var ReactFiberCommitWork = function( function commitAttachRef(finishedWork) { var ref = finishedWork.ref; if (ref !== null) { - var _instance5 = finishedWork.stateNode; + var _instance6 = finishedWork.stateNode; var instanceToUse = void 0; switch (finishedWork.tag) { case HostComponent: - instanceToUse = getPublicInstance(_instance5); + instanceToUse = getPublicInstance(_instance6); break; default: - instanceToUse = _instance5; + instanceToUse = _instance6; } if (typeof ref === "function") { ref(instanceToUse); @@ -10466,9 +10815,9 @@ var ReactFiberCommitWork = function( switch (current.tag) { case ClassComponent: { safelyDetachRef(current); - var _instance6 = current.stateNode; - if (typeof _instance6.componentWillUnmount === "function") { - safelyCallComponentWillUnmount(current, _instance6); + var _instance7 = current.stateNode; + if (typeof _instance7.componentWillUnmount === "function") { + safelyCallComponentWillUnmount(current, _instance7); } return; } @@ -10605,6 +10954,7 @@ var ReactFiberCommitWork = function( }, commitLifeCycles: commitLifeCycles, + commitBeforeMutationLifeCycles: commitBeforeMutationLifeCycles, commitErrorLogging: commitErrorLogging, commitAttachRef: commitAttachRef, commitDetachRef: commitDetachRef @@ -10863,8 +11213,8 @@ var ReactFiberCommitWork = function( return; } case HostComponent: { - var _instance7 = finishedWork.stateNode; - if (_instance7 != null) { + var _instance8 = finishedWork.stateNode; + if (_instance8 != null) { // Commit the work prepared earlier. var newProps = finishedWork.memoizedProps; // For hydration we reuse the update path but we treat the oldProps @@ -10877,7 +11227,7 @@ var ReactFiberCommitWork = function( finishedWork.updateQueue = null; if (updatePayload !== null) { commitUpdate( - _instance7, + _instance8, updatePayload, type, oldProps, @@ -10922,6 +11272,7 @@ var ReactFiberCommitWork = function( if (enableMutatingReconciler) { return { + commitBeforeMutationLifeCycles: commitBeforeMutationLifeCycles, commitResetTextContent: commitResetTextContent, commitPlacement: commitPlacement, commitDeletion: commitDeletion, @@ -10967,12 +11318,19 @@ var ReactFiberHostContext = function(config, stack) { // Push current root instance onto the stack; // This allows us to reset root when portals are popped. push(rootInstanceStackCursor, nextRootInstance, fiber); - - var nextRootContext = getRootHostContext(nextRootInstance); - // 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, NO_CONTEXT, fiber); + var nextRootContext = getRootHostContext(nextRootInstance); + // Now that we know this function doesn't throw, replace it. + pop(contextStackCursor, fiber); push(contextStackCursor, nextRootContext, fiber); } @@ -11683,7 +12041,7 @@ var ReactFiberNewContext = function(stack) { } function pushProvider(providerFiber) { - var context = providerFiber.type.context; + var context = providerFiber.type._context; push(changedBitsCursor, context._changedBits, providerFiber); push(valueCursor, context._currentValue, providerFiber); @@ -11693,12 +12051,16 @@ var ReactFiberNewContext = function(stack) { context._changedBits = providerFiber.stateNode; { - warning( + !( context._currentRenderer === null || - context._currentRenderer === rendererSigil, - "Detected multiple renderers concurrently rendering the " + - "same context provider. This is currently unsupported." - ); + context._currentRenderer === rendererSigil + ) + ? warning( + false, + "Detected multiple renderers concurrently rendering the " + + "same context provider. This is currently unsupported." + ) + : void 0; context._currentRenderer = rendererSigil; } } @@ -11711,7 +12073,7 @@ var ReactFiberNewContext = function(stack) { pop(valueCursor, providerFiber); pop(changedBitsCursor, providerFiber); - var context = providerFiber.type.context; + var context = providerFiber.type._context; context._currentValue = currentValue; context._changedBits = changedBits; } @@ -11824,17 +12186,19 @@ var warnAboutInvalidUpdates = void 0; var didWarnStateUpdateForUnmountedComponent = {}; warnAboutUpdateOnUnmounted = function(fiber) { + // 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) || "ReactClass"; if (didWarnStateUpdateForUnmountedComponent[componentName]) { return; } warning( false, - "Can only update a mounted or mounting " + - "component. This usually means you called setState, replaceState, " + - "or forceUpdate on an unmounted component. This is a no-op.\n\nPlease " + - "check the code for the %s component.", - componentName + "Can't call setState (or forceUpdate) 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 the " + + "componentWillUnmount method.%s", + getStackAddendumByWorkInProgressFiber(fiber) ); didWarnStateUpdateForUnmountedComponent[componentName] = true; }; @@ -11920,6 +12284,8 @@ var ReactFiberScheduler = function(config) { markLegacyErrorBoundaryAsFailed, recalculateCurrentTime ), + commitBeforeMutationLifeCycles = + _ReactFiberCommitWork.commitBeforeMutationLifeCycles, commitResetTextContent = _ReactFiberCommitWork.commitResetTextContent, commitPlacement = _ReactFiberCommitWork.commitPlacement, commitDeletion = _ReactFiberCommitWork.commitDeletion, @@ -11971,11 +12337,19 @@ var ReactFiberScheduler = function(config) { var stashedWorkInProgressProperties = void 0; var replayUnitOfWork = void 0; + var isReplayingFailedUnitOfWork = void 0; + var originalReplayError = void 0; + var rethrowOriginalError = void 0; if (true && replayFailedUnitOfWorkWithInvokeGuardedCallback) { stashedWorkInProgressProperties = null; - replayUnitOfWork = function(failedUnitOfWork, isAsync) { - // Retore the original state of the work-in-progress - Object.assign(failedUnitOfWork, stashedWorkInProgressProperties); + isReplayingFailedUnitOfWork = false; + originalReplayError = null; + replayUnitOfWork = function(failedUnitOfWork, error, isAsync) { + // Restore the original state of the work-in-progress + assignFiberPropertiesInDEV( + failedUnitOfWork, + stashedWorkInProgressProperties + ); switch (failedUnitOfWork.tag) { case HostRoot: popHostContainer(failedUnitOfWork); @@ -11995,14 +12369,22 @@ var ReactFiberScheduler = function(config) { break; } // Replay the begin phase. + isReplayingFailedUnitOfWork = true; + originalReplayError = error; invokeGuardedCallback$2(null, workLoop, null, isAsync); + isReplayingFailedUnitOfWork = false; + originalReplayError = null; if (hasCaughtError()) { clearCaughtError(); } else { - // This should be unreachable because the render phase is - // idempotent + // If the begin phase did not fail the second time, set this pointer + // back to the original value. + nextUnitOfWork = failedUnitOfWork; } }; + rethrowOriginalError = function() { + throw originalReplayError; + }; } function resetStack() { @@ -12034,6 +12416,7 @@ var ReactFiberScheduler = function(config) { recordEffect(); var effectTag = nextEffect.effectTag; + if (effectTag & ContentReset) { commitResetTextContent(nextEffect); } @@ -12091,6 +12474,22 @@ var ReactFiberScheduler = function(config) { } } + function commitBeforeMutationLifecycles() { + while (nextEffect !== null) { + var effectTag = nextEffect.effectTag; + + if (effectTag & Snapshot) { + recordEffect(); + var current = nextEffect.alternate; + commitBeforeMutationLifeCycles(current, nextEffect); + } + + // Don't cleanup effects yet; + // This will be done by commitAllLifeCycles() + nextEffect = nextEffect.nextEffect; + } + } + function commitAllLifeCycles( finishedRoot, currentTime, @@ -12198,16 +12597,14 @@ var ReactFiberScheduler = function(config) { prepareForCommit(root.containerInfo); - // Commit all the side-effects within a tree. We'll do this in two passes. - // The first pass performs all the host insertions, updates, deletions and - // ref unmounts. + // Invoke instances of getSnapshotBeforeUpdate before mutation. nextEffect = firstEffect; - startCommitHostEffectsTimer(); + startCommitSnapshotEffectsTimer(); while (nextEffect !== null) { var didError = false; var error = void 0; { - invokeGuardedCallback$2(null, commitAllHostEffects, null); + invokeGuardedCallback$2(null, commitBeforeMutationLifecycles, null); if (hasCaughtError()) { didError = true; error = clearCaughtError(); @@ -12226,6 +12623,36 @@ var ReactFiberScheduler = function(config) { } } } + stopCommitSnapshotEffectsTimer(); + + // Commit all the side-effects within a tree. We'll do this in two passes. + // The first pass performs all the host insertions, updates, deletions and + // ref unmounts. + nextEffect = firstEffect; + startCommitHostEffectsTimer(); + while (nextEffect !== null) { + var _didError = false; + var _error = void 0; + { + invokeGuardedCallback$2(null, commitAllHostEffects, null); + if (hasCaughtError()) { + _didError = true; + _error = clearCaughtError(); + } + } + if (_didError) { + invariant( + nextEffect !== null, + "Should have next effect. This error is likely caused by a bug " + + "in React. Please file an issue." + ); + onCommitPhaseError(nextEffect, _error); + // Clean-up + if (nextEffect !== null) { + nextEffect = nextEffect.nextEffect; + } + } + } stopCommitHostEffectsTimer(); resetAfterCommit(root.containerInfo); @@ -12243,8 +12670,8 @@ var ReactFiberScheduler = function(config) { nextEffect = firstEffect; startCommitLifeCyclesTimer(); while (nextEffect !== null) { - var _didError = false; - var _error = void 0; + var _didError2 = false; + var _error2 = void 0; { invokeGuardedCallback$2( null, @@ -12255,17 +12682,17 @@ var ReactFiberScheduler = function(config) { committedExpirationTime ); if (hasCaughtError()) { - _didError = true; - _error = clearCaughtError(); + _didError2 = true; + _error2 = clearCaughtError(); } } - if (_didError) { + if (_didError2) { invariant( nextEffect !== null, "Should have next effect. This error is likely caused by a bug " + "in React. Please file an issue." ); - onCommitPhaseError(nextEffect, _error); + onCommitPhaseError(nextEffect, _error2); if (nextEffect !== null) { nextEffect = nextEffect.nextEffect; } @@ -12489,12 +12916,21 @@ var ReactFiberScheduler = function(config) { } if (true && replayFailedUnitOfWorkWithInvokeGuardedCallback) { - stashedWorkInProgressProperties = Object.assign({}, workInProgress); + stashedWorkInProgressProperties = assignFiberPropertiesInDEV( + stashedWorkInProgressProperties, + workInProgress + ); } var next = beginWork(current, workInProgress, nextRenderExpirationTime); - { ReactDebugCurrentFiber.resetCurrentFiber(); + if (isReplayingFailedUnitOfWork) { + // Currently replaying a failed unit of work. This should be unreachable, + // because the render phase is meant to be idempotent, and it should + // have thrown again. Since it didn't, rethrow the original error, so + // React's internal stack is not misaligned. + rethrowOriginalError(); + } } if (true && ReactFiberInstrumentation_1.debugTool) { ReactFiberInstrumentation_1.debugTool.onBeginWork(workInProgress); @@ -12568,13 +13004,18 @@ var ReactFiberScheduler = function(config) { if (true && replayFailedUnitOfWorkWithInvokeGuardedCallback) { var failedUnitOfWork = nextUnitOfWork; - replayUnitOfWork(failedUnitOfWork, isAsync); + replayUnitOfWork(failedUnitOfWork, thrownValue, isAsync); } var sourceFiber = nextUnitOfWork; var returnFiber = sourceFiber["return"]; if (returnFiber === null) { - // This is a fatal error. + // This is the root. The root could capture its own errors. However, + // we don't know if it errors before or after we pushed the host + // context. This information is needed to avoid a stack mismatch. + // Because we're not sure, treat this as a fatal error. We could track + // which phase it fails in, but doesn't seem worth it. At least + // for now. didFatal = true; onUncaughtError(thrownValue); break; @@ -12586,12 +13027,13 @@ var ReactFiberScheduler = function(config) { } while (true); // We're done performing work. Time to clean up. - stopWorkLoopTimer(interruptedBy); - interruptedBy = null; + var didCompleteRoot = false; isWorking = false; // Yield back to main thread. if (didFatal) { + stopWorkLoopTimer(interruptedBy, didCompleteRoot); + interruptedBy = null; // There was a fatal error. { stack.resetStackAfterFatalErrorInDev(); @@ -12600,12 +13042,17 @@ var ReactFiberScheduler = function(config) { } else if (nextUnitOfWork === null) { // We reached the root. if (isRootReadyForCommit) { + didCompleteRoot = true; + stopWorkLoopTimer(interruptedBy, didCompleteRoot); + interruptedBy = null; // The root successfully completed. It's ready for commit. root.pendingCommitExpirationTime = expirationTime; var finishedWork = root.current.alternate; return finishedWork; } else { // The root did not complete. + stopWorkLoopTimer(interruptedBy, didCompleteRoot); + interruptedBy = null; invariant( false, "Expired work should have completed. This error is likely caused " + @@ -12613,6 +13060,8 @@ var ReactFiberScheduler = function(config) { ); } } else { + stopWorkLoopTimer(interruptedBy, didCompleteRoot); + interruptedBy = null; // There's more work to do, but we ran out of time. Yield back to // the renderer. return null; @@ -12798,7 +13247,15 @@ var ReactFiberScheduler = function(config) { interruptedBy = fiber; resetStack(); } - if (nextRoot !== root || !isWorking) { + if ( + // If we're in the render phase, we don't need to schedule this root + // for an update, because we'll do it before we exit... + !isWorking || + isCommitting || + // ...unless this is a different root than the one we're rendering. + nextRoot !== root + ) { + // Add this root to the root schedule. requestWork(root, expirationTime); } if (nestedUpdateCount > NESTED_UPDATE_LIMIT) { @@ -13058,7 +13515,8 @@ var ReactFiberScheduler = function(config) { if (enableUserTimingAPI && deadline !== null) { var didExpire = nextFlushedExpirationTime < recalculateCurrentTime(); - stopRequestCallbackTimer(didExpire); + var timeout = expirationTimeToMs(nextFlushedExpirationTime); + stopRequestCallbackTimer(didExpire, timeout); } if (isAsync) { @@ -13118,7 +13576,11 @@ var ReactFiberScheduler = function(config) { // Perform work on root as if the given expiration time is the current time. // This has the effect of synchronously flushing all work up to and // including the given time. + nextFlushedRoot = root; + nextFlushedExpirationTime = expirationTime; performWorkOnRoot(root, expirationTime, false); + // Flush any sync work that was scheduled by lifecycles + performSyncWork(); finishRendering(); } @@ -13445,12 +13907,14 @@ var ReactFiberReconciler$1 = function(config) { callback = callback === undefined ? null : callback; { - warning( - callback === null || typeof callback === "function", - "render(...): Expected the last optional `callback` argument to be a " + - "function. Instead received: %s.", - callback - ); + !(callback === null || typeof callback === "function") + ? warning( + false, + "render(...): Expected the last optional `callback` argument to be a " + + "function. Instead received: %s.", + callback + ) + : void 0; } var update = { @@ -13772,7 +14236,8 @@ var frameDeadline = 0; var frameDeadlineObject = { timeRemaining: function() { return frameDeadline - now(); - } + }, + didTimeout: false }; function setTimeoutCallback() { diff --git a/Libraries/Renderer/ReactNativeRenderer-prod.js b/Libraries/Renderer/ReactNativeRenderer-prod.js index f11aa6c82da4b1..055ddd7bb0c161 100644 --- a/Libraries/Renderer/ReactNativeRenderer-prod.js +++ b/Libraries/Renderer/ReactNativeRenderer-prod.js @@ -2246,23 +2246,20 @@ function ReactFiberClassComponent( instance.state !== workInProgress && updater.enqueueReplaceState(instance, instance.state, null); } - function callGetDerivedStateFromProps(workInProgress, instance, props) { + function callGetDerivedStateFromProps( + workInProgress, + instance, + nextProps, + prevState + ) { instance = workInProgress.type; if ("function" === typeof instance.getDerivedStateFromProps) return ( (debugRenderPhaseSideEffects || (debugRenderPhaseSideEffectsForStrictMode && workInProgress.mode & 2)) && - instance.getDerivedStateFromProps.call( - null, - props, - workInProgress.memoizedState - ), - instance.getDerivedStateFromProps.call( - null, - props, - workInProgress.memoizedState - ) + instance.getDerivedStateFromProps.call(null, nextProps, prevState), + instance.getDerivedStateFromProps.call(null, nextProps, prevState) ); } var cacheContext = legacyContext.cacheContext, @@ -2337,7 +2334,7 @@ function ReactFiberClassComponent( null !== ctor.state && void 0 !== ctor.state ? ctor.state : null; adoptClassInstance(workInProgress, ctor); workInProgress.memoizedState = state; - props = callGetDerivedStateFromProps(workInProgress, ctor, props); + props = callGetDerivedStateFromProps(workInProgress, ctor, props, state); null !== props && void 0 !== props && (workInProgress.memoizedState = Object.assign( @@ -2358,9 +2355,10 @@ function ReactFiberClassComponent( instance.state = workInProgress.memoizedState; instance.refs = emptyObject; instance.context = getMaskedContext(workInProgress, unmaskedContext); - ("function" !== typeof instance.UNSAFE_componentWillMount && - "function" !== typeof instance.componentWillMount) || - "function" === typeof ctor.getDerivedStateFromProps || + "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(), @@ -2391,9 +2389,12 @@ function ReactFiberClassComponent( oldContext = instance.context, newUnmaskedContext = getUnmaskedContext(workInProgress); newUnmaskedContext = getMaskedContext(workInProgress, newUnmaskedContext); - ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && - "function" !== typeof instance.componentWillReceiveProps) || + var hasNewLifecycles = "function" === typeof ctor.getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate; + hasNewLifecycles || + ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && + "function" !== typeof instance.componentWillReceiveProps) || ((oldProps !== newProps || oldContext !== newUnmaskedContext) && callComponentWillReceiveProps( workInProgress, @@ -2401,15 +2402,8 @@ function ReactFiberClassComponent( newProps, newUnmaskedContext )); - oldContext = void 0; - oldProps !== newProps && - (oldContext = callGetDerivedStateFromProps( - workInProgress, - instance, - newProps - )); - var oldState = workInProgress.memoizedState, - derivedStateFromCatch = void 0; + oldContext = workInProgress.memoizedState; + var derivedStateFromCatch = void 0; if (null !== workInProgress.updateQueue) { renderExpirationTime = processUpdateQueue( null, @@ -2428,23 +2422,45 @@ function ReactFiberClassComponent( ctor, updateQueue.capturedValues )); - } else renderExpirationTime = oldState; - null !== oldContext && - void 0 !== oldContext && - (renderExpirationTime = + } else renderExpirationTime = oldContext; + ctor = void 0; + oldProps !== newProps && + (ctor = callGetDerivedStateFromProps( + workInProgress, + instance, + newProps, + renderExpirationTime + )); + null !== ctor && + void 0 !== ctor && + ((renderExpirationTime = null === renderExpirationTime || void 0 === renderExpirationTime - ? oldContext - : Object.assign({}, renderExpirationTime, oldContext)); + ? ctor + : Object.assign({}, renderExpirationTime, ctor)), + (updateQueue = workInProgress.updateQueue), + null !== updateQueue && + (updateQueue.baseState = Object.assign( + {}, + updateQueue.baseState, + ctor + ))); null !== derivedStateFromCatch && void 0 !== derivedStateFromCatch && - (renderExpirationTime = + ((renderExpirationTime = null === renderExpirationTime || void 0 === renderExpirationTime ? derivedStateFromCatch - : Object.assign({}, renderExpirationTime, derivedStateFromCatch)); + : Object.assign({}, renderExpirationTime, derivedStateFromCatch)), + (ctor = workInProgress.updateQueue), + null !== ctor && + (ctor.baseState = Object.assign( + {}, + ctor.baseState, + derivedStateFromCatch + ))); if ( !( oldProps !== newProps || - oldState !== renderExpirationTime || + oldContext !== renderExpirationTime || hasContextChanged() || (null !== workInProgress.updateQueue && workInProgress.updateQueue.hasForceUpdate) @@ -2459,13 +2475,13 @@ function ReactFiberClassComponent( workInProgress, oldProps, newProps, - oldState, + oldContext, renderExpirationTime, newUnmaskedContext )) - ? (("function" !== typeof instance.UNSAFE_componentWillMount && - "function" !== typeof instance.componentWillMount) || - "function" === typeof ctor.getDerivedStateFromProps || + ? (hasNewLifecycles || + ("function" !== typeof instance.UNSAFE_componentWillMount && + "function" !== typeof instance.componentWillMount) || ("function" === typeof instance.componentWillMount && instance.componentWillMount(), "function" === typeof instance.UNSAFE_componentWillMount && @@ -2495,9 +2511,12 @@ function ReactFiberClassComponent( oldContext = instance.context, newUnmaskedContext = getUnmaskedContext(workInProgress); newUnmaskedContext = getMaskedContext(workInProgress, newUnmaskedContext); - ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && - "function" !== typeof instance.componentWillReceiveProps) || + var hasNewLifecycles = "function" === typeof ctor.getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate; + hasNewLifecycles || + ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && + "function" !== typeof instance.componentWillReceiveProps) || ((oldProps !== newProps || oldContext !== newUnmaskedContext) && callComponentWillReceiveProps( workInProgress, @@ -2505,13 +2524,6 @@ function ReactFiberClassComponent( newProps, newUnmaskedContext )); - var derivedStateFromProps = void 0; - oldProps !== newProps && - (derivedStateFromProps = callGetDerivedStateFromProps( - workInProgress, - instance, - newProps - )); oldContext = workInProgress.memoizedState; var derivedStateFromCatch = void 0; if (null !== workInProgress.updateQueue) { @@ -2533,18 +2545,40 @@ function ReactFiberClassComponent( updateQueue.capturedValues )); } else renderExpirationTime = oldContext; - null !== derivedStateFromProps && - void 0 !== derivedStateFromProps && - (renderExpirationTime = + ctor = void 0; + oldProps !== newProps && + (ctor = callGetDerivedStateFromProps( + workInProgress, + instance, + newProps, + renderExpirationTime + )); + null !== ctor && + void 0 !== ctor && + ((renderExpirationTime = null === renderExpirationTime || void 0 === renderExpirationTime - ? derivedStateFromProps - : Object.assign({}, renderExpirationTime, derivedStateFromProps)); + ? ctor + : Object.assign({}, renderExpirationTime, ctor)), + (updateQueue = workInProgress.updateQueue), + null !== updateQueue && + (updateQueue.baseState = Object.assign( + {}, + updateQueue.baseState, + ctor + ))); null !== derivedStateFromCatch && void 0 !== derivedStateFromCatch && - (renderExpirationTime = + ((renderExpirationTime = null === renderExpirationTime || void 0 === renderExpirationTime ? derivedStateFromCatch - : Object.assign({}, renderExpirationTime, derivedStateFromCatch)); + : Object.assign({}, renderExpirationTime, derivedStateFromCatch)), + (ctor = workInProgress.updateQueue), + null !== ctor && + (ctor.baseState = Object.assign( + {}, + ctor.baseState, + derivedStateFromCatch + ))); if ( !( oldProps !== newProps || @@ -2559,9 +2593,13 @@ function ReactFiberClassComponent( (oldProps === current.memoizedProps && oldContext === current.memoizedState) || (workInProgress.effectTag |= 4), + "function" !== typeof instance.getSnapshotBeforeUpdate || + (oldProps === current.memoizedProps && + oldContext === current.memoizedState) || + (workInProgress.effectTag |= 2048), !1 ); - (derivedStateFromProps = checkShouldComponentUpdate( + (derivedStateFromCatch = checkShouldComponentUpdate( workInProgress, oldProps, newProps, @@ -2569,9 +2607,9 @@ function ReactFiberClassComponent( renderExpirationTime, newUnmaskedContext )) - ? (("function" !== typeof instance.UNSAFE_componentWillUpdate && - "function" !== typeof instance.componentWillUpdate) || - "function" === typeof ctor.getDerivedStateFromProps || + ? (hasNewLifecycles || + ("function" !== typeof instance.UNSAFE_componentWillUpdate && + "function" !== typeof instance.componentWillUpdate) || ("function" === typeof instance.componentWillUpdate && instance.componentWillUpdate( newProps, @@ -2585,17 +2623,23 @@ function ReactFiberClassComponent( newUnmaskedContext )), "function" === typeof instance.componentDidUpdate && - (workInProgress.effectTag |= 4)) + (workInProgress.effectTag |= 4), + "function" === typeof instance.getSnapshotBeforeUpdate && + (workInProgress.effectTag |= 2048)) : ("function" !== typeof instance.componentDidUpdate || (oldProps === current.memoizedProps && oldContext === current.memoizedState) || (workInProgress.effectTag |= 4), + "function" !== typeof instance.getSnapshotBeforeUpdate || + (oldProps === current.memoizedProps && + oldContext === current.memoizedState) || + (workInProgress.effectTag |= 2048), memoizeProps(workInProgress, newProps), memoizeState(workInProgress, renderExpirationTime)); instance.props = newProps; instance.state = renderExpirationTime; instance.context = newUnmaskedContext; - return derivedStateFromProps; + return derivedStateFromCatch; } }; } @@ -3444,7 +3488,7 @@ function ReactFiberBeginWork( workInProgress, renderExpirationTime ) { - var context = workInProgress.type.context, + var context = workInProgress.type._context, newProps = workInProgress.pendingProps, oldProps = workInProgress.memoizedProps; if (!hasLegacyContextChanged() && oldProps === newProps) @@ -3610,7 +3654,8 @@ function ReactFiberBeginWork( ((props = callGetDerivedStateFromProps( workInProgress, fn, - props + props, + workInProgress.memoizedState )), null !== props && void 0 !== props && @@ -3881,43 +3926,33 @@ function ReactFiberBeginWork( renderExpirationTime ); case 12: - a: { - fn = workInProgress.type; - unmaskedContext = workInProgress.pendingProps; - updateQueue = workInProgress.memoizedProps; - props = fn._currentValue; - var changedBits = fn._changedBits; - if ( - hasLegacyContextChanged() || - 0 !== changedBits || - updateQueue !== unmaskedContext - ) { - workInProgress.memoizedProps = unmaskedContext; - var observedBits = unmaskedContext.unstable_observedBits; - if (void 0 === observedBits || null === observedBits) - observedBits = 1073741823; - workInProgress.stateNode = observedBits; - if (0 !== (changedBits & observedBits)) - propagateContextChange( - workInProgress, - fn, - changedBits, - renderExpirationTime - ); - else if ( - null !== updateQueue && - updateQueue.children === unmaskedContext.children - ) { - current = bailoutOnAlreadyFinishedWork(current, workInProgress); - break a; - } - renderExpirationTime = unmaskedContext.children; - renderExpirationTime = renderExpirationTime(props); - reconcileChildren(current, workInProgress, renderExpirationTime); - current = workInProgress.child; - } else - current = bailoutOnAlreadyFinishedWork(current, workInProgress); - } + fn = workInProgress.type; + unmaskedContext = workInProgress.pendingProps; + var oldProps = workInProgress.memoizedProps; + props = fn._currentValue; + updateQueue = fn._changedBits; + if ( + hasLegacyContextChanged() || + 0 !== updateQueue || + oldProps !== unmaskedContext + ) { + workInProgress.memoizedProps = unmaskedContext; + oldProps = unmaskedContext.unstable_observedBits; + if (void 0 === oldProps || null === oldProps) oldProps = 1073741823; + workInProgress.stateNode = oldProps; + 0 !== (updateQueue & oldProps) && + propagateContextChange( + workInProgress, + fn, + updateQueue, + renderExpirationTime + ); + renderExpirationTime = unmaskedContext.children; + renderExpirationTime = renderExpirationTime(props); + reconcileChildren(current, workInProgress, renderExpirationTime); + current = workInProgress.child; + } else + current = bailoutOnAlreadyFinishedWork(current, workInProgress); return current; default: invariant( @@ -4313,9 +4348,9 @@ function logError(boundary, errorInfo) { stack = errorInfo.stack; null === stack && (stack = getStackAddendumByWorkInProgressFiber(source)); null !== source && getComponentName(source); + source = null !== stack ? stack : ""; errorInfo = errorInfo.value; - stack = null !== stack ? stack : ""; - null !== boundary && getComponentName(boundary); + null !== boundary && 2 === boundary.tag && getComponentName(boundary); try { if (errorInfo instanceof Error) { var message = errorInfo.message, @@ -4325,13 +4360,13 @@ function logError(boundary, errorInfo) { errorToHandle.message = (message ? name + ": " + message : name) + "\n\nThis error is located at:" + - stack; + source; } catch (e) {} } else errorToHandle = "string" === typeof errorInfo - ? Error(errorInfo + "\n\nThis error is located at:" + stack) - : Error("Unspecified error at:" + stack); + ? Error(errorInfo + "\n\nThis error is located at:" + source) + : Error("Unspecified error at:" + source); ExceptionsManager.handleException(errorToHandle, !1); } catch (e) { (e && e.suppressReactErrorLogging) || console.error(e); @@ -4360,12 +4395,12 @@ function ReactFiberCommitWork( switch (current.tag) { case 2: safelyDetachRef(current); - var _instance6 = current.stateNode; - if ("function" === typeof _instance6.componentWillUnmount) + var _instance7 = current.stateNode; + if ("function" === typeof _instance7.componentWillUnmount) try { - (_instance6.props = current.memoizedProps), - (_instance6.state = current.memoizedState), - _instance6.componentWillUnmount(); + (_instance7.props = current.memoizedProps), + (_instance7.state = current.memoizedState), + _instance7.componentWillUnmount(); } catch (unmountError) { captureError(current, unmountError); } @@ -4475,6 +4510,34 @@ function ReactFiberCommitWork( removeChild = mutation.removeChild, removeChildFromContainer = mutation.removeChildFromContainer; return { + commitBeforeMutationLifeCycles: function(current, finishedWork) { + switch (finishedWork.tag) { + case 2: + if (finishedWork.effectTag & 2048 && null !== current) { + var prevProps = current.memoizedProps, + prevState = current.memoizedState; + current = finishedWork.stateNode; + current.props = finishedWork.memoizedProps; + current.state = finishedWork.memoizedState; + finishedWork = current.getSnapshotBeforeUpdate( + prevProps, + prevState + ); + current.__reactInternalSnapshotBeforeUpdate = finishedWork; + } + break; + case 3: + case 5: + case 6: + case 4: + break; + default: + invariant( + !1, + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + }, commitResetTextContent: function(current) { resetTextContent(current.stateNode); }, @@ -4580,8 +4643,8 @@ function ReactFiberCommitWork( case 2: break; case 5: - var _instance7 = finishedWork.stateNode; - if (null != _instance7) { + var _instance8 = finishedWork.stateNode; + if (null != _instance8) { var newProps = finishedWork.memoizedProps; current = null !== current ? current.memoizedProps : newProps; var type = finishedWork.type, @@ -4589,7 +4652,7 @@ function ReactFiberCommitWork( finishedWork.updateQueue = null; null !== updatePayload && commitUpdate( - _instance7, + _instance8, updatePayload, type, current, @@ -4603,11 +4666,11 @@ function ReactFiberCommitWork( null !== finishedWork.stateNode, "This should have a text node initialized. This error is likely caused by a bug in React. Please file an issue." ); - _instance7 = finishedWork.memoizedProps; + _instance8 = finishedWork.memoizedProps; commitTextUpdate( finishedWork.stateNode, - null !== current ? current.memoizedProps : _instance7, - _instance7 + null !== current ? current.memoizedProps : _instance8, + _instance8 ); break; case 3: @@ -4633,7 +4696,11 @@ function ReactFiberCommitWork( current = current.memoizedState; finishedRoot.props = finishedWork.memoizedProps; finishedRoot.state = finishedWork.memoizedState; - finishedRoot.componentDidUpdate(prevProps, current); + finishedRoot.componentDidUpdate( + prevProps, + current, + finishedRoot.__reactInternalSnapshotBeforeUpdate + ); } finishedWork = finishedWork.updateQueue; null !== finishedWork && commitCallbacks(finishedWork, finishedRoot); @@ -4695,9 +4762,12 @@ function ReactFiberCommitWork( onUncaughtError.state = finishedWork.memoizedState; for (ctor = 0; ctor < capturedErrors.length; ctor++) { updateQueue = capturedErrors[ctor]; - var _error = updateQueue.value; + var _error = updateQueue.value, + stack = updateQueue.stack; logError(finishedWork, updateQueue); - onUncaughtError.componentDidCatch(_error); + onUncaughtError.componentDidCatch(_error, { + componentStack: null !== stack ? stack : "" + }); } break; case 3: @@ -4723,13 +4793,13 @@ function ReactFiberCommitWork( commitAttachRef: function(finishedWork) { var ref = finishedWork.ref; if (null !== ref) { - var _instance5 = finishedWork.stateNode; + var _instance6 = finishedWork.stateNode; switch (finishedWork.tag) { case 5: - finishedWork = getPublicInstance(_instance5); + finishedWork = getPublicInstance(_instance6); break; default: - finishedWork = _instance5; + finishedWork = _instance6; } "function" === typeof ref ? ref(finishedWork) @@ -4780,8 +4850,10 @@ function ReactFiberHostContext(config, stack) { }, pushHostContainer: function(fiber, nextRootInstance) { push(rootInstanceStackCursor, nextRootInstance, fiber); - nextRootInstance = getRootHostContext(nextRootInstance); push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor, NO_CONTEXT, fiber); + nextRootInstance = getRootHostContext(nextRootInstance); + pop(contextStackCursor, fiber); push(contextStackCursor, nextRootInstance, fiber); }, pushHostContext: function(fiber) { @@ -5088,7 +5160,7 @@ function ReactFiberNewContext(stack) { changedBitsCursor = createCursor(0); return { pushProvider: function(providerFiber) { - var context = providerFiber.type.context; + var context = providerFiber.type._context; push(changedBitsCursor, context._changedBits, providerFiber); push(valueCursor, context._currentValue, providerFiber); push(providerCursor, providerFiber, providerFiber); @@ -5101,7 +5173,7 @@ function ReactFiberNewContext(stack) { pop(providerCursor, providerFiber); pop(valueCursor, providerFiber); pop(changedBitsCursor, providerFiber); - providerFiber = providerFiber.type.context; + providerFiber = providerFiber.type._context; providerFiber._currentValue = currentValue; providerFiber._changedBits = changedBits; } @@ -5214,7 +5286,7 @@ function ReactFiberScheduler(config) { workInProgress$jscomp$0 = unwindWork(workInProgress$jscomp$0); if (null !== workInProgress$jscomp$0) return ( - (workInProgress$jscomp$0.effectTag &= 511), workInProgress$jscomp$0 + (workInProgress$jscomp$0.effectTag &= 2559), workInProgress$jscomp$0 ); null !== returnFiber && ((returnFiber.firstEffect = returnFiber.lastEffect = null), @@ -5378,7 +5450,7 @@ function ReactFiberScheduler(config) { 0 !== nextRenderExpirationTime && expirationTime < nextRenderExpirationTime && resetStack(); - (nextRoot === root && isWorking) || + (isWorking && !isCommitting && nextRoot === root) || requestWork(root, expirationTime); nestedUpdateCount > NESTED_UPDATE_LIMIT && invariant( @@ -5442,7 +5514,7 @@ function ReactFiberScheduler(config) { (nextFlushedExpirationTime = 1), performWorkOnRoot(root, 1, !1)) : 1 === expirationTime - ? performWork(1, !1, null) + ? performSyncWork() : scheduleCallbackWithExpiration(expirationTime)); } function findHighestPriorityRoot() { @@ -5502,6 +5574,9 @@ function ReactFiberScheduler(config) { function performAsyncWork(dl) { performWork(0, !0, dl); } + function performSyncWork() { + performWork(1, !1, null); + } function performWork(minExpirationTime, isAsync, dl) { deadline = dl; findHighestPriorityRoot(); @@ -5624,6 +5699,25 @@ function ReactFiberScheduler(config) { for (nextEffect = firstEffect; null !== nextEffect; ) { var didError = !1, error = void 0; + try { + for (; null !== nextEffect; ) + nextEffect.effectTag & 2048 && + commitBeforeMutationLifeCycles(nextEffect.alternate, nextEffect), + (nextEffect = nextEffect.nextEffect); + } catch (e) { + (didError = !0), (error = e); + } + didError && + (invariant( + null !== nextEffect, + "Should have next effect. This error is likely caused by a bug in React. Please file an issue." + ), + onCommitPhaseError(nextEffect, error), + null !== nextEffect && (nextEffect = nextEffect.nextEffect)); + } + for (nextEffect = firstEffect; null !== nextEffect; ) { + didError = !1; + error = void 0; try { for (; null !== nextEffect; ) { var effectTag = nextEffect.effectTag; @@ -5764,7 +5858,9 @@ function ReactFiberScheduler(config) { }, recalculateCurrentTime ); - var commitResetTextContent = hostContext.commitResetTextContent, + var commitBeforeMutationLifeCycles = + hostContext.commitBeforeMutationLifeCycles, + commitResetTextContent = hostContext.commitResetTextContent, commitPlacement = hostContext.commitPlacement, commitDeletion = hostContext.commitDeletion, commitWork = hostContext.commitWork, @@ -5819,7 +5915,10 @@ function ReactFiberScheduler(config) { !isRendering, "work.commit(): Cannot commit while already rendering. This likely means you attempted to commit from inside a lifecycle method." ); + nextFlushedRoot = root; + nextFlushedExpirationTime = expirationTime; performWorkOnRoot(root, expirationTime, !1); + performSyncWork(); finishRendering(); }, batchedUpdates: function(fn, a) { @@ -5830,7 +5929,7 @@ function ReactFiberScheduler(config) { } finally { (isBatchingUpdates = previousIsBatchingUpdates) || isRendering || - performWork(1, !1, null); + performSyncWork(); } }, unbatchedUpdates: function(fn, a) { @@ -5854,8 +5953,7 @@ function ReactFiberScheduler(config) { try { return syncUpdates(fn, a); } finally { - (isBatchingUpdates = previousIsBatchingUpdates), - performWork(1, !1, null); + (isBatchingUpdates = previousIsBatchingUpdates), performSyncWork(); } }, flushControlled: function(fn) { @@ -5896,7 +5994,7 @@ function ReactFiberScheduler(config) { (isBatchingInteractiveUpdates = previousIsBatchingInteractiveUpdates), (isBatchingUpdates = previousIsBatchingUpdates) || isRendering || - performWork(1, !1, null); + performSyncWork(); } }, flushInteractiveUpdates: function() { @@ -6128,7 +6226,8 @@ var ReactFiberReconciler$2 = Object.freeze({ default: ReactFiberReconciler$1 }), frameDeadlineObject = { timeRemaining: function() { return frameDeadline - now(); - } + }, + didTimeout: !1 }; function setTimeoutCallback() { frameDeadline = now() + 5; @@ -6462,7 +6561,7 @@ NativeRenderer.injectIntoDevTools({ findFiberByHostInstance: getInstanceFromTag, getInspectorDataForViewTag: getInspectorDataForViewTag, bundleType: 0, - version: "16.3.0-alpha.2", + version: "16.3.1", rendererPackageName: "react-native-renderer" }); var ReactNativeRenderer$2 = Object.freeze({ default: ReactNativeRenderer }), diff --git a/Libraries/Renderer/shims/ReactFabric.js b/Libraries/Renderer/shims/ReactFabric.js index 6ab336bf11f058..4162ca62fef73d 100644 --- a/Libraries/Renderer/shims/ReactFabric.js +++ b/Libraries/Renderer/shims/ReactFabric.js @@ -25,4 +25,3 @@ if (__DEV__) { BatchedBridge.registerCallableModule('ReactFabric', ReactFabric); module.exports = (ReactFabric: ReactNativeType); - diff --git a/Libraries/Renderer/shims/ReactTypes.js b/Libraries/Renderer/shims/ReactTypes.js index f6a56ccc96ed4e..689ed18bf95294 100644 --- a/Libraries/Renderer/shims/ReactTypes.js +++ b/Libraries/Renderer/shims/ReactTypes.js @@ -62,7 +62,7 @@ export type ReactProvider = { export type ReactProviderType = { $$typeof: Symbol | number, - context: ReactContext, + _context: ReactContext, }; export type ReactConsumer = { @@ -72,7 +72,7 @@ export type ReactConsumer = { ref: null, props: { children: (value: T) => ReactNodeList, - bits?: number, + unstable_observedBits?: number, }, }; diff --git a/package.json b/package.json index d15a462f15e1bf..4f4f558451100f 100644 --- a/package.json +++ b/package.json @@ -142,7 +142,7 @@ "react-native": "local-cli/wrong-react-native.js" }, "peerDependencies": { - "react": "^16.3.0-alpha.2" + "react": "16.3.1" }, "dependencies": { "absolute-path": "^0.0.0", @@ -219,8 +219,8 @@ "jest": "23.0.0-alpha.4", "jest-junit": "3.6.0", "prettier": "1.9.1", - "react": "^16.3.0-alpha.2", - "react-test-renderer": "^16.3.0-alpha.2", + "react": "16.3.1", + "react-test-renderer": "16.3.1", "shelljs": "^0.7.8", "sinon": "^2.2.0" } From 490f22ae72ba43fa9364ce0f6c238744c07ac830 Mon Sep 17 00:00:00 2001 From: Peter Argany Date: Wed, 4 Apr 2018 16:43:37 -0700 Subject: [PATCH 0207/1109] Fix bug with safe area conformance Reviewed By: wwalser Differential Revision: D7507732 fbshipit-source-id: 10bf8d58c65f1353a3e62a27fc74c2dfd73ac2c4 --- Libraries/Text/TextInput/RCTInputAccessoryViewContent.m | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Libraries/Text/TextInput/RCTInputAccessoryViewContent.m b/Libraries/Text/TextInput/RCTInputAccessoryViewContent.m index 73ec648ad8e128..5a9f142c6108a5 100644 --- a/Libraries/Text/TextInput/RCTInputAccessoryViewContent.m +++ b/Libraries/Text/TextInput/RCTInputAccessoryViewContent.m @@ -27,18 +27,13 @@ - (void)didMoveToSuperview { #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */ - // Avoid the home pill (in portrait mode) and notch (in landscape mode) on iPhoneX. + // Avoid the home pill (in portrait mode) + // TODO: Support rotation, anchor to left and right without breaking frame x coordinate (T27974328). if (@available(iOS 11.0, *)) { if (self.window) { [_safeAreaContainer.bottomAnchor constraintLessThanOrEqualToSystemSpacingBelowAnchor:self.window.safeAreaLayoutGuide.bottomAnchor multiplier:1.0f].active = YES; - [_safeAreaContainer.leftAnchor - constraintGreaterThanOrEqualToSystemSpacingAfterAnchor:self.window.safeAreaLayoutGuide.leftAnchor - multiplier:1.0f].active = YES; - [_safeAreaContainer.rightAnchor - constraintLessThanOrEqualToSystemSpacingAfterAnchor:self.window.safeAreaLayoutGuide.rightAnchor - multiplier:1.0f].active = YES; } } #endif From 3ed076b65a79cf8438d99d2e031013d8859eec33 Mon Sep 17 00:00:00 2001 From: philvasseur Date: Wed, 4 Apr 2018 20:33:11 -0700 Subject: [PATCH 0208/1109] added in snapAlignment for horizontal android scrollView Summary: `snapToAlignment` is available on iOS but not android yet. This PR is to add support for `snapToAlignment` on android as `snapToInterval` was recently added to android and they are very useful together. Make a `Flatlist` in android with `pagingEnabled`, `horizontal`, `snapToInterval` and `snapToAlignment` set and see how adjusting between the three values of `snapToAlignment` aligns just like it does in iOS. [ANDROID] [MINOR] [ScrollView] - On Android, **ScrollView** now takes snapToAlignment like iOS Closes https://github.com/facebook/react-native/pull/18648 Differential Revision: D7473762 Pulled By: mdvacca fbshipit-source-id: ad4778b83f9fd1352455b2ed28a5f37229d9d8c7 --- .../scroll/ReactHorizontalScrollView.java | 21 ++++++++++++++++++- .../ReactHorizontalScrollViewManager.java | 5 +++++ 2 files changed, 25 insertions(+), 1 deletion(-) 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 90b9d1fc4d3a9c..fe4762ac4a2f2e 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 @@ -52,6 +52,7 @@ public class ReactHorizontalScrollView extends HorizontalScrollView implements private @Nullable Drawable mEndBackground; private int mEndFillColor = Color.TRANSPARENT; private int mSnapInterval = 0; + private String mSnapAlignment = "start"; private ReactViewBackgroundManager mReactBackgroundManager; public ReactHorizontalScrollView(Context context) { @@ -96,6 +97,13 @@ public void setPagingEnabled(boolean pagingEnabled) { public void setSnapInterval(int snapInterval) { mSnapInterval = snapInterval; + if(snapInterval != 0) { + mPagingEnabled = true; + } + } + + public void setSnapAlignment(String snapAlignment) { + mSnapAlignment = snapAlignment; } public void flashScrollIndicators() { @@ -236,6 +244,17 @@ private int getSnapInterval() { return getWidth(); } + private int getAlignmentOffset() { + int width = getWidth(); + int snapInterval = getSnapInterval(); + if (mSnapAlignment.equals("center")) { + return (width - snapInterval)/2; + } else if(mSnapAlignment.equals("end")) { + return (width - snapInterval); + } + return 0; + } + public void setEndFillColor(int color) { if (color != mEndFillColor) { mEndFillColor = color; @@ -349,7 +368,7 @@ private void smoothScrollToPage(int velocity) { if (predictedX > page * width + width / 2) { page = page + 1; } - smoothScrollTo(page * width, getScrollY()); + smoothScrollTo(page * width - getAlignmentOffset(), getScrollY()); } @Override diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java index e6536a6e53eb76..d5fe728c309896 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java @@ -80,6 +80,11 @@ public void setSnapToInterval(ReactHorizontalScrollView view, float snapToInterv view.setSnapInterval((int) (snapToInterval * screenDisplayMetrics.density)); } + @ReactProp(name = "snapToAlignment") + public void setSnapToAlignment(ReactHorizontalScrollView view, String snapToAlignment) { + view.setSnapAlignment(snapToAlignment); + } + @ReactProp(name = ReactClippingViewGroupHelper.PROP_REMOVE_CLIPPED_SUBVIEWS) public void setRemoveClippedSubviews(ReactHorizontalScrollView view, boolean removeClippedSubviews) { view.setRemoveClippedSubviews(removeClippedSubviews); From 4a814d1370329ac75a6fb0924c73c48b3d3754fb Mon Sep 17 00:00:00 2001 From: Peter van der Zee Date: Thu, 5 Apr 2018 06:14:51 -0700 Subject: [PATCH 0209/1109] Change ES6 module syntax to module.exports Reviewed By: rubennorte Differential Revision: D7490562 fbshipit-source-id: 861681c24eab678d25af47bb25738651fe3e26b4 --- Libraries/Components/View/ViewContext.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Libraries/Components/View/ViewContext.js b/Libraries/Components/View/ViewContext.js index 563d2b253b93e0..f9f98000409ddc 100644 --- a/Libraries/Components/View/ViewContext.js +++ b/Libraries/Components/View/ViewContext.js @@ -16,6 +16,8 @@ export type ViewChildContext = {| +isInAParentText: boolean, |}; -export const ViewContextTypes = { - isInAParentText: PropTypes.bool, +module.exports = { + ViewContextTypes: { + isInAParentText: PropTypes.bool, + }, }; From cea798c57b4a46d7819cfc417278c764b2486a45 Mon Sep 17 00:00:00 2001 From: Peter van der Zee Date: Thu, 5 Apr 2018 06:14:52 -0700 Subject: [PATCH 0210/1109] Downgrade ES6 import to ES5 compat module.exports Reviewed By: rubennorte Differential Revision: D7498658 fbshipit-source-id: 6825c3010ce13c56f05284448ad9961fe058d7ea --- Libraries/Network/fetch.js | 2 +- Libraries/StyleSheet/StyleSheetTypes.js | 2 +- bots/dangerfile.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Libraries/Network/fetch.js b/Libraries/Network/fetch.js index 5a0de646c91258..1e1c934316d6db 100644 --- a/Libraries/Network/fetch.js +++ b/Libraries/Network/fetch.js @@ -12,7 +12,7 @@ 'use strict'; -import whatwg from 'whatwg-fetch'; +const whatwg = require('whatwg-fetch'); if (whatwg && whatwg.fetch) { module.exports = whatwg; diff --git a/Libraries/StyleSheet/StyleSheetTypes.js b/Libraries/StyleSheet/StyleSheetTypes.js index 6ff412ce8a6798..1e359e8b515cf4 100644 --- a/Libraries/StyleSheet/StyleSheetTypes.js +++ b/Libraries/StyleSheet/StyleSheetTypes.js @@ -11,7 +11,7 @@ 'use strict'; -import AnimatedNode from 'AnimatedNode'; +const AnimatedNode = require('AnimatedNode'); export opaque type ____StyleSheetInternalStyleIdentifier_Internal: number = number; diff --git a/bots/dangerfile.js b/bots/dangerfile.js index b97ecaf8e19f96..3380e718fb3407 100644 --- a/bots/dangerfile.js +++ b/bots/dangerfile.js @@ -11,7 +11,7 @@ const fs = require('fs'); const includes = require('lodash.includes'); const minimatch = require('minimatch'); -import { danger, fail, markdown, message, warn } from 'danger'; +const { danger, fail, markdown, message, warn } = require('danger'); // Fails if the description is too short. if (!danger.github.pr.body || danger.github.pr.body.length < 10) { From 439614891cb0ea5c0eeb6ef4d3bf1bbdec88d659 Mon Sep 17 00:00:00 2001 From: Peter van der Zee Date: Thu, 5 Apr 2018 06:14:54 -0700 Subject: [PATCH 0211/1109] Small refactor Reviewed By: cpojer Differential Revision: D7498659 fbshipit-source-id: 43ad85645e2366a385e08d68172e76e336fdfb1f --- Libraries/Components/ScrollView/ScrollView.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js index 29b9d57ca2a2da..bc57f5cb400b62 100644 --- a/Libraries/Components/ScrollView/ScrollView.js +++ b/Libraries/Components/ScrollView/ScrollView.js @@ -746,10 +746,9 @@ const ScrollView = createReactClass({ this.props.horizontal && styles.contentContainerHorizontal, this.props.contentContainerStyle, ]; - let style, childLayoutProps; if (__DEV__ && this.props.style) { - style = flattenStyle(this.props.style); - childLayoutProps = ['alignItems', 'justifyContent'] + const style = flattenStyle(this.props.style); + const childLayoutProps = ['alignItems', 'justifyContent'] .filter((prop) => style && style[prop] !== undefined); invariant( childLayoutProps.length === 0, From 6be5d7827bd92b833319671c446bfabe34f9491d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Thu, 5 Apr 2018 08:54:52 -0700 Subject: [PATCH 0212/1109] Adds an experimental hook for custom resolutions Reviewed By: mjesun Differential Revision: D7337022 fbshipit-source-id: fea1ee345e4d3b5713fed6cdc33869fbba6f21e2 --- local-cli/bundle/buildBundle.js | 3 ++- local-cli/server/runServer.js | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/local-cli/bundle/buildBundle.js b/local-cli/bundle/buildBundle.js index ebebc09c6ebf0d..5b1f5be0653425 100644 --- a/local-cli/bundle/buildBundle.js +++ b/local-cli/bundle/buildBundle.js @@ -98,8 +98,9 @@ async function buildBundle( postProcessBundleSourcemap: config.postProcessBundleSourcemap, projectRoots: config.getProjectRoots(), providesModuleNodeModules: providesModuleNodeModules, - resetCache: args.resetCache, reporter: new TerminalReporter(terminal), + resetCache: args.resetCache, + resolveRequest: config.resolveRequest, sourceExts: sourceExts.concat(defaultSourceExts), transformCache: TransformCaching.useTempDir(), transformModulePath: transformModulePath, diff --git a/local-cli/server/runServer.js b/local-cli/server/runServer.js index 768fbaf0d3676a..1ccedf77765ed3 100644 --- a/local-cli/server/runServer.js +++ b/local-cli/server/runServer.js @@ -202,6 +202,7 @@ function getPackagerServer(args, config, reporter) { providesModuleNodeModules: providesModuleNodeModules, reporter, resetCache: args.resetCache, + resolveRequest: config.resolveRequest, sourceExts: args.sourceExts.concat(defaultSourceExts), transformModulePath: transformModulePath, transformCache: TransformCaching.useTempDir(), From 52a3443e9805b2d56cbd288e10cab6e9d154cf90 Mon Sep 17 00:00:00 2001 From: Mehdi Mulani Date: Thu, 5 Apr 2018 14:32:43 -0700 Subject: [PATCH 0213/1109] Weakly capture the bridge in callback methods Summary: Callback blocks are frequently held onto by modules, e.g. for animation the `RCTFrameAnimation` holds onto its callback method. This causes a bunch of retain cycles since the module will be strongly held onto by the bridge. Reviewed By: Megra Differential Revision: D7492136 fbshipit-source-id: 708e61ffe7bf0dcffaebc056ab861b9023ffc1df --- React/Base/RCTModuleMethod.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/React/Base/RCTModuleMethod.mm b/React/Base/RCTModuleMethod.mm index a8361482c4edcd..1a151577914724 100644 --- a/React/Base/RCTModuleMethod.mm +++ b/React/Base/RCTModuleMethod.mm @@ -213,7 +213,7 @@ - (void)processMethodSignature #endif #define RCT_RETAINED_ARG_BLOCK(_logic) \ -[argumentBlocks addObject:^(__unused RCTBridge *bridge, NSUInteger index, id json) { \ +[argumentBlocks addObject:^(__unused __weak RCTBridge *bridge, NSUInteger index, id json) { \ _logic \ [invocation setArgument:&value atIndex:(index) + 2]; \ if (value) { \ From 7a29ad1d834a77cb66a3470f7598b1e6861adc70 Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Thu, 5 Apr 2018 15:47:03 -0700 Subject: [PATCH 0214/1109] Specify platforms for the a few targets Differential Revision: D7516968 fbshipit-source-id: db9d6df7c1b67dbdd998ea017229a976f78b2eb1 --- ReactCommon/cxxreact/BUCK | 1 + ReactCommon/jschelpers/BUCK | 2 ++ 2 files changed, 3 insertions(+) diff --git a/ReactCommon/cxxreact/BUCK b/ReactCommon/cxxreact/BUCK index 5f84b3fd5a241b..6201e74cdf3b0d 100644 --- a/ReactCommon/cxxreact/BUCK +++ b/ReactCommon/cxxreact/BUCK @@ -141,6 +141,7 @@ rn_xplat_cxx_library( ], fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + APPLE_INSPECTOR_FLAGS, force_static = True, + platforms = (ANDROID, APPLE), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", diff --git a/ReactCommon/jschelpers/BUCK b/ReactCommon/jschelpers/BUCK index ac9ee706deb1a0..37dc1abb0df57d 100644 --- a/ReactCommon/jschelpers/BUCK +++ b/ReactCommon/jschelpers/BUCK @@ -40,6 +40,7 @@ rn_xplat_cxx_library( fbandroid_deps = ANDROID_JSC_INTERNAL_DEPS, fbobjc_deps = APPLE_JSC_INTERNAL_DEPS, force_static = True, + platforms = (ANDROID, APPLE), visibility = [ "PUBLIC", ], @@ -64,6 +65,7 @@ rn_xplat_cxx_library( ], fbobjc_srcs = ["systemJSCWrapper.cpp"], force_static = True, + platforms = (ANDROID, APPLE), visibility = [ "PUBLIC", ], From 9b9b6c845e597e38a9801d34b6ffbe491cea7a20 Mon Sep 17 00:00:00 2001 From: gengjiawen Date: Thu, 5 Apr 2018 17:26:39 -0700 Subject: [PATCH 0215/1109] Inline and fix proguard rules Summary: The original proguard rules are put in the template, which is not very convenient and easy to get wrong. Because new rules get put, people also has two copy paste the rule. And there are also existing project import react native as a dependency. So the best way to keep a android library project proguard rule is to manage the rule itself, using `consumerProguardFiles` like [dagger](https://github.com/JakeWharton/butterknife/blob/46baef6d96e93a1872efa17fdfc1d2af59b36f0c/butterknife/build.gradle#L9) and other android library project. Use RNTester to build the release flavor (now it has bugs https://github.com/facebook/react-native/issues/18460, I keep my change in local for now), after build success, run to check if crash. In the process, I also fix https://github.com/facebook/react-native/issues/12994 and https://github.com/facebook/react-native/issues/6624 by adding the following to proguard rules ```proguard -keep,includedescriptorclasses class com.facebook.react.bridge.** { *; } ``` [ANDROID] [ENHANCEMENT and BUGFIX] [Proguard rules] - inline and fix proguard rules . Closes https://github.com/facebook/react-native/pull/18461 Differential Revision: D7527533 Pulled By: hramos fbshipit-source-id: 447dbc16983bcfb597187b40c1be3987a8c5a832 --- ReactAndroid/build.gradle | 2 + ReactAndroid/proguard-rules.pro | 90 +++++++++++++++++++ .../HelloWorld/android/app/proguard-rules.pro | 72 --------------- 3 files changed, 92 insertions(+), 72 deletions(-) create mode 100644 ReactAndroid/proguard-rules.pro diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle index fa1be07afa74a2..15b5c02cdcab7d 100644 --- a/ReactAndroid/build.gradle +++ b/ReactAndroid/build.gradle @@ -251,6 +251,8 @@ android { versionCode 1 versionName "1.0" + consumerProguardFiles 'proguard-rules.pro' + ndk { moduleName "reactnativejni" } diff --git a/ReactAndroid/proguard-rules.pro b/ReactAndroid/proguard-rules.pro new file mode 100644 index 00000000000000..6e9ff0ac75515f --- /dev/null +++ b/ReactAndroid/proguard-rules.pro @@ -0,0 +1,90 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Disabling obfuscation is useful if you collect stack traces from production crashes +# (unless you are using a system that supports de-obfuscate the stack traces). +# -dontobfuscate + +# React Native + +# Keep our interfaces so they can be used by other ProGuard rules. +# See http://sourceforge.net/p/proguard/bugs/466/ +-keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip +-keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters +-keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip + +# Do not strip any method/class that is annotated with @DoNotStrip +-keep @com.facebook.proguard.annotations.DoNotStrip class * +-keep @com.facebook.common.internal.DoNotStrip class * +-keepclassmembers class * { + @com.facebook.proguard.annotations.DoNotStrip *; + @com.facebook.common.internal.DoNotStrip *; +} + +-keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * { + void set*(***); + *** get*(); +} + +-keep class * extends com.facebook.react.bridge.JavaScriptModule { *; } +-keep class * extends com.facebook.react.bridge.NativeModule { *; } +-keepclassmembers,includedescriptorclasses class * { native ; } +-keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; } +-keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; } +-keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; } + +-dontwarn com.facebook.react.** +-keep,includedescriptorclasses class com.facebook.react.bridge.** { *; } + +# TextLayoutBuilder uses a non-public Android constructor within StaticLayout. +# See libs/proxy/src/main/java/com/facebook/fbui/textlayoutbuilder/proxy for details. +-dontwarn android.text.StaticLayout + +# okhttp + +-keepattributes Signature +-keepattributes *Annotation* +-keep class okhttp3.** { *; } +-keep interface okhttp3.** { *; } +-dontwarn okhttp3.** + +# okio + +-keep class sun.misc.Unsafe { *; } +-dontwarn java.nio.file.* +-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement +-dontwarn okio.** + +# Fresco +# Keep our interfaces so they can be used by other ProGuard rules. +# See http://sourceforge.net/p/proguard/bugs/466/ +-keep,allowobfuscation @interface com.facebook.soloader.DoNotOptimize + +# Do not strip any method/class that is annotated with @DoNotOptimize +-keep @com.facebook.soloader.DoNotOptimize class * +-keepclassmembers class * { + @com.facebook.soloader.DoNotOptimize *; +} + +# Keep native methods +-keepclassmembers class * { + native ; +} + +-dontwarn javax.annotation.** +-dontwarn com.facebook.infer.** diff --git a/local-cli/templates/HelloWorld/android/app/proguard-rules.pro b/local-cli/templates/HelloWorld/android/app/proguard-rules.pro index b30112461f0e74..a92fa177ee49f0 100644 --- a/local-cli/templates/HelloWorld/android/app/proguard-rules.pro +++ b/local-cli/templates/HelloWorld/android/app/proguard-rules.pro @@ -15,75 +15,3 @@ #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} - -# Disabling obfuscation is useful if you collect stack traces from production crashes -# (unless you are using a system that supports de-obfuscate the stack traces). -# -dontobfuscate - -# React Native - -# Keep our interfaces so they can be used by other ProGuard rules. -# See http://sourceforge.net/p/proguard/bugs/466/ --keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip --keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters --keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip - -# Do not strip any method/class that is annotated with @DoNotStrip --keep @com.facebook.proguard.annotations.DoNotStrip class * --keep @com.facebook.common.internal.DoNotStrip class * --keepclassmembers class * { - @com.facebook.proguard.annotations.DoNotStrip *; - @com.facebook.common.internal.DoNotStrip *; -} - --keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * { - void set*(***); - *** get*(); -} - --keep class * extends com.facebook.react.bridge.JavaScriptModule { *; } --keep class * extends com.facebook.react.bridge.NativeModule { *; } --keepclassmembers,includedescriptorclasses class * { native ; } --keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; } --keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; } --keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; } - --dontwarn com.facebook.react.** - -# TextLayoutBuilder uses a non-public Android constructor within StaticLayout. -# See libs/proxy/src/main/java/com/facebook/fbui/textlayoutbuilder/proxy for details. --dontwarn android.text.StaticLayout - -# Fresco -# Keep our interfaces so they can be used by other ProGuard rules. -# See http://sourceforge.net/p/proguard/bugs/466/ --keep,allowobfuscation @interface com.facebook.soloader.DoNotOptimize - -# Do not strip any method/class that is annotated with @DoNotOptimize --keep @com.facebook.soloader.DoNotOptimize class * --keepclassmembers class * { - @com.facebook.soloader.DoNotOptimize *; -} - -# Keep native methods --keepclassmembers class * { - native ; -} - --dontwarn javax.annotation.** --dontwarn com.facebook.infer.** - -# okhttp - --keepattributes Signature --keepattributes *Annotation* --keep class okhttp3.** { *; } --keep interface okhttp3.** { *; } --dontwarn okhttp3.** - -# okio - --keep class sun.misc.Unsafe { *; } --dontwarn java.nio.file.* --dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement --dontwarn okio.** From 445b0c7080dca699744f2aa7c69dde4f62b9c657 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Thu, 5 Apr 2018 17:33:08 -0700 Subject: [PATCH 0216/1109] React sync for revisions 1c2876d...7a3416f Reviewed By: bvaughn Differential Revision: D7526137 fbshipit-source-id: 9f9db8a6b56cb4ae581a7b8d28079ec38de2180f --- Libraries/Renderer/REVISION | 2 +- Libraries/Renderer/ReactFabric-dev.js | 29 +- Libraries/Renderer/ReactFabric-prod.js | 61 ++-- Libraries/Renderer/ReactNativeRenderer-dev.js | 178 ++++----- .../Renderer/ReactNativeRenderer-prod.js | 344 +++++++++--------- 5 files changed, 322 insertions(+), 292 deletions(-) diff --git a/Libraries/Renderer/REVISION b/Libraries/Renderer/REVISION index fc81a7c7f28c85..f505341495fa69 100644 --- a/Libraries/Renderer/REVISION +++ b/Libraries/Renderer/REVISION @@ -1 +1 @@ -1c2876d5b558b8591feb335d8d7204bc46f7da8a \ No newline at end of file +7a3416f27532ac25849dfbc505300d469b43bbcc \ No newline at end of file diff --git a/Libraries/Renderer/ReactFabric-dev.js b/Libraries/Renderer/ReactFabric-dev.js index 0b7a78516c11ba..e51c0254b90454 100644 --- a/Libraries/Renderer/ReactFabric-dev.js +++ b/Libraries/Renderer/ReactFabric-dev.js @@ -4765,6 +4765,14 @@ var ReactStrictModeWarnings = { var didWarnAboutDeprecatedLifecycles = new Set(); var didWarnAboutUnsafeLifecycles = new Set(); + var setToSortedString = function(set) { + var array = []; + set.forEach(function(value) { + array.push(value); + }); + return array.sort().join(", "); + }; + ReactStrictModeWarnings.discardPendingWarnings = function() { pendingComponentWillMountWarnings = []; pendingComponentWillReceivePropsWarnings = []; @@ -4790,9 +4798,7 @@ var ReactStrictModeWarnings = { var formatted = lifecycle.replace("UNSAFE_", ""); var suggestion = LIFECYCLE_SUGGESTIONS[lifecycle]; - var sortedComponentNames = Array.from(componentNames) - .sort() - .join(", "); + var sortedComponentNames = setToSortedString(componentNames); lifecyclesWarningMesages.push( formatted + @@ -4844,9 +4850,7 @@ var ReactStrictModeWarnings = { didWarnAboutDeprecatedLifecycles.add(fiber.type); }); - var sortedNames = Array.from(uniqueNames) - .sort() - .join(", "); + var sortedNames = setToSortedString(uniqueNames); lowPriorityWarning$1( false, @@ -4869,9 +4873,7 @@ var ReactStrictModeWarnings = { didWarnAboutDeprecatedLifecycles.add(fiber.type); }); - var _sortedNames = Array.from(_uniqueNames) - .sort() - .join(", "); + var _sortedNames = setToSortedString(_uniqueNames); lowPriorityWarning$1( false, @@ -4893,9 +4895,7 @@ var ReactStrictModeWarnings = { didWarnAboutDeprecatedLifecycles.add(fiber.type); }); - var _sortedNames2 = Array.from(_uniqueNames2) - .sort() - .join(", "); + var _sortedNames2 = setToSortedString(_uniqueNames2); lowPriorityWarning$1( false, @@ -6217,7 +6217,6 @@ var ReactFiberClassComponent = function( if ( typeof instance.getSnapshotBeforeUpdate === "function" && typeof instance.componentDidUpdate !== "function" && - typeof instance.componentDidUpdate !== "function" && !didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.has(type) ) { didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.add(type); @@ -9199,6 +9198,10 @@ var ReactFiberBeginWork = function( changedBits, renderExpirationTime ); + } else if (oldProps === newProps) { + // Skip over a memoized parent with a bitmask bailout even + // if we began working on it because of a deeper matching child. + return bailoutOnAlreadyFinishedWork(current, workInProgress); } // There is no bailout on `children` equality because we expect people // to often pass a bound method as a child, but it may reference diff --git a/Libraries/Renderer/ReactFabric-prod.js b/Libraries/Renderer/ReactFabric-prod.js index c12ebd601c84d0..c57d9bb9d0c927 100644 --- a/Libraries/Renderer/ReactFabric-prod.js +++ b/Libraries/Renderer/ReactFabric-prod.js @@ -3656,33 +3656,40 @@ function ReactFiberBeginWork( renderExpirationTime ); case 12: - fn = workInProgress.type; - unmaskedContext = workInProgress.pendingProps; - var oldProps = workInProgress.memoizedProps; - props = fn._currentValue; - updateQueue = fn._changedBits; - if ( - hasLegacyContextChanged() || - 0 !== updateQueue || - oldProps !== unmaskedContext - ) { - workInProgress.memoizedProps = unmaskedContext; - oldProps = unmaskedContext.unstable_observedBits; - if (void 0 === oldProps || null === oldProps) oldProps = 1073741823; - workInProgress.stateNode = oldProps; - 0 !== (updateQueue & oldProps) && - propagateContextChange( - workInProgress, - fn, - updateQueue, - renderExpirationTime - ); - renderExpirationTime = unmaskedContext.children; - renderExpirationTime = renderExpirationTime(props); - reconcileChildren(current, workInProgress, renderExpirationTime); - current = workInProgress.child; - } else - current = bailoutOnAlreadyFinishedWork(current, workInProgress); + a: { + fn = workInProgress.type; + unmaskedContext = workInProgress.pendingProps; + updateQueue = workInProgress.memoizedProps; + props = fn._currentValue; + var changedBits = fn._changedBits; + if ( + hasLegacyContextChanged() || + 0 !== changedBits || + updateQueue !== unmaskedContext + ) { + workInProgress.memoizedProps = unmaskedContext; + var observedBits = unmaskedContext.unstable_observedBits; + if (void 0 === observedBits || null === observedBits) + observedBits = 1073741823; + workInProgress.stateNode = observedBits; + if (0 !== (changedBits & observedBits)) + propagateContextChange( + workInProgress, + fn, + changedBits, + renderExpirationTime + ); + else if (updateQueue === unmaskedContext) { + current = bailoutOnAlreadyFinishedWork(current, workInProgress); + break a; + } + renderExpirationTime = unmaskedContext.children; + renderExpirationTime = renderExpirationTime(props); + reconcileChildren(current, workInProgress, renderExpirationTime); + current = workInProgress.child; + } else + current = bailoutOnAlreadyFinishedWork(current, workInProgress); + } return current; default: invariant( diff --git a/Libraries/Renderer/ReactNativeRenderer-dev.js b/Libraries/Renderer/ReactNativeRenderer-dev.js index 7fd62f11ca6ae4..97bbfa4bef4d72 100644 --- a/Libraries/Renderer/ReactNativeRenderer-dev.js +++ b/Libraries/Renderer/ReactNativeRenderer-dev.js @@ -2995,6 +2995,75 @@ var TouchHistoryMath = { var ReactVersion = "16.3.1"; +var describeComponentFrame = function(name, source, ownerName) { + return ( + "\n in " + + (name || "Unknown") + + (source + ? " (at " + + source.fileName.replace(/^.*[\\\/]/, "") + + ":" + + source.lineNumber + + ")" + : ownerName ? " (created by " + ownerName + ")" : "") + ); +}; + +function getComponentName(fiber) { + var type = fiber.type; + + if (typeof type === "function") { + return type.displayName || type.name; + } + if (typeof type === "string") { + return type; + } + switch (type) { + case REACT_FRAGMENT_TYPE: + return "ReactFragment"; + case REACT_PORTAL_TYPE: + return "ReactPortal"; + case REACT_CALL_TYPE: + return "ReactCall"; + case REACT_RETURN_TYPE: + return "ReactReturn"; + } + return null; +} + +function describeFiber(fiber) { + switch (fiber.tag) { + case IndeterminateComponent: + case FunctionalComponent: + case ClassComponent: + case HostComponent: + var owner = fiber._debugOwner; + var source = fiber._debugSource; + var name = getComponentName(fiber); + var ownerName = null; + if (owner) { + ownerName = getComponentName(owner); + } + return describeComponentFrame(name, source, ownerName); + default: + return ""; + } +} + +// This function can only be called with a work-in-progress fiber and +// only during begin or complete phase. Do not call it under any other +// circumstances. +function getStackAddendumByWorkInProgressFiber(workInProgress) { + var info = ""; + var node = workInProgress; + do { + info += describeFiber(node); + // Otherwise this return pointer might point to the wrong tree: + node = node["return"]; + } while (node); + return info; +} + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); @@ -3589,28 +3658,6 @@ var ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; var ReactCurrentOwner = ReactInternals.ReactCurrentOwner; var ReactDebugCurrentFrame = ReactInternals.ReactDebugCurrentFrame; -function getComponentName(fiber) { - var type = fiber.type; - - if (typeof type === "function") { - return type.displayName || type.name; - } - if (typeof type === "string") { - return type; - } - switch (type) { - case REACT_FRAGMENT_TYPE: - return "ReactFragment"; - case REACT_PORTAL_TYPE: - return "ReactPortal"; - case REACT_CALL_TYPE: - return "ReactCall"; - case REACT_RETURN_TYPE: - return "ReactReturn"; - } - return null; -} - // TODO: Share this module between Fabric and React Native renderers // so that both can be used in the same tree. @@ -4878,53 +4925,6 @@ function onCommitUnmount(fiber) { } } -var describeComponentFrame = function(name, source, ownerName) { - return ( - "\n in " + - (name || "Unknown") + - (source - ? " (at " + - source.fileName.replace(/^.*[\\\/]/, "") + - ":" + - source.lineNumber + - ")" - : ownerName ? " (created by " + ownerName + ")" : "") - ); -}; - -function describeFiber(fiber) { - switch (fiber.tag) { - case IndeterminateComponent: - case FunctionalComponent: - case ClassComponent: - case HostComponent: - var owner = fiber._debugOwner; - var source = fiber._debugSource; - var name = getComponentName(fiber); - var ownerName = null; - if (owner) { - ownerName = getComponentName(owner); - } - return describeComponentFrame(name, source, ownerName); - default: - return ""; - } -} - -// This function can only be called with a work-in-progress fiber and -// only during begin or complete phase. Do not call it under any other -// circumstances. -function getStackAddendumByWorkInProgressFiber(workInProgress) { - var info = ""; - var node = workInProgress; - do { - info += describeFiber(node); - // Otherwise this return pointer might point to the wrong tree: - node = node["return"]; - } while (node); - return info; -} - /** * Forked from fbjs/warning: * https://github.com/facebook/fbjs/blob/e66ba20ad5be433eb54423f2b097d829324d9de6/packages/fbjs/src/__forks__/warning.js @@ -5019,6 +5019,14 @@ var ReactStrictModeWarnings = { var didWarnAboutDeprecatedLifecycles = new Set(); var didWarnAboutUnsafeLifecycles = new Set(); + var setToSortedString = function(set) { + var array = []; + set.forEach(function(value) { + array.push(value); + }); + return array.sort().join(", "); + }; + ReactStrictModeWarnings.discardPendingWarnings = function() { pendingComponentWillMountWarnings = []; pendingComponentWillReceivePropsWarnings = []; @@ -5044,9 +5052,7 @@ var ReactStrictModeWarnings = { var formatted = lifecycle.replace("UNSAFE_", ""); var suggestion = LIFECYCLE_SUGGESTIONS[lifecycle]; - var sortedComponentNames = Array.from(componentNames) - .sort() - .join(", "); + var sortedComponentNames = setToSortedString(componentNames); lifecyclesWarningMesages.push( formatted + @@ -5098,9 +5104,7 @@ var ReactStrictModeWarnings = { didWarnAboutDeprecatedLifecycles.add(fiber.type); }); - var sortedNames = Array.from(uniqueNames) - .sort() - .join(", "); + var sortedNames = setToSortedString(uniqueNames); lowPriorityWarning$1( false, @@ -5123,9 +5127,7 @@ var ReactStrictModeWarnings = { didWarnAboutDeprecatedLifecycles.add(fiber.type); }); - var _sortedNames = Array.from(_uniqueNames) - .sort() - .join(", "); + var _sortedNames = setToSortedString(_uniqueNames); lowPriorityWarning$1( false, @@ -5147,9 +5149,7 @@ var ReactStrictModeWarnings = { didWarnAboutDeprecatedLifecycles.add(fiber.type); }); - var _sortedNames2 = Array.from(_uniqueNames2) - .sort() - .join(", "); + var _sortedNames2 = setToSortedString(_uniqueNames2); lowPriorityWarning$1( false, @@ -6475,7 +6475,6 @@ var ReactFiberClassComponent = function( if ( typeof instance.getSnapshotBeforeUpdate === "function" && typeof instance.componentDidUpdate !== "function" && - typeof instance.componentDidUpdate !== "function" && !didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.has(type) ) { didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.add(type); @@ -9457,6 +9456,10 @@ var ReactFiberBeginWork = function( changedBits, renderExpirationTime ); + } else if (oldProps === newProps) { + // Skip over a memoized parent with a bitmask bailout even + // if we began working on it because of a deeper matching child. + return bailoutOnAlreadyFinishedWork(current, workInProgress); } // There is no bailout on `children` equality because we expect people // to often pass a bound method as a child, but it may reference @@ -14707,6 +14710,14 @@ injectFindHostInstance(NativeRenderer.findHostInstance); injection$2.injectRenderer(NativeRenderer); +function computeComponentStackForErrorReporting(reactTag) { + var fiber = getInstanceFromTag(reactTag); + if (!fiber) { + return ""; + } + return getStackAddendumByWorkInProgressFiber(fiber); +} + var roots = new Map(); var ReactNativeRenderer = { @@ -14762,7 +14773,8 @@ var ReactNativeRenderer = { ReactNativePropRegistry: ReactNativePropRegistry, // flattenStyle, Stylesheet TouchHistoryMath: TouchHistoryMath, // PanResponder createReactNativeComponentClass: createReactNativeComponentClass, // RCTText, RCTView, ReactNativeART - takeSnapshot: takeSnapshot + takeSnapshot: takeSnapshot, // react-native-implementation + computeComponentStackForErrorReporting: computeComponentStackForErrorReporting } }; diff --git a/Libraries/Renderer/ReactNativeRenderer-prod.js b/Libraries/Renderer/ReactNativeRenderer-prod.js index 055ddd7bb0c161..bf2480f1c03d6f 100644 --- a/Libraries/Renderer/ReactNativeRenderer-prod.js +++ b/Libraries/Renderer/ReactNativeRenderer-prod.js @@ -1198,107 +1198,152 @@ function createPortal(children, containerInfo, implementation) { }; } var TouchHistoryMath = { - centroidDimension: function( - touchHistory, - touchesChangedAfter, - isXAxis, - ofCurrent - ) { - var touchBank = touchHistory.touchBank, - total = 0, - count = 0; - touchHistory = - 1 === touchHistory.numberActiveTouches - ? touchHistory.touchBank[touchHistory.indexOfSingleActiveTouch] - : null; - if (null !== touchHistory) - touchHistory.touchActive && - touchHistory.currentTimeStamp > touchesChangedAfter && + centroidDimension: function( + touchHistory, + touchesChangedAfter, + isXAxis, + ofCurrent + ) { + var touchBank = touchHistory.touchBank, + total = 0, + count = 0; + touchHistory = + 1 === touchHistory.numberActiveTouches + ? touchHistory.touchBank[touchHistory.indexOfSingleActiveTouch] + : null; + if (null !== touchHistory) + touchHistory.touchActive && + touchHistory.currentTimeStamp > touchesChangedAfter && + ((total += + ofCurrent && isXAxis + ? touchHistory.currentPageX + : ofCurrent && !isXAxis + ? touchHistory.currentPageY + : !ofCurrent && isXAxis + ? touchHistory.previousPageX + : touchHistory.previousPageY), + (count = 1)); + else + for (touchHistory = 0; touchHistory < touchBank.length; touchHistory++) { + var touchTrack = touchBank[touchHistory]; + null !== touchTrack && + void 0 !== touchTrack && + touchTrack.touchActive && + touchTrack.currentTimeStamp >= touchesChangedAfter && ((total += ofCurrent && isXAxis - ? touchHistory.currentPageX + ? touchTrack.currentPageX : ofCurrent && !isXAxis - ? touchHistory.currentPageY + ? touchTrack.currentPageY : !ofCurrent && isXAxis - ? touchHistory.previousPageX - : touchHistory.previousPageY), - (count = 1)); - else - for ( - touchHistory = 0; - touchHistory < touchBank.length; - touchHistory++ - ) { - var touchTrack = touchBank[touchHistory]; - null !== touchTrack && - void 0 !== touchTrack && - touchTrack.touchActive && - touchTrack.currentTimeStamp >= touchesChangedAfter && - ((total += - ofCurrent && isXAxis - ? touchTrack.currentPageX - : ofCurrent && !isXAxis - ? touchTrack.currentPageY - : !ofCurrent && isXAxis - ? touchTrack.previousPageX - : touchTrack.previousPageY), - count++); - } - return 0 < count ? total / count : TouchHistoryMath.noCentroid; - }, - currentCentroidXOfTouchesChangedAfter: function( + ? touchTrack.previousPageX + : touchTrack.previousPageY), + count++); + } + return 0 < count ? total / count : TouchHistoryMath.noCentroid; + }, + currentCentroidXOfTouchesChangedAfter: function( + touchHistory, + touchesChangedAfter + ) { + return TouchHistoryMath.centroidDimension( touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - !0, - !0 - ); - }, - currentCentroidYOfTouchesChangedAfter: function( + touchesChangedAfter, + !0, + !0 + ); + }, + currentCentroidYOfTouchesChangedAfter: function( + touchHistory, + touchesChangedAfter + ) { + return TouchHistoryMath.centroidDimension( touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - !1, - !0 - ); - }, - previousCentroidXOfTouchesChangedAfter: function( + touchesChangedAfter, + !1, + !0 + ); + }, + previousCentroidXOfTouchesChangedAfter: function( + touchHistory, + touchesChangedAfter + ) { + return TouchHistoryMath.centroidDimension( touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - !0, - !1 - ); - }, - previousCentroidYOfTouchesChangedAfter: function( + touchesChangedAfter, + !0, + !1 + ); + }, + previousCentroidYOfTouchesChangedAfter: function( + touchHistory, + touchesChangedAfter + ) { + return TouchHistoryMath.centroidDimension( touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - !1, - !1 - ); - }, - currentCentroidX: function(touchHistory) { - return TouchHistoryMath.centroidDimension(touchHistory, 0, !0, !0); - }, - currentCentroidY: function(touchHistory) { - return TouchHistoryMath.centroidDimension(touchHistory, 0, !1, !0); - }, - noCentroid: -1 + touchesChangedAfter, + !1, + !1 + ); + }, + currentCentroidX: function(touchHistory) { + return TouchHistoryMath.centroidDimension(touchHistory, 0, !0, !0); }, - objects = {}, + currentCentroidY: function(touchHistory) { + return TouchHistoryMath.centroidDimension(touchHistory, 0, !1, !0); + }, + noCentroid: -1 +}; +function getComponentName(fiber) { + fiber = fiber.type; + if ("function" === typeof fiber) return fiber.displayName || fiber.name; + if ("string" === typeof fiber) return fiber; + switch (fiber) { + case REACT_FRAGMENT_TYPE: + return "ReactFragment"; + case REACT_PORTAL_TYPE: + return "ReactPortal"; + case REACT_CALL_TYPE: + return "ReactCall"; + case REACT_RETURN_TYPE: + return "ReactReturn"; + } + return null; +} +function getStackAddendumByWorkInProgressFiber(workInProgress) { + var info = ""; + do { + a: switch (workInProgress.tag) { + case 0: + case 1: + case 2: + case 5: + var owner = workInProgress._debugOwner, + source = workInProgress._debugSource; + var JSCompiler_inline_result = getComponentName(workInProgress); + var ownerName = null; + owner && (ownerName = getComponentName(owner)); + owner = source; + JSCompiler_inline_result = + "\n in " + + (JSCompiler_inline_result || "Unknown") + + (owner + ? " (at " + + owner.fileName.replace(/^.*[\\\/]/, "") + + ":" + + owner.lineNumber + + ")" + : ownerName ? " (created by " + ownerName + ")" : ""); + break a; + default: + JSCompiler_inline_result = ""; + } + info += JSCompiler_inline_result; + workInProgress = workInProgress["return"]; + } while (workInProgress); + return info; +} +var objects = {}, uniqueID = 1, emptyObject$2 = {}, ReactNativePropRegistry = (function() { @@ -1561,22 +1606,6 @@ function mountSafeCallback(context, callback) { } var ReactCurrentOwner = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner; -function getComponentName(fiber) { - fiber = fiber.type; - if ("function" === typeof fiber) return fiber.displayName || fiber.name; - if ("string" === typeof fiber) return fiber; - switch (fiber) { - case REACT_FRAGMENT_TYPE: - return "ReactFragment"; - case REACT_PORTAL_TYPE: - return "ReactPortal"; - case REACT_CALL_TYPE: - return "ReactCall"; - case REACT_RETURN_TYPE: - return "ReactReturn"; - } - return null; -} function findHostInstance() { return null; } @@ -1988,39 +2017,6 @@ function onCommitRoot(root) { function onCommitUnmount(fiber) { "function" === typeof onCommitFiberUnmount && onCommitFiberUnmount(fiber); } -function getStackAddendumByWorkInProgressFiber(workInProgress) { - var info = ""; - do { - a: switch (workInProgress.tag) { - case 0: - case 1: - case 2: - case 5: - var owner = workInProgress._debugOwner, - source = workInProgress._debugSource; - var JSCompiler_inline_result = getComponentName(workInProgress); - var ownerName = null; - owner && (ownerName = getComponentName(owner)); - owner = source; - JSCompiler_inline_result = - "\n in " + - (JSCompiler_inline_result || "Unknown") + - (owner - ? " (at " + - owner.fileName.replace(/^.*[\\\/]/, "") + - ":" + - owner.lineNumber + - ")" - : ownerName ? " (created by " + ownerName + ")" : ""); - break a; - default: - JSCompiler_inline_result = ""; - } - info += JSCompiler_inline_result; - workInProgress = workInProgress["return"]; - } while (workInProgress); - return info; -} var _require = require("ReactFeatureFlags"), enableGetDerivedStateFromCatch = _require.enableGetDerivedStateFromCatch, debugRenderPhaseSideEffects = _require.debugRenderPhaseSideEffects, @@ -3926,33 +3922,40 @@ function ReactFiberBeginWork( renderExpirationTime ); case 12: - fn = workInProgress.type; - unmaskedContext = workInProgress.pendingProps; - var oldProps = workInProgress.memoizedProps; - props = fn._currentValue; - updateQueue = fn._changedBits; - if ( - hasLegacyContextChanged() || - 0 !== updateQueue || - oldProps !== unmaskedContext - ) { - workInProgress.memoizedProps = unmaskedContext; - oldProps = unmaskedContext.unstable_observedBits; - if (void 0 === oldProps || null === oldProps) oldProps = 1073741823; - workInProgress.stateNode = oldProps; - 0 !== (updateQueue & oldProps) && - propagateContextChange( - workInProgress, - fn, - updateQueue, - renderExpirationTime - ); - renderExpirationTime = unmaskedContext.children; - renderExpirationTime = renderExpirationTime(props); - reconcileChildren(current, workInProgress, renderExpirationTime); - current = workInProgress.child; - } else - current = bailoutOnAlreadyFinishedWork(current, workInProgress); + a: { + fn = workInProgress.type; + unmaskedContext = workInProgress.pendingProps; + updateQueue = workInProgress.memoizedProps; + props = fn._currentValue; + var changedBits = fn._changedBits; + if ( + hasLegacyContextChanged() || + 0 !== changedBits || + updateQueue !== unmaskedContext + ) { + workInProgress.memoizedProps = unmaskedContext; + var observedBits = unmaskedContext.unstable_observedBits; + if (void 0 === observedBits || null === observedBits) + observedBits = 1073741823; + workInProgress.stateNode = observedBits; + if (0 !== (changedBits & observedBits)) + propagateContextChange( + workInProgress, + fn, + changedBits, + renderExpirationTime + ); + else if (updateQueue === unmaskedContext) { + current = bailoutOnAlreadyFinishedWork(current, workInProgress); + break a; + } + renderExpirationTime = unmaskedContext.children; + renderExpirationTime = renderExpirationTime(props); + reconcileChildren(current, workInProgress, renderExpirationTime); + current = workInProgress.child; + } else + current = bailoutOnAlreadyFinishedWork(current, workInProgress); + } return current; default: invariant( @@ -6554,6 +6557,11 @@ var roots = new Map(), "window" !== view && (view = findNumericNodeHandleFiber(view) || "window"); return UIManager.__takeSnapshot(view, options); + }, + computeComponentStackForErrorReporting: function(reactTag) { + return (reactTag = getInstanceFromTag(reactTag)) + ? getStackAddendumByWorkInProgressFiber(reactTag) + : ""; } } }; From 06085d38366373f3135074dc14e2c9871ca4fe29 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Thu, 5 Apr 2018 21:53:07 -0700 Subject: [PATCH 0217/1109] Move TouchHistoryMath from React Repo to React Native Summary: This hasn't been used by React core for a while. It's unclear why it was in the first place. We can move it back next to the Panresponder. https://github.com/facebook/react/pull/12557 Reviewed By: sophiebits Differential Revision: D7529949 fbshipit-source-id: ef9892cfa8d2d6768da216b81befabe02795a245 --- Libraries/Interaction/TouchHistoryMath.js | 151 +++++++++++++++++++ Libraries/Renderer/shims/TouchHistoryMath.js | 17 --- 2 files changed, 151 insertions(+), 17 deletions(-) create mode 100644 Libraries/Interaction/TouchHistoryMath.js delete mode 100644 Libraries/Renderer/shims/TouchHistoryMath.js diff --git a/Libraries/Interaction/TouchHistoryMath.js b/Libraries/Interaction/TouchHistoryMath.js new file mode 100644 index 00000000000000..be5aa707653c36 --- /dev/null +++ b/Libraries/Interaction/TouchHistoryMath.js @@ -0,0 +1,151 @@ +/** + * Copyright (c) 2016-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +const TouchHistoryMath = { + /** + * This code is optimized and not intended to look beautiful. This allows + * computing of touch centroids that have moved after `touchesChangedAfter` + * timeStamp. You can compute the current centroid involving all touches + * moves after `touchesChangedAfter`, or you can compute the previous + * centroid of all touches that were moved after `touchesChangedAfter`. + * + * @param {TouchHistoryMath} touchHistory Standard Responder touch track + * data. + * @param {number} touchesChangedAfter timeStamp after which moved touches + * are considered "actively moving" - not just "active". + * @param {boolean} isXAxis Consider `x` dimension vs. `y` dimension. + * @param {boolean} ofCurrent Compute current centroid for actively moving + * touches vs. previous centroid of now actively moving touches. + * @return {number} value of centroid in specified dimension. + */ + centroidDimension: function( + touchHistory, + touchesChangedAfter, + isXAxis, + ofCurrent, + ) { + const touchBank = touchHistory.touchBank; + let total = 0; + let count = 0; + + const oneTouchData = + touchHistory.numberActiveTouches === 1 + ? touchHistory.touchBank[touchHistory.indexOfSingleActiveTouch] + : null; + + if (oneTouchData !== null) { + if ( + oneTouchData.touchActive && + oneTouchData.currentTimeStamp > touchesChangedAfter + ) { + total += + ofCurrent && isXAxis + ? oneTouchData.currentPageX + : ofCurrent && !isXAxis + ? oneTouchData.currentPageY + : !ofCurrent && isXAxis + ? oneTouchData.previousPageX + : oneTouchData.previousPageY; + count = 1; + } + } else { + for (let i = 0; i < touchBank.length; i++) { + const touchTrack = touchBank[i]; + if ( + touchTrack !== null && + touchTrack !== undefined && + touchTrack.touchActive && + touchTrack.currentTimeStamp >= touchesChangedAfter + ) { + let toAdd; // Yuck, program temporarily in invalid state. + if (ofCurrent && isXAxis) { + toAdd = touchTrack.currentPageX; + } else if (ofCurrent && !isXAxis) { + toAdd = touchTrack.currentPageY; + } else if (!ofCurrent && isXAxis) { + toAdd = touchTrack.previousPageX; + } else { + toAdd = touchTrack.previousPageY; + } + total += toAdd; + count++; + } + } + } + return count > 0 ? total / count : TouchHistoryMath.noCentroid; + }, + + currentCentroidXOfTouchesChangedAfter: function( + touchHistory, + touchesChangedAfter, + ) { + return TouchHistoryMath.centroidDimension( + touchHistory, + touchesChangedAfter, + true, // isXAxis + true, // ofCurrent + ); + }, + + currentCentroidYOfTouchesChangedAfter: function( + touchHistory, + touchesChangedAfter, + ) { + return TouchHistoryMath.centroidDimension( + touchHistory, + touchesChangedAfter, + false, // isXAxis + true, // ofCurrent + ); + }, + + previousCentroidXOfTouchesChangedAfter: function( + touchHistory, + touchesChangedAfter, + ) { + return TouchHistoryMath.centroidDimension( + touchHistory, + touchesChangedAfter, + true, // isXAxis + false, // ofCurrent + ); + }, + + previousCentroidYOfTouchesChangedAfter: function( + touchHistory, + touchesChangedAfter, + ) { + return TouchHistoryMath.centroidDimension( + touchHistory, + touchesChangedAfter, + false, // isXAxis + false, // ofCurrent + ); + }, + + currentCentroidX: function(touchHistory) { + return TouchHistoryMath.centroidDimension( + touchHistory, + 0, // touchesChangedAfter + true, // isXAxis + true, // ofCurrent + ); + }, + + currentCentroidY: function(touchHistory) { + return TouchHistoryMath.centroidDimension( + touchHistory, + 0, // touchesChangedAfter + false, // isXAxis + true, // ofCurrent + ); + }, + + noCentroid: -1, +}; + +module.exports = TouchHistoryMath; diff --git a/Libraries/Renderer/shims/TouchHistoryMath.js b/Libraries/Renderer/shims/TouchHistoryMath.js deleted file mode 100644 index 75edb24a7209c4..00000000000000 --- a/Libraries/Renderer/shims/TouchHistoryMath.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule TouchHistoryMath - */ - -'use strict'; - -const { - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, -} = require('ReactNative'); - -module.exports = - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.TouchHistoryMath; From 95f625e151c7abbb05efcd14404c8aa9583faa83 Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Thu, 5 Apr 2018 22:01:35 -0700 Subject: [PATCH 0218/1109] Fixed RNTester (iOS) xcode project to include new Yoga files Summary: Recent commit that added YGConfig.h broke this project because the files were not added to it. Reviewed By: shergin Differential Revision: D7530369 fbshipit-source-id: 77129288905d25b94ad7aad4be43e0052a784163 --- React/React.xcodeproj/project.pbxproj | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj index dbc8cef8aad008..e9d07dd8d9e8ff 100644 --- a/React/React.xcodeproj/project.pbxproj +++ b/React/React.xcodeproj/project.pbxproj @@ -1147,6 +1147,8 @@ 59EDBCC61FDF4E55003573DE /* (null) in Copy Headers */ = {isa = PBXBuildFile; }; 59EDBCC71FDF4E55003573DE /* RCTScrollView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 59EDBCA31FDF4E0C003573DE /* RCTScrollView.h */; }; 59EDBCC81FDF4E55003573DE /* RCTScrollViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 59EDBCA51FDF4E0C003573DE /* RCTScrollViewManager.h */; }; + 5CE2080220772F7D009A43B3 /* YGConfig.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5CE2080020772F7C009A43B3 /* YGConfig.cpp */; }; + 5CE2080320772F7D009A43B3 /* YGConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CE2080120772F7C009A43B3 /* YGConfig.h */; }; 657734841EE834C900A0E9EA /* RCTInspectorDevServerHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 657734821EE834C900A0E9EA /* RCTInspectorDevServerHelper.h */; }; 657734851EE834C900A0E9EA /* RCTInspectorDevServerHelper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 657734831EE834C900A0E9EA /* RCTInspectorDevServerHelper.mm */; }; 657734861EE834D900A0E9EA /* RCTInspectorDevServerHelper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 657734831EE834C900A0E9EA /* RCTInspectorDevServerHelper.mm */; }; @@ -2237,6 +2239,8 @@ 59EDBCA41FDF4E0C003573DE /* RCTScrollView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTScrollView.m; sourceTree = ""; }; 59EDBCA51FDF4E0C003573DE /* RCTScrollViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTScrollViewManager.h; sourceTree = ""; }; 59EDBCA61FDF4E0C003573DE /* RCTScrollViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTScrollViewManager.m; sourceTree = ""; }; + 5CE2080020772F7C009A43B3 /* YGConfig.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YGConfig.cpp; sourceTree = ""; }; + 5CE2080120772F7C009A43B3 /* YGConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGConfig.h; sourceTree = ""; }; 657734821EE834C900A0E9EA /* RCTInspectorDevServerHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTInspectorDevServerHelper.h; sourceTree = ""; }; 657734831EE834C900A0E9EA /* RCTInspectorDevServerHelper.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RCTInspectorDevServerHelper.mm; sourceTree = ""; }; 6577348A1EE8354A00A0E9EA /* RCTInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RCTInspector.h; path = Inspector/RCTInspector.h; sourceTree = ""; }; @@ -2355,6 +2359,8 @@ 130A77021DF767AF001F9587 /* yoga */ = { isa = PBXGroup; children = ( + 5CE2080020772F7C009A43B3 /* YGConfig.cpp */, + 5CE2080120772F7C009A43B3 /* YGConfig.h */, 53DEF6E6205AE59B006A3890 /* YGFloatOptional.cpp */, 53DEF6E7205AE59C006A3890 /* YGFloatOptional.h */, 5343895E203905B6008E0CB3 /* YGLayout.cpp */, @@ -3561,6 +3567,7 @@ 59EDBCAD1FDF4E0C003573DE /* RCTScrollContentView.h in Headers */, 59EDBCA71FDF4E0C003573DE /* RCTScrollableProtocol.h in Headers */, 591F78DC202ADB22004A668C /* RCTLayout.h in Headers */, + 5CE2080320772F7D009A43B3 /* YGConfig.h in Headers */, 3D80DA631DF820620028D040 /* RCTBorderDrawing.h in Headers */, 3D80DA641DF820620028D040 /* RCTBorderStyle.h in Headers */, 3D80DA651DF820620028D040 /* RCTComponent.h in Headers */, @@ -4538,6 +4545,7 @@ 13A1F71E1A75392D00D3D453 /* RCTKeyCommands.m in Sources */, 83CBBA531A601E3B00E9B192 /* RCTUtils.m in Sources */, 130443C61E401A8C00D93A67 /* RCTConvert+Transform.m in Sources */, + 5CE2080220772F7D009A43B3 /* YGConfig.cpp in Sources */, 191E3EC11C29DC3800C180A6 /* RCTRefreshControl.m in Sources */, 3DCE532B1FEAB23100613583 /* RCTDatePickerManager.m in Sources */, 13C156051AB1A2840079392D /* RCTWebView.m in Sources */, From c6610577fd6f6ad443f96669fb39a2197e33434e Mon Sep 17 00:00:00 2001 From: Angly Cat Date: Fri, 6 Apr 2018 09:49:56 -0700 Subject: [PATCH 0219/1109] Fix launching iOS simulator regression Summary: PR #17284 (accepted in 2ad34075f1d048bebb08ef30799ac0d081073150) introduced a couple of regressions. ~1. There's the code:~ ``` .then((appName) => resolve(selectedSimulator.udid, appName)); /* ... */ .then((udid, appName) => { ``` ~~This makes `appName` to be always `undefined` as per `resolve` accepts only 1 argument. This regression causes issues if an app name differs from a scheme name.~ ~This PR fixes this by wrapping both values in an array.~ This was fixed in 589eae1432cc4bbc16221f841e27b038099fd128. 2. The code ``` child_process.execFileSync('xcrun', ['simctl', 'boot', selectedSimulator.udid]); ``` makes a simulator *boot*, but the simulator *doesn't launch*. That's a regression, which forces developers to launch simulators by other means (by running a number of elaborate console commands, by running Xcode, or by running a simulator manually). This PR reverts that part of changes. Create a blank project with a name that differs from scheme name. Try to `react-native run-ios` in it. See that a simulator is launched and installing succeeds. Without this changes simulator wouldn't launch, and installing step would fail because of app name mismatch. [CLI][BUGFIX][local-cli/runIOS/runIOS.js] - Fix running on multiple simulators feature regressions Closes https://github.com/facebook/react-native/pull/18711 Differential Revision: D7535150 Pulled By: hramos fbshipit-source-id: 5c714231e9977c0c829b6f8c793497cd31cd46b5 --- local-cli/runIOS/runIOS.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/local-cli/runIOS/runIOS.js b/local-cli/runIOS/runIOS.js index 8927be98d80226..1cbcc4108db727 100644 --- a/local-cli/runIOS/runIOS.js +++ b/local-cli/runIOS/runIOS.js @@ -115,15 +115,12 @@ function runOnSimulator(xcodeProject, args, scheme) { if (!selectedSimulator.booted) { const simulatorFullName = formattedDeviceName(selectedSimulator); - console.log(`Booting ${simulatorFullName}...`); + console.log(`Launching ${simulatorFullName}...`); try { - child_process.execFileSync('xcrun', ['simctl', 'boot', selectedSimulator.udid]); + child_process.spawnSync('xcrun', ['instruments', '-w', selectedSimulator.udid]); } catch (e) { - throw new Error( -`Could not boot ${args.simulator} simulator. Is there already a simulator running? -Running multiple simulators is only supported from Xcode 9 and up. -Try closing the simulator or run the command again without specifying a simulator.` - ); + // instruments always fail with 255 because it expects more arguments, + // but we want it to only launch the simulator } } From 159869d250c8d8a7a43c3cfcd114ad8bc674e23e Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Fri, 6 Apr 2018 10:36:56 -0700 Subject: [PATCH 0220/1109] Fix: "Metro listenting on port undefined" Summary: Regression introduced in https://github.com/facebook/react-native/commit/2ad34075f1d048bebb08ef30799ac0d081073150. Fixes https://github.com/facebook/react-native/issues/18681 Closes https://github.com/facebook/react-native/pull/18722 Differential Revision: D7535684 Pulled By: hramos fbshipit-source-id: 21bc79091148daba7b668965cd5becaa43117721 --- local-cli/runIOS/runIOS.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/local-cli/runIOS/runIOS.js b/local-cli/runIOS/runIOS.js index 1cbcc4108db727..ba6e844b5c2a28 100644 --- a/local-cli/runIOS/runIOS.js +++ b/local-cli/runIOS/runIOS.js @@ -124,10 +124,10 @@ function runOnSimulator(xcodeProject, args, scheme) { } } - buildProject(xcodeProject, selectedSimulator.udid, scheme, args.configuration, args.packager, args.verbose) - .then((appName) => resolve(selectedSimulator.udid, appName)); + buildProject(xcodeProject, selectedSimulator.udid, scheme, args.configuration, args.packager, args.verbose, args.port) + .then((appName) => resolve({ udid: selectedSimulator.udid, appName })); }) - .then((udid, appName) => { + .then(({udid, appName}) => { if (!appName) { appName = scheme; } From c2b9be08f8a20b080859e0d245e0cd1140522836 Mon Sep 17 00:00:00 2001 From: "Andrew Chen (Eng)" Date: Fri, 6 Apr 2018 12:31:02 -0700 Subject: [PATCH 0221/1109] Thread safe renderComponent Reviewed By: mdvacca Differential Revision: D7528307 fbshipit-source-id: 1f22898c17f10b883965b03d5c95bbb3c39209c4 --- .../ReactAppInstrumentationTestCase.java | 19 ++----- .../react/testing/ReactAppTestActivity.java | 55 ++++++++++++++----- .../testing/ReactInstrumentationTest.java | 30 ++-------- 3 files changed, 51 insertions(+), 53 deletions(-) diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppInstrumentationTestCase.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppInstrumentationTestCase.java index 863e249cbfe375..b01d0542af4b12 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppInstrumentationTestCase.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppInstrumentationTestCase.java @@ -37,21 +37,10 @@ protected void setUp() throws Exception { intent.putExtra(ReactAppTestActivity.EXTRA_IS_FABRIC_TEST, isFabricTest()); setActivityIntent(intent); final ReactAppTestActivity activity = getActivity(); - try { - runTestOnUiThread(new Runnable() { - @Override - public void run() { - activity.loadApp( - getReactApplicationKeyUnderTest(), - createReactInstanceSpecForTest(), - getEnableDevSupport()); - } - }); - } catch (Throwable t) { - throw new Exception("Unable to load react app", t); - } - waitForBridgeAndUIIdle(); - assertTrue("Layout never occurred!", activity.waitForLayout(5000)); + activity.loadApp( + getReactApplicationKeyUnderTest(), + createReactInstanceSpecForTest(), + getEnableDevSupport()); waitForBridgeAndUIIdle(); } diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java index 341c8781494238..de18fad93e27ce 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java @@ -11,6 +11,7 @@ import android.graphics.Bitmap; import android.os.Bundle; import android.support.v4.app.FragmentActivity; +import android.util.Log; import android.view.View; import android.view.ViewTreeObserver; import android.widget.FrameLayout; @@ -180,17 +181,32 @@ public void loadApp( renderComponent(appKey, initialProps); } - public void renderComponent(String appKey, @Nullable Bundle initialProps) { + public void renderComponent(String appKey) { + renderComponent(appKey, null); + } + + public void renderComponent(final String appKey, final @Nullable Bundle initialProps) { final CountDownLatch currentLayoutEvent = mLayoutEvent = new CountDownLatch(1); - Assertions.assertNotNull(mReactRootView).getViewTreeObserver().addOnGlobalLayoutListener( - new ViewTreeObserver.OnGlobalLayoutListener() { - @Override - public void onGlobalLayout() { - currentLayoutEvent.countDown(); - } - }); - Assertions.assertNotNull(mReactRootView) - .startReactApplication(mReactInstanceManager, appKey, initialProps); + runOnUiThread(new Runnable() { + @Override + public void run() { + Assertions.assertNotNull(mReactRootView).getViewTreeObserver().addOnGlobalLayoutListener( + new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + currentLayoutEvent.countDown(); + } + }); + Assertions.assertNotNull(mReactRootView) + .startReactApplication(mReactInstanceManager, appKey, initialProps); + } + }); + try { + waitForBridgeAndUIIdle(); + waitForLayout(5000); + } catch (InterruptedException e) { + throw new RuntimeException("Layout never occurred for component " + appKey, e); + } } public void loadBundle( @@ -208,7 +224,7 @@ public void loadBundle( mBridgeIdleSignaler = new ReactBridgeIdleSignaler(); - ReactInstanceManagerBuilder builder = + final ReactInstanceManagerBuilder builder = ReactTestHelper.getReactTestFactory() .getReactInstanceManagerBuilder() .setApplication(getApplication()) @@ -259,8 +275,21 @@ public FabricUIManager getJSIModule() { }}) .setUIImplementationProvider(uiImplementationProvider); - mReactInstanceManager = builder.build(); - mReactInstanceManager.onHostResume(this, this); + final CountDownLatch latch = new CountDownLatch(1); + runOnUiThread(new Runnable() { + @Override + public void run() { + mReactInstanceManager = builder.build(); + mReactInstanceManager.onHostResume(ReactAppTestActivity.this, ReactAppTestActivity.this); + latch.countDown(); + } + }); + try { + latch.await(1000, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + throw new RuntimeException( + "ReactInstanceManager never finished initializing " + bundleName, e); + } } private ReactInstanceManager getReactInstanceManager() { diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactInstrumentationTest.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactInstrumentationTest.java index 3f0a7e250bfa72..20dcc3ef516cf8 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactInstrumentationTest.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactInstrumentationTest.java @@ -37,37 +37,17 @@ protected void setUp() throws Exception { intent.putExtra(ReactAppTestActivity.EXTRA_IS_FABRIC_TEST, isFabricTest()); setActivityIntent(intent); final ReactAppTestActivity activity = getActivity(); - try { - runTestOnUiThread(new Runnable() { - @Override - public void run() { - activity.loadBundle( - createReactInstanceSpecForTest(), - getBundleName(), - getEnableDevSupport()); - } - }); - } catch (Throwable t) { - throw new Exception("Unable to load react bundle " + getBundleName(), t); - } + activity.loadBundle( + createReactInstanceSpecForTest(), + getBundleName(), + getEnableDevSupport()); } /** * Renders this component within this test's activity */ public void renderComponent(final String componentName) throws Exception { - final ReactAppTestActivity activity = getActivity(); - try { - runTestOnUiThread(new Runnable() { - @Override - public void run() { - activity.renderComponent(componentName, null); - } - }); - } catch (Throwable t) { - throw new Exception("Unable to render component " + componentName, t); - } - assertTrue("Layout never occurred!", activity.waitForLayout(5000)); + getActivity().renderComponent(componentName, null); waitForBridgeAndUIIdle(); } From 9736ddc061e9c4291df8a3185c7f9d6f73e435c7 Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Fri, 6 Apr 2018 14:10:12 -0700 Subject: [PATCH 0222/1109] Fix `run-ios` not turning on Simulator app Summary: Right now, `run-ios` will "boot" Simulator in the headless mode in the background, as long as the Simulator.app is not running. It is exactly what "detox" does - it executes your test suite in the background. It seems to me that the author of this change was testing it with `Simulator.app` open. In order to fix this behavior, we have to make sure it runs before we attempt booting. This passed through the release process since we don't use `run-ios` there (it recommends turning on XCode and testing manually which is what I have done recently too). Differential Revision: D7535693 Pulled By: hramos fbshipit-source-id: 881db7740ace805ecefb98bfdb660e32aafd4664 --- local-cli/runIOS/runIOS.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/local-cli/runIOS/runIOS.js b/local-cli/runIOS/runIOS.js index ba6e844b5c2a28..de72569de6e4b9 100644 --- a/local-cli/runIOS/runIOS.js +++ b/local-cli/runIOS/runIOS.js @@ -112,6 +112,24 @@ function runOnSimulator(xcodeProject, args, scheme) { if (!selectedSimulator) { throw new Error(`Could not find ${args.simulator} simulator`); } + + /** + * Booting simulator through `xcrun simctl boot` will boot it in the `headless` mode + * (running in the background). + * + * In order for user to see the app and the simulator itself, we have to make sure + * that the Simulator.app is running. + * + * We also pass it `-CurrentDeviceUDID` so that when we launch it for the first time, + * it will not boot the "default" device, but the one we set. If the app is already running, + * this flag has no effect. + */ + child_process.execFileSync('open', [ + '/Applications/Xcode.app/Contents/Developer/Applications/Simulator.app', + '--args', + '-CurrentDeviceUDID', + selectedSimulator.udid + ]); if (!selectedSimulator.booted) { const simulatorFullName = formattedDeviceName(selectedSimulator); From e21bbee5862eaf08c8f198fa18a32350f5caabbc Mon Sep 17 00:00:00 2001 From: David Vacca Date: Fri, 6 Apr 2018 15:01:13 -0700 Subject: [PATCH 0223/1109] Mutate shared ReactShadowNode during Fabric.appendChild Reviewed By: shergin Differential Revision: D7495539 fbshipit-source-id: 2b2b06d3d4f02a00b01c7ed27d47b61787ea922f --- .../java/com/facebook/react/fabric/FabricUIManager.java | 6 ++++++ 1 file changed, 6 insertions(+) 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 2cadd153c3f1a7..52519e9d31291f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -216,6 +216,12 @@ public void appendChild(ReactShadowNode parent, ReactShadowNode child) { Log.d(TAG, "appendChild \n\tparent: " + parent + "\n\tchild: " + child); } try { + // If the child to append is shared with another tree (child.getParent() != null), + // then we add a mutation of it. In the future this will be performed by FabricJS / Fiber. + //TODO: T27926878 avoid cloning shared child + if (child.getParent() != null) { + child = child.mutableCopy(); + } parent.addChildAt(child, parent.getChildCount()); } catch (Throwable t) { handleException(parent, t); From 84ae1c9aecf38fdb1e02e0dea3ee7f9e73728e9f Mon Sep 17 00:00:00 2001 From: David Vacca Date: Fri, 6 Apr 2018 15:01:15 -0700 Subject: [PATCH 0224/1109] Move execution of Yoga.calculateLayout method before diffing algorithm Reviewed By: shergin Differential Revision: D7495581 fbshipit-source-id: 63d2f2a66c53727dea7981837d6d0f896bac35d3 --- .../react/fabric/FabricUIManager.java | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) 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 52519e9d31291f..0e7f8e7724a637 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -256,20 +256,12 @@ public synchronized void completeRoot(int rootTag, List childLi currentRootShadowNode, "Root view with tag " + rootTag + " must be added before completeRoot is called"); - currentRootShadowNode = calculateDiffingAndCreateNewRootNode(currentRootShadowNode, childList); - if (DEBUG) { - Log.d(TAG, "ReactShadowNodeHierarchy after diffing: " + currentRootShadowNode.getHierarchyInfo()); - } - - notifyOnBeforeLayoutRecursive(currentRootShadowNode); - currentRootShadowNode.calculateLayout(); - if (DEBUG) { Log.d( TAG, - "ReactShadowNodeHierarchy after calculate Layout: " + currentRootShadowNode.getHierarchyInfo()); + "ReactShadowNodeHierarchy after diffing: " + currentRootShadowNode.getHierarchyInfo()); } applyUpdatesRecursive(currentRootShadowNode, 0, 0); @@ -299,6 +291,21 @@ private ReactShadowNode calculateDiffingAndCreateNewRootNode( appendChild(newRootShadowNode, child); } + if (DEBUG) { + Log.d( + TAG, + "ReactShadowNodeHierarchy before calculateLayout: " + newRootShadowNode.getHierarchyInfo()); + } + + notifyOnBeforeLayoutRecursive(newRootShadowNode); + newRootShadowNode.calculateLayout(); + + if (DEBUG) { + Log.d( + TAG, + "ReactShadowNodeHierarchy after calculateLayout: " + newRootShadowNode.getHierarchyInfo()); + } + mFabricReconciler.manageChildren(currentRootShadowNode, newRootShadowNode); return newRootShadowNode; } From 9fd2b9a75fe3128de80230d5a1faf7d72e916cb0 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Fri, 6 Apr 2018 15:01:17 -0700 Subject: [PATCH 0225/1109] Add more logs into FabricUIManager and ReactShadowNodeImpl Reviewed By: shergin, achen1 Differential Revision: D7495615 fbshipit-source-id: 4227b6648aaff8d9fe59bff1d4f75fd546baae6a --- .../react/fabric/FabricUIManager.java | 2 +- .../react/uimanager/ReactShadowNodeImpl.java | 28 +++++++++++++------ 2 files changed, 21 insertions(+), 9 deletions(-) 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 0e7f8e7724a637..2eda32a0ee9f97 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -305,7 +305,7 @@ private ReactShadowNode calculateDiffingAndCreateNewRootNode( TAG, "ReactShadowNodeHierarchy after calculateLayout: " + newRootShadowNode.getHierarchyInfo()); } - + mFabricReconciler.manageChildren(currentRootShadowNode, newRootShadowNode); return newRootShadowNode; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java index c5727e664e4c1b..1e92ab47858150 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java @@ -8,6 +8,7 @@ import static java.lang.System.arraycopy; +import android.util.Log; import com.facebook.infer.annotation.Assertions; import com.facebook.react.uimanager.annotations.ReactPropertyHolder; import com.facebook.yoga.YogaNodeCloneFunction; @@ -58,6 +59,8 @@ @ReactPropertyHolder public class ReactShadowNodeImpl implements ReactShadowNode { + private static final boolean DEBUG = true; + private static final String TAG = ReactShadowNodeImpl.class.getSimpleName(); private static final YogaConfig sYogaConfig; static { sYogaConfig = ReactYogaConfigProvider.get(); @@ -68,10 +71,17 @@ public YogaNode cloneNode(YogaNode oldYogaNode, int childIndex) { ReactShadowNodeImpl parentReactShadowNode = (ReactShadowNodeImpl) parent.getData(); Assertions.assertNotNull(parentReactShadowNode); - ReactShadowNodeImpl newReactShadowNode = (ReactShadowNodeImpl) oldYogaNode.getData(); - Assertions.assertNotNull(newReactShadowNode); + ReactShadowNodeImpl oldReactShadowNode = (ReactShadowNodeImpl) oldYogaNode.getData(); + Assertions.assertNotNull(oldReactShadowNode); + + if (DEBUG) { + Log.d( + TAG, + "YogaNode started cloning: oldYogaNode: " + oldReactShadowNode + " - parent: " + + parentReactShadowNode + " index: " + childIndex); + } - ReactShadowNodeImpl newNode = newReactShadowNode.mutableCopy(); + ReactShadowNodeImpl newNode = oldReactShadowNode.mutableCopy(); parentReactShadowNode.replaceChild(newNode, childIndex); return newNode.mYogaNode; } @@ -1044,17 +1054,19 @@ public String getHierarchyInfo() { private void getHierarchyInfoWithIndentation(StringBuilder result, int level) { // Spaces and tabs are dropped by IntelliJ logcat integration, so rely on __ instead. for (int i = 0; i < level; ++i) { - result.append("__"); + result.append(" "); } - result.append(getClass().getSimpleName()).append(" ").append(getReactTag()).append(" "); + result.append("<").append(getClass().getSimpleName()).append(" tag=").append(getReactTag()).append(" hash=") + .append(hashCode()); if (mYogaNode != null) { - result.append(getScreenX()).append(";").append(getScreenY()).append(";") - .append(getLayoutWidth()).append(";").append(getLayoutHeight()); + result.append(" layout='x:").append(getScreenX()) + .append(" y:").append(getScreenY()).append(" w:").append(getLayoutWidth()).append(" h:") + .append(getLayoutHeight()).append("'"); } else { result.append("(virtual node)"); } - result.append("\n"); + result.append(">\n"); if (getChildCount() == 0) { return; From bf7601fde102114eda1144b48d2cfbc8dd7c95c1 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Fri, 6 Apr 2018 15:01:19 -0700 Subject: [PATCH 0226/1109] Avoid holding references to ReactShadowNode after a tree is commited Reviewed By: achen1 Differential Revision: D7495721 fbshipit-source-id: 33d5bba5040729f891455a9c330234fe25130b02 --- .../react/fabric/FabricUIManager.java | 3 ++ .../react/uimanager/ReactShadowNodeImpl.java | 35 ++++++------------- 2 files changed, 14 insertions(+), 24 deletions(-) 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 2eda32a0ee9f97..50e24738bf5699 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -329,6 +329,9 @@ private void applyUpdatesRecursive(ReactShadowNode node, float absoluteX, float boolean frameDidChange = node.dispatchUpdates(absoluteX, absoluteY, mUIViewOperationQueue, null); } + // Set the reference to the OriginalReactShadowNode to NULL, as the tree is already committed + // and we do not need to hold references to the previous tree anymore + node.setOriginalReactShadowNode(null); node.markUpdateSeen(); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java index 1e92ab47858150..7d08bd08ec6526 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java @@ -131,13 +131,16 @@ protected ReactShadowNodeImpl(ReactShadowNodeImpl original) { mViewClassName = original.mViewClassName; mThemedContext = original.mThemedContext; mShouldNotifyOnLayout = original.mShouldNotifyOnLayout; - mNodeUpdated = original.mNodeUpdated; mIsLayoutOnly = original.mIsLayoutOnly; mNativeParent = original.mNativeParent; - mScreenX = original.mScreenX; - mScreenY = original.mScreenY; - mScreenWidth = original.mScreenWidth; - mScreenHeight = original.mScreenHeight; + // Cloned nodes should be always updated. + mNodeUpdated = true; + // "cached" screen coordinates are not cloned because FabricJS not always clone the last + // ReactShadowNode that was rendered in the screen. + mScreenX = 0; + mScreenY = 0; + mScreenWidth = 0; + mScreenHeight = 0; arraycopy(original.mPadding, 0, mPadding, 0, original.mPadding.length); arraycopy(original.mPaddingIsPercent, 0, mPaddingIsPercent, 0, original.mPaddingIsPercent.length); mNewProps = null; @@ -148,6 +151,7 @@ protected ReactShadowNodeImpl(ReactShadowNodeImpl original) { private void replaceChild(ReactShadowNodeImpl newNode, int childIndex) { mChildren.remove(childIndex); mChildren.add(childIndex, newNode); + newNode.mParent = this; } /** @@ -164,14 +168,7 @@ public ReactShadowNodeImpl mutableCopy() { copy.mNativeChildren = mNativeChildren == null ? null : new ArrayList<>(mNativeChildren); copy.mTotalNativeChildren = mTotalNativeChildren; copy.mChildren = mChildren == null ? null : new ArrayList<>(mChildren); - copy.mYogaNode.setData(this); - if (mChildren != null) { - for (ReactShadowNode child : mChildren) { - if (child.getOriginalReactShadowNode() == null) { - child.setOriginalReactShadowNode(child); - } - } - } + copy.mYogaNode.setData(copy); return copy; } @@ -182,7 +179,7 @@ public ReactShadowNodeImpl mutableCopyWithNewChildren() { copy.mNativeChildren = null; copy.mChildren = null; copy.mTotalNativeChildren = 0; - copy.mYogaNode.setData(this); + copy.mYogaNode.setData(copy); return copy; } @@ -306,16 +303,6 @@ public void addChildAt(ReactShadowNodeImpl child, int i) { + toString() + "')"); } - // TODO: T26729293 This is a temporary code that will be replaced as part of T26729293. - YogaNode parent = childYogaNode.getOwner(); - if (parent != null) { - for (int k = 0; k < parent.getChildCount(); k++) { - if (parent.getChildAt(k) == childYogaNode) { - parent.removeChildAt(k); - break; - } - } - } mYogaNode.addChildAt(childYogaNode, i); } markUpdated(); From b0fa3228a77d89d6736da6fcae5dd32f74f3052c Mon Sep 17 00:00:00 2001 From: Dulmandakh Date: Fri, 6 Apr 2018 15:57:09 -0700 Subject: [PATCH 0227/1109] Implement Image.defaultSource property on Android Summary: This pull request implements Image.defaultSource property on Android, using Fresco (http://frescolib.org/docs/placeholder-failure-retry.html), which will show placeholder image (local asset) while loading remote image. Implementation code is almost same with loadingIndicatorSource, but without rotation. This requires release or production to bundle local images in an APK file. This provides feature parity with iOS. Set Image.defaultSource on Android, and will show it while loading Image.source. ```JSX ')} source={{uri: ''}} style={{ height: 300, width: 300 }} /> ``` [ANDROID] [FEATURE] [IMAGE] - Image.defaultSource will show local image as placeholder while loading remote Image.source. Closes https://github.com/facebook/react-native/pull/18588 Differential Revision: D7540489 Pulled By: himabindugadupudi fbshipit-source-id: 908ceb659b3416e517bba64c76a31879d965ec09 --- Libraries/Image/Image.android.js | 15 +++++++++++++++ .../react/views/image/ReactImageManager.java | 6 ++++++ .../react/views/image/ReactImageView.java | 10 ++++++++++ 3 files changed, 31 insertions(+) diff --git a/Libraries/Image/Image.android.js b/Libraries/Image/Image.android.js index 4e218487c9b505..870b31cd8f92cb 100644 --- a/Libraries/Image/Image.android.js +++ b/Libraries/Image/Image.android.js @@ -74,6 +74,10 @@ var Image = createReactClass({ * See https://facebook.github.io/react-native/docs/image.html#blurradius */ blurRadius: PropTypes.number, + /** + * See https://facebook.github.io/react-native/docs/image.html#defaultsource + */ + defaultSource: PropTypes.number, /** * See https://facebook.github.io/react-native/docs/image.html#loadingindicatorsource */ @@ -197,6 +201,7 @@ var Image = createReactClass({ render: function() { const source = resolveAssetSource(this.props.source); + const defaultSource = resolveAssetSource(this.props.defaultSource); const loadingIndicatorSource = resolveAssetSource( this.props.loadingIndicatorSource, ); @@ -220,6 +225,12 @@ var Image = createReactClass({ ); } + if (this.props.defaultSource && this.props.loadingIndicatorSource) { + throw new Error( + 'The component cannot have defaultSource and loadingIndicatorSource at the same time. Please use either defaultSource or loadingIndicatorSource.', + ); + } + if (source && (source.uri || Array.isArray(source))) { let style; let sources; @@ -243,6 +254,9 @@ var Image = createReactClass({ ), src: sources, headers: source.headers, + defaultSrc: defaultSource + ? defaultSource.uri + : null, loadingIndicatorSrc: loadingIndicatorSource ? loadingIndicatorSource.uri : null, @@ -268,6 +282,7 @@ var cfg = { nativeOnly: { src: true, headers: true, + defaultSrc: true, loadingIndicatorSrc: true, shouldNotifyLoadEvents: true, }, diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java index 938524d3012156..2565e2294ef1c6 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java @@ -88,6 +88,12 @@ public void setBlurRadius(ReactImageView view, float blurRadius) { view.setBlurRadius(blurRadius); } + // In JS this is Image.props.defaultSource + @ReactProp(name = "defaultSrc") + public void setDefaultSource(ReactImageView view, @Nullable String source) { + view.setDefaultSource(source); + } + // In JS this is Image.props.loadingIndicatorSource.uri @ReactProp(name = "loadingIndicatorSrc") public void setLoadingIndicatorSource(ReactImageView view, @Nullable String source) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java index 9ab9c8884e800c..cb294cbb93d7eb 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java @@ -184,6 +184,7 @@ public CloseableReference process(Bitmap source, PlatformBitmapFactory b private @Nullable ImageSource mImageSource; private @Nullable ImageSource mCachedImageSource; + private @Nullable Drawable mDefaultImageDrawable; private @Nullable Drawable mLoadingImageDrawable; private @Nullable RoundedColorDrawable mBackgroundImageDrawable; private int mBackgroundColor = 0x00000000; @@ -369,6 +370,11 @@ public void setSource(@Nullable ReadableArray sources) { mIsDirty = true; } + public void setDefaultSource(@Nullable String name) { + mDefaultImageDrawable = ResourceDrawableIdHelper.getInstance().getResourceDrawable(getContext(), name); + mIsDirty = true; + } + public void setLoadingIndicatorSource(@Nullable String name) { Drawable drawable = ResourceDrawableIdHelper.getInstance().getResourceDrawable(getContext(), name); mLoadingImageDrawable = @@ -428,6 +434,10 @@ public void maybeUpdateView() { GenericDraweeHierarchy hierarchy = getHierarchy(); hierarchy.setActualImageScaleType(mScaleType); + if (mDefaultImageDrawable != null) { + hierarchy.setPlaceholderImage(mDefaultImageDrawable, ScalingUtils.ScaleType.CENTER); + } + if (mLoadingImageDrawable != null) { hierarchy.setPlaceholderImage(mLoadingImageDrawable, ScalingUtils.ScaleType.CENTER); } From 667ca15893f4ef0538ed34dd93a2c04696e01240 Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Fri, 6 Apr 2018 17:16:55 -0700 Subject: [PATCH 0228/1109] android: don't process touch events too early Summary: There can be a race when loading JS from rootview for the first time vs touching rootview before JS is ready. This may cause redbox on the JS side. Reviewed By: mdvacca Differential Revision: D7531334 fbshipit-source-id: 36ffa1e5ff205f60b95e0a1d1016301ea76936aa --- .../com/facebook/react/ReactRootView.java | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java index 5b8e3c53947ebb..c1d74a4aeddb6b 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java @@ -84,7 +84,7 @@ public interface ReactRootViewEventListener { private int mRootViewTag; private boolean mIsAttachedToInstance; private boolean mShouldLogContentAppeared; - private final JSTouchDispatcher mJSTouchDispatcher = new JSTouchDispatcher(this); + private @Nullable JSTouchDispatcher mJSTouchDispatcher; private final ReactAndroidHWInputDeviceHelper mAndroidHWInputDeviceHelper = new ReactAndroidHWInputDeviceHelper(this); private boolean mWasMeasured = false; private int mWidthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); @@ -183,6 +183,12 @@ public void onChildStartedNativeGesture(MotionEvent androidEvent) { "Unable to dispatch touch to JS as the catalyst instance has not been attached"); return; } + if (mJSTouchDispatcher == null) { + FLog.w( + ReactConstants.TAG, + "Unable to dispatch touch to JS before the dispatcher is available"); + return; + } ReactContext reactContext = mReactInstanceManager.getCurrentReactContext(); EventDispatcher eventDispatcher = reactContext.getNativeModule(UIManagerModule.class) .getEventDispatcher(); @@ -264,6 +270,12 @@ private void dispatchJSTouchEvent(MotionEvent event) { "Unable to dispatch touch to JS as the catalyst instance has not been attached"); return; } + if (mJSTouchDispatcher == null) { + FLog.w( + ReactConstants.TAG, + "Unable to dispatch touch to JS before the dispatcher is available"); + return; + } ReactContext reactContext = mReactInstanceManager.getCurrentReactContext(); EventDispatcher eventDispatcher = reactContext.getNativeModule(UIManagerModule.class) .getEventDispatcher(); @@ -414,6 +426,11 @@ public void unmountReactApplication() { } public void onAttachedToReactInstance() { + // Create the touch dispatcher here instead of having it always available, to make sure + // that all touch events are only passed to JS after React/JS side is ready to consume + // them. Otherwise, these events might break the states expected by JS. + // Note that this callback was invoked from within the UI thread. + mJSTouchDispatcher = new JSTouchDispatcher(this); if (mRootViewEventListener != null) { mRootViewEventListener.onAttachedToReactInstance(this); } @@ -582,7 +599,7 @@ public boolean isFabric() { public ReactInstanceManager getReactInstanceManager() { return mReactInstanceManager; } - + /* package */ void sendEvent(String eventName, @Nullable WritableMap params) { if (mReactInstanceManager != null) { mReactInstanceManager.getCurrentReactContext() From 3372541a2a7ffc38311ba02f9183ba96edc6dfd8 Mon Sep 17 00:00:00 2001 From: Liamandrew Date: Fri, 6 Apr 2018 17:39:54 -0700 Subject: [PATCH 0229/1109] Add ability for Animated views to be created with scale X or scale Y Summary: *Accidentally closed previous PR* Sometimes it can be useful to have an animated view be created with either scale X or scale Y in cases where scaleXY might not be as visually appealing. Test Plan Tested on both ios and android in the sample project: https://github.com/Liamandrew/ScaleAnimationSample ![scaleanimation](https://user-images.githubusercontent.com/30114733/37023697-d0aa7372-217a-11e8-8d3b-2958c63ad83a.gif) Closes https://github.com/facebook/react-native/pull/18220 Differential Revision: D7542334 Pulled By: hramos fbshipit-source-id: 208472e5d8f5a04ca3c3a99adce77b035e331ef1 --- Libraries/LayoutAnimation/LayoutAnimation.js | 2 ++ React/Modules/RCTUIManager.m | 14 +++++++++- .../layoutanimation/AnimatedPropertyType.java | 2 ++ .../layoutanimation/BaseLayoutAnimation.java | 26 +++++++++++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/Libraries/LayoutAnimation/LayoutAnimation.js b/Libraries/LayoutAnimation/LayoutAnimation.js index fe4a2cc2b84328..f04feca9331afb 100644 --- a/Libraries/LayoutAnimation/LayoutAnimation.js +++ b/Libraries/LayoutAnimation/LayoutAnimation.js @@ -32,6 +32,8 @@ const Types = keyMirror(TypesEnum); const PropertiesEnum = { opacity: true, + scaleX: true, + scaleY: true, scaleXY: true, }; const Properties = keyMirror(PropertiesEnum); diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m index 5dcce46588ba58..49b0f774e3cdab 100644 --- a/React/Modules/RCTUIManager.m +++ b/React/Modules/RCTUIManager.m @@ -595,6 +595,10 @@ - (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTRootShadowView * NSString *property = creatingLayoutAnimation.property; if ([property isEqualToString:@"scaleXY"]) { view.layer.transform = CATransform3DMakeScale(0, 0, 0); + } else if ([property isEqualToString:@"scaleX"]) { + view.layer.transform = CATransform3DMakeScale(0, 1, 0); + } else if ([property isEqualToString:@"scaleY"]) { + view.layer.transform = CATransform3DMakeScale(1, 0, 0); } else if ([property isEqualToString:@"opacity"]) { view.layer.opacity = 0.0; } else { @@ -603,7 +607,11 @@ - (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTRootShadowView * } [creatingLayoutAnimation performAnimations:^{ - if ([property isEqualToString:@"scaleXY"]) { + if ( + [property isEqualToString:@"scaleX"] || + [property isEqualToString:@"scaleY"] || + [property isEqualToString:@"scaleXY"] + ) { view.layer.transform = finalTransform; } else if ([property isEqualToString:@"opacity"]) { view.layer.opacity = finalOpacity; @@ -738,6 +746,10 @@ - (void)_removeChildren:(NSArray *)children [deletingLayoutAnimation performAnimations:^{ if ([property isEqualToString:@"scaleXY"]) { removedChild.layer.transform = CATransform3DMakeScale(0.001, 0.001, 0.001); + } else if ([property isEqualToString:@"scaleX"]) { + removedChild.layer.transform = CATransform3DMakeScale(0.001, 1, 0.001); + } else if ([property isEqualToString:@"scaleY"]) { + removedChild.layer.transform = CATransform3DMakeScale(1, 0.001, 0.001); } else if ([property isEqualToString:@"opacity"]) { removedChild.layer.opacity = 0.0; } else { diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AnimatedPropertyType.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AnimatedPropertyType.java index 51a9d246c061bb..b979799747ca7a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AnimatedPropertyType.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AnimatedPropertyType.java @@ -8,6 +8,8 @@ */ /* package */ enum AnimatedPropertyType { OPACITY("opacity"), + SCALE_X("scaleX"), + SCALE_Y("scaleY"), SCALE_XY("scaleXY"); private final String mName; diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/BaseLayoutAnimation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/BaseLayoutAnimation.java index f4fa2ea5cd4254..be06aedbc195f8 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/BaseLayoutAnimation.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/BaseLayoutAnimation.java @@ -42,6 +42,32 @@ Animation createAnimationImpl(View view, int x, int y, int width, int height) { Animation.RELATIVE_TO_SELF, .5f); } + case SCALE_X: { + float fromValue = isReverse() ? 1.0f : 0.0f; + float toValue = isReverse() ? 0.0f : 1.0f; + return new ScaleAnimation( + fromValue, + toValue, + 1f, + 1f, + Animation.RELATIVE_TO_SELF, + .5f, + Animation.RELATIVE_TO_SELF, + 0f); + } + case SCALE_Y: { + float fromValue = isReverse() ? 1.0f : 0.0f; + float toValue = isReverse() ? 0.0f : 1.0f; + return new ScaleAnimation( + 1f, + 1f, + fromValue, + toValue, + Animation.RELATIVE_TO_SELF, + 0f, + Animation.RELATIVE_TO_SELF, + .5f); + } default: throw new IllegalViewOperationException( "Missing animation for property : " + mAnimatedProperty); From 16bed9e6e50508c99e9666cb2fb5a06b0b534bf6 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Sat, 7 Apr 2018 00:50:38 -0700 Subject: [PATCH 0230/1109] Support cloning of virtual ReactShadowNodes Reviewed By: achen1 Differential Revision: D7542648 fbshipit-source-id: 58494db9f8525d4deabc6345f36941fa93a1d887 --- .../react/uimanager/ReactShadowNodeImpl.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java index 7d08bd08ec6526..018fa5ddace08b 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java @@ -164,22 +164,32 @@ protected ReactShadowNodeImpl copy() { @Override public ReactShadowNodeImpl mutableCopy() { ReactShadowNodeImpl copy = copy(); - copy.mYogaNode = mYogaNode.clone(); + if (mYogaNode != null) { + copy.mYogaNode = mYogaNode.clone(); + copy.mYogaNode.setData(copy); + } else { + // Virtual ReactShadowNode do not have a YogaNode associated + copy.mYogaNode = null; + } copy.mNativeChildren = mNativeChildren == null ? null : new ArrayList<>(mNativeChildren); copy.mTotalNativeChildren = mTotalNativeChildren; copy.mChildren = mChildren == null ? null : new ArrayList<>(mChildren); - copy.mYogaNode.setData(copy); return copy; } @Override public ReactShadowNodeImpl mutableCopyWithNewChildren() { ReactShadowNodeImpl copy = copy(); - copy.mYogaNode = mYogaNode.cloneWithNewChildren(); + if (mYogaNode != null) { + copy.mYogaNode = mYogaNode.cloneWithNewChildren(); + copy.mYogaNode.setData(copy); + } else { + // Virtual ReactShadowNode do not have a YogaNode associated + copy.mYogaNode = null; + } copy.mNativeChildren = null; copy.mChildren = null; copy.mTotalNativeChildren = 0; - copy.mYogaNode.setData(copy); return copy; } From 554243eb567cc587ce50a3f2224bbf42b931c9b4 Mon Sep 17 00:00:00 2001 From: Sam Mueller Date: Sat, 7 Apr 2018 21:02:43 -0700 Subject: [PATCH 0231/1109] Fix TouchHistoryMath import Summary: The reference needed to be updated after the file was moved in this commit: https://github.com/facebook/react-native/commit/06085d38366373f3135074dc14e2c9871ca4fe29 Otherwise, results in the packager failing with the following error: > Unable to resolve module TouchHistoryMath from /node_modules/react-native/Libraries/Interaction/PanResponder.js: Module TouchHistoryMath does not exist in the Haste module map Closes https://github.com/facebook/react-native/pull/18732 Differential Revision: D7547181 Pulled By: sebmarkbage fbshipit-source-id: 78028c2f46faa2ce130a1a0c25fcaca47d2516a8 --- Libraries/Interaction/PanResponder.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/Interaction/PanResponder.js b/Libraries/Interaction/PanResponder.js index db7d85c87e2714..d927fa5fc14d89 100644 --- a/Libraries/Interaction/PanResponder.js +++ b/Libraries/Interaction/PanResponder.js @@ -10,7 +10,7 @@ 'use strict'; const InteractionManager = require('./InteractionManager'); -const TouchHistoryMath = require('TouchHistoryMath'); +const TouchHistoryMath = require('./TouchHistoryMath'); const currentCentroidXOfTouchesChangedAfter = TouchHistoryMath.currentCentroidXOfTouchesChangedAfter; const currentCentroidYOfTouchesChangedAfter = TouchHistoryMath.currentCentroidYOfTouchesChangedAfter; From 9574f88701d2a23bbf2438d08d5af467e6a04ae8 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Sat, 7 Apr 2018 23:02:28 -0700 Subject: [PATCH 0232/1109] Move takeSnapshot from React repo to RN Reviewed By: sophiebits Differential Revision: D7547298 fbshipit-source-id: 6ab0c0a9e244a2f68d27307b84285b2c8fff1342 --- Libraries/ReactNative/takeSnapshot.js | 48 ++++++++++++++++++++++++ Libraries/Renderer/shims/takeSnapshot.js | 17 --------- 2 files changed, 48 insertions(+), 17 deletions(-) create mode 100644 Libraries/ReactNative/takeSnapshot.js delete mode 100644 Libraries/Renderer/shims/takeSnapshot.js diff --git a/Libraries/ReactNative/takeSnapshot.js b/Libraries/ReactNative/takeSnapshot.js new file mode 100644 index 00000000000000..212e6338faca72 --- /dev/null +++ b/Libraries/ReactNative/takeSnapshot.js @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @providesModule takeSnapshot + * @format + * @flow + */ + +const ReactNative = require('ReactNative'); +const UIManager = require('UIManager'); + +/** + * Capture an image of the screen, window or an individual view. The image + * will be stored in a temporary file that will only exist for as long as the + * app is running. + * + * The `view` argument can be the literal string `window` if you want to + * capture the entire window, or it can be a reference to a specific + * React Native component. + * + * The `options` argument may include: + * - width/height (number) - the width and height of the image to capture. + * - format (string) - either 'png' or 'jpeg'. Defaults to 'png'. + * - quality (number) - the quality when using jpeg. 0.0 - 1.0 (default). + * + * Returns a Promise. + * @platform ios + */ +module.exports = function takeSnapshot( + view?: 'window' | React$Element | number, + options?: { + width?: number, + height?: number, + format?: 'png' | 'jpeg', + quality?: number, + }, +): Promise { + if (typeof view !== 'number' && view !== 'window') { + view = ReactNative.findNodeHandle(view) || 'window'; + } + + // Call the hidden '__takeSnapshot' method; the main one throws an error to + // prevent accidental backwards-incompatible usage. + return UIManager.__takeSnapshot(view, options); +}; diff --git a/Libraries/Renderer/shims/takeSnapshot.js b/Libraries/Renderer/shims/takeSnapshot.js deleted file mode 100644 index 00abd891769c7d..00000000000000 --- a/Libraries/Renderer/shims/takeSnapshot.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule takeSnapshot - */ - -'use strict'; - -const { - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, -} = require('ReactNative'); - -module.exports = - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.takeSnapshot; From 9874004711f971648eb4f5d7e74b3a888eb8a521 Mon Sep 17 00:00:00 2001 From: gengjiawen Date: Sun, 8 Apr 2018 17:13:52 -0700 Subject: [PATCH 0233/1109] enhance RNTester android config Summary: * cliPath is not config right * root config can be better config instead of a relative path which can easily go wrong if location changed * DeveloperSupport should only be in debug mode. * make https://github.com/facebook/react-native/pull/18732 change on local. * config signingConfig * execute `./gradlew :RNTester:android:app:assembleRelease`, and run app on device to check everything is fine. none [GENERAL][ENHANCEMENT][RNTester] Closes https://github.com/facebook/react-native/pull/18746 Differential Revision: D7548846 Pulled By: hramos fbshipit-source-id: 8943f84a6c99456477dff2deeaacc96f093b2e09 --- RNTester/android/app/build.gradle | 3 ++- .../java/com/facebook/react/uiapp/RNTesterApplication.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/RNTester/android/app/build.gradle b/RNTester/android/app/build.gradle index bc001b26aca508..5e5503b5eb7ca6 100644 --- a/RNTester/android/app/build.gradle +++ b/RNTester/android/app/build.gradle @@ -58,9 +58,10 @@ import com.android.build.OutputFile */ project.ext.react = [ + cliPath: "$rootDir/local-cli/cli.js", bundleAssetName: "RNTesterApp.android.bundle", entryFile: file("../../js/RNTesterApp.android.js"), - root: "../../../", + root: "$rootDir", inputExcludes: ["android/**", "./**"] ] diff --git a/RNTester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.java b/RNTester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.java index b8c61a384ac443..b5eb40277e89e7 100644 --- a/RNTester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.java +++ b/RNTester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.java @@ -34,7 +34,7 @@ public String getJSMainModuleName() { @Override public boolean getUseDeveloperSupport() { - return true; + return BuildConfig.DEBUG; } @Override From 4b6e9d3dfd213689c5b319a4efee8d4f606d6f9d Mon Sep 17 00:00:00 2001 From: Eric Rozell Date: Sun, 8 Apr 2018 18:06:21 -0700 Subject: [PATCH 0234/1109] Revert "Remove Platform check from WebSocket module" Summary: This reverts commit b9be28915cf323eb36f1d7c77821cdf994954074. Thank you for sending the PR! We appreciate you spending the time to work on these changes. Help us understand your motivation by explaining why you decided to make this change. Fix #18696 Run Jest tests. Run WebSocket example from RNTester on Android. [CATEGORY] [TYPE] [LOCATION] - Message [ANDROID][BUGFIX][WebSocketModule] - revert change that regresses WebSocketModule Closes https://github.com/facebook/react-native/pull/18733 Differential Revision: D7548850 Pulled By: hramos fbshipit-source-id: b8c79810c1cd6e5a30ec4118bd5ff8ad719f04b9 --- Libraries/WebSocket/WebSocket.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Libraries/WebSocket/WebSocket.js b/Libraries/WebSocket/WebSocket.js index 021e42507e5db0..1b401d236c2830 100644 --- a/Libraries/WebSocket/WebSocket.js +++ b/Libraries/WebSocket/WebSocket.js @@ -14,6 +14,7 @@ const EventTarget = require('event-target-shim'); const NativeEventEmitter = require('NativeEventEmitter'); const BlobManager = require('BlobManager'); const NativeModules = require('NativeModules'); +const Platform = require('Platform'); const WebSocketEvent = require('WebSocketEvent'); /* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error @@ -205,7 +206,7 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) { } _close(code?: number, reason?: string): void { - if (WebSocketModule.close.length === 3) { + if (Platform.OS === 'android') { // 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 : ''; From bfcfe7961db0970e2575eafe2f3c9c668bd8940d Mon Sep 17 00:00:00 2001 From: Gabriele Mondada Date: Sun, 8 Apr 2018 22:57:49 -0700 Subject: [PATCH 0235/1109] fix use of C++ syntax in an header file Summary: All public header files can be included from Obj-C and Swift, except RCTSurfaceSizeMeasureMode.h which contains C++ code. Change is trivial and can be validated by review. None. [IOS][BUGFIX][{RCTSurfaceSizeMeasureMode.h}] - fix use of C++ syntax in an header file that could be included from Obj-C and Swift Closes https://github.com/facebook/react-native/pull/18730 Differential Revision: D7550290 Pulled By: shergin fbshipit-source-id: 3835e2c57697a067ff94afdaeaca06bce132ef66 --- .../RCTSurfaceHostingView.mm | 8 ++++---- .../RCTSurfaceSizeMeasureMode.h | 4 ++-- .../RCTSurfaceSizeMeasureMode.mm | 20 +++++++++---------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm b/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm index 9eb41ff0b2d091..f8c3a5d6981391 100644 --- a/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm +++ b/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm @@ -70,8 +70,8 @@ - (void)setFrame:(CGRect)frame RCTSurfaceMinimumSizeAndMaximumSizeFromSizeAndSizeMeasureMode( self.bounds.size, _sizeMeasureMode, - minimumSize, - maximumSize + &minimumSize, + &maximumSize ); [_surface setMinimumSize:minimumSize @@ -107,8 +107,8 @@ - (CGSize)sizeThatFits:(CGSize)size RCTSurfaceMinimumSizeAndMaximumSizeFromSizeAndSizeMeasureMode( size, _sizeMeasureMode, - minimumSize, - maximumSize + &minimumSize, + &maximumSize ); return [_surface sizeThatFitsMinimumSize:minimumSize diff --git a/React/Base/Surface/SurfaceHostingView/RCTSurfaceSizeMeasureMode.h b/React/Base/Surface/SurfaceHostingView/RCTSurfaceSizeMeasureMode.h index d463d36d091aff..ead7429b557419 100644 --- a/React/Base/Surface/SurfaceHostingView/RCTSurfaceSizeMeasureMode.h +++ b/React/Base/Surface/SurfaceHostingView/RCTSurfaceSizeMeasureMode.h @@ -28,6 +28,6 @@ typedef NS_OPTIONS(NSInteger, RCTSurfaceSizeMeasureMode) { RCT_EXTERN void RCTSurfaceMinimumSizeAndMaximumSizeFromSizeAndSizeMeasureMode( CGSize size, RCTSurfaceSizeMeasureMode sizeMeasureMode, - CGSize &minimumSize, - CGSize &maximumSize + CGSize *minimumSize, + CGSize *maximumSize ); diff --git a/React/Base/Surface/SurfaceHostingView/RCTSurfaceSizeMeasureMode.mm b/React/Base/Surface/SurfaceHostingView/RCTSurfaceSizeMeasureMode.mm index 5d1689b1b369a9..946b027d8c0ac1 100644 --- a/React/Base/Surface/SurfaceHostingView/RCTSurfaceSizeMeasureMode.mm +++ b/React/Base/Surface/SurfaceHostingView/RCTSurfaceSizeMeasureMode.mm @@ -12,25 +12,25 @@ void RCTSurfaceMinimumSizeAndMaximumSizeFromSizeAndSizeMeasureMode( CGSize size, RCTSurfaceSizeMeasureMode sizeMeasureMode, - CGSize &minimumSize, - CGSize &maximumSize + CGSize *minimumSize, + CGSize *maximumSize ) { - minimumSize = CGSizeZero; - maximumSize = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX); + *minimumSize = CGSizeZero; + *maximumSize = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX); if (sizeMeasureMode & RCTSurfaceSizeMeasureModeWidthExact) { - minimumSize.width = size.width; - maximumSize.width = size.width; + minimumSize->width = size.width; + maximumSize->width = size.width; } else if (sizeMeasureMode & RCTSurfaceSizeMeasureModeWidthAtMost) { - maximumSize.width = size.width; + maximumSize->width = size.width; } if (sizeMeasureMode & RCTSurfaceSizeMeasureModeHeightExact) { - minimumSize.height = size.height; - maximumSize.height = size.height; + minimumSize->height = size.height; + maximumSize->height = size.height; } else if (sizeMeasureMode & RCTSurfaceSizeMeasureModeHeightAtMost) { - maximumSize.height = size.height; + maximumSize->height = size.height; } } From 43014eaf1992c0b6d8610ba52e1bfea31d00ffe6 Mon Sep 17 00:00:00 2001 From: Matt Oakes Date: Mon, 9 Apr 2018 11:15:22 -0700 Subject: [PATCH 0236/1109] Fix #18279: Add 'addNetworkingHandler' to jest mock setup Summary: Fixes #18279 by adding the correct methods to the jest mocks setup file. Test by no longer including the workarounds in [issue comments](https://github.com/facebook/react-native/issues/18279#issuecomment-374177940). A [comment from hramos](https://github.com/facebook/react-native/issues/18279#issuecomment-371914037) mentioned improving the test coverage as well, but I wasn't certain how to achieve that. [GENERAL] [BUGFIX] [BlobManager] - Fixed the jest mocks to avoid breaking tests Closes https://github.com/facebook/react-native/pull/18718 Differential Revision: D7542458 Pulled By: hramos fbshipit-source-id: 77c9c7cae77971d62e878c4832b2e1d205131e8f --- jest/setup.js | 1 + 1 file changed, 1 insertion(+) diff --git a/jest/setup.js b/jest/setup.js index 0d4553b3f756f8..52916060777e87 100644 --- a/jest/setup.js +++ b/jest/setup.js @@ -297,6 +297,7 @@ const mockNativeModules = { BlobModule: { BLOB_URI_SCHEME: 'content', BLOB_URI_HOST: null, + addNetworkingHandler: jest.fn(), enableBlobSupport: jest.fn(), disableBlobSupport: jest.fn(), createFromParts: jest.fn(), From 0934c1778f0e3c0b691e1a3ca2df1d486eb905dd Mon Sep 17 00:00:00 2001 From: Angly Cat Date: Mon, 9 Apr 2018 12:24:39 -0700 Subject: [PATCH 0237/1109] Fix installing step of `run-ios` command Summary: To date if you create a new `react-native@0.55.0` project and try to build/run it for iOS via CLI, e.g. by running: ``` $ react-native init test $ cd test $ react-native run-ios --no-packager ``` the build would succeed, but installing will fail afterwards: ``` ** BUILD SUCCEEDED ** Installing Build/Products/Debug-iphonesimulator/test.app An error was encountered processing the command (domain=NSPOSIXErrorDomain, code=2): Failed to install the requested application An application bundle was not found at the provided path. Provide a valid path to the desired application bundle. Print: Entry, ":CFBundleIdentifier", Does Not Exist Command failed: /usr/libexec/PlistBuddy -c Print:CFBundleIdentifier Build/Products/Debug-iphonesimulator/test.app/Info.plist Print: Entry, ":CFBundleIdentifier", Does Not Exist ``` This fail happens because `/usr/libexec/PlistBuddy` can't find `Info.plist` file at the provided path. This is a regression introduced by changes from PR #17963 (accepted in https://github.com/facebook/react-native/commit/5447ca67076a110e2b0df03b014f53d1df4646ab). If you execute test plan from that PR, it would fail. As per why: By default, `run-ios` process's working directory is `$PROJECT_DIR/ios`. According to [this line in `runIOS.js`](https://github.com/facebook/react-native/blob/3cd2b4342653d0cc6edfc9e7d436d73bfb4f139f/local-cli/runIOS/runIOS.js#L184), `xcodebuild` places all artifacts in `build` directory. And the default Xcode paths for products is `Build/Products` (at least of Xcode 9.2 which I use, and Xcode 9.3 which I tested this with also). So, the required `Info.plist` file is actually being created at `$PROJECT_DIR/ios/build/Build/Products/Debug-iphonesimulator/test.app/Info.plist` (with double `build`, the first from `derivedDataPath` key, the second from default products path). Relatively to `run-ios` process's working directory, the path of the file is `build/Build/Products/Debug-iphonesimulator/test.app/Info.plist`. PR #17963 changed correct path to incorrect, thus introducing this regression. If changes from that PR are reverted, CLI doesn't fail on install step. I catch this error on both existing project and a freshly created test project. I can build/run an app from Xcode just fine, but running from CLI still would fail. The other workaround is to change path of products artifacts in Xcode, which is user settings and therefore can't be commited to a project's repo with VCS. Run: ``` $ react-native init test $ cd test $ react-native run-ios --no-packager ``` Ensure that it doesn't fail on install step and produce output similar to this: ``` Installing build/Build/Products/Debug-iphonesimulator/test.app Launching org.reactjs.native.example.test ``` [CLI][BUGFIX][local-cli/runIOS/runIOS.js] - Fix failing of `run-ios` command on install step Closes https://github.com/facebook/react-native/pull/18700 Differential Revision: D7555096 Pulled By: hramos fbshipit-source-id: d877b867e89256f4356f22781d78308affbb9d9c --- local-cli/runIOS/runIOS.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/local-cli/runIOS/runIOS.js b/local-cli/runIOS/runIOS.js index de72569de6e4b9..61b6795d5ab55b 100644 --- a/local-cli/runIOS/runIOS.js +++ b/local-cli/runIOS/runIOS.js @@ -24,7 +24,7 @@ const getBuildPath = function (configuration = 'Debug', appName, isDevice) { device = 'iphonesimulator'; } - return `Build/Products/${configuration}-${device}/${appName}.app`; + return `build/Build/Products/${configuration}-${device}/${appName}.app`; }; const xcprettyAvailable = function() { try { From 722f88ca9058c5d902c416b826a7a7ab347326b8 Mon Sep 17 00:00:00 2001 From: Andrew Kriger Date: Mon, 9 Apr 2018 16:57:54 -0700 Subject: [PATCH 0238/1109] Adds Android click sound to Touchables Summary: Android apps play a touch sound on press, as long as you have "Touch sounds" enabled in the settings. As and Android user, when building my app using React Native, one of the first things I noticed was that there were not any touch sounds. This is missing from React Native and there have been multiple PRs to have this implemented, but no success. This PR iterates over [#6825](https://github.com/facebook/react-native/pull/6825) and [#11136](https://github.com/facebook/react-native/pull/11136) This PR keeps it simple by only implementing the enhancement for Android, as iOS apps typically do not use touch sounds, and follows the users' system settings for whether or not the sound is played. I have manually tested this on multiple devices and emulators with zero problems [ANDROID] [ENHANCEMENT] [UIManagerModule.java]- Adds Android click sound to touchables [ANDROID] [ENHANCEMENT] [Touchable] - Adds Android click sound to touchables Closes https://github.com/facebook/react-native/pull/17183 Differential Revision: D7560327 Pulled By: hramos fbshipit-source-id: ce1094c437541bc677c7d64b0dba343dd9574422 --- Libraries/Components/Touchable/Touchable.js | 9 ++++++++- .../com/facebook/react/uimanager/UIManagerModule.java | 10 ++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Libraries/Components/Touchable/Touchable.js b/Libraries/Components/Touchable/Touchable.js index 00a82cd64ac6e6..f39457b827253d 100644 --- a/Libraries/Components/Touchable/Touchable.js +++ b/Libraries/Components/Touchable/Touchable.js @@ -741,6 +741,9 @@ const TouchableMixin = { this._startHighlight(e); this._endHighlight(e); } + if (Platform.OS === 'android') { + this._playTouchSound(); + } this.touchableHandlePress(e); } } @@ -748,7 +751,11 @@ const TouchableMixin = { this.touchableDelayTimeout && clearTimeout(this.touchableDelayTimeout); this.touchableDelayTimeout = null; }, - + + _playTouchSound: function() { + UIManager.playTouchSound(); + }, + _startHighlight: function(e) { this._savePressInLocation(e); this.touchableHandleActivePressIn && this.touchableHandleActivePressIn(e); diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java index 57430f3d07e7dd..3ef612874938d8 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java @@ -12,6 +12,8 @@ import android.content.ComponentCallbacks2; import android.content.res.Configuration; +import android.content.Context; +import android.media.AudioManager; import com.facebook.common.logging.FLog; import com.facebook.debug.holder.PrinterHolder; import com.facebook.debug.tags.ReactDebugOverlayTags; @@ -584,6 +586,14 @@ public void clearJSResponder() { public void dispatchViewManagerCommand(int reactTag, int commandId, ReadableArray commandArgs) { mUIImplementation.dispatchViewManagerCommand(reactTag, commandId, commandArgs); } + + @ReactMethod + public void playTouchSound() { + AudioManager audioManager = (AudioManager) getReactApplicationContext().getSystemService(Context.AUDIO_SERVICE); + if (audioManager != null) { + audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK); + } + } /** * Show a PopupMenu. From a8e3c7f5780516eb0297830632862484ad032c10 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Mon, 9 Apr 2018 18:39:48 -0700 Subject: [PATCH 0239/1109] Yolo Delete ReactNativePropRegistry Summary: Changed StyleSheet.create to be the identity function. We no longer hide it behind an opaque number. Better for types and perf since we don't use it. I don't really know if we have/need any safer way of rolling this out than just landing it. It can break if the object passed to StyleSheet.create is mutated afterwards but that isn't a practice anywhere I've seen. Reviewed By: sophiebits Differential Revision: D7530023 fbshipit-source-id: bc1afa879c5a5d9cd95cb13bc8ff3347b3622851 --- .../Renderer/shims/ReactNativePropRegistry.js | 18 ----------- Libraries/StyleSheet/StyleSheet.js | 32 +++++++++---------- Libraries/StyleSheet/StyleSheetTypes.js | 4 --- .../StyleSheet/__tests__/flattenStyle-test.js | 2 +- Libraries/StyleSheet/flattenStyle.js | 19 ++--------- jest/setup.js | 6 +--- 6 files changed, 20 insertions(+), 61 deletions(-) delete mode 100644 Libraries/Renderer/shims/ReactNativePropRegistry.js diff --git a/Libraries/Renderer/shims/ReactNativePropRegistry.js b/Libraries/Renderer/shims/ReactNativePropRegistry.js deleted file mode 100644 index 1ffd01057d51e4..00000000000000 --- a/Libraries/Renderer/shims/ReactNativePropRegistry.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule ReactNativePropRegistry - * @flow - */ - -'use strict'; - -const { - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, -} = require('ReactNative'); - -module.exports = - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactNativePropRegistry; diff --git a/Libraries/StyleSheet/StyleSheet.js b/Libraries/StyleSheet/StyleSheet.js index ec20623d8a27e4..ff9a88a088aa3d 100644 --- a/Libraries/StyleSheet/StyleSheet.js +++ b/Libraries/StyleSheet/StyleSheet.js @@ -11,14 +11,12 @@ 'use strict'; const PixelRatio = require('PixelRatio'); -const ReactNativePropRegistry = require('ReactNativePropRegistry'); const ReactNativeStyleAttributes = require('ReactNativeStyleAttributes'); const StyleSheetValidation = require('StyleSheetValidation'); const flatten = require('flattenStyle'); import type { - ____StyleSheetInternalStyleIdentifier_Internal as StyleSheetInternalStyleIdentifier, ____Styles_Internal, ____DangerouslyImpreciseStyle_Internal, ____DangerouslyImpreciseStyleProp_Internal, @@ -171,16 +169,16 @@ if (hairlineWidth === 0) { hairlineWidth = 1 / PixelRatio.get(); } -const absoluteFillObject: LayoutStyle = { +const absoluteFill: LayoutStyle = { position: 'absolute', left: 0, right: 0, top: 0, bottom: 0, }; -const absoluteFill: StyleSheetInternalStyleIdentifier = ReactNativePropRegistry.register( - absoluteFillObject, -); // This also freezes it +if (__DEV__) { + Object.freeze(absoluteFill); +} /** * A StyleSheet is an abstraction similar to CSS StyleSheets @@ -253,7 +251,7 @@ module.exports = { * so `absoluteFill` can be used for convenience and to reduce duplication of these repeated * styles. */ - absoluteFill, + absoluteFill: (absoluteFill: any), // TODO: This should be updated after we fix downstream Flow sites. /** * Sometimes you may want `absoluteFill` but with a couple tweaks - `absoluteFillObject` can be @@ -267,7 +265,7 @@ module.exports = { * }, * }); */ - absoluteFillObject, + absoluteFillObject: absoluteFill, /** * Combines two styles such that `style2` will override any styles in `style1`. @@ -361,14 +359,16 @@ module.exports = { /** * Creates a StyleSheet style reference from the given object. */ - create<+S: ____Styles_Internal>( - obj: S, - ): $ObjMap StyleSheetInternalStyleIdentifier> { - const result = {}; - for (const key in obj) { - StyleSheetValidation.validateStyle(key, obj); - result[key] = obj[key] && ReactNativePropRegistry.register(obj[key]); + create<+S: ____Styles_Internal>(obj: S): $ObjMap any> { + // TODO: This should return S as the return type. But first, + // we need to codemod all the callsites that are typing this + // return value as a number (even though it was opaque). + if (__DEV__) { + for (const key in obj) { + StyleSheetValidation.validateStyle(key, obj); + Object.freeze(obj[key]); + } } - return result; + return obj; }, }; diff --git a/Libraries/StyleSheet/StyleSheetTypes.js b/Libraries/StyleSheet/StyleSheetTypes.js index 1e359e8b515cf4..cd80f8b8d6e074 100644 --- a/Libraries/StyleSheet/StyleSheetTypes.js +++ b/Libraries/StyleSheet/StyleSheetTypes.js @@ -13,8 +13,6 @@ const AnimatedNode = require('AnimatedNode'); -export opaque type ____StyleSheetInternalStyleIdentifier_Internal: number = number; - export type ColorValue = null | string; export type DimensionValue = null | number | string | AnimatedNode; @@ -224,8 +222,6 @@ type GenericStyleProp<+T> = | null | void | T - | ____StyleSheetInternalStyleIdentifier_Internal - | number | false | '' | $ReadOnlyArray>; diff --git a/Libraries/StyleSheet/__tests__/flattenStyle-test.js b/Libraries/StyleSheet/__tests__/flattenStyle-test.js index 2f0fdcc0fb0ab5..76ce2822d900f2 100644 --- a/Libraries/StyleSheet/__tests__/flattenStyle-test.js +++ b/Libraries/StyleSheet/__tests__/flattenStyle-test.js @@ -150,7 +150,7 @@ describe('flattenStyle', () => { it('should ignore invalid class names', () => { var invalid = flattenStyle(1234, null); - expect(invalid).toEqual({}); + expect(invalid).toEqual(undefined); // Invalid class name 1234 skipping ... }); }); diff --git a/Libraries/StyleSheet/flattenStyle.js b/Libraries/StyleSheet/flattenStyle.js index 3ef381d0b6a298..176f5492a7e79e 100644 --- a/Libraries/StyleSheet/flattenStyle.js +++ b/Libraries/StyleSheet/flattenStyle.js @@ -10,35 +10,20 @@ */ 'use strict'; -var ReactNativePropRegistry; - import type { DangerouslyImpreciseStyle, DangerouslyImpreciseStyleProp, } from 'StyleSheet'; -function getStyle(style) { - if (ReactNativePropRegistry === undefined) { - ReactNativePropRegistry = require('ReactNativePropRegistry'); - } - if (typeof style === 'number') { - return ReactNativePropRegistry.getByID(style); - } - return style; -} - function flattenStyle( style: ?DangerouslyImpreciseStyleProp, ): ?DangerouslyImpreciseStyle { - if (style == null) { + if (style === null || typeof style !== 'object') { return undefined; } if (!Array.isArray(style)) { - /* $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 getStyle(style); + return style; } var result = {}; diff --git a/jest/setup.js b/jest/setup.js index 52916060777e87..25fed46877e9d4 100644 --- a/jest/setup.js +++ b/jest/setup.js @@ -324,11 +324,7 @@ Object.keys(mockNativeModules).forEach(module => { }); jest - .doMock('NativeModules', () => mockNativeModules) - .doMock('ReactNativePropRegistry', () => ({ - register: id => id, - getByID: () => mockEmptyObject, - })); + .doMock('NativeModules', () => mockNativeModules); jest.doMock('requireNativeComponent', () => { const React = require('react'); From b4c71361d953bb743205b72c0e5f5844983b3ed2 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Tue, 10 Apr 2018 09:09:57 -0700 Subject: [PATCH 0240/1109] Don't freeze null Reviewed By: acdlite Differential Revision: D7567032 fbshipit-source-id: ea9c826d572371748c6e9b5defbb92b427d83bee --- Libraries/StyleSheet/StyleSheet.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Libraries/StyleSheet/StyleSheet.js b/Libraries/StyleSheet/StyleSheet.js index ff9a88a088aa3d..5aab99d157626a 100644 --- a/Libraries/StyleSheet/StyleSheet.js +++ b/Libraries/StyleSheet/StyleSheet.js @@ -366,7 +366,9 @@ module.exports = { if (__DEV__) { for (const key in obj) { StyleSheetValidation.validateStyle(key, obj); - Object.freeze(obj[key]); + if (obj[key]) { + Object.freeze(obj[key]); + } } } return obj; From 2f1421dec7cd3a35779caceac108e872033c7d72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn-Erik=20Andreasen?= Date: Tue, 10 Apr 2018 10:33:25 -0700 Subject: [PATCH 0241/1109] Fix for scrollview android Summary: Trying this again with a fresh pullrequest as the old one kept having issued due to rebasing. Fixes #16635 the issue is a little serious if you use a scrollview which contains textinput, you will never get a chance to input something since keyboard will always be dismissed because of on-drag event if your scroll-view use the property: keyboardDismissMode ='on-drag' verify the issue #16635 and tested this fix worked [ANDROID] [BUGFIX] [ScrollView] - Check that isTouching is also set when dismissing keyboard with on-drag android. Closes https://github.com/facebook/react-native/pull/18785 Differential Revision: D7569815 Pulled By: hramos fbshipit-source-id: 2a07369297ce9ce5a7714e513ccb480ee7011a4d --- Libraries/Components/ScrollView/ScrollView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js index bc57f5cb400b62..2d9d031027ca92 100644 --- a/Libraries/Components/ScrollView/ScrollView.js +++ b/Libraries/Components/ScrollView/ScrollView.js @@ -681,7 +681,7 @@ const ScrollView = createReactClass({ } } if (Platform.OS === 'android') { - if (this.props.keyboardDismissMode === 'on-drag') { + if (this.props.keyboardDismissMode === 'on-drag' && this.state.isTouching) { dismissKeyboard(); } } From 4ebb57b0bae83dadf07a5fe9ce528796b1bb35b5 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 12:45:28 -0700 Subject: [PATCH 0242/1109] Fabric: `ShadowNode.revision_` field is now private Summary: It prevents accidental access to the variable. Reviewed By: fkgozali Differential Revision: D7467789 fbshipit-source-id: fa026734f58f0039e9b6d401751e022a9ae2431d --- ReactCommon/fabric/core/shadownode/ShadowNode.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.h b/ReactCommon/fabric/core/shadownode/ShadowNode.h index 4045be8462e6df..2efadda40b2d1e 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.h +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.h @@ -81,7 +81,15 @@ class ShadowNode: SharedProps props_; SharedShadowNodeSharedList children_; WeakShadowNode sourceNode_; - int revision_; + +private: + + /* + * A number of the generation of the ShadowNode instance; + * is used and useful for debug-printing purposes *only*. + * Do not access this value in any circumstances. + */ + const int revision_; }; } // namespace react From 1f969d34404175c04eb5a579b6bb886c8493c170 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 12:45:30 -0700 Subject: [PATCH 0243/1109] Fabric: Equality operators for ShadowNode Summary: Test for equality will be used in ShadowNode Tree Diffing algorithm. Reviewed By: fkgozali Differential Revision: D7467802 fbshipit-source-id: 5383add9fc7d7e4a772ca16e70a54f7e0c36823a --- ReactCommon/fabric/core/shadownode/ShadowNode.cpp | 15 +++++++++++++++ ReactCommon/fabric/core/shadownode/ShadowNode.h | 12 ++++++++++++ 2 files changed, 27 insertions(+) diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp index 2313be859eef83..c2da0db17ee525 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp @@ -116,6 +116,21 @@ void ShadowNode::clearSourceNode() { sourceNode_.reset(); } +#pragma mark - Equality + +bool ShadowNode::operator==(const ShadowNode& rhs) const { + // Note: Child nodes are not considered as part of instance's value + // and/or identity. + return + tag_ == rhs.tag_ && + rootTag_ == rhs.rootTag_ && + props_ == rhs.props_; +} + +bool ShadowNode::operator!=(const ShadowNode& rhs) const { + return !(*this == rhs); +} + #pragma mark - DebugStringConvertible std::string ShadowNode::getDebugName() const { diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.h b/ReactCommon/fabric/core/shadownode/ShadowNode.h index 2efadda40b2d1e..f03acb107ee59b 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.h +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.h @@ -67,6 +67,18 @@ class ShadowNode: void replaceChild(const SharedShadowNode &oldChild, const SharedShadowNode &newChild); void clearSourceNode(); +#pragma mark - Equality + + /* + * Equality operators. + * Use this to compare `ShadowNode`s values for equality (and non-equality). + * Same values indicates that nodes must not produce mutation instructions + * during tree diffing process. + * Child nodes are not considered as part of the value. + */ + virtual bool operator==(const ShadowNode& rhs) const; + virtual bool operator!=(const ShadowNode& rhs) const; + #pragma mark - DebugStringConvertible std::string getDebugName() const override; From c83aeaaf821c3905c273c826eebe8d032ea01800 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 12:45:33 -0700 Subject: [PATCH 0244/1109] Fabric: Forgotten compiler directive and include Summary: Trivial. Those nits prevent cause compilation errors in some configurations. Reviewed By: fkgozali Differential Revision: D7467794 fbshipit-source-id: cbda285748374fd941a0b1ca6718d702ca2d6d82 --- ReactCommon/exceptions/ExceptionManager.h | 2 ++ ReactCommon/fabric/graphics/Geometry.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/ReactCommon/exceptions/ExceptionManager.h b/ReactCommon/exceptions/ExceptionManager.h index 842975b3ba879a..278179c67dec40 100644 --- a/ReactCommon/exceptions/ExceptionManager.h +++ b/ReactCommon/exceptions/ExceptionManager.h @@ -5,6 +5,8 @@ * LICENSE file in the root directory of this source tree. */ +#pragma once + #include namespace facebook { diff --git a/ReactCommon/fabric/graphics/Geometry.h b/ReactCommon/fabric/graphics/Geometry.h index 8471b1d1a7db88..6c2b0f041fae96 100644 --- a/ReactCommon/fabric/graphics/Geometry.h +++ b/ReactCommon/fabric/graphics/Geometry.h @@ -2,6 +2,8 @@ #pragma once +#include + #include namespace facebook { From 7e84cadc9c933fce19d2f9cc580f76b1e0d54089 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 12:45:35 -0700 Subject: [PATCH 0245/1109] Fabric: Refined conception and usage of Sealable Summary: Slightly new approach: Some non-const methods might not always mutate objects, so sometimes we should call `ensureUnsealed()` only inside conditional branches where we actually mutate an instance. Reviewed By: fkgozali Differential Revision: D7467793 fbshipit-source-id: 1b9f229cf6816e54e0df36699a571fdb612d3c3c --- ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp | 7 ++++--- ReactCommon/fabric/core/primitives/Sealable.h | 8 ++++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp b/ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp index 8148f00dff002b..0e2652efc887d0 100644 --- a/ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp +++ b/ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp @@ -23,6 +23,8 @@ bool LayoutableShadowNode::setLayoutMetrics(LayoutMetrics layoutMetrics) { return false; } + ensureUnsealed(); + layoutMetrics_ = layoutMetrics; return true; } @@ -60,8 +62,6 @@ Float LayoutableShadowNode::lastBaseline(Size size) const { } void LayoutableShadowNode::layout(LayoutContext layoutContext) { - ensureUnsealed(); - layoutChildren(layoutContext); for (auto child : getChildren()) { @@ -69,6 +69,8 @@ void LayoutableShadowNode::layout(LayoutContext layoutContext) { continue; } + ensureUnsealed(); + // The assumption: // All `sealed` children were replaced with not-yet-sealed clones // somewhere in `layoutChildren`. @@ -89,7 +91,6 @@ void LayoutableShadowNode::layout(LayoutContext layoutContext) { } void LayoutableShadowNode::layoutChildren(LayoutContext layoutContext) { - ensureUnsealed(); // Default implementation does nothing. } diff --git a/ReactCommon/fabric/core/primitives/Sealable.h b/ReactCommon/fabric/core/primitives/Sealable.h index e0d168e44e0809..7f07819a1ff78c 100644 --- a/ReactCommon/fabric/core/primitives/Sealable.h +++ b/ReactCommon/fabric/core/primitives/Sealable.h @@ -31,7 +31,12 @@ namespace react { * * How to use: * 1. Inherit your class from `Sealable`. - * 2. Call `ensureUnsealed()` from all non-const methods. + * 2. Call `ensureUnsealed()` in all cases where the object might be mutated: + * a. At the beginning of all *always* mutating `non-const` methods; + * b. Right before the place where actual mutation happens in all *possible* + * mutating `non-const` methods; + * c. Right after performing `const_cast`. (Optionally. This is not strictly + * necessary but might help detect problems earlier.) * 3. Call `seal()` at some point from which any modifications * must be prevented. */ @@ -55,7 +60,6 @@ class Sealable { */ bool getSealed() const; -protected: /* * Throws an exception if the object is sealed. * Call this from all non-`const` methods. From dc1a9680de59b68f6efc5d553bf5a8b8382c2c1d Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 12:45:40 -0700 Subject: [PATCH 0246/1109] Fabric: Refined TreeMutationInstruction class Summary: Two additional types of instructions were added and now all of them have explicitly clear semantic. Reviewed By: fkgozali Differential Revision: D7467798 fbshipit-source-id: 83c0e774d56975be504aa3fe892035f5f724f809 --- .../uimanager/TreeMutationInstruction.cpp | 66 +++++++++++++++---- .../uimanager/TreeMutationInstruction.h | 43 +++++++----- 2 files changed, 79 insertions(+), 30 deletions(-) diff --git a/ReactCommon/fabric/uimanager/TreeMutationInstruction.cpp b/ReactCommon/fabric/uimanager/TreeMutationInstruction.cpp index da60fb83cf0153..42882ee6cfc629 100644 --- a/ReactCommon/fabric/uimanager/TreeMutationInstruction.cpp +++ b/ReactCommon/fabric/uimanager/TreeMutationInstruction.cpp @@ -12,6 +12,34 @@ namespace facebook { namespace react { +const TreeMutationInstruction TreeMutationInstruction::Create( + SharedShadowNode node +) { + assert(node); + + return TreeMutationInstruction( + Creation, + nullptr, + nullptr, + node, + -1 + ); +} + +const TreeMutationInstruction TreeMutationInstruction::Delete( + SharedShadowNode node +) { + assert(node); + + return TreeMutationInstruction( + Deletion, + nullptr, + node, + nullptr, + -1 + ); +} + const TreeMutationInstruction TreeMutationInstruction::Insert( SharedShadowNode parentNode, SharedShadowNode childNode, @@ -22,7 +50,7 @@ const TreeMutationInstruction TreeMutationInstruction::Insert( assert(index != -1); return TreeMutationInstruction( - Inserting, + Insertion, parentNode, nullptr, childNode, @@ -30,7 +58,7 @@ const TreeMutationInstruction TreeMutationInstruction::Insert( ); } -const TreeMutationInstruction TreeMutationInstruction::Delete( +const TreeMutationInstruction TreeMutationInstruction::Remove( SharedShadowNode parentNode, SharedShadowNode childNode, int index @@ -40,7 +68,7 @@ const TreeMutationInstruction TreeMutationInstruction::Delete( assert(index != -1); return TreeMutationInstruction( - Deleting, + Removal, parentNode, childNode, nullptr, @@ -48,7 +76,7 @@ const TreeMutationInstruction TreeMutationInstruction::Delete( ); } -const TreeMutationInstruction TreeMutationInstruction::Update( +const TreeMutationInstruction TreeMutationInstruction::Replace( SharedShadowNode parentNode, SharedShadowNode oldChildNode, SharedShadowNode newChildNode, @@ -60,7 +88,7 @@ const TreeMutationInstruction TreeMutationInstruction::Update( assert(index != -1); return TreeMutationInstruction( - Updating, + Replacement, parentNode, oldChildNode, newChildNode, @@ -111,12 +139,16 @@ int TreeMutationInstruction::getIndex() const { std::string TreeMutationInstruction::getDebugName() const { switch (type_) { - case Inserting: - return "Insert"; - case Deleting: + case Creation: + return "Create"; + case Deletion: return "Delete"; - case Updating: - return "Update"; + case Insertion: + return "Insert"; + case Removal: + return "Remove"; + case Replacement: + return "Replace"; } }; @@ -124,19 +156,27 @@ SharedDebugStringConvertibleList TreeMutationInstruction::getDebugProps() const DebugStringConvertibleOptions options = {.maximumDepth = 1, .format = false}; switch (type_) { - case Inserting: + case Creation: + return SharedDebugStringConvertibleList { + std::make_shared("node", newChildNode_->getDebugDescription(options)), + }; + case Deletion: + return SharedDebugStringConvertibleList { + std::make_shared("node", oldChildNode_->getDebugDescription(options)), + }; + case Insertion: return SharedDebugStringConvertibleList { std::make_shared("parentNode", parentNode_->getDebugDescription(options)), std::make_shared("childNode", newChildNode_->getDebugDescription(options)), std::make_shared("index", std::to_string(index_)) }; - case Deleting: + case Removal: return SharedDebugStringConvertibleList { std::make_shared("parentNode", parentNode_->getDebugDescription(options)), std::make_shared("childNode", oldChildNode_->getDebugDescription(options)), std::make_shared("index", std::to_string(index_)) }; - case Updating: + case Replacement: return SharedDebugStringConvertibleList { std::make_shared("parentNode", parentNode_->getDebugDescription(options)), std::make_shared("oldChildNode", oldChildNode_->getDebugDescription(options)), diff --git a/ReactCommon/fabric/uimanager/TreeMutationInstruction.h b/ReactCommon/fabric/uimanager/TreeMutationInstruction.h index f0e09c17d35b8b..920cd27f87cbd0 100644 --- a/ReactCommon/fabric/uimanager/TreeMutationInstruction.h +++ b/ReactCommon/fabric/uimanager/TreeMutationInstruction.h @@ -25,6 +25,7 @@ using TreeMutationInstructionList = std::vector; * final index of inserted or updated node. * The relationship between native view instances and shadow node instances is * defined by `tag` value. + * Use static methods to instantiate mutation instructions of different types. */ class TreeMutationInstruction: public DebugStringConvertible { @@ -33,10 +34,21 @@ class TreeMutationInstruction: #pragma mark - Designated Initializers /* - * Creates and returns an *Insert* instruction with following semantic: - * 1. Create a native view for the shadow node if needed; - * 2. Unmount the native view from a previous superview if needed; - * 3. Mount the native view to the new superview. + * Creates and returns an *Creation* instruction. + */ + static const TreeMutationInstruction Create( + SharedShadowNode node + ); + + /* + * Creates and returns an *Deletion* instruction. + */ + static const TreeMutationInstruction Delete( + SharedShadowNode node + ); + + /* + * Creates and returns an *Insertion* instruction. */ static const TreeMutationInstruction Insert( SharedShadowNode parentNode, @@ -45,23 +57,18 @@ class TreeMutationInstruction: ); /* - * Creates and returns a *Delete* instruction with following semantic: - * 1. Unmount the native view from a previous superview if needed; - * 2. Destroy (or return to a recycle pool) the native view. + * Creates and returns a *Removal* instruction. */ - static const TreeMutationInstruction Delete( + static const TreeMutationInstruction Remove( SharedShadowNode parentNode, SharedShadowNode childNode, int index ); /* - * Creates and returns an *Update* instruction with following semantic: - * 1. Update the presentation of a native view based on the new shadow node; - * 2. The exact set of changes are not specified but might contain - * new props and/or new layout (or might be empty). + * Creates and returns an *Replacement* instruction. */ - static const TreeMutationInstruction Update( + static const TreeMutationInstruction Replace( SharedShadowNode parentNode, SharedShadowNode oldChildNode, SharedShadowNode newChildNode, @@ -71,9 +78,11 @@ class TreeMutationInstruction: #pragma mark - Type enum Type { - Inserting, - Deleting, - Updating + Creation, + Deletion, + Insertion, + Removal, + Replacement }; #pragma mark - Getters @@ -98,7 +107,7 @@ class TreeMutationInstruction: int index ); - Type type_ {Inserting}; + Type type_ {Creation}; SharedShadowNode parentNode_ {nullptr}; SharedShadowNode oldChildNode_ {nullptr}; SharedShadowNode newChildNode_ {nullptr}; From a38f32a5a6880a5429d1c57dd530b8ad9f0dc79e Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 12:45:43 -0700 Subject: [PATCH 0247/1109] Fabric: Couple of ViewProps fields were exposed as getters Summary: We have to have getters for all props/fields. Reviewed By: mdvacca Differential Revision: D7467792 fbshipit-source-id: 1492aad2d3398e6c14e0e354047730cf91201175 --- ReactCommon/fabric/view/ViewProps.cpp | 12 ++++++++++++ ReactCommon/fabric/view/ViewProps.h | 5 +++++ 2 files changed, 17 insertions(+) diff --git a/ReactCommon/fabric/view/ViewProps.cpp b/ReactCommon/fabric/view/ViewProps.cpp index e3f9f6fddc0d94..725c2014bc276d 100644 --- a/ReactCommon/fabric/view/ViewProps.cpp +++ b/ReactCommon/fabric/view/ViewProps.cpp @@ -45,6 +45,18 @@ void ViewProps::apply(const RawProps &rawProps) { } } +#pragma mark - Getters + +SharedColor ViewProps::getForegroundColor() const { + return foregroundColor_; +} + +SharedColor ViewProps::getBackgroundColor() const { + return backgroundColor_; +} + +#pragma mark - DebugStringConvertible + SharedDebugStringConvertibleList ViewProps::getDebugProps() const { ViewProps defaultProps = {}; diff --git a/ReactCommon/fabric/view/ViewProps.h b/ReactCommon/fabric/view/ViewProps.h index 89b20dec799f6b..365d469f746bf6 100644 --- a/ReactCommon/fabric/view/ViewProps.h +++ b/ReactCommon/fabric/view/ViewProps.h @@ -28,6 +28,11 @@ class ViewProps: public: void apply(const RawProps &rawProps) override; +#pragma mark - Getters + + SharedColor getForegroundColor() const; + SharedColor getBackgroundColor() const; + private: int zIndex_ {0}; float opacity_ {1.0}; From fec0a51e85811d20c84480946d953d6410bb5393 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 12:45:46 -0700 Subject: [PATCH 0248/1109] Fabric: Simplified `ViewShadowNode::cloneAndReplaceChild` Summary: Using methods of the base class instead of custom implementation. Reviewed By: fkgozali Differential Revision: D7467795 fbshipit-source-id: 4d168b72880f6900bf8b747e1d655c10140e0c79 --- ReactCommon/fabric/view/ViewShadowNode.cpp | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/ReactCommon/fabric/view/ViewShadowNode.cpp b/ReactCommon/fabric/view/ViewShadowNode.cpp index 8bb5f33fdb83a4..2418279903e343 100644 --- a/ReactCommon/fabric/view/ViewShadowNode.cpp +++ b/ReactCommon/fabric/view/ViewShadowNode.cpp @@ -92,26 +92,14 @@ SharedLayoutableShadowNodeList ViewShadowNode::getChildren() const { SharedLayoutableShadowNode ViewShadowNode::cloneAndReplaceChild(const SharedLayoutableShadowNode &child) { ensureUnsealed(); - // We cannot mutate `children_` in place here because it is a *shared* - // data structure which means other `ShadowNodes` might refer to its old value. - // So, we have to clone this and only then mutate. - auto nonConstChildrenCopy = SharedShadowNodeList(*children_); - auto viewShadowNodeChild = std::dynamic_pointer_cast(child); assert(viewShadowNodeChild); - auto viewShadowNodeChildClone = std::make_shared(viewShadowNodeChild); + ShadowNode::replaceChild(viewShadowNodeChild, viewShadowNodeChildClone); + return std::static_pointer_cast(viewShadowNodeChildClone); - std::replace( - nonConstChildrenCopy.begin(), - nonConstChildrenCopy.end(), - std::static_pointer_cast(viewShadowNodeChild), - std::static_pointer_cast(viewShadowNodeChildClone) - ); - children_ = std::make_shared(nonConstChildrenCopy); - return std::static_pointer_cast(viewShadowNodeChildClone); } #pragma mark - DebugStringConvertible From 1a4b6f0b3dbe2bef1ddee0e81fb1fff784737420 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 12:45:48 -0700 Subject: [PATCH 0249/1109] Fabric: Overriden equality operator for ViewShadowNode Summary: Computed `layoutMetrics` are also considered as part of ViewShadowNode's value. In the future we probably have to add something like `localData` and `imperativeCommands`. We need all this for diffing algorithm and mointing phase. Reviewed By: mdvacca Differential Revision: D7467800 fbshipit-source-id: 8a0dcf1fd2f97dc501d6969cb0b0f6a2c6a648b4 --- ReactCommon/fabric/view/ViewShadowNode.cpp | 8 ++++++++ ReactCommon/fabric/view/ViewShadowNode.h | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/ReactCommon/fabric/view/ViewShadowNode.cpp b/ReactCommon/fabric/view/ViewShadowNode.cpp index 2418279903e343..b8f610c10d5faa 100644 --- a/ReactCommon/fabric/view/ViewShadowNode.cpp +++ b/ReactCommon/fabric/view/ViewShadowNode.cpp @@ -97,9 +97,17 @@ SharedLayoutableShadowNode ViewShadowNode::cloneAndReplaceChild(const SharedLayo auto viewShadowNodeChildClone = std::make_shared(viewShadowNodeChild); ShadowNode::replaceChild(viewShadowNodeChild, viewShadowNodeChildClone); return std::static_pointer_cast(viewShadowNodeChildClone); +} +#pragma mark - Equality +bool ViewShadowNode::operator==(const ShadowNode& rhs) const { + if (!ShadowNode::operator==(rhs)) { + return false; + } + auto &&other = static_cast(rhs); + return getLayoutMetrics() == other.getLayoutMetrics(); } #pragma mark - DebugStringConvertible diff --git a/ReactCommon/fabric/view/ViewShadowNode.h b/ReactCommon/fabric/view/ViewShadowNode.h index 4ac446556d77df..b80a138fd444f0 100644 --- a/ReactCommon/fabric/view/ViewShadowNode.h +++ b/ReactCommon/fabric/view/ViewShadowNode.h @@ -48,6 +48,10 @@ class ViewShadowNode: void appendChild(const SharedShadowNode &child); +#pragma mark - Equality + + bool operator==(const ShadowNode& rhs) const override; + #pragma mark - DebugStringConvertible SharedDebugStringConvertibleList getDebugProps() const override; From 5dca3e7c7411ca370e0d9911fdef9f3a88dc14b4 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 12:45:51 -0700 Subject: [PATCH 0250/1109] Fabric: New approach of mutating ShadowNode's children collection Summary: Previously we recreate a vector with pointers to child nodes every single time we modify the collection. That was okay but recently I realized that the we can simply make a copy of the vector one time during object construction and then mutate it freely. Reviewed By: mdvacca Differential Revision: D7467796 fbshipit-source-id: 660f1706a19ae5f07c34c509f411ce9d67b93b35 --- .../fabric/core/shadownode/ShadowNode.cpp | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp index c2da0db17ee525..f15964b0b5d9b6 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp @@ -31,7 +31,7 @@ ShadowNode::ShadowNode( rootTag_(rootTag), instanceHandle_(instanceHandle), props_(props), - children_(children), + children_(std::make_shared(*children)), revision_(1) {} ShadowNode::ShadowNode( @@ -43,7 +43,7 @@ ShadowNode::ShadowNode( rootTag_(shadowNode->rootTag_), instanceHandle_(shadowNode->instanceHandle_), props_(props ? props : shadowNode->props_), - children_(children ? children : shadowNode->children_), + children_(std::make_shared(*(children ? children : shadowNode->children_))), sourceNode_(shadowNode), revision_(shadowNode->revision_ + 1) {} @@ -92,23 +92,15 @@ void ShadowNode::sealRecursive() const { void ShadowNode::appendChild(const SharedShadowNode &child) { ensureUnsealed(); - // We cannot mutate `children_` in place here because it is a *shared* - // data structure which means other `ShadowNodes` might refer to its old value. - // So, we have to clone this and only then mutate. - auto nonConstChildrenCopy = SharedShadowNodeList(*children_); - nonConstChildrenCopy.push_back(child); - children_ = std::make_shared(nonConstChildrenCopy); + auto nonConstChildren = std::const_pointer_cast(children_); + nonConstChildren->push_back(child); } void ShadowNode::replaceChild(const SharedShadowNode &oldChild, const SharedShadowNode &newChild) { ensureUnsealed(); - // We cannot mutate `children_` in place here because it is a *shared* - // data structure which means other `ShadowNodes` might refer to its old value. - // So, we have to clone this and only then mutate. - auto nonConstChildrenCopy = SharedShadowNodeList(*children_); - std::replace(nonConstChildrenCopy.begin(), nonConstChildrenCopy.end(), oldChild, newChild); - children_ = std::make_shared(nonConstChildrenCopy); + auto nonConstChildren = std::const_pointer_cast(children_); + std::replace(nonConstChildren->begin(), nonConstChildren->end(), oldChild, newChild); } void ShadowNode::clearSourceNode() { From ef6b916e48204158f649035d08d2183fafeab00b Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 12:45:53 -0700 Subject: [PATCH 0251/1109] Fabric: New approach to manage Yoga's parent/owner references Summary: The modern Concurent Yoga's concept is: We have to set parent/owner reference as part of `appendChild` process only if the current reference to parent/owner is `null`. The motivation: * Null-parent indicates that this node was not attached to anything yet; * So, in this case there is no any concurrent memory access because we always create and (first time) attach the node on same thread; * Simmetrical parent-child relationship indicates that we don't need to (re)clone assosiated ShadowNode (nor Yoga node). Reviewed By: mdvacca Differential Revision: D7467791 fbshipit-source-id: 9a7f517380fde3bb00272de18fd5dc13edb52071 --- .../fabric/view/yoga/YogaLayoutableShadowNode.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp index 6ad453100e8f0e..9aadda4d83caee 100644 --- a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp +++ b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp @@ -97,6 +97,11 @@ void YogaLayoutableShadowNode::appendChild(SharedYogaLayoutableShadowNode child) auto nonConstYogaNode = std::const_pointer_cast(yogaNode_); auto nonConstChildYogaNode = std::const_pointer_cast(child->yogaNode_); nonConstYogaNode->insertChild(nonConstChildYogaNode.get(), nonConstYogaNode->getChildrenCount()); + + if (nonConstChildYogaNode->getParent() == nullptr) { + child->ensureUnsealed(); + nonConstChildYogaNode->setParent(nonConstYogaNode.get()); + } } void YogaLayoutableShadowNode::layout(LayoutContext layoutContext) { @@ -211,7 +216,14 @@ void YogaLayoutableShadowNode::setYogaNodeChildrenBasedOnShadowNodeChildren(YGNo continue; } - yogaNodeChildren.push_back((YGNode *)yogaLayoutableShadowNode->yogaNode_.get()); + YGNode *yogaNodeChild = (YGNode *)yogaLayoutableShadowNode->yogaNode_.get(); + + yogaNodeChildren.push_back(yogaNodeChild); + + if (yogaNodeChild->getParent() == nullptr) { + yogaLayoutableShadowNode->ensureUnsealed(); + yogaNodeChild->setParent(&yogaNode); + } } yogaNode.setChildren(yogaNodeChildren); From 0332d475ccfbbe4ec7649e1b80c02a142294a025 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 12:45:56 -0700 Subject: [PATCH 0252/1109] Fabric: Refined Yoga's `isDirty` flag management in YogaLayoutableShadowNode Summary: Motivation: * We never should call `markDirtyAndPropogate()` during tree construction/mutation because it might affect trees in different thread/dimentions; * In Fabric we basically always have to dirty nodes ourselves manually duting tree construction; * In Fabric we don't have "scoped/limited" tree mutations which require recursive dirtying; any mutation is creation of the new tree instance; * Default value of the `isDirty` flag is "false", so we have to change this right after creation of Yoga node (and after cloning). Reviewed By: mdvacca Differential Revision: D7467797 fbshipit-source-id: 2c9144271dceea6ba2b95173209b99b5d86fbd87 --- .../fabric/view/yoga/YogaLayoutableShadowNode.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp index 9aadda4d83caee..71e5ac89b345ac 100644 --- a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp +++ b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp @@ -42,7 +42,7 @@ YogaLayoutableShadowNode::YogaLayoutableShadowNode( yogaNode->setConfig(suitableYogaConfig().get()); yogaNode->setStyle(props->getYogaStyle()); yogaNode->setContext(this); - yogaNode->markDirtyAndPropogate(); + yogaNode->setDirty(true); YogaLayoutableShadowNode::setYogaNodeChildrenBasedOnShadowNodeChildren(*yogaNode, children); yogaNode_ = yogaNode; } @@ -53,8 +53,10 @@ YogaLayoutableShadowNode::YogaLayoutableShadowNode( const SharedShadowNodeSharedList &children ) { auto yogaNode = std::make_shared(*shadowNode->yogaNode_); + yogaNode->setConfig(suitableYogaConfig().get()); yogaNode->setContext(this); yogaNode->setOwner(nullptr); + yogaNode->setDirty(true); if (props) { yogaNode->setStyle(props->getYogaStyle()); @@ -64,8 +66,6 @@ YogaLayoutableShadowNode::YogaLayoutableShadowNode( YogaLayoutableShadowNode::setYogaNodeChildrenBasedOnShadowNodeChildren(*yogaNode, children); } - yogaNode->markDirtyAndPropogate(); - yogaNode_ = yogaNode; } @@ -98,9 +98,9 @@ void YogaLayoutableShadowNode::appendChild(SharedYogaLayoutableShadowNode child) auto nonConstChildYogaNode = std::const_pointer_cast(child->yogaNode_); nonConstYogaNode->insertChild(nonConstChildYogaNode.get(), nonConstYogaNode->getChildrenCount()); - if (nonConstChildYogaNode->getParent() == nullptr) { + if (nonConstChildYogaNode->getOwner() == nullptr) { child->ensureUnsealed(); - nonConstChildYogaNode->setParent(nonConstYogaNode.get()); + nonConstChildYogaNode->setOwner(nonConstYogaNode.get()); } } @@ -220,14 +220,13 @@ void YogaLayoutableShadowNode::setYogaNodeChildrenBasedOnShadowNodeChildren(YGNo yogaNodeChildren.push_back(yogaNodeChild); - if (yogaNodeChild->getParent() == nullptr) { + if (yogaNodeChild->getOwner() == nullptr) { yogaLayoutableShadowNode->ensureUnsealed(); - yogaNodeChild->setParent(&yogaNode); + yogaNodeChild->setOwner(&yogaNode); } } yogaNode.setChildren(yogaNodeChildren); - yogaNode.markDirtyAndPropogate(); } } // namespace react From b2af59a0f0ff51c292b0f15be5a970f5073092c9 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 12:45:59 -0700 Subject: [PATCH 0253/1109] Fabric: Diffing Algorithm (computing shadow node tree mutation instructions) Summary: The first and quite naive implementation of The Diffing algorithm. The exact set of instructions, their semantic, order, amount, and excessiveness are still unclear. The concept should be verified by comprehensive testing with working native views rendering layer. Reviewed By: mdvacca Differential Revision: D7467790 fbshipit-source-id: 08f2f646e058cac8a4b73bf7b148e2748633348d --- .../fabric/uimanager/Differentiator.cpp | 159 ++++++++++++++++++ ReactCommon/fabric/uimanager/Differentiator.h | 24 +++ 2 files changed, 183 insertions(+) create mode 100644 ReactCommon/fabric/uimanager/Differentiator.cpp create mode 100644 ReactCommon/fabric/uimanager/Differentiator.h diff --git a/ReactCommon/fabric/uimanager/Differentiator.cpp b/ReactCommon/fabric/uimanager/Differentiator.cpp new file mode 100644 index 00000000000000..20ff6add69df4c --- /dev/null +++ b/ReactCommon/fabric/uimanager/Differentiator.cpp @@ -0,0 +1,159 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include "Differentiator.h" + +namespace facebook { +namespace react { + +void calculateMutationInstructions( + TreeMutationInstructionList &instructions, + SharedShadowNode parentNode, + SharedShadowNodeSharedList oldChildNodes, + SharedShadowNodeSharedList newChildNodes +) { + // The current version of the algorithm is otimized for simplicity, + // not for performance of optimal result. + + // TODO(shergin): Consider to use Minimal Edit Distance algorithm to produce + // optimal set of instructions and improve mounting performance. + // https://en.wikipedia.org/wiki/Edit_distance + // https://www.geeksforgeeks.org/dynamic-programming-set-5-edit-distance/ + + if (oldChildNodes == newChildNodes) { + return; + } + + if (oldChildNodes->size() == 0 && newChildNodes->size() == 0) { + return; + } + + std::unordered_set insertedTags = {}; + int index = 0; + + TreeMutationInstructionList createInstructions = {}; + TreeMutationInstructionList deleteInstructions = {}; + TreeMutationInstructionList insertInstructions = {}; + TreeMutationInstructionList removeInstructions = {}; + TreeMutationInstructionList replaceInstructions = {}; + TreeMutationInstructionList downwardInstructions = {}; + + // Stage 1: Collectings Updates + + for (index = 0; index < oldChildNodes->size() && index < newChildNodes->size(); index++) { + SharedShadowNode oldChildNode = oldChildNodes->at(index); + SharedShadowNode newChildNode = newChildNodes->at(index); + + if (oldChildNode->getTag() != newChildNode->getTag()) { + // Totally different nodes, updating is impossible. + break; + } + + if (*oldChildNode != *newChildNode) { + replaceInstructions.push_back( + TreeMutationInstruction::Replace( + parentNode, + oldChildNode, + newChildNode, + index + ) + ); + } + + calculateMutationInstructions( + downwardInstructions, + oldChildNode, + oldChildNode->getChildren(), + newChildNode->getChildren() + ); + } + + int lastIndexAfterFirstStage = index; + + // Stage 2: Collectings Insertions + for (; index < newChildNodes->size(); index++) { + SharedShadowNode newChildNode = newChildNodes->at(index); + + insertInstructions.push_back( + TreeMutationInstruction::Insert( + parentNode, + newChildNodes->at(index), + index + ) + ); + + insertedTags.insert(newChildNode->getTag()); + + SharedShadowNode newChildSourceNode = newChildNode->getSourceNode(); + SharedShadowNodeSharedList newChildSourceChildNodes = + newChildSourceNode ? newChildSourceNode->getChildren() : ShadowNode::emptySharedShadowNodeSharedList(); + + calculateMutationInstructions( + downwardInstructions, + newChildNode, + newChildSourceChildNodes, + newChildNode->getChildren() + ); + } + + // Stage 3: Collectings Deletions and Removals + for (index = lastIndexAfterFirstStage; index < oldChildNodes->size(); index++) { + SharedShadowNode oldChildNode = oldChildNodes->at(index); + + auto numberOfRemovedTags = insertedTags.erase(oldChildNode->getTag()); + assert(numberOfRemovedTags == 0 || numberOfRemovedTags == 1); + + if (numberOfRemovedTags != 0) { + // The old node *was* (re)inserted, + // so we have to generate `remove` instruction. + removeInstructions.push_back( + TreeMutationInstruction::Remove( + parentNode, + oldChildNode, + index + ) + ); + } else { + // The old node was *not* (re)inserted, + // so we have to generate `delete` instruction and apply the algorithm + // recursively. + deleteInstructions.push_back( + TreeMutationInstruction::Delete( + oldChildNode + ) + ); + + calculateMutationInstructions( + downwardInstructions, + oldChildNode, + oldChildNode->getChildren(), + ShadowNode::emptySharedShadowNodeSharedList() + ); + } + } + + // Stage 4: Collectings Creations + for (index = lastIndexAfterFirstStage; index < newChildNodes->size(); index++) { + SharedShadowNode newChildNode = newChildNodes->at(index); + if (insertedTags.find(newChildNode->getTag()) == insertedTags.end()) { + // The new node was (re)inserted, so there is no need to create it. + continue; + } + + createInstructions.push_back( + TreeMutationInstruction::Create( + newChildNode + ) + ); + } + + // All instructions in an optimal order: + instructions.insert(instructions.end(), replaceInstructions.begin(), replaceInstructions.end()); + instructions.insert(instructions.end(), removeInstructions.begin(), removeInstructions.end()); + instructions.insert(instructions.end(), deleteInstructions.begin(), deleteInstructions.end()); + instructions.insert(instructions.end(), createInstructions.begin(), createInstructions.end()); + instructions.insert(instructions.end(), insertInstructions.begin(), insertInstructions.end()); + instructions.insert(instructions.end(), downwardInstructions.begin(), downwardInstructions.end()); +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/uimanager/Differentiator.h b/ReactCommon/fabric/uimanager/Differentiator.h new file mode 100644 index 00000000000000..7eb9fa332ff6ca --- /dev/null +++ b/ReactCommon/fabric/uimanager/Differentiator.h @@ -0,0 +1,24 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include + +namespace facebook { +namespace react { + +/* + * Calculates set of mutation instuctions which describe how the old + * ShadowNode tree can be transformed to the new ShadowNode tree. + * The set of instuctions might be and might not be optimal. + */ +void calculateMutationInstructions( + TreeMutationInstructionList &instructions, + SharedShadowNode parentNode, + SharedShadowNodeSharedList oldChildNodes, + SharedShadowNodeSharedList newChildNodes +); + +} // namespace react +} // namespace facebook From 5463fc260b8d703f9da34e6be5f83d1079e4302a Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 12:46:01 -0700 Subject: [PATCH 0254/1109] Fabric: ComponentDescriptorRegistry::operator[] marked as const Summary: Quite trivial. Note that std::unordered_map's `operator[]` is not `const`, so we have to use `at` instead. Reviewed By: mdvacca Differential Revision: D7467799 fbshipit-source-id: df38b21dccee4b347f7c070600af0d52f38d6570 --- .../fabric/uimanager/ComponentDescriptorRegistry.cpp | 8 ++++---- .../fabric/uimanager/ComponentDescriptorRegistry.h | 8 ++++++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/ReactCommon/fabric/uimanager/ComponentDescriptorRegistry.cpp b/ReactCommon/fabric/uimanager/ComponentDescriptorRegistry.cpp index d209f590ce554f..298e6c999c5230 100644 --- a/ReactCommon/fabric/uimanager/ComponentDescriptorRegistry.cpp +++ b/ReactCommon/fabric/uimanager/ComponentDescriptorRegistry.cpp @@ -13,13 +13,13 @@ void ComponentDescriptorRegistry::registerComponentDescriptor(SharedComponentDes _registryByName[componentName] = componentDescriptor; } -const SharedComponentDescriptor ComponentDescriptorRegistry::operator[](const SharedShadowNode &shadowNode) { +const SharedComponentDescriptor ComponentDescriptorRegistry::operator[](const SharedShadowNode &shadowNode) const { ComponentHandle componentHandle = shadowNode->getComponentHandle(); - return _registryByHandle[componentHandle]; + return _registryByHandle.at(componentHandle); } -const SharedComponentDescriptor ComponentDescriptorRegistry::operator[](const ComponentName &componentName) { - return _registryByName[componentName]; +const SharedComponentDescriptor ComponentDescriptorRegistry::operator[](const ComponentName &componentName) const { + return _registryByName.at(componentName); } } // namespace react diff --git a/ReactCommon/fabric/uimanager/ComponentDescriptorRegistry.h b/ReactCommon/fabric/uimanager/ComponentDescriptorRegistry.h index 462ab9f7f0d8e7..57d03d5242cc0d 100644 --- a/ReactCommon/fabric/uimanager/ComponentDescriptorRegistry.h +++ b/ReactCommon/fabric/uimanager/ComponentDescriptorRegistry.h @@ -9,6 +9,10 @@ namespace facebook { namespace react { +class ComponentDescriptorRegistry; + +using SharedComponentDescriptorRegistry = std::shared_ptr; + /* * Registry of particular `ComponentDescriptor`s. */ @@ -17,8 +21,8 @@ class ComponentDescriptorRegistry { public: void registerComponentDescriptor(SharedComponentDescriptor componentDescriptor); - const SharedComponentDescriptor operator[](const SharedShadowNode &shadowNode); - const SharedComponentDescriptor operator[](const ComponentName &componentName); + const SharedComponentDescriptor operator[](const SharedShadowNode &shadowNode) const; + const SharedComponentDescriptor operator[](const ComponentName &componentName) const; private: std::unordered_map _registryByHandle; From db7f98b78993a28100ca15134c0f8f8138e9efcf Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 12:46:04 -0700 Subject: [PATCH 0255/1109] Fabric: Introducing ShadowNode::shallowSourceNode() Summary: The method replaces the current source node with its source node. It's useful when we have to clone some node but don't want to change a source node pointer. Reviewed By: fkgozali Differential Revision: D7503384 fbshipit-source-id: 81ec64079c7e99cb9abdda2af10d85281a94e1b1 --- ReactCommon/fabric/core/shadownode/ShadowNode.cpp | 4 ++++ ReactCommon/fabric/core/shadownode/ShadowNode.h | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp index f15964b0b5d9b6..8f54601d04315d 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp @@ -108,6 +108,10 @@ void ShadowNode::clearSourceNode() { sourceNode_.reset(); } +void ShadowNode::shallowSourceNode() { + sourceNode_ = sourceNode_.lock()->getSourceNode(); +} + #pragma mark - Equality bool ShadowNode::operator==(const ShadowNode& rhs) const { diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.h b/ReactCommon/fabric/core/shadownode/ShadowNode.h index f03acb107ee59b..cd0264c2242f8e 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.h +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.h @@ -67,6 +67,14 @@ class ShadowNode: void replaceChild(const SharedShadowNode &oldChild, const SharedShadowNode &newChild); void clearSourceNode(); + /* + * Replaces the current source node with its source node. + * This method might be used for illuminating side-effects caused by the last + * cloning operation which are not desirable from the diffing algorithm + * perspective. + */ + void shallowSourceNode(); + #pragma mark - Equality /* From c4bd7cef69ccdccaee848435ef068bb95c4ca7ba Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 12:46:07 -0700 Subject: [PATCH 0256/1109] Fabric: Fixed issue in the diffing algorithm Summary: Previously we generated `removed` *or* `delete` instruction, but sometimes we have to generate both. So, basically we did it wrong. :( Reviewed By: mdvacca Differential Revision: D7503386 fbshipit-source-id: 8ee476abd29f088f31dc776f6e6a68d5293fbb35 --- .../fabric/uimanager/Differentiator.cpp | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/ReactCommon/fabric/uimanager/Differentiator.cpp b/ReactCommon/fabric/uimanager/Differentiator.cpp index 20ff6add69df4c..87f92990450339 100644 --- a/ReactCommon/fabric/uimanager/Differentiator.cpp +++ b/ReactCommon/fabric/uimanager/Differentiator.cpp @@ -38,7 +38,6 @@ void calculateMutationInstructions( TreeMutationInstructionList downwardInstructions = {}; // Stage 1: Collectings Updates - for (index = 0; index < oldChildNodes->size() && index < newChildNodes->size(); index++) { SharedShadowNode oldChildNode = oldChildNodes->at(index); SharedShadowNode newChildNode = newChildNodes->at(index); @@ -76,7 +75,7 @@ void calculateMutationInstructions( insertInstructions.push_back( TreeMutationInstruction::Insert( parentNode, - newChildNodes->at(index), + newChildNode, index ) ); @@ -99,20 +98,20 @@ void calculateMutationInstructions( for (index = lastIndexAfterFirstStage; index < oldChildNodes->size(); index++) { SharedShadowNode oldChildNode = oldChildNodes->at(index); + // Even if the old node was (re)inserted, we have to generate `remove` + // instruction. + removeInstructions.push_back( + TreeMutationInstruction::Remove( + parentNode, + oldChildNode, + index + ) + ); + auto numberOfRemovedTags = insertedTags.erase(oldChildNode->getTag()); assert(numberOfRemovedTags == 0 || numberOfRemovedTags == 1); - if (numberOfRemovedTags != 0) { - // The old node *was* (re)inserted, - // so we have to generate `remove` instruction. - removeInstructions.push_back( - TreeMutationInstruction::Remove( - parentNode, - oldChildNode, - index - ) - ); - } else { + if (numberOfRemovedTags == 0) { // The old node was *not* (re)inserted, // so we have to generate `delete` instruction and apply the algorithm // recursively. From 53837c4a4f9e689eb2f435564afede5f3466b84e Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 12:46:09 -0700 Subject: [PATCH 0257/1109] Fabric: Refined usage of `ensureunSealed` in `YogaLayoutableShadowNode::layout()` Summary: We have to call `ensureunSealed()` only if the node was changed. Reviewed By: mdvacca Differential Revision: D7503388 fbshipit-source-id: a3d07d50fa983ef93c14fa771711fa783fdf4c12 --- ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp index 71e5ac89b345ac..e2aa05f843a19b 100644 --- a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp +++ b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp @@ -105,9 +105,8 @@ void YogaLayoutableShadowNode::appendChild(SharedYogaLayoutableShadowNode child) } void YogaLayoutableShadowNode::layout(LayoutContext layoutContext) { - ensureUnsealed(); - if (!getIsLayoutClean()) { + ensureUnsealed(); YGNode *yogaNode = const_cast(yogaNode_.get()); YGNodeCalculateLayout(yogaNode, YGUndefined, YGUndefined, YGDirectionInherit); } @@ -116,8 +115,6 @@ void YogaLayoutableShadowNode::layout(LayoutContext layoutContext) { } void YogaLayoutableShadowNode::layoutChildren(LayoutContext layoutContext) { - ensureUnsealed(); - for (auto child : getChildren()) { auto yogaLayoutableChild = std::dynamic_pointer_cast(child); if (!yogaLayoutableChild) { From 47c0ab91a5af2606b185272eedf8888a26d01126 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 12:46:12 -0700 Subject: [PATCH 0258/1109] Fabric: Using `shallowSourceNode()` inside `ViewShadowNode::cloneAndReplaceChild()` Summary: We have to call shallowSourceNode() in all cases of cloning which were not caused by UIManager instructions, otherwise the diffing alogorith might produce incorrect mutation instructions. Reviewed By: mdvacca Differential Revision: D7503383 fbshipit-source-id: b33e5c39b7ba8cbd0f925fd29b3af379441a40a4 --- .../fabric/core/shadownode/ShadowNode.cpp | 6 ++++- .../fabric/core/shadownode/ShadowNode.h | 8 +++++++ .../fabric/core/tests/ShadowNodeTest.cpp | 24 +++++++++++++++++++ ReactCommon/fabric/view/ViewShadowNode.cpp | 16 ++++++++++++- 4 files changed, 52 insertions(+), 2 deletions(-) diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp index 8f54601d04315d..3c9fa034bdbe0a 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp @@ -109,7 +109,11 @@ void ShadowNode::clearSourceNode() { } void ShadowNode::shallowSourceNode() { - sourceNode_ = sourceNode_.lock()->getSourceNode(); + ensureUnsealed(); + + auto sourceNode = sourceNode_.lock(); + assert(sourceNode); + sourceNode_ = sourceNode->getSourceNode(); } #pragma mark - Equality diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.h b/ReactCommon/fabric/core/shadownode/ShadowNode.h index cd0264c2242f8e..48e840fd67987b 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.h +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.h @@ -58,7 +58,15 @@ class ShadowNode: Tag getTag() const; Tag getRootTag() const; InstanceHandle getInstanceHandle() const; + + /* + * Returns the node which was used as a prototype in clone constructor. + * The node is held as a weak reference so that the method may return + * `nullptr` in cases where the node was constructed using the explicit + * constructor or the node was already deallocated. + */ SharedShadowNode getSourceNode() const; + void sealRecursive() const; #pragma mark - Mutating Methods diff --git a/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp b/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp index 418938a497e1ab..c14fda2003dd70 100644 --- a/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp +++ b/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp @@ -94,3 +94,27 @@ TEST(ShadowNodeTest, handleShadowNodeMutation) { node5->clearSourceNode(); ASSERT_EQ(node5->getSourceNode(), nullptr); } + +TEST(ShadowNodeTest, handleSourceNode) { + auto nodeFirstGeneration = std::make_shared(9, 1, (void *)NULL); + auto nodeSecondGeneration = std::make_shared(nodeFirstGeneration); + auto nodeThirdGeneration = std::make_shared(nodeSecondGeneration); + auto nodeForthGeneration = std::make_shared(nodeThirdGeneration); + + // Ensure established shource nodes structure. + ASSERT_EQ(nodeForthGeneration->getSourceNode(), nodeThirdGeneration); + ASSERT_EQ(nodeThirdGeneration->getSourceNode(), nodeSecondGeneration); + ASSERT_EQ(nodeSecondGeneration->getSourceNode(), nodeFirstGeneration); + + // Shallow source node for the forth generation node. + nodeForthGeneration->shallowSourceNode(); + ASSERT_EQ(nodeForthGeneration->getSourceNode(), nodeSecondGeneration); + + // Shallow it one more time. + nodeForthGeneration->shallowSourceNode(); + ASSERT_EQ(nodeForthGeneration->getSourceNode(), nodeFirstGeneration); + + // Ensure that 3th and 2nd were not affected. + ASSERT_EQ(nodeThirdGeneration->getSourceNode(), nodeSecondGeneration); + ASSERT_EQ(nodeSecondGeneration->getSourceNode(), nodeFirstGeneration); +} diff --git a/ReactCommon/fabric/view/ViewShadowNode.cpp b/ReactCommon/fabric/view/ViewShadowNode.cpp index b8f610c10d5faa..a51f151b92ffd1 100644 --- a/ReactCommon/fabric/view/ViewShadowNode.cpp +++ b/ReactCommon/fabric/view/ViewShadowNode.cpp @@ -94,7 +94,21 @@ SharedLayoutableShadowNode ViewShadowNode::cloneAndReplaceChild(const SharedLayo auto viewShadowNodeChild = std::dynamic_pointer_cast(child); assert(viewShadowNodeChild); - auto viewShadowNodeChildClone = std::make_shared(viewShadowNodeChild); + auto viewShadowNodeChildClone = std::make_shared(viewShadowNodeChild); + + // This is overloading of `SharedLayoutableShadowNode::cloneAndReplaceChild`, + // the method is used to clone some node as a preparation for future mutation + // caused by relayout. + // Because those changes are not requested by UIManager, they add a layer + // of node generation (between the committed stage and new proposed stage). + // That additional layer confuses the Diffing algorithm which uses + // `sourceNode` for referencing the previous (aka committed) stage + // of the tree to produce mutation instructions. + // In other words, if we don't compensate this change here, + // the Diffing algorithm will compare wrong trees + // ("new-but-not-laid-out-yet vs. new" instead of "committed vs. new"). + viewShadowNodeChildClone->shallowSourceNode(); + ShadowNode::replaceChild(viewShadowNodeChild, viewShadowNodeChildClone); return std::static_pointer_cast(viewShadowNodeChildClone); } From 534abeca040e1d43514cfa8d8197adb20b30862c Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 12:46:15 -0700 Subject: [PATCH 0259/1109] Fabric: Introducing UIManagerDelegate Summary: UIManager uses UIManagerDelegate to communicate about shadow tree changes to another parts of the system. Reviewed By: fkgozali Differential Revision: D7503484 fbshipit-source-id: 0afe0f0d6cad31fe2ee9d61235d02b379cfe8217 --- React/Fabric/RCTFabricUIManagerWrapper.mm | 9 +- .../fabric/uimanager/FabricUIManager.cpp | 96 ++++++++++--------- .../fabric/uimanager/FabricUIManager.h | 31 +++--- .../fabric/uimanager/UIManagerDelegate.h | 37 +++++++ 4 files changed, 117 insertions(+), 56 deletions(-) create mode 100644 ReactCommon/fabric/uimanager/UIManagerDelegate.h diff --git a/React/Fabric/RCTFabricUIManagerWrapper.mm b/React/Fabric/RCTFabricUIManagerWrapper.mm index d3b6839eba06d3..dff3f263f12d01 100644 --- a/React/Fabric/RCTFabricUIManagerWrapper.mm +++ b/React/Fabric/RCTFabricUIManagerWrapper.mm @@ -8,7 +8,9 @@ #import "RCTFabricUIManagerWrapper.h" #include +#include #include +#include #include #include @@ -28,7 +30,12 @@ - (instancetype)init if (self) { _exceptionManager = std::make_shared(); _platformUIOperationManager = std::make_shared(); - _manager = std::make_shared(_platformUIOperationManager); + + auto componentDescriptorRegistry = std::make_shared(); + SharedComponentDescriptor viewComponentDescriptor = std::make_shared(); + componentDescriptorRegistry->registerComponentDescriptor(viewComponentDescriptor); + + _manager = std::make_shared(componentDescriptorRegistry); } return self; } diff --git a/ReactCommon/fabric/uimanager/FabricUIManager.cpp b/ReactCommon/fabric/uimanager/FabricUIManager.cpp index 0da19722a252c9..e2f3233980d564 100644 --- a/ReactCommon/fabric/uimanager/FabricUIManager.cpp +++ b/ReactCommon/fabric/uimanager/FabricUIManager.cpp @@ -9,13 +9,14 @@ #include +#include #include -#include +#include +#include +#include #include #include -#include "IFabricPlatformUIOperationManager.h" - namespace facebook { namespace react { @@ -37,63 +38,83 @@ static const RawProps rawPropsFromDynamic(const folly::dynamic object) { return result; } -FabricUIManager::FabricUIManager(const std::shared_ptr &platformUIOperationManager): - platformUIOperationManager_(platformUIOperationManager) { +FabricUIManager::FabricUIManager(SharedComponentDescriptorRegistry componentDescriptorRegistry) { + componentDescriptorRegistry_ = componentDescriptorRegistry; +} + +void FabricUIManager::setDelegate(UIManagerDelegate *delegate) { + delegate_ = delegate; +} - SharedComponentDescriptor viewComponentDescriptor = std::make_shared(); - _registry.registerComponentDescriptor(viewComponentDescriptor); +UIManagerDelegate *FabricUIManager::getDelegate() { + return delegate_; } SharedShadowNode FabricUIManager::createNode(int tag, std::string viewName, int rootTag, folly::dynamic props, void *instanceHandle) { LOG(INFO) << "FabricUIManager::createNode(tag: " << tag << ", name: " << viewName << ", rootTag" << rootTag << ", props: " << props << ")"; - ComponentDescriptor &componentDescriptor = *_registry["View"]; + const SharedComponentDescriptor &componentDescriptor = (*componentDescriptorRegistry_)["View"]; RawProps rawProps = rawPropsFromDynamic(props); - SharedShadowNode shadowNode = componentDescriptor.createShadowNode(tag, rootTag, instanceHandle, rawProps); + SharedShadowNode shadowNode = componentDescriptor->createShadowNode(tag, rootTag, instanceHandle, rawProps); LOG(INFO) << "FabricUIManager::createNode() -> " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}); + + if (delegate_) { + delegate_->uiManagerDidCreateShadowNode(shadowNode); + } + return shadowNode; } SharedShadowNode FabricUIManager::cloneNode(const SharedShadowNode &shadowNode) { LOG(INFO) << "FabricUIManager::cloneNode(shadowNode: " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ")"; - ComponentDescriptor &componentDescriptor = *_registry[shadowNode]; - SharedShadowNode clonnedShadowNode = componentDescriptor.cloneShadowNode(shadowNode); - LOG(INFO) << "FabricUIManager::cloneNode() -> " << clonnedShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}); - return clonnedShadowNode; + const SharedComponentDescriptor &componentDescriptor = (*componentDescriptorRegistry_)[shadowNode]; + SharedShadowNode clonedShadowNode = componentDescriptor->cloneShadowNode(shadowNode); + LOG(INFO) << "FabricUIManager::cloneNode() -> " << clonedShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}); + return clonedShadowNode; } SharedShadowNode FabricUIManager::cloneNodeWithNewChildren(const SharedShadowNode &shadowNode) { LOG(INFO) << "FabricUIManager::cloneNodeWithNewChildren(shadowNode: " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ")"; // Assuming semantic: Cloning with same props but empty children. - ComponentDescriptor &componentDescriptor = *_registry[shadowNode]; - SharedShadowNode clonnedShadowNode = componentDescriptor.cloneShadowNode(shadowNode, nullptr, ShadowNode::emptySharedShadowNodeSharedList()); - LOG(INFO) << "FabricUIManager::cloneNodeWithNewChildren() -> " << clonnedShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}); - return clonnedShadowNode; + const SharedComponentDescriptor &componentDescriptor = (*componentDescriptorRegistry_)[shadowNode]; + SharedShadowNode clonedShadowNode = componentDescriptor->cloneShadowNode(shadowNode, nullptr, ShadowNode::emptySharedShadowNodeSharedList()); + LOG(INFO) << "FabricUIManager::cloneNodeWithNewChildren() -> " << clonedShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}); + return clonedShadowNode; } SharedShadowNode FabricUIManager::cloneNodeWithNewProps(const SharedShadowNode &shadowNode, folly::dynamic props) { LOG(INFO) << "FabricUIManager::cloneNodeWithNewProps(shadowNode: " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ", props: " << props << ")"; // Assuming semantic: Cloning with same children and specified props. - ComponentDescriptor &componentDescriptor = *_registry[shadowNode]; + const SharedComponentDescriptor &componentDescriptor = (*componentDescriptorRegistry_)[shadowNode]; RawProps rawProps = rawPropsFromDynamic(props); - SharedShadowNode clonnedShadowNode = componentDescriptor.cloneShadowNode(shadowNode, std::make_shared(rawProps), nullptr); - LOG(INFO) << "FabricUIManager::cloneNodeWithNewProps() -> " << clonnedShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}); - return clonnedShadowNode; + SharedShadowNode clonedShadowNode = componentDescriptor->cloneShadowNode(shadowNode, std::make_shared(rawProps), nullptr); + LOG(INFO) << "FabricUIManager::cloneNodeWithNewProps() -> " << clonedShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}); + return clonedShadowNode; } SharedShadowNode FabricUIManager::cloneNodeWithNewChildrenAndProps(const SharedShadowNode &shadowNode, folly::dynamic props) { LOG(INFO) << "FabricUIManager::cloneNodeWithNewChildrenAndProps(shadowNode: " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ", props: " << props << ")"; // Assuming semantic: Cloning with empty children and specified props. - ComponentDescriptor &componentDescriptor = *_registry[shadowNode]; + const SharedComponentDescriptor &componentDescriptor = (*componentDescriptorRegistry_)[shadowNode]; RawProps rawProps = rawPropsFromDynamic(props); - SharedShadowNode clonnedShadowNode = componentDescriptor.cloneShadowNode(shadowNode, std::make_shared(rawProps), ShadowNode::emptySharedShadowNodeSharedList()); - LOG(INFO) << "FabricUIManager::cloneNodeWithNewChildrenAndProps() -> " << clonnedShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}); - return clonnedShadowNode; + SharedShadowNode clonedShadowNode = componentDescriptor->cloneShadowNode(shadowNode, std::make_shared(rawProps), ShadowNode::emptySharedShadowNodeSharedList()); + LOG(INFO) << "FabricUIManager::cloneNodeWithNewChildrenAndProps() -> " << clonedShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}); + return clonedShadowNode; } void FabricUIManager::appendChild(const SharedShadowNode &parentShadowNode, const SharedShadowNode &childShadowNode) { LOG(INFO) << "FabricUIManager::appendChild(parentShadowNode: " << parentShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ", childShadowNode: " << childShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ")"; - ComponentDescriptor &componentDescriptor = *_registry[parentShadowNode]; - componentDescriptor.appendChild(parentShadowNode, childShadowNode); + const SharedComponentDescriptor &componentDescriptor = (*componentDescriptorRegistry_)[parentShadowNode]; + + // TODO: Remove this after we move this to JS side. + if (childShadowNode->getSealed()) { + auto clonedChildShadowNode = componentDescriptor->cloneShadowNode(childShadowNode); + auto nonConstClonedChildShadowNode = std::const_pointer_cast(clonedChildShadowNode); + nonConstClonedChildShadowNode->shallowSourceNode(); + componentDescriptor->appendChild(parentShadowNode, clonedChildShadowNode); + return; + } + + componentDescriptor->appendChild(parentShadowNode, childShadowNode); } SharedShadowNodeUnsharedList FabricUIManager::createChildSet(int rootTag) { @@ -107,24 +128,11 @@ void FabricUIManager::appendChildToSet(const SharedShadowNodeUnsharedList &shado } void FabricUIManager::completeRoot(int rootTag, const SharedShadowNodeUnsharedList &children) { - LOG(INFO) << "FabricUIManager::appendChildToSet(rootTag: " << rootTag << ", shadowNodeList: " << children << ")"; - ComponentDescriptor &componentDescriptor = *_registry["View"]; - SharedShadowNode previousRootShadowNode = componentDescriptor.createShadowNode(rootTag, rootTag, nullptr, {}); - auto childrenCopy = std::make_shared(SharedShadowNodeList(*children)); - SharedShadowNode rootShadowNode = componentDescriptor.cloneShadowNode(previousRootShadowNode, nullptr, childrenCopy); - - SharedViewShadowNode viewShadowNode = std::dynamic_pointer_cast(rootShadowNode); - LayoutContext layoutContext = LayoutContext(); - layoutContext.affectedShadowNodes = std::make_shared>(); - - LOG(INFO) << "Shadow tree *before* layout: \n" << viewShadowNode->getDebugDescription() ; + LOG(INFO) << "FabricUIManager::completeRoot(rootTag: " << rootTag << ", shadowNodeList: " << children << ")"; - auto nonConstViewShadowNode = std::const_pointer_cast(viewShadowNode); - nonConstViewShadowNode->layout(layoutContext); - - rootShadowNode->sealRecursive(); - - LOG(INFO) << "Shadow tree *after* layout: \n" << nonConstViewShadowNode->getDebugDescription(); + if (delegate_) { + delegate_->uiManagerDidFinishTransaction(rootTag, children); + } } } // namespace react diff --git a/ReactCommon/fabric/uimanager/FabricUIManager.h b/ReactCommon/fabric/uimanager/FabricUIManager.h index 1db615b37c3fc2..c2b3dea9bfee7a 100644 --- a/ReactCommon/fabric/uimanager/FabricUIManager.h +++ b/ReactCommon/fabric/uimanager/FabricUIManager.h @@ -11,34 +11,43 @@ #include -#include #include #include +#include namespace facebook { namespace react { -class IFabricPlatformUIOperationManager; -class ComponentDescriptorRegistry; - class FabricUIManager { - public: - FabricUIManager(const std::shared_ptr &platformUIOperationManager); - SharedShadowNode createNode(int reactTag, std::string viewName, int rootTag, folly::dynamic props, void *instanceHandle); +#pragma mark - Native-facing Interface + + FabricUIManager(SharedComponentDescriptorRegistry componentDescriptorRegistry); + + /* + * Sets and gets the UIManager's delegate. + * The delegate is stored as a raw pointer, so the owner must null + * the pointer before being destroyed. + */ + void setDelegate(UIManagerDelegate *delegate); + UIManagerDelegate *getDelegate(); + +#pragma mark - JavaScript/React-facing Interface + + SharedShadowNode createNode(Tag reactTag, std::string viewName, Tag rootTag, folly::dynamic props, void *instanceHandle); SharedShadowNode cloneNode(const SharedShadowNode &node); SharedShadowNode cloneNodeWithNewChildren(const SharedShadowNode &node); SharedShadowNode cloneNodeWithNewProps(const SharedShadowNode &node, folly::dynamic props); SharedShadowNode cloneNodeWithNewChildrenAndProps(const SharedShadowNode &node, folly::dynamic newProps); void appendChild(const SharedShadowNode &parentNode, const SharedShadowNode &childNode); - SharedShadowNodeUnsharedList createChildSet(int rootTag); + SharedShadowNodeUnsharedList createChildSet(Tag rootTag); void appendChildToSet(const SharedShadowNodeUnsharedList &childSet, const SharedShadowNode &childNode); - void completeRoot(int rootTag, const SharedShadowNodeUnsharedList &childSet); + void completeRoot(Tag rootTag, const SharedShadowNodeUnsharedList &childSet); private: - ComponentDescriptorRegistry _registry; - std::shared_ptr platformUIOperationManager_; + SharedComponentDescriptorRegistry componentDescriptorRegistry_; + UIManagerDelegate *delegate_; }; } // namespace react diff --git a/ReactCommon/fabric/uimanager/UIManagerDelegate.h b/ReactCommon/fabric/uimanager/UIManagerDelegate.h new file mode 100644 index 00000000000000..e94af1f44034b1 --- /dev/null +++ b/ReactCommon/fabric/uimanager/UIManagerDelegate.h @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 { + +/* + * Abstract class for UIManager's delegate. + */ +class UIManagerDelegate { +public: + + /* + * Called right after the new/updated Shadow Node tree is constructed. + * The tree is not layed out and not sealed at this time. + */ + virtual void uiManagerDidFinishTransaction(Tag rootTag, const SharedShadowNodeUnsharedList &rootChildNodes) = 0; + + /* + * Called each time when UIManager constructs a new Shadow Node. Receiver + * maight use this to preluminary optimistically allocate a new native view + * instances. + */ + virtual void uiManagerDidCreateShadowNode(const SharedShadowNode &shadowNode) = 0; +}; + +} // namespace react +} // namespace facebook From f6f7d0484c7e561cd6583844f75ba6004acbe744 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 12:46:17 -0700 Subject: [PATCH 0260/1109] Fixed typo in RCTShadowView Summary: Trivial. Reviewed By: PeteTheHeat Differential Revision: D7503382 fbshipit-source-id: 0c553553bcde5c2f32bace0fa047aee6a106619b --- React/Views/RCTShadowView.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/React/Views/RCTShadowView.m b/React/Views/RCTShadowView.m index 457117653900de..84ad1c908c3e23 100644 --- a/React/Views/RCTShadowView.m +++ b/React/Views/RCTShadowView.m @@ -340,10 +340,10 @@ - (void)layoutSubviewsWithContext:(RCTLayoutContext)layoutContext - (CGSize)sizeThatFitsMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximumSize { - YGNodeRef clonnedYogaNode = YGNodeClone(self.yogaNode); + YGNodeRef clonedYogaNode = YGNodeClone(self.yogaNode); YGNodeRef constraintYogaNode = YGNodeNewWithConfig([[self class] yogaConfig]); - YGNodeInsertChild(constraintYogaNode, clonnedYogaNode, 0); + YGNodeInsertChild(constraintYogaNode, clonedYogaNode, 0); YGNodeStyleSetMinWidth(constraintYogaNode, RCTYogaFloatFromCoreGraphicsFloat(minimumSize.width)); YGNodeStyleSetMinHeight(constraintYogaNode, RCTYogaFloatFromCoreGraphicsFloat(minimumSize.height)); @@ -362,9 +362,9 @@ - (CGSize)sizeThatFitsMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximu RCTCoreGraphicsFloatFromYogaFloat(YGNodeLayoutGetHeight(constraintYogaNode)), }; - YGNodeRemoveChild(constraintYogaNode, clonnedYogaNode); + YGNodeRemoveChild(constraintYogaNode, clonedYogaNode); YGNodeFree(constraintYogaNode); - YGNodeFree(clonnedYogaNode); + YGNodeFree(clonedYogaNode); return measuredSize; } From ba45895a3f7b54cf2b0bf93daaf6b362726e14df Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 12:46:20 -0700 Subject: [PATCH 0261/1109] Fabric: Introducing Scheduler Summary: Scheduler coordinates Shadow Tree updates and event flows (not yet). Reviewed By: mdvacca Differential Revision: D7503387 fbshipit-source-id: 4cb8bc574c25a0fd2ace6319c26c644a1e4757a9 --- ReactCommon/fabric/uimanager/Scheduler.cpp | 108 ++++++++++++++++++ ReactCommon/fabric/uimanager/Scheduler.h | 74 ++++++++++++ .../fabric/uimanager/SchedulerDelegate.h | 33 ++++++ 3 files changed, 215 insertions(+) create mode 100644 ReactCommon/fabric/uimanager/Scheduler.cpp create mode 100644 ReactCommon/fabric/uimanager/Scheduler.h create mode 100644 ReactCommon/fabric/uimanager/SchedulerDelegate.h diff --git a/ReactCommon/fabric/uimanager/Scheduler.cpp b/ReactCommon/fabric/uimanager/Scheduler.cpp new file mode 100644 index 00000000000000..b2571ebf6168d5 --- /dev/null +++ b/ReactCommon/fabric/uimanager/Scheduler.cpp @@ -0,0 +1,108 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include "Scheduler.h" + +#include +#include +#include +#include +#include +#include + +#include "Differentiator.h" + +namespace facebook { +namespace react { + +Scheduler::Scheduler() { + auto componentDescriptorRegistry = std::make_shared(); + SharedComponentDescriptor viewComponentDescriptor = std::make_shared(); + componentDescriptorRegistry->registerComponentDescriptor(viewComponentDescriptor); + + uiManager_ = std::make_shared(componentDescriptorRegistry); + uiManager_->setDelegate(this); +} + +Scheduler::~Scheduler() { + uiManager_->setDelegate(nullptr); +} + +void Scheduler::registerRootTag(Tag rootTag) { + auto rootShadowNode = std::make_shared(rootTag, rootTag, nullptr); + rootNodeRegistry_.insert({rootTag, rootShadowNode}); +} + +void Scheduler::unregisterRootTag(Tag rootTag) { + rootNodeRegistry_.erase(rootTag); +} + +#pragma mark - Delegate + +void Scheduler::setDelegate(SchedulerDelegate *delegate) { + delegate_ = delegate; +} + +SchedulerDelegate *Scheduler::getDelegate() { + return delegate_; +} + +#pragma mark - UIManagerDelegate + +void Scheduler::uiManagerDidFinishTransaction(Tag rootTag, const SharedShadowNodeUnsharedList &rootChildNodes) { + SharedRootShadowNode oldRootShadowNode = rootNodeRegistry_[rootTag]; + assert(oldRootShadowNode); + + SharedRootShadowNode newRootShadowNode = + std::make_shared(oldRootShadowNode, nullptr, SharedShadowNodeSharedList(rootChildNodes)); + + auto nonConstOldRootShadowNode = std::const_pointer_cast(oldRootShadowNode); + auto nonConstNewRootShadowNode = std::const_pointer_cast(newRootShadowNode); + + LayoutContext layoutContext = LayoutContext(); + layoutContext.affectedShadowNodes = std::make_shared>(); + + LOG(INFO) << "Old Shadow Tree: \n" << oldRootShadowNode->getDebugDescription(); + LOG(INFO) << "New Shadow Tree *before* layout: \n" << newRootShadowNode->getDebugDescription(); + + nonConstNewRootShadowNode->layout(layoutContext); + + nonConstNewRootShadowNode->sealRecursive(); + + LOG(INFO) << "New Shadow Tree *after* layout: \n" << nonConstNewRootShadowNode->getDebugDescription(); + + TreeMutationInstructionList instructions = TreeMutationInstructionList(); + + calculateMutationInstructions( + instructions, + oldRootShadowNode, + oldRootShadowNode->ShadowNode::getChildren(), + newRootShadowNode->ShadowNode::getChildren() + ); + + LOG(INFO) << "TreeMutationInstructionList:"; + + for (auto instruction : instructions) { + LOG(INFO) << "Instruction: " << instruction.getDebugDescription(); + } + + rootNodeRegistry_[rootTag] = newRootShadowNode; + + if (delegate_) { + delegate_->schedulerDidComputeMutationInstructions(rootTag, instructions); + } +} + +void Scheduler::uiManagerDidCreateShadowNode(const SharedShadowNode &shadowNode) { + if (delegate_) { + delegate_->schedulerDidRequestPreliminaryViewAllocation(shadowNode->getComponentName()); + } +} + +#pragma mark - Deprecated + +std::shared_ptr Scheduler::getUIManager_DO_NOT_USE() { + return uiManager_; +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/uimanager/Scheduler.h b/ReactCommon/fabric/uimanager/Scheduler.h new file mode 100644 index 00000000000000..4f4ff203b54a92 --- /dev/null +++ b/ReactCommon/fabric/uimanager/Scheduler.h @@ -0,0 +1,74 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include + +#include +#include +#include +#include +#include + +namespace facebook { +namespace react { + +/* + * We expect having a dedicated subclass for root shadow node. + */ +using SharedRootShadowNode = SharedViewShadowNode; +using RootShadowNode = ViewShadowNode; + +class FabricUIManager; + +/* + * Scheduler coordinates Shadow Tree updates and event flows. + */ +class Scheduler: + public UIManagerDelegate { + +public: + Scheduler(); + ~Scheduler(); + +#pragma mark - Root Nodes Managerment + + void registerRootTag(Tag rootTag); + void unregisterRootTag(Tag rootTag); + + void setLayoutConstraints(Tag rootTag, LayoutConstraints layoutConstraints); + +#pragma mark - Delegate + + /* + * Sets and gets the Scheduler's delegate. + * The delegate is stored as a raw pointer, so the owner must null + * the pointer before being destroyed. + */ + void setDelegate(SchedulerDelegate *delegate); + SchedulerDelegate *getDelegate(); + +#pragma mark - UIManagerDelegate + + void uiManagerDidFinishTransaction(Tag rootTag, const SharedShadowNodeUnsharedList &rootChildNodes) override; + void uiManagerDidCreateShadowNode(const SharedShadowNode &shadowNode) override; + +#pragma mark - Deprecated + + /* + * UIManager instance must be temporarily exposed for registration purposes. + */ + std::shared_ptr getUIManager_DO_NOT_USE(); + +private: + SchedulerDelegate *delegate_; + std::shared_ptr uiManager_; + + /* + * All commited `RootShadowNode` instances to differentiate against. + */ + std::unordered_map rootNodeRegistry_; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/uimanager/SchedulerDelegate.h b/ReactCommon/fabric/uimanager/SchedulerDelegate.h new file mode 100644 index 00000000000000..2fe3da02ace154 --- /dev/null +++ b/ReactCommon/fabric/uimanager/SchedulerDelegate.h @@ -0,0 +1,33 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include + +#include +#include +#include + +namespace facebook { +namespace react { + +/* + * Abstract class for Scheduler's delegate. + */ +class SchedulerDelegate { +public: + /* + * Called right after Scheduler computed (and laid out) a new updated version + * of the tree and calculated a set of mutation instructions which are + * suffisient to construct a new one. + */ + virtual void schedulerDidComputeMutationInstructions(Tag rootTag, const TreeMutationInstructionList &instructions) = 0; + + /* + * Called right after a new ShadowNode was created. + */ + virtual void schedulerDidRequestPreliminaryViewAllocation(ComponentName componentName) = 0; +}; + +} // namespace react +} // namespace facebook From 906dde06b3f25b4e87adcbc8ed64f72bc930ac6a Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Tue, 10 Apr 2018 15:19:57 -0700 Subject: [PATCH 0262/1109] React sync for revisions 7a3416f...725c054 Reviewed By: bvaughn Differential Revision: D7565731 fbshipit-source-id: 91d76a11b7c91dab2fb3295418d1372ca9c1b572 --- Libraries/Components/View/FabricView.js | 102 +- Libraries/ReactNative/ReactFabricInternals.js | 8 +- .../ReactNative/requireFabricComponent.js | 10 +- .../ReactNative/requireNativeComponent.js | 6 - Libraries/Renderer/REVISION | 2 +- Libraries/Renderer/ReactFabric-dev.js | 1438 ++++++----------- Libraries/Renderer/ReactFabric-prod.js | 671 +++----- Libraries/Renderer/ReactNativeRenderer-dev.js | 1334 ++++++--------- .../Renderer/ReactNativeRenderer-prod.js | 600 +++---- .../shims/ReactNativeBridgeEventPlugin.js | 17 - Libraries/Renderer/shims/ReactNativeTypes.js | 23 +- .../shims/ReactNativeViewConfigRegistry.js | 106 ++ .../shims/createReactNativeComponentClass.js | 24 +- Libraries/Text/FabricText.js | 231 +-- 14 files changed, 1494 insertions(+), 3078 deletions(-) delete mode 100644 Libraries/Renderer/shims/ReactNativeBridgeEventPlugin.js create mode 100644 Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js diff --git a/Libraries/Components/View/FabricView.js b/Libraries/Components/View/FabricView.js index 4d686f7beb29cb..d56189052877b8 100644 --- a/Libraries/Components/View/FabricView.js +++ b/Libraries/Components/View/FabricView.js @@ -10,104 +10,4 @@ */ 'use strict'; -/** - * This is a temporary fork of View.js for Fabric purpose. - * Do not use outside of Fabric tree. - */ - -const Platform = require('Platform'); -const React = require('React'); -const ReactNativeStyleAttributes = require('ReactNativeStyleAttributes'); -const ReactNativeViewAttributes = require('ReactNativeViewAttributes'); -const ViewPropTypes = require('ViewPropTypes'); -const {NativeMethodsMixin} = require('ReactFabricInternals'); -const {ViewContextTypes} = require('ViewContext'); - -const createReactClass = require('create-react-class'); -const invariant = require('fbjs/lib/invariant'); -const requireFabricComponent = require('requireFabricComponent'); - -import type {ViewProps} from 'ViewPropTypes'; -import type {ViewChildContext} from 'ViewContext'; - -export type Props = ViewProps; - -/** - * The most fundamental component for building a UI. - * - * See http://facebook.github.io/react-native/docs/view.html - */ -const View = createReactClass({ - displayName: 'View', - // TODO: We should probably expose the mixins, viewConfig, and statics publicly. For example, - // one of the props is of type AccessibilityComponentType. That is defined as a const[] above, - // but it is not rendered by the docs, since `statics` below is not rendered. So its Possible - // values had to be hardcoded. - mixins: [NativeMethodsMixin], - - // `propTypes` should not be accessed directly on View since this wrapper only - // exists for DEV mode. However it's important for them to be declared. - // If the object passed to `createClass` specifies `propTypes`, Flow will - // create a static type from it. - propTypes: ViewPropTypes, - - /** - * `NativeMethodsMixin` will look for this when invoking `setNativeProps`. We - * make `this` look like an actual native component class. - */ - viewConfig: { - uiViewClassName: 'RCTView', - validAttributes: ReactNativeViewAttributes.RCTView, - }, - - childContextTypes: ViewContextTypes, - - getChildContext(): ViewChildContext { - return { - isInAParentText: false, - }; - }, - - render() { - invariant( - !(this.context.isInAParentText && Platform.OS === 'android'), - 'Nesting of within is not supported on Android.', - ); - - // WARNING: This method will not be used in production mode as in that mode we - // replace wrapper component View with generated native wrapper RCTView. Avoid - // adding functionality this component that you'd want to be available in both - // dev and prod modes. - return ; - }, -}); - -const RCTView = requireFabricComponent('RCTView', View, { - nativeOnly: { - nativeBackgroundAndroid: true, - nativeForegroundAndroid: true, - }, - fabric: true, -}); - -if (__DEV__) { - const UIManager = require('UIManager'); - const viewConfig = - (UIManager.viewConfigs && UIManager.viewConfigs.RCTView) || {}; - for (const prop in viewConfig.nativeProps) { - const viewAny: any = View; // Appease flow - if (!viewAny.propTypes[prop] && !ReactNativeStyleAttributes[prop]) { - throw new Error( - 'View is missing propType for native prop `' + prop + '`', - ); - } - } -} - -let ViewToExport = RCTView; -if (__DEV__) { - ViewToExport = View; -} - -// No one should depend on the DEV-mode createClass View wrapper. -module.exports = ((ViewToExport: any): typeof RCTView); +module.exports = require('View'); diff --git a/Libraries/ReactNative/ReactFabricInternals.js b/Libraries/ReactNative/ReactFabricInternals.js index d360803412a14a..72f37a41232d73 100644 --- a/Libraries/ReactNative/ReactFabricInternals.js +++ b/Libraries/ReactNative/ReactFabricInternals.js @@ -14,19 +14,15 @@ const { __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, } = require('ReactFabric'); +const createReactNativeComponentClass = require('createReactNativeComponentClass'); import type {NativeMethodsMixinType} from 'ReactNativeTypes'; -const { - NativeMethodsMixin, - ReactNativeBridgeEventPlugin, - createReactNativeComponentClass, -} = __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; +const {NativeMethodsMixin} = __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; module.exports = { NativeMethodsMixin: ((NativeMethodsMixin: any): $Exact< NativeMethodsMixinType, >), - ReactNativeBridgeEventPlugin, createReactNativeComponentClass, }; diff --git a/Libraries/ReactNative/requireFabricComponent.js b/Libraries/ReactNative/requireFabricComponent.js index 4d9fca04cd58d5..dfd02bfeb6122c 100644 --- a/Libraries/ReactNative/requireFabricComponent.js +++ b/Libraries/ReactNative/requireFabricComponent.js @@ -11,10 +11,7 @@ 'use strict'; const Platform = require('Platform'); -const { - ReactNativeBridgeEventPlugin, - createReactNativeComponentClass, -} = require('ReactFabricInternals'); +const {createReactNativeComponentClass} = require('ReactFabricInternals'); const ReactNativeStyleAttributes = require('ReactNativeStyleAttributes'); const UIManager = require('UIManager'); @@ -200,11 +197,6 @@ function requireNativeComponent( hasAttachedDefaultEventTypes = true; } - // Register this view's event types with the ReactNative renderer. - // This enables view managers to be initialized lazily, improving perf, - // While also enabling 3rd party components to define custom event types. - ReactNativeBridgeEventPlugin.processEventTypes(viewConfig); - return viewConfig; } diff --git a/Libraries/ReactNative/requireNativeComponent.js b/Libraries/ReactNative/requireNativeComponent.js index 453be93f715b6f..77141b1c049ae1 100644 --- a/Libraries/ReactNative/requireNativeComponent.js +++ b/Libraries/ReactNative/requireNativeComponent.js @@ -11,7 +11,6 @@ 'use strict'; const Platform = require('Platform'); -const ReactNativeBridgeEventPlugin = require('ReactNativeBridgeEventPlugin'); const ReactNativeStyleAttributes = require('ReactNativeStyleAttributes'); const UIManager = require('UIManager'); @@ -198,11 +197,6 @@ function requireNativeComponent( hasAttachedDefaultEventTypes = true; } - // Register this view's event types with the ReactNative renderer. - // This enables view managers to be initialized lazily, improving perf, - // While also enabling 3rd party components to define custom event types. - ReactNativeBridgeEventPlugin.processEventTypes(viewConfig); - return viewConfig; } diff --git a/Libraries/Renderer/REVISION b/Libraries/Renderer/REVISION index f505341495fa69..4d4db61db4a5ee 100644 --- a/Libraries/Renderer/REVISION +++ b/Libraries/Renderer/REVISION @@ -1 +1 @@ -7a3416f27532ac25849dfbc505300d469b43bbcc \ No newline at end of file +52afbe0ebb6fca0fe480e77c6fa8482870ddb2c9 \ No newline at end of file diff --git a/Libraries/Renderer/ReactFabric-dev.js b/Libraries/Renderer/ReactFabric-dev.js index e51c0254b90454..e933ab8f0bb430 100644 --- a/Libraries/Renderer/ReactFabric-dev.js +++ b/Libraries/Renderer/ReactFabric-dev.js @@ -19,6 +19,7 @@ require("InitializeCore"); var invariant = require("fbjs/lib/invariant"); var warning = require("fbjs/lib/warning"); var emptyFunction = require("fbjs/lib/emptyFunction"); +var ReactNativeViewConfigRegistry = require("ReactNativeViewConfigRegistry"); var UIManager = require("UIManager"); var TextInputState = require("TextInputState"); var deepDiffer = require("deepDiffer"); @@ -1294,7 +1295,7 @@ function getPooledWarningPropertyDefinition(propName, getVal) { return { configurable: true, set: set, - get: get + get: get$$1 }; function set(val) { @@ -1303,7 +1304,7 @@ function getPooledWarningPropertyDefinition(propName, getVal) { return val; } - function get() { + function get$$1() { var action = isFunction ? "accessing the method" : "accessing the property"; var result = isFunction ? "This is a no-op function" @@ -1620,7 +1621,7 @@ var changeResponder = function(nextResponderInst, blockHostResponder) { } }; -var eventTypes = { +var eventTypes$1 = { /** * On a `touchStart`/`mouseDown`, is it desired that this element become the * responder? @@ -1885,12 +1886,12 @@ function setResponderAndExtractTransfer( nativeEventTarget ) { var shouldSetEventType = isStartish(topLevelType) - ? eventTypes.startShouldSetResponder + ? eventTypes$1.startShouldSetResponder : isMoveish(topLevelType) - ? eventTypes.moveShouldSetResponder + ? eventTypes$1.moveShouldSetResponder : topLevelType === "topSelectionChange" - ? eventTypes.selectionChangeShouldSetResponder - : eventTypes.scrollShouldSetResponder; + ? eventTypes$1.selectionChangeShouldSetResponder + : eventTypes$1.scrollShouldSetResponder; // TODO: stop one short of the current responder. var bubbleShouldSetFrom = !responderInst @@ -1924,7 +1925,7 @@ function setResponderAndExtractTransfer( } var extracted = void 0; var grantEvent = ResponderSyntheticEvent.getPooled( - eventTypes.responderGrant, + eventTypes$1.responderGrant, wantsResponderInst, nativeEvent, nativeEventTarget @@ -1935,7 +1936,7 @@ function setResponderAndExtractTransfer( var blockHostResponder = executeDirectDispatch(grantEvent) === true; if (responderInst) { var terminationRequestEvent = ResponderSyntheticEvent.getPooled( - eventTypes.responderTerminationRequest, + eventTypes$1.responderTerminationRequest, responderInst, nativeEvent, nativeEventTarget @@ -1952,7 +1953,7 @@ function setResponderAndExtractTransfer( if (shouldSwitch) { var terminateEvent = ResponderSyntheticEvent.getPooled( - eventTypes.responderTerminate, + eventTypes$1.responderTerminate, responderInst, nativeEvent, nativeEventTarget @@ -1963,7 +1964,7 @@ function setResponderAndExtractTransfer( changeResponder(wantsResponderInst, blockHostResponder); } else { var rejectEvent = ResponderSyntheticEvent.getPooled( - eventTypes.responderReject, + eventTypes$1.responderReject, wantsResponderInst, nativeEvent, nativeEventTarget @@ -2032,7 +2033,7 @@ var ResponderEventPlugin = { return responderInst; }, - eventTypes: eventTypes, + eventTypes: eventTypes$1, /** * We must be resilient to `targetInst` being `null` on `touchMove` or @@ -2082,10 +2083,10 @@ var ResponderEventPlugin = { var isResponderTouchMove = responderInst && isMoveish(topLevelType); var isResponderTouchEnd = responderInst && isEndish(topLevelType); var incrementalTouch = isResponderTouchStart - ? eventTypes.responderStart + ? eventTypes$1.responderStart : isResponderTouchMove - ? eventTypes.responderMove - : isResponderTouchEnd ? eventTypes.responderEnd : null; + ? eventTypes$1.responderMove + : isResponderTouchEnd ? eventTypes$1.responderEnd : null; if (incrementalTouch) { var gesture = ResponderSyntheticEvent.getPooled( @@ -2107,8 +2108,8 @@ var ResponderEventPlugin = { isEndish(topLevelType) && noResponderTouches(nativeEvent); var finalTouch = isResponderTerminate - ? eventTypes.responderTerminate - : isResponderRelease ? eventTypes.responderRelease : null; + ? eventTypes$1.responderTerminate + : isResponderRelease ? eventTypes$1.responderRelease : null; if (finalTouch) { var finalEvent = ResponderSyntheticEvent.getPooled( finalTouch, @@ -2160,11 +2161,14 @@ var ResponderEventPlugin = { } }; -var customBubblingEventTypes = {}; -var customDirectEventTypes = {}; +var customBubblingEventTypes$1 = + ReactNativeViewConfigRegistry.customBubblingEventTypes; +var customDirectEventTypes$1 = + ReactNativeViewConfigRegistry.customDirectEventTypes; +var eventTypes$2 = ReactNativeViewConfigRegistry.eventTypes; var ReactNativeBridgeEventPlugin = { - eventTypes: {}, + eventTypes: eventTypes$2, /** * @see {EventPluginHub.extractEvents} @@ -2179,8 +2183,8 @@ var ReactNativeBridgeEventPlugin = { // Probably a node belonging to another renderer's tree. return null; } - var bubbleDispatchConfig = customBubblingEventTypes[topLevelType]; - var directDispatchConfig = customDirectEventTypes[topLevelType]; + var bubbleDispatchConfig = customBubblingEventTypes$1[topLevelType]; + var directDispatchConfig = customDirectEventTypes$1[topLevelType]; invariant( bubbleDispatchConfig || directDispatchConfig, 'Unsupported top level event type "%s" dispatched', @@ -2200,45 +2204,6 @@ var ReactNativeBridgeEventPlugin = { return null; } return event; - }, - - processEventTypes: function(viewConfig) { - var bubblingEventTypes = viewConfig.bubblingEventTypes, - directEventTypes = viewConfig.directEventTypes; - - { - if (bubblingEventTypes != null && directEventTypes != null) { - for (var topLevelType in directEventTypes) { - invariant( - bubblingEventTypes[topLevelType] == null, - "Event cannot be both direct and bubbling: %s", - topLevelType - ); - } - } - } - - if (bubblingEventTypes != null) { - for (var _topLevelType in bubblingEventTypes) { - if (customBubblingEventTypes[_topLevelType] == null) { - ReactNativeBridgeEventPlugin.eventTypes[ - _topLevelType - ] = customBubblingEventTypes[_topLevelType] = - bubblingEventTypes[_topLevelType]; - } - } - } - - if (directEventTypes != null) { - for (var _topLevelType2 in directEventTypes) { - if (customDirectEventTypes[_topLevelType2] == null) { - ReactNativeBridgeEventPlugin.eventTypes[ - _topLevelType2 - ] = customDirectEventTypes[_topLevelType2] = - directEventTypes[_topLevelType2]; - } - } - } } }; @@ -2402,56 +2367,6 @@ function createPortal( }; } -// Use to restore controlled state after a change event has fired. - -var fiberHostComponent = 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; - } - invariant( - fiberHostComponent && - typeof fiberHostComponent.restoreControlledState === "function", - "Fiber needs to be injected to handle a fiber target for controlled " + - "events. This error is likely caused by a bug in React. Please file an issue." - ); - var props = getFiberCurrentPropsFromNode(internalInstance.stateNode); - fiberHostComponent.restoreControlledState( - 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 @@ -2467,33 +2382,6 @@ var _interactiveUpdates = function(fn, a, b) { }; var _flushInteractiveUpdates = 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 _batchedUpdates(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. - _flushInteractiveUpdates(); - restoreStateIfNeeded(); - } - } -} - var injection$2 = { injectRenderer: function(renderer) { _batchedUpdates = renderer.batchedUpdates; @@ -2502,195 +2390,10 @@ var injection$2 = { } }; -var TouchHistoryMath = { - /** - * This code is optimized and not intended to look beautiful. This allows - * computing of touch centroids that have moved after `touchesChangedAfter` - * timeStamp. You can compute the current centroid involving all touches - * moves after `touchesChangedAfter`, or you can compute the previous - * centroid of all touches that were moved after `touchesChangedAfter`. - * - * @param {TouchHistoryMath} touchHistory Standard Responder touch track - * data. - * @param {number} touchesChangedAfter timeStamp after which moved touches - * are considered "actively moving" - not just "active". - * @param {boolean} isXAxis Consider `x` dimension vs. `y` dimension. - * @param {boolean} ofCurrent Compute current centroid for actively moving - * touches vs. previous centroid of now actively moving touches. - * @return {number} value of centroid in specified dimension. - */ - centroidDimension: function( - touchHistory, - touchesChangedAfter, - isXAxis, - ofCurrent - ) { - var touchBank = touchHistory.touchBank; - var total = 0; - var count = 0; - - var oneTouchData = - touchHistory.numberActiveTouches === 1 - ? touchHistory.touchBank[touchHistory.indexOfSingleActiveTouch] - : null; - - if (oneTouchData !== null) { - if ( - oneTouchData.touchActive && - oneTouchData.currentTimeStamp > touchesChangedAfter - ) { - total += - ofCurrent && isXAxis - ? oneTouchData.currentPageX - : ofCurrent && !isXAxis - ? oneTouchData.currentPageY - : !ofCurrent && isXAxis - ? oneTouchData.previousPageX - : oneTouchData.previousPageY; - count = 1; - } - } else { - for (var i = 0; i < touchBank.length; i++) { - var touchTrack = touchBank[i]; - if ( - touchTrack !== null && - touchTrack !== undefined && - touchTrack.touchActive && - touchTrack.currentTimeStamp >= touchesChangedAfter - ) { - var toAdd = void 0; // Yuck, program temporarily in invalid state. - if (ofCurrent && isXAxis) { - toAdd = touchTrack.currentPageX; - } else if (ofCurrent && !isXAxis) { - toAdd = touchTrack.currentPageY; - } else if (!ofCurrent && isXAxis) { - toAdd = touchTrack.previousPageX; - } else { - toAdd = touchTrack.previousPageY; - } - total += toAdd; - count++; - } - } - } - return count > 0 ? total / count : TouchHistoryMath.noCentroid; - }, - - currentCentroidXOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - true, // isXAxis - true - ); - }, - - currentCentroidYOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - false, // isXAxis - true - ); - }, - - previousCentroidXOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - true, // isXAxis - false - ); - }, - - previousCentroidYOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - false, // isXAxis - false - ); - }, - - currentCentroidX: function(touchHistory) { - return TouchHistoryMath.centroidDimension( - touchHistory, - 0, // touchesChangedAfter - true, // isXAxis - true - ); - }, - - currentCentroidY: function(touchHistory) { - return TouchHistoryMath.centroidDimension( - touchHistory, - 0, // touchesChangedAfter - false, // isXAxis - true - ); - }, - - noCentroid: -1 -}; - // TODO: this is special because it gets imported during build. var ReactVersion = "16.3.1"; -function _classCallCheck(instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); - } -} - -var objects = {}; -var uniqueID = 1; -var emptyObject$2 = {}; - -var ReactNativePropRegistry = (function() { - function ReactNativePropRegistry() { - _classCallCheck(this, ReactNativePropRegistry); - } - - ReactNativePropRegistry.register = function register(object) { - var id = ++uniqueID; - { - Object.freeze(object); - } - objects[id] = object; - return id; - }; - - ReactNativePropRegistry.getByID = function getByID(id) { - if (!id) { - // Used in the style={[condition && id]} pattern, - // we want it to be a no-op when the value is false or null - return emptyObject$2; - } - - var object = objects[id]; - if (!object) { - console.warn("Invalid style with id `" + id + "`. Skipping ..."); - return emptyObject$2; - } - return object; - }; - - return ReactNativePropRegistry; -})(); - // Modules provided by RN: var emptyObject$1 = {}; @@ -2717,13 +2420,6 @@ function defaultDiffer(prevProp, nextProp) { } } -function resolveObject(idOrObject) { - if (typeof idOrObject === "number") { - return ReactNativePropRegistry.getByID(idOrObject); - } - return idOrObject; -} - function restoreDeletedValuesInNestedArray( updatePayload, node, @@ -2739,7 +2435,7 @@ function restoreDeletedValuesInNestedArray( ); } } else if (node && removedKeyCount > 0) { - var obj = resolveObject(node); + var obj = node; for (var propKey in removedKeys) { if (!removedKeys[propKey]) { continue; @@ -2843,12 +2539,7 @@ function diffNestedProperty( if (!Array.isArray(prevProp) && !Array.isArray(nextProp)) { // Both are leaves, we can diff the leaves. - return diffProperties( - updatePayload, - resolveObject(prevProp), - resolveObject(nextProp), - validAttributes - ); + return diffProperties(updatePayload, prevProp, nextProp, validAttributes); } if (Array.isArray(prevProp) && Array.isArray(nextProp)) { @@ -2867,14 +2558,14 @@ function diffNestedProperty( // $FlowFixMe - We know that this is always an object when the input is. flattenStyle(prevProp), // $FlowFixMe - We know that this isn't an array because of above flow. - resolveObject(nextProp), + nextProp, validAttributes ); } return diffProperties( updatePayload, - resolveObject(prevProp), + prevProp, // $FlowFixMe - We know that this is always an object when the input is. flattenStyle(nextProp), validAttributes @@ -2893,11 +2584,7 @@ function addNestedProperty(updatePayload, nextProp, validAttributes) { if (!Array.isArray(nextProp)) { // Add each property of the leaf. - return addProperties( - updatePayload, - resolveObject(nextProp), - validAttributes - ); + return addProperties(updatePayload, nextProp, validAttributes); } for (var i = 0; i < nextProp.length; i++) { @@ -2923,11 +2610,7 @@ function clearNestedProperty(updatePayload, prevProp, validAttributes) { if (!Array.isArray(prevProp)) { // Add each property of the leaf. - return clearProperties( - updatePayload, - resolveObject(prevProp), - validAttributes - ); + return clearProperties(updatePayload, prevProp, validAttributes); } for (var i = 0; i < prevProp.length; i++) { @@ -3214,361 +2897,195 @@ function warnForStyleProps(props, validAttributes) { } } -/** - * `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 ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; - -var ReactCurrentOwner = ReactInternals.ReactCurrentOwner; -var ReactDebugCurrentFrame = ReactInternals.ReactDebugCurrentFrame; - -function getComponentName(fiber) { - var type = fiber.type; - - if (typeof type === "function") { - return type.displayName || type.name; - } - if (typeof type === "string") { - return type; - } - switch (type) { - case REACT_FRAGMENT_TYPE: - return "ReactFragment"; - case REACT_PORTAL_TYPE: - return "ReactPortal"; - case REACT_CALL_TYPE: - return "ReactCall"; - case REACT_RETURN_TYPE: - return "ReactReturn"; - } - return null; -} - -// TODO: Share this module between Fabric and React Native renderers -// so that both can be used in the same tree. - -var findHostInstance = function(fiber) { - return null; -}; - -var findHostInstanceFabric = function(fiber) { - return null; -}; - -function injectFindHostInstanceFabric(impl) { - findHostInstanceFabric = impl; -} - -/** - * ReactNative vs ReactWeb - * ----------------------- - * React treats some pieces of data opaquely. This means that the information - * is first class (it can be passed around), but cannot be inspected. This - * allows us to build infrastructure that reasons about resources, without - * making assumptions about the nature of those resources, and this allows that - * infra to be shared across multiple platforms, where the resources are very - * different. General infra (such as `ReactMultiChild`) reasons opaquely about - * the data, but platform specific code (such as `ReactNativeBaseComponent`) can - * make assumptions about the data. - * - * - * `rootNodeID`, uniquely identifies a position in the generated native view - * tree. Many layers of composite components (created with `React.createClass`) - * can all share the same `rootNodeID`. - * - * `nodeHandle`: A sufficiently unambiguous way to refer to a lower level - * resource (dom node, native view etc). The `rootNodeID` is sufficient for web - * `nodeHandle`s, because the position in a tree is always enough to uniquely - * identify a DOM node (we never have nodes in some bank outside of the - * document). The same would be true for `ReactNative`, but we must maintain a - * mapping that we can send efficiently serializable - * strings across native boundaries. - * - * Opaque name TodaysWebReact FutureWebWorkerReact ReactNative - * ---------------------------------------------------------------------------- - * nodeHandle N/A rootNodeID tag - */ - -// TODO (bvaughn) Rename the findNodeHandle module to something more descriptive -// eg findInternalHostInstance. This will reduce the likelihood of someone -// accidentally deep-requiring this version. -function findNodeHandle(componentOrHandle) { - { - var owner = ReactCurrentOwner.current; - if (owner !== null && owner.stateNode !== null) { - !owner.stateNode._warnedAboutRefsInRender - ? warning( - 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) || "A component" - ) - : void 0; - - owner.stateNode._warnedAboutRefsInRender = true; - } - } - if (componentOrHandle == null) { - return null; - } - if (typeof componentOrHandle === "number") { - // Already a node handle - return componentOrHandle; - } - - var component = componentOrHandle; - - // TODO (balpert): Wrap iOS native components in a composite wrapper, then - // ReactInstanceMap.get here will always succeed for mounted components - var internalInstance = get(component); - if (internalInstance) { - return ( - findHostInstance(internalInstance) || - findHostInstanceFabric(internalInstance) - ); - } else { - if (component) { - return component; - } else { - invariant( - // Native - (typeof component === "object" && "_nativeTag" in component) || - // Composite - (component.render != null && typeof component.render === "function"), - "findNodeHandle(...): Argument is not a component " + - "(type: %s, keys: %s)", - typeof component, - Object.keys(component) - ); - invariant( - false, - "findNodeHandle(...): Unable to find node handle for unmounted " + - "component." - ); - } - } -} - -/** - * External users of findNodeHandle() expect the host tag number return type. - * The injected findNodeHandle() strategy returns the instance wrapper though. - * See NativeMethodsMixin#setNativeProps for more info on why this is done. - */ -function findNumericNodeHandleFiber(componentOrHandle) { - var instance = findNodeHandle(componentOrHandle); - if (instance == null || typeof instance === "number") { - return instance; - } - return instance._nativeTag; -} - // Modules provided by RN: -/** - * `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 = { +var NativeMethodsMixin = function(findNodeHandle, findHostInstance) { /** - * 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: + * `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. * - * - x - * - y - * - width - * - height - * - pageX - * - pageY + * 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 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. + * Note the Flow $Exact<> syntax is required to support mixins. + * React createClass mixins can only be used with exact types. */ - measure: function(callback) { - UIManager.measure( - findNumericNodeHandleFiber(this), - mountSafeCallback(this, callback) - ); - }, + 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) { + UIManager.measure( + findNodeHandle(this), + mountSafeCallback(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) { - UIManager.measureInWindow( - findNumericNodeHandleFiber(this), - mountSafeCallback(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) { + UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback(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 - * `findNumericNodeHandle(component)`. - */ - measureLayout: function( - relativeToNativeNode, - onSuccess, - onFail /* currently unused */ - ) { - UIManager.measureLayout( - findNumericNodeHandleFiber(this), + /** + * 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, - mountSafeCallback(this, onFail), - mountSafeCallback(this, onSuccess) - ); - }, + onSuccess, + onFail /* currently unused */ + ) { + UIManager.measureLayout( + findNodeHandle(this), + relativeToNativeNode, + mountSafeCallback(this, onFail), + mountSafeCallback(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 findNumericNodeHandle() 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 = findNodeHandle(this); - } catch (error) {} + /** + * 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 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; + } - var viewConfig = maybeInstance.viewConfig; + var viewConfig = maybeInstance.viewConfig; - { - warnForStyleProps(nativeProps, viewConfig.validAttributes); - } + { + warnForStyleProps(nativeProps, viewConfig.validAttributes); + } - var updatePayload = create(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) { - UIManager.updateView( - maybeInstance._nativeTag, - viewConfig.uiViewClassName, - updatePayload - ); + // 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) { + UIManager.updateView( + maybeInstance._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() { + TextInputState.focusTextInput(findNodeHandle(this)); + }, + + /** + * Removes focus from an input or view. This is the opposite of `focus()`. + */ + blur: function() { + TextInputState.blurTextInput(findNodeHandle(this)); } - }, + }; - /** - * Requests focus for the given input or view. The exact behavior triggered - * will depend on the platform and type of view. - */ - focus: function() { - TextInputState.focusTextInput(findNumericNodeHandleFiber(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; + invariant( + !NativeMethodsMixin_DEV.componentWillMount && + !NativeMethodsMixin_DEV.componentWillReceiveProps && + !NativeMethodsMixin_DEV.UNSAFE_componentWillMount && + !NativeMethodsMixin_DEV.UNSAFE_componentWillReceiveProps, + "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); + }; - /** - * Removes focus from an input or view. This is the opposite of `focus()`. - */ - blur: function() { - TextInputState.blurTextInput(findNumericNodeHandleFiber(this)); + // 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; } -}; - -{ - // 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; - invariant( - !NativeMethodsMixin_DEV.componentWillMount && - !NativeMethodsMixin_DEV.componentWillReceiveProps && - !NativeMethodsMixin_DEV.UNSAFE_componentWillMount && - !NativeMethodsMixin_DEV.UNSAFE_componentWillReceiveProps, - "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) { +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } @@ -3607,166 +3124,171 @@ function _inherits(subClass, superClass) { } // Modules provided by RN: -/** - * 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); +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); + function ReactNativeComponent() { + _classCallCheck(this, ReactNativeComponent); - return _possibleConstructorReturn( - this, - _React$Component.apply(this, arguments) - ); - } + return _possibleConstructorReturn( + this, + _React$Component.apply(this, arguments) + ); + } - /** - * Removes focus. This is the opposite of `focus()`. - */ + /** + * 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() { - TextInputState.blurTextInput(findNumericNodeHandleFiber(this)); - }; + /** + * 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() { + TextInputState.blurTextInput(findNodeHandle(this)); + }; - /** - * Requests focus. The exact behavior depends on the platform and view. - */ + /** + * Requests focus. The exact behavior depends on the platform and view. + */ - ReactNativeComponent.prototype.focus = function focus() { - TextInputState.focusTextInput(findNumericNodeHandleFiber(this)); - }; + ReactNativeComponent.prototype.focus = function focus() { + 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. - */ + /** + * 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) { - UIManager.measure( - findNumericNodeHandleFiber(this), - mountSafeCallback(this, callback) - ); - }; + ReactNativeComponent.prototype.measure = function measure(callback) { + UIManager.measure( + findNodeHandle(this), + mountSafeCallback(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. - */ + /** + * 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 - ) { - UIManager.measureInWindow( - findNumericNodeHandleFiber(this), - mountSafeCallback(this, callback) - ); - }; + ReactNativeComponent.prototype.measureInWindow = function measureInWindow( + callback + ) { + UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback(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)`. - */ + /** + * 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 */ - ) { - UIManager.measureLayout( - findNumericNodeHandleFiber(this), + ReactNativeComponent.prototype.measureLayout = function measureLayout( relativeToNativeNode, - mountSafeCallback(this, onFail), - mountSafeCallback(this, onSuccess) - ); - }; + onSuccess, + onFail /* currently unused */ + ) { + UIManager.measureLayout( + findNodeHandle(this), + relativeToNativeNode, + mountSafeCallback(this, onFail), + mountSafeCallback(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)). - */ + /** + * 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 = findNodeHandle(this); - } catch (error) {} + 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 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; + } - var viewConfig = - maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + var viewConfig = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; - var updatePayload = create(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) { - UIManager.updateView( - maybeInstance._nativeTag, - viewConfig.uiViewClassName, - updatePayload - ); - } - }; + // 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) { + UIManager.updateView( + maybeInstance._nativeTag, + viewConfig.uiViewClassName, + updatePayload + ); + } + }; + + return ReactNativeComponent; + })(React.Component); + + // eslint-disable-next-line no-unused-expressions return ReactNativeComponent; -})(React.Component); +}; var hasNativePerformanceNow = typeof performance === "object" && typeof performance.now === "function"; @@ -3817,47 +3339,55 @@ function cancelDeferredCallback(callbackID) { clearTimeout(callbackID); } -var viewConfigCallbacks = new Map(); -var viewConfigs = new Map(); - /** - * 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. + * `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. */ -function register(name, callback) { - invariant( - !viewConfigCallbacks.has(name), - "Tried to register two views with the same name %s", - name - ); - viewConfigCallbacks.set(name, callback); - return name; -} /** - * Retrieves a config for the specified view. - * If this is the first time the view has been used, - * This configuration will be lazy-loaded from UIManager. + * 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$1(name) { - var viewConfig = void 0; - if (!viewConfigs.has(name)) { - var callback = viewConfigCallbacks.get(name); - invariant( - typeof callback === "function", - "View config not found for name %s", - name - ); - viewConfigCallbacks.set(name, null); - viewConfig = callback(); - viewConfigs.set(name, viewConfig); - } else { - viewConfig = viewConfigs.get(name); + +function get$1(key) { + return key._reactInternalFiber; +} + +function set(key, value) { + key._reactInternalFiber = value; +} + +var ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; + +var ReactCurrentOwner = ReactInternals.ReactCurrentOwner; +var ReactDebugCurrentFrame = ReactInternals.ReactDebugCurrentFrame; + +function getComponentName(fiber) { + var type = fiber.type; + + if (typeof type === "function") { + return type.displayName || type.name; + } + if (typeof type === "string") { + return type; } - invariant(viewConfig, "View config not found for name %s", name); - return viewConfig; + switch (type) { + case REACT_FRAGMENT_TYPE: + return "ReactFragment"; + case REACT_PORTAL_TYPE: + return "ReactPortal"; + case REACT_CALL_TYPE: + return "ReactCall"; + case REACT_RETURN_TYPE: + return "ReactReturn"; + } + return null; } // Don't change these two values. They're used by React Dev Tools. @@ -3940,7 +3470,7 @@ function isMounted(component) { } } - var fiber = get(component); + var fiber = get$1(component); if (!fiber) { return false; } @@ -5947,7 +5477,7 @@ var ReactFiberClassComponent = function( var updater = { isMounted: isMounted, enqueueSetState: function(instance, partialState, callback) { - var fiber = get(instance); + var fiber = get$1(instance); callback = callback === undefined ? null : callback; { warnOnInvalidCallback(callback, "setState"); @@ -5966,7 +5496,7 @@ var ReactFiberClassComponent = function( scheduleWork(fiber, expirationTime); }, enqueueReplaceState: function(instance, state, callback) { - var fiber = get(instance); + var fiber = get$1(instance); callback = callback === undefined ? null : callback; { warnOnInvalidCallback(callback, "replaceState"); @@ -5985,7 +5515,7 @@ var ReactFiberClassComponent = function( scheduleWork(fiber, expirationTime); }, enqueueForceUpdate: function(instance, callback) { - var fiber = get(instance); + var fiber = get$1(instance); callback = callback === undefined ? null : callback; { warnOnInvalidCallback(callback, "forceUpdate"); @@ -9418,7 +8948,7 @@ var ReactFiberCompleteWork = function( function markUpdate(workInProgress) { // Tag the fiber with an update effect. This turns a Placement into - // an UpdateAndPlacement. + // a PlacementAndUpdate. workInProgress.effectTag |= Update; } @@ -13584,7 +13114,7 @@ var ReactFiberReconciler$1 = function(config) { return emptyObject; } - var fiber = get(parentComponent); + var fiber = get$1(parentComponent); var parentContext = findCurrentUnmaskedContext(fiber); return isContextProvider(fiber) ? processChildContext(fiber, parentContext) @@ -13682,7 +13212,19 @@ var ReactFiberReconciler$1 = function(config) { ); } - function findHostInstance(fiber) { + function findHostInstance(component) { + var fiber = get$1(component); + if (fiber === undefined) { + if (typeof component.render === "function") { + invariant(false, "Unable to find node on an unmounted component."); + } else { + invariant( + false, + "Argument appears to not be a ReactComponent. Keys: %s", + Object.keys(component) + ); + } + } var hostFiber = findCurrentHostFiber(fiber); if (hostFiber === null) { return null; @@ -13775,7 +13317,11 @@ var ReactFiberReconciler$1 = function(config) { return injectInternals( Object.assign({}, devToolsConfig, { findHostInstanceByFiber: function(fiber) { - return findHostInstance(fiber); + var hostFiber = findCurrentHostFiber(fiber); + if (hostFiber === null) { + return null; + } + return hostFiber.stateNode; }, findFiberByHostInstance: function(instance) { if (!findFiberByHostInstance) { @@ -13805,62 +13351,26 @@ var reactReconciler = ReactFiberReconciler$3["default"] ? ReactFiberReconciler$3["default"] : ReactFiberReconciler$3; -/** - * Keeps track of allocating and associating native "tags" which are numeric, - * unique view IDs. All the native tags are negative numbers, to avoid - * collisions, but in the JS we keep track of them as positive integers to store - * them effectively in Arrays. So we must refer to them as "inverses" of the - * native tags (that are * normally negative). - * - * It *must* be the case that every `rootNodeID` always maps to the exact same - * `tag` forever. The easiest way to accomplish this is to never delete - * anything from this table. - * Why: Because `dangerouslyReplaceNodeWithMarkupByID` relies on being able to - * unmount a component with a `rootNodeID`, then mount a new one in its place, - */ -var INITIAL_TAG_COUNT = 1; -var ReactNativeTagHandles = { - tagsStartAt: INITIAL_TAG_COUNT, - tagCount: INITIAL_TAG_COUNT, - - allocateTag: function() { - // Skip over root IDs as those are reserved for native - while (this.reactTagIsNativeTopRootID(ReactNativeTagHandles.tagCount)) { - ReactNativeTagHandles.tagCount++; - } - var tag = ReactNativeTagHandles.tagCount; - ReactNativeTagHandles.tagCount++; - return tag; - }, - - assertRootTag: function(tag) { - invariant( - this.reactTagIsNativeTopRootID(tag), - "Expect a native root tag, instead got %s", - tag - ); - }, - - reactTagIsNativeTopRootID: function(reactTag) { - // We reserve all tags that are 1 mod 10 for native root views - return reactTag % 10 === 1; - } -}; - -function _classCallCheck$2(instance, Constructor) { +function _classCallCheck$1(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } // Modules provided by RN: +// 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; + /** * This is used for refs on host components. */ var ReactFabricHostComponent = (function() { function ReactFabricHostComponent(tag, viewConfig, props) { - _classCallCheck$2(this, ReactFabricHostComponent); + _classCallCheck$1(this, ReactFabricHostComponent); this._nativeTag = tag; this.viewConfig = viewConfig; @@ -13936,8 +13446,10 @@ var ReactFabricRenderer = reactReconciler({ hostContext, internalInstanceHandle ) { - var tag = ReactNativeTagHandles.allocateTag(); - var viewConfig = get$1(type); + var tag = nextReactTag; + nextReactTag += 2; + + var viewConfig = ReactNativeViewConfigRegistry.get(type); { for (var key in viewConfig.validAttributes) { @@ -13970,7 +13482,8 @@ var ReactFabricRenderer = reactReconciler({ hostContext, internalInstanceHandle ) { - var tag = ReactNativeTagHandles.allocateTag(); + var tag = nextReactTag; + nextReactTag += 2; var node = FabricUIManager.createNode( tag, // reactTag @@ -14190,56 +13703,59 @@ var getInspectorDataForViewTag = void 0; }; } -/** - * Creates a renderable ReactNative host component. - * Use this method for view configs that are loaded from UIManager. - * Use createReactNativeComponentClass() for view configs defined within JavaScript. - * - * @param {string} config iOS View configuration. - * @private - */ -var createReactNativeComponentClass = function(name, callback) { - return register(name, callback); -}; +var findHostInstance = ReactFabricRenderer.findHostInstance; -// Module provided by RN: -/** - * Capture an image of the screen, window or an individual view. The image - * will be stored in a temporary file that will only exist for as long as the - * app is running. - * - * The `view` argument can be the literal string `window` if you want to - * capture the entire window, or it can be a reference to a specific - * React Native component. - * - * The `options` argument may include: - * - width/height (number) - the width and height of the image to capture. - * - format (string) - either 'png' or 'jpeg'. Defaults to 'png'. - * - quality (number) - the quality when using jpeg. 0.0 - 1.0 (default). - * - * Returns a Promise. - * @platform ios - */ -function takeSnapshot(view, options) { - if (typeof view !== "number" && view !== "window") { - view = findNumericNodeHandleFiber(view) || "window"; - } +function findNodeHandle(componentOrHandle) { + { + var owner = ReactCurrentOwner.current; + if (owner !== null && owner.stateNode !== null) { + !owner.stateNode._warnedAboutRefsInRender + ? warning( + 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) || "A component" + ) + : void 0; - // Call the hidden '__takeSnapshot' method; the main one throws an error to - // prevent accidental backwards-incompatible usage. - return UIManager.__takeSnapshot(view, options); + 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 = findHostInstance(componentOrHandle); + if (hostInstance == null) { + return hostInstance; + } + if (hostInstance.canonical) { + // Fabric + return hostInstance.canonical._nativeTag; + } + return hostInstance._nativeTag; } -injectFindHostInstanceFabric(ReactFabricRenderer.findHostInstance); - injection$2.injectRenderer(ReactFabricRenderer); var roots = new Map(); var ReactFabric = { - NativeComponent: ReactNativeComponent, + NativeComponent: ReactNativeComponent(findNodeHandle, findHostInstance), - findNodeHandle: findNumericNodeHandleFiber, + findNodeHandle: findNodeHandle, render: function(element, containerTag, callback) { var root = roots.get(containerTag); @@ -14263,9 +13779,6 @@ var ReactFabric = { }); } }, - unmountComponentAtNodeAndRemoveContainer: function(containerTag) { - ReactFabric.unmountComponentAtNode(containerTag); - }, createPortal: function(children, containerTag) { var key = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; @@ -14273,20 +13786,11 @@ var ReactFabric = { return createPortal(children, containerTag, null, key); }, - unstable_batchedUpdates: batchedUpdates, - - flushSync: ReactFabricRenderer.flushSync, - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { // Used as a mixin in many createClass-based components - NativeMethodsMixin: NativeMethodsMixin, + NativeMethodsMixin: NativeMethodsMixin(findNodeHandle, findHostInstance), // Used by react-native-github/Libraries/ components - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin, // requireNativeComponent - ReactNativeComponentTree: ReactNativeComponentTree, // ScrollResponder - ReactNativePropRegistry: ReactNativePropRegistry, // flattenStyle, Stylesheet - TouchHistoryMath: TouchHistoryMath, // PanResponder - createReactNativeComponentClass: createReactNativeComponentClass, // RCTText, RCTView, ReactNativeART - takeSnapshot: takeSnapshot + ReactNativeComponentTree: ReactNativeComponentTree } }; diff --git a/Libraries/Renderer/ReactFabric-prod.js b/Libraries/Renderer/ReactFabric-prod.js index c57d9bb9d0c927..d264fcf0163716 100644 --- a/Libraries/Renderer/ReactFabric-prod.js +++ b/Libraries/Renderer/ReactFabric-prod.js @@ -13,6 +13,7 @@ require("InitializeCore"); var invariant = require("fbjs/lib/invariant"), emptyFunction = require("fbjs/lib/emptyFunction"), + ReactNativeViewConfigRegistry = require("ReactNativeViewConfigRegistry"), UIManager = require("UIManager"), TextInputState = require("TextInputState"), deepDiffer = require("deepDiffer"), @@ -528,7 +529,7 @@ function changeResponder(nextResponderInst, blockHostResponder) { blockHostResponder ); } -var eventTypes = { +var eventTypes$1 = { startShouldSetResponder: { phasedRegistrationNames: { bubbled: "onStartShouldSetResponder", @@ -568,7 +569,7 @@ var eventTypes = { _getResponder: function() { return responderInst; }, - eventTypes: eventTypes, + eventTypes: eventTypes$1, extractEvents: function( topLevelType, targetInst, @@ -594,12 +595,12 @@ var eventTypes = { isMoveish(topLevelType)) ) { var JSCompiler_temp = isStartish(topLevelType) - ? eventTypes.startShouldSetResponder + ? eventTypes$1.startShouldSetResponder : isMoveish(topLevelType) - ? eventTypes.moveShouldSetResponder + ? eventTypes$1.moveShouldSetResponder : "topSelectionChange" === topLevelType - ? eventTypes.selectionChangeShouldSetResponder - : eventTypes.scrollShouldSetResponder; + ? eventTypes$1.selectionChangeShouldSetResponder + : eventTypes$1.scrollShouldSetResponder; if (responderInst) b: { var JSCompiler_temp$jscomp$0 = responderInst; @@ -685,7 +686,7 @@ var eventTypes = { JSCompiler_temp && JSCompiler_temp !== responderInst ? ((JSCompiler_temp$jscomp$0 = void 0), (targetInst = ResponderSyntheticEvent.getPooled( - eventTypes.responderGrant, + eventTypes$1.responderGrant, JSCompiler_temp, nativeEvent, nativeEventTarget @@ -695,7 +696,7 @@ var eventTypes = { (depthA = !0 === executeDirectDispatch(targetInst)), responderInst ? ((tempA = ResponderSyntheticEvent.getPooled( - eventTypes.responderTerminationRequest, + eventTypes$1.responderTerminationRequest, responderInst, nativeEvent, nativeEventTarget @@ -707,7 +708,7 @@ var eventTypes = { tempA.isPersistent() || tempA.constructor.release(tempA), tempB ? ((tempA = ResponderSyntheticEvent.getPooled( - eventTypes.responderTerminate, + eventTypes$1.responderTerminate, responderInst, nativeEvent, nativeEventTarget @@ -721,7 +722,7 @@ var eventTypes = { )), changeResponder(JSCompiler_temp, depthA)) : ((JSCompiler_temp = ResponderSyntheticEvent.getPooled( - eventTypes.responderReject, + eventTypes$1.responderReject, JSCompiler_temp, nativeEvent, nativeEventTarget @@ -749,10 +750,10 @@ var eventTypes = { depthA = responderInst && isEndish(topLevelType); if ( (JSCompiler_temp$jscomp$0 = JSCompiler_temp$jscomp$0 - ? eventTypes.responderStart + ? eventTypes$1.responderStart : targetInst - ? eventTypes.responderMove - : depthA ? eventTypes.responderEnd : null) + ? eventTypes$1.responderMove + : depthA ? eventTypes$1.responderEnd : null) ) (JSCompiler_temp$jscomp$0 = ResponderSyntheticEvent.getPooled( JSCompiler_temp$jscomp$0, @@ -803,8 +804,8 @@ var eventTypes = { } if ( (topLevelType = JSCompiler_temp$jscomp$0 - ? eventTypes.responderTerminate - : topLevelType ? eventTypes.responderRelease : null) + ? eventTypes$1.responderTerminate + : topLevelType ? eventTypes$1.responderRelease : null) ) (nativeEvent = ResponderSyntheticEvent.getPooled( topLevelType, @@ -836,10 +837,12 @@ var eventTypes = { } } }, - customBubblingEventTypes = {}, - customDirectEventTypes = {}, + customBubblingEventTypes$1 = + ReactNativeViewConfigRegistry.customBubblingEventTypes, + customDirectEventTypes$1 = + ReactNativeViewConfigRegistry.customDirectEventTypes, ReactNativeBridgeEventPlugin = { - eventTypes: {}, + eventTypes: ReactNativeViewConfigRegistry.eventTypes, extractEvents: function( topLevelType, targetInst, @@ -847,8 +850,8 @@ var eventTypes = { nativeEventTarget ) { if (null == targetInst) return null; - var bubbleDispatchConfig = customBubblingEventTypes[topLevelType], - directDispatchConfig = customDirectEventTypes[topLevelType]; + var bubbleDispatchConfig = customBubblingEventTypes$1[topLevelType], + directDispatchConfig = customDirectEventTypes$1[topLevelType]; invariant( bubbleDispatchConfig || directDispatchConfig, 'Unsupported top level event type "%s" dispatched', @@ -866,24 +869,6 @@ var eventTypes = { forEachAccumulated(topLevelType, accumulateDirectDispatchesSingle); else return null; return topLevelType; - }, - processEventTypes: function(viewConfig) { - var bubblingEventTypes = viewConfig.bubblingEventTypes; - viewConfig = viewConfig.directEventTypes; - if (null != bubblingEventTypes) - for (var _topLevelType in bubblingEventTypes) - null == customBubblingEventTypes[_topLevelType] && - (ReactNativeBridgeEventPlugin.eventTypes[ - _topLevelType - ] = customBubblingEventTypes[_topLevelType] = - bubblingEventTypes[_topLevelType]); - if (null != viewConfig) - for (var _topLevelType2 in viewConfig) - null == customDirectEventTypes[_topLevelType2] && - (ReactNativeBridgeEventPlugin.eventTypes[ - _topLevelType2 - ] = customDirectEventTypes[_topLevelType2] = - viewConfig[_topLevelType2]); } }, instanceCache = {}, @@ -968,155 +953,9 @@ function createPortal(children, containerInfo, implementation) { implementation: implementation }; } -var restoreTarget = null, - restoreQueue = null; -function restoreStateOfTarget(target) { - if ((target = getInstanceFromNode(target))) { - invariant( - null, - "Fiber needs to be injected to handle a fiber target for controlled events. This error is likely caused by a bug in React. Please file an issue." - ); - var props = getFiberCurrentPropsFromNode(target.stateNode); - null.restoreControlledState(target.stateNode, target.type, props); - } -} -function _batchedUpdates(fn, bookkeeping) { - return fn(bookkeeping); -} -function _flushInteractiveUpdates() {} -var isBatching = !1, - TouchHistoryMath = { - centroidDimension: function( - touchHistory, - touchesChangedAfter, - isXAxis, - ofCurrent - ) { - var touchBank = touchHistory.touchBank, - total = 0, - count = 0; - touchHistory = - 1 === touchHistory.numberActiveTouches - ? touchHistory.touchBank[touchHistory.indexOfSingleActiveTouch] - : null; - if (null !== touchHistory) - touchHistory.touchActive && - touchHistory.currentTimeStamp > touchesChangedAfter && - ((total += - ofCurrent && isXAxis - ? touchHistory.currentPageX - : ofCurrent && !isXAxis - ? touchHistory.currentPageY - : !ofCurrent && isXAxis - ? touchHistory.previousPageX - : touchHistory.previousPageY), - (count = 1)); - else - for ( - touchHistory = 0; - touchHistory < touchBank.length; - touchHistory++ - ) { - var touchTrack = touchBank[touchHistory]; - null !== touchTrack && - void 0 !== touchTrack && - touchTrack.touchActive && - touchTrack.currentTimeStamp >= touchesChangedAfter && - ((total += - ofCurrent && isXAxis - ? touchTrack.currentPageX - : ofCurrent && !isXAxis - ? touchTrack.currentPageY - : !ofCurrent && isXAxis - ? touchTrack.previousPageX - : touchTrack.previousPageY), - count++); - } - return 0 < count ? total / count : TouchHistoryMath.noCentroid; - }, - currentCentroidXOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - !0, - !0 - ); - }, - currentCentroidYOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - !1, - !0 - ); - }, - previousCentroidXOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - !0, - !1 - ); - }, - previousCentroidYOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - !1, - !1 - ); - }, - currentCentroidX: function(touchHistory) { - return TouchHistoryMath.centroidDimension(touchHistory, 0, !0, !0); - }, - currentCentroidY: function(touchHistory) { - return TouchHistoryMath.centroidDimension(touchHistory, 0, !1, !0); - }, - noCentroid: -1 - }, - objects = {}, - uniqueID = 1, - emptyObject$2 = {}, - ReactNativePropRegistry = (function() { - function ReactNativePropRegistry() { - if (!(this instanceof ReactNativePropRegistry)) - throw new TypeError("Cannot call a class as a function"); - } - ReactNativePropRegistry.register = function(object) { - var id = ++uniqueID; - objects[id] = object; - return id; - }; - ReactNativePropRegistry.getByID = function(id) { - if (!id) return emptyObject$2; - var object = objects[id]; - return object - ? object - : (console.warn("Invalid style with id `" + id + "`. Skipping ..."), - emptyObject$2); - }; - return ReactNativePropRegistry; - })(), - emptyObject$1 = {}, +var emptyObject$1 = {}, removedKeys = null, removedKeyCount = 0; -function resolveObject(idOrObject) { - return "number" === typeof idOrObject - ? ReactNativePropRegistry.getByID(idOrObject) - : idOrObject; -} function restoreDeletedValuesInNestedArray( updatePayload, node, @@ -1130,7 +969,7 @@ function restoreDeletedValuesInNestedArray( validAttributes ); else if (node && 0 < removedKeyCount) - for (i in ((node = resolveObject(node)), removedKeys)) + for (i in removedKeys) if (removedKeys[i]) { var _nextProp = node[i]; if (void 0 !== _nextProp) { @@ -1169,12 +1008,7 @@ function diffNestedProperty( ? clearNestedProperty(updatePayload, prevProp, validAttributes) : updatePayload; if (!Array.isArray(prevProp) && !Array.isArray(nextProp)) - return diffProperties( - updatePayload, - resolveObject(prevProp), - resolveObject(nextProp), - validAttributes - ); + return diffProperties(updatePayload, prevProp, nextProp, validAttributes); if (Array.isArray(prevProp) && Array.isArray(nextProp)) { var minLength = prevProp.length < nextProp.length ? prevProp.length : nextProp.length, @@ -1204,12 +1038,12 @@ function diffNestedProperty( ? diffProperties( updatePayload, flattenStyle(prevProp), - resolveObject(nextProp), + nextProp, validAttributes ) : diffProperties( updatePayload, - resolveObject(prevProp), + prevProp, flattenStyle(nextProp), validAttributes ); @@ -1217,9 +1051,11 @@ function diffNestedProperty( function addNestedProperty(updatePayload, nextProp, validAttributes) { if (!nextProp) return updatePayload; if (!Array.isArray(nextProp)) - return ( - (nextProp = resolveObject(nextProp)), - diffProperties(updatePayload, emptyObject$1, nextProp, validAttributes) + return diffProperties( + updatePayload, + emptyObject$1, + nextProp, + validAttributes ); for (var i = 0; i < nextProp.length; i++) updatePayload = addNestedProperty( @@ -1232,9 +1068,11 @@ function addNestedProperty(updatePayload, nextProp, validAttributes) { function clearNestedProperty(updatePayload, prevProp, validAttributes) { if (!prevProp) return updatePayload; if (!Array.isArray(prevProp)) - return ( - (prevProp = resolveObject(prevProp)), - diffProperties(updatePayload, prevProp, emptyObject$1, validAttributes) + return diffProperties( + updatePayload, + prevProp, + emptyObject$1, + validAttributes ); for (var i = 0; i < prevProp.length; i++) updatePayload = clearNestedProperty( @@ -1347,53 +1185,6 @@ function mountSafeCallback(context, callback) { } }; } -var ReactCurrentOwner = - React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner; -function getComponentName(fiber) { - fiber = fiber.type; - if ("function" === typeof fiber) return fiber.displayName || fiber.name; - if ("string" === typeof fiber) return fiber; - switch (fiber) { - case REACT_FRAGMENT_TYPE: - return "ReactFragment"; - case REACT_PORTAL_TYPE: - return "ReactPortal"; - case REACT_CALL_TYPE: - return "ReactCall"; - case REACT_RETURN_TYPE: - return "ReactReturn"; - } - return null; -} -function findHostInstanceFabric() { - return null; -} -function findNodeHandle(componentOrHandle) { - if (null == componentOrHandle) return null; - if ("number" === typeof componentOrHandle) return componentOrHandle; - var internalInstance = componentOrHandle._reactInternalFiber; - if (internalInstance) return findHostInstanceFabric(internalInstance); - if (componentOrHandle) return componentOrHandle; - invariant( - ("object" === typeof componentOrHandle && - "_nativeTag" in componentOrHandle) || - (null != componentOrHandle.render && - "function" === typeof componentOrHandle.render), - "findNodeHandle(...): Argument is not a component (type: %s, keys: %s)", - typeof componentOrHandle, - Object.keys(componentOrHandle) - ); - invariant( - !1, - "findNodeHandle(...): Unable to find node handle for unmounted component." - ); -} -function findNumericNodeHandleFiber(componentOrHandle) { - componentOrHandle = findNodeHandle(componentOrHandle); - return null == componentOrHandle || "number" === typeof componentOrHandle - ? componentOrHandle - : componentOrHandle._nativeTag; -} function _inherits(subClass, superClass) { if ("function" !== typeof superClass && null !== superClass) throw new TypeError( @@ -1413,75 +1204,7 @@ function _inherits(subClass, superClass) { ? Object.setPrototypeOf(subClass, superClass) : (subClass.__proto__ = superClass)); } -var ReactNativeComponent = (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() { - TextInputState.blurTextInput(findNumericNodeHandleFiber(this)); - }; - ReactNativeComponent.prototype.focus = function() { - TextInputState.focusTextInput(findNumericNodeHandleFiber(this)); - }; - ReactNativeComponent.prototype.measure = function(callback) { - UIManager.measure( - findNumericNodeHandleFiber(this), - mountSafeCallback(this, callback) - ); - }; - ReactNativeComponent.prototype.measureInWindow = function(callback) { - UIManager.measureInWindow( - findNumericNodeHandleFiber(this), - mountSafeCallback(this, callback) - ); - }; - ReactNativeComponent.prototype.measureLayout = function( - relativeToNativeNode, - onSuccess, - onFail - ) { - UIManager.measureLayout( - findNumericNodeHandleFiber(this), - relativeToNativeNode, - mountSafeCallback(this, onFail), - mountSafeCallback(this, onSuccess) - ); - }; - ReactNativeComponent.prototype.setNativeProps = function(nativeProps) { - var maybeInstance = void 0; - try { - maybeInstance = findNodeHandle(this); - } catch (error) {} - if (null != maybeInstance) { - var viewConfig = - maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; - nativeProps = diffProperties( - null, - emptyObject$1, - nativeProps, - viewConfig.validAttributes - ); - null != nativeProps && - UIManager.updateView( - maybeInstance._nativeTag, - viewConfig.uiViewClassName, - nativeProps - ); - } - }; - return ReactNativeComponent; - })(React.Component), - now = +var now = "object" === typeof performance && "function" === typeof performance.now ? function() { return performance.now(); @@ -1503,8 +1226,24 @@ function setTimeoutCallback() { scheduledCallback = null; null !== callback && callback(frameDeadlineObject); } -var viewConfigCallbacks = new Map(), - viewConfigs = new Map(); +var ReactCurrentOwner = + React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner; +function getComponentName(fiber) { + fiber = fiber.type; + if ("function" === typeof fiber) return fiber.displayName || fiber.name; + if ("string" === typeof fiber) return fiber; + switch (fiber) { + case REACT_FRAGMENT_TYPE: + return "ReactFragment"; + case REACT_PORTAL_TYPE: + return "ReactPortal"; + case REACT_CALL_TYPE: + return "ReactCall"; + case REACT_RETURN_TYPE: + return "ReactReturn"; + } + return null; +} function isFiberMountedImpl(fiber) { var node = fiber; if (fiber.alternate) for (; node["return"]; ) node = node["return"]; @@ -5649,10 +5388,6 @@ function ReactFiberReconciler$1(config) { scheduleWork(currentTime, expirationTime); return expirationTime; } - function findHostInstance(fiber) { - fiber = findCurrentHostFiber(fiber); - return null === fiber ? null : fiber.stateNode; - } var getPublicInstance = config.getPublicInstance; config = ReactFiberScheduler(config); var recalculateCurrentTime = config.recalculateCurrentTime, @@ -5731,7 +5466,19 @@ function ReactFiberReconciler$1(config) { return container.child.stateNode; } }, - findHostInstance: findHostInstance, + findHostInstance: function(component) { + var fiber = component._reactInternalFiber; + void 0 === fiber && + ("function" === typeof component.render + ? invariant(!1, "Unable to find node on an unmounted component.") + : invariant( + !1, + "Argument appears to not be a ReactComponent. Keys: %s", + Object.keys(component) + )); + component = findCurrentHostFiber(fiber); + return null === component ? null : component.stateNode; + }, findHostInstanceWithNoPortals: function(fiber) { fiber = findCurrentHostFiberWithNoPortals(fiber); return null === fiber ? null : fiber.stateNode; @@ -5741,7 +5488,8 @@ function ReactFiberReconciler$1(config) { return injectInternals( Object.assign({}, devToolsConfig, { findHostInstanceByFiber: function(fiber) { - return findHostInstance(fiber); + fiber = findCurrentHostFiber(fiber); + return null === fiber ? null : fiber.stateNode; }, findFiberByHostInstance: function(instance) { return findFiberByHostInstance @@ -5760,27 +5508,7 @@ var ReactFiberReconciler$2 = Object.freeze({ default: ReactFiberReconciler$1 }), reactReconciler = ReactFiberReconciler$3["default"] ? ReactFiberReconciler$3["default"] : ReactFiberReconciler$3, - ReactNativeTagHandles = { - tagsStartAt: 1, - tagCount: 1, - allocateTag: function() { - for (; this.reactTagIsNativeTopRootID(ReactNativeTagHandles.tagCount); ) - ReactNativeTagHandles.tagCount++; - var tag = ReactNativeTagHandles.tagCount; - ReactNativeTagHandles.tagCount++; - return tag; - }, - assertRootTag: function(tag) { - invariant( - this.reactTagIsNativeTopRootID(tag), - "Expect a native root tag, instead got %s", - tag - ); - }, - reactTagIsNativeTopRootID: function(reactTag) { - return 1 === reactTag % 10; - } - }, + nextReactTag = 2, ReactFabricHostComponent = (function() { function ReactFabricHostComponent(tag, viewConfig, props) { if (!(this instanceof ReactFabricHostComponent)) @@ -5843,21 +5571,10 @@ var ReactFiberReconciler$2 = Object.freeze({ default: ReactFiberReconciler$1 }), hostContext, internalInstanceHandle ) { - hostContext = ReactNativeTagHandles.allocateTag(); - if (viewConfigs.has(type)) var viewConfig = viewConfigs.get(type); - else - (viewConfig = viewConfigCallbacks.get(type)), - invariant( - "function" === typeof viewConfig, - "View config not found for name %s", - type - ), - viewConfigCallbacks.set(type, null), - (viewConfig = viewConfig()), - viewConfigs.set(type, viewConfig); - invariant(viewConfig, "View config not found for name %s", type); - type = viewConfig; - viewConfig = diffProperties( + hostContext = nextReactTag; + nextReactTag += 2; + type = ReactNativeViewConfigRegistry.get(type); + var updatePayload = diffProperties( null, emptyObject$1, props, @@ -5867,7 +5584,7 @@ var ReactFiberReconciler$2 = Object.freeze({ default: ReactFiberReconciler$1 }), hostContext, type.uiViewClassName, rootContainerInstance, - viewConfig, + updatePayload, internalInstanceHandle ); props = new ReactFabricHostComponent(hostContext, type, props); @@ -5879,7 +5596,8 @@ var ReactFiberReconciler$2 = Object.freeze({ default: ReactFiberReconciler$1 }), hostContext, internalInstanceHandle ) { - hostContext = ReactNativeTagHandles.allocateTag(); + hostContext = nextReactTag; + nextReactTag += 2; return { node: FabricUIManager.createNode( hostContext, @@ -5968,91 +5686,76 @@ var ReactFiberReconciler$2 = Object.freeze({ default: ReactFiberReconciler$1 }), getInspectorDataForViewTag = function() { invariant(!1, "getInspectorDataForViewTag() is not available in production"); }; -findHostInstanceFabric = ReactFabricRenderer.findHostInstance; -_batchedUpdates = ReactFabricRenderer.batchedUpdates; -_flushInteractiveUpdates = ReactFabricRenderer.flushInteractiveUpdates; +var findHostInstance = ReactFabricRenderer.findHostInstance; +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; +} var roots = new Map(), ReactFabric = { - NativeComponent: ReactNativeComponent, - findNodeHandle: findNumericNodeHandleFiber, - render: function(element, containerTag, callback) { - var root = roots.get(containerTag); - root || - ((root = ReactFabricRenderer.createContainer(containerTag, !1, !1)), - roots.set(containerTag, root)); - ReactFabricRenderer.updateContainer(element, root, null, callback); - return ReactFabricRenderer.getPublicRootInstance(root); - }, - unmountComponentAtNode: function(containerTag) { - var root = roots.get(containerTag); - root && - ReactFabricRenderer.updateContainer(null, root, null, function() { - roots["delete"](containerTag); - }); - }, - unmountComponentAtNodeAndRemoveContainer: function(containerTag) { - ReactFabric.unmountComponentAtNode(containerTag); - }, - createPortal: function(children, containerTag) { - return createPortal( - children, - containerTag, - null, - 2 < arguments.length && void 0 !== arguments[2] ? arguments[2] : null - ); - }, - unstable_batchedUpdates: function(fn, bookkeeping) { - if (isBatching) return fn(bookkeeping); - isBatching = !0; - try { - return _batchedUpdates(fn, bookkeeping); - } finally { - if ( - ((isBatching = !1), null !== restoreTarget || null !== restoreQueue) - ) - if ( - (_flushInteractiveUpdates(), - restoreTarget && - ((bookkeeping = restoreTarget), - (fn = restoreQueue), - (restoreQueue = restoreTarget = null), - restoreStateOfTarget(bookkeeping), - fn)) - ) - for (bookkeeping = 0; bookkeeping < fn.length; bookkeeping++) - restoreStateOfTarget(fn[bookkeeping]); - } - }, - flushSync: ReactFabricRenderer.flushSync, - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { - NativeMethodsMixin: { - measure: function(callback) { + 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() { + TextInputState.blurTextInput(findNodeHandle(this)); + }; + ReactNativeComponent.prototype.focus = function() { + TextInputState.focusTextInput(findNodeHandle(this)); + }; + ReactNativeComponent.prototype.measure = function(callback) { UIManager.measure( - findNumericNodeHandleFiber(this), + findNodeHandle(this), mountSafeCallback(this, callback) ); - }, - measureInWindow: function(callback) { + }; + ReactNativeComponent.prototype.measureInWindow = function(callback) { UIManager.measureInWindow( - findNumericNodeHandleFiber(this), + findNodeHandle(this), mountSafeCallback(this, callback) ); - }, - measureLayout: function(relativeToNativeNode, onSuccess, onFail) { + }; + ReactNativeComponent.prototype.measureLayout = function( + relativeToNativeNode, + onSuccess, + onFail + ) { UIManager.measureLayout( - findNumericNodeHandleFiber(this), + findNodeHandle(this), relativeToNativeNode, mountSafeCallback(this, onFail), mountSafeCallback(this, onSuccess) ); - }, - setNativeProps: function(nativeProps) { + }; + ReactNativeComponent.prototype.setNativeProps = function(nativeProps) { var maybeInstance = void 0; try { - maybeInstance = findNodeHandle(this); + maybeInstance = findHostInstance(this); } catch (error) {} if (null != maybeInstance) { - var viewConfig = maybeInstance.viewConfig; + var viewConfig = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; nativeProps = diffProperties( null, emptyObject$1, @@ -6066,33 +5769,87 @@ var roots = new Map(), nativeProps ); } - }, - focus: function() { - TextInputState.focusTextInput(findNumericNodeHandleFiber(this)); - }, - blur: function() { - TextInputState.blurTextInput(findNumericNodeHandleFiber(this)); - } - }, - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin, - ReactNativeComponentTree: ReactNativeComponentTree, - ReactNativePropRegistry: ReactNativePropRegistry, - TouchHistoryMath: TouchHistoryMath, - createReactNativeComponentClass: function(name, callback) { - invariant( - !viewConfigCallbacks.has(name), - "Tried to register two views with the same name %s", - name - ); - viewConfigCallbacks.set(name, callback); - return name; - }, - takeSnapshot: function(view, options) { - "number" !== typeof view && - "window" !== view && - (view = findNumericNodeHandleFiber(view) || "window"); - return UIManager.__takeSnapshot(view, options); - } + }; + return ReactNativeComponent; + })(React.Component); + })(findNodeHandle, findHostInstance), + findNodeHandle: findNodeHandle, + render: function(element, containerTag, callback) { + var root = roots.get(containerTag); + root || + ((root = ReactFabricRenderer.createContainer(containerTag, !1, !1)), + roots.set(containerTag, root)); + ReactFabricRenderer.updateContainer(element, root, null, callback); + return ReactFabricRenderer.getPublicRootInstance(root); + }, + unmountComponentAtNode: function(containerTag) { + var root = roots.get(containerTag); + root && + ReactFabricRenderer.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) { + UIManager.measure( + findNodeHandle(this), + mountSafeCallback(this, callback) + ); + }, + measureInWindow: function(callback) { + UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback(this, callback) + ); + }, + measureLayout: function(relativeToNativeNode, onSuccess, onFail) { + UIManager.measureLayout( + findNodeHandle(this), + relativeToNativeNode, + mountSafeCallback(this, onFail), + mountSafeCallback(this, onSuccess) + ); + }, + setNativeProps: function(nativeProps) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + if (null != maybeInstance) { + var viewConfig = maybeInstance.viewConfig; + nativeProps = diffProperties( + null, + emptyObject$1, + nativeProps, + viewConfig.validAttributes + ); + null != nativeProps && + UIManager.updateView( + maybeInstance._nativeTag, + viewConfig.uiViewClassName, + nativeProps + ); + } + }, + focus: function() { + TextInputState.focusTextInput(findNodeHandle(this)); + }, + blur: function() { + TextInputState.blurTextInput(findNodeHandle(this)); + } + }; + })(findNodeHandle, findHostInstance), + ReactNativeComponentTree: ReactNativeComponentTree } }; ReactFabricRenderer.injectIntoDevTools({ diff --git a/Libraries/Renderer/ReactNativeRenderer-dev.js b/Libraries/Renderer/ReactNativeRenderer-dev.js index 97bbfa4bef4d72..51e4aa2b0adcd6 100644 --- a/Libraries/Renderer/ReactNativeRenderer-dev.js +++ b/Libraries/Renderer/ReactNativeRenderer-dev.js @@ -19,6 +19,7 @@ require("InitializeCore"); var invariant = require("fbjs/lib/invariant"); var warning = require("fbjs/lib/warning"); var emptyFunction = require("fbjs/lib/emptyFunction"); +var ReactNativeViewConfigRegistry = require("ReactNativeViewConfigRegistry"); var UIManager = require("UIManager"); var RCTEventEmitter = require("RCTEventEmitter"); var TextInputState = require("TextInputState"); @@ -1449,7 +1450,7 @@ function getPooledWarningPropertyDefinition(propName, getVal) { return { configurable: true, set: set, - get: get + get: get$$1 }; function set(val) { @@ -1458,7 +1459,7 @@ function getPooledWarningPropertyDefinition(propName, getVal) { return val; } - function get() { + function get$$1() { var action = isFunction ? "accessing the method" : "accessing the property"; var result = isFunction ? "This is a no-op function" @@ -1775,7 +1776,7 @@ var changeResponder = function(nextResponderInst, blockHostResponder) { } }; -var eventTypes = { +var eventTypes$1 = { /** * On a `touchStart`/`mouseDown`, is it desired that this element become the * responder? @@ -2040,12 +2041,12 @@ function setResponderAndExtractTransfer( nativeEventTarget ) { var shouldSetEventType = isStartish(topLevelType) - ? eventTypes.startShouldSetResponder + ? eventTypes$1.startShouldSetResponder : isMoveish(topLevelType) - ? eventTypes.moveShouldSetResponder + ? eventTypes$1.moveShouldSetResponder : topLevelType === "topSelectionChange" - ? eventTypes.selectionChangeShouldSetResponder - : eventTypes.scrollShouldSetResponder; + ? eventTypes$1.selectionChangeShouldSetResponder + : eventTypes$1.scrollShouldSetResponder; // TODO: stop one short of the current responder. var bubbleShouldSetFrom = !responderInst @@ -2079,7 +2080,7 @@ function setResponderAndExtractTransfer( } var extracted = void 0; var grantEvent = ResponderSyntheticEvent.getPooled( - eventTypes.responderGrant, + eventTypes$1.responderGrant, wantsResponderInst, nativeEvent, nativeEventTarget @@ -2090,7 +2091,7 @@ function setResponderAndExtractTransfer( var blockHostResponder = executeDirectDispatch(grantEvent) === true; if (responderInst) { var terminationRequestEvent = ResponderSyntheticEvent.getPooled( - eventTypes.responderTerminationRequest, + eventTypes$1.responderTerminationRequest, responderInst, nativeEvent, nativeEventTarget @@ -2107,7 +2108,7 @@ function setResponderAndExtractTransfer( if (shouldSwitch) { var terminateEvent = ResponderSyntheticEvent.getPooled( - eventTypes.responderTerminate, + eventTypes$1.responderTerminate, responderInst, nativeEvent, nativeEventTarget @@ -2118,7 +2119,7 @@ function setResponderAndExtractTransfer( changeResponder(wantsResponderInst, blockHostResponder); } else { var rejectEvent = ResponderSyntheticEvent.getPooled( - eventTypes.responderReject, + eventTypes$1.responderReject, wantsResponderInst, nativeEvent, nativeEventTarget @@ -2187,7 +2188,7 @@ var ResponderEventPlugin = { return responderInst; }, - eventTypes: eventTypes, + eventTypes: eventTypes$1, /** * We must be resilient to `targetInst` being `null` on `touchMove` or @@ -2237,10 +2238,10 @@ var ResponderEventPlugin = { var isResponderTouchMove = responderInst && isMoveish(topLevelType); var isResponderTouchEnd = responderInst && isEndish(topLevelType); var incrementalTouch = isResponderTouchStart - ? eventTypes.responderStart + ? eventTypes$1.responderStart : isResponderTouchMove - ? eventTypes.responderMove - : isResponderTouchEnd ? eventTypes.responderEnd : null; + ? eventTypes$1.responderMove + : isResponderTouchEnd ? eventTypes$1.responderEnd : null; if (incrementalTouch) { var gesture = ResponderSyntheticEvent.getPooled( @@ -2262,8 +2263,8 @@ var ResponderEventPlugin = { isEndish(topLevelType) && noResponderTouches(nativeEvent); var finalTouch = isResponderTerminate - ? eventTypes.responderTerminate - : isResponderRelease ? eventTypes.responderRelease : null; + ? eventTypes$1.responderTerminate + : isResponderRelease ? eventTypes$1.responderRelease : null; if (finalTouch) { var finalEvent = ResponderSyntheticEvent.getPooled( finalTouch, @@ -2315,11 +2316,14 @@ var ResponderEventPlugin = { } }; -var customBubblingEventTypes = {}; -var customDirectEventTypes = {}; +var customBubblingEventTypes$1 = + ReactNativeViewConfigRegistry.customBubblingEventTypes; +var customDirectEventTypes$1 = + ReactNativeViewConfigRegistry.customDirectEventTypes; +var eventTypes$2 = ReactNativeViewConfigRegistry.eventTypes; var ReactNativeBridgeEventPlugin = { - eventTypes: {}, + eventTypes: eventTypes$2, /** * @see {EventPluginHub.extractEvents} @@ -2334,8 +2338,8 @@ var ReactNativeBridgeEventPlugin = { // Probably a node belonging to another renderer's tree. return null; } - var bubbleDispatchConfig = customBubblingEventTypes[topLevelType]; - var directDispatchConfig = customDirectEventTypes[topLevelType]; + var bubbleDispatchConfig = customBubblingEventTypes$1[topLevelType]; + var directDispatchConfig = customDirectEventTypes$1[topLevelType]; invariant( bubbleDispatchConfig || directDispatchConfig, 'Unsupported top level event type "%s" dispatched', @@ -2355,45 +2359,6 @@ var ReactNativeBridgeEventPlugin = { return null; } return event; - }, - - processEventTypes: function(viewConfig) { - var bubblingEventTypes = viewConfig.bubblingEventTypes, - directEventTypes = viewConfig.directEventTypes; - - { - if (bubblingEventTypes != null && directEventTypes != null) { - for (var topLevelType in directEventTypes) { - invariant( - bubblingEventTypes[topLevelType] == null, - "Event cannot be both direct and bubbling: %s", - topLevelType - ); - } - } - } - - if (bubblingEventTypes != null) { - for (var _topLevelType in bubblingEventTypes) { - if (customBubblingEventTypes[_topLevelType] == null) { - ReactNativeBridgeEventPlugin.eventTypes[ - _topLevelType - ] = customBubblingEventTypes[_topLevelType] = - bubblingEventTypes[_topLevelType]; - } - } - } - - if (directEventTypes != null) { - for (var _topLevelType2 in directEventTypes) { - if (customDirectEventTypes[_topLevelType2] == null) { - ReactNativeBridgeEventPlugin.eventTypes[ - _topLevelType2 - ] = customDirectEventTypes[_topLevelType2] = - directEventTypes[_topLevelType2]; - } - } - } } }; @@ -2588,48 +2553,6 @@ var injection$2 = { } }; -/** - * Keeps track of allocating and associating native "tags" which are numeric, - * unique view IDs. All the native tags are negative numbers, to avoid - * collisions, but in the JS we keep track of them as positive integers to store - * them effectively in Arrays. So we must refer to them as "inverses" of the - * native tags (that are * normally negative). - * - * It *must* be the case that every `rootNodeID` always maps to the exact same - * `tag` forever. The easiest way to accomplish this is to never delete - * anything from this table. - * Why: Because `dangerouslyReplaceNodeWithMarkupByID` relies on being able to - * unmount a component with a `rootNodeID`, then mount a new one in its place, - */ -var INITIAL_TAG_COUNT = 1; -var ReactNativeTagHandles = { - tagsStartAt: INITIAL_TAG_COUNT, - tagCount: INITIAL_TAG_COUNT, - - allocateTag: function() { - // Skip over root IDs as those are reserved for native - while (this.reactTagIsNativeTopRootID(ReactNativeTagHandles.tagCount)) { - ReactNativeTagHandles.tagCount++; - } - var tag = ReactNativeTagHandles.tagCount; - ReactNativeTagHandles.tagCount++; - return tag; - }, - - assertRootTag: function(tag) { - invariant( - this.reactTagIsNativeTopRootID(tag), - "Expect a native root tag, instead got %s", - tag - ); - }, - - reactTagIsNativeTopRootID: function(reactTag) { - // We reserve all tags that are 1 mod 10 for native root views - return reactTag % 10 === 1; - } -}; - /** * Version of `ReactBrowserEventEmitter` that works on the receiving side of a * serialized worker boundary. @@ -2762,7 +2685,7 @@ function receiveTouches(eventTopLevelType, touches, changedIndices) { var rootNodeID = null; var target = nativeEvent.target; if (target !== null && target !== undefined) { - if (target < ReactNativeTagHandles.tagsStartAt) { + if (target < 1) { { warning( false, @@ -2848,149 +2771,6 @@ function createPortal( }; } -var TouchHistoryMath = { - /** - * This code is optimized and not intended to look beautiful. This allows - * computing of touch centroids that have moved after `touchesChangedAfter` - * timeStamp. You can compute the current centroid involving all touches - * moves after `touchesChangedAfter`, or you can compute the previous - * centroid of all touches that were moved after `touchesChangedAfter`. - * - * @param {TouchHistoryMath} touchHistory Standard Responder touch track - * data. - * @param {number} touchesChangedAfter timeStamp after which moved touches - * are considered "actively moving" - not just "active". - * @param {boolean} isXAxis Consider `x` dimension vs. `y` dimension. - * @param {boolean} ofCurrent Compute current centroid for actively moving - * touches vs. previous centroid of now actively moving touches. - * @return {number} value of centroid in specified dimension. - */ - centroidDimension: function( - touchHistory, - touchesChangedAfter, - isXAxis, - ofCurrent - ) { - var touchBank = touchHistory.touchBank; - var total = 0; - var count = 0; - - var oneTouchData = - touchHistory.numberActiveTouches === 1 - ? touchHistory.touchBank[touchHistory.indexOfSingleActiveTouch] - : null; - - if (oneTouchData !== null) { - if ( - oneTouchData.touchActive && - oneTouchData.currentTimeStamp > touchesChangedAfter - ) { - total += - ofCurrent && isXAxis - ? oneTouchData.currentPageX - : ofCurrent && !isXAxis - ? oneTouchData.currentPageY - : !ofCurrent && isXAxis - ? oneTouchData.previousPageX - : oneTouchData.previousPageY; - count = 1; - } - } else { - for (var i = 0; i < touchBank.length; i++) { - var touchTrack = touchBank[i]; - if ( - touchTrack !== null && - touchTrack !== undefined && - touchTrack.touchActive && - touchTrack.currentTimeStamp >= touchesChangedAfter - ) { - var toAdd = void 0; // Yuck, program temporarily in invalid state. - if (ofCurrent && isXAxis) { - toAdd = touchTrack.currentPageX; - } else if (ofCurrent && !isXAxis) { - toAdd = touchTrack.currentPageY; - } else if (!ofCurrent && isXAxis) { - toAdd = touchTrack.previousPageX; - } else { - toAdd = touchTrack.previousPageY; - } - total += toAdd; - count++; - } - } - } - return count > 0 ? total / count : TouchHistoryMath.noCentroid; - }, - - currentCentroidXOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - true, // isXAxis - true - ); - }, - - currentCentroidYOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - false, // isXAxis - true - ); - }, - - previousCentroidXOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - true, // isXAxis - false - ); - }, - - previousCentroidYOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - false, // isXAxis - false - ); - }, - - currentCentroidX: function(touchHistory) { - return TouchHistoryMath.centroidDimension( - touchHistory, - 0, // touchesChangedAfter - true, // isXAxis - true - ); - }, - - currentCentroidY: function(touchHistory) { - return TouchHistoryMath.centroidDimension( - touchHistory, - 0, // touchesChangedAfter - false, // isXAxis - true - ); - }, - - noCentroid: -1 -}; - // TODO: this is special because it gets imported during build. var ReactVersion = "16.3.1"; @@ -3064,48 +2844,6 @@ function getStackAddendumByWorkInProgressFiber(workInProgress) { return info; } -function _classCallCheck(instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); - } -} - -var objects = {}; -var uniqueID = 1; -var emptyObject$2 = {}; - -var ReactNativePropRegistry = (function() { - function ReactNativePropRegistry() { - _classCallCheck(this, ReactNativePropRegistry); - } - - ReactNativePropRegistry.register = function register(object) { - var id = ++uniqueID; - { - Object.freeze(object); - } - objects[id] = object; - return id; - }; - - ReactNativePropRegistry.getByID = function getByID(id) { - if (!id) { - // Used in the style={[condition && id]} pattern, - // we want it to be a no-op when the value is false or null - return emptyObject$2; - } - - var object = objects[id]; - if (!object) { - console.warn("Invalid style with id `" + id + "`. Skipping ..."); - return emptyObject$2; - } - return object; - }; - - return ReactNativePropRegistry; -})(); - // Modules provided by RN: var emptyObject$1 = {}; @@ -3132,13 +2870,6 @@ function defaultDiffer(prevProp, nextProp) { } } -function resolveObject(idOrObject) { - if (typeof idOrObject === "number") { - return ReactNativePropRegistry.getByID(idOrObject); - } - return idOrObject; -} - function restoreDeletedValuesInNestedArray( updatePayload, node, @@ -3154,7 +2885,7 @@ function restoreDeletedValuesInNestedArray( ); } } else if (node && removedKeyCount > 0) { - var obj = resolveObject(node); + var obj = node; for (var propKey in removedKeys) { if (!removedKeys[propKey]) { continue; @@ -3258,12 +2989,7 @@ function diffNestedProperty( if (!Array.isArray(prevProp) && !Array.isArray(nextProp)) { // Both are leaves, we can diff the leaves. - return diffProperties( - updatePayload, - resolveObject(prevProp), - resolveObject(nextProp), - validAttributes - ); + return diffProperties(updatePayload, prevProp, nextProp, validAttributes); } if (Array.isArray(prevProp) && Array.isArray(nextProp)) { @@ -3282,14 +3008,14 @@ function diffNestedProperty( // $FlowFixMe - We know that this is always an object when the input is. flattenStyle(prevProp), // $FlowFixMe - We know that this isn't an array because of above flow. - resolveObject(nextProp), + nextProp, validAttributes ); } return diffProperties( updatePayload, - resolveObject(prevProp), + prevProp, // $FlowFixMe - We know that this is always an object when the input is. flattenStyle(nextProp), validAttributes @@ -3308,11 +3034,7 @@ function addNestedProperty(updatePayload, nextProp, validAttributes) { if (!Array.isArray(nextProp)) { // Add each property of the leaf. - return addProperties( - updatePayload, - resolveObject(nextProp), - validAttributes - ); + return addProperties(updatePayload, nextProp, validAttributes); } for (var i = 0; i < nextProp.length; i++) { @@ -3338,11 +3060,7 @@ function clearNestedProperty(updatePayload, prevProp, validAttributes) { if (!Array.isArray(prevProp)) { // Add each property of the leaf. - return clearProperties( - updatePayload, - resolveObject(prevProp), - validAttributes - ); + return clearProperties(updatePayload, prevProp, validAttributes); } for (var i = 0; i < prevProp.length; i++) { @@ -3629,339 +3347,195 @@ function warnForStyleProps(props, validAttributes) { } } -/** - * `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 ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; - -var ReactCurrentOwner = ReactInternals.ReactCurrentOwner; -var ReactDebugCurrentFrame = ReactInternals.ReactDebugCurrentFrame; - -// TODO: Share this module between Fabric and React Native renderers -// so that both can be used in the same tree. - -var findHostInstance = function(fiber) { - return null; -}; - -var findHostInstanceFabric = function(fiber) { - return null; -}; - -function injectFindHostInstance(impl) { - findHostInstance = impl; -} - -/** - * ReactNative vs ReactWeb - * ----------------------- - * React treats some pieces of data opaquely. This means that the information - * is first class (it can be passed around), but cannot be inspected. This - * allows us to build infrastructure that reasons about resources, without - * making assumptions about the nature of those resources, and this allows that - * infra to be shared across multiple platforms, where the resources are very - * different. General infra (such as `ReactMultiChild`) reasons opaquely about - * the data, but platform specific code (such as `ReactNativeBaseComponent`) can - * make assumptions about the data. - * - * - * `rootNodeID`, uniquely identifies a position in the generated native view - * tree. Many layers of composite components (created with `React.createClass`) - * can all share the same `rootNodeID`. - * - * `nodeHandle`: A sufficiently unambiguous way to refer to a lower level - * resource (dom node, native view etc). The `rootNodeID` is sufficient for web - * `nodeHandle`s, because the position in a tree is always enough to uniquely - * identify a DOM node (we never have nodes in some bank outside of the - * document). The same would be true for `ReactNative`, but we must maintain a - * mapping that we can send efficiently serializable - * strings across native boundaries. - * - * Opaque name TodaysWebReact FutureWebWorkerReact ReactNative - * ---------------------------------------------------------------------------- - * nodeHandle N/A rootNodeID tag - */ - -// TODO (bvaughn) Rename the findNodeHandle module to something more descriptive -// eg findInternalHostInstance. This will reduce the likelihood of someone -// accidentally deep-requiring this version. -function findNodeHandle(componentOrHandle) { - { - var owner = ReactCurrentOwner.current; - if (owner !== null && owner.stateNode !== null) { - !owner.stateNode._warnedAboutRefsInRender - ? warning( - 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) || "A component" - ) - : void 0; - - owner.stateNode._warnedAboutRefsInRender = true; - } - } - if (componentOrHandle == null) { - return null; - } - if (typeof componentOrHandle === "number") { - // Already a node handle - return componentOrHandle; - } - - var component = componentOrHandle; - - // TODO (balpert): Wrap iOS native components in a composite wrapper, then - // ReactInstanceMap.get here will always succeed for mounted components - var internalInstance = get(component); - if (internalInstance) { - return ( - findHostInstance(internalInstance) || - findHostInstanceFabric(internalInstance) - ); - } else { - if (component) { - return component; - } else { - invariant( - // Native - (typeof component === "object" && "_nativeTag" in component) || - // Composite - (component.render != null && typeof component.render === "function"), - "findNodeHandle(...): Argument is not a component " + - "(type: %s, keys: %s)", - typeof component, - Object.keys(component) - ); - invariant( - false, - "findNodeHandle(...): Unable to find node handle for unmounted " + - "component." - ); - } - } -} - -/** - * External users of findNodeHandle() expect the host tag number return type. - * The injected findNodeHandle() strategy returns the instance wrapper though. - * See NativeMethodsMixin#setNativeProps for more info on why this is done. - */ -function findNumericNodeHandleFiber(componentOrHandle) { - var instance = findNodeHandle(componentOrHandle); - if (instance == null || typeof instance === "number") { - return instance; - } - return instance._nativeTag; -} - // Modules provided by RN: -/** - * `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 = { +var NativeMethodsMixin = function(findNodeHandle, findHostInstance) { /** - * 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: + * `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. * - * - x - * - y - * - width - * - height - * - pageX - * - pageY + * 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 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. + * Note the Flow $Exact<> syntax is required to support mixins. + * React createClass mixins can only be used with exact types. */ - measure: function(callback) { - UIManager.measure( - findNumericNodeHandleFiber(this), - mountSafeCallback(this, callback) - ); - }, + 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) { + UIManager.measure( + findNodeHandle(this), + mountSafeCallback(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) { - UIManager.measureInWindow( - findNumericNodeHandleFiber(this), - mountSafeCallback(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) { + UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback(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 - * `findNumericNodeHandle(component)`. - */ - measureLayout: function( - relativeToNativeNode, - onSuccess, - onFail /* currently unused */ - ) { - UIManager.measureLayout( - findNumericNodeHandleFiber(this), + /** + * 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, - mountSafeCallback(this, onFail), - mountSafeCallback(this, onSuccess) - ); - }, + onSuccess, + onFail /* currently unused */ + ) { + UIManager.measureLayout( + findNodeHandle(this), + relativeToNativeNode, + mountSafeCallback(this, onFail), + mountSafeCallback(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 findNumericNodeHandle() 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 = findNodeHandle(this); - } catch (error) {} + /** + * 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 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; + } - var viewConfig = maybeInstance.viewConfig; + var viewConfig = maybeInstance.viewConfig; - { - warnForStyleProps(nativeProps, viewConfig.validAttributes); - } + { + warnForStyleProps(nativeProps, viewConfig.validAttributes); + } - var updatePayload = create(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) { - UIManager.updateView( - maybeInstance._nativeTag, - viewConfig.uiViewClassName, - updatePayload - ); + // 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) { + UIManager.updateView( + maybeInstance._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() { + TextInputState.focusTextInput(findNodeHandle(this)); + }, + + /** + * Removes focus from an input or view. This is the opposite of `focus()`. + */ + blur: function() { + TextInputState.blurTextInput(findNodeHandle(this)); } - }, + }; - /** - * Requests focus for the given input or view. The exact behavior triggered - * will depend on the platform and type of view. - */ - focus: function() { - TextInputState.focusTextInput(findNumericNodeHandleFiber(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; + invariant( + !NativeMethodsMixin_DEV.componentWillMount && + !NativeMethodsMixin_DEV.componentWillReceiveProps && + !NativeMethodsMixin_DEV.UNSAFE_componentWillMount && + !NativeMethodsMixin_DEV.UNSAFE_componentWillReceiveProps, + "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); + }; - /** - * Removes focus from an input or view. This is the opposite of `focus()`. - */ - blur: function() { - TextInputState.blurTextInput(findNumericNodeHandleFiber(this)); + // 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; } -}; - -{ - // 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; - invariant( - !NativeMethodsMixin_DEV.componentWillMount && - !NativeMethodsMixin_DEV.componentWillReceiveProps && - !NativeMethodsMixin_DEV.UNSAFE_componentWillMount && - !NativeMethodsMixin_DEV.UNSAFE_componentWillReceiveProps, - "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) { +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } @@ -4000,166 +3574,200 @@ function _inherits(subClass, superClass) { } // Modules provided by RN: -/** - * 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); +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); + function ReactNativeComponent() { + _classCallCheck(this, ReactNativeComponent); - return _possibleConstructorReturn( - this, - _React$Component.apply(this, arguments) - ); - } + return _possibleConstructorReturn( + this, + _React$Component.apply(this, arguments) + ); + } - /** - * Removes focus. This is the opposite of `focus()`. - */ + /** + * 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() { - TextInputState.blurTextInput(findNumericNodeHandleFiber(this)); - }; + /** + * 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() { + TextInputState.blurTextInput(findNodeHandle(this)); + }; - /** - * Requests focus. The exact behavior depends on the platform and view. - */ + /** + * Requests focus. The exact behavior depends on the platform and view. + */ - ReactNativeComponent.prototype.focus = function focus() { - TextInputState.focusTextInput(findNumericNodeHandleFiber(this)); - }; + ReactNativeComponent.prototype.focus = function focus() { + 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. - */ + /** + * 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) { - UIManager.measure( - findNumericNodeHandleFiber(this), - mountSafeCallback(this, callback) - ); - }; + ReactNativeComponent.prototype.measure = function measure(callback) { + UIManager.measure( + findNodeHandle(this), + mountSafeCallback(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. - */ + /** + * 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 - ) { - UIManager.measureInWindow( - findNumericNodeHandleFiber(this), - mountSafeCallback(this, callback) - ); - }; + ReactNativeComponent.prototype.measureInWindow = function measureInWindow( + callback + ) { + UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback(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)`. - */ + /** + * 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 */ - ) { - UIManager.measureLayout( - findNumericNodeHandleFiber(this), + ReactNativeComponent.prototype.measureLayout = function measureLayout( relativeToNativeNode, - mountSafeCallback(this, onFail), - mountSafeCallback(this, onSuccess) - ); - }; + onSuccess, + onFail /* currently unused */ + ) { + UIManager.measureLayout( + findNodeHandle(this), + relativeToNativeNode, + mountSafeCallback(this, onFail), + mountSafeCallback(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)). - */ + /** + * 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 = findNodeHandle(this); - } catch (error) {} + 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 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; + } - var viewConfig = - maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + var viewConfig = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; - var updatePayload = create(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) { - UIManager.updateView( - maybeInstance._nativeTag, - viewConfig.uiViewClassName, - updatePayload - ); - } - }; + // 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) { + UIManager.updateView( + maybeInstance._nativeTag, + viewConfig.uiViewClassName, + updatePayload + ); + } + }; + + return ReactNativeComponent; + })(React.Component); + + // eslint-disable-next-line no-unused-expressions return ReactNativeComponent; -})(React.Component); +}; + +/** + * `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$1(key) { + return key._reactInternalFiber; +} + +function set(key, value) { + key._reactInternalFiber = value; +} + +var ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; + +var ReactCurrentOwner = ReactInternals.ReactCurrentOwner; +var ReactDebugCurrentFrame = ReactInternals.ReactDebugCurrentFrame; // Don't change these two values. They're used by React Dev Tools. var NoEffect = /* */ 0; @@ -4241,7 +3849,7 @@ function isMounted(component) { } } - var fiber = get(component); + var fiber = get$1(component); if (!fiber) { return false; } @@ -6205,7 +5813,7 @@ var ReactFiberClassComponent = function( var updater = { isMounted: isMounted, enqueueSetState: function(instance, partialState, callback) { - var fiber = get(instance); + var fiber = get$1(instance); callback = callback === undefined ? null : callback; { warnOnInvalidCallback(callback, "setState"); @@ -6224,7 +5832,7 @@ var ReactFiberClassComponent = function( scheduleWork(fiber, expirationTime); }, enqueueReplaceState: function(instance, state, callback) { - var fiber = get(instance); + var fiber = get$1(instance); callback = callback === undefined ? null : callback; { warnOnInvalidCallback(callback, "replaceState"); @@ -6243,7 +5851,7 @@ var ReactFiberClassComponent = function( scheduleWork(fiber, expirationTime); }, enqueueForceUpdate: function(instance, callback) { - var fiber = get(instance); + var fiber = get$1(instance); callback = callback === undefined ? null : callback; { warnOnInvalidCallback(callback, "forceUpdate"); @@ -9676,7 +9284,7 @@ var ReactFiberCompleteWork = function( function markUpdate(workInProgress) { // Tag the fiber with an update effect. This turns a Placement into - // an UpdateAndPlacement. + // a PlacementAndUpdate. workInProgress.effectTag |= Update; } @@ -13876,7 +13484,7 @@ var ReactFiberReconciler$1 = function(config) { return emptyObject; } - var fiber = get(parentComponent); + var fiber = get$1(parentComponent); var parentContext = findCurrentUnmaskedContext(fiber); return isContextProvider(fiber) ? processChildContext(fiber, parentContext) @@ -13974,7 +13582,19 @@ var ReactFiberReconciler$1 = function(config) { ); } - function findHostInstance(fiber) { + function findHostInstance(component) { + var fiber = get$1(component); + if (fiber === undefined) { + if (typeof component.render === "function") { + invariant(false, "Unable to find node on an unmounted component."); + } else { + invariant( + false, + "Argument appears to not be a ReactComponent. Keys: %s", + Object.keys(component) + ); + } + } var hostFiber = findCurrentHostFiber(fiber); if (hostFiber === null) { return null; @@ -14067,7 +13687,11 @@ var ReactFiberReconciler$1 = function(config) { return injectInternals( Object.assign({}, devToolsConfig, { findHostInstanceByFiber: function(fiber) { - return findHostInstance(fiber); + var hostFiber = findCurrentHostFiber(fiber); + if (hostFiber === null) { + return null; + } + return hostFiber.stateNode; }, findFiberByHostInstance: function(instance) { if (!findFiberByHostInstance) { @@ -14097,50 +13721,7 @@ var reactReconciler = ReactFiberReconciler$3["default"] ? ReactFiberReconciler$3["default"] : ReactFiberReconciler$3; -var viewConfigCallbacks = new Map(); -var viewConfigs = new Map(); - -/** - * 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. - */ -function register(name, callback) { - invariant( - !viewConfigCallbacks.has(name), - "Tried to register two views with the same name %s", - name - ); - viewConfigCallbacks.set(name, callback); - return name; -} - -/** - * Retrieves a config for the specified view. - * If this is the first time the view has been used, - * This configuration will be lazy-loaded from UIManager. - */ -function get$1(name) { - var viewConfig = void 0; - if (!viewConfigs.has(name)) { - var callback = viewConfigCallbacks.get(name); - invariant( - typeof callback === "function", - "View config not found for name %s", - name - ); - viewConfigCallbacks.set(name, null); - viewConfig = callback(); - viewConfigs.set(name, viewConfig); - } else { - viewConfig = viewConfigs.get(name); - } - invariant(viewConfig, "View config not found for name %s", name); - return viewConfig; -} - -function _classCallCheck$2(instance, Constructor) { +function _classCallCheck$1(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } @@ -14157,7 +13738,7 @@ function _classCallCheck$2(instance, Constructor) { var ReactNativeFiberHostComponent = (function() { function ReactNativeFiberHostComponent(tag, viewConfig) { - _classCallCheck$2(this, ReactNativeFiberHostComponent); + _classCallCheck$1(this, ReactNativeFiberHostComponent); this._nativeTag = tag; this._children = []; @@ -14272,6 +13853,19 @@ function cancelDeferredCallback(callbackID) { } // Modules provided by RN: +// 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) @@ -14294,8 +13888,8 @@ var NativeRenderer = reactReconciler({ hostContext, internalInstanceHandle ) { - var tag = ReactNativeTagHandles.allocateTag(); - var viewConfig = get$1(type); + var tag = allocateTag(); + var viewConfig = ReactNativeViewConfigRegistry.get(type); { for (var key in viewConfig.validAttributes) { @@ -14329,7 +13923,7 @@ var NativeRenderer = reactReconciler({ hostContext, internalInstanceHandle ) { - var tag = ReactNativeTagHandles.allocateTag(); + var tag = allocateTag(); UIManager.createView( tag, // reactTag @@ -14665,48 +14259,51 @@ var getInspectorDataForViewTag = void 0; }; } -/** - * Creates a renderable ReactNative host component. - * Use this method for view configs that are loaded from UIManager. - * Use createReactNativeComponentClass() for view configs defined within JavaScript. - * - * @param {string} config iOS View configuration. - * @private - */ -var createReactNativeComponentClass = function(name, callback) { - return register(name, callback); -}; - // Module provided by RN: -/** - * Capture an image of the screen, window or an individual view. The image - * will be stored in a temporary file that will only exist for as long as the - * app is running. - * - * The `view` argument can be the literal string `window` if you want to - * capture the entire window, or it can be a reference to a specific - * React Native component. - * - * The `options` argument may include: - * - width/height (number) - the width and height of the image to capture. - * - format (string) - either 'png' or 'jpeg'. Defaults to 'png'. - * - quality (number) - the quality when using jpeg. 0.0 - 1.0 (default). - * - * Returns a Promise. - * @platform ios - */ -function takeSnapshot(view, options) { - if (typeof view !== "number" && view !== "window") { - view = findNumericNodeHandleFiber(view) || "window"; - } +var findHostInstance = NativeRenderer.findHostInstance; - // Call the hidden '__takeSnapshot' method; the main one throws an error to - // prevent accidental backwards-incompatible usage. - return UIManager.__takeSnapshot(view, options); -} +function findNodeHandle(componentOrHandle) { + { + var owner = ReactCurrentOwner.current; + if (owner !== null && owner.stateNode !== null) { + !owner.stateNode._warnedAboutRefsInRender + ? warning( + 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) || "A component" + ) + : void 0; -// Module provided by RN: -injectFindHostInstance(NativeRenderer.findHostInstance); + 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 = findHostInstance(componentOrHandle); + if (hostInstance == null) { + return hostInstance; + } + if (hostInstance.canonical) { + // Fabric + return hostInstance.canonical._nativeTag; + } + return hostInstance._nativeTag; +} injection$2.injectRenderer(NativeRenderer); @@ -14721,9 +14318,9 @@ function computeComponentStackForErrorReporting(reactTag) { var roots = new Map(); var ReactNativeRenderer = { - NativeComponent: ReactNativeComponent, + NativeComponent: ReactNativeComponent(findNodeHandle, findHostInstance), - findNodeHandle: findNumericNodeHandleFiber, + findNodeHandle: findNodeHandle, render: function(element, containerTag, callback) { var root = roots.get(containerTag); @@ -14762,18 +14359,11 @@ var ReactNativeRenderer = { unstable_batchedUpdates: batchedUpdates, - flushSync: NativeRenderer.flushSync, - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { // Used as a mixin in many createClass-based components - NativeMethodsMixin: NativeMethodsMixin, + NativeMethodsMixin: NativeMethodsMixin(findNodeHandle, findHostInstance), // Used by react-native-github/Libraries/ components - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin, // requireNativeComponent ReactNativeComponentTree: ReactNativeComponentTree, // ScrollResponder - ReactNativePropRegistry: ReactNativePropRegistry, // flattenStyle, Stylesheet - TouchHistoryMath: TouchHistoryMath, // PanResponder - createReactNativeComponentClass: createReactNativeComponentClass, // RCTText, RCTView, ReactNativeART - takeSnapshot: takeSnapshot, // react-native-implementation computeComponentStackForErrorReporting: computeComponentStackForErrorReporting } }; diff --git a/Libraries/Renderer/ReactNativeRenderer-prod.js b/Libraries/Renderer/ReactNativeRenderer-prod.js index bf2480f1c03d6f..10e7f6b5fc964f 100644 --- a/Libraries/Renderer/ReactNativeRenderer-prod.js +++ b/Libraries/Renderer/ReactNativeRenderer-prod.js @@ -13,6 +13,7 @@ require("InitializeCore"); var invariant = require("fbjs/lib/invariant"), emptyFunction = require("fbjs/lib/emptyFunction"), + ReactNativeViewConfigRegistry = require("ReactNativeViewConfigRegistry"), UIManager = require("UIManager"), RCTEventEmitter = require("RCTEventEmitter"), TextInputState = require("TextInputState"), @@ -624,7 +625,7 @@ function changeResponder(nextResponderInst, blockHostResponder) { blockHostResponder ); } -var eventTypes = { +var eventTypes$1 = { startShouldSetResponder: { phasedRegistrationNames: { bubbled: "onStartShouldSetResponder", @@ -664,7 +665,7 @@ var eventTypes = { _getResponder: function() { return responderInst; }, - eventTypes: eventTypes, + eventTypes: eventTypes$1, extractEvents: function( topLevelType, targetInst, @@ -690,12 +691,12 @@ var eventTypes = { isMoveish(topLevelType)) ) { var JSCompiler_temp = isStartish(topLevelType) - ? eventTypes.startShouldSetResponder + ? eventTypes$1.startShouldSetResponder : isMoveish(topLevelType) - ? eventTypes.moveShouldSetResponder + ? eventTypes$1.moveShouldSetResponder : "topSelectionChange" === topLevelType - ? eventTypes.selectionChangeShouldSetResponder - : eventTypes.scrollShouldSetResponder; + ? eventTypes$1.selectionChangeShouldSetResponder + : eventTypes$1.scrollShouldSetResponder; if (responderInst) b: { var JSCompiler_temp$jscomp$0 = responderInst; @@ -781,7 +782,7 @@ var eventTypes = { JSCompiler_temp && JSCompiler_temp !== responderInst ? ((JSCompiler_temp$jscomp$0 = void 0), (targetInst = ResponderSyntheticEvent.getPooled( - eventTypes.responderGrant, + eventTypes$1.responderGrant, JSCompiler_temp, nativeEvent, nativeEventTarget @@ -791,7 +792,7 @@ var eventTypes = { (depthA = !0 === executeDirectDispatch(targetInst)), responderInst ? ((tempA = ResponderSyntheticEvent.getPooled( - eventTypes.responderTerminationRequest, + eventTypes$1.responderTerminationRequest, responderInst, nativeEvent, nativeEventTarget @@ -803,7 +804,7 @@ var eventTypes = { tempA.isPersistent() || tempA.constructor.release(tempA), tempB ? ((tempA = ResponderSyntheticEvent.getPooled( - eventTypes.responderTerminate, + eventTypes$1.responderTerminate, responderInst, nativeEvent, nativeEventTarget @@ -817,7 +818,7 @@ var eventTypes = { )), changeResponder(JSCompiler_temp, depthA)) : ((JSCompiler_temp = ResponderSyntheticEvent.getPooled( - eventTypes.responderReject, + eventTypes$1.responderReject, JSCompiler_temp, nativeEvent, nativeEventTarget @@ -845,10 +846,10 @@ var eventTypes = { depthA = responderInst && isEndish(topLevelType); if ( (JSCompiler_temp$jscomp$0 = JSCompiler_temp$jscomp$0 - ? eventTypes.responderStart + ? eventTypes$1.responderStart : targetInst - ? eventTypes.responderMove - : depthA ? eventTypes.responderEnd : null) + ? eventTypes$1.responderMove + : depthA ? eventTypes$1.responderEnd : null) ) (JSCompiler_temp$jscomp$0 = ResponderSyntheticEvent.getPooled( JSCompiler_temp$jscomp$0, @@ -899,8 +900,8 @@ var eventTypes = { } if ( (topLevelType = JSCompiler_temp$jscomp$0 - ? eventTypes.responderTerminate - : topLevelType ? eventTypes.responderRelease : null) + ? eventTypes$1.responderTerminate + : topLevelType ? eventTypes$1.responderRelease : null) ) (nativeEvent = ResponderSyntheticEvent.getPooled( topLevelType, @@ -932,10 +933,12 @@ var eventTypes = { } } }, - customBubblingEventTypes = {}, - customDirectEventTypes = {}, + customBubblingEventTypes$1 = + ReactNativeViewConfigRegistry.customBubblingEventTypes, + customDirectEventTypes$1 = + ReactNativeViewConfigRegistry.customDirectEventTypes, ReactNativeBridgeEventPlugin = { - eventTypes: {}, + eventTypes: ReactNativeViewConfigRegistry.eventTypes, extractEvents: function( topLevelType, targetInst, @@ -943,8 +946,8 @@ var eventTypes = { nativeEventTarget ) { if (null == targetInst) return null; - var bubbleDispatchConfig = customBubblingEventTypes[topLevelType], - directDispatchConfig = customDirectEventTypes[topLevelType]; + var bubbleDispatchConfig = customBubblingEventTypes$1[topLevelType], + directDispatchConfig = customDirectEventTypes$1[topLevelType]; invariant( bubbleDispatchConfig || directDispatchConfig, 'Unsupported top level event type "%s" dispatched', @@ -962,24 +965,6 @@ var eventTypes = { forEachAccumulated(topLevelType, accumulateDirectDispatchesSingle); else return null; return topLevelType; - }, - processEventTypes: function(viewConfig) { - var bubblingEventTypes = viewConfig.bubblingEventTypes; - viewConfig = viewConfig.directEventTypes; - if (null != bubblingEventTypes) - for (var _topLevelType in bubblingEventTypes) - null == customBubblingEventTypes[_topLevelType] && - (ReactNativeBridgeEventPlugin.eventTypes[ - _topLevelType - ] = customBubblingEventTypes[_topLevelType] = - bubblingEventTypes[_topLevelType]); - if (null != viewConfig) - for (var _topLevelType2 in viewConfig) - null == customDirectEventTypes[_topLevelType2] && - (ReactNativeBridgeEventPlugin.eventTypes[ - _topLevelType2 - ] = customDirectEventTypes[_topLevelType2] = - viewConfig[_topLevelType2]); } }, instanceCache = {}, @@ -1067,28 +1052,7 @@ function batchedUpdates(fn, bookkeeping) { restoreStateOfTarget(fn[bookkeeping]); } } -var ReactNativeTagHandles = { - tagsStartAt: 1, - tagCount: 1, - allocateTag: function() { - for (; this.reactTagIsNativeTopRootID(ReactNativeTagHandles.tagCount); ) - ReactNativeTagHandles.tagCount++; - var tag = ReactNativeTagHandles.tagCount; - ReactNativeTagHandles.tagCount++; - return tag; - }, - assertRootTag: function(tag) { - invariant( - this.reactTagIsNativeTopRootID(tag), - "Expect a native root tag, instead got %s", - tag - ); - }, - reactTagIsNativeTopRootID: function(reactTag) { - return 1 === reactTag % 10; - } - }, - EMPTY_NATIVE_EVENT = {}; +var EMPTY_NATIVE_EVENT = {}; function _receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam) { var nativeEvent = nativeEventParam || EMPTY_NATIVE_EVENT, inst = getInstanceFromTag(rootNodeID); @@ -1153,10 +1117,7 @@ var ReactNativeEventEmitter = Object.freeze({ i.touches = touches; index = null; var target = i.target; - null === target || - void 0 === target || - target < ReactNativeTagHandles.tagsStartAt || - (index = target); + null === target || void 0 === target || 1 > target || (index = target); _receiveRootNodeIDEvent(index, eventTopLevelType, i); } } @@ -1197,103 +1158,6 @@ function createPortal(children, containerInfo, implementation) { implementation: implementation }; } -var TouchHistoryMath = { - centroidDimension: function( - touchHistory, - touchesChangedAfter, - isXAxis, - ofCurrent - ) { - var touchBank = touchHistory.touchBank, - total = 0, - count = 0; - touchHistory = - 1 === touchHistory.numberActiveTouches - ? touchHistory.touchBank[touchHistory.indexOfSingleActiveTouch] - : null; - if (null !== touchHistory) - touchHistory.touchActive && - touchHistory.currentTimeStamp > touchesChangedAfter && - ((total += - ofCurrent && isXAxis - ? touchHistory.currentPageX - : ofCurrent && !isXAxis - ? touchHistory.currentPageY - : !ofCurrent && isXAxis - ? touchHistory.previousPageX - : touchHistory.previousPageY), - (count = 1)); - else - for (touchHistory = 0; touchHistory < touchBank.length; touchHistory++) { - var touchTrack = touchBank[touchHistory]; - null !== touchTrack && - void 0 !== touchTrack && - touchTrack.touchActive && - touchTrack.currentTimeStamp >= touchesChangedAfter && - ((total += - ofCurrent && isXAxis - ? touchTrack.currentPageX - : ofCurrent && !isXAxis - ? touchTrack.currentPageY - : !ofCurrent && isXAxis - ? touchTrack.previousPageX - : touchTrack.previousPageY), - count++); - } - return 0 < count ? total / count : TouchHistoryMath.noCentroid; - }, - currentCentroidXOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - !0, - !0 - ); - }, - currentCentroidYOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - !1, - !0 - ); - }, - previousCentroidXOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - !0, - !1 - ); - }, - previousCentroidYOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - !1, - !1 - ); - }, - currentCentroidX: function(touchHistory) { - return TouchHistoryMath.centroidDimension(touchHistory, 0, !0, !0); - }, - currentCentroidY: function(touchHistory) { - return TouchHistoryMath.centroidDimension(touchHistory, 0, !1, !0); - }, - noCentroid: -1 -}; function getComponentName(fiber) { fiber = fiber.type; if ("function" === typeof fiber) return fiber.displayName || fiber.name; @@ -1343,37 +1207,9 @@ function getStackAddendumByWorkInProgressFiber(workInProgress) { } while (workInProgress); return info; } -var objects = {}, - uniqueID = 1, - emptyObject$2 = {}, - ReactNativePropRegistry = (function() { - function ReactNativePropRegistry() { - if (!(this instanceof ReactNativePropRegistry)) - throw new TypeError("Cannot call a class as a function"); - } - ReactNativePropRegistry.register = function(object) { - var id = ++uniqueID; - objects[id] = object; - return id; - }; - ReactNativePropRegistry.getByID = function(id) { - if (!id) return emptyObject$2; - var object = objects[id]; - return object - ? object - : (console.warn("Invalid style with id `" + id + "`. Skipping ..."), - emptyObject$2); - }; - return ReactNativePropRegistry; - })(), - emptyObject$1 = {}, +var emptyObject$1 = {}, removedKeys = null, removedKeyCount = 0; -function resolveObject(idOrObject) { - return "number" === typeof idOrObject - ? ReactNativePropRegistry.getByID(idOrObject) - : idOrObject; -} function restoreDeletedValuesInNestedArray( updatePayload, node, @@ -1387,7 +1223,7 @@ function restoreDeletedValuesInNestedArray( validAttributes ); else if (node && 0 < removedKeyCount) - for (i in ((node = resolveObject(node)), removedKeys)) + for (i in removedKeys) if (removedKeys[i]) { var _nextProp = node[i]; if (void 0 !== _nextProp) { @@ -1426,12 +1262,7 @@ function diffNestedProperty( ? clearNestedProperty(updatePayload, prevProp, validAttributes) : updatePayload; if (!Array.isArray(prevProp) && !Array.isArray(nextProp)) - return diffProperties( - updatePayload, - resolveObject(prevProp), - resolveObject(nextProp), - validAttributes - ); + return diffProperties(updatePayload, prevProp, nextProp, validAttributes); if (Array.isArray(prevProp) && Array.isArray(nextProp)) { var minLength = prevProp.length < nextProp.length ? prevProp.length : nextProp.length, @@ -1461,12 +1292,12 @@ function diffNestedProperty( ? diffProperties( updatePayload, flattenStyle(prevProp), - resolveObject(nextProp), + nextProp, validAttributes ) : diffProperties( updatePayload, - resolveObject(prevProp), + prevProp, flattenStyle(nextProp), validAttributes ); @@ -1474,9 +1305,11 @@ function diffNestedProperty( function addNestedProperty(updatePayload, nextProp, validAttributes) { if (!nextProp) return updatePayload; if (!Array.isArray(nextProp)) - return ( - (nextProp = resolveObject(nextProp)), - diffProperties(updatePayload, emptyObject$1, nextProp, validAttributes) + return diffProperties( + updatePayload, + emptyObject$1, + nextProp, + validAttributes ); for (var i = 0; i < nextProp.length; i++) updatePayload = addNestedProperty( @@ -1489,9 +1322,11 @@ function addNestedProperty(updatePayload, nextProp, validAttributes) { function clearNestedProperty(updatePayload, prevProp, validAttributes) { if (!prevProp) return updatePayload; if (!Array.isArray(prevProp)) - return ( - (prevProp = resolveObject(prevProp)), - diffProperties(updatePayload, prevProp, emptyObject$1, validAttributes) + return diffProperties( + updatePayload, + prevProp, + emptyObject$1, + validAttributes ); for (var i = 0; i < prevProp.length; i++) updatePayload = clearNestedProperty( @@ -1604,37 +1439,6 @@ function mountSafeCallback(context, callback) { } }; } -var ReactCurrentOwner = - React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner; -function findHostInstance() { - return null; -} -function findNodeHandle(componentOrHandle) { - if (null == componentOrHandle) return null; - if ("number" === typeof componentOrHandle) return componentOrHandle; - var internalInstance = componentOrHandle._reactInternalFiber; - if (internalInstance) return findHostInstance(internalInstance) || null; - if (componentOrHandle) return componentOrHandle; - invariant( - ("object" === typeof componentOrHandle && - "_nativeTag" in componentOrHandle) || - (null != componentOrHandle.render && - "function" === typeof componentOrHandle.render), - "findNodeHandle(...): Argument is not a component (type: %s, keys: %s)", - typeof componentOrHandle, - Object.keys(componentOrHandle) - ); - invariant( - !1, - "findNodeHandle(...): Unable to find node handle for unmounted component." - ); -} -function findNumericNodeHandleFiber(componentOrHandle) { - componentOrHandle = findNodeHandle(componentOrHandle); - return null == componentOrHandle || "number" === typeof componentOrHandle - ? componentOrHandle - : componentOrHandle._nativeTag; -} function _inherits(subClass, superClass) { if ("function" !== typeof superClass && null !== superClass) throw new TypeError( @@ -1654,74 +1458,8 @@ function _inherits(subClass, superClass) { ? Object.setPrototypeOf(subClass, superClass) : (subClass.__proto__ = superClass)); } -var ReactNativeComponent = (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() { - TextInputState.blurTextInput(findNumericNodeHandleFiber(this)); - }; - ReactNativeComponent.prototype.focus = function() { - TextInputState.focusTextInput(findNumericNodeHandleFiber(this)); - }; - ReactNativeComponent.prototype.measure = function(callback) { - UIManager.measure( - findNumericNodeHandleFiber(this), - mountSafeCallback(this, callback) - ); - }; - ReactNativeComponent.prototype.measureInWindow = function(callback) { - UIManager.measureInWindow( - findNumericNodeHandleFiber(this), - mountSafeCallback(this, callback) - ); - }; - ReactNativeComponent.prototype.measureLayout = function( - relativeToNativeNode, - onSuccess, - onFail - ) { - UIManager.measureLayout( - findNumericNodeHandleFiber(this), - relativeToNativeNode, - mountSafeCallback(this, onFail), - mountSafeCallback(this, onSuccess) - ); - }; - ReactNativeComponent.prototype.setNativeProps = function(nativeProps) { - var maybeInstance = void 0; - try { - maybeInstance = findNodeHandle(this); - } catch (error) {} - if (null != maybeInstance) { - var viewConfig = - maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; - nativeProps = diffProperties( - null, - emptyObject$1, - nativeProps, - viewConfig.validAttributes - ); - null != nativeProps && - UIManager.updateView( - maybeInstance._nativeTag, - viewConfig.uiViewClassName, - nativeProps - ); - } - }; - return ReactNativeComponent; -})(React.Component); +var ReactCurrentOwner = + React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner; function isFiberMountedImpl(fiber) { var node = fiber; if (fiber.alternate) for (; node["return"]; ) node = node["return"]; @@ -6048,10 +5786,6 @@ function ReactFiberReconciler$1(config) { scheduleWork(currentTime, expirationTime); return expirationTime; } - function findHostInstance(fiber) { - fiber = findCurrentHostFiber(fiber); - return null === fiber ? null : fiber.stateNode; - } var getPublicInstance = config.getPublicInstance; config = ReactFiberScheduler(config); var recalculateCurrentTime = config.recalculateCurrentTime, @@ -6130,7 +5864,19 @@ function ReactFiberReconciler$1(config) { return container.child.stateNode; } }, - findHostInstance: findHostInstance, + findHostInstance: function(component) { + var fiber = component._reactInternalFiber; + void 0 === fiber && + ("function" === typeof component.render + ? invariant(!1, "Unable to find node on an unmounted component.") + : invariant( + !1, + "Argument appears to not be a ReactComponent. Keys: %s", + Object.keys(component) + )); + component = findCurrentHostFiber(fiber); + return null === component ? null : component.stateNode; + }, findHostInstanceWithNoPortals: function(fiber) { fiber = findCurrentHostFiberWithNoPortals(fiber); return null === fiber ? null : fiber.stateNode; @@ -6140,7 +5886,8 @@ function ReactFiberReconciler$1(config) { return injectInternals( Object.assign({}, devToolsConfig, { findHostInstanceByFiber: function(fiber) { - return findHostInstance(fiber); + fiber = findCurrentHostFiber(fiber); + return null === fiber ? null : fiber.stateNode; }, findFiberByHostInstance: function(instance) { return findFiberByHostInstance @@ -6159,8 +5906,6 @@ var ReactFiberReconciler$2 = Object.freeze({ default: ReactFiberReconciler$1 }), reactReconciler = ReactFiberReconciler$3["default"] ? ReactFiberReconciler$3["default"] : ReactFiberReconciler$3, - viewConfigCallbacks = new Map(), - viewConfigs = new Map(), ReactNativeFiberHostComponent = (function() { function ReactNativeFiberHostComponent(tag, viewConfig) { if (!(this instanceof ReactNativeFiberHostComponent)) @@ -6238,6 +5983,13 @@ function setTimeoutCallback() { scheduledCallback = null; null !== callback && callback(frameDeadlineObject); } +var nextReactTag = 3; +function allocateTag() { + var tag = nextReactTag; + 1 === tag % 10 && (tag += 2); + nextReactTag = tag + 2; + return tag; +} function recursivelyUncacheFiberNode(node) { "number" === typeof node ? uncacheFiberNode(node) @@ -6255,21 +6007,9 @@ var NativeRenderer = reactReconciler({ hostContext, internalInstanceHandle ) { - hostContext = ReactNativeTagHandles.allocateTag(); - if (viewConfigs.has(type)) var viewConfig = viewConfigs.get(type); - else - (viewConfig = viewConfigCallbacks.get(type)), - invariant( - "function" === typeof viewConfig, - "View config not found for name %s", - type - ), - viewConfigCallbacks.set(type, null), - (viewConfig = viewConfig()), - viewConfigs.set(type, viewConfig); - invariant(viewConfig, "View config not found for name %s", type); - type = viewConfig; - viewConfig = diffProperties( + hostContext = allocateTag(); + type = ReactNativeViewConfigRegistry.get(type); + var updatePayload = diffProperties( null, emptyObject$1, props, @@ -6279,7 +6019,7 @@ var NativeRenderer = reactReconciler({ hostContext, type.uiViewClassName, rootContainerInstance, - viewConfig + updatePayload ); rootContainerInstance = new ReactNativeFiberHostComponent( hostContext, @@ -6295,7 +6035,7 @@ var NativeRenderer = reactReconciler({ hostContext, internalInstanceHandle ) { - hostContext = ReactNativeTagHandles.allocateTag(); + hostContext = allocateTag(); UIManager.createView(hostContext, "RCTRawText", rootContainerInstance, { text: text }); @@ -6453,13 +6193,96 @@ var NativeRenderer = reactReconciler({ getInspectorDataForViewTag = function() { invariant(!1, "getInspectorDataForViewTag() is not available in production"); }; -findHostInstance = NativeRenderer.findHostInstance; +var findHostInstance = NativeRenderer.findHostInstance; +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; +} _batchedUpdates = NativeRenderer.batchedUpdates; _flushInteractiveUpdates = NativeRenderer.flushInteractiveUpdates; var roots = new Map(), ReactNativeRenderer = { - NativeComponent: ReactNativeComponent, - findNodeHandle: findNumericNodeHandleFiber, + 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() { + TextInputState.blurTextInput(findNodeHandle(this)); + }; + ReactNativeComponent.prototype.focus = function() { + TextInputState.focusTextInput(findNodeHandle(this)); + }; + ReactNativeComponent.prototype.measure = function(callback) { + UIManager.measure( + findNodeHandle(this), + mountSafeCallback(this, callback) + ); + }; + ReactNativeComponent.prototype.measureInWindow = function(callback) { + UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback(this, callback) + ); + }; + ReactNativeComponent.prototype.measureLayout = function( + relativeToNativeNode, + onSuccess, + onFail + ) { + UIManager.measureLayout( + findNodeHandle(this), + relativeToNativeNode, + mountSafeCallback(this, onFail), + mountSafeCallback(this, onSuccess) + ); + }; + ReactNativeComponent.prototype.setNativeProps = function(nativeProps) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + if (null != maybeInstance) { + var viewConfig = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + nativeProps = diffProperties( + null, + emptyObject$1, + nativeProps, + viewConfig.validAttributes + ); + null != nativeProps && + UIManager.updateView( + maybeInstance._nativeTag, + viewConfig.uiViewClassName, + nativeProps + ); + } + }; + return ReactNativeComponent; + })(React.Component); + })(findNodeHandle, findHostInstance), + findNodeHandle: findNodeHandle, render: function(element, containerTag, callback) { var root = roots.get(containerTag); root || @@ -6488,76 +6311,59 @@ var roots = new Map(), ); }, unstable_batchedUpdates: batchedUpdates, - flushSync: NativeRenderer.flushSync, __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { - NativeMethodsMixin: { - measure: function(callback) { - UIManager.measure( - findNumericNodeHandleFiber(this), - mountSafeCallback(this, callback) - ); - }, - measureInWindow: function(callback) { - UIManager.measureInWindow( - findNumericNodeHandleFiber(this), - mountSafeCallback(this, callback) - ); - }, - measureLayout: function(relativeToNativeNode, onSuccess, onFail) { - UIManager.measureLayout( - findNumericNodeHandleFiber(this), - relativeToNativeNode, - mountSafeCallback(this, onFail), - mountSafeCallback(this, onSuccess) - ); - }, - setNativeProps: function(nativeProps) { - var maybeInstance = void 0; - try { - maybeInstance = findNodeHandle(this); - } catch (error) {} - if (null != maybeInstance) { - var viewConfig = maybeInstance.viewConfig; - nativeProps = diffProperties( - null, - emptyObject$1, - nativeProps, - viewConfig.validAttributes + NativeMethodsMixin: (function(findNodeHandle, findHostInstance) { + return { + measure: function(callback) { + UIManager.measure( + findNodeHandle(this), + mountSafeCallback(this, callback) ); - null != nativeProps && - UIManager.updateView( - maybeInstance._nativeTag, - viewConfig.uiViewClassName, - nativeProps + }, + measureInWindow: function(callback) { + UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback(this, callback) + ); + }, + measureLayout: function(relativeToNativeNode, onSuccess, onFail) { + UIManager.measureLayout( + findNodeHandle(this), + relativeToNativeNode, + mountSafeCallback(this, onFail), + mountSafeCallback(this, onSuccess) + ); + }, + setNativeProps: function(nativeProps) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + if (null != maybeInstance) { + var viewConfig = maybeInstance.viewConfig; + nativeProps = diffProperties( + null, + emptyObject$1, + nativeProps, + viewConfig.validAttributes ); + null != nativeProps && + UIManager.updateView( + maybeInstance._nativeTag, + viewConfig.uiViewClassName, + nativeProps + ); + } + }, + focus: function() { + TextInputState.focusTextInput(findNodeHandle(this)); + }, + blur: function() { + TextInputState.blurTextInput(findNodeHandle(this)); } - }, - focus: function() { - TextInputState.focusTextInput(findNumericNodeHandleFiber(this)); - }, - blur: function() { - TextInputState.blurTextInput(findNumericNodeHandleFiber(this)); - } - }, - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin, + }; + })(findNodeHandle, findHostInstance), ReactNativeComponentTree: ReactNativeComponentTree, - ReactNativePropRegistry: ReactNativePropRegistry, - TouchHistoryMath: TouchHistoryMath, - createReactNativeComponentClass: function(name, callback) { - invariant( - !viewConfigCallbacks.has(name), - "Tried to register two views with the same name %s", - name - ); - viewConfigCallbacks.set(name, callback); - return name; - }, - takeSnapshot: function(view, options) { - "number" !== typeof view && - "window" !== view && - (view = findNumericNodeHandleFiber(view) || "window"); - return UIManager.__takeSnapshot(view, options); - }, computeComponentStackForErrorReporting: function(reactTag) { return (reactTag = getInstanceFromTag(reactTag)) ? getStackAddendumByWorkInProgressFiber(reactTag) diff --git a/Libraries/Renderer/shims/ReactNativeBridgeEventPlugin.js b/Libraries/Renderer/shims/ReactNativeBridgeEventPlugin.js deleted file mode 100644 index 3170faedbad7c0..00000000000000 --- a/Libraries/Renderer/shims/ReactNativeBridgeEventPlugin.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule ReactNativeBridgeEventPlugin - */ - -'use strict'; - -const { - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, -} = require('ReactNative'); - -module.exports = - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactNativeBridgeEventPlugin; diff --git a/Libraries/Renderer/shims/ReactNativeTypes.js b/Libraries/Renderer/shims/ReactNativeTypes.js index f20bb30faa7938..fdee974ae88aa5 100644 --- a/Libraries/Renderer/shims/ReactNativeTypes.js +++ b/Libraries/Renderer/shims/ReactNativeTypes.js @@ -69,19 +69,9 @@ export type NativeMethodsMixinType = { setNativeProps(nativeProps: Object): void, }; -type ReactNativeBridgeEventPlugin = { - processEventTypes(viewConfig: ReactNativeBaseComponentViewConfig): void, -}; - type SecretInternalsType = { NativeMethodsMixin: NativeMethodsMixinType, - createReactNativeComponentClass( - name: string, - callback: ViewConfigGetter, - ): any, - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin, ReactNativeComponentTree: any, - ReactNativePropRegistry: any, // TODO (bvaughn) Decide which additional types to expose here? // And how much information to fill in for the above types. }; @@ -104,3 +94,16 @@ export type ReactNativeType = { __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: SecretInternalsType, }; + +export type ReactFabricType = { + NativeComponent: any, + findNodeHandle(componentOrHandle: any): ?number, + render( + element: React$Element, + containerTag: any, + callback: ?Function, + ): any, + unmountComponentAtNode(containerTag: number): any, + + __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: SecretInternalsType, +}; diff --git a/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js b/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js new file mode 100644 index 00000000000000..ffb0fa213f3b31 --- /dev/null +++ b/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js @@ -0,0 +1,106 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @providesModule ReactNativeViewConfigRegistry + * @flow + */ +'use strict'; + +import type { + ReactNativeBaseComponentViewConfig, + ViewConfigGetter, +} from './ReactNativeTypes'; + +const invariant = require('fbjs/lib/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(); + +function processEventTypes( + viewConfig: ReactNativeBaseComponentViewConfig, +): void { + const {bubblingEventTypes, directEventTypes} = viewConfig; + + if (__DEV__) { + if (bubblingEventTypes != null && directEventTypes != null) { + for (const topLevelType in directEventTypes) { + invariant( + bubblingEventTypes[topLevelType] == null, + 'Event cannot be both direct and bubbling: %s', + topLevelType, + ); + } + } + } + + if (bubblingEventTypes != null) { + for (const topLevelType in bubblingEventTypes) { + if (customBubblingEventTypes[topLevelType] == null) { + eventTypes[topLevelType] = customBubblingEventTypes[topLevelType] = + bubblingEventTypes[topLevelType]; + } + } + } + + if (directEventTypes != null) { + for (const topLevelType in directEventTypes) { + if (customDirectEventTypes[topLevelType] == null) { + eventTypes[topLevelType] = customDirectEventTypes[topLevelType] = + directEventTypes[topLevelType]; + } + } + } +} + +/** + * 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( + !viewConfigCallbacks.has(name), + 'Tried to register two views with the same name %s', + name, + ); + viewConfigCallbacks.set(name, callback); + return name; +}; + +/** + * Retrieves a config for the specified view. + * If this is the first time the view has been used, + * This configuration will be lazy-loaded from UIManager. + */ +exports.get = function(name: string): ReactNativeBaseComponentViewConfig { + let viewConfig; + if (!viewConfigs.has(name)) { + const callback = viewConfigCallbacks.get(name); + invariant( + typeof callback === 'function', + 'View config not found for name %s', + name, + ); + viewConfigCallbacks.set(name, null); + viewConfig = callback(); + processEventTypes(viewConfig); + viewConfigs.set(name, viewConfig); + } else { + viewConfig = viewConfigs.get(name); + } + invariant(viewConfig, 'View config not found for name %s', name); + return viewConfig; +}; diff --git a/Libraries/Renderer/shims/createReactNativeComponentClass.js b/Libraries/Renderer/shims/createReactNativeComponentClass.js index d5d2b8c590093a..1a050e8b3cf0f8 100644 --- a/Libraries/Renderer/shims/createReactNativeComponentClass.js +++ b/Libraries/Renderer/shims/createReactNativeComponentClass.js @@ -10,9 +10,23 @@ 'use strict'; -const { - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, -} = require('ReactNative'); +import type {ViewConfigGetter} from './ReactNativeTypes'; -module.exports = - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.createReactNativeComponentClass; +const {register} = require('ReactNativeViewConfigRegistry'); + +/** + * Creates a renderable ReactNative host component. + * Use this method for view configs that are loaded from UIManager. + * Use createReactNativeComponentClass() for view configs defined within JavaScript. + * + * @param {string} config iOS View configuration. + * @private + */ +const createReactNativeComponentClass = function( + name: string, + callback: ViewConfigGetter, +): string { + return register(name, callback); +}; + +module.exports = createReactNativeComponentClass; diff --git a/Libraries/Text/FabricText.js b/Libraries/Text/FabricText.js index 1eedd8b181c836..2b6748749b7e74 100644 --- a/Libraries/Text/FabricText.js +++ b/Libraries/Text/FabricText.js @@ -10,233 +10,4 @@ */ 'use strict'; -const React = require('React'); -const ReactNative = require('ReactNative'); -const ReactNativeViewAttributes = require('ReactNativeViewAttributes'); -const TextPropTypes = require('TextPropTypes'); -const Touchable = require('Touchable'); -const UIManager = require('UIManager'); - -const {createReactNativeComponentClass} = require('ReactFabricInternals'); -const mergeFast = require('mergeFast'); -const processColor = require('processColor'); -const {ViewContextTypes} = require('ViewContext'); - -import type {PressEvent} from 'CoreEventTypes'; -import type {TextProps} from 'TextProps'; -import type {ViewChildContext} from 'ViewContext'; - -type State = { - isHighlighted: boolean, -}; - -type RectOffset = { - top: number, - left: number, - right: number, - bottom: number, -}; - -const PRESS_RECT_OFFSET = {top: 20, left: 20, right: 20, bottom: 30}; - -const viewConfig = { - validAttributes: mergeFast(ReactNativeViewAttributes.UIView, { - isHighlighted: true, - numberOfLines: true, - ellipsizeMode: true, - allowFontScaling: true, - disabled: true, - selectable: true, - selectionColor: true, - adjustsFontSizeToFit: true, - minimumFontScale: true, - textBreakStrategy: true, - }), - uiViewClassName: 'RCTText', -}; - -/** - * A React component for displaying text. - * - * See https://facebook.github.io/react-native/docs/text.html - */ -class Text extends ReactNative.NativeComponent { - static propTypes = TextPropTypes; - static childContextTypes = ViewContextTypes; - static contextTypes = ViewContextTypes; - - static defaultProps = { - accessible: true, - allowFontScaling: true, - ellipsizeMode: 'tail', - }; - - state = mergeFast(Touchable.Mixin.touchableGetInitialState(), { - isHighlighted: false, - }); - - viewConfig = viewConfig; - - getChildContext(): ViewChildContext { - return { - isInAParentText: true, - }; - } - - _handlers: ?Object; - - _hasPressHandler(): boolean { - return !!this.props.onPress || !!this.props.onLongPress; - } - /** - * These are assigned lazily the first time the responder is set to make plain - * text nodes as cheap as possible. - */ - touchableHandleActivePressIn: ?Function; - touchableHandleActivePressOut: ?Function; - touchableHandlePress: ?Function; - touchableHandleLongPress: ?Function; - touchableHandleResponderGrant: ?Function; - touchableHandleResponderMove: ?Function; - touchableHandleResponderRelease: ?Function; - touchableHandleResponderTerminate: ?Function; - touchableHandleResponderTerminationRequest: ?Function; - touchableGetPressRectOffset: ?Function; - - render(): React.Element { - let newProps = this.props; - if (this.props.onStartShouldSetResponder || this._hasPressHandler()) { - if (!this._handlers) { - this._handlers = { - onStartShouldSetResponder: (): boolean => { - const shouldSetFromProps = - this.props.onStartShouldSetResponder && - this.props.onStartShouldSetResponder(); - const setResponder = shouldSetFromProps || this._hasPressHandler(); - if (setResponder && !this.touchableHandleActivePressIn) { - // Attach and bind all the other handlers only the first time a touch - // actually happens. - for (const key in Touchable.Mixin) { - if (typeof Touchable.Mixin[key] === 'function') { - (this: any)[key] = Touchable.Mixin[key].bind(this); - } - } - this.touchableHandleActivePressIn = () => { - if ( - this.props.suppressHighlighting || - !this._hasPressHandler() - ) { - return; - } - this.setState({ - isHighlighted: true, - }); - }; - - this.touchableHandleActivePressOut = () => { - if ( - this.props.suppressHighlighting || - !this._hasPressHandler() - ) { - return; - } - this.setState({ - isHighlighted: false, - }); - }; - - this.touchableHandlePress = (e: PressEvent) => { - this.props.onPress && this.props.onPress(e); - }; - - this.touchableHandleLongPress = (e: PressEvent) => { - this.props.onLongPress && this.props.onLongPress(e); - }; - - this.touchableGetPressRectOffset = function(): RectOffset { - return this.props.pressRetentionOffset || PRESS_RECT_OFFSET; - }; - } - return setResponder; - }, - onResponderGrant: function(e: SyntheticEvent<>, dispatchID: string) { - // $FlowFixMe TouchableMixin handlers couldn't actually be null - this.touchableHandleResponderGrant(e, dispatchID); - this.props.onResponderGrant && - this.props.onResponderGrant.apply(this, arguments); - }.bind(this), - onResponderMove: function(e: SyntheticEvent<>) { - // $FlowFixMe TouchableMixin handlers couldn't actually be null - this.touchableHandleResponderMove(e); - this.props.onResponderMove && - this.props.onResponderMove.apply(this, arguments); - }.bind(this), - onResponderRelease: function(e: SyntheticEvent<>) { - // $FlowFixMe TouchableMixin handlers couldn't actually be null - this.touchableHandleResponderRelease(e); - this.props.onResponderRelease && - this.props.onResponderRelease.apply(this, arguments); - }.bind(this), - onResponderTerminate: function(e: SyntheticEvent<>) { - // $FlowFixMe TouchableMixin handlers couldn't actually be null - this.touchableHandleResponderTerminate(e); - this.props.onResponderTerminate && - this.props.onResponderTerminate.apply(this, arguments); - }.bind(this), - onResponderTerminationRequest: function(): boolean { - // Allow touchable or props.onResponderTerminationRequest to deny - // the request - // $FlowFixMe TouchableMixin handlers couldn't actually be null - var allowTermination = this.touchableHandleResponderTerminationRequest(); - if (allowTermination && this.props.onResponderTerminationRequest) { - allowTermination = this.props.onResponderTerminationRequest.apply( - this, - arguments, - ); - } - return allowTermination; - }.bind(this), - }; - } - newProps = { - ...this.props, - ...this._handlers, - isHighlighted: this.state.isHighlighted, - }; - } - if (newProps.selectionColor != null) { - newProps = { - ...newProps, - selectionColor: processColor(newProps.selectionColor), - }; - } - if (Touchable.TOUCH_TARGET_DEBUG && newProps.onPress) { - newProps = { - ...newProps, - style: [this.props.style, {color: 'magenta'}], - }; - } - if (this.context.isInAParentText) { - return ; - } else { - return ; - } - } -} - -var RCTText = createReactNativeComponentClass( - viewConfig.uiViewClassName, - () => viewConfig, -); -var RCTVirtualText = RCTText; - -if (UIManager.RCTVirtualText) { - RCTVirtualText = createReactNativeComponentClass('RCTVirtualText', () => ({ - validAttributes: mergeFast(ReactNativeViewAttributes.UIView, { - isHighlighted: true, - }), - uiViewClassName: 'RCTVirtualText', - })); -} - -module.exports = Text; +module.exports = require('Text'); From 87539c34dbe1ba359d4f42caf612380a930498ff Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 16:36:43 -0700 Subject: [PATCH 0263/1109] Fabric: RCTComponentViewProtocol Summary: RCTComponentViewProtocol is a protocol for all UIView instances which are managed by React/MountingManager. Reviewed By: mdvacca Differential Revision: D7507520 fbshipit-source-id: dcbed8c5d0cc97f72942508aeccb445833ade271 --- .../Mounting/RCTComponentViewProtocol.h | 64 +++++++++++++++++++ React/Fabric/RCTPrimitives.h | 10 +++ 2 files changed, 74 insertions(+) create mode 100644 React/Fabric/Mounting/RCTComponentViewProtocol.h create mode 100644 React/Fabric/RCTPrimitives.h diff --git a/React/Fabric/Mounting/RCTComponentViewProtocol.h b/React/Fabric/Mounting/RCTComponentViewProtocol.h new file mode 100644 index 00000000000000..d23ac72adfef53 --- /dev/null +++ b/React/Fabric/Mounting/RCTComponentViewProtocol.h @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * Represents a `UIView` instance managed by React. + * All methods are non-@optional. + * `UIView+ComponentViewProtocol` category provides default implementation + * for all of them. + */ +@protocol RCTComponentViewProtocol + +/* + * Called for mounting (attaching) a child component view inside `self` + * component view. + * Receiver must add `childComponentView` as a subview. + */ +- (void)mountChildComponentView:(UIView *)childComponentView + index:(NSInteger)index; + +/* + * Called for unmounting (detaching) a child component view from `self` + * component view. + * Receiver must remove `childComponentView` as a subview. + */ +- (void)unmountChildComponentView:(UIView *)childComponentView + index:(NSInteger)index; + +/* + * Called for updating component's props. + * Receiver must update native view props accordingly changed props. + */ +- (void)updateProps:(facebook::react::SharedProps)props + oldProps:(facebook::react::SharedProps)oldProps; + +/* + * Called for updating component's layout metrics. + * Receiver must update `UIView` layout-related fields (such as `frame`, + * `bounds`, `layer.zPosition`, and so on) accordingly. + */ +- (void)updateLayoutMetrics:(facebook::react::LayoutMetrics)layoutMetrics + oldLayoutMetrics:(facebook::react::LayoutMetrics)oldLayoutMetrics; + +/* + * Called right after the component view is moved to a recycle pool. + * Receiver must reset any local state and release associated + * non-reusable resources. + */ +- (void)prepareForRecycle; + +@end + +NS_ASSUME_NONNULL_END diff --git a/React/Fabric/RCTPrimitives.h b/React/Fabric/RCTPrimitives.h new file mode 100644 index 00000000000000..7712dabc9f1ed4 --- /dev/null +++ b/React/Fabric/RCTPrimitives.h @@ -0,0 +1,10 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +typedef NSInteger ReactTag; From dfb8fd26e64b66ca9731f7f37b6d5082d6df4035 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 16:36:45 -0700 Subject: [PATCH 0264/1109] Fabric: Default implementation of RCTComponentViewProtocol Summary: All methods of RCTComponentViewProtocol are non-optional, but this default implementation removes necessity to implement all of them manually. Reviewed By: mdvacca Differential Revision: D7507522 fbshipit-source-id: e4dff97e8bf64e79d2f1ffca94f0549bd4b5e2fa --- .../Mounting/UIView+ComponentViewProtocol.h | 35 ++++++++++++ .../Mounting/UIView+ComponentViewProtocol.mm | 57 +++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 React/Fabric/Mounting/UIView+ComponentViewProtocol.h create mode 100644 React/Fabric/Mounting/UIView+ComponentViewProtocol.mm diff --git a/React/Fabric/Mounting/UIView+ComponentViewProtocol.h b/React/Fabric/Mounting/UIView+ComponentViewProtocol.h new file mode 100644 index 00000000000000..b38b41ba5cfb75 --- /dev/null +++ b/React/Fabric/Mounting/UIView+ComponentViewProtocol.h @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * Default implementation of RCTComponentViewProtocol. + */ +@interface UIView (ComponentViewProtocol) + +- (void)mountChildComponentView:(UIView *)childComponentView + index:(NSInteger)index; + +- (void)unmountChildComponentView:(UIView *)childComponentView + index:(NSInteger)index; + +- (void)updateProps:(facebook::react::SharedProps)props + oldProps:(facebook::react::SharedProps)oldProps; + +- (void)updateLayoutMetrics:(facebook::react::LayoutMetrics)layoutMetrics + oldLayoutMetrics:(facebook::react::LayoutMetrics)oldLayoutMetrics; + +- (void)prepareForRecycle; + +@end + +NS_ASSUME_NONNULL_END diff --git a/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm b/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm new file mode 100644 index 00000000000000..93b5784e3d92c0 --- /dev/null +++ b/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "UIView+ComponentViewProtocol.h" + +#import + +@implementation UIView (ComponentViewProtocol) + +- (void)mountChildComponentView:(UIView *)childComponentView + index:(NSInteger)index +{ + [self insertSubview:childComponentView atIndex:index]; +} + +- (void)unmountChildComponentView:(UIView *)childComponentView + index:(NSInteger)index +{ + RCTAssert(childComponentView.superview == self, @"Attempt to unmount improperly mounted component view."); + [childComponentView removeFromSuperview]; +} + +- (void)updateProps:(facebook::react::SharedProps)props + oldProps:(facebook::react::SharedProps)oldProps +{ + // Default implementation does nothing. +} + +- (void)updateLayoutMetrics:(facebook::react::LayoutMetrics)layoutMetrics + oldLayoutMetrics:(facebook::react::LayoutMetrics)oldLayoutMetrics +{ + if (layoutMetrics.frame != oldLayoutMetrics.frame) { + self.frame = { + .origin = { + .x = layoutMetrics.frame.origin.x, + .y = layoutMetrics.frame.origin.y + }, + .size = { + .width = layoutMetrics.frame.size.width, + .height = layoutMetrics.frame.size.height + } + }; + } + + // TODO: Apply another layout metrics here. +} + +- (void)prepareForRecycle +{ + // Default implementation does nothing. +} + +@end From 11833714d9a98b3963e28f025b4fafb03497b0d1 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 16:36:47 -0700 Subject: [PATCH 0265/1109] Fabric: RCTMountItemProtocol and five base mount items Summary: MountItem is a small granular light-weight instruction describing a change in the component view tree. All instruction are supposed to be small and standard. All additional logic must be implemented in component view subclasses. No more opaque and untyped objcblocks. All that allows mounting manager to control and optimize an execution of those items (eventually). Besides that five we probably will need `perform imperative instruction` (for execution something like `scrollTo`) and `update local data` (for updating local state of something like text input). Reviewed By: mdvacca Differential Revision: D7507518 fbshipit-source-id: 745b93125231a02cbc152cfa6c6baf423d100f81 --- .../Mounting/MountItems/RCTCreateMountItem.h | 27 ++++++++++++ .../Mounting/MountItems/RCTCreateMountItem.mm | 33 +++++++++++++++ .../Mounting/MountItems/RCTDeleteMountItem.h | 25 +++++++++++ .../Mounting/MountItems/RCTDeleteMountItem.mm | 34 +++++++++++++++ .../Mounting/MountItems/RCTInsertMountItem.h | 28 +++++++++++++ .../Mounting/MountItems/RCTInsertMountItem.mm | 40 ++++++++++++++++++ .../MountItems/RCTMountItemProtocol.h | 23 +++++++++++ .../Mounting/MountItems/RCTRemoveMountItem.h | 26 ++++++++++++ .../Mounting/MountItems/RCTRemoveMountItem.mm | 40 ++++++++++++++++++ .../RCTUpdateLayoutMetricsMountItem.h | 27 ++++++++++++ .../RCTUpdateLayoutMetricsMountItem.mm | 41 +++++++++++++++++++ .../MountItems/RCTUpdatePropsMountItem.h | 27 ++++++++++++ .../MountItems/RCTUpdatePropsMountItem.mm | 39 ++++++++++++++++++ 13 files changed, 410 insertions(+) create mode 100644 React/Fabric/Mounting/MountItems/RCTCreateMountItem.h create mode 100644 React/Fabric/Mounting/MountItems/RCTCreateMountItem.mm create mode 100644 React/Fabric/Mounting/MountItems/RCTDeleteMountItem.h create mode 100644 React/Fabric/Mounting/MountItems/RCTDeleteMountItem.mm create mode 100644 React/Fabric/Mounting/MountItems/RCTInsertMountItem.h create mode 100644 React/Fabric/Mounting/MountItems/RCTInsertMountItem.mm create mode 100644 React/Fabric/Mounting/MountItems/RCTMountItemProtocol.h create mode 100644 React/Fabric/Mounting/MountItems/RCTRemoveMountItem.h create mode 100644 React/Fabric/Mounting/MountItems/RCTRemoveMountItem.mm create mode 100644 React/Fabric/Mounting/MountItems/RCTUpdateLayoutMetricsMountItem.h create mode 100644 React/Fabric/Mounting/MountItems/RCTUpdateLayoutMetricsMountItem.mm create mode 100644 React/Fabric/Mounting/MountItems/RCTUpdatePropsMountItem.h create mode 100644 React/Fabric/Mounting/MountItems/RCTUpdatePropsMountItem.mm diff --git a/React/Fabric/Mounting/MountItems/RCTCreateMountItem.h b/React/Fabric/Mounting/MountItems/RCTCreateMountItem.h new file mode 100644 index 00000000000000..6376094894d21d --- /dev/null +++ b/React/Fabric/Mounting/MountItems/RCTCreateMountItem.h @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@class RCTComponentViewRegistry; + +/** + * Creates a ready-to-mount component view. + */ +@interface RCTCreateMountItem : NSObject + +- (instancetype)initWithComponentName:(NSString *)componentName + tag:(ReactTag)tag; + +@end + +NS_ASSUME_NONNULL_END diff --git a/React/Fabric/Mounting/MountItems/RCTCreateMountItem.mm b/React/Fabric/Mounting/MountItems/RCTCreateMountItem.mm new file mode 100644 index 00000000000000..df04396b476039 --- /dev/null +++ b/React/Fabric/Mounting/MountItems/RCTCreateMountItem.mm @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTCreateMountItem.h" + +#import "RCTComponentViewRegistry.h" + +@implementation RCTCreateMountItem { + NSString *_componentName; + ReactTag _tag; +} + +- (instancetype)initWithComponentName:(NSString *)componentName + tag:(ReactTag)tag +{ + if (self = [super init]) { + _componentName = componentName; + _tag = tag; + } + + return self; +} + +- (void)executeWithRegistry:(RCTComponentViewRegistry *)registry +{ + [registry dequeueComponentViewWithName:_componentName tag:_tag]; +} + +@end diff --git a/React/Fabric/Mounting/MountItems/RCTDeleteMountItem.h b/React/Fabric/Mounting/MountItems/RCTDeleteMountItem.h new file mode 100644 index 00000000000000..a4c6077b56f3d4 --- /dev/null +++ b/React/Fabric/Mounting/MountItems/RCTDeleteMountItem.h @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * Deletes (returns to recycle pool) a component view. + */ +@interface RCTDeleteMountItem : NSObject + +- (instancetype)initWithComponentName:(NSString *)componentName + tag:(ReactTag)tag; + +@end + +NS_ASSUME_NONNULL_END diff --git a/React/Fabric/Mounting/MountItems/RCTDeleteMountItem.mm b/React/Fabric/Mounting/MountItems/RCTDeleteMountItem.mm new file mode 100644 index 00000000000000..99909f450cc245 --- /dev/null +++ b/React/Fabric/Mounting/MountItems/RCTDeleteMountItem.mm @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTDeleteMountItem.h" + +#import "RCTComponentViewRegistry.h" + +@implementation RCTDeleteMountItem { + NSString *_componentName; + ReactTag _tag; +} + +- (instancetype)initWithComponentName:(NSString *)componentName + tag:(ReactTag)tag +{ + if (self = [super init]) { + _componentName = componentName; + _tag = tag; + } + + return self; +} + +- (void)executeWithRegistry:(RCTComponentViewRegistry *)registry +{ + UIView *componentView = [registry componentViewByTag:_tag]; + [registry enqueueComponentViewWithName:_componentName tag:_tag componentView:componentView]; +} + +@end diff --git a/React/Fabric/Mounting/MountItems/RCTInsertMountItem.h b/React/Fabric/Mounting/MountItems/RCTInsertMountItem.h new file mode 100644 index 00000000000000..e3d4ac29d7aad5 --- /dev/null +++ b/React/Fabric/Mounting/MountItems/RCTInsertMountItem.h @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@class RCTComponentViewRegistry; + +/** + * Inserts a component view into another component view. + */ +@interface RCTInsertMountItem : NSObject + +- (instancetype)initWithChildTag:(ReactTag)childTag + parentTag:(ReactTag)parentTag + index:(NSInteger)index; + +@end + +NS_ASSUME_NONNULL_END diff --git a/React/Fabric/Mounting/MountItems/RCTInsertMountItem.mm b/React/Fabric/Mounting/MountItems/RCTInsertMountItem.mm new file mode 100644 index 00000000000000..f714cb0a70db71 --- /dev/null +++ b/React/Fabric/Mounting/MountItems/RCTInsertMountItem.mm @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTInsertMountItem.h" + +#import "RCTComponentViewRegistry.h" + +@implementation RCTInsertMountItem { + ReactTag _childTag; + ReactTag _parentTag; + NSInteger _index; +} + +- (instancetype)initWithChildTag:(ReactTag)childTag + parentTag:(ReactTag)parentTag + index:(NSInteger)index +{ + if (self = [super init]) { + _childTag = childTag; + _parentTag = parentTag; + _index = index; + } + + return self; +} + +- (void)executeWithRegistry:(RCTComponentViewRegistry *)registry +{ + UIView *childComponentView = [registry componentViewByTag:_childTag]; + UIView *parentComponentView = [registry componentViewByTag:_parentTag]; + + [parentComponentView mountChildComponentView:childComponentView + index:_index]; +} + +@end diff --git a/React/Fabric/Mounting/MountItems/RCTMountItemProtocol.h b/React/Fabric/Mounting/MountItems/RCTMountItemProtocol.h new file mode 100644 index 00000000000000..f46c397498b456 --- /dev/null +++ b/React/Fabric/Mounting/MountItems/RCTMountItemProtocol.h @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@class RCTComponentViewRegistry; + +/** + * Granular representation of any change in a user interface. + */ +@protocol RCTMountItemProtocol + +- (void)executeWithRegistry:(RCTComponentViewRegistry *)registry; + +@end + +NS_ASSUME_NONNULL_END diff --git a/React/Fabric/Mounting/MountItems/RCTRemoveMountItem.h b/React/Fabric/Mounting/MountItems/RCTRemoveMountItem.h new file mode 100644 index 00000000000000..0fe9555a613ea4 --- /dev/null +++ b/React/Fabric/Mounting/MountItems/RCTRemoveMountItem.h @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * Removes a component view from another component view. + */ +@interface RCTRemoveMountItem : NSObject + +- (instancetype)initWithChildTag:(ReactTag)childTag + parentTag:(ReactTag)parentTag + index:(NSInteger)index; + +@end + +NS_ASSUME_NONNULL_END diff --git a/React/Fabric/Mounting/MountItems/RCTRemoveMountItem.mm b/React/Fabric/Mounting/MountItems/RCTRemoveMountItem.mm new file mode 100644 index 00000000000000..d46b936dd04474 --- /dev/null +++ b/React/Fabric/Mounting/MountItems/RCTRemoveMountItem.mm @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTRemoveMountItem.h" + +#import "RCTComponentViewRegistry.h" + +@implementation RCTRemoveMountItem { + ReactTag _childTag; + ReactTag _parentTag; + NSInteger _index; +} + +- (instancetype)initWithChildTag:(ReactTag)childTag + parentTag:(ReactTag)parentTag + index:(NSInteger)index +{ + if (self = [super init]) { + _childTag = childTag; + _parentTag = parentTag; + _index = index; + } + + return self; +} + +- (void)executeWithRegistry:(RCTComponentViewRegistry *)registry +{ + UIView *childComponentView = [registry componentViewByTag:_childTag]; + UIView *parentComponentView = [registry componentViewByTag:_parentTag]; + + [parentComponentView unmountChildComponentView:childComponentView + index:_index]; +} + +@end diff --git a/React/Fabric/Mounting/MountItems/RCTUpdateLayoutMetricsMountItem.h b/React/Fabric/Mounting/MountItems/RCTUpdateLayoutMetricsMountItem.h new file mode 100644 index 00000000000000..378c179d3c46cd --- /dev/null +++ b/React/Fabric/Mounting/MountItems/RCTUpdateLayoutMetricsMountItem.h @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * Updates layout metrics of a component view. + */ +@interface RCTUpdateLayoutMetricsMountItem : NSObject + +- (instancetype)initWithTag:(ReactTag)tag + oldLayoutMetrics:(facebook::react::LayoutMetrics)oldLayoutMetrics + newLayoutMetrics:(facebook::react::LayoutMetrics)newLayoutMetrics; + +@end + +NS_ASSUME_NONNULL_END diff --git a/React/Fabric/Mounting/MountItems/RCTUpdateLayoutMetricsMountItem.mm b/React/Fabric/Mounting/MountItems/RCTUpdateLayoutMetricsMountItem.mm new file mode 100644 index 00000000000000..c61a043626a62f --- /dev/null +++ b/React/Fabric/Mounting/MountItems/RCTUpdateLayoutMetricsMountItem.mm @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTUpdateLayoutMetricsMountItem.h" + +#import "RCTComponentViewRegistry.h" + +using namespace facebook::react; + +@implementation RCTUpdateLayoutMetricsMountItem { + ReactTag _tag; + LayoutMetrics _oldLayoutMetrics; + LayoutMetrics _newLayoutMetrics; +} + +- (instancetype)initWithTag:(ReactTag)tag + oldLayoutMetrics:(facebook::react::LayoutMetrics)oldLayoutMetrics + newLayoutMetrics:(facebook::react::LayoutMetrics)newLayoutMetrics +{ + if (self = [super init]) { + _tag = tag; + _oldLayoutMetrics = oldLayoutMetrics; + _newLayoutMetrics = newLayoutMetrics; + } + + return self; +} + +- (void)executeWithRegistry:(RCTComponentViewRegistry *)registry +{ + UIView *componentView = [registry componentViewByTag:_tag]; + + [componentView updateLayoutMetrics:_newLayoutMetrics + oldLayoutMetrics:_oldLayoutMetrics]; +} + +@end diff --git a/React/Fabric/Mounting/MountItems/RCTUpdatePropsMountItem.h b/React/Fabric/Mounting/MountItems/RCTUpdatePropsMountItem.h new file mode 100644 index 00000000000000..efdfed64ddbf32 --- /dev/null +++ b/React/Fabric/Mounting/MountItems/RCTUpdatePropsMountItem.h @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * Updates props of a component view. + */ +@interface RCTUpdatePropsMountItem : NSObject + +- (instancetype)initWithTag:(ReactTag)tag + oldProps:(facebook::react::SharedProps)oldProps + newProps:(facebook::react::SharedProps)newProps; + +@end + +NS_ASSUME_NONNULL_END diff --git a/React/Fabric/Mounting/MountItems/RCTUpdatePropsMountItem.mm b/React/Fabric/Mounting/MountItems/RCTUpdatePropsMountItem.mm new file mode 100644 index 00000000000000..694b72e4046a3a --- /dev/null +++ b/React/Fabric/Mounting/MountItems/RCTUpdatePropsMountItem.mm @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTUpdatePropsMountItem.h" + +#import "RCTComponentViewRegistry.h" + +using namespace facebook::react; + +@implementation RCTUpdatePropsMountItem { + ReactTag _tag; + SharedProps _oldProps; + SharedProps _newProps; +} + +- (instancetype)initWithTag:(ReactTag)tag + oldProps:(SharedProps)oldProps + newProps:(SharedProps)newProps +{ + if (self = [super init]) { + _tag = tag; + _oldProps = oldProps; + _newProps = newProps; + } + + return self; +} + +- (void)executeWithRegistry:(RCTComponentViewRegistry *)registry +{ + UIView *componentView = [registry componentViewByTag:_tag]; + [componentView updateProps:_newProps oldProps:_oldProps]; +} + +@end From 6c406ffe3873db931022d6674a12f4d294fcf5e0 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 16:36:50 -0700 Subject: [PATCH 0266/1109] Fabric: RCTComponentViewRegistry Summary: A registry for components. The registry allows to refer to component view instance by react tag. It also has recycle-pool-like interface (and eventually the pool will be implemented). Reviewed By: mdvacca Differential Revision: D7507519 fbshipit-source-id: ed74203fb4d0694490b0dc23aae0aa067b3fc55b --- .../Mounting/RCTComponentViewRegistry.h | 48 +++++++++++++++ .../Mounting/RCTComponentViewRegistry.mm | 59 +++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 React/Fabric/Mounting/RCTComponentViewRegistry.h create mode 100644 React/Fabric/Mounting/RCTComponentViewRegistry.mm diff --git a/React/Fabric/Mounting/RCTComponentViewRegistry.h b/React/Fabric/Mounting/RCTComponentViewRegistry.h new file mode 100644 index 00000000000000..1e747b124da12c --- /dev/null +++ b/React/Fabric/Mounting/RCTComponentViewRegistry.h @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * Registry of native component views. + * Provides basic functionality for allocation, recycling, and querying (by tag) native view instances. + */ +@interface RCTComponentViewRegistry : NSObject + +/** + * Returns a native view instance from the recycle pool (or create) + * for given `componentName` and with given `tag`. + * #RefuseSingleUse + */ +- (UIView *)dequeueComponentViewWithName:(NSString *)componentName + tag:(ReactTag)tag; + +/** + * Puts a given native component view to the recycle pool. + * #RefuseSingleUse + */ +- (void)enqueueComponentViewWithName:(NSString *)componentName + tag:(ReactTag)tag + componentView:(UIView *)componentView; + +/** + * Returns a native component view by given `tag`. + */ +- (UIView *)componentViewByTag:(ReactTag)tag; + +/** + * Returns `tag` assosiated with given `componentView`. + */ +- (ReactTag)tagByComponentView:(UIView *)componentView; + +@end + +NS_ASSUME_NONNULL_END diff --git a/React/Fabric/Mounting/RCTComponentViewRegistry.mm b/React/Fabric/Mounting/RCTComponentViewRegistry.mm new file mode 100644 index 00000000000000..c9d8224007e407 --- /dev/null +++ b/React/Fabric/Mounting/RCTComponentViewRegistry.mm @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTComponentViewRegistry.h" + +#import +#import + +@implementation RCTComponentViewRegistry { + NSMapTable *> *_registry; +} + +- (instancetype)init +{ + if (self = [super init]) { + _registry = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsIntegerPersonality | NSPointerFunctionsOpaqueMemory + valueOptions:NSPointerFunctionsObjectPersonality]; + } + + return self; +} + +- (UIView *)dequeueComponentViewWithName:(NSString *)componentName + tag:(ReactTag)tag +{ + RCTAssertMainQueue(); + // This is temporary approach. + NSString *className = [NSString stringWithFormat:@"RCT%@ComponentView", componentName]; + UIView *componentView = [[NSClassFromString(className) alloc] init]; + componentView.tag = tag; + [_registry setObject:componentView forKey:(__bridge id)(void *)tag]; + return componentView; +} + +- (void)enqueueComponentViewWithName:(NSString *)componentName + tag:(ReactTag)tag + componentView:(UIView *)componentView +{ + RCTAssertMainQueue(); + [_registry removeObjectForKey:(__bridge id)(void *)tag]; +} + +- (UIView *)componentViewByTag:(ReactTag)tag +{ + RCTAssertMainQueue(); + return [_registry objectForKey:(__bridge id)(void *)tag]; +} + +- (ReactTag)tagByComponentView:(UIView *)componentView +{ + RCTAssertMainQueue(); + return componentView.tag; +} + +@end From 3093df675490c9b40801350a994e9479dc445350 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 16:36:54 -0700 Subject: [PATCH 0267/1109] Fabric: RCTMountingManager and RCTMountingManagerDelegate Summary: RCTMountingManager manages mounting process transforming mutation instructions into mount items and executing them. Reviewed By: mdvacca Differential Revision: D7507521 fbshipit-source-id: 6e5acdbf0b7f8bedc7e1de141dc9086f35a376c9 --- React/Fabric/Mounting/RCTMountingManager.h | 35 ++++ React/Fabric/Mounting/RCTMountingManager.mm | 152 ++++++++++++++++++ .../Mounting/RCTMountingManagerDelegate.h | 37 +++++ 3 files changed, 224 insertions(+) create mode 100644 React/Fabric/Mounting/RCTMountingManager.h create mode 100644 React/Fabric/Mounting/RCTMountingManager.mm create mode 100644 React/Fabric/Mounting/RCTMountingManagerDelegate.h diff --git a/React/Fabric/Mounting/RCTMountingManager.h b/React/Fabric/Mounting/RCTMountingManager.h new file mode 100644 index 00000000000000..bf66ac7f5757a6 --- /dev/null +++ b/React/Fabric/Mounting/RCTMountingManager.h @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@class RCTComponentViewRegistry; + +/** + * Manages mounting process. + */ +@interface RCTMountingManager : NSObject + +@property (nonatomic, weak) id delegate; +@property (nonatomic, strong) RCTComponentViewRegistry *componentViewRegistry; + +/** + * Transfroms mutation insturctions to mount items and execute them. + * The order of mutation tnstructions matters. + */ +- (void)mutateComponentViewTreeWithMutationInstructions:(facebook::react::TreeMutationInstructionList)instructions + rootTag:(ReactTag)rootTag; + +@end + +NS_ASSUME_NONNULL_END diff --git a/React/Fabric/Mounting/RCTMountingManager.mm b/React/Fabric/Mounting/RCTMountingManager.mm new file mode 100644 index 00000000000000..5f16ac2513dce2 --- /dev/null +++ b/React/Fabric/Mounting/RCTMountingManager.mm @@ -0,0 +1,152 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTMountingManager.h" + +#import +#import +#import + +#import "RCTComponentViewProtocol.h" +#import "RCTComponentViewRegistry.h" +#import "RCTMountItemProtocol.h" + +#import "RCTCreateMountItem.h" +#import "RCTDeleteMountItem.h" +#import "RCTInsertMountItem.h" +#import "RCTRemoveMountItem.h" +#import "RCTUpdatePropsMountItem.h" +#import "RCTUpdateLayoutMetricsMountItem.h" + +using namespace facebook::react; + +@implementation RCTMountingManager + +- (instancetype)init +{ + if (self = [super init]) { + _componentViewRegistry = [[RCTComponentViewRegistry alloc] init]; + } + + return self; +} + +- (void)mutateComponentViewTreeWithMutationInstructions:(facebook::react::TreeMutationInstructionList)instructions + rootTag:(ReactTag)rootTag +{ + NSMutableArray *mountItems = + [[NSMutableArray alloc] initWithCapacity:instructions.size() * 2 /* ~ the worst case */]; + + for (auto instruction : instructions) { + switch (instruction.getType()) { + case TreeMutationInstruction::Creation: { + NSString *componentName = [NSString stringWithCString:instruction.getNewChildNode()->getComponentName().c_str() + encoding:NSASCIIStringEncoding]; + RCTCreateMountItem *mountItem = + [[RCTCreateMountItem alloc] initWithComponentName:componentName + tag:instruction.getNewChildNode()->getTag()]; + [mountItems addObject:mountItem]; + break; + } + case TreeMutationInstruction::Deletion: { + NSString *componentName = [NSString stringWithCString:instruction.getOldChildNode()->getComponentName().c_str() + encoding:NSASCIIStringEncoding]; + RCTDeleteMountItem *mountItem = + [[RCTDeleteMountItem alloc] initWithComponentName:componentName + tag:instruction.getOldChildNode()->getTag()]; + [mountItems addObject:mountItem]; + break; + } + + case TreeMutationInstruction::Insertion: { + RCTInsertMountItem *mountItem = + [[RCTInsertMountItem alloc] initWithChildTag:instruction.getNewChildNode()->getTag() + parentTag:instruction.getParentNode()->getTag() + index:instruction.getIndex()]; + [mountItems addObject:mountItem]; + + // Props + [mountItems addObject:[[RCTUpdatePropsMountItem alloc] initWithTag:instruction.getNewChildNode()->getTag() + oldProps:nullptr + newProps:instruction.getNewChildNode()->getProps()]]; + + // Layout + SharedLayoutableShadowNode layoutableNewShadowNode = + std::dynamic_pointer_cast(instruction.getNewChildNode()); + + if (layoutableNewShadowNode) { + [mountItems addObject:[[RCTUpdateLayoutMetricsMountItem alloc] initWithTag:instruction.getNewChildNode()->getTag() + oldLayoutMetrics:{} + newLayoutMetrics:layoutableNewShadowNode->getLayoutMetrics()]]; + } + break; + } + + case TreeMutationInstruction::Removal: { + RCTRemoveMountItem *mountItem = + [[RCTRemoveMountItem alloc] initWithChildTag:instruction.getOldChildNode()->getTag() + parentTag:instruction.getParentNode()->getTag() + index:instruction.getIndex()]; + [mountItems addObject:mountItem]; + break; + } + + case TreeMutationInstruction::Replacement: { + SharedShadowNode oldShadowNode = instruction.getOldChildNode(); + SharedShadowNode newShadowNode = instruction.getNewChildNode(); + + // Props + if (oldShadowNode->getProps() != newShadowNode->getProps()) { + RCTUpdatePropsMountItem *mountItem = + [[RCTUpdatePropsMountItem alloc] initWithTag:instruction.getOldChildNode()->getTag() + oldProps:instruction.getOldChildNode()->getProps() + newProps:instruction.getNewChildNode()->getProps()]; + [mountItems addObject:mountItem]; + } + + // Layout + SharedLayoutableShadowNode layoutableOldShadowNode = + std::dynamic_pointer_cast(oldShadowNode); + + if (layoutableOldShadowNode) { + SharedLayoutableShadowNode layoutableNewShadowNode = + std::dynamic_pointer_cast(newShadowNode); + + if (layoutableOldShadowNode->getLayoutMetrics() != layoutableNewShadowNode->getLayoutMetrics()) { + RCTUpdateLayoutMetricsMountItem *mountItem = + [[RCTUpdateLayoutMetricsMountItem alloc] initWithTag:instruction.getOldChildNode()->getTag() + oldLayoutMetrics:layoutableOldShadowNode->getLayoutMetrics() + newLayoutMetrics:layoutableNewShadowNode->getLayoutMetrics()]; + [mountItems addObject:mountItem]; + } + } + + break; + } + } + } + + RCTExecuteOnMainQueue(^{ + [self _performMountItems:mountItems rootTag:rootTag]; + }); +} + +- (void)_performMountItems:(NSArray *)mountItems + rootTag:(ReactTag)rootTag +{ + RCTAssertMainQueue(); + + [self.delegate mountingManager:self willMountComponentsWithRootTag:rootTag]; + + for (id mountItem in mountItems) { + [mountItem executeWithRegistry:_componentViewRegistry]; + } + + [self.delegate mountingManager:self didMountComponentsWithRootTag:rootTag]; +} + +@end diff --git a/React/Fabric/Mounting/RCTMountingManagerDelegate.h b/React/Fabric/Mounting/RCTMountingManagerDelegate.h new file mode 100644 index 00000000000000..90ef6cecfa6ad0 --- /dev/null +++ b/React/Fabric/Mounting/RCTMountingManagerDelegate.h @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import + +NS_ASSUME_NONNULL_BEGIN + +@class RCTMountingManager; + +/** + * MountingManager's delegate. + */ +@protocol RCTMountingManagerDelegate + +/* + * Called right *before* execution of mount items which affect a Surface with + * given `rootTag`. + * Always called on the main queue. + */ +- (void)mountingManager:(RCTMountingManager *)mountingManager willMountComponentsWithRootTag:(ReactTag)MountingManager; + +/* + * Called right *after* execution of mount items which affect a Surface with + * given `rootTag`. + * Always called on the main queue. + */ +- (void)mountingManager:(RCTMountingManager *)mountingManager didMountComponentsWithRootTag:(ReactTag)rootTag; + +@end + +NS_ASSUME_NONNULL_END From 05f41931e22fd6fe849876646802c07f4cbd1b69 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 16:36:56 -0700 Subject: [PATCH 0268/1109] Fabric: Fixed YogaLayoutableShadowNode::yogaNodeCloneCallbackConnector Summary: YogaLayoutableShadowNode::yogaNodeCloneCallbackConnector recently was disabled because of change in Yoga (D7339832). This diff brings is back. Reviewed By: mdvacca Differential Revision: D7526417 fbshipit-source-id: 5369d641bf1e118132cf742d2d243bf426c0ffdb --- .../fabric/view/yoga/YogaLayoutableShadowNode.cpp | 11 ++++------- .../fabric/view/yoga/YogaLayoutableShadowNode.h | 2 +- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp index e2aa05f843a19b..62c803b2f0c1cb 100644 --- a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp +++ b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp @@ -23,9 +23,8 @@ SharedYogaConfig YogaLayoutableShadowNode::suitableYogaConfig() { static SharedYogaConfig sharedYogaConfig; if (!sharedYogaConfig) { - sharedYogaConfig = std::make_shared(YGConfig({ - // .cloneNodeCallback = YogaLayoutableShadowNode::yogaNodeCloneCallbackConnector - })); + sharedYogaConfig = std::shared_ptr(YGConfigNew()); + sharedYogaConfig->cloneNodeCallback = YogaLayoutableShadowNode::yogaNodeCloneCallbackConnector; } return sharedYogaConfig; @@ -169,7 +168,7 @@ SharedDebugStringConvertibleList YogaLayoutableShadowNode::getDebugProps() const #pragma mark - Yoga Connectors -void YogaLayoutableShadowNode::yogaNodeCloneCallbackConnector(YGNode *oldYogaNode, YGNode *newYogaNode, YGNode *parentYogaNode, int childIndex) { +YGNode *YogaLayoutableShadowNode::yogaNodeCloneCallbackConnector(YGNode *oldYogaNode, YGNode *parentYogaNode, int childIndex) { // We have only raw pointer to the parent shadow node, but that's enough for now. YogaLayoutableShadowNode *parentShadowNodeRawPtr = (YogaLayoutableShadowNode *)parentYogaNode->getContext(); assert(parentShadowNodeRawPtr); @@ -198,9 +197,7 @@ void YogaLayoutableShadowNode::yogaNodeCloneCallbackConnector(YGNode *oldYogaNod std::dynamic_pointer_cast(parentShadowNodeRawPtr->cloneAndReplaceChild(oldShadowNode)); assert(newShadowNode); - // And finally, we have to replace underline yoga node with the new one provided by Yoga. - newYogaNode->setContext((void *)newShadowNode.get()); - newShadowNode->yogaNode_ = std::shared_ptr(newYogaNode); + return newShadowNode->yogaNode_.get(); } void YogaLayoutableShadowNode::setYogaNodeChildrenBasedOnShadowNodeChildren(YGNode &yogaNode, const SharedShadowNodeSharedList &children) { diff --git a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.h b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.h index e07acc8598cf91..15f25cdf4043ec 100644 --- a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.h +++ b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.h @@ -85,7 +85,7 @@ class YogaLayoutableShadowNode: static SharedYogaConfig suitableYogaConfig(); static void setYogaNodeChildrenBasedOnShadowNodeChildren(YGNode &yogaNode, const SharedShadowNodeSharedList &children); - static void yogaNodeCloneCallbackConnector(YGNode *oldYogaNode, YGNode *newYogaNode, YGNode *parentYogaNode, int childIndex); + static YGNode *yogaNodeCloneCallbackConnector(YGNode *oldYogaNode, YGNode *parentYogaNode, int childIndex); }; } // namespace react From 00f44248b3c35c78ed4c0b67fbd8d91da8a86b41 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 16:36:59 -0700 Subject: [PATCH 0269/1109] Fabric: RCTFabricSurface as separate class Summary: RCTFabricSurface was reimplemented as separate class which does not rely on (old) RCTUIManager and delegate some functionality (which must be coordinated between Surface instances and Scheduler) to RCTSurfacePresenter. Reviewed By: mdvacca Differential Revision: D7526404 fbshipit-source-id: e8c38261bc489fd6066ba29a829cd8f623c26217 --- React/Fabric/Surface/RCTFabricSurface.h | 119 +++++++- React/Fabric/Surface/RCTFabricSurface.mm | 256 +++++++++++++++++- .../RCTFabricSurfaceHostingProxyRootView.mm | 2 +- .../Surface/RCTFabricSurfaceHostingView.mm | 6 +- 4 files changed, 369 insertions(+), 14 deletions(-) diff --git a/React/Fabric/Surface/RCTFabricSurface.h b/React/Fabric/Surface/RCTFabricSurface.h index 1672a9a86ac6b9..498fe1807c8964 100644 --- a/React/Fabric/Surface/RCTFabricSurface.h +++ b/React/Fabric/Surface/RCTFabricSurface.h @@ -5,12 +5,123 @@ * LICENSE file in the root directory of this source tree. */ -#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@class RCTBridge; +@class RCTSurfaceView; +@class RCTSurfacePresenter; +@protocol RCTSurfaceDelegate; + +/** + * (This is Fabric-compatible RCTSurface implementation.) + * + * RCTSurface instance represents React Native-powered piece of a user interface + * which can be a full-screen app, separate modal view controller, + * or even small widget. + * It is called "Surface". + * + * The RCTSurface instance is completely thread-safe by design; + * it can be created on any thread, and any its method can be called from + * any thread (if the opposite is not mentioned explicitly). + * + * The primary goals of the RCTSurface are: + * * ability to measure and layout the surface in a thread-safe + * and synchronous manner; + * * ability to create a UIView instance on demand (later); + * * ability to communicate the current stage of the surface granularly. + */ +@interface RCTFabricSurface : NSObject + +@property (atomic, readonly) RCTSurfaceStage stage; +@property (atomic, readonly) RCTBridge *bridge; +@property (atomic, readonly) NSString *moduleName; +@property (atomic, readonly) NSNumber *rootViewTag; + +@property (atomic, readwrite, weak, nullable) id delegate; + +@property (atomic, copy, readwrite) NSDictionary *properties; + +- (instancetype)initWithBridge:(RCTBridge *)bridge + moduleName:(NSString *)moduleName + initialProperties:(NSDictionary *)initialProperties; + +- (instancetype)initWithSurfacePresenter:(RCTSurfacePresenter *)surfacePresenter + moduleName:(NSString *)moduleName + initialProperties:(NSDictionary *)initialProperties; + +#pragma mark - Dealing with UIView representation, the Main thread only access /** - * Fabric-compatible RCTSurface implementation. - * It may not continue extending from RCTSurface in the future. + * Creates (if needed) and returns `UIView` instance which represents the Surface. + * The Surface will cache and *retain* this object. + * Returning the UIView instance does not mean that the Surface is ready + * to execute and layout. It can be just a handler which Surface will use later + * to mount the actual views. + * RCTSurface does not control (or influence in any way) the size or origin + * of this view. Some superview (or another owner) must use other methods + * of this class to setup proper layout and interop interactions with UIKit + * or another UI framework. + * This method must be called only from the main queue. */ -@interface RCTFabricSurface : RCTSurface +- (RCTSurfaceView *)view; + +#pragma mark - Layout: Setting the size constrains + +/** + * Sets `minimumSize` and `maximumSize` layout constraints for the Surface. + */ +- (void)setMinimumSize:(CGSize)minimumSize + maximumSize:(CGSize)maximumSize; + +/** + * Previously set `minimumSize` layout constraint. + * Defaults to `{0, 0}`. + */ +@property (atomic, assign, readonly) CGSize minimumSize; + +/** + * Previously set `maximumSize` layout constraint. + * Defaults to `{CGFLOAT_MAX, CGFLOAT_MAX}`. + */ +@property (atomic, assign, readonly) CGSize maximumSize; + +/** + * Simple shortcut to `-[RCTSurface setMinimumSize:size maximumSize:size]`. + */ +- (void)setSize:(CGSize)size; + +#pragma mark - Layout: Measuring + +/** + * Measures the Surface with given constraints. + * This method does not cause any side effects on the surface object. + */ +- (CGSize)sizeThatFitsMinimumSize:(CGSize)minimumSize + maximumSize:(CGSize)maximumSize; + +/** + * Return the current size of the root view based on (but not clamp by) current + * size constraints. + */ +@property (atomic, assign, readonly) CGSize intrinsicSize; + +#pragma mark - Synchronous waiting + +/** + * Synchronously blocks the current thread up to given `timeout` until + * the Surface reaches `stage`. + * NOT SUPPORTED IN FABRIC YET. + */ +- (BOOL)synchronouslyWaitForStage:(RCTSurfaceStage)stage timeout:(NSTimeInterval)timeout; @end + +@interface RCTFabricSurface (Internal) + +- (void)_setStage:(RCTSurfaceStage)stage; + +@end + +NS_ASSUME_NONNULL_END diff --git a/React/Fabric/Surface/RCTFabricSurface.mm b/React/Fabric/Surface/RCTFabricSurface.mm index bcdaac13129e94..babdc28c7c3d40 100644 --- a/React/Fabric/Surface/RCTFabricSurface.mm +++ b/React/Fabric/Surface/RCTFabricSurface.mm @@ -7,16 +7,260 @@ #import "RCTFabricSurface.h" +#import + +#import +#import + +#import #import +#import +#import +#import +#import +#import +#import + +#import "RCTSurfacePresenter.h" +#import "RCTMountingManager.h" + +@implementation RCTFabricSurface { + // Immutable + RCTSurfacePresenter *_surfacePresenter; + NSString *_moduleName; + ReactTag _rootTag; + + // Protected by the `_mutex` + std::mutex _mutex; + RCTSurfaceStage _stage; + NSDictionary *_properties; + CGSize _minimumSize; + CGSize _maximumSize; + CGSize _intrinsicSize; + + // The Main thread only + RCTSurfaceView *_Nullable _view; + RCTTouchHandler *_Nullable _touchHandler; +} + +- (instancetype)initWithBridge:(RCTBridge *)bridge + moduleName:(NSString *)moduleName + initialProperties:(NSDictionary *)initialProperties +{ + RCTAssert(bridge.valid, @"Valid bridge is required to instanciate `RCTSurface`."); + + self = [self initWithSurfacePresenter:bridge.surfacePresenter + moduleName:moduleName + initialProperties:initialProperties]; + + return self; +} + +- (instancetype)initWithSurfacePresenter:(RCTSurfacePresenter *)surfacePresenter + moduleName:(NSString *)moduleName + initialProperties:(NSDictionary *)initialProperties +{ + + if (self = [super init]) { + _surfacePresenter = surfacePresenter; + _moduleName = moduleName; + _properties = [initialProperties copy]; + _rootTag = [RCTAllocateRootViewTag() integerValue]; + + _minimumSize = CGSizeZero; + _maximumSize = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX); + + _stage = RCTSurfaceStageSurfaceDidInitialize; + + [self _run]; + } + + return self; +} + +- (void)dealloc +{ + [self _stop]; +} + +#pragma mark - Immutable Properties (no need to enforce synchonization) + +- (NSString *)moduleName +{ + return _moduleName; +} + +- (NSNumber *)rootViewTag +{ + return @(_rootTag); +} + +#pragma mark - Main-Threaded Routines + +- (RCTSurfaceView *)view +{ + RCTAssertMainQueue(); + + if (!_view) { + _view = [[RCTSurfaceView alloc] initWithSurface:(RCTSurface *)self]; + } + + return _view; +} + +#pragma mark - Stage management + +- (RCTSurfaceStage)stage +{ + std::lock_guard lock(_mutex); + return _stage; +} + +- (void)_setStage:(RCTSurfaceStage)stage +{ + RCTSurfaceStage updatedStage; + { + std::lock_guard lock(_mutex); + + if (_stage & stage) { + return; + } + + updatedStage = (RCTSurfaceStage)(_stage | stage); + _stage = updatedStage; + } + + [self _propagateStageChange:updatedStage]; +} + +- (void)_propagateStageChange:(RCTSurfaceStage)stage +{ + // Updating the `view` + RCTExecuteOnMainQueue(^{ + self->_view.stage = stage; + }); + + // Notifying the `delegate` + id delegate = self.delegate; + if ([delegate respondsToSelector:@selector(surface:didChangeStage:)]) { + [delegate surface:(RCTSurface *)self didChangeStage:stage]; + } +} + +#pragma mark - Properties Management + +- (NSDictionary *)properties +{ + std::lock_guard lock(_mutex); + return _properties; +} + +- (void)setProperties:(NSDictionary *)properties +{ + { + std::lock_guard lock(_mutex); + + if ([properties isEqualToDictionary:_properties]) { + return; + } + + _properties = [properties copy]; + } + + [self _run]; +} + +#pragma mark - Running + +- (void)_run +{ + [_surfacePresenter registerSurface:self]; + [self _setStage:RCTSurfaceStageSurfaceDidRun]; +} + +- (void)_stop +{ + [_surfacePresenter unregisterSurface:self]; + [self _setStage:RCTSurfaceStageSurfaceDidStop]; +} + +#pragma mark - Layout + +- (CGSize)sizeThatFitsMinimumSize:(CGSize)minimumSize + maximumSize:(CGSize)maximumSize +{ + // TODO: Not supported yet. + return CGSizeZero; +} + +#pragma mark - Size Constraints + +- (void)setSize:(CGSize)size +{ + [self setMinimumSize:size maximumSize:size]; +} + +- (void)setMinimumSize:(CGSize)minimumSize + maximumSize:(CGSize)maximumSize +{ + { + std::lock_guard lock(_mutex); + if (CGSizeEqualToSize(minimumSize, _minimumSize) && + CGSizeEqualToSize(maximumSize, _maximumSize)) { + return; + } + + _maximumSize = maximumSize; + _minimumSize = minimumSize; + } + + // TODO: Not supported yet. +} + +- (CGSize)minimumSize +{ + std::lock_guard lock(_mutex); + return _minimumSize; +} + +- (CGSize)maximumSize +{ + std::lock_guard lock(_mutex); + return _maximumSize; +} + +#pragma mark - intrinsicSize + +- (void)setIntrinsicSize:(CGSize)intrinsicSize +{ + { + std::lock_guard lock(_mutex); + if (CGSizeEqualToSize(intrinsicSize, _intrinsicSize)) { + return; + } + + _intrinsicSize = intrinsicSize; + } + + // Notifying `delegate` + id delegate = self.delegate; + if ([delegate respondsToSelector:@selector(surface:didChangeIntrinsicSize:)]) { + [delegate surface:(RCTSurface *)(id)self didChangeIntrinsicSize:intrinsicSize]; + } +} + +- (CGSize)intrinsicSize +{ + std::lock_guard lock(_mutex); + return _intrinsicSize; +} -@implementation RCTFabricSurface +#pragma mark - Synchronous Waiting -- (void)unmountReactComponentWithBridge:(RCTBridge *)bridge rootViewTag:(NSNumber *)rootViewTag +- (BOOL)synchronouslyWaitForStage:(RCTSurfaceStage)stage timeout:(NSTimeInterval)timeout { - [bridge enqueueJSCall:@"ReactFabric" - method:@"unmountComponentAtNodeAndRemoveContainer" - args:@[rootViewTag] - completion:NULL]; + // TODO: Not supported yet. + return NO; } @end diff --git a/React/Fabric/Surface/RCTFabricSurfaceHostingProxyRootView.mm b/React/Fabric/Surface/RCTFabricSurfaceHostingProxyRootView.mm index 159a63c865e444..e2210daf8cd238 100644 --- a/React/Fabric/Surface/RCTFabricSurfaceHostingProxyRootView.mm +++ b/React/Fabric/Surface/RCTFabricSurfaceHostingProxyRootView.mm @@ -13,7 +13,7 @@ @implementation RCTFabricSurfaceHostingProxyRootView - (RCTSurface *)createSurfaceWithBridge:(RCTBridge *)bridge moduleName:(NSString *)moduleName initialProperties:(NSDictionary *)initialProperties { - return [[RCTFabricSurface alloc] initWithBridge:bridge moduleName:moduleName initialProperties:initialProperties]; + return (RCTSurface *)[[RCTFabricSurface alloc] initWithBridge:bridge moduleName:moduleName initialProperties:initialProperties]; } @end diff --git a/React/Fabric/Surface/RCTFabricSurfaceHostingView.mm b/React/Fabric/Surface/RCTFabricSurfaceHostingView.mm index eec159cceb9236..0157c974b3fd74 100644 --- a/React/Fabric/Surface/RCTFabricSurfaceHostingView.mm +++ b/React/Fabric/Surface/RCTFabricSurfaceHostingView.mm @@ -16,9 +16,9 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge initialProperties:(NSDictionary *)initialProperties sizeMeasureMode:(RCTSurfaceSizeMeasureMode)sizeMeasureMode { - RCTFabricSurface *surface = [[RCTFabricSurface alloc] initWithBridge:bridge - moduleName:moduleName - initialProperties:initialProperties]; + RCTSurface *surface = (RCTSurface *)[[RCTFabricSurface alloc] initWithBridge:bridge + moduleName:moduleName + initialProperties:initialProperties]; return [self initWithSurface:surface sizeMeasureMode:sizeMeasureMode]; } From 515d49ed1c144c5827107dda3a2210a4d343cd1d Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 16:37:01 -0700 Subject: [PATCH 0270/1109] Fabric: Introducing RCTScheduler Summary: RCTScheduler represent facebook::react::Scheduler as a Obejctive-C object. It supposed to be single, unified, bidirectional interop layer between C++ and Obejctive-C worlds. Reviewed By: mdvacca Differential Revision: D7526405 fbshipit-source-id: a206755f64f2904981b356a40e7659922b24d7bb --- React/Fabric/RCTScheduler.h | 49 ++++++++++++++++++++++++ React/Fabric/RCTScheduler.mm | 73 ++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 React/Fabric/RCTScheduler.h create mode 100644 React/Fabric/RCTScheduler.mm diff --git a/React/Fabric/RCTScheduler.h b/React/Fabric/RCTScheduler.h new file mode 100644 index 00000000000000..1f1e367060f506 --- /dev/null +++ b/React/Fabric/RCTScheduler.h @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import +#import + +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@class RCTMountingManager; + +/** + * Exacly same semantic as `facebook::react::SchedulerDelegate`. + */ +@protocol RCTSchedulerDelegate + +- (void)schedulerDidComputeMutationInstructions:(facebook::react::TreeMutationInstructionList)instructions rootTag:(ReactTag)rootTag; + +- (void)schedulerDidRequestPreliminaryViewAllocationWithComponentName:(NSString *)componentName; + +@end + +/** + * `facebook::react::Scheduler` as an Objective-C class. + */ +@interface RCTScheduler : NSObject + +@property (atomic, weak, nullable) id delegate; + +- (void)registerRootTag:(ReactTag)tag; + +- (void)unregisterRootTag:(ReactTag)tag; + +@end + +@interface RCTScheduler (Deprecated) + +- (std::shared_ptr)uiManager_DO_NOT_USE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/React/Fabric/RCTScheduler.mm b/React/Fabric/RCTScheduler.mm new file mode 100644 index 00000000000000..0fe06175ee4dbc --- /dev/null +++ b/React/Fabric/RCTScheduler.mm @@ -0,0 +1,73 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTScheduler.h" + +#import +#import + +using namespace facebook::react; + +class SchedulerDelegateProxy: public SchedulerDelegate { +public: + SchedulerDelegateProxy(void *scheduler): scheduler_(scheduler) {} + + void schedulerDidComputeMutationInstructions(Tag rootTag, const TreeMutationInstructionList &instructions) override { + RCTScheduler *scheduler = (__bridge RCTScheduler *)scheduler_; + [scheduler.delegate schedulerDidComputeMutationInstructions:instructions rootTag:rootTag]; + } + + void schedulerDidRequestPreliminaryViewAllocation(ComponentName componentName) override { + RCTScheduler *scheduler = (__bridge RCTScheduler *)scheduler_; + [scheduler.delegate schedulerDidRequestPreliminaryViewAllocationWithComponentName:[NSString stringWithCString:componentName.c_str() encoding:NSASCIIStringEncoding]]; + } + +private: + void *scheduler_; +}; + +@implementation RCTScheduler { + std::shared_ptr _scheduler; + std::shared_ptr _delegateProxy; +} + +- (instancetype)init +{ + if (self = [super init]) { + _delegateProxy = std::make_shared((__bridge void *)self); + _scheduler = std::make_shared(); + _scheduler->setDelegate(_delegateProxy.get()); + } + + return self; +} + +- (void)dealloc +{ + _scheduler->setDelegate(nullptr); +} + +- (void)registerRootTag:(ReactTag)tag +{ + _scheduler->registerRootTag(tag); +} + +- (void)unregisterRootTag:(ReactTag)tag +{ + _scheduler->unregisterRootTag(tag); +} + +@end + +@implementation RCTScheduler (Deprecated) + +- (std::shared_ptr)uiManager_DO_NOT_USE +{ + return _scheduler->getUIManager_DO_NOT_USE(); +} + +@end From ab5859b44b2ad3998625d42088943362167ae276 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 16:37:04 -0700 Subject: [PATCH 0271/1109] Fabric: Introducing RCTSurfaceRegistry Summary: Simple incapsulation of thread-safe weak set of Surface instances. Reviewed By: mdvacca Differential Revision: D7526409 fbshipit-source-id: 8dd789fd6148af3dacf74aac2125b022d11a0fdb --- React/Fabric/RCTSurfaceRegistry.h | 43 ++++++++++++++++++++++++ React/Fabric/RCTSurfaceRegistry.mm | 52 ++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 React/Fabric/RCTSurfaceRegistry.h create mode 100644 React/Fabric/RCTSurfaceRegistry.mm diff --git a/React/Fabric/RCTSurfaceRegistry.h b/React/Fabric/RCTSurfaceRegistry.h new file mode 100644 index 00000000000000..013d70f4895569 --- /dev/null +++ b/React/Fabric/RCTSurfaceRegistry.h @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import + +NS_ASSUME_NONNULL_BEGIN + +@class RCTFabricSurface; + +/** + * Registry of Surfaces. + * Incapsulates storing Surface objects and quering them by root tag. + * All methods of the registry are thread-safe. + * The registry stores Surface objects as weak refereces. + */ +@interface RCTSurfaceRegistry : NSObject + +/** + * Adds Surface object into the registry. + * The registry does not retain Surface references. + */ +- (void)registerSurface:(RCTFabricSurface *)surface; + +/** + * Removes Surface object from the registry. + */ +- (void)unregisterSurface:(RCTFabricSurface *)surface; + +/** + * Returns stored Surface object by given root tag. + * If the registry does not have such Surface registred, returns `nil`. + */ +- (nullable RCTFabricSurface *)surfaceForRootTag:(ReactTag)rootTag; + +@end + +NS_ASSUME_NONNULL_END diff --git a/React/Fabric/RCTSurfaceRegistry.mm b/React/Fabric/RCTSurfaceRegistry.mm new file mode 100644 index 00000000000000..d2aa3bde42d56a --- /dev/null +++ b/React/Fabric/RCTSurfaceRegistry.mm @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTSurfaceRegistry.h" + +#import + +#import + +@implementation RCTSurfaceRegistry { + std::mutex _mutex; + NSMapTable *_registry; +} + +- (instancetype)init +{ + if (self = [super init]) { + _registry = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsIntegerPersonality | NSPointerFunctionsOpaqueMemory + valueOptions:NSPointerFunctionsObjectPersonality]; + } + + return self; +} + +- (void)registerSurface:(RCTFabricSurface *)surface +{ + std::lock_guard lock(_mutex); + + ReactTag rootTag = surface.rootViewTag.integerValue; + [_registry setObject:surface forKey:(__bridge id)(void *)rootTag]; +} + +- (void)unregisterSurface:(RCTFabricSurface *)surface +{ + std::lock_guard lock(_mutex); + + ReactTag rootTag = surface.rootViewTag.integerValue; + [_registry removeObjectForKey:(__bridge id)(void *)rootTag]; +} + +- (RCTFabricSurface *)surfaceForRootTag:(ReactTag)rootTag +{ + std::lock_guard lock(_mutex); + + return [_registry objectForKey:(__bridge id)(void *)rootTag]; +} + +@end From cf036ee2fafac646662bcb7913e8b99ba90e0a4e Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 16:37:06 -0700 Subject: [PATCH 0272/1109] Fabric: Introducing RCTSurfacePresenter Summary: RCTSurfacePresenter coordinates presenting of React Native Surfaces and represents application-facing interface of running React Native core. SurfacePresenter incapsulates a bridge object inside and discourages direct access to it. Reviewed By: mdvacca Differential Revision: D7526413 fbshipit-source-id: 9b6c513ec63a84d8b6c0951458cbd6b47f49669b --- React/Fabric/RCTSurfacePresenter.h | 60 +++++++++++ React/Fabric/RCTSurfacePresenter.mm | 154 ++++++++++++++++++++++++++++ 2 files changed, 214 insertions(+) create mode 100644 React/Fabric/RCTSurfacePresenter.h create mode 100644 React/Fabric/RCTSurfacePresenter.mm diff --git a/React/Fabric/RCTSurfacePresenter.h b/React/Fabric/RCTSurfacePresenter.h new file mode 100644 index 00000000000000..d99133d59a91c8 --- /dev/null +++ b/React/Fabric/RCTSurfacePresenter.h @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import +#import + +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@class RCTFabricSurface; +@class RCTMountingManager; + +/** + * Coordinates presenting of React Native Surfaces and represents application + * facing interface of running React Native core. + * SurfacePresenter incapsulates a bridge object inside and discourage direct + * access to it. + */ +@interface RCTSurfacePresenter : NSObject + +- (instancetype)initWithBridge:(RCTBridge *)bridge; + +@end + +@interface RCTSurfacePresenter (Internal) + +/** + * Surface uses those methods to register itself in the Presenter. + * Registering initiates running, rendering and mounting processes. + */ +- (void)registerSurface:(RCTFabricSurface *)surface; +- (void)unregisterSurface:(RCTFabricSurface *)surface; + +@end + +@interface RCTSurfacePresenter (Deprecated) + +/** + * We need to expose `exceptionManager` and `uiManager` for registration + * purposes. Eventually, we will move this down to C++ side. + */ +- (std::shared_ptr)exceptionManager_DO_NOT_USE; +- (std::shared_ptr)uiManager_DO_NOT_USE; + +@end + +@interface RCTBridge (RCTSurfacePresenter) + +- (RCTSurfacePresenter *)surfacePresenter; + +@end + +NS_ASSUME_NONNULL_END diff --git a/React/Fabric/RCTSurfacePresenter.mm b/React/Fabric/RCTSurfacePresenter.mm new file mode 100644 index 00000000000000..8e88548c8d78df --- /dev/null +++ b/React/Fabric/RCTSurfacePresenter.mm @@ -0,0 +1,154 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTSurfacePresenter.h" + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +using namespace facebook::react; + +@interface RCTSurfacePresenter () +@end + +@implementation RCTSurfacePresenter { + std::shared_ptr _exceptionManager; + RCTScheduler *_scheduler; + RCTMountingManager *_mountingManager; + RCTBridge *_bridge; + RCTBridge *_batchedBridge; + RCTSurfaceRegistry *_surfaceRegistry; +} + +- (instancetype)initWithBridge:(RCTBridge *)bridge +{ + if (self = [super init]) { + _bridge = bridge; + _batchedBridge = [_bridge batchedBridge] ?: _bridge; + + _exceptionManager = std::make_shared(); + + _scheduler = [[RCTScheduler alloc] init]; + _scheduler.delegate = self; + + _surfaceRegistry = [[RCTSurfaceRegistry alloc] init]; + _mountingManager = [[RCTMountingManager alloc] init]; + _mountingManager.delegate = self; + } + + return self; +} + +- (std::shared_ptr)exceptionManager +{ + return _exceptionManager; +} + +- (void)schedulerDidComputeMutationInstructions:(facebook::react::TreeMutationInstructionList)instructions rootTag:(ReactTag)rootTag +{ + [_mountingManager mutateComponentViewTreeWithMutationInstructions:instructions + rootTag:rootTag]; +} + +- (void)schedulerDidRequestPreliminaryViewAllocationWithComponentName:(NSString *)componentName +{ + // TODO: To be implemeted. +} + +#pragma mark - Internal Surface-dedicated Interface + +- (void)registerSurface:(RCTFabricSurface *)surface +{ + [_surfaceRegistry registerSurface:surface]; + [_scheduler registerRootTag:surface.rootViewTag.integerValue]; + [self runSurface:surface]; + + // FIXME: Mutation instruction MUST produce instruction for root node. + [_mountingManager.componentViewRegistry dequeueComponentViewWithName:@"Root" tag:surface.rootViewTag.integerValue]; +} + +- (void)unregisterSurface:(RCTFabricSurface *)surface +{ + [self stopSurface:surface]; + [_scheduler unregisterRootTag:surface.rootViewTag.integerValue]; + [_surfaceRegistry unregisterSurface:surface]; +} + +- (void)runSurface:(RCTFabricSurface *)surface +{ + NSDictionary *applicationParameters = @{ + @"rootTag": surface.rootViewTag, + @"initialProps": surface.properties, + }; + + [_batchedBridge enqueueJSCall:@"AppRegistry" method:@"runApplication" args:@[surface.moduleName, applicationParameters] completion:NULL]; +} + +- (void)stopSurface:(RCTFabricSurface *)surface +{ + [_batchedBridge enqueueJSCall:@"AppRegistry" method:@"unmountApplicationComponentAtRootTag" args:@[surface.rootViewTag] completion:NULL]; +} + +#pragma mark - RCTMountingManagerDelegate + +- (void)mountingManager:(RCTMountingManager *)mountingManager willMountComponentsWithRootTag:(ReactTag)rootTag +{ + RCTIsMainQueue(); + // TODO: Propagate state change to Surface. +} + +- (void)mountingManager:(RCTMountingManager *)mountingManager didMountComponentsWithRootTag:(ReactTag)rootTag +{ + RCTIsMainQueue(); + RCTFabricSurface *surface = [_surfaceRegistry surfaceForRootTag:rootTag]; + + // FIXME: Implement proper state propagation mechanism. + [surface _setStage:RCTSurfaceStageSurfaceDidInitialRendering]; + [surface _setStage:RCTSurfaceStageSurfaceDidInitialLayout]; + [surface _setStage:RCTSurfaceStageSurfaceDidInitialMounting]; + + UIView *rootComponentView = [_mountingManager.componentViewRegistry componentViewByTag:rootTag]; + + // FIXME: Remove this. + rootComponentView.frame = CGRectMake(0, 0, 400, 400); + + surface.view.rootView = (RCTSurfaceRootView *)rootComponentView; +} + +@end + +@implementation RCTSurfacePresenter (Deprecated) + +- (std::shared_ptr)uiManager_DO_NOT_USE +{ + return _scheduler.uiManager_DO_NOT_USE; +} + +- (std::shared_ptr)exceptionManager_DO_NOT_USE +{ + return _exceptionManager; +} + +@end + +@implementation RCTBridge (RCTSurfacePresenter) + +- (RCTSurfacePresenter *)surfacePresenter +{ + return [self jsBoundExtraModuleForClass:[RCTSurfacePresenter class]]; +} + +@end From db92b16e04c2f9e807572a7fbd9fbbb26a4eeddb Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 16:37:09 -0700 Subject: [PATCH 0273/1109] Fabric: Proper invocation of `ensureunsealed` in `LayoutableShadowNode::layout` Summary: Quite obvious. We have to check `sealable` flag of the child (not a parent) before mutating it. Reviewed By: mdvacca Differential Revision: D7526407 fbshipit-source-id: ce8e0d6446ff7eb23baee9c92f246d5e198fe377 --- ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp b/ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp index 0e2652efc887d0..df967d57c15155 100644 --- a/ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp +++ b/ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp @@ -69,7 +69,7 @@ void LayoutableShadowNode::layout(LayoutContext layoutContext) { continue; } - ensureUnsealed(); + child->ensureUnsealed(); // The assumption: // All `sealed` children were replaced with not-yet-sealed clones From 568529e1ecdc12726a152ba627c552612f85a2d9 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 16:37:11 -0700 Subject: [PATCH 0274/1109] Fabric: Introducting RCTViewComponentView Summary: Implementation of the native view component of . Root View also must have dedicated class even if its empty now. Reviewed By: mdvacca Differential Revision: D7526406 fbshipit-source-id: 9e14c9f679396c2cdb2d64c99086bb19df37c25c --- React/Fabric/Mounting/RCTRootComponentView.h | 21 ++++++++++++ React/Fabric/Mounting/RCTRootComponentView.mm | 12 +++++++ React/Fabric/Mounting/RCTViewComponentView.h | 22 +++++++++++++ React/Fabric/Mounting/RCTViewComponentView.mm | 33 +++++++++++++++++++ 4 files changed, 88 insertions(+) create mode 100644 React/Fabric/Mounting/RCTRootComponentView.h create mode 100644 React/Fabric/Mounting/RCTRootComponentView.mm create mode 100644 React/Fabric/Mounting/RCTViewComponentView.h create mode 100644 React/Fabric/Mounting/RCTViewComponentView.mm diff --git a/React/Fabric/Mounting/RCTRootComponentView.h b/React/Fabric/Mounting/RCTRootComponentView.h new file mode 100644 index 00000000000000..687d4f73a72ba7 --- /dev/null +++ b/React/Fabric/Mounting/RCTRootComponentView.h @@ -0,0 +1,21 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * UIView class for root component. + */ +@interface RCTRootComponentView : RCTViewComponentView + +@end + +NS_ASSUME_NONNULL_END diff --git a/React/Fabric/Mounting/RCTRootComponentView.mm b/React/Fabric/Mounting/RCTRootComponentView.mm new file mode 100644 index 00000000000000..703c03e5ddfe5d --- /dev/null +++ b/React/Fabric/Mounting/RCTRootComponentView.mm @@ -0,0 +1,12 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTRootComponentView.h" + +@implementation RCTRootComponentView + +@end diff --git a/React/Fabric/Mounting/RCTViewComponentView.h b/React/Fabric/Mounting/RCTViewComponentView.h new file mode 100644 index 00000000000000..046030a8faa371 --- /dev/null +++ b/React/Fabric/Mounting/RCTViewComponentView.h @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * UIView class for component. + */ +@interface RCTViewComponentView : UIView + +@end + +NS_ASSUME_NONNULL_END diff --git a/React/Fabric/Mounting/RCTViewComponentView.mm b/React/Fabric/Mounting/RCTViewComponentView.mm new file mode 100644 index 00000000000000..24a98594901266 --- /dev/null +++ b/React/Fabric/Mounting/RCTViewComponentView.mm @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTViewComponentView.h" + +#import + +using namespace facebook::react; + +@implementation RCTViewComponentView + +- (void)updateProps:(facebook::react::SharedProps)props + oldProps:(facebook::react::SharedProps)oldProps +{ + if (!oldProps) { + oldProps = std::make_shared(); + } + + auto oldViewProps = *std::dynamic_pointer_cast(oldProps); + auto newViewProps = *std::dynamic_pointer_cast(props); + + if (oldViewProps.getBackgroundColor() != newViewProps.getBackgroundColor()) { + self.backgroundColor = [UIColor colorWithCGColor:newViewProps.getBackgroundColor().get()]; + } + + // TODO: Implement all sutable non-layout props. +} + +@end From dd49f9e0bc10cf3bc4cc86015823c4a7a6e297ae Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 16:37:16 -0700 Subject: [PATCH 0275/1109] Fabric: Fixed incorrect usage of `Undefined` (instead of `kFloatUndefined`) in `yogaValuesConversions` Summary: `Undefined` is actually equal `0` (becasuse it is `LayoutDirection::Undefined`), whereas `kFloatUndefined` is a magic huge number. Reviewed By: fkgozali Differential Revision: D7554550 fbshipit-source-id: 3ea37f0b8b6a59b4b0e00d205b75cd7252247d03 --- ReactCommon/fabric/view/yoga/yogaValuesConversions.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ReactCommon/fabric/view/yoga/yogaValuesConversions.cpp b/ReactCommon/fabric/view/yoga/yogaValuesConversions.cpp index e780d2cecd6fb1..05137f5e92b4f8 100644 --- a/ReactCommon/fabric/view/yoga/yogaValuesConversions.cpp +++ b/ReactCommon/fabric/view/yoga/yogaValuesConversions.cpp @@ -16,14 +16,14 @@ namespace react { Float fabricFloatFromYogaFloat(float value) { if (value == YGUndefined) { - return Undefined; + return kFloatUndefined; } return (Float)value; } float yogaFloatFromFabricFloat(Float value) { - if (value == Undefined) { + if (value == kFloatUndefined) { return YGUndefined; } From 711abeda7968311ab95bb0f4404ad53bfc008093 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 16:37:19 -0700 Subject: [PATCH 0276/1109] Fabric: Using `enum class` for some graphics types Summary: `enum class` types do not provide default conversion to integers and reguire use typename before value names. This must prevent bugs like the previous one where we used `Undefined` as a number value. Reviewed By: fkgozali Differential Revision: D7554548 fbshipit-source-id: b19379aae48c9aebe03043e08cf3acc712da3cb8 --- ReactCommon/fabric/core/layout/LayoutMetrics.h | 4 ++-- ReactCommon/fabric/core/layout/LayoutPrimitives.h | 4 ++-- ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp | 2 +- ReactCommon/fabric/view/yoga/yogaValuesConversions.cpp | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ReactCommon/fabric/core/layout/LayoutMetrics.h b/ReactCommon/fabric/core/layout/LayoutMetrics.h index 4bc2641a91bd75..22cff2d7cc1e6f 100644 --- a/ReactCommon/fabric/core/layout/LayoutMetrics.h +++ b/ReactCommon/fabric/core/layout/LayoutMetrics.h @@ -20,8 +20,8 @@ struct LayoutMetrics { Rect frame; EdgeInsets contentInsets {0}; EdgeInsets borderWidth {0}; - DisplayType displayType {Flex}; - LayoutDirection layoutDirection {Undefined}; + DisplayType displayType {DisplayType::Flex}; + LayoutDirection layoutDirection {LayoutDirection::Undefined}; bool operator ==(const LayoutMetrics& rhs) const { return diff --git a/ReactCommon/fabric/core/layout/LayoutPrimitives.h b/ReactCommon/fabric/core/layout/LayoutPrimitives.h index 0036e134e887f3..0d699aac3c6bec 100644 --- a/ReactCommon/fabric/core/layout/LayoutPrimitives.h +++ b/ReactCommon/fabric/core/layout/LayoutPrimitives.h @@ -14,7 +14,7 @@ namespace react { * Defines visibility of the shadow node and partucular layout * engine which should be used for laying out the node. */ -enum DisplayType { +enum class DisplayType { None, Flex, Inline, @@ -23,7 +23,7 @@ enum DisplayType { /* * User interface layout direction. */ -enum LayoutDirection { +enum class LayoutDirection { Undefined, LeftToRight, RightToLeft, diff --git a/ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp b/ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp index df967d57c15155..b6f9923fd0714a 100644 --- a/ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp +++ b/ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp @@ -79,7 +79,7 @@ void LayoutableShadowNode::layout(LayoutContext layoutContext) { nonConstChild->setHasNewLayout(false); const LayoutMetrics childLayoutMetrics = nonConstChild->getLayoutMetrics(); - if (childLayoutMetrics.displayType == None) { + if (childLayoutMetrics.displayType == DisplayType::None) { continue; } diff --git a/ReactCommon/fabric/view/yoga/yogaValuesConversions.cpp b/ReactCommon/fabric/view/yoga/yogaValuesConversions.cpp index 05137f5e92b4f8..f13744de757722 100644 --- a/ReactCommon/fabric/view/yoga/yogaValuesConversions.cpp +++ b/ReactCommon/fabric/view/yoga/yogaValuesConversions.cpp @@ -77,10 +77,10 @@ LayoutMetrics layoutMetricsFromYogaNode(YGNode &yogaNode) { }; layoutMetrics.displayType = - yogaNode.getStyle().display == YGDisplayNone ? None : Flex; + yogaNode.getStyle().display == YGDisplayNone ? DisplayType::None : DisplayType::Flex; layoutMetrics.layoutDirection = - layout.direction == YGDirectionRTL ? RightToLeft : LeftToRight; + layout.direction == YGDirectionRTL ? LayoutDirection::RightToLeft : LayoutDirection::LeftToRight; return layoutMetrics; } From b13d5beb11ee633509896c1d432be23f7da76117 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 16:37:22 -0700 Subject: [PATCH 0277/1109] Fabric: `LayoutableShadowNodeList::getChildren` renamed to `getLayoutableChildNodes` Summary: The previous name conflicts with the method with same (but with different semantic) name in `ShadowNode` class. That was bad idea to use same name especially because the different semantic. Reviewed By: fkgozali Differential Revision: D7554549 fbshipit-source-id: 0bccbaacd0812f8a26592b2008f15ddb5bc34ebc --- ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp | 2 +- ReactCommon/fabric/core/layout/LayoutableShadowNode.h | 2 +- ReactCommon/fabric/view/ViewShadowNode.cpp | 2 +- ReactCommon/fabric/view/ViewShadowNode.h | 2 +- ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp b/ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp index b6f9923fd0714a..3e2b4a0e8f7b6a 100644 --- a/ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp +++ b/ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp @@ -64,7 +64,7 @@ Float LayoutableShadowNode::lastBaseline(Size size) const { void LayoutableShadowNode::layout(LayoutContext layoutContext) { layoutChildren(layoutContext); - for (auto child : getChildren()) { + for (auto child : getLayoutableChildNodes()) { if (!child->getHasNewLayout()) { continue; } diff --git a/ReactCommon/fabric/core/layout/LayoutableShadowNode.h b/ReactCommon/fabric/core/layout/LayoutableShadowNode.h index e3176f1f3572ae..d1c9ce1d6a3e7f 100644 --- a/ReactCommon/fabric/core/layout/LayoutableShadowNode.h +++ b/ReactCommon/fabric/core/layout/LayoutableShadowNode.h @@ -88,7 +88,7 @@ class LayoutableShadowNode: /* * Returns layoutable children to interate on. */ - virtual SharedLayoutableShadowNodeList getChildren() const = 0; + virtual SharedLayoutableShadowNodeList getLayoutableChildNodes() const = 0; /* * In case layout algorithm needs to mutate this (probably sealed) node, diff --git a/ReactCommon/fabric/view/ViewShadowNode.cpp b/ReactCommon/fabric/view/ViewShadowNode.cpp index a51f151b92ffd1..111d220ec12d52 100644 --- a/ReactCommon/fabric/view/ViewShadowNode.cpp +++ b/ReactCommon/fabric/view/ViewShadowNode.cpp @@ -75,7 +75,7 @@ void ViewShadowNode::appendChild(const SharedShadowNode &child) { #pragma mark - YogaLayoutableShadowNode -SharedLayoutableShadowNodeList ViewShadowNode::getChildren() const { +SharedLayoutableShadowNodeList ViewShadowNode::getLayoutableChildNodes() const { SharedLayoutableShadowNodeList sharedLayoutableShadowNodeList = {}; for (auto child : *children_) { const SharedLayoutableShadowNode layoutableShadowNode = std::dynamic_pointer_cast(child); diff --git a/ReactCommon/fabric/view/ViewShadowNode.h b/ReactCommon/fabric/view/ViewShadowNode.h index b80a138fd444f0..230aad5694fe4e 100644 --- a/ReactCommon/fabric/view/ViewShadowNode.h +++ b/ReactCommon/fabric/view/ViewShadowNode.h @@ -60,7 +60,7 @@ class ViewShadowNode: #pragma mark - LayoutableShadowNode - SharedLayoutableShadowNodeList getChildren() const override; + SharedLayoutableShadowNodeList getLayoutableChildNodes() const override; SharedLayoutableShadowNode cloneAndReplaceChild(const SharedLayoutableShadowNode &child) override; }; diff --git a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp index 62c803b2f0c1cb..2851fa4d985b64 100644 --- a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp +++ b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp @@ -114,7 +114,7 @@ void YogaLayoutableShadowNode::layout(LayoutContext layoutContext) { } void YogaLayoutableShadowNode::layoutChildren(LayoutContext layoutContext) { - for (auto child : getChildren()) { + for (auto child : getLayoutableChildNodes()) { auto yogaLayoutableChild = std::dynamic_pointer_cast(child); if (!yogaLayoutableChild) { continue; @@ -183,7 +183,7 @@ YGNode *YogaLayoutableShadowNode::yogaNodeCloneCallbackConnector(YGNode *oldYoga // * Create a new `shared_ptr` with empty deleter. // * Using `childIndex` to find exact node. SharedLayoutableShadowNode oldShadowNode = nullptr; - for (auto child : parentShadowNodeRawPtr->getChildren()) { + for (auto child : parentShadowNodeRawPtr->getLayoutableChildNodes()) { if (child.get() == oldShadowNodeRawPtr) { oldShadowNode = child; break; From 6924d44b201b9f91e6c8672f053d9a5ad9352358 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 10 Apr 2018 16:37:24 -0700 Subject: [PATCH 0278/1109] Fabric: Fixed ConcreteShadowNode::getProps() Summary: Apparently, there is no point to return a reference from this method because the struct (std::shared_ptr) is allocated on stack. The test is also updated. allow-large-files Reviewed By: fkgozali Differential Revision: D7557749 fbshipit-source-id: aa74146322c6d340256752586f05fc672024038e --- ReactCommon/fabric/core/shadownode/ConcreteShadowNode.h | 2 +- ReactCommon/fabric/core/tests/ShadowNodeTest.cpp | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/ReactCommon/fabric/core/shadownode/ConcreteShadowNode.h b/ReactCommon/fabric/core/shadownode/ConcreteShadowNode.h index c9f2741762c51c..278d448708c886 100644 --- a/ReactCommon/fabric/core/shadownode/ConcreteShadowNode.h +++ b/ReactCommon/fabric/core/shadownode/ConcreteShadowNode.h @@ -76,7 +76,7 @@ class ConcreteShadowNode: public ShadowNode { return typeid(*this).hash_code(); } - const SharedConcreteProps &getProps() const { + const SharedConcreteProps getProps() const { return std::static_pointer_cast(props_); } diff --git a/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp b/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp index c14fda2003dd70..168cf48869850f 100644 --- a/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp +++ b/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp @@ -41,14 +41,11 @@ TEST(ShadowNodeTest, handleShadowNodeCreation) { ASSERT_EQ(node->getSourceNode(), nullptr); ASSERT_EQ(node->getChildren()->size(), 0); - // TODO(#27369757): getProps() doesn't work - // ASSERT_STREQ(node->getProps()->getNativeId().c_str(), "testNativeID"); + ASSERT_STREQ(node->getProps()->getNativeId().c_str(), "testNativeID"); node->sealRecursive(); ASSERT_TRUE(node->getSealed()); - - // TODO(#27369757): verify Props are also sealed. - // ASSERT_TRUE(node->getProps()->getSealed()); + ASSERT_TRUE(node->getProps()->getSealed()); } TEST(ShadowNodeTest, handleShadowNodeSimpleCloning) { From edd22bf49de6954ea0f57c009f563ae25d22db28 Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Tue, 10 Apr 2018 19:23:07 -0700 Subject: [PATCH 0279/1109] Log bridge description for e2e reloads Reviewed By: mhorowitz Differential Revision: D7577953 fbshipit-source-id: 96871c664cb7ec84570bc76f2edb36ff8c8c6aeb --- React/Base/RCTBridge.h | 6 ++++++ React/Base/RCTBridge.m | 1 + React/CxxBridge/RCTCxxBridge.mm | 6 +++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/React/Base/RCTBridge.h b/React/Base/RCTBridge.h index 2a7eabe5ce84ba..5222a15b5ca714 100644 --- a/React/Base/RCTBridge.h +++ b/React/Base/RCTBridge.h @@ -72,6 +72,12 @@ RCT_EXTERN NSString *const RCTBridgeDidDownloadScriptNotification; */ RCT_EXTERN NSString *const RCTBridgeDidDownloadScriptNotificationSourceKey; +/** + * Key for the bridge description (NSString_ in the + * RCTBridgeDidDownloadScriptNotification userInfo dictionary. + */ +RCT_EXTERN NSString *const RCTBridgeDidDownloadScriptNotificationBridgeDescriptionKey; + /** * This block can be used to instantiate modules that require additional * init parameters, or additional configuration prior to being used. diff --git a/React/Base/RCTBridge.m b/React/Base/RCTBridge.m index 76f2d17a203faf..4f85966d971269 100644 --- a/React/Base/RCTBridge.m +++ b/React/Base/RCTBridge.m @@ -31,6 +31,7 @@ NSString *const RCTBridgeWillDownloadScriptNotification = @"RCTBridgeWillDownloadScriptNotification"; NSString *const RCTBridgeDidDownloadScriptNotification = @"RCTBridgeDidDownloadScriptNotification"; NSString *const RCTBridgeDidDownloadScriptNotificationSourceKey = @"source"; +NSString *const RCTBridgeDidDownloadScriptNotificationBridgeDescriptionKey = @"bridgeDescription"; static NSMutableArray *RCTModuleClasses; NSArray *RCTGetModuleClasses(void) diff --git a/React/CxxBridge/RCTCxxBridge.mm b/React/CxxBridge/RCTCxxBridge.mm index 7411dcdcc61394..cd82c3ccd85aaa 100644 --- a/React/CxxBridge/RCTCxxBridge.mm +++ b/React/CxxBridge/RCTCxxBridge.mm @@ -400,7 +400,11 @@ - (void)loadSource:(RCTSourceLoadBlock)_onSourceLoad onProgress:(RCTSourceLoadPr [performanceLogger markStopForTag:RCTPLScriptDownload]; [performanceLogger setValue:source.length forTag:RCTPLBundleSize]; - NSDictionary *userInfo = source ? @{ RCTBridgeDidDownloadScriptNotificationSourceKey: source } : nil; + NSDictionary *userInfo = @{ + RCTBridgeDidDownloadScriptNotificationSourceKey: source ?: [NSNull null], + RCTBridgeDidDownloadScriptNotificationBridgeDescriptionKey: self->_bridgeDescription ?: [NSNull null], + }; + [center postNotificationName:RCTBridgeDidDownloadScriptNotification object:self->_parentBridge userInfo:userInfo]; _onSourceLoad(error, source); From 80fc415cf179ffe26d020bc8d6e4451352da94fd Mon Sep 17 00:00:00 2001 From: Manuel Alabor Date: Tue, 10 Apr 2018 19:47:21 -0700 Subject: [PATCH 0280/1109] Expose InputAccessoryView Module Summary: The latest release of react-native (0.55.2) does not expose the new `InputAccessoryView` component; It can't be accessed at all. This change fixes this problem. * Problem: Snack showing the problem: https://snack.expo.io/B1fDQRYif * Proof: `RNTester` still works with adapted imports No related PRs. [IOS] [BUGFIX] [InputAccessoryView] - Expose `InputAccessoryView` so it can be imported Closes https://github.com/facebook/react-native/pull/18780 Differential Revision: D7581729 Pulled By: hramos fbshipit-source-id: d61ab1f167360e829e32b93fb5414d2f7e57e115 --- .../react-native-implementation.js | 1 + RNTester/js/InputAccessoryViewExample.js | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index 200409bcbc041b..e3b19adc459c80 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -26,6 +26,7 @@ const ReactNative = { get ImageBackground() { return require('ImageBackground'); }, get ImageEditor() { return require('ImageEditor'); }, get ImageStore() { return require('ImageStore'); }, + get InputAccessoryView() { return require('InputAccessoryView') }, get KeyboardAvoidingView() { return require('KeyboardAvoidingView'); }, get ListView() { return require('ListView'); }, get MaskedViewIOS() { return require('MaskedViewIOS'); }, diff --git a/RNTester/js/InputAccessoryViewExample.js b/RNTester/js/InputAccessoryViewExample.js index 7ebcf5f0090ac4..9287fb7e1e6833 100644 --- a/RNTester/js/InputAccessoryViewExample.js +++ b/RNTester/js/InputAccessoryViewExample.js @@ -11,15 +11,18 @@ 'use strict'; -const Alert = require('Alert'); -const Button = require('Button'); -const InputAccessoryView = require('InputAccessoryView'); const React = require('React'); -const ScrollView = require('ScrollView'); -const StyleSheet = require('StyleSheet'); -const Text = require('Text'); -const TextInput = require('TextInput'); -const View = require('View'); +const ReactNative = require('react-native'); +const { + Alert, + Button, + InputAccessoryView, + ScrollView, + StyleSheet, + Text, + TextInput, + View, +} = ReactNative; class Message extends React.PureComponent<*> { render() { From ebd12fa09fca8c9cee4a48e3f1652986d51fcdb3 Mon Sep 17 00:00:00 2001 From: Peter van der Zee Date: Tue, 10 Apr 2018 20:58:22 -0700 Subject: [PATCH 0281/1109] BREAKING CHANGE: UPGRADE REACT NATIVE TO BABEL 7! Summary: BREAKING CHANGE This change upgrades the React Native build pipeline from Babel 6 to Babel 7 If you use a `.babelrc` then you'll need to update it to Babel 7 (note that some plugins are no longer relevant, some plugins are automatically upgraded, and some will need some manual love). Note that you may also need to upgrade your dev env, tests etc, to make sure they work with Babel 7. Reviewed By: cpojer Differential Revision: D7097279 fbshipit-source-id: 9fb204cae733174a1c155669b7c17ddb70f7aecc --- Libraries/polyfills/babelHelpers.js | 220 ++++++++++++++++++---------- babel-preset/configs/main.js | 78 +++++----- jest/preprocessor.js | 47 +++++- 3 files changed, 233 insertions(+), 112 deletions(-) diff --git a/Libraries/polyfills/babelHelpers.js b/Libraries/polyfills/babelHelpers.js index dfe819464f09c4..7d251ea347489b 100644 --- a/Libraries/polyfills/babelHelpers.js +++ b/Libraries/polyfills/babelHelpers.js @@ -12,19 +12,15 @@ /* eslint-disable quotes, curly, no-proto, no-undef-init, dot-notation */ // Created by running: -// require('babel-core').buildExternalHelpers('_extends classCallCheck createClass createRawReactElement defineProperty get inherits interopRequireDefault interopRequireWildcard objectWithoutProperties possibleConstructorReturn slicedToArray taggedTemplateLiteral toArray toConsumableArray '.split(' ')) -// then replacing the `global` reference in the last line to also use `this`. +// require('fs').writeFileSync('babelExternalHelpers.js', require('@babel/core').buildExternalHelpers('_extends classCallCheck createClass createRawReactElement defineProperty get inherits interopRequireDefault interopRequireWildcard objectWithoutProperties possibleConstructorReturn slicedToArray taggedTemplateLiteral toArray toConsumableArray wrapNativeSuper assertThisInitialized taggedTemplateLiteralLoose'.split(' ')))// then replacing the `global` reference in the last line to also use `this`. // -// actually, that's a lie, because babel6 omits _extends and createRawReactElement +// Actually, that's a lie, because babel omits _extends and +// createRawReactElement. the file is also cleaned up a bit. +// You may need to clear wrapNativeSuper while the bug hasn't been fixed yet. +// Do try to keep diffs to a minimum. var babelHelpers = global.babelHelpers = {}; -babelHelpers.typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { - return typeof obj; -} : function (obj) { - return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; -}; - babelHelpers.createRawReactElement = (function () { var REACT_ELEMENT_TYPE = typeof Symbol === "function" && Symbol.for && Symbol.for("react.element") || 0xeac7; return function createRawReactElement(type, key, props) { @@ -45,32 +41,20 @@ babelHelpers.classCallCheck = function (instance, Constructor) { } }; -babelHelpers.createClass = (function () { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || false; - descriptor.configurable = true; - if ("value" in descriptor) descriptor.writable = true; - Object.defineProperty(target, descriptor.key, descriptor); - } +function _defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); } +} - return function (Constructor, protoProps, staticProps) { - if (protoProps) defineProperties(Constructor.prototype, protoProps); - if (staticProps) defineProperties(Constructor, staticProps); - return Constructor; - }; -})(); - -babelHelpers.defineEnumerableProperties = function(obj, descs) { - for (var key in descs) { - var desc = descs[key]; - desc.configurable = (desc.enumerable = true); - if ('value' in desc) desc.writable = true; - Object.defineProperty(obj, key, desc); - } - return obj; +babelHelpers.createClass = function(Constructor, protoProps, staticProps) { + if (protoProps) _defineProperties(Constructor.prototype, protoProps); + if (staticProps) _defineProperties(Constructor, staticProps); + return Constructor; }; babelHelpers.defineProperty = function (obj, key, value) { @@ -129,9 +113,8 @@ babelHelpers.get = function get(object, property, receiver) { babelHelpers.inherits = function (subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { - throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); + throw new TypeError("Super expression must either be null or a function"); } - subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, @@ -143,6 +126,54 @@ babelHelpers.inherits = function (subClass, superClass) { if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }; +var _gPO = Object.getPrototypeOf || function _gPO(o) { return o.__proto__ }; +var _sPO = Object.setPrototypeOf || function _sPO(o, p) { o.__proto__ = p; return o }; +var _construct = +// TODO: prepack does not like this line (and we can use the fallback just fine) +// (typeof Reflect === "object" && Reflect.construct) || + function _construct(Parent, args, Class) { + var Constructor, a = [null]; + a.push.apply(a, args); + Constructor = Parent.bind.apply(Parent, a); + return _sPO(new Constructor, Class.prototype); + }; +var _cache = typeof Map === "function" && new Map(); +babelHelpers.wrapNativeSuper = function(Class) { + // FB: + // Note: while extending native classes is pretty meh we do have cases, for + // example; Error. There is also a false positive, for example; Blob. + + if (typeof Class !== "function") { + throw new TypeError("Super expression must either be null or a function"); + } + if (typeof _cache !== "undefined") { + if (_cache.has(Class)) return _cache.get(Class); + _cache.set(Class, Wrapper); + } + function Wrapper() { + // this is a temporary fix for a babel bug (it's invoking the wrong func + // when you do `super()`) + return _construct(Class, arguments, _gPO(this).constructor); + } + Wrapper.prototype = Object.create(Class.prototype, { + constructor: { + value: Wrapper, + enumerable: false, + writeable: true, + configurable: true, + } + }); + return _sPO( + Wrapper, + _sPO( + function Super() { + return _construct(Class, arguments, _gPO(this).constructor); + }, + Class + ) + ); +}; + babelHelpers.interopRequireDefault = function (obj) { return obj && obj.__esModule ? obj : { default: obj @@ -157,7 +188,15 @@ babelHelpers.interopRequireWildcard = function (obj) { if (obj != null) { for (var key in obj) { - if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; + if (Object.prototype.hasOwnProperty.call(obj, key)) { + var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; + + if (desc.get || desc.set) { + Object.defineProperty(newObj, key, desc); + } else { + newObj[key] = obj[key]; + } + } } } @@ -166,63 +205,79 @@ babelHelpers.interopRequireWildcard = function (obj) { } }; -babelHelpers.objectWithoutProperties = function (obj, keys) { +babelHelpers.objectWithoutProperties = function(source, excluded) { + if (source == null) return {}; var target = {}; + var sourceKeys = Object.keys(source); + var key, i; + + for (i = 0; i < sourceKeys.length; i++) { + key = sourceKeys[i]; + if (excluded.indexOf(key) >= 0) continue; + target[key] = source[key]; + } + + if (Object.getOwnPropertySymbols) { + var sourceSymbolKeys = Object.getOwnPropertySymbols(source); - for (var i in obj) { - if (keys.indexOf(i) >= 0) continue; - if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; - target[i] = obj[i]; + for (i = 0; i < sourceSymbolKeys.length; i++) { + key = sourceSymbolKeys[i]; + if (excluded.indexOf(key) >= 0) continue; + if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; + target[key] = source[key]; + } } return target; }; babelHelpers.possibleConstructorReturn = function (self, call) { - if (!self) { + if (call && (typeof call === "object" || typeof call === "function")) { + return call; + } + + if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } - return call && (typeof call === "object" || typeof call === "function") ? call : self; + return self; }; -babelHelpers.slicedToArray = (function () { - function sliceIterator(arr, i) { - var _arr = []; - var _n = true; - var _d = false; - var _e = undefined; +function _sliceIterator(arr, i) { + var _arr = []; + var _n = true; + var _d = false; + var _e = undefined; - try { - for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { - _arr.push(_s.value); + try { + for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); - if (i && _arr.length === i) break; - } - } catch (err) { - _d = true; - _e = err; + if (i && _arr.length === i) break; + } + } catch (err) { + _d = true; + _e = err; + } finally { + try { + if (!_n && _i["return"] != null) _i["return"](); } finally { - try { - if (!_n && _i["return"]) _i["return"](); - } finally { - if (_d) throw _e; - } + if (_d) throw _e; } - - return _arr; } - return function (arr, i) { - if (Array.isArray(arr)) { - return arr; - } else if (Symbol.iterator in Object(arr)) { - return sliceIterator(arr, i); - } else { - throw new TypeError("Invalid attempt to destructure non-iterable instance"); - } - }; -})(); + return _arr; +} + +babelHelpers.slicedToArray = function(arr, i) { + if (Array.isArray(arr)) { + return arr; + } else if (Symbol.iterator in Object(arr)) { + return _sliceIterator(arr, i); + } else { + throw new TypeError("Invalid attempt to destructure non-iterable instance"); + } +}; babelHelpers.taggedTemplateLiteral = function (strings, raw) { return Object.freeze(Object.defineProperties(strings, { @@ -238,10 +293,25 @@ babelHelpers.toArray = function (arr) { babelHelpers.toConsumableArray = function (arr) { if (Array.isArray(arr)) { - for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; + for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } }; + +babelHelpers.assertThisInitialized = function(self) { + if (self === void 0) { + throw new ReferenceError( + "this hasn't been initialised - super() hasn't been called", + ); + } + + return self; +}; + +babelHelpers.taggedTemplateLiteralLoose = function(strings, raw) { + strings.raw = raw; + return strings; +}; diff --git a/babel-preset/configs/main.js b/babel-preset/configs/main.js index 96405f002f9538..d17db86969f797 100644 --- a/babel-preset/configs/main.js +++ b/babel-preset/configs/main.js @@ -8,37 +8,55 @@ 'use strict'; const defaultPlugins = [ - [require('babel-plugin-syntax-class-properties')], - [require('babel-plugin-syntax-trailing-function-commas')], - [require('babel-plugin-transform-class-properties')], - [require('babel-plugin-transform-es2015-block-scoping')], - [require('babel-plugin-transform-es2015-computed-properties')], - [require('babel-plugin-transform-es2015-destructuring')], - [require('babel-plugin-transform-es2015-function-name')], - [require('babel-plugin-transform-es2015-literals')], - [require('babel-plugin-transform-es2015-parameters')], - [require('babel-plugin-transform-es2015-shorthand-properties')], - [require('babel-plugin-transform-flow-strip-types')], - [require('babel-plugin-transform-react-jsx')], - [require('babel-plugin-transform-regenerator')], + [require('@babel/plugin-transform-block-scoping')], + // the flow strip types plugin must go BEFORE class properties! + // there'll be a test case that fails if you don't. + [require('@babel/plugin-transform-flow-strip-types')], [ - require('babel-plugin-transform-es2015-modules-commonjs'), - {strict: false, allowTopLevelThis: true}, + require('@babel/plugin-proposal-class-properties'), + // use `this.foo = bar` instead of `this.defineProperty('foo', ...)` + // (Makes the properties enumerable) + {loose: true}, + ], + [require('@babel/plugin-transform-computed-properties')], + [require('@babel/plugin-transform-destructuring')], + [require('@babel/plugin-transform-function-name')], + [require('@babel/plugin-transform-literals')], + [require('@babel/plugin-transform-parameters')], + [require('@babel/plugin-transform-shorthand-properties')], + [require('@babel/plugin-transform-react-jsx')], + [require('@babel/plugin-transform-regenerator')], + [require('@babel/plugin-transform-sticky-regex')], + [require('@babel/plugin-transform-unicode-regex')], + [ + require('@babel/plugin-transform-modules-commonjs'), + { + strict: false, + strictMode : false, // prevent "use strict" injections + allowTopLevelThis: true, // dont rewrite global `this` -> `undefined` + }, ], ]; -const checkES2015Constants = [require('babel-plugin-check-es2015-constants')]; -const es2015ArrowFunctions = [require('babel-plugin-transform-es2015-arrow-functions')]; -const es2015Classes = [require('babel-plugin-transform-es2015-classes')]; -const es2015ForOf = [require('babel-plugin-transform-es2015-for-of'), {loose: true}]; -const es2015Spread = [require('babel-plugin-transform-es2015-spread')]; -const es2015TemplateLiterals = [require('babel-plugin-transform-es2015-template-literals')]; -const asyncFunctions = [require('babel-plugin-syntax-async-functions')]; -const exponentiationOperator = [require('babel-plugin-transform-exponentiation-operator')]; -const objectAssign = [require('babel-plugin-transform-object-assign')]; -const objectRestSpread = [require('babel-plugin-transform-object-rest-spread')]; -const reactDisplayName = [require('babel-plugin-transform-react-display-name')]; -const reactJsxSource = [require('babel-plugin-transform-react-jsx-source')]; +const es2015ArrowFunctions = [ + require('@babel/plugin-transform-arrow-functions'), +]; +const es2015Classes = [require('@babel/plugin-transform-classes')]; +const es2015ForOf = [require('@babel/plugin-transform-for-of'), {loose: true}]; +const es2015Spread = [require('@babel/plugin-transform-spread')]; +const es2015TemplateLiterals = [ + require('@babel/plugin-transform-template-literals'), + {loose: true}, // dont 'a'.concat('b'), just use 'a'+'b' +]; +const exponentiationOperator = [ + require('@babel/plugin-transform-exponentiation-operator'), +]; +const objectAssign = [require('@babel/plugin-transform-object-assign')]; +const objectRestSpread = [require('@babel/plugin-proposal-object-rest-spread')]; +const reactDisplayName = [ + require('@babel/plugin-transform-react-display-name'), +]; +const reactJsxSource = [require('@babel/plugin-transform-react-jsx-source')]; const symbolMember = [require('../transforms/transform-symbol-member')]; const getPreset = (src, options) => { @@ -49,18 +67,12 @@ const getPreset = (src, options) => { const extraPlugins = []; - if (isNull || src.indexOf('async') !== -1 || src.indexOf('await') !== -1) { - extraPlugins.push(asyncFunctions); - } if (hasClass) { extraPlugins.push(es2015Classes); } if (isNull || src.indexOf('=>') !== -1) { extraPlugins.push(es2015ArrowFunctions); } - if (isNull || src.indexOf('const') !== -1) { - extraPlugins.push(checkES2015Constants); - } if (isNull || hasClass || src.indexOf('...') !== -1) { extraPlugins.push(es2015Spread); extraPlugins.push(objectRestSpread); diff --git a/jest/preprocessor.js b/jest/preprocessor.js index e6a897f8e02abc..a7c52411f19017 100644 --- a/jest/preprocessor.js +++ b/jest/preprocessor.js @@ -11,7 +11,7 @@ 'use strict'; -const babel = require('babel-core'); +const {transformSync: babelTransformSync} = require('@babel/core'); /* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error * found when Flow v0.54 was deployed. To see the error delete this comment and * run Flow. */ @@ -20,7 +20,7 @@ const babelRegisterOnly = require('metro/src/babelRegisterOnly'); * found when Flow v0.54 was deployed. To see the error delete this comment and * run Flow. */ const createCacheKeyFunction = require('fbjs-scripts/jest/createCacheKeyFunction'); -const generate = require('babel-generator').default; +const generate = require('@babel/generator').default; const nodeFiles = RegExp([ '/local-cli/', @@ -35,7 +35,7 @@ const transformer = require('metro/src/transformer.js'); module.exports = { process(src/*: string*/, file/*: string*/) { if (nodeFiles.test(file)) { // node specific transforms only - return babel.transform( + return babelTransformSync( src, Object.assign({filename: file}, nodeOptions) ).code; @@ -54,6 +54,45 @@ module.exports = { retainLines: true, }, src, + plugins: [ + [require('@babel/plugin-transform-block-scoping')], + // the flow strip types plugin must go BEFORE class properties! + // there'll be a test case that fails if you don't. + [require('@babel/plugin-transform-flow-strip-types')], + [ + require('@babel/plugin-proposal-class-properties'), + // use `this.foo = bar` instead of `this.defineProperty('foo', ...)` + // (Makes the properties enumerable) + {loose: true}, + ], + [require('@babel/plugin-transform-computed-properties')], + [require('@babel/plugin-transform-destructuring')], + [require('@babel/plugin-transform-function-name')], + [require('@babel/plugin-transform-literals')], + [require('@babel/plugin-transform-parameters')], + [require('@babel/plugin-transform-shorthand-properties')], + [require('@babel/plugin-transform-react-jsx')], + [require('@babel/plugin-transform-regenerator')], + [require('@babel/plugin-transform-sticky-regex')], + [require('@babel/plugin-transform-unicode-regex')], + [ + require('@babel/plugin-transform-modules-commonjs'), + {strict: false, allowTopLevelThis: true}, + ], + [require('@babel/plugin-transform-classes')], + [require('@babel/plugin-transform-arrow-functions')], + [require('@babel/plugin-transform-spread')], + [require('@babel/plugin-proposal-object-rest-spread')], + [ + require('@babel/plugin-transform-template-literals'), + {loose: true}, // dont 'a'.concat('b'), just use 'a'+'b' + ], + [require('@babel/plugin-transform-exponentiation-operator')], + [require('@babel/plugin-transform-object-assign')], + [require('@babel/plugin-transform-for-of'), {loose: true}], + [require('@babel/plugin-transform-react-display-name')], + [require('@babel/plugin-transform-react-jsx-source')], + ], }); return generate(ast, { @@ -70,6 +109,6 @@ module.exports = { getCacheKey: createCacheKeyFunction([ __filename, require.resolve('metro/src/transformer.js'), - require.resolve('babel-core/package.json'), + require.resolve('@babel/core/package.json'), ]), }; From c9a6b8560f0e6ef3e995d99c89ebca412a505521 Mon Sep 17 00:00:00 2001 From: Matt Mahoney Date: Wed, 11 Apr 2018 08:12:44 -0700 Subject: [PATCH 0282/1109] Revert D7097279: BREAKING CHANGE: UPGRADE REACT NATIVE TO BABEL 7! Differential Revision: D7097279 Original commit changeset: 9fb204cae733 fbshipit-source-id: bbbb20b5dbed5dc01ae5557686a07d987b9a6cc6 --- Libraries/polyfills/babelHelpers.js | 220 ++++++++++------------------ babel-preset/configs/main.js | 78 +++++----- jest/preprocessor.js | 47 +----- 3 files changed, 112 insertions(+), 233 deletions(-) diff --git a/Libraries/polyfills/babelHelpers.js b/Libraries/polyfills/babelHelpers.js index 7d251ea347489b..dfe819464f09c4 100644 --- a/Libraries/polyfills/babelHelpers.js +++ b/Libraries/polyfills/babelHelpers.js @@ -12,15 +12,19 @@ /* eslint-disable quotes, curly, no-proto, no-undef-init, dot-notation */ // Created by running: -// require('fs').writeFileSync('babelExternalHelpers.js', require('@babel/core').buildExternalHelpers('_extends classCallCheck createClass createRawReactElement defineProperty get inherits interopRequireDefault interopRequireWildcard objectWithoutProperties possibleConstructorReturn slicedToArray taggedTemplateLiteral toArray toConsumableArray wrapNativeSuper assertThisInitialized taggedTemplateLiteralLoose'.split(' ')))// then replacing the `global` reference in the last line to also use `this`. +// require('babel-core').buildExternalHelpers('_extends classCallCheck createClass createRawReactElement defineProperty get inherits interopRequireDefault interopRequireWildcard objectWithoutProperties possibleConstructorReturn slicedToArray taggedTemplateLiteral toArray toConsumableArray '.split(' ')) +// then replacing the `global` reference in the last line to also use `this`. // -// Actually, that's a lie, because babel omits _extends and -// createRawReactElement. the file is also cleaned up a bit. -// You may need to clear wrapNativeSuper while the bug hasn't been fixed yet. -// Do try to keep diffs to a minimum. +// actually, that's a lie, because babel6 omits _extends and createRawReactElement var babelHelpers = global.babelHelpers = {}; +babelHelpers.typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; +} : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; +}; + babelHelpers.createRawReactElement = (function () { var REACT_ELEMENT_TYPE = typeof Symbol === "function" && Symbol.for && Symbol.for("react.element") || 0xeac7; return function createRawReactElement(type, key, props) { @@ -41,20 +45,32 @@ babelHelpers.classCallCheck = function (instance, Constructor) { } }; -function _defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || false; - descriptor.configurable = true; - if ("value" in descriptor) descriptor.writable = true; - Object.defineProperty(target, descriptor.key, descriptor); +babelHelpers.createClass = (function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } } -} -babelHelpers.createClass = function(Constructor, protoProps, staticProps) { - if (protoProps) _defineProperties(Constructor.prototype, protoProps); - if (staticProps) _defineProperties(Constructor, staticProps); - return Constructor; + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; +})(); + +babelHelpers.defineEnumerableProperties = function(obj, descs) { + for (var key in descs) { + var desc = descs[key]; + desc.configurable = (desc.enumerable = true); + if ('value' in desc) desc.writable = true; + Object.defineProperty(obj, key, desc); + } + return obj; }; babelHelpers.defineProperty = function (obj, key, value) { @@ -113,8 +129,9 @@ babelHelpers.get = function get(object, property, receiver) { babelHelpers.inherits = function (subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { - throw new TypeError("Super expression must either be null or a function"); + 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, @@ -126,54 +143,6 @@ babelHelpers.inherits = function (subClass, superClass) { if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }; -var _gPO = Object.getPrototypeOf || function _gPO(o) { return o.__proto__ }; -var _sPO = Object.setPrototypeOf || function _sPO(o, p) { o.__proto__ = p; return o }; -var _construct = -// TODO: prepack does not like this line (and we can use the fallback just fine) -// (typeof Reflect === "object" && Reflect.construct) || - function _construct(Parent, args, Class) { - var Constructor, a = [null]; - a.push.apply(a, args); - Constructor = Parent.bind.apply(Parent, a); - return _sPO(new Constructor, Class.prototype); - }; -var _cache = typeof Map === "function" && new Map(); -babelHelpers.wrapNativeSuper = function(Class) { - // FB: - // Note: while extending native classes is pretty meh we do have cases, for - // example; Error. There is also a false positive, for example; Blob. - - if (typeof Class !== "function") { - throw new TypeError("Super expression must either be null or a function"); - } - if (typeof _cache !== "undefined") { - if (_cache.has(Class)) return _cache.get(Class); - _cache.set(Class, Wrapper); - } - function Wrapper() { - // this is a temporary fix for a babel bug (it's invoking the wrong func - // when you do `super()`) - return _construct(Class, arguments, _gPO(this).constructor); - } - Wrapper.prototype = Object.create(Class.prototype, { - constructor: { - value: Wrapper, - enumerable: false, - writeable: true, - configurable: true, - } - }); - return _sPO( - Wrapper, - _sPO( - function Super() { - return _construct(Class, arguments, _gPO(this).constructor); - }, - Class - ) - ); -}; - babelHelpers.interopRequireDefault = function (obj) { return obj && obj.__esModule ? obj : { default: obj @@ -188,15 +157,7 @@ babelHelpers.interopRequireWildcard = function (obj) { if (obj != null) { for (var key in obj) { - if (Object.prototype.hasOwnProperty.call(obj, key)) { - var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; - - if (desc.get || desc.set) { - Object.defineProperty(newObj, key, desc); - } else { - newObj[key] = obj[key]; - } - } + if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } @@ -205,79 +166,63 @@ babelHelpers.interopRequireWildcard = function (obj) { } }; -babelHelpers.objectWithoutProperties = function(source, excluded) { - if (source == null) return {}; +babelHelpers.objectWithoutProperties = function (obj, keys) { var target = {}; - var sourceKeys = Object.keys(source); - var key, i; - - for (i = 0; i < sourceKeys.length; i++) { - key = sourceKeys[i]; - if (excluded.indexOf(key) >= 0) continue; - target[key] = source[key]; - } - - if (Object.getOwnPropertySymbols) { - var sourceSymbolKeys = Object.getOwnPropertySymbols(source); - for (i = 0; i < sourceSymbolKeys.length; i++) { - key = sourceSymbolKeys[i]; - if (excluded.indexOf(key) >= 0) continue; - if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; - target[key] = source[key]; - } + for (var i in obj) { + if (keys.indexOf(i) >= 0) continue; + if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; + target[i] = obj[i]; } return target; }; babelHelpers.possibleConstructorReturn = function (self, call) { - if (call && (typeof call === "object" || typeof call === "function")) { - return call; - } - - if (self === void 0) { + if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } - return self; + return call && (typeof call === "object" || typeof call === "function") ? call : self; }; -function _sliceIterator(arr, i) { - var _arr = []; - var _n = true; - var _d = false; - var _e = undefined; - - try { - for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { - _arr.push(_s.value); +babelHelpers.slicedToArray = (function () { + function sliceIterator(arr, i) { + var _arr = []; + var _n = true; + var _d = false; + var _e = undefined; - if (i && _arr.length === i) break; - } - } catch (err) { - _d = true; - _e = err; - } finally { try { - if (!_n && _i["return"] != null) _i["return"](); + for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); + + if (i && _arr.length === i) break; + } + } catch (err) { + _d = true; + _e = err; } finally { - if (_d) throw _e; + try { + if (!_n && _i["return"]) _i["return"](); + } finally { + if (_d) throw _e; + } } - } - - return _arr; -} -babelHelpers.slicedToArray = function(arr, i) { - if (Array.isArray(arr)) { - return arr; - } else if (Symbol.iterator in Object(arr)) { - return _sliceIterator(arr, i); - } else { - throw new TypeError("Invalid attempt to destructure non-iterable instance"); + return _arr; } -}; + + return function (arr, i) { + if (Array.isArray(arr)) { + return arr; + } else if (Symbol.iterator in Object(arr)) { + return sliceIterator(arr, i); + } else { + throw new TypeError("Invalid attempt to destructure non-iterable instance"); + } + }; +})(); babelHelpers.taggedTemplateLiteral = function (strings, raw) { return Object.freeze(Object.defineProperties(strings, { @@ -293,25 +238,10 @@ babelHelpers.toArray = function (arr) { babelHelpers.toConsumableArray = function (arr) { if (Array.isArray(arr)) { - for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; + for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } }; - -babelHelpers.assertThisInitialized = function(self) { - if (self === void 0) { - throw new ReferenceError( - "this hasn't been initialised - super() hasn't been called", - ); - } - - return self; -}; - -babelHelpers.taggedTemplateLiteralLoose = function(strings, raw) { - strings.raw = raw; - return strings; -}; diff --git a/babel-preset/configs/main.js b/babel-preset/configs/main.js index d17db86969f797..96405f002f9538 100644 --- a/babel-preset/configs/main.js +++ b/babel-preset/configs/main.js @@ -8,55 +8,37 @@ 'use strict'; const defaultPlugins = [ - [require('@babel/plugin-transform-block-scoping')], - // the flow strip types plugin must go BEFORE class properties! - // there'll be a test case that fails if you don't. - [require('@babel/plugin-transform-flow-strip-types')], + [require('babel-plugin-syntax-class-properties')], + [require('babel-plugin-syntax-trailing-function-commas')], + [require('babel-plugin-transform-class-properties')], + [require('babel-plugin-transform-es2015-block-scoping')], + [require('babel-plugin-transform-es2015-computed-properties')], + [require('babel-plugin-transform-es2015-destructuring')], + [require('babel-plugin-transform-es2015-function-name')], + [require('babel-plugin-transform-es2015-literals')], + [require('babel-plugin-transform-es2015-parameters')], + [require('babel-plugin-transform-es2015-shorthand-properties')], + [require('babel-plugin-transform-flow-strip-types')], + [require('babel-plugin-transform-react-jsx')], + [require('babel-plugin-transform-regenerator')], [ - require('@babel/plugin-proposal-class-properties'), - // use `this.foo = bar` instead of `this.defineProperty('foo', ...)` - // (Makes the properties enumerable) - {loose: true}, - ], - [require('@babel/plugin-transform-computed-properties')], - [require('@babel/plugin-transform-destructuring')], - [require('@babel/plugin-transform-function-name')], - [require('@babel/plugin-transform-literals')], - [require('@babel/plugin-transform-parameters')], - [require('@babel/plugin-transform-shorthand-properties')], - [require('@babel/plugin-transform-react-jsx')], - [require('@babel/plugin-transform-regenerator')], - [require('@babel/plugin-transform-sticky-regex')], - [require('@babel/plugin-transform-unicode-regex')], - [ - require('@babel/plugin-transform-modules-commonjs'), - { - strict: false, - strictMode : false, // prevent "use strict" injections - allowTopLevelThis: true, // dont rewrite global `this` -> `undefined` - }, + require('babel-plugin-transform-es2015-modules-commonjs'), + {strict: false, allowTopLevelThis: true}, ], ]; -const es2015ArrowFunctions = [ - require('@babel/plugin-transform-arrow-functions'), -]; -const es2015Classes = [require('@babel/plugin-transform-classes')]; -const es2015ForOf = [require('@babel/plugin-transform-for-of'), {loose: true}]; -const es2015Spread = [require('@babel/plugin-transform-spread')]; -const es2015TemplateLiterals = [ - require('@babel/plugin-transform-template-literals'), - {loose: true}, // dont 'a'.concat('b'), just use 'a'+'b' -]; -const exponentiationOperator = [ - require('@babel/plugin-transform-exponentiation-operator'), -]; -const objectAssign = [require('@babel/plugin-transform-object-assign')]; -const objectRestSpread = [require('@babel/plugin-proposal-object-rest-spread')]; -const reactDisplayName = [ - require('@babel/plugin-transform-react-display-name'), -]; -const reactJsxSource = [require('@babel/plugin-transform-react-jsx-source')]; +const checkES2015Constants = [require('babel-plugin-check-es2015-constants')]; +const es2015ArrowFunctions = [require('babel-plugin-transform-es2015-arrow-functions')]; +const es2015Classes = [require('babel-plugin-transform-es2015-classes')]; +const es2015ForOf = [require('babel-plugin-transform-es2015-for-of'), {loose: true}]; +const es2015Spread = [require('babel-plugin-transform-es2015-spread')]; +const es2015TemplateLiterals = [require('babel-plugin-transform-es2015-template-literals')]; +const asyncFunctions = [require('babel-plugin-syntax-async-functions')]; +const exponentiationOperator = [require('babel-plugin-transform-exponentiation-operator')]; +const objectAssign = [require('babel-plugin-transform-object-assign')]; +const objectRestSpread = [require('babel-plugin-transform-object-rest-spread')]; +const reactDisplayName = [require('babel-plugin-transform-react-display-name')]; +const reactJsxSource = [require('babel-plugin-transform-react-jsx-source')]; const symbolMember = [require('../transforms/transform-symbol-member')]; const getPreset = (src, options) => { @@ -67,12 +49,18 @@ const getPreset = (src, options) => { const extraPlugins = []; + if (isNull || src.indexOf('async') !== -1 || src.indexOf('await') !== -1) { + extraPlugins.push(asyncFunctions); + } if (hasClass) { extraPlugins.push(es2015Classes); } if (isNull || src.indexOf('=>') !== -1) { extraPlugins.push(es2015ArrowFunctions); } + if (isNull || src.indexOf('const') !== -1) { + extraPlugins.push(checkES2015Constants); + } if (isNull || hasClass || src.indexOf('...') !== -1) { extraPlugins.push(es2015Spread); extraPlugins.push(objectRestSpread); diff --git a/jest/preprocessor.js b/jest/preprocessor.js index a7c52411f19017..e6a897f8e02abc 100644 --- a/jest/preprocessor.js +++ b/jest/preprocessor.js @@ -11,7 +11,7 @@ 'use strict'; -const {transformSync: babelTransformSync} = require('@babel/core'); +const babel = require('babel-core'); /* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error * found when Flow v0.54 was deployed. To see the error delete this comment and * run Flow. */ @@ -20,7 +20,7 @@ const babelRegisterOnly = require('metro/src/babelRegisterOnly'); * found when Flow v0.54 was deployed. To see the error delete this comment and * run Flow. */ const createCacheKeyFunction = require('fbjs-scripts/jest/createCacheKeyFunction'); -const generate = require('@babel/generator').default; +const generate = require('babel-generator').default; const nodeFiles = RegExp([ '/local-cli/', @@ -35,7 +35,7 @@ const transformer = require('metro/src/transformer.js'); module.exports = { process(src/*: string*/, file/*: string*/) { if (nodeFiles.test(file)) { // node specific transforms only - return babelTransformSync( + return babel.transform( src, Object.assign({filename: file}, nodeOptions) ).code; @@ -54,45 +54,6 @@ module.exports = { retainLines: true, }, src, - plugins: [ - [require('@babel/plugin-transform-block-scoping')], - // the flow strip types plugin must go BEFORE class properties! - // there'll be a test case that fails if you don't. - [require('@babel/plugin-transform-flow-strip-types')], - [ - require('@babel/plugin-proposal-class-properties'), - // use `this.foo = bar` instead of `this.defineProperty('foo', ...)` - // (Makes the properties enumerable) - {loose: true}, - ], - [require('@babel/plugin-transform-computed-properties')], - [require('@babel/plugin-transform-destructuring')], - [require('@babel/plugin-transform-function-name')], - [require('@babel/plugin-transform-literals')], - [require('@babel/plugin-transform-parameters')], - [require('@babel/plugin-transform-shorthand-properties')], - [require('@babel/plugin-transform-react-jsx')], - [require('@babel/plugin-transform-regenerator')], - [require('@babel/plugin-transform-sticky-regex')], - [require('@babel/plugin-transform-unicode-regex')], - [ - require('@babel/plugin-transform-modules-commonjs'), - {strict: false, allowTopLevelThis: true}, - ], - [require('@babel/plugin-transform-classes')], - [require('@babel/plugin-transform-arrow-functions')], - [require('@babel/plugin-transform-spread')], - [require('@babel/plugin-proposal-object-rest-spread')], - [ - require('@babel/plugin-transform-template-literals'), - {loose: true}, // dont 'a'.concat('b'), just use 'a'+'b' - ], - [require('@babel/plugin-transform-exponentiation-operator')], - [require('@babel/plugin-transform-object-assign')], - [require('@babel/plugin-transform-for-of'), {loose: true}], - [require('@babel/plugin-transform-react-display-name')], - [require('@babel/plugin-transform-react-jsx-source')], - ], }); return generate(ast, { @@ -109,6 +70,6 @@ module.exports = { getCacheKey: createCacheKeyFunction([ __filename, require.resolve('metro/src/transformer.js'), - require.resolve('@babel/core/package.json'), + require.resolve('babel-core/package.json'), ]), }; From fcecc1502af772c3523531b0acd5ce5845bde006 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Wed, 11 Apr 2018 08:46:10 -0700 Subject: [PATCH 0283/1109] Revert D7473762: [react-native][PR] added in snapAlignment for horizontal android scrollView Differential Revision: D7473762 Original commit changeset: ad4778b83f9f fbshipit-source-id: 90f002ad60d26abd801a7a9d37e71254b063faef --- .../scroll/ReactHorizontalScrollView.java | 21 +------------------ .../ReactHorizontalScrollViewManager.java | 5 ----- 2 files changed, 1 insertion(+), 25 deletions(-) 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 fe4762ac4a2f2e..90b9d1fc4d3a9c 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 @@ -52,7 +52,6 @@ public class ReactHorizontalScrollView extends HorizontalScrollView implements private @Nullable Drawable mEndBackground; private int mEndFillColor = Color.TRANSPARENT; private int mSnapInterval = 0; - private String mSnapAlignment = "start"; private ReactViewBackgroundManager mReactBackgroundManager; public ReactHorizontalScrollView(Context context) { @@ -97,13 +96,6 @@ public void setPagingEnabled(boolean pagingEnabled) { public void setSnapInterval(int snapInterval) { mSnapInterval = snapInterval; - if(snapInterval != 0) { - mPagingEnabled = true; - } - } - - public void setSnapAlignment(String snapAlignment) { - mSnapAlignment = snapAlignment; } public void flashScrollIndicators() { @@ -244,17 +236,6 @@ private int getSnapInterval() { return getWidth(); } - private int getAlignmentOffset() { - int width = getWidth(); - int snapInterval = getSnapInterval(); - if (mSnapAlignment.equals("center")) { - return (width - snapInterval)/2; - } else if(mSnapAlignment.equals("end")) { - return (width - snapInterval); - } - return 0; - } - public void setEndFillColor(int color) { if (color != mEndFillColor) { mEndFillColor = color; @@ -368,7 +349,7 @@ private void smoothScrollToPage(int velocity) { if (predictedX > page * width + width / 2) { page = page + 1; } - smoothScrollTo(page * width - getAlignmentOffset(), getScrollY()); + smoothScrollTo(page * width, getScrollY()); } @Override diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java index d5fe728c309896..e6536a6e53eb76 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java @@ -80,11 +80,6 @@ public void setSnapToInterval(ReactHorizontalScrollView view, float snapToInterv view.setSnapInterval((int) (snapToInterval * screenDisplayMetrics.density)); } - @ReactProp(name = "snapToAlignment") - public void setSnapToAlignment(ReactHorizontalScrollView view, String snapToAlignment) { - view.setSnapAlignment(snapToAlignment); - } - @ReactProp(name = ReactClippingViewGroupHelper.PROP_REMOVE_CLIPPED_SUBVIEWS) public void setRemoveClippedSubviews(ReactHorizontalScrollView view, boolean removeClippedSubviews) { view.setRemoveClippedSubviews(removeClippedSubviews); From 3277bed1f861e81e9066be19fabd050ffb5a6016 Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Wed, 11 Apr 2018 10:38:48 -0700 Subject: [PATCH 0284/1109] Bump metro@0.32.0 Reviewed By: mjesun Differential Revision: D7586296 fbshipit-source-id: 72407851366c5c2de15d4b3c7fe6311281d697bf --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 4f4f558451100f..df681175da83ca 100644 --- a/package.json +++ b/package.json @@ -175,8 +175,8 @@ "graceful-fs": "^4.1.3", "inquirer": "^3.0.6", "lodash": "^4.17.5", - "metro": "^0.31.0", - "metro-core": "^0.31.0", + "metro": "^0.32.0", + "metro-core": "^0.32.0", "mime": "^1.3.4", "minimist": "^1.2.0", "mkdirp": "^0.5.1", From f8d6b97140cffe8d18b2558f94570c8d1b410d5c Mon Sep 17 00:00:00 2001 From: Peter van der Zee Date: Wed, 11 Apr 2018 16:29:36 -0700 Subject: [PATCH 0285/1109] BREAKING CHANGE: UPGRADE REACT NATIVE TO BABEL 7! Summary: BREAKING CHANGE This change upgrades the React Native build pipeline from Babel 6 to Babel 7 If you use a `.babelrc` then you'll need to update it to Babel 7 (note that some plugins are no longer relevant, some plugins are automatically upgraded, and some will need some manual love). Note that you may also need to upgrade your dev env, tests etc, to make sure they work with Babel 7. Reviewed By: mjesun Differential Revision: D7591303 fbshipit-source-id: 29cef21f6466633a9c366d1f3c0d3cf874c714db --- Libraries/polyfills/babelHelpers.js | 220 ++++++++++++++++++---------- babel-preset/configs/main.js | 78 +++++----- jest/preprocessor.js | 47 +++++- 3 files changed, 233 insertions(+), 112 deletions(-) diff --git a/Libraries/polyfills/babelHelpers.js b/Libraries/polyfills/babelHelpers.js index dfe819464f09c4..7d251ea347489b 100644 --- a/Libraries/polyfills/babelHelpers.js +++ b/Libraries/polyfills/babelHelpers.js @@ -12,19 +12,15 @@ /* eslint-disable quotes, curly, no-proto, no-undef-init, dot-notation */ // Created by running: -// require('babel-core').buildExternalHelpers('_extends classCallCheck createClass createRawReactElement defineProperty get inherits interopRequireDefault interopRequireWildcard objectWithoutProperties possibleConstructorReturn slicedToArray taggedTemplateLiteral toArray toConsumableArray '.split(' ')) -// then replacing the `global` reference in the last line to also use `this`. +// require('fs').writeFileSync('babelExternalHelpers.js', require('@babel/core').buildExternalHelpers('_extends classCallCheck createClass createRawReactElement defineProperty get inherits interopRequireDefault interopRequireWildcard objectWithoutProperties possibleConstructorReturn slicedToArray taggedTemplateLiteral toArray toConsumableArray wrapNativeSuper assertThisInitialized taggedTemplateLiteralLoose'.split(' ')))// then replacing the `global` reference in the last line to also use `this`. // -// actually, that's a lie, because babel6 omits _extends and createRawReactElement +// Actually, that's a lie, because babel omits _extends and +// createRawReactElement. the file is also cleaned up a bit. +// You may need to clear wrapNativeSuper while the bug hasn't been fixed yet. +// Do try to keep diffs to a minimum. var babelHelpers = global.babelHelpers = {}; -babelHelpers.typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { - return typeof obj; -} : function (obj) { - return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; -}; - babelHelpers.createRawReactElement = (function () { var REACT_ELEMENT_TYPE = typeof Symbol === "function" && Symbol.for && Symbol.for("react.element") || 0xeac7; return function createRawReactElement(type, key, props) { @@ -45,32 +41,20 @@ babelHelpers.classCallCheck = function (instance, Constructor) { } }; -babelHelpers.createClass = (function () { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || false; - descriptor.configurable = true; - if ("value" in descriptor) descriptor.writable = true; - Object.defineProperty(target, descriptor.key, descriptor); - } +function _defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); } +} - return function (Constructor, protoProps, staticProps) { - if (protoProps) defineProperties(Constructor.prototype, protoProps); - if (staticProps) defineProperties(Constructor, staticProps); - return Constructor; - }; -})(); - -babelHelpers.defineEnumerableProperties = function(obj, descs) { - for (var key in descs) { - var desc = descs[key]; - desc.configurable = (desc.enumerable = true); - if ('value' in desc) desc.writable = true; - Object.defineProperty(obj, key, desc); - } - return obj; +babelHelpers.createClass = function(Constructor, protoProps, staticProps) { + if (protoProps) _defineProperties(Constructor.prototype, protoProps); + if (staticProps) _defineProperties(Constructor, staticProps); + return Constructor; }; babelHelpers.defineProperty = function (obj, key, value) { @@ -129,9 +113,8 @@ babelHelpers.get = function get(object, property, receiver) { babelHelpers.inherits = function (subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { - throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); + throw new TypeError("Super expression must either be null or a function"); } - subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, @@ -143,6 +126,54 @@ babelHelpers.inherits = function (subClass, superClass) { if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }; +var _gPO = Object.getPrototypeOf || function _gPO(o) { return o.__proto__ }; +var _sPO = Object.setPrototypeOf || function _sPO(o, p) { o.__proto__ = p; return o }; +var _construct = +// TODO: prepack does not like this line (and we can use the fallback just fine) +// (typeof Reflect === "object" && Reflect.construct) || + function _construct(Parent, args, Class) { + var Constructor, a = [null]; + a.push.apply(a, args); + Constructor = Parent.bind.apply(Parent, a); + return _sPO(new Constructor, Class.prototype); + }; +var _cache = typeof Map === "function" && new Map(); +babelHelpers.wrapNativeSuper = function(Class) { + // FB: + // Note: while extending native classes is pretty meh we do have cases, for + // example; Error. There is also a false positive, for example; Blob. + + if (typeof Class !== "function") { + throw new TypeError("Super expression must either be null or a function"); + } + if (typeof _cache !== "undefined") { + if (_cache.has(Class)) return _cache.get(Class); + _cache.set(Class, Wrapper); + } + function Wrapper() { + // this is a temporary fix for a babel bug (it's invoking the wrong func + // when you do `super()`) + return _construct(Class, arguments, _gPO(this).constructor); + } + Wrapper.prototype = Object.create(Class.prototype, { + constructor: { + value: Wrapper, + enumerable: false, + writeable: true, + configurable: true, + } + }); + return _sPO( + Wrapper, + _sPO( + function Super() { + return _construct(Class, arguments, _gPO(this).constructor); + }, + Class + ) + ); +}; + babelHelpers.interopRequireDefault = function (obj) { return obj && obj.__esModule ? obj : { default: obj @@ -157,7 +188,15 @@ babelHelpers.interopRequireWildcard = function (obj) { if (obj != null) { for (var key in obj) { - if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; + if (Object.prototype.hasOwnProperty.call(obj, key)) { + var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; + + if (desc.get || desc.set) { + Object.defineProperty(newObj, key, desc); + } else { + newObj[key] = obj[key]; + } + } } } @@ -166,63 +205,79 @@ babelHelpers.interopRequireWildcard = function (obj) { } }; -babelHelpers.objectWithoutProperties = function (obj, keys) { +babelHelpers.objectWithoutProperties = function(source, excluded) { + if (source == null) return {}; var target = {}; + var sourceKeys = Object.keys(source); + var key, i; + + for (i = 0; i < sourceKeys.length; i++) { + key = sourceKeys[i]; + if (excluded.indexOf(key) >= 0) continue; + target[key] = source[key]; + } + + if (Object.getOwnPropertySymbols) { + var sourceSymbolKeys = Object.getOwnPropertySymbols(source); - for (var i in obj) { - if (keys.indexOf(i) >= 0) continue; - if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; - target[i] = obj[i]; + for (i = 0; i < sourceSymbolKeys.length; i++) { + key = sourceSymbolKeys[i]; + if (excluded.indexOf(key) >= 0) continue; + if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; + target[key] = source[key]; + } } return target; }; babelHelpers.possibleConstructorReturn = function (self, call) { - if (!self) { + if (call && (typeof call === "object" || typeof call === "function")) { + return call; + } + + if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } - return call && (typeof call === "object" || typeof call === "function") ? call : self; + return self; }; -babelHelpers.slicedToArray = (function () { - function sliceIterator(arr, i) { - var _arr = []; - var _n = true; - var _d = false; - var _e = undefined; +function _sliceIterator(arr, i) { + var _arr = []; + var _n = true; + var _d = false; + var _e = undefined; - try { - for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { - _arr.push(_s.value); + try { + for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); - if (i && _arr.length === i) break; - } - } catch (err) { - _d = true; - _e = err; + if (i && _arr.length === i) break; + } + } catch (err) { + _d = true; + _e = err; + } finally { + try { + if (!_n && _i["return"] != null) _i["return"](); } finally { - try { - if (!_n && _i["return"]) _i["return"](); - } finally { - if (_d) throw _e; - } + if (_d) throw _e; } - - return _arr; } - return function (arr, i) { - if (Array.isArray(arr)) { - return arr; - } else if (Symbol.iterator in Object(arr)) { - return sliceIterator(arr, i); - } else { - throw new TypeError("Invalid attempt to destructure non-iterable instance"); - } - }; -})(); + return _arr; +} + +babelHelpers.slicedToArray = function(arr, i) { + if (Array.isArray(arr)) { + return arr; + } else if (Symbol.iterator in Object(arr)) { + return _sliceIterator(arr, i); + } else { + throw new TypeError("Invalid attempt to destructure non-iterable instance"); + } +}; babelHelpers.taggedTemplateLiteral = function (strings, raw) { return Object.freeze(Object.defineProperties(strings, { @@ -238,10 +293,25 @@ babelHelpers.toArray = function (arr) { babelHelpers.toConsumableArray = function (arr) { if (Array.isArray(arr)) { - for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; + for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } }; + +babelHelpers.assertThisInitialized = function(self) { + if (self === void 0) { + throw new ReferenceError( + "this hasn't been initialised - super() hasn't been called", + ); + } + + return self; +}; + +babelHelpers.taggedTemplateLiteralLoose = function(strings, raw) { + strings.raw = raw; + return strings; +}; diff --git a/babel-preset/configs/main.js b/babel-preset/configs/main.js index 96405f002f9538..d17db86969f797 100644 --- a/babel-preset/configs/main.js +++ b/babel-preset/configs/main.js @@ -8,37 +8,55 @@ 'use strict'; const defaultPlugins = [ - [require('babel-plugin-syntax-class-properties')], - [require('babel-plugin-syntax-trailing-function-commas')], - [require('babel-plugin-transform-class-properties')], - [require('babel-plugin-transform-es2015-block-scoping')], - [require('babel-plugin-transform-es2015-computed-properties')], - [require('babel-plugin-transform-es2015-destructuring')], - [require('babel-plugin-transform-es2015-function-name')], - [require('babel-plugin-transform-es2015-literals')], - [require('babel-plugin-transform-es2015-parameters')], - [require('babel-plugin-transform-es2015-shorthand-properties')], - [require('babel-plugin-transform-flow-strip-types')], - [require('babel-plugin-transform-react-jsx')], - [require('babel-plugin-transform-regenerator')], + [require('@babel/plugin-transform-block-scoping')], + // the flow strip types plugin must go BEFORE class properties! + // there'll be a test case that fails if you don't. + [require('@babel/plugin-transform-flow-strip-types')], [ - require('babel-plugin-transform-es2015-modules-commonjs'), - {strict: false, allowTopLevelThis: true}, + require('@babel/plugin-proposal-class-properties'), + // use `this.foo = bar` instead of `this.defineProperty('foo', ...)` + // (Makes the properties enumerable) + {loose: true}, + ], + [require('@babel/plugin-transform-computed-properties')], + [require('@babel/plugin-transform-destructuring')], + [require('@babel/plugin-transform-function-name')], + [require('@babel/plugin-transform-literals')], + [require('@babel/plugin-transform-parameters')], + [require('@babel/plugin-transform-shorthand-properties')], + [require('@babel/plugin-transform-react-jsx')], + [require('@babel/plugin-transform-regenerator')], + [require('@babel/plugin-transform-sticky-regex')], + [require('@babel/plugin-transform-unicode-regex')], + [ + require('@babel/plugin-transform-modules-commonjs'), + { + strict: false, + strictMode : false, // prevent "use strict" injections + allowTopLevelThis: true, // dont rewrite global `this` -> `undefined` + }, ], ]; -const checkES2015Constants = [require('babel-plugin-check-es2015-constants')]; -const es2015ArrowFunctions = [require('babel-plugin-transform-es2015-arrow-functions')]; -const es2015Classes = [require('babel-plugin-transform-es2015-classes')]; -const es2015ForOf = [require('babel-plugin-transform-es2015-for-of'), {loose: true}]; -const es2015Spread = [require('babel-plugin-transform-es2015-spread')]; -const es2015TemplateLiterals = [require('babel-plugin-transform-es2015-template-literals')]; -const asyncFunctions = [require('babel-plugin-syntax-async-functions')]; -const exponentiationOperator = [require('babel-plugin-transform-exponentiation-operator')]; -const objectAssign = [require('babel-plugin-transform-object-assign')]; -const objectRestSpread = [require('babel-plugin-transform-object-rest-spread')]; -const reactDisplayName = [require('babel-plugin-transform-react-display-name')]; -const reactJsxSource = [require('babel-plugin-transform-react-jsx-source')]; +const es2015ArrowFunctions = [ + require('@babel/plugin-transform-arrow-functions'), +]; +const es2015Classes = [require('@babel/plugin-transform-classes')]; +const es2015ForOf = [require('@babel/plugin-transform-for-of'), {loose: true}]; +const es2015Spread = [require('@babel/plugin-transform-spread')]; +const es2015TemplateLiterals = [ + require('@babel/plugin-transform-template-literals'), + {loose: true}, // dont 'a'.concat('b'), just use 'a'+'b' +]; +const exponentiationOperator = [ + require('@babel/plugin-transform-exponentiation-operator'), +]; +const objectAssign = [require('@babel/plugin-transform-object-assign')]; +const objectRestSpread = [require('@babel/plugin-proposal-object-rest-spread')]; +const reactDisplayName = [ + require('@babel/plugin-transform-react-display-name'), +]; +const reactJsxSource = [require('@babel/plugin-transform-react-jsx-source')]; const symbolMember = [require('../transforms/transform-symbol-member')]; const getPreset = (src, options) => { @@ -49,18 +67,12 @@ const getPreset = (src, options) => { const extraPlugins = []; - if (isNull || src.indexOf('async') !== -1 || src.indexOf('await') !== -1) { - extraPlugins.push(asyncFunctions); - } if (hasClass) { extraPlugins.push(es2015Classes); } if (isNull || src.indexOf('=>') !== -1) { extraPlugins.push(es2015ArrowFunctions); } - if (isNull || src.indexOf('const') !== -1) { - extraPlugins.push(checkES2015Constants); - } if (isNull || hasClass || src.indexOf('...') !== -1) { extraPlugins.push(es2015Spread); extraPlugins.push(objectRestSpread); diff --git a/jest/preprocessor.js b/jest/preprocessor.js index e6a897f8e02abc..a7c52411f19017 100644 --- a/jest/preprocessor.js +++ b/jest/preprocessor.js @@ -11,7 +11,7 @@ 'use strict'; -const babel = require('babel-core'); +const {transformSync: babelTransformSync} = require('@babel/core'); /* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error * found when Flow v0.54 was deployed. To see the error delete this comment and * run Flow. */ @@ -20,7 +20,7 @@ const babelRegisterOnly = require('metro/src/babelRegisterOnly'); * found when Flow v0.54 was deployed. To see the error delete this comment and * run Flow. */ const createCacheKeyFunction = require('fbjs-scripts/jest/createCacheKeyFunction'); -const generate = require('babel-generator').default; +const generate = require('@babel/generator').default; const nodeFiles = RegExp([ '/local-cli/', @@ -35,7 +35,7 @@ const transformer = require('metro/src/transformer.js'); module.exports = { process(src/*: string*/, file/*: string*/) { if (nodeFiles.test(file)) { // node specific transforms only - return babel.transform( + return babelTransformSync( src, Object.assign({filename: file}, nodeOptions) ).code; @@ -54,6 +54,45 @@ module.exports = { retainLines: true, }, src, + plugins: [ + [require('@babel/plugin-transform-block-scoping')], + // the flow strip types plugin must go BEFORE class properties! + // there'll be a test case that fails if you don't. + [require('@babel/plugin-transform-flow-strip-types')], + [ + require('@babel/plugin-proposal-class-properties'), + // use `this.foo = bar` instead of `this.defineProperty('foo', ...)` + // (Makes the properties enumerable) + {loose: true}, + ], + [require('@babel/plugin-transform-computed-properties')], + [require('@babel/plugin-transform-destructuring')], + [require('@babel/plugin-transform-function-name')], + [require('@babel/plugin-transform-literals')], + [require('@babel/plugin-transform-parameters')], + [require('@babel/plugin-transform-shorthand-properties')], + [require('@babel/plugin-transform-react-jsx')], + [require('@babel/plugin-transform-regenerator')], + [require('@babel/plugin-transform-sticky-regex')], + [require('@babel/plugin-transform-unicode-regex')], + [ + require('@babel/plugin-transform-modules-commonjs'), + {strict: false, allowTopLevelThis: true}, + ], + [require('@babel/plugin-transform-classes')], + [require('@babel/plugin-transform-arrow-functions')], + [require('@babel/plugin-transform-spread')], + [require('@babel/plugin-proposal-object-rest-spread')], + [ + require('@babel/plugin-transform-template-literals'), + {loose: true}, // dont 'a'.concat('b'), just use 'a'+'b' + ], + [require('@babel/plugin-transform-exponentiation-operator')], + [require('@babel/plugin-transform-object-assign')], + [require('@babel/plugin-transform-for-of'), {loose: true}], + [require('@babel/plugin-transform-react-display-name')], + [require('@babel/plugin-transform-react-jsx-source')], + ], }); return generate(ast, { @@ -70,6 +109,6 @@ module.exports = { getCacheKey: createCacheKeyFunction([ __filename, require.resolve('metro/src/transformer.js'), - require.resolve('babel-core/package.json'), + require.resolve('@babel/core/package.json'), ]), }; From 5001b9f39eb9c81ba9dc38ed00972954c7d325e4 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Wed, 11 Apr 2018 18:05:54 -0700 Subject: [PATCH 0286/1109] Unfork Fabric Reviewed By: achen1, mdvacca Differential Revision: D7582130 fbshipit-source-id: f198c63ed2fcd8619610b4b2f28276e7ffca9217 --- Libraries/Components/View/FabricView.js | 13 - .../Components/View/requireFabricView.js | 25 -- Libraries/ReactNative/renderFabricSurface.js | 2 +- .../ReactNative/requireFabricComponent.js | 234 ------------------ Libraries/Text/FabricText.js | 13 - 5 files changed, 1 insertion(+), 286 deletions(-) delete mode 100644 Libraries/Components/View/FabricView.js delete mode 100644 Libraries/Components/View/requireFabricView.js delete mode 100644 Libraries/ReactNative/requireFabricComponent.js delete mode 100644 Libraries/Text/FabricText.js diff --git a/Libraries/Components/View/FabricView.js b/Libraries/Components/View/FabricView.js deleted file mode 100644 index d56189052877b8..00000000000000 --- a/Libraries/Components/View/FabricView.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule FabricView - * @flow - * @format - */ -'use strict'; - -module.exports = require('View'); diff --git a/Libraries/Components/View/requireFabricView.js b/Libraries/Components/View/requireFabricView.js deleted file mode 100644 index 55a7c40f4da0f6..00000000000000 --- a/Libraries/Components/View/requireFabricView.js +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule requireFabricView - * @flow - * @format - */ -'use strict'; - -/** - * This is a switch on the correct view to use for Fabric - */ -module.exports = (name: string, fabric: boolean) => { - switch (name) { - case 'View': - return fabric ? require('FabricView') : require('View'); - case 'Text': - return fabric ? require('FabricText') : require('Text'); - default: - throw new Error(name + ' is not supported by Fabric yet'); - } -}; diff --git a/Libraries/ReactNative/renderFabricSurface.js b/Libraries/ReactNative/renderFabricSurface.js index 46536a755ce5a3..0279f1759926d6 100644 --- a/Libraries/ReactNative/renderFabricSurface.js +++ b/Libraries/ReactNative/renderFabricSurface.js @@ -34,7 +34,7 @@ function renderFabricSurface( fabric={true} rootTag={rootTag} WrapperComponent={WrapperComponent}> - + ); diff --git a/Libraries/ReactNative/requireFabricComponent.js b/Libraries/ReactNative/requireFabricComponent.js deleted file mode 100644 index dfd02bfeb6122c..00000000000000 --- a/Libraries/ReactNative/requireFabricComponent.js +++ /dev/null @@ -1,234 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule requireFabricComponent - * @flow - * @format - */ -'use strict'; - -const Platform = require('Platform'); -const {createReactNativeComponentClass} = require('ReactFabricInternals'); -const ReactNativeStyleAttributes = require('ReactNativeStyleAttributes'); -const UIManager = require('UIManager'); - -const insetsDiffer = require('insetsDiffer'); -const matricesDiffer = require('matricesDiffer'); -const pointsDiffer = require('pointsDiffer'); -const processColor = require('processColor'); -const resolveAssetSource = require('resolveAssetSource'); -const sizesDiffer = require('sizesDiffer'); -const verifyPropTypes = require('verifyPropTypes'); -const invariant = require('fbjs/lib/invariant'); -const warning = require('fbjs/lib/warning'); - -/** - * Used to create React components that directly wrap native component - * implementations. Config information is extracted from data exported from the - * UIManager module. You should also wrap the native component in a - * hand-written component with full propTypes definitions and other - * documentation - pass the hand-written component in as `componentInterface` to - * verify all the native props are documented via `propTypes`. - * - * If some native props shouldn't be exposed in the wrapper interface, you can - * pass null for `componentInterface` and call `verifyPropTypes` directly - * with `nativePropsToIgnore`; - * - * Common types are lined up with the appropriate prop differs with - * `TypeToDifferMap`. Non-scalar types not in the map default to `deepDiffer`. - */ -import type {ComponentInterface} from 'verifyPropTypes'; - -let hasAttachedDefaultEventTypes: boolean = false; - -function requireNativeComponent( - viewName: string, - componentInterface?: ?ComponentInterface, - extraConfig?: ?{nativeOnly?: Object}, -): React$ComponentType | string { - 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) { - // Lazy view managers enabled. - viewConfig = merge(viewConfig, UIManager.getDefaultEventTypes()); - } else { - viewConfig.bubblingEventTypes = merge( - viewConfig.bubblingEventTypes, - UIManager.genericBubblingEventTypes, - ); - viewConfig.directEventTypes = merge( - viewConfig.directEventTypes, - UIManager.genericDirectEventTypes, - ); - } - } - - function merge(destination: ?Object, source: ?Object): ?Object { - if (!source) { - return destination; - } - if (!destination) { - return source; - } - - for (const key in source) { - if (!source.hasOwnProperty(key)) { - continue; - } - - var sourceValue = source[key]; - if (destination.hasOwnProperty(key)) { - const destinationValue = destination[key]; - if ( - typeof sourceValue === 'object' && - typeof destinationValue === 'object' - ) { - sourceValue = merge(destinationValue, sourceValue); - } - } - destination[key] = sourceValue; - } - return destination; - } - - // Don't load the ViewConfig from UIManager until it's needed for rendering. - // Lazy-loading this can help avoid Prepack deopts. - function getViewConfig() { - const viewConfig = UIManager[viewName]; - - invariant( - viewConfig != null && !viewConfig.NativeProps != null, - 'Native component for "%s" does not exist', - viewName, - ); - - viewConfig.uiViewClassName = viewName; - viewConfig.validAttributes = {}; - - // ReactNative `View.propTypes` have been deprecated in favor of - // `ViewPropTypes`. In their place a temporary getter has been added with a - // deprecated warning message. Avoid triggering that warning here by using - // temporary workaround, __propTypesSecretDontUseThesePlease. - // TODO (bvaughn) Revert this particular change any time after April 1 - if (componentInterface) { - viewConfig.propTypes = - /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an - * error found when Flow v0.68 was deployed. To see the error delete - * this comment and run Flow. */ - typeof componentInterface.__propTypesSecretDontUseThesePlease === - 'object' - ? componentInterface.__propTypesSecretDontUseThesePlease - : componentInterface.propTypes; - } else { - viewConfig.propTypes = null; - } - - let baseModuleName = viewConfig.baseModuleName; - let bubblingEventTypes = viewConfig.bubblingEventTypes; - let directEventTypes = viewConfig.directEventTypes; - let nativeProps = viewConfig.NativeProps; - while (baseModuleName) { - const baseModule = UIManager[baseModuleName]; - if (!baseModule) { - warning(false, 'Base module "%s" does not exist', baseModuleName); - baseModuleName = null; - } else { - bubblingEventTypes = { - ...baseModule.bubblingEventTypes, - ...bubblingEventTypes, - }; - directEventTypes = { - ...baseModule.directEventTypes, - ...directEventTypes, - }; - nativeProps = { - ...baseModule.NativeProps, - ...nativeProps, - }; - baseModuleName = baseModule.baseModuleName; - } - } - - viewConfig.bubblingEventTypes = bubblingEventTypes; - viewConfig.directEventTypes = directEventTypes; - - for (const key in nativeProps) { - let useAttribute = false; - const attribute = {}; - - const differ = TypeToDifferMap[nativeProps[key]]; - if (differ) { - attribute.diff = differ; - useAttribute = true; - } - - const processor = TypeToProcessorMap[nativeProps[key]]; - if (processor) { - attribute.process = processor; - useAttribute = true; - } - - viewConfig.validAttributes[key] = useAttribute ? attribute : true; - } - - // Unfortunately, the current set up puts the style properties on the top - // level props object. We also need to add the nested form for API - // compatibility. This allows these props on both the top level and the - // nested style level. TODO: Move these to nested declarations on the - // native side. - viewConfig.validAttributes.style = ReactNativeStyleAttributes; - - if (__DEV__) { - componentInterface && - verifyPropTypes( - componentInterface, - viewConfig, - extraConfig && extraConfig.nativeOnly, - ); - } - - if (!hasAttachedDefaultEventTypes) { - attachDefaultEventTypes(viewConfig); - hasAttachedDefaultEventTypes = true; - } - - return viewConfig; - } - - return createReactNativeComponentClass(viewName, getViewConfig); -} - -const TypeToDifferMap = { - // iOS Types - CATransform3D: matricesDiffer, - CGPoint: pointsDiffer, - CGSize: sizesDiffer, - UIEdgeInsets: insetsDiffer, - // Android Types - // (not yet implemented) -}; - -function processColorArray(colors: ?Array): ?Array { - return colors && colors.map(processColor); -} - -const TypeToProcessorMap = { - // iOS Types - CGColor: processColor, - CGColorArray: processColorArray, - UIColor: processColor, - UIColorArray: processColorArray, - CGImage: resolveAssetSource, - UIImage: resolveAssetSource, - RCTImageSource: resolveAssetSource, - // Android Types - Color: processColor, - ColorArray: processColorArray, -}; - -module.exports = requireNativeComponent; diff --git a/Libraries/Text/FabricText.js b/Libraries/Text/FabricText.js deleted file mode 100644 index 2b6748749b7e74..00000000000000 --- a/Libraries/Text/FabricText.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule FabricText - * @flow - * @format - */ -'use strict'; - -module.exports = require('Text'); From 88139eb6e18ec268b1ba1e4f373992be33b5aae7 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Thu, 12 Apr 2018 09:50:55 -0700 Subject: [PATCH 0287/1109] rename unmountComponentAtNodeAndRemoveContainer -> unmountComponentAtNode Reviewed By: achen1 Differential Revision: D7597730 fbshipit-source-id: d72a138b3fc82b09ab7b871089356d38c8405631 --- .../src/main/java/com/facebook/react/ReactInstanceManager.java | 2 +- .../java/com/facebook/react/modules/fabric/ReactFabric.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java index d2dbda4dd6d9e0..250f2091af7250 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java @@ -1033,7 +1033,7 @@ private void detachViewFromInstance( UiThreadUtil.assertOnUiThread(); if (rootView.isFabric()) { catalystInstance.getJSModule(ReactFabric.class) - .unmountComponentAtNodeAndRemoveContainer(rootView.getId()); + .unmountComponentAtNode(rootView.getId()); } else { catalystInstance.getJSModule(AppRegistry.class) .unmountApplicationComponentAtRootTag(rootView.getId()); diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/fabric/ReactFabric.java b/ReactAndroid/src/main/java/com/facebook/react/modules/fabric/ReactFabric.java index 888e9bafda3e62..fd0896bdd6fd8a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/fabric/ReactFabric.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/fabric/ReactFabric.java @@ -13,6 +13,6 @@ public interface ReactFabric extends JavaScriptModule { * JS method used to unmount Fabric surfaces. * @param rootTag {@link int} react tag of Root {@link com.facebook.react.uimanager.ReactShadowNode} */ - void unmountComponentAtNodeAndRemoveContainer(int rootTag); + void unmountComponentAtNode(int rootTag); } From 4fbd244b9a6b62e0efe1b4b5a7ec3de468f020f6 Mon Sep 17 00:00:00 2001 From: Aaron Brager Date: Thu, 12 Apr 2018 11:40:33 -0700 Subject: [PATCH 0288/1109] Suggest git apply --reject for failed upgrades Summary: The upgrade script uses `git apply --3way`: https://github.com/facebook/react-native/blob/4906f8d28cdbaf1b432494b473a4c61c1e193881/react-native-git-upgrade/cliEntry.js#L368-L369 If you've already upgraded something that React Native upgraded, this will silently fail. For example if you have already upgraded Gradle to the version available in the new version of React Native, the 3-way patch will fail. In this case, the upgraded version is installed into `node_modules` but `package.json` is not updated. More context, discussion, and information is in https://github.com/facebook/react-native/issues/12112#issuecomment-292619346. Until a more robust solution is implemented, this PR proposes to mitigate the effects of the problem by informing the user of the possible issue and instructing them of a workaround. In an affected project, I ran `react-native-git-upgrade` after applying my patch. As expected, I now receive the following output: ![image](https://user-images.githubusercontent.com/789577/38165770-6209ac68-34de-11e8-9d96-7c782e9ef7ce.png) After running the suggested command, `git status` now shows me the two rejections: ![image](https://user-images.githubusercontent.com/789577/38165796-d10ca7c8-34de-11e8-9037-8427513e3a84.png) And I can now [manually apply](https://stackoverflow.com/a/28569128/1445366) these changes. [CLI] [ENHANCEMENT] [react-native-git-upgrade/cliEntry.js] - Provide instructions for upgrading React Native when 3-way merges don't apply Closes https://github.com/facebook/react-native/pull/18636 Differential Revision: D7603073 Pulled By: hramos fbshipit-source-id: 32d387e1ee67d8b182d248c585cd33ba94808357 --- react-native-git-upgrade/cliEntry.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/react-native-git-upgrade/cliEntry.js b/react-native-git-upgrade/cliEntry.js index a9cbfa5641f369..49f9d53b4807ee 100644 --- a/react-native-git-upgrade/cliEntry.js +++ b/react-native-git-upgrade/cliEntry.js @@ -376,7 +376,9 @@ async function run(requestedVersion, cliArgs) { } catch (err) { log.warn( 'The upgrade process succeeded but there might be conflicts to be resolved. ' + - 'See above for the list of files that have merge conflicts.'); + 'See above for the list of files that have merge conflicts. ' + + 'If you don’t see the expected changes, try running:\n' + + `git apply --reject ${patchPath}`); } finally { log.info('Upgrade done'); if (cliArgs.verbose) { From f6e2f13f4b8c92e96c6fd72b910341240a7d84a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leo=20Nikkil=C3=A4?= Date: Thu, 12 Apr 2018 13:44:45 -0700 Subject: [PATCH 0289/1109] Handle layout updates during LayoutAnimation animations on Android MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: On Android, LayoutAnimation directly updates the layout since a generic scaling animation is more difficult to implement. This causes a problem if the layout is updated during an animation, as the previous layout is stored with the animation and is not updated. As a result the view gets the old layout instead once the animation completes. This commit fixes this issue by storing the layout handling animations while those animations are active, and updating the animations on the fly if one of the views receives a new layout. The resulting behaviour mirrors what iOS currently does. This bug has real world consequences, for example if a LayoutAnimation happens right after a VirtualizedList has mounted, it’s possible that some list rows are mounted while the animation is active, making the list content view bigger. If the content view is being animated, the new size will not take effect and it becomes impossible to scroll to the end of the list. I wrote a minimal test case to verify the bug, which I’ve also added to RNTester. You can find the standalone app here: The app creates a 100x300 view that gets animated to 200x300 using LayoutAnimation. In the middle of that animation, the view’s dimensions are updated to 300x300. The expected result (which is currently exhibited by iOS) is that the view’s dimensions after the animation would be 300x300. On Android the view keeps the 200x300 dimensions since the animation overrides the layout update. The test app could probably be turned into an integration test by measuring the view through UIManager after the animation, however I don’t have time to do that right now... Here are some GIFs to compare, click to expand:
Current master (iOS vs Android)

With this patch (iOS vs Android, fixed)

No documentation changes needed. [ANDROID] [BUGFIX] [LayoutAnimation] - View layout is updated correctly during an ongoing LayoutAnimation, mirroring iOS behaviour. Closes https://github.com/facebook/react-native/pull/18651 Differential Revision: D7604698 Pulled By: hramos fbshipit-source-id: 4d114682fd540419b7447e999910e05726f42b39 --- RNTester/js/LayoutAnimationExample.js | 56 +++++++++++++++++++ .../layoutanimation/HandlesLayout.java | 10 ---- .../LayoutAnimationController.java | 36 +++++++++++- .../LayoutHandlingAnimation.java | 20 +++++++ .../PositionAndSizeAnimation.java | 36 +++++++----- 5 files changed, 133 insertions(+), 25 deletions(-) delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/HandlesLayout.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutHandlingAnimation.java diff --git a/RNTester/js/LayoutAnimationExample.js b/RNTester/js/LayoutAnimationExample.js index 92134409879afe..d815712bba4f0b 100644 --- a/RNTester/js/LayoutAnimationExample.js +++ b/RNTester/js/LayoutAnimationExample.js @@ -102,6 +102,57 @@ class CrossFadeExample extends React.Component<{}, $FlowFixMeState> { } } +class LayoutUpdateExample extends React.Component<{}, $FlowFixMeState> { + state = { + width: 200, + height: 100, + }; + + timeout = null; + + componentWillUnmount() { + this._clearTimeout(); + } + + _clearTimeout = () => { + if (this.timeout !== null) { + clearTimeout(this.timeout); + this.timeout = null; + } + } + + _onPressToggle = () => { + this._clearTimeout(); + this.setState({width: 150}); + + LayoutAnimation.configureNext({ + duration: 1000, + update: { + type: LayoutAnimation.Types.linear, + }, + }); + + this.timeout = setTimeout(() => this.setState({width: 100}), 500); + }; + + render() { + const {width, height} = this.state; + + return ( + + + + Make box square + + + + {width}x{height} + + + ); + } +} + const styles = StyleSheet.create({ container: { flex: 1, @@ -156,4 +207,9 @@ exports.examples = [{ render(): React.Element { return ; }, +}, { + title: 'Layout update during animation', + render(): React.Element { + return ; + }, }]; diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/HandlesLayout.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/HandlesLayout.java deleted file mode 100644 index 9f3c907e97d079..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/HandlesLayout.java +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -package com.facebook.react.uimanager.layoutanimation; - -/** - * Marker interface to indicate a given animation type takes care of updating the view layout. - */ -/* package */ interface HandleLayout { - -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationController.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationController.java index d5a08e6b264ac5..7c88514f90031e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationController.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationController.java @@ -5,6 +5,7 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.NotThreadSafe; +import android.util.SparseArray; import android.view.View; import android.view.ViewGroup; import android.view.animation.Animation; @@ -27,6 +28,7 @@ public class LayoutAnimationController { private final AbstractLayoutAnimation mLayoutCreateAnimation = new LayoutCreateAnimation(); private final AbstractLayoutAnimation mLayoutUpdateAnimation = new LayoutUpdateAnimation(); private final AbstractLayoutAnimation mLayoutDeleteAnimation = new LayoutDeleteAnimation(); + private final SparseArray mLayoutHandlers = new SparseArray<>(0); private boolean mShouldAnimateLayout; public void initializeFromConfig(final @Nullable ReadableMap config) { @@ -68,7 +70,10 @@ public void reset() { public boolean shouldAnimateLayout(View viewToAnimate) { // if view parent is null, skip animation: view have been clipped, we don't want animation to // resume when view is re-attached to parent, which is the standard android animation behavior. - return mShouldAnimateLayout && viewToAnimate.getParent() != null; + // If there's a layout handling animation going on, it should be animated nonetheless since the + // ongoing animation needs to be updated. + return (mShouldAnimateLayout && viewToAnimate.getParent() != null) + || mLayoutHandlers.get(viewToAnimate.getId()) != null; } /** @@ -85,6 +90,16 @@ public boolean shouldAnimateLayout(View viewToAnimate) { public void applyLayoutUpdate(View view, int x, int y, int width, int height) { UiThreadUtil.assertOnUiThread(); + final int reactTag = view.getId(); + LayoutHandlingAnimation existingAnimation = mLayoutHandlers.get(reactTag); + + // Update an ongoing animation if possible, otherwise the layout update would be ignored as + // the existing animation would still animate to the old layout. + if (existingAnimation != null) { + existingAnimation.onLayoutUpdate(x, y, width, height); + return; + } + // Determine which animation to use : if view is initially invisible, use create animation, // otherwise use update animation. This approach is easier than maintaining a list of tags // for recently created views. @@ -93,9 +108,26 @@ public void applyLayoutUpdate(View view, int x, int y, int width, int height) { mLayoutUpdateAnimation; Animation animation = layoutAnimation.createAnimation(view, x, y, width, height); - if (animation == null || !(animation instanceof HandleLayout)) { + + if (animation instanceof LayoutHandlingAnimation) { + animation.setAnimationListener(new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + mLayoutHandlers.put(reactTag, (LayoutHandlingAnimation) animation); + } + + @Override + public void onAnimationEnd(Animation animation) { + mLayoutHandlers.remove(reactTag); + } + + @Override + public void onAnimationRepeat(Animation animation) {} + }); + } else { view.layout(x, y, x + width, y + height); } + if (animation != null) { view.startAnimation(animation); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutHandlingAnimation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutHandlingAnimation.java new file mode 100644 index 00000000000000..69234e27029ac7 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutHandlingAnimation.java @@ -0,0 +1,20 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +package com.facebook.react.uimanager.layoutanimation; + +/** + * Interface for an animation type that takes care of updating the view layout. + */ +/* package */ interface LayoutHandlingAnimation { + /** + * Notifies the animation of a layout update in case one occurs during the animation. This + * avoids animating the view to the old layout since it's no longer correct; instead the + * animation should update and do whatever it can so that the final layout is correct. + * + * @param x the new X position for the view + * @param y the new Y position for the view + * @param width the new width value for the view + * @param height the new height value for the view + */ + void onLayoutUpdate(int x, int y, int width, int height); +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/PositionAndSizeAnimation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/PositionAndSizeAnimation.java index 1cb3e83ac6f858..9bce9f781627ed 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/PositionAndSizeAnimation.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/PositionAndSizeAnimation.java @@ -12,24 +12,15 @@ * layout passes occurring on every frame. * What we might want to try to do instead is use a combined ScaleAnimation and TranslateAnimation. */ -/* package */ class PositionAndSizeAnimation extends Animation implements HandleLayout { +/* package */ class PositionAndSizeAnimation extends Animation implements LayoutHandlingAnimation { private final View mView; - private final float mStartX, mStartY, mDeltaX, mDeltaY; - private final int mStartWidth, mStartHeight, mDeltaWidth, mDeltaHeight; + private float mStartX, mStartY, mDeltaX, mDeltaY; + private int mStartWidth, mStartHeight, mDeltaWidth, mDeltaHeight; public PositionAndSizeAnimation(View view, int x, int y, int width, int height) { mView = view; - - mStartX = view.getX() - view.getTranslationX(); - mStartY = view.getY() - view.getTranslationY(); - mStartWidth = view.getWidth(); - mStartHeight = view.getHeight(); - - mDeltaX = x - mStartX; - mDeltaY = y - mStartY; - mDeltaWidth = width - mStartWidth; - mDeltaHeight = height - mStartHeight; + calculateAnimation(x, y, width, height); } @Override @@ -45,8 +36,27 @@ protected void applyTransformation(float interpolatedTime, Transformation t) { Math.round(newY + newHeight)); } + @Override + public void onLayoutUpdate(int x, int y, int width, int height) { + // Layout changed during the animation, we should update our values so that the final layout + // is correct. + calculateAnimation(x, y, width, height); + } + @Override public boolean willChangeBounds() { return true; } + + private void calculateAnimation(int x, int y, int width, int height) { + mStartX = mView.getX() - mView.getTranslationX(); + mStartY = mView.getY() - mView.getTranslationY(); + mStartWidth = mView.getWidth(); + mStartHeight = mView.getHeight(); + + mDeltaX = x - mStartX; + mDeltaY = y - mStartY; + mDeltaWidth = width - mStartWidth; + mDeltaHeight = height - mStartHeight; + } } From 3e92073afc16b79a97ca050a969bb973da87a129 Mon Sep 17 00:00:00 2001 From: Jakub Grzmiel Date: Thu, 12 Apr 2018 14:19:28 -0700 Subject: [PATCH 0290/1109] Handle processColor in routes Reviewed By: shergin Differential Revision: D6646858 fbshipit-source-id: c709464699482ef0c0b77434560612b99716074f --- Libraries/{StyleSheet => Color}/normalizeColor.js | 0 Libraries/Color/package.json | 5 +++++ 2 files changed, 5 insertions(+) rename Libraries/{StyleSheet => Color}/normalizeColor.js (100%) create mode 100644 Libraries/Color/package.json diff --git a/Libraries/StyleSheet/normalizeColor.js b/Libraries/Color/normalizeColor.js similarity index 100% rename from Libraries/StyleSheet/normalizeColor.js rename to Libraries/Color/normalizeColor.js diff --git a/Libraries/Color/package.json b/Libraries/Color/package.json new file mode 100644 index 00000000000000..1781e2e3d60bc2 --- /dev/null +++ b/Libraries/Color/package.json @@ -0,0 +1,5 @@ +{ + "name": "Color", + "private": true, + "version": "0.0.0" +} From e636eb60d7c8cff3a73183e02d9d457d32a6ec53 Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Thu, 12 Apr 2018 15:54:36 -0700 Subject: [PATCH 0291/1109] iOS OSS: added CocoaPods setup to RNTester and fix up the podspecs Summary: This adds a way to test out CocoaPods build to RNTester, but as a separate project/workspace. This also fixes the podspecs due to Fabric stuffs. Note that this setup is meant to be run manually, not by CI (yet) Reviewed By: mmmulani Differential Revision: D7603823 fbshipit-source-id: 2219aa4c77f40ec07097a5c9ed4052529226618b --- RNTester/.gitignore | 2 + RNTester/Podfile | 36 + RNTester/README.md | 8 + .../RNTesterPods.xcodeproj/project.pbxproj | 729 ++++++++++++++++++ React.podspec | 9 +- 5 files changed, 783 insertions(+), 1 deletion(-) create mode 100644 RNTester/.gitignore create mode 100644 RNTester/Podfile create mode 100644 RNTester/RNTesterPods.xcodeproj/project.pbxproj diff --git a/RNTester/.gitignore b/RNTester/.gitignore new file mode 100644 index 00000000000000..003be3341c3e66 --- /dev/null +++ b/RNTester/.gitignore @@ -0,0 +1,2 @@ +Podfile.lock +Pods/ diff --git a/RNTester/Podfile b/RNTester/Podfile new file mode 100644 index 00000000000000..1bcd939928b89f --- /dev/null +++ b/RNTester/Podfile @@ -0,0 +1,36 @@ +platform :ios, '8.0' + +target 'RNTester' do + # Uncomment for Swift + # use_frameworks! + + project 'RNTesterPods.xcodeproj' + + pod 'React', :path => '../', :subspecs => [ + 'ART', + 'Core', + 'CxxBridge', + 'DevSupport', + 'RCTActionSheet', + 'RCTAnimation', + 'RCTBlob', + 'RCTCameraRoll', + 'RCTGeolocation', + 'RCTImage', + 'RCTLinkingIOS', + 'RCTNetwork', + 'RCTPushNotification', + 'RCTSettings', + 'RCTText', + 'RCTVibration', + 'RCTWebSocket', + ] + + pod 'yoga', :path => '../ReactCommon/yoga' + + # Third party deps podspec link + pod 'DoubleConversion', :podspec => '../third-party-podspecs/DoubleConversion.podspec' + pod 'glog', :podspec => '../third-party-podspecs/glog.podspec' + pod 'Folly', :podspec => '../third-party-podspecs/Folly.podspec' + +end diff --git a/RNTester/README.md b/RNTester/README.md index 2b5642852f2e4d..b612a321532f7a 100644 --- a/RNTester/README.md +++ b/RNTester/README.md @@ -19,6 +19,14 @@ Mac OS and Xcode are required. See [Running on device](https://facebook.github.io/react-native/docs/running-on-device.html) if you want to use a physical device. +### Running on iOS with CocoaPods + +Similar to above, you can build the app via Xcode with help of CocoaPods. + +- Install [CocoaPods](http://facebook.github.io/react-native/docs/integration-with-existing-apps.html#3-install-cocoapods) +- Run `cd RNTester; pod install` +- Open the generated `RNTesterPods.xcworkspace` (this is not checked in). Do not open `RNTesterPods.xcodeproj` directly. + ### Running on Android You'll need to have all the [prerequisites](https://github.com/facebook/react-native/tree/master/ReactAndroid#prerequisites) (SDK, NDK) for Building React Native installed. diff --git a/RNTester/RNTesterPods.xcodeproj/project.pbxproj b/RNTester/RNTesterPods.xcodeproj/project.pbxproj new file mode 100644 index 00000000000000..054c9cc2e7e52d --- /dev/null +++ b/RNTester/RNTesterPods.xcodeproj/project.pbxproj @@ -0,0 +1,729 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; }; + 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; }; + 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; + 272E6B3F1BEA849E001FCF37 /* UpdatePropertiesExampleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 272E6B3C1BEA849E001FCF37 /* UpdatePropertiesExampleView.m */; }; + 27F441EC1BEBE5030039B79C /* FlexibleSizeExampleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 27F441E81BEBE5030039B79C /* FlexibleSizeExampleView.m */; }; + 2DD323DC1DA2DDBF000FE1B8 /* FlexibleSizeExampleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 27F441E81BEBE5030039B79C /* FlexibleSizeExampleView.m */; }; + 2DD323DD1DA2DDBF000FE1B8 /* UpdatePropertiesExampleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 272E6B3C1BEA849E001FCF37 /* UpdatePropertiesExampleView.m */; }; + 2DD323DE1DA2DDBF000FE1B8 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; }; + 2DD323E01DA2DDBF000FE1B8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; + 2DD323E11DA2DDBF000FE1B8 /* legacy_image@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3D2AFAF41D646CF80089D1A3 /* legacy_image@2x.png */; }; + 2DD323E21DA2DDBF000FE1B8 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB61A68108700A75B9A /* Info.plist */; }; + 2DDEF0101F84BF7B00DBDF73 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2DDEF00F1F84BF7B00DBDF73 /* Images.xcassets */; }; + 3D13F8481D6F6AF900E69E0E /* ImageInBundle.png in Resources */ = {isa = PBXBuildFile; fileRef = 3D13F8441D6F6AF200E69E0E /* ImageInBundle.png */; }; + 3D13F84A1D6F6AFD00E69E0E /* OtherImages.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3D13F8451D6F6AF200E69E0E /* OtherImages.xcassets */; }; + 3D2AFAF51D646CF80089D1A3 /* legacy_image@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3D2AFAF41D646CF80089D1A3 /* legacy_image@2x.png */; }; + 3D56F9F11D6F6E9B00F53A06 /* RNTesterBundle.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 3D13F83E1D6F6AE000E69E0E /* RNTesterBundle.bundle */; }; + EC31D453B972BC46FE559C89 /* libPods-RNTester.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6C062A1C08AD9375355BE47F /* libPods-RNTester.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 143BC59B1B21E3E100462512 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 13B07F861A680F5B00A75B9A; + remoteInfo = RNTester; + }; + 3D13F84B1D6F6B5F00E69E0E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 3D13F83D1D6F6AE000E69E0E; + remoteInfo = RNTesterBundle; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 13B07F961A680F5B00A75B9A /* RNTester.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RNTester.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = RNTester/AppDelegate.h; sourceTree = ""; }; + 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = RNTester/AppDelegate.m; sourceTree = ""; }; + 13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; + 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = RNTester/Info.plist; sourceTree = ""; }; + 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = RNTester/main.m; sourceTree = ""; }; + 272E6B3B1BEA849E001FCF37 /* UpdatePropertiesExampleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UpdatePropertiesExampleView.h; path = RNTester/NativeExampleViews/UpdatePropertiesExampleView.h; sourceTree = ""; }; + 272E6B3C1BEA849E001FCF37 /* UpdatePropertiesExampleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = UpdatePropertiesExampleView.m; path = RNTester/NativeExampleViews/UpdatePropertiesExampleView.m; sourceTree = ""; }; + 27F441E81BEBE5030039B79C /* FlexibleSizeExampleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FlexibleSizeExampleView.m; path = RNTester/NativeExampleViews/FlexibleSizeExampleView.m; sourceTree = ""; }; + 27F441EA1BEBE5030039B79C /* FlexibleSizeExampleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FlexibleSizeExampleView.h; path = RNTester/NativeExampleViews/FlexibleSizeExampleView.h; sourceTree = ""; }; + 2DDEF00F1F84BF7B00DBDF73 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = RNTester/Images.xcassets; sourceTree = ""; }; + 3D13F83E1D6F6AE000E69E0E /* RNTesterBundle.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RNTesterBundle.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 3D13F8401D6F6AE000E69E0E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = ../Info.plist; sourceTree = ""; }; + 3D13F8441D6F6AF200E69E0E /* ImageInBundle.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ImageInBundle.png; sourceTree = ""; }; + 3D13F8451D6F6AF200E69E0E /* OtherImages.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = OtherImages.xcassets; sourceTree = ""; }; + 3D2AFAF41D646CF80089D1A3 /* legacy_image@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "legacy_image@2x.png"; path = "RNTester/legacy_image@2x.png"; sourceTree = ""; }; + 5BEC8567F3741044B6A5EFC5 /* Pods-RNTester.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RNTester.release.xcconfig"; path = "Pods/Target Support Files/Pods-RNTester/Pods-RNTester.release.xcconfig"; sourceTree = ""; }; + 6C062A1C08AD9375355BE47F /* libPods-RNTester.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RNTester.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 98233960D1D6A1977D1C7EAF /* Pods-RNTester.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RNTester.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RNTester/Pods-RNTester.debug.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 004D289B1AAF61C70097A701 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + EC31D453B972BC46FE559C89 /* libPods-RNTester.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 143BC5921B21E3E100462512 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2D4624D91DA2EA6900C74D09 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2DD3238D1DA2DD8A000FE1B8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2DD323A21DA2DD8B000FE1B8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3D13F83B1D6F6AE000E69E0E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 1323F18D1C04ABAC0091BED0 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 3D2AFAF41D646CF80089D1A3 /* legacy_image@2x.png */, + 13B07FB61A68108700A75B9A /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 13B07FAE1A68108700A75B9A /* RNTester */ = { + isa = PBXGroup; + children = ( + 2DDEF00F1F84BF7B00DBDF73 /* Images.xcassets */, + 272E6B3A1BEA846C001FCF37 /* NativeExampleViews */, + 13B07FAF1A68108700A75B9A /* AppDelegate.h */, + 13B07FB01A68108700A75B9A /* AppDelegate.m */, + 13B07FB11A68108700A75B9A /* LaunchScreen.xib */, + 13B07FB71A68108700A75B9A /* main.m */, + 1323F18D1C04ABAC0091BED0 /* Supporting Files */, + ); + name = RNTester; + sourceTree = ""; + }; + 272E6B3A1BEA846C001FCF37 /* NativeExampleViews */ = { + isa = PBXGroup; + children = ( + 27F441E81BEBE5030039B79C /* FlexibleSizeExampleView.m */, + 27F441EA1BEBE5030039B79C /* FlexibleSizeExampleView.h */, + 272E6B3B1BEA849E001FCF37 /* UpdatePropertiesExampleView.h */, + 272E6B3C1BEA849E001FCF37 /* UpdatePropertiesExampleView.m */, + ); + name = NativeExampleViews; + sourceTree = ""; + }; + 2DE7E7D81FB2A4F3009E225D /* Frameworks */ = { + isa = PBXGroup; + children = ( + 6C062A1C08AD9375355BE47F /* libPods-RNTester.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + 3D13F83F1D6F6AE000E69E0E /* RNTesterBundle */ = { + isa = PBXGroup; + children = ( + 3D13F8401D6F6AE000E69E0E /* Info.plist */, + 3D13F8441D6F6AF200E69E0E /* ImageInBundle.png */, + 3D13F8451D6F6AF200E69E0E /* OtherImages.xcassets */, + ); + name = RNTesterBundle; + path = RNTester/RNTesterBundle; + sourceTree = ""; + }; + 571A4A20844C3BA40A3D302B /* Pods */ = { + isa = PBXGroup; + children = ( + 98233960D1D6A1977D1C7EAF /* Pods-RNTester.debug.xcconfig */, + 5BEC8567F3741044B6A5EFC5 /* Pods-RNTester.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; + 83CBB9F61A601CBA00E9B192 = { + isa = PBXGroup; + children = ( + 13B07FAE1A68108700A75B9A /* RNTester */, + 3D13F83F1D6F6AE000E69E0E /* RNTesterBundle */, + 83CBBA001A601CBA00E9B192 /* Products */, + 2DE7E7D81FB2A4F3009E225D /* Frameworks */, + 571A4A20844C3BA40A3D302B /* Pods */, + ); + indentWidth = 2; + sourceTree = ""; + tabWidth = 2; + usesTabs = 0; + }; + 83CBBA001A601CBA00E9B192 /* Products */ = { + isa = PBXGroup; + children = ( + 13B07F961A680F5B00A75B9A /* RNTester.app */, + 3D13F83E1D6F6AE000E69E0E /* RNTesterBundle.bundle */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 13B07F861A680F5B00A75B9A /* RNTester */ = { + isa = PBXNativeTarget; + buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "RNTester" */; + buildPhases = ( + F9CB97B0D9633939D43E75E0 /* [CP] Check Pods Manifest.lock */, + 13B07F871A680F5B00A75B9A /* Sources */, + 13B07F8C1A680F5B00A75B9A /* Frameworks */, + 13B07F8E1A680F5B00A75B9A /* Resources */, + 68CD48B71D2BCB2C007E06A9 /* Build JS Bundle */, + 5CF0FD27207FC6EC00C13D65 /* Start Metro */, + ); + buildRules = ( + ); + dependencies = ( + 3D13F84C1D6F6B5F00E69E0E /* PBXTargetDependency */, + ); + name = RNTester; + productName = "Hello World"; + productReference = 13B07F961A680F5B00A75B9A /* RNTester.app */; + productType = "com.apple.product-type.application"; + }; + 3D13F83D1D6F6AE000E69E0E /* RNTesterBundle */ = { + isa = PBXNativeTarget; + buildConfigurationList = 3D13F8411D6F6AE000E69E0E /* Build configuration list for PBXNativeTarget "RNTesterBundle" */; + buildPhases = ( + 3D13F83A1D6F6AE000E69E0E /* Sources */, + 3D13F83B1D6F6AE000E69E0E /* Frameworks */, + 3D13F83C1D6F6AE000E69E0E /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = RNTesterBundle; + productName = RNTesterBundle; + productReference = 3D13F83E1D6F6AE000E69E0E /* RNTesterBundle.bundle */; + productType = "com.apple.product-type.bundle"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 83CBB9F71A601CBA00E9B192 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0820; + ORGANIZATIONNAME = Facebook; + TargetAttributes = { + 004D289D1AAF61C70097A701 = { + CreatedOnToolsVersion = 6.1.1; + }; + 13B07F861A680F5B00A75B9A = { + DevelopmentTeam = V9WTTPBFK9; + }; + 143BC5941B21E3E100462512 = { + CreatedOnToolsVersion = 6.3.2; + TestTargetID = 13B07F861A680F5B00A75B9A; + }; + 2DD3238F1DA2DD8A000FE1B8 = { + CreatedOnToolsVersion = 8.0; + ProvisioningStyle = Automatic; + }; + 2DD323A41DA2DD8B000FE1B8 = { + CreatedOnToolsVersion = 8.0; + ProvisioningStyle = Automatic; + TestTargetID = 2DD3238F1DA2DD8A000FE1B8; + }; + 3D13F83D1D6F6AE000E69E0E = { + CreatedOnToolsVersion = 7.3.1; + }; + }; + }; + buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "RNTesterPods" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 83CBB9F61A601CBA00E9B192; + productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 13B07F861A680F5B00A75B9A /* RNTester */, + 3D13F83D1D6F6AE000E69E0E /* RNTesterBundle */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 004D289C1AAF61C70097A701 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 13B07F8E1A680F5B00A75B9A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3D56F9F11D6F6E9B00F53A06 /* RNTesterBundle.bundle in Resources */, + 2DDEF0101F84BF7B00DBDF73 /* Images.xcassets in Resources */, + 3D2AFAF51D646CF80089D1A3 /* legacy_image@2x.png in Resources */, + 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 143BC5931B21E3E100462512 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2D4624DB1DA2EA6900C74D09 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2DD3238E1DA2DD8A000FE1B8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2DD323E11DA2DDBF000FE1B8 /* legacy_image@2x.png in Resources */, + 2DD323E21DA2DDBF000FE1B8 /* Info.plist in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2DD323A31DA2DD8B000FE1B8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3D13F83C1D6F6AE000E69E0E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3D13F8481D6F6AF900E69E0E /* ImageInBundle.png in Resources */, + 3D13F84A1D6F6AFD00E69E0E /* OtherImages.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 2DD323EB1DA2DEC1000FE1B8 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "export NODE_BINARY=node\n$SRCROOT/../scripts/react-native-xcode.sh RNTester/js/RNTesterApp.ios.js"; + }; + 5CF0FD27207FC6EC00C13D65 /* Start Metro */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Start Metro"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open \"$SRCROOT/../scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi"; + showEnvVarsInLog = 0; + }; + 68CD48B71D2BCB2C007E06A9 /* Build JS Bundle */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Build JS Bundle"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "export NODE_BINARY=node\n$SRCROOT/../scripts/react-native-xcode.sh RNTester/js/RNTesterApp.ios.js"; + }; + F9CB97B0D9633939D43E75E0 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RNTester-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 004D289A1AAF61C70097A701 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 13B07F871A680F5B00A75B9A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 272E6B3F1BEA849E001FCF37 /* UpdatePropertiesExampleView.m in Sources */, + 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */, + 27F441EC1BEBE5030039B79C /* FlexibleSizeExampleView.m in Sources */, + 13B07FC11A68108700A75B9A /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 143BC5911B21E3E100462512 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2D4624C41DA2EA6900C74D09 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2DD3238C1DA2DD8A000FE1B8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2DD323DC1DA2DDBF000FE1B8 /* FlexibleSizeExampleView.m in Sources */, + 2DD323DD1DA2DDBF000FE1B8 /* UpdatePropertiesExampleView.m in Sources */, + 2DD323E01DA2DDBF000FE1B8 /* main.m in Sources */, + 2DD323DE1DA2DDBF000FE1B8 /* AppDelegate.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2DD323A11DA2DD8B000FE1B8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3D13F83A1D6F6AE000E69E0E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 143BC59C1B21E3E100462512 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 13B07F861A680F5B00A75B9A /* RNTester */; + targetProxy = 143BC59B1B21E3E100462512 /* PBXContainerItemProxy */; + }; + 3D13F84C1D6F6B5F00E69E0E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 3D13F83D1D6F6AE000E69E0E /* RNTesterBundle */; + targetProxy = 3D13F84B1D6F6B5F00E69E0E /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = { + isa = PBXVariantGroup; + children = ( + 13B07FB21A68108700A75B9A /* Base */, + ); + name = LaunchScreen.xib; + path = RNTester; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 13B07F941A680F5B00A75B9A /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 98233960D1D6A1977D1C7EAF /* Pods-RNTester.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = V9WTTPBFK9; + INFOPLIST_FILE = "$(SRCROOT)/RNTester/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + LIBRARY_SEARCH_PATHS = "$(inherited)"; + PRODUCT_BUNDLE_IDENTIFIER = com.facebook.react.uiapp; + PRODUCT_NAME = RNTester; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 13B07F951A680F5B00A75B9A /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5BEC8567F3741044B6A5EFC5 /* Pods-RNTester.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = V9WTTPBFK9; + INFOPLIST_FILE = "$(SRCROOT)/RNTester/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + LIBRARY_SEARCH_PATHS = "$(inherited)"; + PRODUCT_BUNDLE_IDENTIFIER = com.facebook.react.uiapp; + PRODUCT_NAME = RNTester; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 3D13F8421D6F6AE000E69E0E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + COMBINE_HIDPI_IMAGES = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = RNTester/RNTesterBundle/Info.plist; + PRODUCT_BUNDLE_IDENTIFIER = com.facebook.RNTesterBundle; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; + 3D13F8431D6F6AE000E69E0E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + COMBINE_HIDPI_IMAGES = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = RNTester/RNTesterBundle/Info.plist; + PRODUCT_BUNDLE_IDENTIFIER = com.facebook.RNTesterBundle; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; + 83CBBA201A601CBA00E9B192 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_ASSIGN_ENUM = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_NEWLINE = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_MULTIPLE_DEFINITION_TYPES_FOR_SELECTOR = YES; + GCC_WARN_SHADOW = YES; + GCC_WARN_STRICT_SELECTOR_MATCH = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNKNOWN_PRAGMAS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_LABEL = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + OTHER_LDFLAGS = ( + "-ObjC", + "-lc++", + ); + SDKROOT = iphoneos; + WARNING_CFLAGS = ( + "-Wextra", + "-Wall", + "-Wno-semicolon-before-method-body", + ); + }; + name = Debug; + }; + 83CBBA211A601CBA00E9B192 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_ASSIGN_ENUM = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_NEWLINE = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_MULTIPLE_DEFINITION_TYPES_FOR_SELECTOR = YES; + GCC_WARN_SHADOW = YES; + GCC_WARN_STRICT_SELECTOR_MATCH = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNKNOWN_PRAGMAS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_LABEL = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ( + "-ObjC", + "-lc++", + ); + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + WARNING_CFLAGS = ( + "-Wextra", + "-Wall", + "-Wno-semicolon-before-method-body", + ); + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "RNTester" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 13B07F941A680F5B00A75B9A /* Debug */, + 13B07F951A680F5B00A75B9A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 3D13F8411D6F6AE000E69E0E /* Build configuration list for PBXNativeTarget "RNTesterBundle" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3D13F8421D6F6AE000E69E0E /* Debug */, + 3D13F8431D6F6AE000E69E0E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "RNTesterPods" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 83CBBA201A601CBA00E9B192 /* Debug */, + 83CBBA211A601CBA00E9B192 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; +} diff --git a/React.podspec b/React.podspec index a9a4de5a523e3d..2aaae1826403c8 100644 --- a/React.podspec +++ b/React.podspec @@ -51,7 +51,7 @@ Pod::Spec.new do |s| "React/Inspector/*", "ReactCommon/yoga/*", "React/Cxx*/*", - "React/Fabric/*", + "React/Fabric/**/*", ss.ios.exclude_files = "React/**/RCTTV*.*" ss.tvos.exclude_files = "React/Modules/RCTClipboard*", "React/Views/RCTDatePicker*", @@ -73,6 +73,13 @@ Pod::Spec.new do |s| ss.compiler_flags = folly_compiler_flags ss.private_header_files = "React/Cxx*/*.h" ss.source_files = "React/Cxx*/*.{h,m,mm}" + ss.exclude_files = "React/CxxExceptions/**/*" + end + + s.subspec "CxxExceptions" do |ss| + ss.dependency "React/CxxBridge" + ss.private_header_files = "React/CxxExceptions/*.h" + ss.source_files = "React/CxxExceptions/*.{h,m,mm}" end s.subspec "DevSupport" do |ss| From 7500b3ec839ada6d8e1f7a88d30743dfb0ad7e70 Mon Sep 17 00:00:00 2001 From: Himabindu Gadupudi Date: Fri, 13 Apr 2018 12:19:57 -0700 Subject: [PATCH 0292/1109] Fix anti aliasing rounded background Reviewed By: shergin, achen1 Differential Revision: D7569885 fbshipit-source-id: 4bfb00485211417b475f14a92fd7b2e52a4b2ff6 --- .../view/ReactViewBackgroundDrawable.java | 197 ++++++++++-------- 1 file changed, 108 insertions(+), 89 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java index 9e374b4c502ecb..e9fa14494a3830 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java @@ -343,113 +343,132 @@ private void drawRoundedBackgroundWithBorders(Canvas canvas) { || borderWidth.bottom > 0 || borderWidth.left > 0 || borderWidth.right > 0) { - mPaint.setStyle(Paint.Style.FILL); - // Draw border - canvas.clipPath(mOuterClipPathForBorderRadius, Region.Op.INTERSECT); - canvas.clipPath(mInnerClipPathForBorderRadius, Region.Op.DIFFERENCE); + //If it's a full and even border draw inner rect path with stroke + final float fullBorderWidth = getFullBorderWidth(); + if (borderWidth.top == fullBorderWidth && + borderWidth.bottom == fullBorderWidth && + borderWidth.left == fullBorderWidth && + borderWidth.right == fullBorderWidth) { + if (fullBorderWidth > 0) { + int borderColor = getBorderColor(Spacing.ALL); + mPaint.setColor(ColorUtil.multiplyColorAlpha(borderColor, mAlpha)); + mPaint.setStyle(Paint.Style.STROKE); + mPaint.setStrokeWidth(fullBorderWidth); + canvas.drawPath(mInnerClipPathForBorderRadius, mPaint); + } + } + //In the case of uneven border widths/colors draw quadrilateral in each direction + else { + mPaint.setStyle(Paint.Style.FILL); - int colorLeft = getBorderColor(Spacing.LEFT); - int colorTop = getBorderColor(Spacing.TOP); - int colorRight = getBorderColor(Spacing.RIGHT); - int colorBottom = getBorderColor(Spacing.BOTTOM); + // Draw border + canvas.clipPath(mOuterClipPathForBorderRadius, Region.Op.INTERSECT); + canvas.clipPath(mInnerClipPathForBorderRadius, Region.Op.DIFFERENCE); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - final boolean isRTL = getResolvedLayoutDirection() == View.LAYOUT_DIRECTION_RTL; - int colorStart = getBorderColor(Spacing.START); - int colorEnd = getBorderColor(Spacing.END); - - if (I18nUtil.getInstance().doLeftAndRightSwapInRTL(mContext)) { - if (!isBorderColorDefined(Spacing.START)) { - colorStart = colorLeft; - } + int colorLeft = getBorderColor(Spacing.LEFT); + int colorTop = getBorderColor(Spacing.TOP); + int colorRight = getBorderColor(Spacing.RIGHT); + int colorBottom = getBorderColor(Spacing.BOTTOM); - if (!isBorderColorDefined(Spacing.END)) { - colorEnd = colorRight; - } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + final boolean isRTL = getResolvedLayoutDirection() == View.LAYOUT_DIRECTION_RTL; + int colorStart = getBorderColor(Spacing.START); + int colorEnd = getBorderColor(Spacing.END); - final int directionAwareColorLeft = isRTL ? colorEnd : colorStart; - final int directionAwareColorRight = isRTL ? colorStart : colorEnd; + if (I18nUtil.getInstance().doLeftAndRightSwapInRTL(mContext)) { + if (!isBorderColorDefined(Spacing.START)) { + colorStart = colorLeft; + } - colorLeft = directionAwareColorLeft; - colorRight = directionAwareColorRight; - } else { - final int directionAwareColorLeft = isRTL ? colorEnd : colorStart; - final int directionAwareColorRight = isRTL ? colorStart : colorEnd; + if (!isBorderColorDefined(Spacing.END)) { + colorEnd = colorRight; + } - final boolean isColorStartDefined = isBorderColorDefined(Spacing.START); - final boolean isColorEndDefined = isBorderColorDefined(Spacing.END); - final boolean isDirectionAwareColorLeftDefined = isRTL ? isColorEndDefined : isColorStartDefined; - final boolean isDirectionAwareColorRightDefined = isRTL ? isColorStartDefined : isColorEndDefined; + final int directionAwareColorLeft = isRTL ? colorEnd : colorStart; + final int directionAwareColorRight = isRTL ? colorStart : colorEnd; - if (isDirectionAwareColorLeftDefined) { colorLeft = directionAwareColorLeft; - } - - if (isDirectionAwareColorRightDefined) { colorRight = directionAwareColorRight; + } else { + final int directionAwareColorLeft = isRTL ? colorEnd : colorStart; + final int directionAwareColorRight = isRTL ? colorStart : colorEnd; + + final boolean isColorStartDefined = isBorderColorDefined(Spacing.START); + final boolean isColorEndDefined = isBorderColorDefined(Spacing.END); + final boolean isDirectionAwareColorLeftDefined = + isRTL ? isColorEndDefined : isColorStartDefined; + final boolean isDirectionAwareColorRightDefined = + isRTL ? isColorStartDefined : isColorEndDefined; + + if (isDirectionAwareColorLeftDefined) { + colorLeft = directionAwareColorLeft; + } + + if (isDirectionAwareColorRightDefined) { + colorRight = directionAwareColorRight; + } } } - } - final float left = mOuterClipTempRectForBorderRadius.left; - final float right = mOuterClipTempRectForBorderRadius.right; - final float top = mOuterClipTempRectForBorderRadius.top; - final float bottom = mOuterClipTempRectForBorderRadius.bottom; - - if (borderWidth.left > 0) { - final float x1 = left; - final float y1 = top; - final float x2 = mInnerTopLeftCorner.x; - final float y2 = mInnerTopLeftCorner.y; - final float x3 = mInnerBottomLeftCorner.x; - final float y3 = mInnerBottomLeftCorner.y; - final float x4 = left; - final float y4 = bottom; - - drawQuadrilateral(canvas, colorLeft, x1, y1, x2, y2, x3, y3, x4, y4); - } + final float left = mOuterClipTempRectForBorderRadius.left; + final float right = mOuterClipTempRectForBorderRadius.right; + final float top = mOuterClipTempRectForBorderRadius.top; + final float bottom = mOuterClipTempRectForBorderRadius.bottom; - if (borderWidth.top > 0) { - final float x1 = left; - final float y1 = top; - final float x2 = mInnerTopLeftCorner.x; - final float y2 = mInnerTopLeftCorner.y; - final float x3 = mInnerTopRightCorner.x; - final float y3 = mInnerTopRightCorner.y; - final float x4 = right; - final float y4 = top; - - drawQuadrilateral(canvas, colorTop, x1, y1, x2, y2, x3, y3, x4, y4); - } + if (borderWidth.left > 0) { + final float x1 = left; + final float y1 = top; + final float x2 = mInnerTopLeftCorner.x; + final float y2 = mInnerTopLeftCorner.y; + final float x3 = mInnerBottomLeftCorner.x; + final float y3 = mInnerBottomLeftCorner.y; + final float x4 = left; + final float y4 = bottom; - if (borderWidth.right > 0) { - final float x1 = right; - final float y1 = top; - final float x2 = mInnerTopRightCorner.x; - final float y2 = mInnerTopRightCorner.y; - final float x3 = mInnerBottomRightCorner.x; - final float y3 = mInnerBottomRightCorner.y; - final float x4 = right; - final float y4 = bottom; - - drawQuadrilateral(canvas, colorRight, x1, y1, x2, y2, x3, y3, x4, y4); - } + drawQuadrilateral(canvas, colorLeft, x1, y1, x2, y2, x3, y3, x4, y4); + } + + if (borderWidth.top > 0) { + final float x1 = left; + final float y1 = top; + final float x2 = mInnerTopLeftCorner.x; + final float y2 = mInnerTopLeftCorner.y; + final float x3 = mInnerTopRightCorner.x; + final float y3 = mInnerTopRightCorner.y; + final float x4 = right; + final float y4 = top; + + drawQuadrilateral(canvas, colorTop, x1, y1, x2, y2, x3, y3, x4, y4); + } + + if (borderWidth.right > 0) { + final float x1 = right; + final float y1 = top; + final float x2 = mInnerTopRightCorner.x; + final float y2 = mInnerTopRightCorner.y; + final float x3 = mInnerBottomRightCorner.x; + final float y3 = mInnerBottomRightCorner.y; + final float x4 = right; + final float y4 = bottom; - if (borderWidth.bottom > 0) { - final float x1 = left; - final float y1 = bottom; - final float x2 = mInnerBottomLeftCorner.x; - final float y2 = mInnerBottomLeftCorner.y; - final float x3 = mInnerBottomRightCorner.x; - final float y3 = mInnerBottomRightCorner.y; - final float x4 = right; - final float y4 = bottom; - - drawQuadrilateral(canvas, colorBottom, x1, y1, x2, y2, x3, y3, x4, y4); + drawQuadrilateral(canvas, colorRight, x1, y1, x2, y2, x3, y3, x4, y4); + } + + if (borderWidth.bottom > 0) { + final float x1 = left; + final float y1 = bottom; + final float x2 = mInnerBottomLeftCorner.x; + final float y2 = mInnerBottomLeftCorner.y; + final float x3 = mInnerBottomRightCorner.x; + final float y3 = mInnerBottomRightCorner.y; + final float x4 = right; + final float y4 = bottom; + + drawQuadrilateral(canvas, colorBottom, x1, y1, x2, y2, x3, y3, x4, y4); + } } } - canvas.restore(); } From af661e4a6f6583b4c2b372a22d71f41470760d93 Mon Sep 17 00:00:00 2001 From: Peter van der Zee Date: Fri, 13 Apr 2018 14:10:43 -0700 Subject: [PATCH 0293/1109] Add metro to paths to be babel-transformed Reviewed By: fkgozali Differential Revision: D7620341 fbshipit-source-id: fc801c938628f5b6b118b8250d5c63268e19359e --- setupBabel.js | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/setupBabel.js b/setupBabel.js index 15e0f19a458bb2..0b21ffe31f5c7d 100644 --- a/setupBabel.js +++ b/setupBabel.js @@ -11,7 +11,7 @@ const babelRegisterOnly = require('metro/src/babelRegisterOnly'); const escapeRegExp = require('lodash/escapeRegExp'); const path = require('path'); -const BABEL_ENABLED_PATHS = ['local-cli']; +const BABEL_ENABLED_PATHS = ['local-cli', 'metro']; /** * We use absolute paths for matching only the top-level folders reliably. For @@ -21,20 +21,24 @@ const BABEL_ENABLED_PATHS = ['local-cli']; function buildRegExps(basePath, dirPaths) { return dirPaths.map( folderPath => - // Babel `only` option works with forward slashes in the RegExp so replace - // backslashes for Windows. - folderPath instanceof RegExp - ? new RegExp( - `^${escapeRegExp( - path.resolve(basePath, '.').replace(/\\/g, '/') - )}/${folderPath.source}`, - folderPath.flags - ) - : new RegExp( - `^${escapeRegExp( - path.resolve(basePath, folderPath).replace(/\\/g, '/') - )}` - ) + folderPath === 'metro' + // metro uses flow (for example) which needs to be stripped out w/babel. + // it'll resolve to .../metro/packages/metro/src/index.js we want root + ? path.resolve(require.resolve('metro'), '..', '..', '..', '..') + // Babel `only` option works with forward slashes in the RegExp so replace + // backslashes for Windows. + : folderPath instanceof RegExp + ? new RegExp( + `^${escapeRegExp( + path.resolve(basePath, '.').replace(/\\/g, '/') + )}/${folderPath.source}`, + folderPath.flags + ) + : new RegExp( + `^${escapeRegExp( + path.resolve(basePath, folderPath).replace(/\\/g, '/') + )}` + ) ); } From e8e2a6e4102c1ba0ee3d068769e47fa61c160524 Mon Sep 17 00:00:00 2001 From: Himabindu Gadupudi Date: Fri, 13 Apr 2018 17:13:07 -0700 Subject: [PATCH 0294/1109] Add tint color to inline icons Reviewed By: achen1 Differential Revision: D7625378 fbshipit-source-id: a60cf79f32f2d4091dbddebd65af4880ebb8c2c7 --- .../FrescoBasedReactTextInlineImageShadowNode.java | 10 +++++++++- .../FrescoBasedReactTextInlineImageSpan.java | 9 +++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageShadowNode.java index c66f009714c8f2..301174772eac6f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageShadowNode.java @@ -41,6 +41,7 @@ public class FrescoBasedReactTextInlineImageShadowNode extends ReactTextInlineIm private final @Nullable Object mCallerContext; private float mWidth = YogaConstants.UNDEFINED; private float mHeight = YogaConstants.UNDEFINED; + private int mTintColor = 0; public FrescoBasedReactTextInlineImageShadowNode( AbstractDraweeControllerBuilder draweeControllerBuilder, @@ -54,6 +55,7 @@ private FrescoBasedReactTextInlineImageShadowNode(FrescoBasedReactTextInlineImag mHeaders = node.mHeaders; // mHeaders is immutable mWidth = node.mWidth; mHeight = node.mHeight; + mTintColor = node.mTintColor; mDraweeControllerBuilder = node.mDraweeControllerBuilder; mCallerContext = node.mCallerContext; mUri = node.mUri; @@ -94,6 +96,11 @@ public void setHeaders(ReadableMap headers) { mHeaders = headers; } + @ReactProp(name = "tintColor") + public void setTintColor(int tintColor) { + mTintColor = tintColor; + } + /** * Besides width/height, all other layout props on inline images are ignored */ @@ -116,7 +123,7 @@ public void setHeight(Dynamic height) { "Inline images must not have percentage based height"); } } - + public @Nullable Uri getUri() { return mUri; } @@ -155,6 +162,7 @@ public TextInlineImageSpan buildInlineImageSpan() { resources, height, width, + mTintColor, getUri(), getHeaders(), getDraweeControllerBuilder(), diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageSpan.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageSpan.java index da53a968703fa8..d769d50fce99af 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageSpan.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageSpan.java @@ -7,6 +7,8 @@ package com.facebook.react.views.text.frescosupport; +import android.graphics.Color; +import android.graphics.PorterDuff; import javax.annotation.Nullable; import android.content.res.Resources; @@ -46,6 +48,7 @@ public class FrescoBasedReactTextInlineImageSpan extends TextInlineImageSpan { private final @Nullable Object mCallerContext; private int mHeight; + private int mTintColor; private Uri mUri; private int mWidth; private ReadableMap mHeaders; @@ -56,6 +59,7 @@ public FrescoBasedReactTextInlineImageSpan( Resources resources, int height, int width, + int tintColor, @Nullable Uri uri, ReadableMap headers, AbstractDraweeControllerBuilder draweeControllerBuilder, @@ -68,6 +72,7 @@ public FrescoBasedReactTextInlineImageSpan( mCallerContext = callerContext; mHeight = height; + mTintColor = tintColor; mWidth = width; mUri = (uri != null) ? uri : Uri.EMPTY; mHeaders = headers; @@ -143,7 +148,11 @@ public void draw( mDrawable = mDraweeHolder.getTopLevelDrawable(); mDrawable.setBounds(0, 0, mWidth, mHeight); + if(mTintColor != 0) { + mDrawable.setColorFilter(mTintColor, PorterDuff.Mode.SRC_IN); + } mDrawable.setCallback(mTextView); + } // NOTE: This drawing code is copied from DynamicDrawableSpan From cc57b7b1d36f7827ee545a38dd6a51cbfe0e1dae Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Fri, 13 Apr 2018 17:19:01 -0700 Subject: [PATCH 0295/1109] iOS OSS: check in the Podfile.lock Summary: Should have been checked in previously. No setup change here. Reviewed By: shergin Differential Revision: D7626040 fbshipit-source-id: e7a1a9de70a40a22e39eb3777d1b62c8d7b66381 --- RNTester/.gitignore | 1 - RNTester/Podfile.lock | 112 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 RNTester/Podfile.lock diff --git a/RNTester/.gitignore b/RNTester/.gitignore index 003be3341c3e66..389a2b20c85b1c 100644 --- a/RNTester/.gitignore +++ b/RNTester/.gitignore @@ -1,2 +1 @@ -Podfile.lock Pods/ diff --git a/RNTester/Podfile.lock b/RNTester/Podfile.lock new file mode 100644 index 00000000000000..64196db77f109f --- /dev/null +++ b/RNTester/Podfile.lock @@ -0,0 +1,112 @@ +PODS: + - boost-for-react-native (1.63.0) + - DoubleConversion (1.1.5) + - Folly (2016.09.26.00): + - boost-for-react-native + - DoubleConversion + - glog + - glog (0.3.4) + - React/ART (1000.0.0): + - React/Core + - React/Core (1000.0.0): + - yoga (= 1000.0.0.React) + - React/CxxBridge (1000.0.0): + - Folly (= 2016.09.26.00) + - React/Core + - React/cxxreact + - React/cxxreact (1000.0.0): + - boost-for-react-native (= 1.63.0) + - Folly (= 2016.09.26.00) + - React/jschelpers + - React/jsinspector + - React/DevSupport (1000.0.0): + - React/Core + - React/RCTWebSocket + - React/fishhook (1000.0.0) + - React/jschelpers (1000.0.0): + - Folly (= 2016.09.26.00) + - React/PrivateDatabase + - React/jsinspector (1000.0.0) + - React/PrivateDatabase (1000.0.0) + - React/RCTActionSheet (1000.0.0): + - React/Core + - React/RCTAnimation (1000.0.0): + - React/Core + - React/RCTBlob (1000.0.0): + - React/Core + - React/RCTCameraRoll (1000.0.0): + - React/Core + - React/RCTImage + - React/RCTGeolocation (1000.0.0): + - React/Core + - React/RCTImage (1000.0.0): + - React/Core + - React/RCTNetwork + - React/RCTLinkingIOS (1000.0.0): + - React/Core + - React/RCTNetwork (1000.0.0): + - React/Core + - React/RCTPushNotification (1000.0.0): + - React/Core + - React/RCTSettings (1000.0.0): + - React/Core + - React/RCTText (1000.0.0): + - React/Core + - React/RCTVibration (1000.0.0): + - React/Core + - React/RCTWebSocket (1000.0.0): + - React/Core + - React/fishhook + - React/RCTBlob + - yoga (1000.0.0.React) + +DEPENDENCIES: + - DoubleConversion (from `../third-party-podspecs/DoubleConversion.podspec`) + - Folly (from `../third-party-podspecs/Folly.podspec`) + - glog (from `../third-party-podspecs/glog.podspec`) + - React/ART (from `../`) + - React/Core (from `../`) + - React/CxxBridge (from `../`) + - React/DevSupport (from `../`) + - React/RCTActionSheet (from `../`) + - React/RCTAnimation (from `../`) + - React/RCTBlob (from `../`) + - React/RCTCameraRoll (from `../`) + - React/RCTGeolocation (from `../`) + - React/RCTImage (from `../`) + - React/RCTLinkingIOS (from `../`) + - React/RCTNetwork (from `../`) + - React/RCTPushNotification (from `../`) + - React/RCTSettings (from `../`) + - React/RCTText (from `../`) + - React/RCTVibration (from `../`) + - React/RCTWebSocket (from `../`) + - yoga (from `../ReactCommon/yoga`) + +SPEC REPOS: + https://github.com/CocoaPods/Specs.git: + - boost-for-react-native + +EXTERNAL SOURCES: + DoubleConversion: + :podspec: "../third-party-podspecs/DoubleConversion.podspec" + Folly: + :podspec: "../third-party-podspecs/Folly.podspec" + glog: + :podspec: "../third-party-podspecs/glog.podspec" + React: + :path: "../" + yoga: + :path: "../ReactCommon/yoga" + +SPEC CHECKSUMS: + boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c + DoubleConversion: e22e0762848812a87afd67ffda3998d9ef29170c + Folly: 211775e49d8da0ca658aebc8eab89d642935755c + glog: 1de0bb937dccdc981596d3b5825ebfb765017ded + React: b5ea2f2f4800bbae06eaa2f11e5709fd1958f7bf + yoga: bdd268c5812f00bdb52cc2b58f129797e97935eb + +PODFILE CHECKSUM: 2db1aae50ba1389ea02bbb867efcf85182b0336a + +COCOAPODS: 1.5.0 From f569b45f4cdd72cca7e8c4eefcb59485ffe6022f Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Fri, 13 Apr 2018 17:19:02 -0700 Subject: [PATCH 0296/1109] OSS: upgrade Folly 2016.09.26 => 2016.10.31 Summary: There was a fix around folly::dynamic constructor that will be needed for Fabric work. This was done in https://github.com/facebook/folly/commit/94e964976c1b65e79b0f7bdd960cfec260399a52#diff-7d1cb97d222ba0c863ea8a8e43b2ee2b and luckily the release 1 month after the Folly version we used in RN already had the fix, so that we don't need to upgrade to the latest folly yet (minimizing breakages). Tested by: * running RNTester xcode project (ios) * running RNTesterPods workspace via cocoapods * building android via gradle Reviewed By: shergin Differential Revision: D7626037 fbshipit-source-id: cb36ba5b91ba131d4e450300bd620db657cfa1e8 --- RNTester/Podfile.lock | 12 ++++---- React.podspec | 7 +++-- React/React.xcodeproj/project.pbxproj | 40 +++++++++++++-------------- React/third-party.xcconfig | 2 +- ReactAndroid/build.gradle | 8 +++--- scripts/ios-install-third-party.sh | 2 +- third-party-podspecs/Folly.podspec | 2 +- 7 files changed, 37 insertions(+), 36 deletions(-) diff --git a/RNTester/Podfile.lock b/RNTester/Podfile.lock index 64196db77f109f..5f5a3acb769e96 100644 --- a/RNTester/Podfile.lock +++ b/RNTester/Podfile.lock @@ -1,7 +1,7 @@ PODS: - boost-for-react-native (1.63.0) - DoubleConversion (1.1.5) - - Folly (2016.09.26.00): + - Folly (2016.10.31.00): - boost-for-react-native - DoubleConversion - glog @@ -11,12 +11,12 @@ PODS: - React/Core (1000.0.0): - yoga (= 1000.0.0.React) - React/CxxBridge (1000.0.0): - - Folly (= 2016.09.26.00) + - Folly (= 2016.10.31.00) - React/Core - React/cxxreact - React/cxxreact (1000.0.0): - boost-for-react-native (= 1.63.0) - - Folly (= 2016.09.26.00) + - Folly (= 2016.10.31.00) - React/jschelpers - React/jsinspector - React/DevSupport (1000.0.0): @@ -24,7 +24,7 @@ PODS: - React/RCTWebSocket - React/fishhook (1000.0.0) - React/jschelpers (1000.0.0): - - Folly (= 2016.09.26.00) + - Folly (= 2016.10.31.00) - React/PrivateDatabase - React/jsinspector (1000.0.0) - React/PrivateDatabase (1000.0.0) @@ -102,9 +102,9 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c DoubleConversion: e22e0762848812a87afd67ffda3998d9ef29170c - Folly: 211775e49d8da0ca658aebc8eab89d642935755c + Folly: 9a8eea4725a0b6ba3256ebf206c21e352c23abf8 glog: 1de0bb937dccdc981596d3b5825ebfb765017ded - React: b5ea2f2f4800bbae06eaa2f11e5709fd1958f7bf + React: 4e8050da47914f710f7bf48d1aca39fd9afafe39 yoga: bdd268c5812f00bdb52cc2b58f129797e97935eb PODFILE CHECKSUM: 2db1aae50ba1389ea02bbb867efcf85182b0336a diff --git a/React.podspec b/React.podspec index 2aaae1826403c8..ac3df357ad1ced 100644 --- a/React.podspec +++ b/React.podspec @@ -13,6 +13,7 @@ else end folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1' +folly_version = '2016.10.31.00' Pod::Spec.new do |s| s.name = "React" @@ -67,7 +68,7 @@ Pod::Spec.new do |s| end s.subspec "CxxBridge" do |ss| - ss.dependency "Folly", "2016.09.26.00" + ss.dependency "Folly", folly_version ss.dependency "React/Core" ss.dependency "React/cxxreact" ss.compiler_flags = folly_compiler_flags @@ -95,7 +96,7 @@ Pod::Spec.new do |s| end s.subspec "jschelpers" do |ss| - ss.dependency "Folly", "2016.09.26.00" + ss.dependency "Folly", folly_version ss.dependency "React/PrivateDatabase" ss.compiler_flags = folly_compiler_flags ss.source_files = "ReactCommon/jschelpers/*.{cpp,h}" @@ -120,7 +121,7 @@ Pod::Spec.new do |s| ss.dependency "React/jschelpers" ss.dependency "React/jsinspector" ss.dependency "boost-for-react-native", "1.63.0" - ss.dependency "Folly", "2016.09.26.00" + ss.dependency "Folly", folly_version ss.compiler_flags = folly_compiler_flags ss.source_files = "ReactCommon/cxxreact/*.{cpp,h}" ss.exclude_files = "ReactCommon/cxxreact/SampleCxxModule.*" diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj index e9d07dd8d9e8ff..5232e06f72a0b2 100644 --- a/React/React.xcodeproj/project.pbxproj +++ b/React/React.xcodeproj/project.pbxproj @@ -1946,21 +1946,21 @@ 139D7F141E25DEC900323FB7 /* raw_logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = raw_logging.h; sourceTree = ""; }; 139D7F161E25DEC900323FB7 /* stl_logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stl_logging.h; sourceTree = ""; }; 139D7F181E25DEC900323FB7 /* vlog_is_on.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vlog_is_on.h; sourceTree = ""; }; - 139D849C1E273B5600323FB7 /* AtomicIntrusiveLinkedList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AtomicIntrusiveLinkedList.h; path = "folly-2016.09.26.00/folly/AtomicIntrusiveLinkedList.h"; sourceTree = ""; }; - 139D849D1E273B5600323FB7 /* Bits.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Bits.cpp; path = "folly-2016.09.26.00/folly/Bits.cpp"; sourceTree = ""; }; - 139D849E1E273B5600323FB7 /* Bits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Bits.h; path = "folly-2016.09.26.00/folly/Bits.h"; sourceTree = ""; }; - 139D849F1E273B5600323FB7 /* Conv.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Conv.cpp; path = "folly-2016.09.26.00/folly/Conv.cpp"; sourceTree = ""; }; - 139D84A01E273B5600323FB7 /* Conv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Conv.h; path = "folly-2016.09.26.00/folly/Conv.h"; sourceTree = ""; }; - 139D84A11E273B5600323FB7 /* dynamic-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "dynamic-inl.h"; path = "folly-2016.09.26.00/folly/dynamic-inl.h"; sourceTree = ""; }; - 139D84A21E273B5600323FB7 /* dynamic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dynamic.cpp; path = "folly-2016.09.26.00/folly/dynamic.cpp"; sourceTree = ""; }; - 139D84A31E273B5600323FB7 /* dynamic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dynamic.h; path = "folly-2016.09.26.00/folly/dynamic.h"; sourceTree = ""; }; - 139D84A41E273B5600323FB7 /* Exception.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Exception.h; path = "folly-2016.09.26.00/folly/Exception.h"; sourceTree = ""; }; - 139D84A71E273B5600323FB7 /* json.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = json.cpp; path = "folly-2016.09.26.00/folly/json.cpp"; sourceTree = ""; }; - 139D84A81E273B5600323FB7 /* json.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = json.h; path = "folly-2016.09.26.00/folly/json.h"; sourceTree = ""; }; - 139D84A91E273B5600323FB7 /* Memory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Memory.h; path = "folly-2016.09.26.00/folly/Memory.h"; sourceTree = ""; }; - 139D84AA1E273B5600323FB7 /* MoveWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MoveWrapper.h; path = "folly-2016.09.26.00/folly/MoveWrapper.h"; sourceTree = ""; }; - 139D84AB1E273B5600323FB7 /* Optional.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Optional.h; path = "folly-2016.09.26.00/folly/Optional.h"; sourceTree = ""; }; - 139D84AC1E273B5600323FB7 /* ScopeGuard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ScopeGuard.h; path = "folly-2016.09.26.00/folly/ScopeGuard.h"; sourceTree = ""; }; + 139D849C1E273B5600323FB7 /* AtomicIntrusiveLinkedList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AtomicIntrusiveLinkedList.h; path = "folly-2016.10.31.00/folly/AtomicIntrusiveLinkedList.h"; sourceTree = ""; }; + 139D849D1E273B5600323FB7 /* Bits.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Bits.cpp; path = "folly-2016.10.31.00/folly/Bits.cpp"; sourceTree = ""; }; + 139D849E1E273B5600323FB7 /* Bits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Bits.h; path = "folly-2016.10.31.00/folly/Bits.h"; sourceTree = ""; }; + 139D849F1E273B5600323FB7 /* Conv.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Conv.cpp; path = "folly-2016.10.31.00/folly/Conv.cpp"; sourceTree = ""; }; + 139D84A01E273B5600323FB7 /* Conv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Conv.h; path = "folly-2016.10.31.00/folly/Conv.h"; sourceTree = ""; }; + 139D84A11E273B5600323FB7 /* dynamic-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "dynamic-inl.h"; path = "folly-2016.10.31.00/folly/dynamic-inl.h"; sourceTree = ""; }; + 139D84A21E273B5600323FB7 /* dynamic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dynamic.cpp; path = "folly-2016.10.31.00/folly/dynamic.cpp"; sourceTree = ""; }; + 139D84A31E273B5600323FB7 /* dynamic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dynamic.h; path = "folly-2016.10.31.00/folly/dynamic.h"; sourceTree = ""; }; + 139D84A41E273B5600323FB7 /* Exception.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Exception.h; path = "folly-2016.10.31.00/folly/Exception.h"; sourceTree = ""; }; + 139D84A71E273B5600323FB7 /* json.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = json.cpp; path = "folly-2016.10.31.00/folly/json.cpp"; sourceTree = ""; }; + 139D84A81E273B5600323FB7 /* json.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = json.h; path = "folly-2016.10.31.00/folly/json.h"; sourceTree = ""; }; + 139D84A91E273B5600323FB7 /* Memory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Memory.h; path = "folly-2016.10.31.00/folly/Memory.h"; sourceTree = ""; }; + 139D84AA1E273B5600323FB7 /* MoveWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MoveWrapper.h; path = "folly-2016.10.31.00/folly/MoveWrapper.h"; sourceTree = ""; }; + 139D84AB1E273B5600323FB7 /* Optional.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Optional.h; path = "folly-2016.10.31.00/folly/Optional.h"; sourceTree = ""; }; + 139D84AC1E273B5600323FB7 /* ScopeGuard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ScopeGuard.h; path = "folly-2016.10.31.00/folly/ScopeGuard.h"; sourceTree = ""; }; 13A0C2851B74F71200B29F6F /* RCTDevLoadingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTDevLoadingView.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 13A0C2861B74F71200B29F6F /* RCTDevLoadingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDevLoadingView.m; sourceTree = ""; }; 13A0C2871B74F71200B29F6F /* RCTDevMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTDevMenu.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; @@ -2024,11 +2024,11 @@ 13E067541A70F44B002CDEE1 /* UIView+React.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+React.m"; sourceTree = ""; }; 13F17A831B8493E5007D4C75 /* RCTRedBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRedBox.h; sourceTree = ""; }; 13F17A841B8493E5007D4C75 /* RCTRedBox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRedBox.m; sourceTree = ""; }; - 13F887521E2971C500C3C7A1 /* Demangle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Demangle.cpp; path = "folly-2016.09.26.00/folly/Demangle.cpp"; sourceTree = ""; }; - 13F887531E2971C500C3C7A1 /* StringBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StringBase.cpp; path = "folly-2016.09.26.00/folly/StringBase.cpp"; sourceTree = ""; }; - 13F887541E2971C500C3C7A1 /* Unicode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Unicode.cpp; path = "folly-2016.09.26.00/folly/Unicode.cpp"; sourceTree = ""; }; - 13F8879C1E29740700C3C7A1 /* BitsFunctexcept.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BitsFunctexcept.cpp; path = "folly-2016.09.26.00/folly/portability/BitsFunctexcept.cpp"; sourceTree = ""; }; - 13F887A01E2977D800C3C7A1 /* MallocImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MallocImpl.cpp; path = "folly-2016.09.26.00/folly/detail/MallocImpl.cpp"; sourceTree = ""; }; + 13F887521E2971C500C3C7A1 /* Demangle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Demangle.cpp; path = "folly-2016.10.31.00/folly/Demangle.cpp"; sourceTree = ""; }; + 13F887531E2971C500C3C7A1 /* StringBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StringBase.cpp; path = "folly-2016.10.31.00/folly/StringBase.cpp"; sourceTree = ""; }; + 13F887541E2971C500C3C7A1 /* Unicode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Unicode.cpp; path = "folly-2016.10.31.00/folly/Unicode.cpp"; sourceTree = ""; }; + 13F8879C1E29740700C3C7A1 /* BitsFunctexcept.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BitsFunctexcept.cpp; path = "folly-2016.10.31.00/folly/portability/BitsFunctexcept.cpp"; sourceTree = ""; }; + 13F887A01E2977D800C3C7A1 /* MallocImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MallocImpl.cpp; path = "folly-2016.10.31.00/folly/detail/MallocImpl.cpp"; sourceTree = ""; }; 14200DA81AC179B3008EE6BA /* RCTJavaScriptLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTJavaScriptLoader.h; sourceTree = ""; }; 142014171B32094000CC17BA /* RCTPerformanceLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPerformanceLogger.m; sourceTree = ""; }; 142014181B32094000CC17BA /* RCTPerformanceLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPerformanceLogger.h; sourceTree = ""; }; diff --git a/React/third-party.xcconfig b/React/third-party.xcconfig index 37a4baa2979b2d..24bf1727b3848c 100644 --- a/React/third-party.xcconfig +++ b/React/third-party.xcconfig @@ -6,5 +6,5 @@ // Copyright © 2017 Facebook. All rights reserved. // -HEADER_SEARCH_PATHS = $(SRCROOT)/../third-party/boost_1_63_0 $(SRCROOT)/../third-party/folly-2016.09.26.00 $(SRCROOT)/../third-party/glog-0.3.4/src +HEADER_SEARCH_PATHS = $(SRCROOT)/../third-party/boost_1_63_0 $(SRCROOT)/../third-party/folly-2016.10.31.00 $(SRCROOT)/../third-party/glog-0.3.4/src OTHER_CFLAGS = -DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle index 15b5c02cdcab7d..eecfe6929779b0 100644 --- a/ReactAndroid/build.gradle +++ b/ReactAndroid/build.gradle @@ -70,17 +70,17 @@ task prepareDoubleConversion(dependsOn: dependenciesPath ? [] : [downloadDoubleC } task downloadFolly(dependsOn: createNativeDepsDirectories, type: Download) { - src 'https://github.com/facebook/folly/archive/v2016.09.26.00.tar.gz' + src 'https://github.com/facebook/folly/archive/v2016.10.31.00.tar.gz' onlyIfNewer true overwrite false - dest new File(downloadsDir, 'folly-2016.09.26.00.tar.gz'); + dest new File(downloadsDir, 'folly-2016.10.31.00.tar.gz'); } task prepareFolly(dependsOn: dependenciesPath ? [] : [downloadFolly], type: Copy) { from dependenciesPath ?: tarTree(downloadFolly.dest) from 'src/main/jni/third-party/folly/Android.mk' - include 'folly-2016.09.26.00/folly/**/*', 'Android.mk' - eachFile {fname -> fname.path = (fname.path - "folly-2016.09.26.00/")} + include 'folly-2016.10.31.00/folly/**/*', 'Android.mk' + eachFile {fname -> fname.path = (fname.path - "folly-2016.10.31.00/")} includeEmptyDirs = false into "$thirdPartyNdkDir/folly" } diff --git a/scripts/ios-install-third-party.sh b/scripts/ios-install-third-party.sh index 0d698ea3de1fe0..f10b23b32a6f28 100755 --- a/scripts/ios-install-third-party.sh +++ b/scripts/ios-install-third-party.sh @@ -64,4 +64,4 @@ SCRIPTDIR=$(dirname "$0") fetch_and_unpack glog-0.3.4.tar.gz https://github.com/google/glog/archive/v0.3.4.tar.gz 69f91cd5a1de35ead0bc4103ea87294b0206a456 "\"$SCRIPTDIR/ios-configure-glog.sh\"" fetch_and_unpack double-conversion-1.1.5.tar.gz https://github.com/google/double-conversion/archive/v1.1.5.tar.gz 96a8aba1b4ce7d4a7a3c123be26c379c2fed1def fetch_and_unpack boost_1_63_0.tar.gz https://github.com/react-native-community/boost-for-react-native/releases/download/v1.63.0-0/boost_1_63_0.tar.gz c3f57e1d22a995e608983effbb752b54b6eab741 -fetch_and_unpack folly-2016.09.26.00.tar.gz https://github.com/facebook/folly/archive/v2016.09.26.00.tar.gz f3b928b5039235bad6cece638c597c6684d1e4e6 +fetch_and_unpack folly-2016.10.31.00.tar.gz https://github.com/facebook/folly/archive/v2016.10.31.00.tar.gz fb8cdf8962d8c9d0c20a150b6ec3b75d1fa50696 diff --git a/third-party-podspecs/Folly.podspec b/third-party-podspecs/Folly.podspec index b04c089e718385..c72b88fba93a1f 100644 --- a/third-party-podspecs/Folly.podspec +++ b/third-party-podspecs/Folly.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'Folly' - spec.version = '2016.09.26.00' + spec.version = '2016.10.31.00' spec.license = { :type => 'Apache License, Version 2.0' } spec.homepage = 'https://github.com/facebook/folly' spec.summary = 'An open-source C++ library developed and used at Facebook.' From 2299d4cd7cc8540c0f31873acb2f652ea1bba90c Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Fri, 13 Apr 2018 17:19:04 -0700 Subject: [PATCH 0297/1109] iOS OSS: updated Podfile to have fabric related targets Summary: Initial attempt to make fabric stuffs built properly with CocoaPods + RNTesterPods project. This simply includes fabric libs to the build, it doesn't change any behavior or enable fabric runtime. Reviewed By: shergin Differential Revision: D7626038 fbshipit-source-id: 4a80e0066cffa4478bb442fa8aefeaee6ff56ddd --- RNTester/Podfile | 1 + RNTester/Podfile.lock | 31 +++++++- React.podspec | 72 ++++++++++++++++++- .../fabric/uimanager/FabricUIManager.cpp | 2 +- 4 files changed, 101 insertions(+), 5 deletions(-) diff --git a/RNTester/Podfile b/RNTester/Podfile index 1bcd939928b89f..155cec5aa04e74 100644 --- a/RNTester/Podfile +++ b/RNTester/Podfile @@ -15,6 +15,7 @@ target 'RNTester' do 'RCTAnimation', 'RCTBlob', 'RCTCameraRoll', + 'RCTFabric', 'RCTGeolocation', 'RCTImage', 'RCTLinkingIOS', diff --git a/RNTester/Podfile.lock b/RNTester/Podfile.lock index 5f5a3acb769e96..57ad2bcedbe748 100644 --- a/RNTester/Podfile.lock +++ b/RNTester/Podfile.lock @@ -14,6 +14,9 @@ PODS: - Folly (= 2016.10.31.00) - React/Core - React/cxxreact + - React/CxxExceptions (1000.0.0): + - React/CxxBridge + - React/exceptions - React/cxxreact (1000.0.0): - boost-for-react-native (= 1.63.0) - Folly (= 2016.10.31.00) @@ -22,6 +25,24 @@ PODS: - React/DevSupport (1000.0.0): - React/Core - React/RCTWebSocket + - React/exceptions (1000.0.0) + - React/fabric (1000.0.0): + - React/fabric/core (= 1000.0.0) + - React/fabric/debug (= 1000.0.0) + - React/fabric/graphics (= 1000.0.0) + - React/fabric/uimanager (= 1000.0.0) + - React/fabric/view (= 1000.0.0) + - React/fabric/core (1000.0.0): + - Folly (= 2016.10.31.00) + - React/fabric/debug (1000.0.0): + - Folly (= 2016.10.31.00) + - React/fabric/graphics (1000.0.0): + - Folly (= 2016.10.31.00) + - React/fabric/uimanager (1000.0.0): + - Folly (= 2016.10.31.00) + - React/fabric/view (1000.0.0): + - Folly (= 2016.10.31.00) + - yoga - React/fishhook (1000.0.0) - React/jschelpers (1000.0.0): - Folly (= 2016.10.31.00) @@ -37,6 +58,11 @@ PODS: - React/RCTCameraRoll (1000.0.0): - React/Core - React/RCTImage + - React/RCTFabric (1000.0.0): + - Folly (= 2016.10.31.00) + - React/Core + - React/CxxExceptions + - React/fabric - React/RCTGeolocation (1000.0.0): - React/Core - React/RCTImage (1000.0.0): @@ -72,6 +98,7 @@ DEPENDENCIES: - React/RCTAnimation (from `../`) - React/RCTBlob (from `../`) - React/RCTCameraRoll (from `../`) + - React/RCTFabric (from `../`) - React/RCTGeolocation (from `../`) - React/RCTImage (from `../`) - React/RCTLinkingIOS (from `../`) @@ -104,9 +131,9 @@ SPEC CHECKSUMS: DoubleConversion: e22e0762848812a87afd67ffda3998d9ef29170c Folly: 9a8eea4725a0b6ba3256ebf206c21e352c23abf8 glog: 1de0bb937dccdc981596d3b5825ebfb765017ded - React: 4e8050da47914f710f7bf48d1aca39fd9afafe39 + React: e3382e39c51a5e5889248e97c6b9b1b3ca443a08 yoga: bdd268c5812f00bdb52cc2b58f129797e97935eb -PODFILE CHECKSUM: 2db1aae50ba1389ea02bbb867efcf85182b0336a +PODFILE CHECKSUM: 1a96172007b66aa74825c234f17139dd9c3d3cd7 COCOAPODS: 1.5.0 diff --git a/React.podspec b/React.podspec index ac3df357ad1ced..027016aa07cbd7 100644 --- a/React.podspec +++ b/React.podspec @@ -52,7 +52,7 @@ Pod::Spec.new do |s| "React/Inspector/*", "ReactCommon/yoga/*", "React/Cxx*/*", - "React/Fabric/**/*", + "React/Fabric/**/*" ss.ios.exclude_files = "React/**/RCTTV*.*" ss.tvos.exclude_files = "React/Modules/RCTClipboard*", "React/Views/RCTDatePicker*", @@ -79,7 +79,7 @@ Pod::Spec.new do |s| s.subspec "CxxExceptions" do |ss| ss.dependency "React/CxxBridge" - ss.private_header_files = "React/CxxExceptions/*.h" + ss.dependency "React/exceptions" ss.source_files = "React/CxxExceptions/*.{h,m,mm}" end @@ -90,6 +90,19 @@ Pod::Spec.new do |s| "React/Inspector/*" end + s.subspec "RCTFabric" do |ss| + ss.dependency "Folly", folly_version + ss.dependency "React/Core" + ss.dependency "React/CxxExceptions" + ss.dependency "React/fabric" + ss.compiler_flags = folly_compiler_flags + ss.source_files = "React/Fabric/**/*.{c,h,m,mm,S,cpp}" + ss.exclude_files = "**/tests/*" + ss.header_dir = "React" + ss.framework = "JavaScriptCore" + ss.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\"" } + end + s.subspec "tvOS" do |ss| ss.dependency "React/Core" ss.source_files = "React/**/RCTTV*.{h, m}" @@ -129,6 +142,61 @@ Pod::Spec.new do |s| ss.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/boost-for-react-native\" \"$(PODS_ROOT)/DoubleConversion\" \"$(PODS_ROOT)/Folly\"" } end + s.subspec "exceptions" do |ss| + ss.source_files = "ReactCommon/exceptions/*.{cpp,h}" + ss.header_dir = "cxxreact" + ss.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\"" } + end + + s.subspec "fabric" do |ss| + ss.subspec "core" do |sss| + sss.dependency "Folly", folly_version + sss.compiler_flags = folly_compiler_flags + sss.source_files = "ReactCommon/fabric/core/**/*.{cpp,h}" + sss.exclude_files = "**/tests/*" + sss.header_dir = "fabric/core" + sss.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/Folly\"" } + end + + ss.subspec "debug" do |sss| + sss.dependency "Folly", folly_version + sss.compiler_flags = folly_compiler_flags + sss.source_files = "ReactCommon/fabric/debug/**/*.{cpp,h}" + sss.exclude_files = "**/tests/*" + sss.header_dir = "fabric/debug" + sss.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/Folly\"" } + end + + ss.subspec "graphics" do |sss| + sss.dependency "Folly", folly_version + sss.compiler_flags = folly_compiler_flags + sss.source_files = "ReactCommon/fabric/graphics/**/*.{cpp,h}" + sss.exclude_files = "**/tests/*" + sss.header_dir = "fabric/graphics" + sss.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/Folly\"" } + end + + ss.subspec "uimanager" do |sss| + sss.dependency "Folly", folly_version + sss.compiler_flags = folly_compiler_flags + sss.source_files = "ReactCommon/fabric/uimanager/**/*.{cpp,h}" + sss.exclude_files = "**/tests/*" + sss.header_dir = "fabric/uimanager" + sss.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/Folly\"" } + end + + ss.subspec "view" do |sss| + sss.dependency "Folly", folly_version + sss.dependency "yoga" + sss.compiler_flags = folly_compiler_flags + sss.source_files = "ReactCommon/fabric/view/**/*.{cpp,h}" + sss.exclude_files = "**/tests/*" + sss.header_dir = "fabric/view" + sss.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/Folly\"" } + end + + end + s.subspec "ART" do |ss| ss.dependency "React/Core" ss.source_files = "Libraries/ART/**/*.{h,m}" diff --git a/ReactCommon/fabric/uimanager/FabricUIManager.cpp b/ReactCommon/fabric/uimanager/FabricUIManager.cpp index e2f3233980d564..5ba9138d9baaab 100644 --- a/ReactCommon/fabric/uimanager/FabricUIManager.cpp +++ b/ReactCommon/fabric/uimanager/FabricUIManager.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include From 7e58e2cbf6910a6b34e932e6494b2fb8ed6bf466 Mon Sep 17 00:00:00 2001 From: Patrice Vignola Date: Fri, 13 Apr 2018 19:59:06 -0700 Subject: [PATCH 0298/1109] Remove duplicate prop definition Summary: - This is most likely a merge issue? - hasTVPreferredFocus was duplicated in the Flow types definition for the Button component, but the PropTypes are fine Removing a duplicated prop can't really throw a Flow error. Anyway, I removed the duplicated prop and successfully ran `$ yarn flow` None [GENERAL] [ENHANCEMENT] [Button] - Remove duplicate prop definition Closes https://github.com/facebook/react-native/pull/18845 Differential Revision: D7627621 Pulled By: mdvacca fbshipit-source-id: 924522641a334212f5e2c1310d81da1e321f19b1 --- Libraries/Components/Button.js | 1 - 1 file changed, 1 deletion(-) diff --git a/Libraries/Components/Button.js b/Libraries/Components/Button.js index 4370f3571c103c..51ca2aa636c359 100644 --- a/Libraries/Components/Button.js +++ b/Libraries/Components/Button.js @@ -57,7 +57,6 @@ class Button extends React.Component<{ accessibilityLabel?: ?string, disabled?: ?boolean, testID?: ?string, - hasTVPreferredFocus?: ?boolean, }> { static propTypes = { /** From a42b2988ae3cf995b8ffe37609e40a7a8b983c06 Mon Sep 17 00:00:00 2001 From: Jakub Grzmiel Date: Sat, 14 Apr 2018 13:04:28 -0700 Subject: [PATCH 0299/1109] Clean up BUCK files for missing dependencies and tests Differential Revision: D7618360 fbshipit-source-id: 421834892519998ad088a138b3fc3d96afe34d79 --- ReactAndroid/src/main/jni/first-party/fb/jni/java/BUCK | 4 ++-- ReactCommon/cxxreact/BUCK | 1 + ReactCommon/fabric/core/BUCK | 8 +++++--- ReactCommon/fabric/debug/BUCK | 8 +++++--- ReactCommon/fabric/graphics/BUCK | 8 +++++--- ReactCommon/fabric/uimanager/BUCK | 8 +++++--- ReactCommon/fabric/view/BUCK | 8 +++++--- 7 files changed, 28 insertions(+), 17 deletions(-) diff --git a/ReactAndroid/src/main/jni/first-party/fb/jni/java/BUCK b/ReactAndroid/src/main/jni/first-party/fb/jni/java/BUCK index afec30c511f956..8b2cb7b5941abe 100644 --- a/ReactAndroid/src/main/jni/first-party/fb/jni/java/BUCK +++ b/ReactAndroid/src/main/jni/first-party/fb/jni/java/BUCK @@ -1,6 +1,6 @@ -load("//ReactNative:DEFS.bzl", "react_native_dep") +load("//ReactNative:DEFS.bzl", "react_native_dep", "rn_java_library") -java_library( +rn_java_library( name = "java", srcs = glob(["**/*.java"]), visibility = ["PUBLIC"], diff --git a/ReactCommon/cxxreact/BUCK b/ReactCommon/cxxreact/BUCK index 6201e74cdf3b0d..43a5ce58276e07 100644 --- a/ReactCommon/cxxreact/BUCK +++ b/ReactCommon/cxxreact/BUCK @@ -141,6 +141,7 @@ rn_xplat_cxx_library( ], fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + APPLE_INSPECTOR_FLAGS, force_static = True, + macosx_tests_override = [], platforms = (ANDROID, APPLE), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", diff --git a/ReactCommon/fabric/core/BUCK b/ReactCommon/fabric/core/BUCK index d9ee58fae8b50b..913078944214fc 100644 --- a/ReactCommon/fabric/core/BUCK +++ b/ReactCommon/fabric/core/BUCK @@ -35,14 +35,16 @@ rn_xplat_cxx_library( ], fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + APPLE_INSPECTOR_FLAGS, + fbobjc_tests = [ + ":tests", + ], force_static = True, preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", ], - tests = [ - ":tests", - ], + macosx_tests_override = [], + tests = [], visibility = ["PUBLIC"], deps = [ "xplat//fbsystrace:fbsystrace", diff --git a/ReactCommon/fabric/debug/BUCK b/ReactCommon/fabric/debug/BUCK index d22caf8f955691..abc85f94c325ee 100644 --- a/ReactCommon/fabric/debug/BUCK +++ b/ReactCommon/fabric/debug/BUCK @@ -32,14 +32,16 @@ rn_xplat_cxx_library( ], fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + APPLE_INSPECTOR_FLAGS, + fbobjc_tests = [ + ":tests", + ], force_static = True, + macosx_tests_override = [], preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", ], - tests = [ - ":tests", - ], + tests = [], visibility = ["PUBLIC"], deps = [ "xplat//folly:headers_only", diff --git a/ReactCommon/fabric/graphics/BUCK b/ReactCommon/fabric/graphics/BUCK index 967f33aafc9b69..82a91faa4f455e 100644 --- a/ReactCommon/fabric/graphics/BUCK +++ b/ReactCommon/fabric/graphics/BUCK @@ -32,14 +32,16 @@ rn_xplat_cxx_library( ], fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + APPLE_INSPECTOR_FLAGS, + fbobjc_tests = [ + ":tests", + ], force_static = True, + macosx_tests_override = [], preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", ], - tests = [ - ":tests", - ], + tests = [], visibility = ["PUBLIC"], deps = [ "xplat//fbsystrace:fbsystrace", diff --git a/ReactCommon/fabric/uimanager/BUCK b/ReactCommon/fabric/uimanager/BUCK index ca7700e5c44bb3..9d1c076a90521b 100644 --- a/ReactCommon/fabric/uimanager/BUCK +++ b/ReactCommon/fabric/uimanager/BUCK @@ -32,14 +32,16 @@ rn_xplat_cxx_library( ], fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + APPLE_INSPECTOR_FLAGS, + fbobjc_tests = [ + ":tests", + ], force_static = True, + macosx_tests_override = [], preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", ], - tests = [ - ":tests", - ], + tests = [], visibility = ["PUBLIC"], deps = [ "xplat//fbsystrace:fbsystrace", diff --git a/ReactCommon/fabric/view/BUCK b/ReactCommon/fabric/view/BUCK index 5716485f77e51e..5202ded14a0f0d 100644 --- a/ReactCommon/fabric/view/BUCK +++ b/ReactCommon/fabric/view/BUCK @@ -35,14 +35,16 @@ rn_xplat_cxx_library( ], fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + APPLE_INSPECTOR_FLAGS, + fbobjc_tests = [ + ":tests", + ], force_static = True, + macosx_tests_override = [], preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", ], - tests = [ - ":tests", - ], + tests = [], visibility = ["PUBLIC"], deps = [ "xplat//fbsystrace:fbsystrace", From c866ef243e0f475affed9518510ccdf9a951b19d Mon Sep 17 00:00:00 2001 From: Jakub Grzmiel Date: Sat, 14 Apr 2018 15:27:04 -0700 Subject: [PATCH 0300/1109] Clean up BUCK files for missing dependencies and tests Differential Revision: D7625433 fbshipit-source-id: 332b7ff7eaed82cb52f459921f1ae67b702a1636 --- ReactCommon/fabric/uimanager/BUCK | 1 + ReactCommon/fabric/view/BUCK | 1 + 2 files changed, 2 insertions(+) diff --git a/ReactCommon/fabric/uimanager/BUCK b/ReactCommon/fabric/uimanager/BUCK index 9d1c076a90521b..218b8ea92ebfa2 100644 --- a/ReactCommon/fabric/uimanager/BUCK +++ b/ReactCommon/fabric/uimanager/BUCK @@ -37,6 +37,7 @@ rn_xplat_cxx_library( ], force_static = True, macosx_tests_override = [], + platforms = (ANDROID, APPLE), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", diff --git a/ReactCommon/fabric/view/BUCK b/ReactCommon/fabric/view/BUCK index 5202ded14a0f0d..8bdb1b175a3914 100644 --- a/ReactCommon/fabric/view/BUCK +++ b/ReactCommon/fabric/view/BUCK @@ -40,6 +40,7 @@ rn_xplat_cxx_library( ], force_static = True, macosx_tests_override = [], + platforms = (ANDROID, APPLE), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", From 2fd7fda05d5dfd63af529838bf3511dca19877fc Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Sat, 14 Apr 2018 18:37:38 -0700 Subject: [PATCH 0301/1109] Delete fb_xplat_cxx.bzl Reviewed By: mzlee, ttsugriy Differential Revision: D7625836 fbshipit-source-id: 3169d43f028b895e1075268495de66816c778b35 --- ReactCommon/cxxreact/tests/BUCK | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactCommon/cxxreact/tests/BUCK b/ReactCommon/cxxreact/tests/BUCK index 010e7c8e50d069..1d7657cc01ec33 100644 --- a/ReactCommon/cxxreact/tests/BUCK +++ b/ReactCommon/cxxreact/tests/BUCK @@ -11,7 +11,7 @@ TEST_SRCS = [ ] if not IS_OSS_BUILD: - load("@xplat//build_defs:fb_xplat_cxx.bzl", "cxx_test") + load("@xplat//build_defs:fb_xplat_cxx_test.bzl", "cxx_test") load("@xplat//configurations/buck/android:jni_instrumentation_test", "jni_instrumentation_test_lib") load("@xplat//configurations/buck:default_platform_defs.bzl", "APPLE") jni_instrumentation_test_lib( From 3fd2e2da4fd5881e469cfda1f2e261e880fb1cab Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Mon, 16 Apr 2018 07:43:22 -0700 Subject: [PATCH 0302/1109] Fabric/Text/Prep: Refined ComponentDescriptor interface Summary: The new interface of ComponentDescriptor makes ShadowNode creation/cloning process a bit more explicit: Now customers (UIManager) must prepare Props object explicitly before creation or cloning. Besides general clarity, we need this to prepare for a new virtual `ShadowNode::clone()` method which will serve "virtual constructor" role, redirecting execution to concrete ComponentDescriptor instance. Actually, the whole purpose of concrete ComponentDescriptor instance is serve "virtual constructor" role (and all this code should be "templated"). Reviewed By: mdvacca Differential Revision: D7591714 fbshipit-source-id: 8793b3ef70ed7ae113efb36ad1eee20573360dc8 --- .../componentdescriptor/ComponentDescriptor.h | 15 ++++++- .../ConcreteComponentDescriptor.h | 18 +++++--- .../core/tests/ComponentDescriptorTest.cpp | 13 +++--- .../fabric/uimanager/FabricUIManager.cpp | 42 ++++++++++++++++--- 4 files changed, 70 insertions(+), 18 deletions(-) diff --git a/ReactCommon/fabric/core/componentdescriptor/ComponentDescriptor.h b/ReactCommon/fabric/core/componentdescriptor/ComponentDescriptor.h index 7b7b7a5578d678..1b92620d9fdc03 100644 --- a/ReactCommon/fabric/core/componentdescriptor/ComponentDescriptor.h +++ b/ReactCommon/fabric/core/componentdescriptor/ComponentDescriptor.h @@ -48,7 +48,7 @@ class ComponentDescriptor { const Tag &tag, const Tag &rootTag, const InstanceHandle &instanceHandle, - const RawProps &rawProps + const SharedProps &props ) const = 0; /* @@ -56,7 +56,7 @@ class ComponentDescriptor { */ virtual SharedShadowNode cloneShadowNode( const SharedShadowNode &shadowNode, - const SharedRawProps &rawProps = nullptr, + const SharedProps &props = nullptr, const SharedShadowNodeSharedList &children = nullptr ) const = 0; @@ -67,6 +67,17 @@ class ComponentDescriptor { const SharedShadowNode &parentShadowNode, const SharedShadowNode &childShadowNode ) const = 0; + + /* + * Creates a new `Props` of a particular type with all values copied from + * `props` and `rawProps` applied on top of this. + * If `props` is `nullptr`, a default `Props` object (with default values) + * will be used. + */ + virtual SharedProps cloneProps( + const SharedProps &props, + const RawProps &rawProps + ) const = 0; }; } // namespace react diff --git a/ReactCommon/fabric/core/componentdescriptor/ConcreteComponentDescriptor.h b/ReactCommon/fabric/core/componentdescriptor/ConcreteComponentDescriptor.h index 95de5e17534dc7..8739d849a4a1f9 100644 --- a/ReactCommon/fabric/core/componentdescriptor/ConcreteComponentDescriptor.h +++ b/ReactCommon/fabric/core/componentdescriptor/ConcreteComponentDescriptor.h @@ -26,6 +26,7 @@ class ConcreteComponentDescriptor: public ComponentDescriptor { static_assert(std::is_base_of::value, "ShadowNodeT must be a descendant of ShadowNode"); using SharedShadowNodeT = std::shared_ptr; + using ConcreteProps = typename ShadowNodeT::ConcreteProps; using SharedConcreteProps = typename ShadowNodeT::SharedConcreteProps; public: @@ -37,19 +38,17 @@ class ConcreteComponentDescriptor: public ComponentDescriptor { const Tag &tag, const Tag &rootTag, const InstanceHandle &instanceHandle, - const RawProps &rawProps + const SharedProps &props ) const override { - auto props = ShadowNodeT::Props(rawProps); - return std::make_shared(tag, rootTag, instanceHandle, props); + return std::make_shared(tag, rootTag, instanceHandle, std::static_pointer_cast(props)); } SharedShadowNode cloneShadowNode( const SharedShadowNode &shadowNode, - const SharedRawProps &rawProps = nullptr, + const SharedProps &props = nullptr, const SharedShadowNodeSharedList &children = nullptr ) const override { - const SharedConcreteProps props = rawProps ? ShadowNodeT::Props(*rawProps, shadowNode->getProps()) : nullptr; - return std::make_shared(std::static_pointer_cast(shadowNode), props, children); + return std::make_shared(std::static_pointer_cast(shadowNode), std::static_pointer_cast(props), children); } void appendChild( @@ -61,6 +60,13 @@ class ConcreteComponentDescriptor: public ComponentDescriptor { concreteNonConstParentShadowNode->appendChild(childShadowNode); } + virtual SharedProps cloneProps( + const SharedProps &props, + const RawProps &rawProps + ) const override { + return ShadowNodeT::Props(rawProps, props); + }; + }; } // namespace react diff --git a/ReactCommon/fabric/core/tests/ComponentDescriptorTest.cpp b/ReactCommon/fabric/core/tests/ComponentDescriptorTest.cpp index 699642ce7f2d34..5c2a0bc9d2961f 100644 --- a/ReactCommon/fabric/core/tests/ComponentDescriptorTest.cpp +++ b/ReactCommon/fabric/core/tests/ComponentDescriptorTest.cpp @@ -19,7 +19,8 @@ TEST(ComponentDescriptorTest, createShadowNode) { RawProps raw; raw["nativeID"] = "abc"; - SharedShadowNode node = descriptor->createShadowNode(9, 1, (void *)NULL, raw); + SharedProps props = descriptor->cloneProps(nullptr, raw); + SharedShadowNode node = descriptor->createShadowNode(9, 1, (void *)NULL, props); ASSERT_EQ(node->getComponentHandle(), typeid(TestShadowNode).hash_code()); ASSERT_STREQ(node->getComponentName().c_str(), "Test"); @@ -35,7 +36,8 @@ TEST(ComponentDescriptorTest, cloneShadowNode) { RawProps raw; raw["nativeID"] = "abc"; - SharedShadowNode node = descriptor->createShadowNode(9, 1, (void *)NULL, raw); + SharedProps props = descriptor->cloneProps(nullptr, raw); + SharedShadowNode node = descriptor->createShadowNode(9, 1, (void *)NULL, props); SharedShadowNode cloned = descriptor->cloneShadowNode(node); ASSERT_EQ(cloned->getComponentHandle(), typeid(TestShadowNode).hash_code()); @@ -52,9 +54,10 @@ TEST(ComponentDescriptorTest, appendChild) { RawProps raw; raw["nativeID"] = "abc"; - SharedShadowNode node1 = descriptor->createShadowNode(1, 1, (void *)NULL, raw); - SharedShadowNode node2 = descriptor->createShadowNode(2, 1, (void *)NULL, raw); - SharedShadowNode node3 = descriptor->createShadowNode(3, 1, (void *)NULL, raw); + SharedProps props = descriptor->cloneProps(nullptr, raw); + SharedShadowNode node1 = descriptor->createShadowNode(1, 1, (void *)NULL, props); + SharedShadowNode node2 = descriptor->createShadowNode(2, 1, (void *)NULL, props); + SharedShadowNode node3 = descriptor->createShadowNode(3, 1, (void *)NULL, props); descriptor->appendChild(node1, node2); descriptor->appendChild(node1, node3); diff --git a/ReactCommon/fabric/uimanager/FabricUIManager.cpp b/ReactCommon/fabric/uimanager/FabricUIManager.cpp index 5ba9138d9baaab..2020732831211f 100644 --- a/ReactCommon/fabric/uimanager/FabricUIManager.cpp +++ b/ReactCommon/fabric/uimanager/FabricUIManager.cpp @@ -54,7 +54,15 @@ SharedShadowNode FabricUIManager::createNode(int tag, std::string viewName, int LOG(INFO) << "FabricUIManager::createNode(tag: " << tag << ", name: " << viewName << ", rootTag" << rootTag << ", props: " << props << ")"; const SharedComponentDescriptor &componentDescriptor = (*componentDescriptorRegistry_)["View"]; RawProps rawProps = rawPropsFromDynamic(props); - SharedShadowNode shadowNode = componentDescriptor->createShadowNode(tag, rootTag, instanceHandle, rawProps); + + SharedShadowNode shadowNode = + componentDescriptor->createShadowNode( + tag, + rootTag, + instanceHandle, + componentDescriptor->cloneProps(nullptr, rawProps) + ); + LOG(INFO) << "FabricUIManager::createNode() -> " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}); if (delegate_) { @@ -67,7 +75,10 @@ SharedShadowNode FabricUIManager::createNode(int tag, std::string viewName, int SharedShadowNode FabricUIManager::cloneNode(const SharedShadowNode &shadowNode) { LOG(INFO) << "FabricUIManager::cloneNode(shadowNode: " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ")"; const SharedComponentDescriptor &componentDescriptor = (*componentDescriptorRegistry_)[shadowNode]; - SharedShadowNode clonedShadowNode = componentDescriptor->cloneShadowNode(shadowNode); + + SharedShadowNode clonedShadowNode = + componentDescriptor->cloneShadowNode(shadowNode); + LOG(INFO) << "FabricUIManager::cloneNode() -> " << clonedShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}); return clonedShadowNode; } @@ -76,7 +87,14 @@ SharedShadowNode FabricUIManager::cloneNodeWithNewChildren(const SharedShadowNod LOG(INFO) << "FabricUIManager::cloneNodeWithNewChildren(shadowNode: " << shadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}) << ")"; // Assuming semantic: Cloning with same props but empty children. const SharedComponentDescriptor &componentDescriptor = (*componentDescriptorRegistry_)[shadowNode]; - SharedShadowNode clonedShadowNode = componentDescriptor->cloneShadowNode(shadowNode, nullptr, ShadowNode::emptySharedShadowNodeSharedList()); + + SharedShadowNode clonedShadowNode = + componentDescriptor->cloneShadowNode( + shadowNode, + nullptr, + ShadowNode::emptySharedShadowNodeSharedList() + ); + LOG(INFO) << "FabricUIManager::cloneNodeWithNewChildren() -> " << clonedShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}); return clonedShadowNode; } @@ -86,7 +104,14 @@ SharedShadowNode FabricUIManager::cloneNodeWithNewProps(const SharedShadowNode & // Assuming semantic: Cloning with same children and specified props. const SharedComponentDescriptor &componentDescriptor = (*componentDescriptorRegistry_)[shadowNode]; RawProps rawProps = rawPropsFromDynamic(props); - SharedShadowNode clonedShadowNode = componentDescriptor->cloneShadowNode(shadowNode, std::make_shared(rawProps), nullptr); + + SharedShadowNode clonedShadowNode = + componentDescriptor->cloneShadowNode( + shadowNode, + componentDescriptor->cloneProps(shadowNode->getProps(), rawProps), + nullptr + ); + LOG(INFO) << "FabricUIManager::cloneNodeWithNewProps() -> " << clonedShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}); return clonedShadowNode; } @@ -96,7 +121,14 @@ SharedShadowNode FabricUIManager::cloneNodeWithNewChildrenAndProps(const SharedS // Assuming semantic: Cloning with empty children and specified props. const SharedComponentDescriptor &componentDescriptor = (*componentDescriptorRegistry_)[shadowNode]; RawProps rawProps = rawPropsFromDynamic(props); - SharedShadowNode clonedShadowNode = componentDescriptor->cloneShadowNode(shadowNode, std::make_shared(rawProps), ShadowNode::emptySharedShadowNodeSharedList()); + + SharedShadowNode clonedShadowNode = + componentDescriptor->cloneShadowNode( + shadowNode, + componentDescriptor->cloneProps(shadowNode->getProps(), rawProps), + ShadowNode::emptySharedShadowNodeSharedList() + ); + LOG(INFO) << "FabricUIManager::cloneNodeWithNewChildrenAndProps() -> " << clonedShadowNode->getDebugDescription(DebugStringConvertibleOptions {.format = false}); return clonedShadowNode; } From c399d697166301a823c7f7250b37ba5112e7bcc7 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Mon, 16 Apr 2018 07:43:23 -0700 Subject: [PATCH 0303/1109] Fabric: More restrictive types (const &) for ShadowNode constuctors' arguments Summary: Should be more performant theoretically. Reviewed By: mdvacca Differential Revision: D7591713 fbshipit-source-id: 74141053f2b91cb621cc0d573f89f3454512c585 --- .../fabric/core/shadownode/ShadowNode.cpp | 16 ++++++++-------- ReactCommon/fabric/core/shadownode/ShadowNode.h | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp index 3c9fa034bdbe0a..e7c6b68f22ef65 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp @@ -21,11 +21,11 @@ SharedShadowNodeSharedList ShadowNode::emptySharedShadowNodeSharedList() { #pragma mark - Constructors ShadowNode::ShadowNode( - Tag tag, - Tag rootTag, - InstanceHandle instanceHandle, - SharedProps props, - SharedShadowNodeSharedList children + const Tag &tag, + const Tag &rootTag, + const InstanceHandle &instanceHandle, + const SharedProps &props, + const SharedShadowNodeSharedList &children ): tag_(tag), rootTag_(rootTag), @@ -35,9 +35,9 @@ ShadowNode::ShadowNode( revision_(1) {} ShadowNode::ShadowNode( - SharedShadowNode shadowNode, - SharedProps props, - SharedShadowNodeSharedList children + const SharedShadowNode &shadowNode, + const SharedProps &props, + const SharedShadowNodeSharedList &children ): tag_(shadowNode->tag_), rootTag_(shadowNode->rootTag_), diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.h b/ReactCommon/fabric/core/shadownode/ShadowNode.h index 48e840fd67987b..a5b8a2ff9da6eb 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.h +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.h @@ -35,17 +35,17 @@ class ShadowNode: #pragma mark - Constructors ShadowNode( - Tag tag, - Tag rootTag, - InstanceHandle instanceHandle, - SharedProps props = SharedProps(), - SharedShadowNodeSharedList children = SharedShadowNodeSharedList() + const Tag &tag, + const Tag &rootTag, + const InstanceHandle &instanceHandle, + const SharedProps &props = SharedProps(), + const SharedShadowNodeSharedList &children = SharedShadowNodeSharedList() ); ShadowNode( - SharedShadowNode shadowNode, - SharedProps props = nullptr, - SharedShadowNodeSharedList children = nullptr + const SharedShadowNode &shadowNode, + const SharedProps &props = nullptr, + const SharedShadowNodeSharedList &children = nullptr ); #pragma mark - Getters From 82bd4337c9b3c58fc8c2cad5f32a0b8908a3bc07 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Mon, 16 Apr 2018 07:43:25 -0700 Subject: [PATCH 0304/1109] Fabric: Fixed ComponentDescriptorTest Summary: Trivial. Reviewed By: mdvacca Differential Revision: D7591712 fbshipit-source-id: fbcaaa30004f096749a6bcd47dcc56c060d7524a --- ReactCommon/fabric/core/tests/ComponentDescriptorTest.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ReactCommon/fabric/core/tests/ComponentDescriptorTest.cpp b/ReactCommon/fabric/core/tests/ComponentDescriptorTest.cpp index 5c2a0bc9d2961f..460a3124bc3e8f 100644 --- a/ReactCommon/fabric/core/tests/ComponentDescriptorTest.cpp +++ b/ReactCommon/fabric/core/tests/ComponentDescriptorTest.cpp @@ -26,9 +26,7 @@ TEST(ComponentDescriptorTest, createShadowNode) { ASSERT_STREQ(node->getComponentName().c_str(), "Test"); ASSERT_EQ(node->getTag(), 9); ASSERT_EQ(node->getRootTag(), 1); - - // TODO(#27369757): getProps() doesn't work - // ASSERT_STREQ(node->getProps()->getNativeId().c_str(), "testNativeID"); + ASSERT_STREQ(node->getProps()->getNativeId().c_str(), "abc"); } TEST(ComponentDescriptorTest, cloneShadowNode) { @@ -44,9 +42,7 @@ TEST(ComponentDescriptorTest, cloneShadowNode) { ASSERT_STREQ(cloned->getComponentName().c_str(), "Test"); ASSERT_EQ(cloned->getTag(), 9); ASSERT_EQ(cloned->getRootTag(), 1); - - // TODO(#27369757): getProps() doesn't work - // ASSERT_STREQ(cloned->getProps()->getNativeId().c_str(), "testNativeID"); + ASSERT_STREQ(cloned->getProps()->getNativeId().c_str(), "abc"); } TEST(ComponentDescriptorTest, appendChild) { From 8621d4b79731e13a0c6e397abd93c193c6219000 Mon Sep 17 00:00:00 2001 From: TomSwift Date: Mon, 16 Apr 2018 08:59:26 -0700 Subject: [PATCH 0305/1109] iOS textTransform style support Summary: Issue [#2088](https://github.com/facebook/react-native/issues/2088). The basic desire is to have a declarative mechanism to transform text content to uppercase or lowercase or titlecase ("capitalized"). My test plan involves having added a test-case to the RNTester app within the `` component area. I then manually verified that the rendered content met my expectation. Here is the markup that exercises my enhancement: ``` This text should be uppercased. This TEXT SHOULD be lowercased. This text should be CAPITALIZED. Mixed:{' '} uppercase{' '} LoWeRcAsE{' '} capitalize each word ``` And here is a screenshot of the result: ![screen shot 2018-03-14 at 3 01 02 pm](https://user-images.githubusercontent.com/575821/37433772-7abe7fa0-279a-11e8-9ec9-fb3aa1952dad.png) [Website Documentation PR](https://github.com/facebook/react-native-website/pull/254) https://github.com/facebook/react-native-website/pull/254 [IOS] [ENHANCEMENT] [Text] - added textTransform style property enabling declarative casing transformations Closes https://github.com/facebook/react-native/pull/18387 Differential Revision: D7583315 Pulled By: shergin fbshipit-source-id: a5d22aea2aa4f494b7b25a055abe64799ccbaa79 --- Libraries/StyleSheet/StyleSheetTypes.js | 1 + .../Text/BaseText/RCTBaseTextShadowView.m | 2 +- .../Text/BaseText/RCTBaseTextViewManager.m | 1 + Libraries/Text/RCTConvert+Text.h | 2 ++ Libraries/Text/RCTConvert+Text.m | 7 ++++ .../Text/RCTText.xcodeproj/project.pbxproj | 6 ++++ Libraries/Text/RCTTextAttributes.h | 7 ++++ Libraries/Text/RCTTextAttributes.m | 20 ++++++++++- Libraries/Text/RCTTextTransform.h | 16 +++++++++ Libraries/Text/TextStylePropTypes.js | 6 ++++ RNTester/js/TextExample.ios.js | 36 +++++++++++++++++++ 11 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 Libraries/Text/RCTTextTransform.h diff --git a/Libraries/StyleSheet/StyleSheetTypes.js b/Libraries/StyleSheet/StyleSheetTypes.js index cd80f8b8d6e074..ffec5b54bc7937 100644 --- a/Libraries/StyleSheet/StyleSheetTypes.js +++ b/Libraries/StyleSheet/StyleSheetTypes.js @@ -201,6 +201,7 @@ export type ____TextStyle_Internal = $ReadOnly<{| | 'underline line-through', textDecorationStyle?: 'solid' | 'double' | 'dotted' | 'dashed', textDecorationColor?: ColorValue, + textTransform?: 'none' | 'capitalize' | 'uppercase' | 'lowercase', writingDirection?: 'auto' | 'ltr' | 'rtl', |}>; diff --git a/Libraries/Text/BaseText/RCTBaseTextShadowView.m b/Libraries/Text/BaseText/RCTBaseTextShadowView.m index 85162926eb198b..49ce7690dfc96e 100644 --- a/Libraries/Text/BaseText/RCTBaseTextShadowView.m +++ b/Libraries/Text/BaseText/RCTBaseTextShadowView.m @@ -63,7 +63,7 @@ - (NSAttributedString *)attributedTextWithBaseTextAttributes:(nullable RCTTextAt NSString *text = rawTextShadowView.text; if (text) { NSAttributedString *rawTextAttributedString = - [[NSAttributedString alloc] initWithString:rawTextShadowView.text + [[NSAttributedString alloc] initWithString:[textAttributes applyTextAttributesToText:text] attributes:textAttributes.effectiveTextAttributes]; [attributedText appendAttributedString:rawTextAttributedString]; } diff --git a/Libraries/Text/BaseText/RCTBaseTextViewManager.m b/Libraries/Text/BaseText/RCTBaseTextViewManager.m index a5d0b2c630975c..2cf43ebf38cf6c 100644 --- a/Libraries/Text/BaseText/RCTBaseTextViewManager.m +++ b/Libraries/Text/BaseText/RCTBaseTextViewManager.m @@ -51,5 +51,6 @@ - (RCTShadowView *)shadowView RCT_REMAP_SHADOW_PROPERTY(textShadowColor, textAttributes.textShadowColor, UIColor) // Special RCT_REMAP_SHADOW_PROPERTY(isHighlighted, textAttributes.isHighlighted, BOOL) +RCT_REMAP_SHADOW_PROPERTY(textTransform, textAttributes.textTransform, RCTTextTransform) @end diff --git a/Libraries/Text/RCTConvert+Text.h b/Libraries/Text/RCTConvert+Text.h index 4cead0948ab73c..81a3c7ccfaff94 100644 --- a/Libraries/Text/RCTConvert+Text.h +++ b/Libraries/Text/RCTConvert+Text.h @@ -6,6 +6,7 @@ */ #import +#import NS_ASSUME_NONNULL_BEGIN @@ -13,6 +14,7 @@ NS_ASSUME_NONNULL_BEGIN + (UITextAutocorrectionType)UITextAutocorrectionType:(nullable id)json; + (UITextSpellCheckingType)UITextSpellCheckingType:(nullable id)json; ++ (RCTTextTransform)RCTTextTransform:(nullable id)json; @end diff --git a/Libraries/Text/RCTConvert+Text.m b/Libraries/Text/RCTConvert+Text.m index d4d1b167c8797c..aaf7c1383c1c79 100644 --- a/Libraries/Text/RCTConvert+Text.m +++ b/Libraries/Text/RCTConvert+Text.m @@ -25,4 +25,11 @@ + (UITextSpellCheckingType)UITextSpellCheckingType:(id)json UITextSpellCheckingTypeNo; } +RCT_ENUM_CONVERTER(RCTTextTransform, (@{ + @"none": @(RCTTextTransformNone), + @"capitalize": @(RCTTextTransformCapitalize), + @"uppercase": @(RCTTextTransformUppercase), + @"lowercase": @(RCTTextTransformLowercase), +}), RCTTextTransformUndefined, integerValue) + @end diff --git a/Libraries/Text/RCTText.xcodeproj/project.pbxproj b/Libraries/Text/RCTText.xcodeproj/project.pbxproj index 8fc301593f0373..9765d035fedd03 100644 --- a/Libraries/Text/RCTText.xcodeproj/project.pbxproj +++ b/Libraries/Text/RCTText.xcodeproj/project.pbxproj @@ -104,6 +104,8 @@ 5956B1A7200FF35C008D9D16 /* RCTVirtualTextShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B12E200FEBAA008D9D16 /* RCTVirtualTextShadowView.m */; }; 5956B1A8200FF35C008D9D16 /* RCTVirtualTextViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B12B200FEBAA008D9D16 /* RCTVirtualTextViewManager.m */; }; 5C245F39205E216A00D936E9 /* RCTInputAccessoryShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5C245F37205E216A00D936E9 /* RCTInputAccessoryShadowView.m */; }; + 5970936920845EFC00D163A7 /* RCTTextTransform.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5970936820845DDE00D163A7 /* RCTTextTransform.h */; }; + 5970936A20845F0600D163A7 /* RCTTextTransform.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5970936820845DDE00D163A7 /* RCTTextTransform.h */; }; 8F2807C7202D2B6B005D65E6 /* RCTInputAccessoryViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F2807C1202D2B6A005D65E6 /* RCTInputAccessoryViewManager.m */; }; 8F2807C8202D2B6B005D65E6 /* RCTInputAccessoryView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F2807C3202D2B6A005D65E6 /* RCTInputAccessoryView.m */; }; 8F2807C9202D2B6B005D65E6 /* RCTInputAccessoryViewContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F2807C5202D2B6B005D65E6 /* RCTInputAccessoryViewContent.m */; }; @@ -116,6 +118,7 @@ dstPath = include/RCTText; dstSubfolderSpec = 16; files = ( + 5970936920845EFC00D163A7 /* RCTTextTransform.h in Copy Headers */, 5956B160200FF324008D9D16 /* RCTBaseTextShadowView.h in Copy Headers */, 5956B161200FF324008D9D16 /* RCTBaseTextViewManager.h in Copy Headers */, 5956B162200FF324008D9D16 /* RCTRawTextShadowView.h in Copy Headers */, @@ -151,6 +154,7 @@ dstPath = include/RCTText; dstSubfolderSpec = 16; files = ( + 5970936A20845F0600D163A7 /* RCTTextTransform.h in Copy Headers */, 5956B179200FF338008D9D16 /* RCTBaseTextShadowView.h in Copy Headers */, 5956B17A200FF338008D9D16 /* RCTBaseTextViewManager.h in Copy Headers */, 5956B17B200FF338008D9D16 /* RCTRawTextShadowView.h in Copy Headers */, @@ -235,6 +239,7 @@ 5956B12F200FEBAA008D9D16 /* RCTConvert+Text.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RCTConvert+Text.m"; sourceTree = ""; }; 5C245F37205E216A00D936E9 /* RCTInputAccessoryShadowView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTInputAccessoryShadowView.m; sourceTree = ""; }; 5C245F38205E216A00D936E9 /* RCTInputAccessoryShadowView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTInputAccessoryShadowView.h; sourceTree = ""; }; + 5970936820845DDE00D163A7 /* RCTTextTransform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTextTransform.h; sourceTree = ""; }; 8F2807C1202D2B6A005D65E6 /* RCTInputAccessoryViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTInputAccessoryViewManager.m; sourceTree = ""; }; 8F2807C2202D2B6A005D65E6 /* RCTInputAccessoryViewContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTInputAccessoryViewContent.h; sourceTree = ""; }; 8F2807C3202D2B6A005D65E6 /* RCTInputAccessoryView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTInputAccessoryView.m; sourceTree = ""; }; @@ -254,6 +259,7 @@ 5956B12F200FEBAA008D9D16 /* RCTConvert+Text.m */, 5956B11A200FEBA9008D9D16 /* RCTTextAttributes.h */, 5956B120200FEBA9008D9D16 /* RCTTextAttributes.m */, + 5970936820845DDE00D163A7 /* RCTTextTransform.h */, 5956B121200FEBAA008D9D16 /* Text */, 5956B0FF200FEBA9008D9D16 /* TextInput */, 5956B12A200FEBAA008D9D16 /* VirtualText */, diff --git a/Libraries/Text/RCTTextAttributes.h b/Libraries/Text/RCTTextAttributes.h index df9171c85d0aa1..802211909a42cf 100644 --- a/Libraries/Text/RCTTextAttributes.h +++ b/Libraries/Text/RCTTextAttributes.h @@ -8,6 +8,7 @@ #import #import +#import NS_ASSUME_NONNULL_BEGIN @@ -50,6 +51,7 @@ extern NSString *const RCTTextAttributesTagAttributeName; @property (nonatomic, assign) BOOL isHighlighted; @property (nonatomic, strong, nullable) NSNumber *tag; @property (nonatomic, assign) UIUserInterfaceLayoutDirection layoutDirection; +@property (nonatomic, assign) RCTTextTransform textTransform; #pragma mark - Inheritance @@ -78,6 +80,11 @@ extern NSString *const RCTTextAttributesTagAttributeName; - (UIColor *)effectiveForegroundColor; - (UIColor *)effectiveBackgroundColor; +/** + * Text transformed per 'none', 'uppercase', 'lowercase', 'capitalize' + */ +- (NSString *)applyTextAttributesToText:(NSString *)text; + @end NS_ASSUME_NONNULL_END diff --git a/Libraries/Text/RCTTextAttributes.m b/Libraries/Text/RCTTextAttributes.m index d74e0ab7611b57..4309138d00fe09 100644 --- a/Libraries/Text/RCTTextAttributes.m +++ b/Libraries/Text/RCTTextAttributes.m @@ -28,6 +28,7 @@ - (instancetype)init _baseWritingDirection = NSWritingDirectionNatural; _textShadowRadius = NAN; _opacity = NAN; + _textTransform = RCTTextTransformUndefined; } return self; @@ -73,6 +74,7 @@ - (void)applyTextAttributes:(RCTTextAttributes *)textAttributes _isHighlighted = textAttributes->_isHighlighted || _isHighlighted; // * _tag = textAttributes->_tag ?: _tag; _layoutDirection = textAttributes->_layoutDirection != UIUserInterfaceLayoutDirectionLeftToRight ? textAttributes->_layoutDirection : _layoutDirection; + _textTransform = textAttributes->_textTransform != RCTTextTransformUndefined ? textAttributes->_textTransform : _textTransform; } - (NSDictionary *)effectiveTextAttributes @@ -214,6 +216,21 @@ - (UIColor *)effectiveBackgroundColor return effectiveBackgroundColor ?: [UIColor clearColor]; } +- (NSString *)applyTextAttributesToText:(NSString *)text +{ + switch (_textTransform) { + case RCTTextTransformUndefined: + case RCTTextTransformNone: + return text; + case RCTTextTransformLowercase: + return [text lowercaseString]; + case RCTTextTransformUppercase: + return [text uppercaseString]; + case RCTTextTransformCapitalize: + return [text capitalizedString]; + } +} + - (RCTTextAttributes *)copyWithZone:(NSZone *)zone { RCTTextAttributes *textAttributes = [RCTTextAttributes new]; @@ -263,7 +280,8 @@ - (BOOL)isEqual:(RCTTextAttributes *)textAttributes // Special RCTTextAttributesCompareOthers(_isHighlighted) && RCTTextAttributesCompareObjects(_tag) && - RCTTextAttributesCompareOthers(_layoutDirection); + RCTTextAttributesCompareOthers(_layoutDirection) && + RCTTextAttributesCompareOthers(_textTransform); } @end diff --git a/Libraries/Text/RCTTextTransform.h b/Libraries/Text/RCTTextTransform.h new file mode 100644 index 00000000000000..eddebd0f0c207e --- /dev/null +++ b/Libraries/Text/RCTTextTransform.h @@ -0,0 +1,16 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +typedef NS_ENUM(NSInteger, RCTTextTransform) { + RCTTextTransformUndefined = 0, + RCTTextTransformNone, + RCTTextTransformCapitalize, + RCTTextTransformUppercase, + RCTTextTransformLowercase, +}; diff --git a/Libraries/Text/TextStylePropTypes.js b/Libraries/Text/TextStylePropTypes.js index c5e67ca99e17f5..872497ecf2ee1f 100644 --- a/Libraries/Text/TextStylePropTypes.js +++ b/Libraries/Text/TextStylePropTypes.js @@ -84,6 +84,12 @@ const TextStylePropTypes = { * @platform ios */ textDecorationColor: ColorPropType, + /** + * @platform ios + */ + textTransform: ReactPropTypes.oneOf( + ['none' /*default*/, 'capitalize', 'uppercase', 'lowercase'] + ), /** * @platform ios */ diff --git a/RNTester/js/TextExample.ios.js b/RNTester/js/TextExample.ios.js index e5510390d0a353..939774aa06a0f6 100644 --- a/RNTester/js/TextExample.ios.js +++ b/RNTester/js/TextExample.ios.js @@ -860,6 +860,42 @@ exports.examples = [ title: 'Text `alignItems: \'baseline\'` style', render: function() { return ; + } + }, + { + title: 'Transform', + render: function() { + return ( + + + This text should be uppercased. + + + This TEXT SHOULD be lowercased. + + + This text should be CAPITALIZED. + + + Mixed:{' '} + + uppercase{' '} + + + LoWeRcAsE{' '} + + + capitalize each word + + + Should be "ABC": + abc + + Should be "AbC": + abc + + + ); }, }, ]; From 8102e35271ab68e0525a9c60d86a855bbeef9c1a Mon Sep 17 00:00:00 2001 From: "Andrew Chen (Eng)" Date: Mon, 16 Apr 2018 12:16:11 -0700 Subject: [PATCH 0306/1109] Fix originalNode memory leak Reviewed By: mdvacca Differential Revision: D7608359 fbshipit-source-id: 7cf69f987d4c92202ea5794b76345cb1c685f881 --- .../main/java/com/facebook/react/fabric/FabricReconciler.java | 4 ++-- .../main/java/com/facebook/react/fabric/FabricUIManager.java | 4 +++- .../com/facebook/react/uimanager/ReactShadowNodeImpl.java | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java index 3e8eca9cabeb73..ddd3a386fc383e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricReconciler.java @@ -61,7 +61,7 @@ private void manageChildren( } enqueueUpdateProperties(newNode); manageChildren(prevNode, prevNode.getChildrenList(), newNode.getChildrenList()); - prevNode.setOriginalReactShadowNode(newNode); + newNode.setOriginalReactShadowNode(null); } int firstRemovedOrAddedViewIndex = sameReactTagIndex; @@ -78,7 +78,7 @@ private void manageChildren( viewsToAdd.add(new ViewAtIndex(newNode.getReactTag(), k)); List previousChildrenList = newNode.getOriginalReactShadowNode() == null ? null : newNode.getOriginalReactShadowNode().getChildrenList(); manageChildren(newNode, previousChildrenList, newNode.getChildrenList()); - newNode.setOriginalReactShadowNode(newNode); + newNode.setOriginalReactShadowNode(null); addedTags.add(newNode.getReactTag()); } 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 50e24738bf5699..191d463ab725c3 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -18,6 +18,7 @@ import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReadableNativeMap; import com.facebook.react.bridge.UIManager; +import com.facebook.react.common.annotations.VisibleForTesting; import com.facebook.react.modules.i18nmanager.I18nUtil; import com.facebook.react.uimanager.DisplayMetricsHolder; import com.facebook.react.uimanager.NativeViewHierarchyManager; @@ -95,7 +96,8 @@ public ReactShadowNode createNode( } } - private ReactShadowNode getRootNode(int rootTag) { + @VisibleForTesting + ReactShadowNode getRootNode(int rootTag) { return mRootShadowNodeRegistry.getNode(rootTag); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java index 018fa5ddace08b..d0eb127f6e29e4 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java @@ -11,7 +11,6 @@ import android.util.Log; import com.facebook.infer.annotation.Assertions; import com.facebook.react.uimanager.annotations.ReactPropertyHolder; -import com.facebook.yoga.YogaNodeCloneFunction; import com.facebook.yoga.YogaAlign; import com.facebook.yoga.YogaBaselineFunction; import com.facebook.yoga.YogaConfig; @@ -23,6 +22,7 @@ import com.facebook.yoga.YogaJustify; import com.facebook.yoga.YogaMeasureFunction; import com.facebook.yoga.YogaNode; +import com.facebook.yoga.YogaNodeCloneFunction; import com.facebook.yoga.YogaOverflow; import com.facebook.yoga.YogaPositionType; import com.facebook.yoga.YogaValue; From a275eac56e21b8f3631bcd03ace86c07a3b0c0ba Mon Sep 17 00:00:00 2001 From: Sophie Alpert Date: Mon, 16 Apr 2018 13:03:50 -0700 Subject: [PATCH 0307/1109] Clean up some grossness in ScrollResponder Summary: Still gross but less gross. Reviewed By: sebmarkbage Differential Revision: D7107180 fbshipit-source-id: 31f1639a8f44e4ab247c338001a4a5c9b4b83cdf --- Libraries/Components/ScrollResponder.js | 28 ++++++------ Libraries/Components/TextInput/TextInput.js | 44 +++++++++++-------- .../Components/TextInput/TextInputState.js | 16 ++++++- 3 files changed, 54 insertions(+), 34 deletions(-) diff --git a/Libraries/Components/ScrollResponder.js b/Libraries/Components/ScrollResponder.js index 9d60c462ef1dc7..6c926b9d40e135 100644 --- a/Libraries/Components/ScrollResponder.js +++ b/Libraries/Components/ScrollResponder.js @@ -23,7 +23,6 @@ const performanceNow = require('fbjs/lib/performanceNow'); const warning = require('fbjs/lib/warning'); const { ScrollViewManager } = require('NativeModules'); -const { getInstanceFromNode } = require('ReactNativeComponentTree'); /** * Mixin that can be integrated in order to handle scrolling that plays well @@ -114,15 +113,6 @@ type State = { }; type Event = Object; -function isTagInstanceOfTextInput(tag) { - const instance = getInstanceFromNode(tag); - return instance && instance.viewConfig && ( - instance.viewConfig.uiViewClassName === 'AndroidTextInput' || - instance.viewConfig.uiViewClassName === 'RCTMultilineTextInputView' || - instance.viewConfig.uiViewClassName === 'RCTSinglelineTextInputView' - ); -} - const ScrollResponderMixin = { mixins: [Subscribable.Mixin], scrollResponderMixinGetInitialState: function(): State { @@ -196,17 +186,27 @@ const ScrollResponderMixin = { * Invoke this from an `onStartShouldSetResponderCapture` event. */ scrollResponderHandleStartShouldSetResponderCapture: function(e: Event): boolean { - // First see if we want to eat taps while the keyboard is up + // The scroll view should receive taps instead of its descendants if: + // * it is already animating/decelerating + if (this.scrollResponderIsAnimating()) { + return true; + } + + // * the keyboard is up, keyboardShouldPersistTaps is 'never' (the default), + // and a new touch starts with a non-textinput target (in which case the + // first tap should be sent to the scroll view and dismiss the keyboard, + // then the second tap goes to the actual interior view) const currentlyFocusedTextInput = TextInputState.currentlyFocusedField(); const {keyboardShouldPersistTaps} = this.props; const keyboardNeverPersistTaps = !keyboardShouldPersistTaps || keyboardShouldPersistTaps === 'never'; if (keyboardNeverPersistTaps && - currentlyFocusedTextInput != null && - !isTagInstanceOfTextInput(e.target)) { + currentlyFocusedTextInput != null + /* && !TextInputState.isTextInput(e.target) */) { return true; } - return this.scrollResponderIsAnimating(); + + return false; }, /** diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js index eb838174f15184..fd67b8ec55fc0a 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -192,10 +192,6 @@ const DataDetectorTypes = [ const TextInput = createReactClass({ displayName: 'TextInput', - statics: { - /* TODO(brentvatne) docs are needed for this */ - State: TextInputState, - }, propTypes: { ...ViewPropTypes, @@ -667,24 +663,30 @@ const TextInput = createReactClass({ componentDidMount: function() { this._lastNativeText = this.props.value; - if (!this.context.focusEmitter) { + const tag = ReactNative.findNodeHandle(this._inputRef); + if (tag != null) { + // tag is null only in unit tests + TextInputState.registerInput(tag); + } + + if (this.context.focusEmitter) { + this._focusSubscription = this.context.focusEmitter.addListener( + 'focus', + el => { + if (this === el) { + this.requestAnimationFrame(this.focus); + } else if (this.isFocused()) { + this.blur(); + } + }, + ); + if (this.props.autoFocus) { + this.context.onFocusRequested(this); + } + } else { if (this.props.autoFocus) { this.requestAnimationFrame(this.focus); } - return; - } - this._focusSubscription = this.context.focusEmitter.addListener( - 'focus', - el => { - if (this === el) { - this.requestAnimationFrame(this.focus); - } else if (this.isFocused()) { - this.blur(); - } - }, - ); - if (this.props.autoFocus) { - this.context.onFocusRequested(this); } }, @@ -693,6 +695,10 @@ const TextInput = createReactClass({ if (this.isFocused()) { this.blur(); } + const tag = ReactNative.findNodeHandle(this._inputRef); + if (tag != null) { + TextInputState.unregisterInput(tag); + } }, getChildContext(): ViewChildContext { diff --git a/Libraries/Components/TextInput/TextInputState.js b/Libraries/Components/TextInput/TextInputState.js index afcca82bf320f3..cb41eef0c529af 100644 --- a/Libraries/Components/TextInput/TextInputState.js +++ b/Libraries/Components/TextInput/TextInputState.js @@ -16,6 +16,8 @@ const Platform = require('Platform'); const UIManager = require('UIManager'); +const inputs = new Set(); + const TextInputState = { /** * Internal state @@ -68,7 +70,19 @@ const TextInputState = { ); } } - } + }, + + registerInput: function(textFieldID: number) { + inputs.add(textFieldID); + }, + + unregisterInput: function(textFieldID: number) { + inputs.delete(textFieldID); + }, + + isTextInput: function(textFieldID: number) { + return inputs.has(textFieldID); + }, }; module.exports = TextInputState; From 311a7a8e82719d61d1e95c262d8535ddb6d214aa Mon Sep 17 00:00:00 2001 From: "Andrew Chen (Eng)" Date: Mon, 16 Apr 2018 13:19:33 -0700 Subject: [PATCH 0308/1109] Use the provided NativeModuleCallExceptionHandler if provided Summary: Before, any calls to ReactContext would either use the default DevSupportManager's exception handler in debug mode OR throw exceptions immediately in non debug mode. In order to intercept these kinds of native exceptions, we should reuse the NativeModuleCallExceptionHandler provided by the ReactInstanceManager. For those who don't specify a NativeModuleCallExceptionHandler, the resulting behavior remains the same. For those who do specify a NativeModuleCallExceptionHandler, the main difference is that it will now be responsible for handling exceptions for ReactContext.handleException Reviewed By: mdvacca Differential Revision: D7641772 fbshipit-source-id: 8f175df687723fcbb8a7620f90d8a08c94798738 --- .../java/com/facebook/react/ReactInstanceManager.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java index 250f2091af7250..26ee98a9a03417 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java @@ -1070,15 +1070,13 @@ private ReactApplicationContext createReactContext( ReactMarker.logMarker(CREATE_REACT_CONTEXT_START); final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext); - if (mUseDeveloperSupport) { - reactContext.setNativeModuleCallExceptionHandler(mDevSupportManager); - } + NativeModuleCallExceptionHandler exceptionHandler = mNativeModuleCallExceptionHandler != null + ? mNativeModuleCallExceptionHandler + : mDevSupportManager; + reactContext.setNativeModuleCallExceptionHandler(exceptionHandler); NativeModuleRegistry nativeModuleRegistry = processPackages(reactContext, mPackages, false); - NativeModuleCallExceptionHandler exceptionHandler = mNativeModuleCallExceptionHandler != null - ? mNativeModuleCallExceptionHandler - : mDevSupportManager; CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder() .setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault()) .setJSExecutor(jsExecutor) From 660a578aebc9acb1c976cc7ed8ac9cf67ec657d4 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Mon, 16 Apr 2018 13:58:29 -0700 Subject: [PATCH 0309/1109] Fix cloning for ReactTextInputShadowNode Reviewed By: shergin Differential Revision: D7628252 fbshipit-source-id: 034f2d619f716600dde21a5dd43538c261be773b --- .../textinput/ReactTextInputShadowNode.java | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java index 2fb427ee805793..1336314cdae3ba 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java @@ -15,6 +15,7 @@ import com.facebook.react.bridge.JSApplicationIllegalArgumentException; import com.facebook.react.common.annotations.VisibleForTesting; import com.facebook.react.uimanager.LayoutShadowNode; +import com.facebook.react.uimanager.ReactShadowNodeImpl; import com.facebook.react.uimanager.Spacing; import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.UIViewOperationQueue; @@ -53,16 +54,33 @@ private ReactTextInputShadowNode(ReactTextInputShadowNode node) { mMostRecentEventCount = node.mMostRecentEventCount; mText = node.mText; mLocalData = node.mLocalData; - setMeasureFunction(this); + } + + @Override + protected ReactTextInputShadowNode copy() { + return new ReactTextInputShadowNode(this); + } + + @Override + public ReactTextInputShadowNode mutableCopy() { + ReactTextInputShadowNode node = (ReactTextInputShadowNode) super.mutableCopy(); + node.setMeasureFunction(this); ThemedReactContext themedContext = getThemedContext(); if (themedContext != null) { - setThemedContext(themedContext); + node.setThemedContext(themedContext); } + return node; } @Override - protected ReactTextInputShadowNode copy() { - return new ReactTextInputShadowNode(this); + public ReactTextInputShadowNode mutableCopyWithNewChildren() { + ReactTextInputShadowNode node = (ReactTextInputShadowNode) super.mutableCopyWithNewChildren(); + node.setMeasureFunction(this); + ThemedReactContext themedContext = getThemedContext(); + if (themedContext != null) { + node.setThemedContext(themedContext); + } + return node; } @Override From d8fcdb9bd7a308ed70caeac1b53da0a05abe452f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leo=20Nikkil=C3=A4?= Date: Mon, 16 Apr 2018 14:00:30 -0700 Subject: [PATCH 0310/1109] Fix view indices with Android LayoutAnimation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Fixes issue #11828 that causes layout animations for removed views to remove some adjacent views as well. This happens because the animated views are still present in the ViewGroup, which throws off subsequent operations that rely on view indices having updated. This issue was addressed in #11962, which was closed in favour of a more reliable solution that addresses the issue globally since it’s difficult to account for animated views everywhere. janicduplessis [recommended][0] handling the issue through ViewManager. Since API 11, Android provides `ViewGroup#startViewTransition(View)` that can be used to keep child views visible even if they have been removed from the group. ViewGroup keeps an array of these views, which is only used for drawing. Methods such as `ViewGroup#getChildCount()` and `ViewGroup#getChildAt(int)` will ignore them. I believe relying on these framework methods within ViewManager is the most reliable way to solve this issue because it also works if callers ignore ViewManager and reach into the native view indices and counts directly. [0]: https://github.com/facebook/react-native/pull/11962#pullrequestreview-21862640 I wrote a minimal test app that you can find here: The expected result is that the red and green squares disappear, a blue one appears, and the black one stays in place. iOS has this behaviour, but Android removes the black square as well. We can see the bug with some breakpoint logging. Without LayoutAnimation: ``` NativeViewHierarchyOptimizer: Removing node from parent with tag 2 at index 0 NativeViewHierarchyOptimizer: Removing node from parent with tag 4 at index 1 NativeViewHierarchyManager: Removing indices [0] with tags [2] RootViewManager: Removing child view at index 0 with tag 2 NativeViewHierarchyManager: Removing indices [1] with tags [4] RootViewManager: Removing child view at index 1 with tag 4 ``` With LayoutAnimation tag 3 gets removed when it shouldn’t be: ``` NativeViewHierarchyOptimizer: Removing node from parent with tag 2 at index 0 NativeViewHierarchyOptimizer: Removing node from parent with tag 4 at index 1 NativeViewHierarchyManager: Removing indices [0] with tags [2] NativeViewHierarchyManager: Removing indices [1] with tags [4] -> RootViewManager: Removing child view at index 1 with tag 3 RootViewManager: Removing child view at index 2 with tag 4 (Animation listener kicks in here) RootViewManager: Removing child view at index 1 with tag 2 ``` Here are some GIFs to compare, click to expand:
Current master (iOS vs Android)

With this patch (iOS vs Android, fixed)

Previously addressed in #11962, which wasn’t merged. Tangentially related to my other LayoutAnimation PR #18651. No documentation changes needed. [ANDROID] [BUGFIX] [LayoutAnimation] - Removal LayoutAnimations no longer remove adjacent views as well in certain cases. Closes https://github.com/facebook/react-native/pull/18830 Reviewed By: achen1 Differential Revision: D7612904 Pulled By: mdvacca fbshipit-source-id: a04cf47ab80e0e813fa043125b1f907e212b1ad4 --- .../react/uimanager/NativeViewHierarchyManager.java | 13 ++++++++----- .../facebook/react/uimanager/ViewGroupManager.java | 8 ++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java index a57205b861ebe2..2b72a0a3333088 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java @@ -373,12 +373,13 @@ public synchronized void manageChildren( if (mLayoutAnimationEnabled && mLayoutAnimator.shouldAnimateLayout(viewToRemove) && arrayContains(tagsToDelete, viewToRemove.getId())) { - // The view will be removed and dropped by the 'delete' layout animation - // instead, so do nothing - } else { - viewManager.removeViewAt(viewToManage, indexToRemove); + // Display the view in the parent after removal for the duration of the layout animation, + // but pretend that it doesn't exist when calling other ViewGroup methods. + viewManager.startViewTransition(viewToManage, viewToRemove); } + viewManager.removeViewAt(viewToManage, indexToRemove); + lastIndexToRemove = indexToRemove; } } @@ -423,7 +424,9 @@ public synchronized void manageChildren( mLayoutAnimator.deleteView(viewToDestroy, new LayoutAnimationListener() { @Override public void onAnimationEnd() { - viewManager.removeView(viewToManage, viewToDestroy); + // Already removed from the ViewGroup, we can just end the transition here to + // release the child. + viewManager.endViewTransition(viewToManage, viewToDestroy); dropView(viewToDestroy); } }); diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewGroupManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewGroupManager.java index 017fb5764e7237..c4d5eed429dde7 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewGroupManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewGroupManager.java @@ -93,6 +93,14 @@ public void removeAllViews(T parent) { } } + public void startViewTransition(T parent, View view) { + parent.startViewTransition(view); + } + + public void endViewTransition(T parent, View view) { + parent.endViewTransition(view); + } + /** * Returns whether this View type needs to handle laying out its own children instead of * deferring to the standard css-layout algorithm. From eff98b6c252476067518bb5525eb4338fdc21823 Mon Sep 17 00:00:00 2001 From: "Andrew Chen (Eng)" Date: Mon, 16 Apr 2018 16:07:36 -0700 Subject: [PATCH 0311/1109] Better error message for invalid native module Reviewed By: mdvacca Differential Revision: D7641828 fbshipit-source-id: b1500029da49b60b6a69bc61ecc7f72629f65dcb --- .../java/com/facebook/react/bridge/NativeModuleRegistry.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java index d30b7a5a378890..66c73e6af16890 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java @@ -141,7 +141,8 @@ public boolean hasModule(Class moduleInterface) { } public T getModule(Class moduleInterface) { - return (T) Assertions.assertNotNull(mModules.get(moduleInterface)).getModule(); + return (T) Assertions.assertNotNull( + mModules.get(moduleInterface), moduleInterface.getSimpleName()).getModule(); } public List getAllModules() { From 7f7020a1dbcbbf843252b470c74cf5c135935683 Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Tue, 17 Apr 2018 01:19:19 -0700 Subject: [PATCH 0312/1109] Fix up wrapped macros Reviewed By: mzlee Differential Revision: D7645524 fbshipit-source-id: e62101dac95fd7458a2519588105ce43607a9769 --- ReactNative/DEFS.bzl | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ReactNative/DEFS.bzl b/ReactNative/DEFS.bzl index 13402b1bc87897..135bacfbc93d2c 100644 --- a/ReactNative/DEFS.bzl +++ b/ReactNative/DEFS.bzl @@ -183,7 +183,3 @@ def cxx_library(allow_jni_merging=None, **kwargs): if not (k.startswith("fbandroid_") or k.startswith("fbobjc_")) } native.cxx_library(**args) - - -def fb_android_library(**kwargs): - native.android_library(**kwargs) From d31dfd6db09a5347768466906892d8c61550f233 Mon Sep 17 00:00:00 2001 From: Peter van der Zee Date: Tue, 17 Apr 2018 05:02:02 -0700 Subject: [PATCH 0313/1109] Remove babel packages from package.json Reviewed By: fkgozali Differential Revision: D7635547 fbshipit-source-id: d0fd9f7c2adde9ff56699dc5c4bc691f94b15772 --- package.json | 9 --------- 1 file changed, 9 deletions(-) diff --git a/package.json b/package.json index df681175da83ca..01c8d57da21e11 100644 --- a/package.json +++ b/package.json @@ -147,15 +147,6 @@ "dependencies": { "absolute-path": "^0.0.0", "art": "^0.10.0", - "babel-core": "^6.24.1", - "babel-plugin-syntax-trailing-function-commas": "^6.20.0", - "babel-plugin-transform-async-to-generator": "6.16.0", - "babel-plugin-transform-class-properties": "^6.18.0", - "babel-plugin-transform-exponentiation-operator": "^6.5.0", - "babel-plugin-transform-flow-strip-types": "^6.21.0", - "babel-plugin-transform-object-rest-spread": "^6.20.2", - "babel-register": "^6.24.1", - "babel-runtime": "^6.23.0", "base64-js": "^1.1.2", "chalk": "^1.1.1", "commander": "^2.9.0", From 6de4ff36b0c5065e9fec9dac6998984552a7418e Mon Sep 17 00:00:00 2001 From: Peter van der Zee Date: Tue, 17 Apr 2018 05:11:58 -0700 Subject: [PATCH 0314/1109] Fix babel-preset-react-native, bump it to babel 7 Reviewed By: yungsters Differential Revision: D7635490 fbshipit-source-id: 9f32f4389178904c68e0a03fee0485372ec10900 --- babel-preset/lib/resolvePlugins.js | 2 +- babel-preset/package.json | 58 ++++++++++++++---------------- babel-preset/plugins.js | 54 ++++++++++++++-------------- 3 files changed, 54 insertions(+), 60 deletions(-) diff --git a/babel-preset/lib/resolvePlugins.js b/babel-preset/lib/resolvePlugins.js index ebbe5ddacfc559..0291c94e70f8d1 100644 --- a/babel-preset/lib/resolvePlugins.js +++ b/babel-preset/lib/resolvePlugins.js @@ -21,7 +21,7 @@ function resolvePlugins(plugins, prefix) { /** * Manually resolve a single Babel plugin. */ -function resolvePlugin(plugin, prefix = 'babel-plugin-') { +function resolvePlugin(plugin, prefix = '@babel/plugin-') { // Normalise plugin to an array. if (!Array.isArray(plugin)) { plugin = [plugin]; diff --git a/babel-preset/package.json b/babel-preset/package.json index 3181ee146f24a4..066af5f61b1537 100644 --- a/babel-preset/package.json +++ b/babel-preset/package.json @@ -15,37 +15,31 @@ }, "homepage": "https://github.com/facebook/react-native/tree/master/babel-preset/README.md", "dependencies": { - "babel-plugin-check-es2015-constants": "^6.5.0", - "babel-plugin-react-transform": "^3.0.0", - "babel-plugin-syntax-async-functions": "^6.5.0", - "babel-plugin-syntax-class-properties": "^6.5.0", - "babel-plugin-syntax-dynamic-import": "^6.18.0", - "babel-plugin-syntax-flow": "^6.5.0", - "babel-plugin-syntax-jsx": "^6.5.0", - "babel-plugin-syntax-trailing-function-commas": "^6.5.0", - "babel-plugin-transform-class-properties": "^6.5.0", - "babel-plugin-transform-es2015-arrow-functions": "^6.5.0", - "babel-plugin-transform-es2015-block-scoping": "^6.5.0", - "babel-plugin-transform-es2015-classes": "^6.5.0", - "babel-plugin-transform-es2015-computed-properties": "^6.5.0", - "babel-plugin-transform-es2015-destructuring": "^6.5.0", - "babel-plugin-transform-es2015-for-of": "^6.5.0", - "babel-plugin-transform-es2015-function-name": "^6.5.0", - "babel-plugin-transform-es2015-literals": "^6.5.0", - "babel-plugin-transform-es2015-modules-commonjs": "^6.5.0", - "babel-plugin-transform-es2015-parameters": "^6.5.0", - "babel-plugin-transform-es2015-shorthand-properties": "^6.5.0", - "babel-plugin-transform-es2015-spread": "^6.5.0", - "babel-plugin-transform-es2015-template-literals": "^6.5.0", - "babel-plugin-transform-exponentiation-operator": "^6.5.0", - "babel-plugin-transform-flow-strip-types": "^6.5.0", - "babel-plugin-transform-object-assign": "^6.5.0", - "babel-plugin-transform-object-rest-spread": "^6.5.0", - "babel-plugin-transform-react-display-name": "^6.5.0", - "babel-plugin-transform-react-jsx": "^6.5.0", - "babel-plugin-transform-react-jsx-source": "^6.5.0", - "babel-plugin-transform-regenerator": "^6.5.0", - "babel-template": "^6.24.1", - "react-transform-hmr": "^1.0.4" + "@babel/plugin-proposal-class-properties": "^7.0.0-beta", + "@babel/plugin-proposal-object-rest-spread": "^7.0.0-beta", + "@babel/plugin-transform-arrow-functions": "^7.0.0-beta", + "@babel/plugin-transform-block-scoping": "^7.0.0-beta", + "@babel/plugin-transform-classes": "^7.0.0-beta", + "@babel/plugin-transform-computed-properties": "^7.0.0-beta", + "@babel/plugin-transform-destructuring": "^7.0.0-beta", + "@babel/plugin-transform-exponentiation-operator": "^7.0.0-beta", + "@babel/plugin-transform-flow-strip-types": "^7.0.0-beta", + "@babel/plugin-transform-for-of": "^7.0.0-beta", + "@babel/plugin-transform-function-name": "^7.0.0-beta", + "@babel/plugin-transform-literals": "^7.0.0-beta", + "@babel/plugin-transform-modules-commonjs": "^7.0.0-beta", + "@babel/plugin-transform-object-assign": "^7.0.0-beta", + "@babel/plugin-transform-parameters": "^7.0.0-beta", + "@babel/plugin-transform-shorthand-properties": "^7.0.0-beta", + "@babel/plugin-transform-react-display-name": "^7.0.0-beta", + "@babel/plugin-transform-react-jsx": "^7.0.0-beta", + "@babel/plugin-transform-react-jsx-source": "^7.0.0-beta", + "@babel/plugin-transform-regenerator": "^7.0.0-beta", + "@babel/plugin-transform-spread": "^7.0.0-beta", + "@babel/plugin-transform-sticky-regex": "^7.0.0-beta", + "@babel/plugin-transform-unicode-regex": "^7.0.0-beta", + "@babel/plugin-transform-template-literals": "^7.0.0-beta", + "@babel/template": "^7.0.0-beta", + "metro-babel7-plugin-react-transform": "0.32.0" } } diff --git a/babel-preset/plugins.js b/babel-preset/plugins.js index d572a11b042e54..b53d23bbe4fc94 100644 --- a/babel-preset/plugins.js +++ b/babel-preset/plugins.js @@ -3,35 +3,35 @@ * * 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'; module.exports = { - 'babel-plugin-react-transform': require('babel-plugin-react-transform'), - 'babel-plugin-syntax-async-functions': require('babel-plugin-syntax-async-functions'), - 'babel-plugin-syntax-class-properties': require('babel-plugin-syntax-class-properties'), - 'babel-plugin-syntax-dynamic-import': require('babel-plugin-syntax-dynamic-import'), - 'babel-plugin-syntax-trailing-function-commas': require('babel-plugin-syntax-trailing-function-commas'), - 'babel-plugin-transform-class-properties': require('babel-plugin-transform-class-properties'), - 'babel-plugin-transform-es2015-function-name': require('babel-plugin-transform-es2015-function-name'), - 'babel-plugin-transform-es2015-arrow-functions': require('babel-plugin-transform-es2015-arrow-functions'), - 'babel-plugin-transform-es2015-block-scoping': require('babel-plugin-transform-es2015-block-scoping'), - 'babel-plugin-transform-es2015-classes': require('babel-plugin-transform-es2015-classes'), - 'babel-plugin-transform-es2015-computed-properties': require('babel-plugin-transform-es2015-computed-properties'), - 'babel-plugin-check-es2015-constants': require('babel-plugin-check-es2015-constants'), - 'babel-plugin-transform-es2015-destructuring': require('babel-plugin-transform-es2015-destructuring'), - 'babel-plugin-transform-es2015-modules-commonjs': require('babel-plugin-transform-es2015-modules-commonjs'), - 'babel-plugin-transform-es2015-parameters': require('babel-plugin-transform-es2015-parameters'), - 'babel-plugin-transform-es2015-shorthand-properties': require('babel-plugin-transform-es2015-shorthand-properties'), - 'babel-plugin-transform-es2015-spread': require('babel-plugin-transform-es2015-spread'), - 'babel-plugin-transform-es2015-template-literals': require('babel-plugin-transform-es2015-template-literals'), - 'babel-plugin-transform-es2015-literals' : require('babel-plugin-transform-es2015-literals'), - 'babel-plugin-transform-flow-strip-types': require('babel-plugin-transform-flow-strip-types'), - 'babel-plugin-transform-object-assign': require('babel-plugin-transform-object-assign'), - 'babel-plugin-transform-object-rest-spread': require('babel-plugin-transform-object-rest-spread'), - 'babel-plugin-transform-react-display-name': require('babel-plugin-transform-react-display-name'), - 'babel-plugin-transform-react-jsx-source': require('babel-plugin-transform-react-jsx-source'), - 'babel-plugin-transform-react-jsx': require('babel-plugin-transform-react-jsx'), - 'babel-plugin-transform-regenerator': require('babel-plugin-transform-regenerator'), - 'babel-plugin-transform-es2015-for-of': require('babel-plugin-transform-es2015-for-of'), + '@babel/plugin-proposal-class-properties': require('@babel/plugin-proposal-class-properties'), + '@babel/plugin-proposal-object-rest-spread': require('@babel/plugin-proposal-object-rest-spread'), + '@babel/plugin-transform-arrow-functions': require('@babel/plugin-transform-arrow-functions'), + '@babel/plugin-transform-block-scoping': require('@babel/plugin-transform-block-scoping'), + '@babel/plugin-transform-classes': require('@babel/plugin-transform-classes'), + '@babel/plugin-transform-computed-properties': require('@babel/plugin-transform-computed-properties'), + '@babel/plugin-transform-destructuring': require('@babel/plugin-transform-destructuring'), + '@babel/plugin-transform-exponentiation-operator': require('@babel/plugin-transform-exponentiation-operator'), + '@babel/plugin-transform-flow-strip-types': require('@babel/plugin-transform-flow-strip-types'), + '@babel/plugin-transform-for-of': require('@babel/plugin-transform-for-of'), + '@babel/plugin-transform-function-name': require('@babel/plugin-transform-function-name'), + '@babel/plugin-transform-literals': require('@babel/plugin-transform-literals'), + '@babel/plugin-transform-modules-commonjs': require('@babel/plugin-transform-modules-commonjs'), + '@babel/plugin-transform-object-assign': require('@babel/plugin-transform-object-assign'), + '@babel/plugin-transform-parameters': require('@babel/plugin-transform-parameters'), + '@babel/plugin-transform-shorthand-properties': require('@babel/plugin-transform-shorthand-properties'), + '@babel/plugin-transform-react-display-name': require('@babel/plugin-transform-react-display-name'), + '@babel/plugin-transform-react-jsx': require('@babel/plugin-transform-react-jsx'), + '@babel/plugin-transform-react-jsx-source': require('@babel/plugin-transform-react-jsx-source'), + '@babel/plugin-transform-regenerator': require('@babel/plugin-transform-regenerator'), + '@babel/plugin-transform-spread': require('@babel/plugin-transform-spread'), + '@babel/plugin-transform-sticky-regex': require('@babel/plugin-transform-sticky-regex'), + '@babel/plugin-transform-unicode-regex': require('@babel/plugin-transform-unicode-regex'), + '@babel/plugin-transform-template-literals': require('@babel/plugin-transform-template-literals'), }; From d2a1461d26df4c1b29362c0f6900fbf639d243d8 Mon Sep 17 00:00:00 2001 From: Avik Chaudhuri Date: Tue, 17 Apr 2018 05:37:02 -0700 Subject: [PATCH 0315/1109] @allow-large-files clean up xplat/js for flow 0.70.0 Reviewed By: fishythefish Differential Revision: D7643236 fbshipit-source-id: 1d9a95f1e249ce3fdc552a4ca92a6c63b267dae4 --- .flowconfig | 2 +- Libraries/Animated/src/nodes/AnimatedInterpolation.js | 3 +++ Libraries/Components/Switch/Switch.js | 9 +++++++++ Libraries/Lists/VirtualizedList.js | 3 +++ RNTester/js/PointerEventsExample.js | 3 +++ RNTester/js/ScrollViewExample.js | 10 ++++++++-- local-cli/templates/HelloWorld/_flowconfig | 2 +- local-cli/util/Config.js | 3 +++ package.json | 2 +- 9 files changed, 32 insertions(+), 5 deletions(-) diff --git a/.flowconfig b/.flowconfig index f67339eee78487..386c9389a49803 100644 --- a/.flowconfig +++ b/.flowconfig @@ -52,4 +52,4 @@ suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError [version] -^0.69.0 +^0.70.0 diff --git a/Libraries/Animated/src/nodes/AnimatedInterpolation.js b/Libraries/Animated/src/nodes/AnimatedInterpolation.js index eb4cc5d6995d77..bc7b1365879db8 100644 --- a/Libraries/Animated/src/nodes/AnimatedInterpolation.js +++ b/Libraries/Animated/src/nodes/AnimatedInterpolation.js @@ -350,6 +350,9 @@ class AnimatedInterpolation extends AnimatedWithChildren { __transformDataType(range: Array) { // Change the string array type to number array // So we can reuse the same logic in iOS and Android platform + /* $FlowFixMe(>=0.70.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.70 was deployed. To see the error delete this + * comment and run Flow. */ return range.map(function(value) { if (typeof value !== 'string') { return value; diff --git a/Libraries/Components/Switch/Switch.js b/Libraries/Components/Switch/Switch.js index e88272dacfa1d0..f259229c3538aa 100644 --- a/Libraries/Components/Switch/Switch.js +++ b/Libraries/Components/Switch/Switch.js @@ -102,9 +102,18 @@ const Switch = createReactClass({ props.onStartShouldSetResponder = () => true; props.onResponderTerminationRequest = () => false; if (Platform.OS === 'android') { + /* $FlowFixMe(>=0.70.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.70 was deployed. To see the error delete + * this comment and run Flow. */ props.enabled = !this.props.disabled; + /* $FlowFixMe(>=0.70.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.70 was deployed. To see the error delete + * this comment and run Flow. */ props.on = this.props.value; props.style = this.props.style; + /* $FlowFixMe(>=0.70.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.70 was deployed. To see the error delete + * this comment and run Flow. */ props.trackTintColor = this.props.value ? this.props.onTintColor : this.props.tintColor; } else if (Platform.OS === 'ios') { props.style = [styles.rctSwitchIOS, this.props.style]; diff --git a/Libraries/Lists/VirtualizedList.js b/Libraries/Lists/VirtualizedList.js index e03750e106ab55..2b1b83ff41bb0b 100644 --- a/Libraries/Lists/VirtualizedList.js +++ b/Libraries/Lists/VirtualizedList.js @@ -906,6 +906,9 @@ class VirtualizedList extends React.PureComponent { stickyHeaderIndices, }; if (inversionStyle) { + /* $FlowFixMe(>=0.70.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.70 was deployed. To see the error delete + * this comment and run Flow. */ scrollProps.style = [inversionStyle, this.props.style]; } diff --git a/RNTester/js/PointerEventsExample.js b/RNTester/js/PointerEventsExample.js index ac838c4eb8e370..ac15811c96ddf7 100644 --- a/RNTester/js/PointerEventsExample.js +++ b/RNTester/js/PointerEventsExample.js @@ -251,4 +251,7 @@ exports.framework = 'React'; exports.title = 'Pointer Events'; exports.description = 'Demonstrates the use of the pointerEvents prop of a ' + 'View to control how touches should be handled.'; +/* $FlowFixMe(>=0.70.0 site=react_native_fb) This comment suppresses an error + * found when Flow v0.70 was deployed. To see the error delete this comment + * and run Flow. */ exports.examples = exampleClasses.map(infoToExample); diff --git a/RNTester/js/ScrollViewExample.js b/RNTester/js/ScrollViewExample.js index f5b5c8aab8fd5c..66bedc93552c7c 100644 --- a/RNTester/js/ScrollViewExample.js +++ b/RNTester/js/ScrollViewExample.js @@ -118,8 +118,14 @@ exports.examples = [ return ( - {renderScrollView('LTR layout', {direction: 'ltr'})} - {renderScrollView('RTL layout', {direction: 'rtl'})} + {/* $FlowFixMe(>=0.70.0 site=react_native_fb) This comment + * suppresses an error found when Flow v0.70 was deployed. To see + * the error delete this comment and run Flow. */ + renderScrollView('LTR layout', {direction: 'ltr'})} + {/* $FlowFixMe(>=0.70.0 site=react_native_fb) This comment + * suppresses an error found when Flow v0.70 was deployed. To see + * the error delete this comment and run Flow. */ + renderScrollView('RTL layout', {direction: 'rtl'})} ); }, diff --git a/local-cli/templates/HelloWorld/_flowconfig b/local-cli/templates/HelloWorld/_flowconfig index 159649f1348ef7..4f75b3cb1405f3 100644 --- a/local-cli/templates/HelloWorld/_flowconfig +++ b/local-cli/templates/HelloWorld/_flowconfig @@ -51,4 +51,4 @@ suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError [version] -^0.69.0 +^0.70.0 diff --git a/local-cli/util/Config.js b/local-cli/util/Config.js index 9fc4487fe83ee8..5cd7b0f5fc2237 100644 --- a/local-cli/util/Config.js +++ b/local-cli/util/Config.js @@ -42,6 +42,9 @@ function getProjectPath() { const resolveSymlinksForRoots = roots => roots.reduce( + /* $FlowFixMe(>=0.70.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.70 was deployed. To see the error delete this + * comment and run Flow. */ (arr, rootPath) => arr.concat(findSymlinkedModules(rootPath, roots)), [...roots], ); diff --git a/package.json b/package.json index 01c8d57da21e11..3509869f9b457c 100644 --- a/package.json +++ b/package.json @@ -206,7 +206,7 @@ "eslint-plugin-jest": "21.8.0", "eslint-plugin-prettier": "2.6.0", "eslint-plugin-react": "7.6.1", - "flow-bin": "^0.69.0", + "flow-bin": "^0.70.0", "jest": "23.0.0-alpha.4", "jest-junit": "3.6.0", "prettier": "1.9.1", From b5f90ed497069481c4cbb3a52eaeb87567abd272 Mon Sep 17 00:00:00 2001 From: Dmitry Zakharov Date: Tue, 17 Apr 2018 07:53:19 -0700 Subject: [PATCH 0316/1109] Update ModuleRegistry if there're new modules registered Reviewed By: fkgozali Differential Revision: D7638394 fbshipit-source-id: c1690da7977f0335bc661df5f19dc9f473150d41 --- React/CxxBridge/RCTCxxBridge.mm | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/React/CxxBridge/RCTCxxBridge.mm b/React/CxxBridge/RCTCxxBridge.mm index cd82c3ccd85aaa..2517e29491925f 100644 --- a/React/CxxBridge/RCTCxxBridge.mm +++ b/React/CxxBridge/RCTCxxBridge.mm @@ -305,7 +305,7 @@ - (void)start [self registerExtraModules]; // Initialize all native modules that cannot be loaded lazily - [self _initModules:RCTGetModuleClasses() withDispatchGroup:prepareBridge lazilyDiscovered:NO]; + (void)[self _initializeModules:RCTGetModuleClasses() withDispatchGroup:prepareBridge lazilyDiscovered:NO]; [_performanceLogger markStopForTag:RCTPLNativeModuleInit]; @@ -635,9 +635,9 @@ - (void)installExtraJSBinding } } -- (void)_initModules:(NSArray> *)modules - withDispatchGroup:(dispatch_group_t)dispatchGroup - lazilyDiscovered:(BOOL)lazilyDiscovered +- (NSArray *)_initializeModules:(NSArray> *)modules + withDispatchGroup:(dispatch_group_t)dispatchGroup + lazilyDiscovered:(BOOL)lazilyDiscovered { RCTAssert(!(RCTIsMainQueue() && lazilyDiscovered), @"Lazy discovery can only happen off the Main Queue"); @@ -688,11 +688,15 @@ - (void)_initModules:(NSArray> *)modules RCTProfileHookModules(self); } #endif + return moduleDataById; } - (void)registerAdditionalModuleClasses:(NSArray *)modules { - [self _initModules:modules withDispatchGroup:NULL lazilyDiscovered:YES]; + NSArray *newModules = [self _initializeModules:modules withDispatchGroup:NULL lazilyDiscovered:YES]; + if (_reactInstance) { + _reactInstance->getModuleRegistry().registerModules(createNativeModules(newModules, self, _reactInstance)); + } } - (void)_prepareModulesWithDispatchGroup:(dispatch_group_t)dispatchGroup From 1433d15557f11ab9ad42cdee9088e07d40f18be3 Mon Sep 17 00:00:00 2001 From: Taras Tsugrii Date: Tue, 17 Apr 2018 09:32:30 -0700 Subject: [PATCH 0317/1109] Avoid top-level read_config invocations. Reviewed By: danzimm Differential Revision: D7651745 fbshipit-source-id: 5cbc82b3c9da3ab514278d438f97f98e19946dc7 --- ReactCommon/cxxreact/BUCK | 6 +++--- ReactCommon/exceptions/BUCK | 4 ++-- ReactCommon/fabric/core/BUCK | 6 +++--- ReactCommon/fabric/debug/BUCK | 4 ++-- ReactCommon/fabric/graphics/BUCK | 4 ++-- ReactCommon/fabric/uimanager/BUCK | 4 ++-- ReactCommon/fabric/view/BUCK | 4 ++-- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/ReactCommon/cxxreact/BUCK b/ReactCommon/cxxreact/BUCK index 43a5ce58276e07..8bf767e828974a 100644 --- a/ReactCommon/cxxreact/BUCK +++ b/ReactCommon/cxxreact/BUCK @@ -1,5 +1,5 @@ load("@xplat//configurations/buck/apple:flag_defs.bzl", "get_debug_preprocessor_flags") -load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "rn_xplat_cxx_library", "ANDROID_INSPECTOR_FLAGS", "APPLE_INSPECTOR_FLAGS", "ANDROID_JSC_DEPS", "APPLE_JSC_DEPS", "react_native_xplat_target") +load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "rn_xplat_cxx_library", "get_android_inspector_flags", "get_apple_inspector_flags", "ANDROID_JSC_DEPS", "APPLE_JSC_DEPS", "react_native_xplat_target") CXX_LIBRARY_COMPILER_FLAGS = [ "-std=c++14", @@ -129,7 +129,7 @@ rn_xplat_cxx_library( "-frtti", ], fbandroid_deps = ANDROID_JSC_DEPS, - fbandroid_preprocessor_flags = ANDROID_INSPECTOR_FLAGS + [ + fbandroid_preprocessor_flags = get_android_inspector_flags() + [ "-DWITH_JSC_EXTRA_TRACING=1", "-DWITH_JSC_MEMORY_PRESSURE=1", "-DWITH_FB_MEMORY_PROFILING=1", @@ -139,7 +139,7 @@ rn_xplat_cxx_library( fbobjc_frameworks = [ "$SDKROOT/System/Library/Frameworks/JavaScriptCore.framework", ], - fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + APPLE_INSPECTOR_FLAGS, + fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), force_static = True, macosx_tests_override = [], platforms = (ANDROID, APPLE), diff --git a/ReactCommon/exceptions/BUCK b/ReactCommon/exceptions/BUCK index 352bc036fdff4e..6f1ef1bb933b45 100644 --- a/ReactCommon/exceptions/BUCK +++ b/ReactCommon/exceptions/BUCK @@ -1,5 +1,5 @@ load("//configurations/buck/apple:flag_defs.bzl", "get_debug_preprocessor_flags") -load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "APPLE_INSPECTOR_FLAGS") +load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "get_apple_inspector_flags") APPLE_COMPILER_FLAGS = [] @@ -24,7 +24,7 @@ rn_xplat_cxx_library( "-Wall", ], fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, - fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + APPLE_INSPECTOR_FLAGS, + fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), force_static = True, preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", diff --git a/ReactCommon/fabric/core/BUCK b/ReactCommon/fabric/core/BUCK index 913078944214fc..23a9f30cfc0cb4 100644 --- a/ReactCommon/fabric/core/BUCK +++ b/ReactCommon/fabric/core/BUCK @@ -1,5 +1,5 @@ load("//configurations/buck/apple:flag_defs.bzl", "get_debug_preprocessor_flags") -load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "APPLE_INSPECTOR_FLAGS") +load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "get_apple_inspector_flags") APPLE_COMPILER_FLAGS = [] @@ -34,16 +34,16 @@ rn_xplat_cxx_library( "-Wall", ], fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, - fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + APPLE_INSPECTOR_FLAGS, + fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), fbobjc_tests = [ ":tests", ], force_static = True, + macosx_tests_override = [], preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", ], - macosx_tests_override = [], tests = [], visibility = ["PUBLIC"], deps = [ diff --git a/ReactCommon/fabric/debug/BUCK b/ReactCommon/fabric/debug/BUCK index abc85f94c325ee..88f7bc47828c43 100644 --- a/ReactCommon/fabric/debug/BUCK +++ b/ReactCommon/fabric/debug/BUCK @@ -1,5 +1,5 @@ load("@xplat//configurations/buck/apple:flag_defs.bzl", "get_debug_preprocessor_flags") -load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "APPLE_INSPECTOR_FLAGS") +load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "get_apple_inspector_flags") APPLE_COMPILER_FLAGS = [] @@ -31,7 +31,7 @@ rn_xplat_cxx_library( "-Wall", ], fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, - fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + APPLE_INSPECTOR_FLAGS, + fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), fbobjc_tests = [ ":tests", ], diff --git a/ReactCommon/fabric/graphics/BUCK b/ReactCommon/fabric/graphics/BUCK index 82a91faa4f455e..7cdb8c59b90f2b 100644 --- a/ReactCommon/fabric/graphics/BUCK +++ b/ReactCommon/fabric/graphics/BUCK @@ -1,5 +1,5 @@ load("//configurations/buck/apple:flag_defs.bzl", "get_debug_preprocessor_flags") -load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "APPLE_INSPECTOR_FLAGS") +load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "get_apple_inspector_flags") APPLE_COMPILER_FLAGS = [] @@ -31,7 +31,7 @@ rn_xplat_cxx_library( "-frtti", ], fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, - fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + APPLE_INSPECTOR_FLAGS, + fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), fbobjc_tests = [ ":tests", ], diff --git a/ReactCommon/fabric/uimanager/BUCK b/ReactCommon/fabric/uimanager/BUCK index 218b8ea92ebfa2..209502316d2b7b 100644 --- a/ReactCommon/fabric/uimanager/BUCK +++ b/ReactCommon/fabric/uimanager/BUCK @@ -1,5 +1,5 @@ load("//configurations/buck/apple:flag_defs.bzl", "get_debug_preprocessor_flags") -load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "APPLE_INSPECTOR_FLAGS") +load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "get_apple_inspector_flags") APPLE_COMPILER_FLAGS = [] @@ -31,7 +31,7 @@ rn_xplat_cxx_library( "-Wall", ], fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, - fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + APPLE_INSPECTOR_FLAGS, + fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), fbobjc_tests = [ ":tests", ], diff --git a/ReactCommon/fabric/view/BUCK b/ReactCommon/fabric/view/BUCK index 8bdb1b175a3914..d6ef5a048cfb30 100644 --- a/ReactCommon/fabric/view/BUCK +++ b/ReactCommon/fabric/view/BUCK @@ -1,5 +1,5 @@ load("//configurations/buck/apple:flag_defs.bzl", "get_application_ios_flags", "get_debug_preprocessor_flags", "OBJC_ARC_PREPROCESSOR_FLAGS") -load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "rn_xplat_cxx_library", "APPLE_INSPECTOR_FLAGS") +load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "rn_xplat_cxx_library", "get_apple_inspector_flags") load("//ReactNative:DEFS.bzl", "react_native_xplat_target") APPLE_COMPILER_FLAGS = [] @@ -34,7 +34,7 @@ rn_xplat_cxx_library( "-Wall", ], fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, - fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + APPLE_INSPECTOR_FLAGS, + fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), fbobjc_tests = [ ":tests", ], From e4f88c66e300505d3c86329dacd84d84e8109837 Mon Sep 17 00:00:00 2001 From: "Andrew Chen (Eng)" Date: Tue, 17 Apr 2018 10:13:52 -0700 Subject: [PATCH 0318/1109] Revert D7569885: Fix anti aliasing rounded background Differential Revision: D7569885 Original commit changeset: 4bfb00485211 fbshipit-source-id: 2fc76ca8615d5562ebe8c7527e9a54058b8d82dc --- .../view/ReactViewBackgroundDrawable.java | 197 ++++++++---------- 1 file changed, 89 insertions(+), 108 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java index e9fa14494a3830..9e374b4c502ecb 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java @@ -343,132 +343,113 @@ private void drawRoundedBackgroundWithBorders(Canvas canvas) { || borderWidth.bottom > 0 || borderWidth.left > 0 || borderWidth.right > 0) { + mPaint.setStyle(Paint.Style.FILL); - //If it's a full and even border draw inner rect path with stroke - final float fullBorderWidth = getFullBorderWidth(); - if (borderWidth.top == fullBorderWidth && - borderWidth.bottom == fullBorderWidth && - borderWidth.left == fullBorderWidth && - borderWidth.right == fullBorderWidth) { - if (fullBorderWidth > 0) { - int borderColor = getBorderColor(Spacing.ALL); - mPaint.setColor(ColorUtil.multiplyColorAlpha(borderColor, mAlpha)); - mPaint.setStyle(Paint.Style.STROKE); - mPaint.setStrokeWidth(fullBorderWidth); - canvas.drawPath(mInnerClipPathForBorderRadius, mPaint); - } - } - //In the case of uneven border widths/colors draw quadrilateral in each direction - else { - mPaint.setStyle(Paint.Style.FILL); - - // Draw border - canvas.clipPath(mOuterClipPathForBorderRadius, Region.Op.INTERSECT); - canvas.clipPath(mInnerClipPathForBorderRadius, Region.Op.DIFFERENCE); - - int colorLeft = getBorderColor(Spacing.LEFT); - int colorTop = getBorderColor(Spacing.TOP); - int colorRight = getBorderColor(Spacing.RIGHT); - int colorBottom = getBorderColor(Spacing.BOTTOM); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - final boolean isRTL = getResolvedLayoutDirection() == View.LAYOUT_DIRECTION_RTL; - int colorStart = getBorderColor(Spacing.START); - int colorEnd = getBorderColor(Spacing.END); + // Draw border + canvas.clipPath(mOuterClipPathForBorderRadius, Region.Op.INTERSECT); + canvas.clipPath(mInnerClipPathForBorderRadius, Region.Op.DIFFERENCE); - if (I18nUtil.getInstance().doLeftAndRightSwapInRTL(mContext)) { - if (!isBorderColorDefined(Spacing.START)) { - colorStart = colorLeft; - } + int colorLeft = getBorderColor(Spacing.LEFT); + int colorTop = getBorderColor(Spacing.TOP); + int colorRight = getBorderColor(Spacing.RIGHT); + int colorBottom = getBorderColor(Spacing.BOTTOM); - if (!isBorderColorDefined(Spacing.END)) { - colorEnd = colorRight; - } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + final boolean isRTL = getResolvedLayoutDirection() == View.LAYOUT_DIRECTION_RTL; + int colorStart = getBorderColor(Spacing.START); + int colorEnd = getBorderColor(Spacing.END); - final int directionAwareColorLeft = isRTL ? colorEnd : colorStart; - final int directionAwareColorRight = isRTL ? colorStart : colorEnd; + if (I18nUtil.getInstance().doLeftAndRightSwapInRTL(mContext)) { + if (!isBorderColorDefined(Spacing.START)) { + colorStart = colorLeft; + } - colorLeft = directionAwareColorLeft; - colorRight = directionAwareColorRight; - } else { - final int directionAwareColorLeft = isRTL ? colorEnd : colorStart; - final int directionAwareColorRight = isRTL ? colorStart : colorEnd; - - final boolean isColorStartDefined = isBorderColorDefined(Spacing.START); - final boolean isColorEndDefined = isBorderColorDefined(Spacing.END); - final boolean isDirectionAwareColorLeftDefined = - isRTL ? isColorEndDefined : isColorStartDefined; - final boolean isDirectionAwareColorRightDefined = - isRTL ? isColorStartDefined : isColorEndDefined; - - if (isDirectionAwareColorLeftDefined) { - colorLeft = directionAwareColorLeft; - } - - if (isDirectionAwareColorRightDefined) { - colorRight = directionAwareColorRight; - } + if (!isBorderColorDefined(Spacing.END)) { + colorEnd = colorRight; } - } - final float left = mOuterClipTempRectForBorderRadius.left; - final float right = mOuterClipTempRectForBorderRadius.right; - final float top = mOuterClipTempRectForBorderRadius.top; - final float bottom = mOuterClipTempRectForBorderRadius.bottom; + final int directionAwareColorLeft = isRTL ? colorEnd : colorStart; + final int directionAwareColorRight = isRTL ? colorStart : colorEnd; - if (borderWidth.left > 0) { - final float x1 = left; - final float y1 = top; - final float x2 = mInnerTopLeftCorner.x; - final float y2 = mInnerTopLeftCorner.y; - final float x3 = mInnerBottomLeftCorner.x; - final float y3 = mInnerBottomLeftCorner.y; - final float x4 = left; - final float y4 = bottom; + colorLeft = directionAwareColorLeft; + colorRight = directionAwareColorRight; + } else { + final int directionAwareColorLeft = isRTL ? colorEnd : colorStart; + final int directionAwareColorRight = isRTL ? colorStart : colorEnd; - drawQuadrilateral(canvas, colorLeft, x1, y1, x2, y2, x3, y3, x4, y4); - } + final boolean isColorStartDefined = isBorderColorDefined(Spacing.START); + final boolean isColorEndDefined = isBorderColorDefined(Spacing.END); + final boolean isDirectionAwareColorLeftDefined = isRTL ? isColorEndDefined : isColorStartDefined; + final boolean isDirectionAwareColorRightDefined = isRTL ? isColorStartDefined : isColorEndDefined; - if (borderWidth.top > 0) { - final float x1 = left; - final float y1 = top; - final float x2 = mInnerTopLeftCorner.x; - final float y2 = mInnerTopLeftCorner.y; - final float x3 = mInnerTopRightCorner.x; - final float y3 = mInnerTopRightCorner.y; - final float x4 = right; - final float y4 = top; + if (isDirectionAwareColorLeftDefined) { + colorLeft = directionAwareColorLeft; + } - drawQuadrilateral(canvas, colorTop, x1, y1, x2, y2, x3, y3, x4, y4); + if (isDirectionAwareColorRightDefined) { + colorRight = directionAwareColorRight; + } } + } - if (borderWidth.right > 0) { - final float x1 = right; - final float y1 = top; - final float x2 = mInnerTopRightCorner.x; - final float y2 = mInnerTopRightCorner.y; - final float x3 = mInnerBottomRightCorner.x; - final float y3 = mInnerBottomRightCorner.y; - final float x4 = right; - final float y4 = bottom; + final float left = mOuterClipTempRectForBorderRadius.left; + final float right = mOuterClipTempRectForBorderRadius.right; + final float top = mOuterClipTempRectForBorderRadius.top; + final float bottom = mOuterClipTempRectForBorderRadius.bottom; + + if (borderWidth.left > 0) { + final float x1 = left; + final float y1 = top; + final float x2 = mInnerTopLeftCorner.x; + final float y2 = mInnerTopLeftCorner.y; + final float x3 = mInnerBottomLeftCorner.x; + final float y3 = mInnerBottomLeftCorner.y; + final float x4 = left; + final float y4 = bottom; + + drawQuadrilateral(canvas, colorLeft, x1, y1, x2, y2, x3, y3, x4, y4); + } - drawQuadrilateral(canvas, colorRight, x1, y1, x2, y2, x3, y3, x4, y4); - } + if (borderWidth.top > 0) { + final float x1 = left; + final float y1 = top; + final float x2 = mInnerTopLeftCorner.x; + final float y2 = mInnerTopLeftCorner.y; + final float x3 = mInnerTopRightCorner.x; + final float y3 = mInnerTopRightCorner.y; + final float x4 = right; + final float y4 = top; + + drawQuadrilateral(canvas, colorTop, x1, y1, x2, y2, x3, y3, x4, y4); + } - if (borderWidth.bottom > 0) { - final float x1 = left; - final float y1 = bottom; - final float x2 = mInnerBottomLeftCorner.x; - final float y2 = mInnerBottomLeftCorner.y; - final float x3 = mInnerBottomRightCorner.x; - final float y3 = mInnerBottomRightCorner.y; - final float x4 = right; - final float y4 = bottom; + if (borderWidth.right > 0) { + final float x1 = right; + final float y1 = top; + final float x2 = mInnerTopRightCorner.x; + final float y2 = mInnerTopRightCorner.y; + final float x3 = mInnerBottomRightCorner.x; + final float y3 = mInnerBottomRightCorner.y; + final float x4 = right; + final float y4 = bottom; + + drawQuadrilateral(canvas, colorRight, x1, y1, x2, y2, x3, y3, x4, y4); + } - drawQuadrilateral(canvas, colorBottom, x1, y1, x2, y2, x3, y3, x4, y4); - } + if (borderWidth.bottom > 0) { + final float x1 = left; + final float y1 = bottom; + final float x2 = mInnerBottomLeftCorner.x; + final float y2 = mInnerBottomLeftCorner.y; + final float x3 = mInnerBottomRightCorner.x; + final float y3 = mInnerBottomRightCorner.y; + final float x4 = right; + final float y4 = bottom; + + drawQuadrilateral(canvas, colorBottom, x1, y1, x2, y2, x3, y3, x4, y4); } } + canvas.restore(); } From c9094e952bb806cd4f0cdb8179f92e595738010d Mon Sep 17 00:00:00 2001 From: Jean Lauliac Date: Tue, 17 Apr 2018 11:54:47 -0700 Subject: [PATCH 0319/1109] cxxreact/RAMBundleRegistry: prepend segment ID Reviewed By: fromcelticpark Differential Revision: D7594348 fbshipit-source-id: 0b433de8722f8a952fd056139a350dc481f0af38 --- ReactCommon/cxxreact/RAMBundleRegistry.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ReactCommon/cxxreact/RAMBundleRegistry.cpp b/ReactCommon/cxxreact/RAMBundleRegistry.cpp index 635875b3b79cbe..127e06e01e8500 100644 --- a/ReactCommon/cxxreact/RAMBundleRegistry.cpp +++ b/ReactCommon/cxxreact/RAMBundleRegistry.cpp @@ -3,6 +3,7 @@ #include "RAMBundleRegistry.h" #include +#include #include @@ -42,7 +43,14 @@ JSModulesUnbundle::Module RAMBundleRegistry::getModule(uint32_t bundleId, uint32 m_bundles.emplace(bundleId, m_factory(bundlePath->second)); } - return getBundle(bundleId)->getModule(moduleId); + auto module = getBundle(bundleId)->getModule(moduleId); + if (bundleId == MAIN_BUNDLE_ID) { + return module; + } + return { + folly::to("seg-", bundleId, '_', std::move(module.name)), + std::move(module.code), + }; } JSModulesUnbundle *RAMBundleRegistry::getBundle(uint32_t bundleId) const { From 281ed9f4ce488e708de339e8543898ce30d4ce5a Mon Sep 17 00:00:00 2001 From: Jean Lauliac Date: Tue, 17 Apr 2018 11:54:49 -0700 Subject: [PATCH 0320/1109] cxxreact/RAMBundleRegistry: nit fixes Reviewed By: mhorowitz Differential Revision: D7587411 fbshipit-source-id: 516753247af585914381308248de9652f18a6cf5 --- ReactCommon/cxxreact/RAMBundleRegistry.cpp | 39 ++++++++++++++-------- ReactCommon/cxxreact/RAMBundleRegistry.h | 25 ++++++++------ 2 files changed, 41 insertions(+), 23 deletions(-) diff --git a/ReactCommon/cxxreact/RAMBundleRegistry.cpp b/ReactCommon/cxxreact/RAMBundleRegistry.cpp index 127e06e01e8500..cc61ea254540db 100644 --- a/ReactCommon/cxxreact/RAMBundleRegistry.cpp +++ b/ReactCommon/cxxreact/RAMBundleRegistry.cpp @@ -12,33 +12,46 @@ namespace react { constexpr uint32_t RAMBundleRegistry::MAIN_BUNDLE_ID; -std::unique_ptr RAMBundleRegistry::singleBundleRegistry(std::unique_ptr mainBundle) { - RAMBundleRegistry *registry = new RAMBundleRegistry(std::move(mainBundle)); - return std::unique_ptr(registry); +std::unique_ptr RAMBundleRegistry::singleBundleRegistry( + std::unique_ptr mainBundle) { + return folly::make_unique(std::move(mainBundle)); } -std::unique_ptr RAMBundleRegistry::multipleBundlesRegistry(std::unique_ptr mainBundle, std::function(std::string)> factory) { - RAMBundleRegistry *registry = new RAMBundleRegistry(std::move(mainBundle), std::move(factory)); - return std::unique_ptr(registry); +std::unique_ptr RAMBundleRegistry::multipleBundlesRegistry( + std::unique_ptr mainBundle, + std::function(std::string)> factory) { + return folly::make_unique( + std::move(mainBundle), std::move(factory)); } -RAMBundleRegistry::RAMBundleRegistry(std::unique_ptr mainBundle, std::function(std::string)> factory): m_factory(factory) { +RAMBundleRegistry::RAMBundleRegistry( + std::unique_ptr mainBundle, + std::function(std::string)> factory): + m_factory(std::move(factory)) { m_bundles.emplace(MAIN_BUNDLE_ID, std::move(mainBundle)); } -void RAMBundleRegistry::registerBundle(uint32_t bundleId, std::string bundlePath) { - m_bundlePaths.emplace(bundleId, bundlePath); +void RAMBundleRegistry::registerBundle( + uint32_t bundleId, std::string bundlePath) { + m_bundlePaths.emplace(bundleId, std::move(bundlePath)); } -JSModulesUnbundle::Module RAMBundleRegistry::getModule(uint32_t bundleId, uint32_t moduleId) { +JSModulesUnbundle::Module RAMBundleRegistry::getModule( + uint32_t bundleId, uint32_t moduleId) { if (m_bundles.find(bundleId) == m_bundles.end()) { if (!m_factory) { - throw std::runtime_error("You need to register factory function in order to support multiple RAM bundles."); + throw std::runtime_error( + "You need to register factory function in order to " + "support multiple RAM bundles." + ); } auto bundlePath = m_bundlePaths.find(bundleId); if (bundlePath == m_bundlePaths.end()) { - throw std::runtime_error("In order to fetch RAM bundle from the registry, its file path needs to be registered first."); + throw std::runtime_error( + "In order to fetch RAM bundle from the registry, its file " + "path needs to be registered first." + ); } m_bundles.emplace(bundleId, m_factory(bundlePath->second)); } @@ -53,7 +66,7 @@ JSModulesUnbundle::Module RAMBundleRegistry::getModule(uint32_t bundleId, uint32 }; } -JSModulesUnbundle *RAMBundleRegistry::getBundle(uint32_t bundleId) const { +JSModulesUnbundle* RAMBundleRegistry::getBundle(uint32_t bundleId) const { return m_bundles.at(bundleId).get(); } diff --git a/ReactCommon/cxxreact/RAMBundleRegistry.h b/ReactCommon/cxxreact/RAMBundleRegistry.h index 2d628f22c35d7c..9fb546066bed36 100644 --- a/ReactCommon/cxxreact/RAMBundleRegistry.h +++ b/ReactCommon/cxxreact/RAMBundleRegistry.h @@ -20,26 +20,31 @@ namespace react { class RN_EXPORT RAMBundleRegistry : noncopyable { public: - using unique_ram_bundle = std::unique_ptr; - using bundle_path = std::string; constexpr static uint32_t MAIN_BUNDLE_ID = 0; - static std::unique_ptr singleBundleRegistry(unique_ram_bundle mainBundle); - static std::unique_ptr multipleBundlesRegistry(unique_ram_bundle mainBundle, std::function factory); + static std::unique_ptr singleBundleRegistry( + std::unique_ptr mainBundle); + static std::unique_ptr multipleBundlesRegistry( + std::unique_ptr mainBundle, + std::function(std::string)> factory); + + explicit RAMBundleRegistry( + std::unique_ptr mainBundle, + std::function< + std::unique_ptr(std::string)> factory = nullptr); RAMBundleRegistry(RAMBundleRegistry&&) = default; RAMBundleRegistry& operator=(RAMBundleRegistry&&) = default; - void registerBundle(uint32_t bundleId, bundle_path bundlePath); + void registerBundle(uint32_t bundleId, std::string bundlePath); JSModulesUnbundle::Module getModule(uint32_t bundleId, uint32_t moduleId); virtual ~RAMBundleRegistry() {}; private: - explicit RAMBundleRegistry(unique_ram_bundle mainBundle, std::function factory = {}); - JSModulesUnbundle *getBundle(uint32_t bundleId) const; + JSModulesUnbundle* getBundle(uint32_t bundleId) const; - std::function m_factory; - std::unordered_map m_bundlePaths; - std::unordered_map m_bundles; + std::function(std::string)> m_factory; + std::unordered_map m_bundlePaths; + std::unordered_map> m_bundles; }; } // namespace react From 7c5d581d7848206603cf9d80a841afb49759ec1a Mon Sep 17 00:00:00 2001 From: shockdesign Date: Tue, 17 Apr 2018 13:21:09 -0700 Subject: [PATCH 0321/1109] Switch equality check in BlobModule.java Summary: Switch the equality check to avoid crash on the first item. The check can be on a null object and return the correct result. Fixes #18709 Just a simple switch on equals, to make sure we're not bombing out by having a null scheme. No related PRs and does not require a document change. [ANDROID][BUGFIX][BlobModule] Switch equality check in BlobModule.java Closes https://github.com/facebook/react-native/pull/18893 Differential Revision: D7658036 Pulled By: hramos fbshipit-source-id: db61b98dae178dbbb645070f7b0d73ab43d30541 --- .../main/java/com/facebook/react/modules/blob/BlobModule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 0c2adc91d43fb7..ee62d2cd278466 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 @@ -79,7 +79,7 @@ public void onMessage(ByteString bytes, WritableMap params) { @Override public boolean supports(Uri uri, String responseType) { String scheme = uri.getScheme(); - boolean isRemote = scheme.equals("http") || scheme.equals("https"); + boolean isRemote = "http".equals(scheme) || "https".equals(scheme); return (!isRemote && responseType.equals("blob")); } From 4469952c9a493dbb865aa7c29055502b44ff570e Mon Sep 17 00:00:00 2001 From: Himabindu Gadupudi Date: Tue, 17 Apr 2018 13:27:46 -0700 Subject: [PATCH 0322/1109] Pass drawable width and height in pixels for inline image Reviewed By: achen1 Differential Revision: D7655775 fbshipit-source-id: 32887eb5a686ccc45f50fb334248aad6889f704a --- .../frescosupport/FrescoBasedReactTextInlineImageSpan.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageSpan.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageSpan.java index d769d50fce99af..39cd24c6fd3cd9 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageSpan.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageSpan.java @@ -9,6 +9,7 @@ import android.graphics.Color; import android.graphics.PorterDuff; +import com.facebook.react.uimanager.PixelUtil; import javax.annotation.Nullable; import android.content.res.Resources; @@ -70,12 +71,12 @@ public FrescoBasedReactTextInlineImageSpan( ); mDraweeControllerBuilder = draweeControllerBuilder; mCallerContext = callerContext; - - mHeight = height; mTintColor = tintColor; - mWidth = width; mUri = (uri != null) ? uri : Uri.EMPTY; mHeaders = headers; + mWidth = (int)(PixelUtil.toPixelFromDIP(width)); + mHeight = (int)(PixelUtil.toPixelFromDIP(height)); + } /** From c10c6dbf7c808b4f69007f297afea7d6f3522612 Mon Sep 17 00:00:00 2001 From: "Andrew Chen (Eng)" Date: Tue, 17 Apr 2018 13:54:42 -0700 Subject: [PATCH 0323/1109] Move Fabric tests to OSS Reviewed By: mdvacca Differential Revision: D7654802 fbshipit-source-id: a30c8cf062636243066a1fc73da0711442a29c76 --- .../test/java/com/facebook/react/fabric/BUCK | 41 ++ .../react/fabric/FabricReconcilerTest.java | 224 ++++++++++ .../react/fabric/FabricUIManagerTest.java | 387 ++++++++++++++++++ 3 files changed, 652 insertions(+) create mode 100644 ReactAndroid/src/test/java/com/facebook/react/fabric/BUCK create mode 100644 ReactAndroid/src/test/java/com/facebook/react/fabric/FabricReconcilerTest.java create mode 100644 ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java diff --git a/ReactAndroid/src/test/java/com/facebook/react/fabric/BUCK b/ReactAndroid/src/test/java/com/facebook/react/fabric/BUCK new file mode 100644 index 00000000000000..21917d67f81feb --- /dev/null +++ b/ReactAndroid/src/test/java/com/facebook/react/fabric/BUCK @@ -0,0 +1,41 @@ +load("//ReactNative:DEFS.bzl", "rn_robolectric_test", "YOGA_TARGET", "react_native_dep", "react_native_target", "react_native_tests_target") + +rn_robolectric_test( + name = "fabric", + srcs = glob(["**/*.java"]), + contacts = ["oncall+fbandroid_sheriff@xmail.facebook.com"], + resources = glob([ + "**/*.txt", + "**/*.json", + ]), + visibility = [ + "PUBLIC", + ], + deps = [ + "xplat//yoga/java:java", + react_native_dep("java/com/facebook/common/executors:executors"), + react_native_dep("java/com/facebook/testing/robolectric/v3:v3"), + react_native_dep("third-party/java/assertj:assertj-core"), + react_native_dep("third-party/java/fest:fest"), + react_native_dep("third-party/java/fest:fest_android"), + react_native_dep("third-party/java/guava:guava"), + react_native_dep("third-party/java/jackson:jackson"), + react_native_dep("third-party/java/jsr-305:jsr-305"), + react_native_dep("third-party/java/jsr-330:jsr-330"), + react_native_dep("third-party/java/junit:junit"), + react_native_dep("third-party/java/mockito:mockito"), + react_native_dep("third-party/java/robolectric3/robolectric:robolectric"), + react_native_dep("libraries/fbcore/src/test/java/com/facebook/powermock:powermock"), + react_native_dep("libraries/soloader/java/com/facebook/soloader:soloader"), + react_native_dep("third-party/android/support/v4:lib-support-v4"), + 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/fabric:fabric"), + react_native_target("java/com/facebook/react/modules/core:core"), + react_native_target("java/com/facebook/react/uimanager:uimanager"), + react_native_target("java/com/facebook/react/views/text:text"), + react_native_target("java/com/facebook/react/views/view:view"), + react_native_tests_target("java/com/facebook/react/bridge:testhelpers"), + ], +) diff --git a/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricReconcilerTest.java b/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricReconcilerTest.java new file mode 100644 index 00000000000000..23272c23427c31 --- /dev/null +++ b/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricReconcilerTest.java @@ -0,0 +1,224 @@ +// Copyright 2004-present Facebook. All Rights Reserved. +package com.facebook.react.fabric; + +import static org.fest.assertions.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.powermock.api.mockito.PowerMockito.mockStatic; + +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.common.ClearableSynchronizedPool; +import com.facebook.react.fabric.FabricReconciler; +import com.facebook.react.modules.core.ReactChoreographer; +import com.facebook.react.uimanager.NativeViewHierarchyManager; +import com.facebook.react.uimanager.ReactShadowNode; +import com.facebook.react.uimanager.ReactShadowNodeImpl; +import com.facebook.react.uimanager.ReactYogaConfigProvider; +import com.facebook.react.uimanager.UIViewOperationQueue; +import com.facebook.react.uimanager.ViewAtIndex; +import com.facebook.react.uimanager.YogaNodePool; +import com.facebook.testing.robolectric.v3.WithTestDefaultsRunner; +import com.facebook.yoga.YogaConfig; +import com.facebook.yoga.YogaNode; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.robolectric.RuntimeEnvironment; + +/** Tests {@link FabricReconciler} */ +@PrepareForTest({ + ReactChoreographer.class, + ReactYogaConfigProvider.class, + YogaNodePool.class, +}) +@RunWith(WithTestDefaultsRunner.class) +@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"}) +public class FabricReconcilerTest { + + private FabricReconciler mFabricReconciler; + private MockUIViewOperationQueue mMockUIViewOperationQueue; + + @Before + public void setUp() { + ReactApplicationContext reactContext = + new ReactApplicationContext(RuntimeEnvironment.application); + mMockUIViewOperationQueue = new MockUIViewOperationQueue(reactContext); + mFabricReconciler = new FabricReconciler(mMockUIViewOperationQueue); + + setupHacks(); + } + + @Test + public void testSimpleHierarchy() { + ReactShadowNode parent = createNode(0); + ReactShadowNode child1 = createNode(1); + ReactShadowNode child2 = createNode(2); + addChildren(parent, child1, child2); + + ReactShadowNode parentCloned = createNode(0); + ReactShadowNode child3 = createNode(3); + addChildren(parentCloned, child3, child2); + + mFabricReconciler.manageChildren(parent, parentCloned); + + List expectedOperations = new ArrayList<>(); + expectedOperations.add( + new ManageChildrenOperation( + 0, + new int[] {0, 1}, + new ViewAtIndex[] {new ViewAtIndex(3, 0), new ViewAtIndex(2, 1)}, + new int[] {1})); + assertThat(mMockUIViewOperationQueue.getOperations()).isEqualTo(expectedOperations); + } + + @Test + public void testVirtualNodes() { + ReactShadowNode parent = createNode(0); + ReactShadowNode child1 = createVirtualNode(1); + ReactShadowNode child2 = createVirtualNode(2); + ReactShadowNode child3 = createVirtualNode(3); + addChildren(parent, child1, child2, child3); + + ReactShadowNode parentCloned = createNode(0); + ReactShadowNode child4 = createVirtualNode(4); + addChildren(parentCloned, child1, child4, child3); + + mFabricReconciler.manageChildren(parent, parentCloned); + + List expectedOperations = new ArrayList<>(); + assertThat(mMockUIViewOperationQueue.getOperations()).isEqualTo(expectedOperations); + } + + private static ReactShadowNode createNode(int tag) { + return createNode(tag, false); + } + + private static ReactShadowNode createVirtualNode(int tag) { + return createNode(tag, true); + } + + private static ReactShadowNode createNode(int tag, boolean virtual) { + ReactShadowNode node; + if (virtual) { + node = new VirtualReactShadowNode(); + } else { + node = new ReactShadowNodeImpl(); + } + node.setReactTag(tag); + return node; + } + + private static class VirtualReactShadowNode extends ReactShadowNodeImpl { + + @Override + public boolean isVirtual() { + return true; + } + } + + private static void addChildren(ReactShadowNode parent, ReactShadowNode... children) { + for (ReactShadowNode child : children) { + parent.addChildAt(child, parent.getChildCount()); + } + } + + private static class ManageChildrenOperation { + private int mTag; + private int[] mIndicesToRemove; + private ViewAtIndex[] mViewsToAdd; + private int[] mTagsToRemove; + + private ManageChildrenOperation( + int tag, int[] indicesToRemove, ViewAtIndex[] viewsToAdd, int[] tagsToRemove) { + mTag = tag; + mIndicesToRemove = indicesToRemove; + mViewsToAdd = viewsToAdd; + mTagsToRemove = tagsToRemove; + } + + @Override + public boolean equals(Object obj) { + if (obj == null || obj.getClass() != getClass()) { + return false; + } + ManageChildrenOperation op = (ManageChildrenOperation) obj; + return mTag == op.mTag + && Arrays.equals(mIndicesToRemove, op.mIndicesToRemove) + && Arrays.equals(mViewsToAdd, op.mViewsToAdd) + && Arrays.equals(mTagsToRemove, op.mTagsToRemove); + } + + @Override + public int hashCode() { + return Arrays.deepHashCode(new Object[] {mTag, mIndicesToRemove, mViewsToAdd, mTagsToRemove}); + } + + @Override + public String toString() { + return "ManageChildrenOperation \n\tindicesToRemove: " + + Arrays.toString(mIndicesToRemove) + + "\n\tviewsToAdd: " + + Arrays.toString(mViewsToAdd) + + "\n\ttagsToRemove: " + + Arrays.toString(mTagsToRemove); + } + } + + private static class MockUIViewOperationQueue extends UIViewOperationQueue { + + private List mOperations; + + private MockUIViewOperationQueue(ReactApplicationContext context) { + super(context, mock(NativeViewHierarchyManager.class), 0); + mOperations = new ArrayList<>(); + } + + @Override + public void enqueueManageChildren( + int reactTag, int[] indicesToRemove, ViewAtIndex[] viewsToAdd, int[] tagsToDelete) { + mOperations.add( + new ManageChildrenOperation(reactTag, indicesToRemove, viewsToAdd, tagsToDelete)); + } + + public List getOperations() { + return Collections.unmodifiableList(mOperations); + } + } + + /** Hacks to get tests to start working end to end */ + private void setupHacks() { + // Hack around Yoga by mocking it out until the UnsatisfiedLinkErrors are fixed t14964130 + mockStatic(YogaNodePool.class, ReactYogaConfigProvider.class); + PowerMockito.when(YogaNodePool.get()) + .thenAnswer( + new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Exception { + ClearableSynchronizedPool yogaPool = + mock(ClearableSynchronizedPool.class); + YogaNode yogaNode = mock(YogaNode.class); + when(yogaNode.clone()).thenReturn(mock(YogaNode.class)); + when(yogaNode.isMeasureDefined()).thenReturn(true); + when(yogaPool.acquire()).thenReturn(yogaNode); + return yogaPool; + } + }); + PowerMockito.when(ReactYogaConfigProvider.get()) + .thenAnswer( + new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + return mock(YogaConfig.class); + } + }); + } +} diff --git a/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java b/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java new file mode 100644 index 00000000000000..d1aebcd7e263f3 --- /dev/null +++ b/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java @@ -0,0 +1,387 @@ +// Copyright 2004-present Facebook. All Rights Reserved. +package com.facebook.react.fabric; + +import static org.fest.assertions.api.Assertions.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.facebook.react.ReactRootView; +import com.facebook.react.bridge.CatalystInstance; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactTestHelper; +import com.facebook.react.bridge.ReadableNativeMap; +import com.facebook.react.common.ClearableSynchronizedPool; +import com.facebook.react.fabric.FabricUIManager; +import com.facebook.react.uimanager.ReactShadowNode; +import com.facebook.react.uimanager.ReactShadowNodeImpl; +import com.facebook.react.uimanager.ReactYogaConfigProvider; +import com.facebook.react.uimanager.Spacing; +import com.facebook.react.uimanager.ThemedReactContext; +import com.facebook.react.uimanager.ViewManager; +import com.facebook.react.uimanager.ViewManagerRegistry; +import com.facebook.react.uimanager.YogaNodePool; +import com.facebook.react.views.text.ReactRawTextManager; +import com.facebook.react.views.text.ReactRawTextShadowNode; +import com.facebook.react.views.text.ReactTextViewManager; +import com.facebook.react.views.view.ReactViewManager; +import com.facebook.testing.robolectric.v3.WithTestDefaultsRunner; +import com.facebook.yoga.YogaConfig; +import com.facebook.yoga.YogaMeasureFunction; +import com.facebook.yoga.YogaNode; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.robolectric.RuntimeEnvironment; + +/** Tests {@link FabricUIManager} */ +@PrepareForTest({YogaNodePool.class, ReactYogaConfigProvider.class}) +@RunWith(WithTestDefaultsRunner.class) +public class FabricUIManagerTest { + + private FabricUIManager mFabricUIManager; + private ThemedReactContext mThemedReactContext; + private int mNextReactTag; + private MockYogaNodePool mMockYogaNodePool; + + private YogaMeasureFunction mLastYogaMeasureFunction; + + @Before + public void setUp() throws Exception { + mNextReactTag = 2; + mThemedReactContext = mock(ThemedReactContext.class); + CatalystInstance catalystInstance = ReactTestHelper.createMockCatalystInstance(); + ReactApplicationContext reactContext = + new ReactApplicationContext(RuntimeEnvironment.application); + reactContext.initializeWithInstance(catalystInstance); + List viewManagers = + Arrays.asList( + new ReactViewManager(), new ReactTextViewManager(), new ReactRawTextManager()); + ViewManagerRegistry viewManagerRegistry = new ViewManagerRegistry(viewManagers); + + mFabricUIManager = new FabricUIManager(reactContext, viewManagerRegistry); + + // Hack around Yoga until the UnsatisfiedLinkErrors are fixed t14964130 + PowerMockito.mockStatic(YogaNodePool.class, ReactYogaConfigProvider.class); + mMockYogaNodePool = new MockYogaNodePool(); + PowerMockito.when(YogaNodePool.get()).thenReturn(mMockYogaNodePool); + PowerMockito.when(ReactYogaConfigProvider.get()) + .thenAnswer( + new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + return mock(YogaConfig.class); + } + }); + } + + @Test + public void testCreateNode() { + ReactRootView rootView = + new ReactRootView(RuntimeEnvironment.application.getApplicationContext()); + int rootTag = mFabricUIManager.addRootView(rootView); + int reactTag = mNextReactTag++; + String viewClass = ReactViewManager.REACT_CLASS; + ReactShadowNode node = mFabricUIManager.createNode(reactTag, viewClass, rootTag, null); + + assertThat(reactTag).isEqualTo(node.getReactTag()); + assertThat(viewClass).isEqualTo(node.getViewClass()); + assertThat(rootTag).isEqualTo(rootTag); + } + + @Test + public void testCreateMultpleRootViews() { + createAndRenderRootView(); + createAndRenderRootView(); + } + + private int createAndRenderRootView() { + ReactRootView rootView = + new ReactRootView(RuntimeEnvironment.application.getApplicationContext()); + int rootTag = mFabricUIManager.addRootView(rootView); + int reactTag = mNextReactTag++; + String viewClass = ReactViewManager.REACT_CLASS; + ReactShadowNode node = mFabricUIManager.createNode(reactTag, viewClass, rootTag, null); + + List childSet = mFabricUIManager.createChildSet(rootTag); + mFabricUIManager.appendChildToSet(childSet, node); + mFabricUIManager.completeRoot(rootTag, childSet); + + return rootTag; + } + + @Test + public void testCloneNode() { + ReactShadowNode node = createViewNode(); + ReactShadowNode child = createViewNode(); + node.addChildAt(child, 0); + + ReactShadowNode clonedNode = mFabricUIManager.cloneNode(node); + + assertThat(clonedNode).isNotSameAs(node); + assertThat(clonedNode.getOriginalReactShadowNode()).isSameAs(node); + assertSameFields(clonedNode, node); + assertSameChildren(clonedNode, node); + assertThat(clonedNode.getChildAt(0)).isEqualTo(child); + } + + @Test + public void testCloneVirtualNode() { + ReactRawTextShadowNode node = new ReactRawTextShadowNode(); + node.setText("test"); + assertThat(node.isVirtual()).isTrue(); + + ReactRawTextShadowNode clonedNode = (ReactRawTextShadowNode) node.mutableCopy(); + + assertThat(clonedNode.getText()).isEqualTo("test"); + assertThat(clonedNode).isNotEqualTo(node); + } + + @Test + public void testCloneNodeWithNewChildren() { + ReactShadowNode node = createViewNode(); + ReactShadowNode child = createViewNode(); + node.addChildAt(child, 0); + + ReactShadowNode clonedNode = mFabricUIManager.cloneNodeWithNewChildren(node); + + assertThat(clonedNode.getChildCount()).isZero(); + assertSameFields(clonedNode, node); + } + + @Test + public void testCloneNodeWithNewProps() { + ReactShadowNode node = createViewNode(); + ReadableNativeMap props = null; // TODO(ayc): Figure out how to create a Native map from tests. + + ReactShadowNode clonedNode = mFabricUIManager.cloneNodeWithNewProps(node, props); + } + + @Test + public void testCloneNodeWithNewChildrenAndProps() { + ReactShadowNode node = createViewNode(); + ReadableNativeMap props = null; + + ReactShadowNode clonedNode = mFabricUIManager.cloneNodeWithNewChildrenAndProps(node, props); + + assertThat(clonedNode.getChildCount()).isZero(); + } + + @Test + public void testAppendChild() { + ReactShadowNode node = createViewNode(); + ReactShadowNode child = createViewNode(); + + mFabricUIManager.appendChild(node, child); + + assertThat(node.getChildCount()).isEqualTo(1); + assertThat(node.getChildAt(0)).isEqualTo(child); + } + + @Test + public void testCreateChildSet() { + List childSet = mFabricUIManager.createChildSet(0); + + assertThat(childSet).isEmpty(); + } + + @Test + public void testAppendChildToSet() { + ReactShadowNode node = createViewNode(); + List childSet = mFabricUIManager.createChildSet(0); + + mFabricUIManager.appendChildToSet(childSet, node); + + assertThat(childSet).hasSize(1); + assertThat(childSet).contains(node); + } + + @Test(expected = AssertionError.class) + public void testCompleteRootBeforeAddRoot() { + mFabricUIManager.completeRoot(0, new ArrayList()); + } + + @Test + public void testCompleteRoot() { + ReactRootView rootView = + new ReactRootView(RuntimeEnvironment.application.getApplicationContext()); + int rootTag = mFabricUIManager.addRootView(rootView); + List children = mFabricUIManager.createChildSet(rootTag); + + mFabricUIManager.completeRoot(rootTag, children); + } + + /** + * Tests that cloned text nodes will reassign their yoga nodes' measure functions. + * + *

TODO(T26729515): Currently this tests the wrong implementation. It assumes that yoga nodes + * are reused across clones and simply checks the most recently assigned measure functions of the + * shared yoga node. When yoga node cloning is implemented, this needs to be changed to mock each + * cloned shadow nodes' yoga nodes and make the same assertions on each of their measure + * functions. + */ + @Test + public void testTextMutableClone() { + ReactRootView rootView = + new ReactRootView(RuntimeEnvironment.application.getApplicationContext()); + int rootTag = mFabricUIManager.addRootView(rootView); + + final YogaNode yogaNode = mock(YogaNode.class); + + doAnswer( + new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + when(yogaNode.isMeasureDefined()).thenReturn(true); + when(yogaNode.clone()).thenReturn(yogaNode); + when(yogaNode.cloneWithNewChildren()).thenReturn(yogaNode); + mLastYogaMeasureFunction = (YogaMeasureFunction) invocation.getArguments()[0]; + return null; + } + }) + .when(yogaNode) + .setMeasureFunction(any(YogaMeasureFunction.class)); + + mMockYogaNodePool.add(yogaNode); + + ReactShadowNode text = + mFabricUIManager.createNode(0, ReactTextViewManager.REACT_CLASS, rootTag, null); + YogaMeasureFunction textMeasureFunction = mLastYogaMeasureFunction; + assertThat(text.isMeasureDefined()).isTrue(); + + ReactShadowNode textCopy = text.mutableCopy(); + YogaMeasureFunction textCopyMeasureFunction = mLastYogaMeasureFunction; + assertThat(textCopy.isMeasureDefined()).isTrue(); + assertThat(textCopyMeasureFunction).isNotSameAs(textMeasureFunction); + + ReactShadowNode textCopyWithNewChildren = text.mutableCopyWithNewChildren(); + YogaMeasureFunction textCopyWithNewChildrenMeasureFunction = mLastYogaMeasureFunction; + assertThat(textCopyWithNewChildren.isMeasureDefined()).isTrue(); + assertThat(textCopyWithNewChildrenMeasureFunction).isNotSameAs(textMeasureFunction); + assertThat(textCopyWithNewChildrenMeasureFunction).isNotSameAs(textCopyMeasureFunction); + } + + /** + * Verifies that the reconciliation phase will always set the originalNode field of every node in + * the tree to null once completeRoot has finished to prevent memory leaks. + */ + @Test + public void testRemoveOriginalNodeReferences() { + ReactRootView rootView = + new ReactRootView(RuntimeEnvironment.application.getApplicationContext()); + int rootTag = mFabricUIManager.addRootView(rootView); + String viewClass = ReactViewManager.REACT_CLASS; + + ReactShadowNode aa = mFabricUIManager.createNode(2, viewClass, rootTag, null); + ReactShadowNode a = mFabricUIManager.createNode(3, viewClass, rootTag, null); + mFabricUIManager.appendChild(a, aa); + ReactShadowNode bb = mFabricUIManager.createNode(4, viewClass, rootTag, null); + ReactShadowNode b = mFabricUIManager.createNode(5, viewClass, rootTag, null); + mFabricUIManager.appendChild(b, bb); + ReactShadowNode container = mFabricUIManager.createNode(6, viewClass, rootTag, null); + mFabricUIManager.appendChild(container, a); + mFabricUIManager.appendChild(container, b); + List childSet = mFabricUIManager.createChildSet(rootTag); + mFabricUIManager.appendChildToSet(childSet, container); + mFabricUIManager.completeRoot(rootTag, childSet); + + ReactShadowNode aaClone = mFabricUIManager.cloneNodeWithNewProps(aa, null); + ReactShadowNode aClone = mFabricUIManager.cloneNodeWithNewChildren(a); + mFabricUIManager.appendChild(aClone, aaClone); + ReactShadowNode containerClone = mFabricUIManager.cloneNodeWithNewChildren(container); + mFabricUIManager.appendChild(containerClone, b); + mFabricUIManager.appendChild(containerClone, aClone); + List childSet2 = mFabricUIManager.createChildSet(rootTag); + mFabricUIManager.appendChildToSet(childSet2, containerClone); + mFabricUIManager.completeRoot(rootTag, childSet2); + + ReactShadowNode[] nodes = + new ReactShadowNode[] {aa, a, bb, b, container, aaClone, aClone, containerClone}; + + for (ReactShadowNode node : nodes) { + assertThat(node.getOriginalReactShadowNode()).isNull(); + } + } + + private void assertSameChildren(ReactShadowNode node1, ReactShadowNode node2) { + assertThat(node1.getChildCount()).isEqualTo(node2.getChildCount()); + for (int i = 0; i < node1.getChildCount(); i++) { + assertThat(node1.getChildAt(i)).isEqualTo(node2.getChildAt(i)); + } + } + + private void assertSameFields(ReactShadowNode node1, ReactShadowNode node2) { + assertThat(node1.getReactTag()).isEqualTo(node2.getReactTag()); + assertThat(node1.getViewClass()).isEqualTo(node2.getViewClass()); + assertThat(node2.getParent()).isNull(); + assertThat(node1.getThemedContext()).isEqualTo(node2.getThemedContext()); + assertThat(node1.isVirtual()).isEqualTo(node2.isVirtual()); + assertThat(node1.getLayoutDirection()).isEqualTo(node2.getLayoutDirection()); + assertThat(node1.getLayoutHeight()).isEqualTo(node2.getLayoutHeight()); + assertThat(node1.getLayoutWidth()).isEqualTo(node2.getLayoutWidth()); + assertThat(node1.getLayoutX()).isEqualTo(node2.getLayoutX()); + assertThat(node1.getLayoutY()).isEqualTo(node2.getLayoutY()); + for (int spacingType = Spacing.LEFT; spacingType <= Spacing.ALL; spacingType++) { + assertThat(node1.getPadding(spacingType)).isEqualTo(node2.getPadding(spacingType)); + assertThat(node1.getStylePadding(spacingType)).isEqualTo(node2.getStylePadding(spacingType)); + } + assertThat(node1.getStyleWidth()).isEqualTo(node2.getStyleWidth()); + assertThat(node1.getStyleHeight()).isEqualTo(node2.getStyleHeight()); + } + + private ReactShadowNode createViewNode() { + ReactShadowNode node = new ReactShadowNodeImpl(); + node.setViewClassName(ReactViewManager.REACT_CLASS); + node.setThemedContext(mThemedReactContext); + return node; + } + + private static class MockYogaNodePool extends ClearableSynchronizedPool { + + private List mMockYogaNodes; + + public MockYogaNodePool() { + super(1024); + mMockYogaNodes = new LinkedList<>(); + } + + public void add(YogaNode... nodes) { + Collections.addAll(mMockYogaNodes, nodes); + } + + @Override + public synchronized YogaNode acquire() { + if (!mMockYogaNodes.isEmpty()) { + return mMockYogaNodes.remove(0); + } + return createMockYogaNode(); + } + + private static YogaNode createMockYogaNode() { + final YogaNode yogaNode = mock(YogaNode.class); + when(yogaNode.clone()).thenReturn(yogaNode); + when(yogaNode.cloneWithNewChildren()).thenReturn(yogaNode); + doAnswer( + new Answer() { + @Override + public Object answer(InvocationOnMock invocation) { + when(yogaNode.isMeasureDefined()).thenReturn(true); + return null; + } + }) + .when(yogaNode) + .setMeasureFunction(any(YogaMeasureFunction.class)); + return yogaNode; + } + } +} From c4ab03a18e75e6ed55444b5d86f3ceee435b9a78 Mon Sep 17 00:00:00 2001 From: Luciano Lima Date: Tue, 17 Apr 2018 16:12:03 -0700 Subject: [PATCH 0324/1109] Add devDependencies support for templates Summary: Add devDependencies support to React Native templates. Template can have a devDependencies.json file with devDependencies inside. Using separate files to dependencies and devDependencies, it maintains compatibility with the current version. Allows React Native templates to have devDependencies, which can help applications to have better organization, quality and testability. It's possible start a new app with some dependencies for dev support like prettier, reactotron, eslint packages and others. Add a devDependencies.json file with at least one dependency (like prettier) [CLI] [FEATURE] [local-cli/generator/templates.js] - Add support to devDependencies for react native templates Closes https://github.com/facebook/react-native/pull/18164 Differential Revision: D7660744 Pulled By: hramos fbshipit-source-id: 6fbb13832d2d1bd0c06bada0842c890dd99cf331 --- local-cli/generator/templates.js | 34 ++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/local-cli/generator/templates.js b/local-cli/generator/templates.js index 98e2897a5d0212..99e63ec2e99c1c 100644 --- a/local-cli/generator/templates.js +++ b/local-cli/generator/templates.js @@ -99,6 +99,7 @@ function createFromBuiltInTemplate(templateName, destPath, newProjectName, yarnV newProjectName, ); installTemplateDependencies(templatePath, yarnVersion); + installTemplateDevDependencies(templatePath, yarnVersion); } /** @@ -143,6 +144,7 @@ function createFromRemoteTemplate(template, destPath, newProjectName, yarnVersio } ); installTemplateDependencies(templatePath, yarnVersion); + installTemplateDevDependencies(templatePath, yarnVersion); } finally { // Clean up the temp files try { @@ -196,6 +198,38 @@ function installTemplateDependencies(templatePath, yarnVersion) { execSync('react-native link', {stdio: 'inherit'}); } +function installTemplateDevDependencies(templatePath, yarnVersion) { + // devDependencies.json is a special file that lists additional develop dependencies + // that are required by this template + const devDependenciesJsonPath = path.resolve( + templatePath, 'devDependencies.json' + ); + console.log('Adding develop dependencies for the project...'); + if (!fs.existsSync(devDependenciesJsonPath)) { + console.log('No additional develop dependencies.'); + return; + } + + let dependencies; + try { + dependencies = JSON.parse(fs.readFileSync(devDependenciesJsonPath)); + } catch (err) { + throw new Error( + 'Could not parse the template\'s devDependencies.json: ' + err.message + ); + } + for (let depName in dependencies) { + const depVersion = dependencies[depName]; + const depToInstall = depName + '@' + depVersion; + console.log('Adding ' + depToInstall + '...'); + if (yarnVersion) { + execSync(`yarn add ${depToInstall} -D`, {stdio: 'inherit'}); + } else { + execSync(`npm install ${depToInstall} --save-dev --save-exact`, {stdio: 'inherit'}); + } + } +} + module.exports = { listTemplatesAndExit, createProjectFromTemplate, From ff9b3c6517d6427b8ca0cec2660555152be3d028 Mon Sep 17 00:00:00 2001 From: "Andrew Chen (Eng)" Date: Tue, 17 Apr 2018 17:17:12 -0700 Subject: [PATCH 0325/1109] Display JS component stack in native view exceptions Reviewed By: mdvacca Differential Revision: D7578033 fbshipit-source-id: 4dc393cddf8487db58cc3a9fefbff220983ba9da --- Libraries/Renderer/shims/ReactNativeTypes.js | 1 + Libraries/Utilities/JSDevSupportModule.js | 27 ++++--- .../com/facebook/react/DebugCorePackage.java | 9 --- .../com/facebook/react/ReactRootView.java | 13 ++-- .../devsupport/DevSupportManagerImpl.java | 71 ------------------- .../react/devsupport/JSDevSupport.java | 59 ++++++++++----- .../react/devsupport/ViewHierarchyUtil.java | 37 ++++++++++ 7 files changed, 102 insertions(+), 115 deletions(-) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/devsupport/ViewHierarchyUtil.java diff --git a/Libraries/Renderer/shims/ReactNativeTypes.js b/Libraries/Renderer/shims/ReactNativeTypes.js index fdee974ae88aa5..1f7f5d0015a2ad 100644 --- a/Libraries/Renderer/shims/ReactNativeTypes.js +++ b/Libraries/Renderer/shims/ReactNativeTypes.js @@ -72,6 +72,7 @@ export type NativeMethodsMixinType = { type SecretInternalsType = { NativeMethodsMixin: NativeMethodsMixinType, ReactNativeComponentTree: any, + computeComponentStackForErrorReporting(tag: number): string, // TODO (bvaughn) Decide which additional types to expose here? // And how much information to fill in for the above types. }; diff --git a/Libraries/Utilities/JSDevSupportModule.js b/Libraries/Utilities/JSDevSupportModule.js index a33e91e886185b..dc45030bf3b5bd 100644 --- a/Libraries/Utilities/JSDevSupportModule.js +++ b/Libraries/Utilities/JSDevSupportModule.js @@ -9,16 +9,25 @@ */ 'use strict'; -var JSDevSupportModule = { - getJSHierarchy: function (tag: string) { - const hook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__; - const renderers = hook._renderers; - const keys = Object.keys(renderers); - const renderer = renderers[keys[0]]; +const JSDevSupport = require('NativeModules').JSDevSupport; +const ReactNative = require('ReactNative'); - var result = renderer.getInspectorDataForViewTag(tag); - var path = result.hierarchy.map( (item) => item.name).join(' -> '); - require('NativeModules').JSDevSupport.setResult(path, null); +const JSDevSupportModule = { + getJSHierarchy: function (tag: number) { + try { + const {computeComponentStackForErrorReporting} = + ReactNative.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; + const componentStack = computeComponentStackForErrorReporting(tag); + if (!componentStack) { + JSDevSupport.onFailure( + JSDevSupport.ERROR_CODE_VIEW_NOT_FOUND, + 'Component stack doesn\'t exist for tag ' + tag); + } else { + JSDevSupport.onSuccess(componentStack); + } + } catch (e) { + JSDevSupport.onFailure(JSDevSupport.ERROR_CODE_EXCEPTION, e.message); + } }, }; diff --git a/ReactAndroid/src/main/java/com/facebook/react/DebugCorePackage.java b/ReactAndroid/src/main/java/com/facebook/react/DebugCorePackage.java index 290082e545ba0c..1de05ef8977a2f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/DebugCorePackage.java +++ b/ReactAndroid/src/main/java/com/facebook/react/DebugCorePackage.java @@ -48,15 +48,6 @@ public NativeModule get() { return new JSCHeapCapture(reactContext); } })); - moduleSpecList.add( - ModuleSpec.nativeModuleSpec( - JSDevSupport.class, - new Provider() { - @Override - public NativeModule get() { - return new JSDevSupport(reactContext); - } - })); moduleSpecList.add( ModuleSpec.nativeModuleSpec( JSCSamplingProfiler.class, diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java index c1d74a4aeddb6b..baa2a6e30d96f6 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java @@ -42,11 +42,11 @@ import com.facebook.react.uimanager.DisplayMetricsHolder; import com.facebook.react.uimanager.IllegalViewOperationException; import com.facebook.react.uimanager.JSTouchDispatcher; -import com.facebook.react.uimanager.common.MeasureSpecProvider; import com.facebook.react.uimanager.PixelUtil; import com.facebook.react.uimanager.RootView; -import com.facebook.react.uimanager.common.SizeMonitoringFrameLayout; import com.facebook.react.uimanager.UIManagerModule; +import com.facebook.react.uimanager.common.MeasureSpecProvider; +import com.facebook.react.uimanager.common.SizeMonitoringFrameLayout; import com.facebook.react.uimanager.events.EventDispatcher; import com.facebook.systrace.Systrace; import javax.annotation.Nullable; @@ -572,18 +572,13 @@ public void setRootViewTag(int rootViewTag) { } @Override - public void handleException(Throwable t) { + public void handleException(final Throwable t) { if (mReactInstanceManager == null || mReactInstanceManager.getCurrentReactContext() == null) { throw new RuntimeException(t); } - // Adding special exception management for StackOverflowError for logging purposes. - // This will be removed in the future. - Exception e = (t instanceof StackOverflowError) ? - new IllegalViewOperationException("StackOverflowException", this, t) : - t instanceof Exception ? (Exception) t : new RuntimeException(t); - + Exception e = new IllegalViewOperationException(t.getMessage(), this, t); mReactInstanceManager.getCurrentReactContext().handleException(e); } 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 c04211a98b0942..ea25bf86c42ae7 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java @@ -22,10 +22,7 @@ import android.net.Uri; import android.os.AsyncTask; import android.util.Pair; -import android.view.View; -import android.view.ViewGroup; import android.widget.Toast; - import com.facebook.common.logging.FLog; import com.facebook.debug.holder.PrinterHolder; import com.facebook.debug.tags.ReactDebugOverlayTags; @@ -45,7 +42,6 @@ import com.facebook.react.common.ShakeDetector; import com.facebook.react.common.futures.SimpleSettableFuture; import com.facebook.react.devsupport.DevServerHelper.PackagerCommandListener; -import com.facebook.react.devsupport.InspectorPackagerConnection; import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener; import com.facebook.react.devsupport.interfaces.DevOptionHandler; import com.facebook.react.devsupport.interfaces.DevSupportManager; @@ -55,24 +51,18 @@ import com.facebook.react.modules.debug.interfaces.DeveloperSettings; import com.facebook.react.packagerconnection.RequestHandler; import com.facebook.react.packagerconnection.Responder; - -import com.facebook.react.uimanager.IllegalViewOperationException; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.LinkedHashMap; -import java.util.LinkedList; import java.util.List; import java.util.Locale; -import java.util.Queue; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; - import javax.annotation.Nullable; - import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; @@ -274,7 +264,6 @@ public void onReceive(Context context, Intent intent) { new DevLoadingViewController(applicationContext, reactInstanceManagerHelper); mExceptionLoggers.add(new JSExceptionLogger()); - mExceptionLoggers.add(new StackOverflowExceptionLogger()); } @Override @@ -322,66 +311,6 @@ public void log(Exception e) { } } - private class StackOverflowExceptionLogger implements ExceptionLogger { - - @Override - public void log(Exception e) { - if (e instanceof IllegalViewOperationException - && e.getCause() instanceof StackOverflowError) { - IllegalViewOperationException ivoe = (IllegalViewOperationException) e; - View view = ivoe.getView(); - if (view != null) - logDeepestJSHierarchy(view); - } - } - - private void logDeepestJSHierarchy(View view) { - if (mCurrentContext == null || view == null) return; - - final Pair deepestPairView = getDeepestNativeView(view); - - View deepestView = deepestPairView.first; - Integer tagId = deepestView.getId(); - final int depth = deepestPairView.second; - JSDevSupport JSDevSupport = mCurrentContext.getNativeModule(JSDevSupport.class); - JSDevSupport.getJSHierarchy(tagId.toString(), new JSDevSupport.DevSupportCallback() { - @Override - public void onSuccess(String hierarchy) { - FLog.e(ReactConstants.TAG, - "StackOverflowError when rendering JS Hierarchy (depth of native hierarchy = " + - depth + "): \n" + hierarchy); - } - - @Override - public void onFailure(Exception ex) { - FLog.e(ReactConstants.TAG, ex, - "Error retrieving JS Hierarchy (depth of native hierarchy = " + depth + ")."); - } - }); - } - - private Pair getDeepestNativeView(View root) { - Queue> queue = new LinkedList<>(); - Pair maxPair = new Pair<>(root, 1); - - queue.add(maxPair); - while (!queue.isEmpty()) { - Pair current = queue.poll(); - if (current.second > maxPair.second) { - maxPair = current; - } - if (current.first instanceof ViewGroup) { - ViewGroup viewGroup = (ViewGroup) current.first; - Integer depth = current.second + 1; - for (int i = 0 ; i < viewGroup.getChildCount() ; i++) { - queue.add(new Pair<>(viewGroup.getChildAt(i), depth)); - } - } - } - return maxPair; - } - } - @Override public void showNewJavaError(String message, Throwable e) { FLog.e(ReactConstants.TAG, "Exception in native call", e); diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/JSDevSupport.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/JSDevSupport.java index b5596d7f365a26..4e306ba1035daa 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/JSDevSupport.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/JSDevSupport.java @@ -2,23 +2,31 @@ package com.facebook.react.devsupport; +import android.util.Pair; +import android.view.View; import com.facebook.react.bridge.JavaScriptModule; import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.module.annotations.ReactModule; +import java.util.HashMap; +import java.util.Map; import javax.annotation.Nullable; -@ReactModule(name = "JSDevSupport", needsEagerInit = true) +@ReactModule(name = JSDevSupport.MODULE_NAME) public class JSDevSupport extends ReactContextBaseJavaModule { static final String MODULE_NAME = "JSDevSupport"; + public static final int ERROR_CODE_EXCEPTION = 0; + public static final int ERROR_CODE_VIEW_NOT_FOUND = 1; + @Nullable private volatile DevSupportCallback mCurrentCallback = null; public interface JSDevSupportModule extends JavaScriptModule { - void getJSHierarchy(String reactTag); + void getJSHierarchy(int reactTag); } public JSDevSupport(ReactApplicationContext reactContext) { @@ -29,19 +37,25 @@ public interface DevSupportCallback { void onSuccess(String data); - void onFailure(Exception error); + void onFailure(int errorCode, Exception error); } - public synchronized void getJSHierarchy(String reactTag, DevSupportCallback callback) { - if (mCurrentCallback != null) { - callback.onFailure(new RuntimeException("JS Hierarchy download already in progress.")); - return; - } + /** + * Notifies the callback with either the JS hierarchy of the deepest leaf from the given root view + * or with an error. + */ + public synchronized void computeDeepestJSHierarchy(View root, DevSupportCallback callback) { + final Pair deepestPairView = ViewHierarchyUtil.getDeepestLeaf(root); + View deepestView = deepestPairView.first; + Integer tagId = deepestView.getId(); + getJSHierarchy(tagId, callback); + } + public synchronized void getJSHierarchy(int reactTag, DevSupportCallback callback) { JSDevSupportModule jsDevSupportModule = getReactApplicationContext().getJSModule(JSDevSupportModule.class); if (jsDevSupportModule == null) { - callback.onFailure(new JSCHeapCapture.CaptureException(MODULE_NAME + + callback.onFailure(ERROR_CODE_EXCEPTION, new JSCHeapCapture.CaptureException(MODULE_NAME + " module not registered.")); return; } @@ -51,20 +65,31 @@ public synchronized void getJSHierarchy(String reactTag, DevSupportCallback call @SuppressWarnings("unused") @ReactMethod - public synchronized void setResult(String data, String error) { + public synchronized void onSuccess(String data) { + if (mCurrentCallback != null) { + mCurrentCallback.onSuccess(data); + } + } + + @SuppressWarnings("unused") + @ReactMethod + public synchronized void onFailure(int errorCode, String error) { if (mCurrentCallback != null) { - if (error == null) { - mCurrentCallback.onSuccess(data); - } else { - mCurrentCallback.onFailure(new RuntimeException(error)); - } + mCurrentCallback.onFailure(errorCode, new RuntimeException(error)); } - mCurrentCallback = null; + } + + @Override + public Map getConstants() { + HashMap constants = new HashMap<>(); + constants.put("ERROR_CODE_EXCEPTION", ERROR_CODE_EXCEPTION); + constants.put("ERROR_CODE_VIEW_NOT_FOUND", ERROR_CODE_VIEW_NOT_FOUND); + return constants; } @Override public String getName() { - return "JSDevSupport"; + return MODULE_NAME; } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/ViewHierarchyUtil.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/ViewHierarchyUtil.java new file mode 100644 index 00000000000000..1aee0099e5f31f --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/ViewHierarchyUtil.java @@ -0,0 +1,37 @@ +package com.facebook.react.devsupport; + +import android.util.Pair; +import android.view.View; +import android.view.ViewGroup; +import java.util.LinkedList; +import java.util.Queue; + +/** + * Helper for computing information about the view hierarchy + */ +public class ViewHierarchyUtil { + + /** + * Returns the view instance and depth of the deepest leaf view from the given root view. + */ + public static Pair getDeepestLeaf(View root) { + Queue> queue = new LinkedList<>(); + Pair maxPair = new Pair<>(root, 1); + + queue.add(maxPair); + while (!queue.isEmpty()) { + Pair current = queue.poll(); + if (current.second > maxPair.second) { + maxPair = current; + } + if (current.first instanceof ViewGroup) { + ViewGroup viewGroup = (ViewGroup) current.first; + Integer depth = current.second + 1; + for (int i = 0 ; i < viewGroup.getChildCount() ; i++) { + queue.add(new Pair<>(viewGroup.getChildAt(i), depth)); + } + } + } + return maxPair; + } +} From 864cc00a6107fd8144f1c4ecaf5b35260d00cf7d Mon Sep 17 00:00:00 2001 From: "Andrew Chen (Eng)" Date: Tue, 17 Apr 2018 18:11:28 -0700 Subject: [PATCH 0326/1109] Use real YogaNodes in FabricUIManagerTest Reviewed By: mdvacca Differential Revision: D7663769 fbshipit-source-id: 78cdde975037c4e8d97d4bd21ddd7927cc105dd0 --- .../react/fabric/FabricUIManagerTest.java | 103 ++---------------- 1 file changed, 8 insertions(+), 95 deletions(-) diff --git a/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java b/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java index d1aebcd7e263f3..540ce011c70851 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java @@ -16,20 +16,15 @@ import com.facebook.react.fabric.FabricUIManager; import com.facebook.react.uimanager.ReactShadowNode; import com.facebook.react.uimanager.ReactShadowNodeImpl; -import com.facebook.react.uimanager.ReactYogaConfigProvider; import com.facebook.react.uimanager.Spacing; import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.ViewManager; import com.facebook.react.uimanager.ViewManagerRegistry; -import com.facebook.react.uimanager.YogaNodePool; import com.facebook.react.views.text.ReactRawTextManager; import com.facebook.react.views.text.ReactRawTextShadowNode; import com.facebook.react.views.text.ReactTextViewManager; import com.facebook.react.views.view.ReactViewManager; import com.facebook.testing.robolectric.v3.WithTestDefaultsRunner; -import com.facebook.yoga.YogaConfig; -import com.facebook.yoga.YogaMeasureFunction; -import com.facebook.yoga.YogaNode; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -45,16 +40,12 @@ import org.robolectric.RuntimeEnvironment; /** Tests {@link FabricUIManager} */ -@PrepareForTest({YogaNodePool.class, ReactYogaConfigProvider.class}) @RunWith(WithTestDefaultsRunner.class) public class FabricUIManagerTest { private FabricUIManager mFabricUIManager; private ThemedReactContext mThemedReactContext; private int mNextReactTag; - private MockYogaNodePool mMockYogaNodePool; - - private YogaMeasureFunction mLastYogaMeasureFunction; @Before public void setUp() throws Exception { @@ -70,19 +61,6 @@ public void setUp() throws Exception { ViewManagerRegistry viewManagerRegistry = new ViewManagerRegistry(viewManagers); mFabricUIManager = new FabricUIManager(reactContext, viewManagerRegistry); - - // Hack around Yoga until the UnsatisfiedLinkErrors are fixed t14964130 - PowerMockito.mockStatic(YogaNodePool.class, ReactYogaConfigProvider.class); - mMockYogaNodePool = new MockYogaNodePool(); - PowerMockito.when(YogaNodePool.get()).thenReturn(mMockYogaNodePool); - PowerMockito.when(ReactYogaConfigProvider.get()) - .thenAnswer( - new Answer() { - @Override - public Object answer(InvocationOnMock invocation) { - return mock(YogaConfig.class); - } - }); } @Test @@ -222,13 +200,7 @@ public void testCompleteRoot() { } /** - * Tests that cloned text nodes will reassign their yoga nodes' measure functions. - * - *

TODO(T26729515): Currently this tests the wrong implementation. It assumes that yoga nodes - * are reused across clones and simply checks the most recently assigned measure functions of the - * shared yoga node. When yoga node cloning is implemented, this needs to be changed to mock each - * cloned shadow nodes' yoga nodes and make the same assertions on each of their measure - * functions. + * Tests that cloned text nodes will not share measure functions */ @Test public void testTextMutableClone() { @@ -236,39 +208,20 @@ public void testTextMutableClone() { new ReactRootView(RuntimeEnvironment.application.getApplicationContext()); int rootTag = mFabricUIManager.addRootView(rootView); - final YogaNode yogaNode = mock(YogaNode.class); - - doAnswer( - new Answer() { - @Override - public Object answer(InvocationOnMock invocation) { - when(yogaNode.isMeasureDefined()).thenReturn(true); - when(yogaNode.clone()).thenReturn(yogaNode); - when(yogaNode.cloneWithNewChildren()).thenReturn(yogaNode); - mLastYogaMeasureFunction = (YogaMeasureFunction) invocation.getArguments()[0]; - return null; - } - }) - .when(yogaNode) - .setMeasureFunction(any(YogaMeasureFunction.class)); - - mMockYogaNodePool.add(yogaNode); - ReactShadowNode text = mFabricUIManager.createNode(0, ReactTextViewManager.REACT_CLASS, rootTag, null); - YogaMeasureFunction textMeasureFunction = mLastYogaMeasureFunction; assertThat(text.isMeasureDefined()).isTrue(); ReactShadowNode textCopy = text.mutableCopy(); - YogaMeasureFunction textCopyMeasureFunction = mLastYogaMeasureFunction; assertThat(textCopy.isMeasureDefined()).isTrue(); - assertThat(textCopyMeasureFunction).isNotSameAs(textMeasureFunction); - ReactShadowNode textCopyWithNewChildren = text.mutableCopyWithNewChildren(); - YogaMeasureFunction textCopyWithNewChildrenMeasureFunction = mLastYogaMeasureFunction; - assertThat(textCopyWithNewChildren.isMeasureDefined()).isTrue(); - assertThat(textCopyWithNewChildrenMeasureFunction).isNotSameAs(textMeasureFunction); - assertThat(textCopyWithNewChildrenMeasureFunction).isNotSameAs(textCopyMeasureFunction); + textCopy.setStyleWidth(200); + text.onBeforeLayout(); + text.calculateLayout(); + textCopy.onBeforeLayout(); + textCopy.calculateLayout(); + + assertThat(text.getLayoutWidth()).isNotEqualTo(textCopy.getLayoutWidth()); } /** @@ -332,7 +285,6 @@ private void assertSameFields(ReactShadowNode node1, ReactShadowNode node2) { assertThat(node1.getLayoutX()).isEqualTo(node2.getLayoutX()); assertThat(node1.getLayoutY()).isEqualTo(node2.getLayoutY()); for (int spacingType = Spacing.LEFT; spacingType <= Spacing.ALL; spacingType++) { - assertThat(node1.getPadding(spacingType)).isEqualTo(node2.getPadding(spacingType)); assertThat(node1.getStylePadding(spacingType)).isEqualTo(node2.getStylePadding(spacingType)); } assertThat(node1.getStyleWidth()).isEqualTo(node2.getStyleWidth()); @@ -345,43 +297,4 @@ private ReactShadowNode createViewNode() { node.setThemedContext(mThemedReactContext); return node; } - - private static class MockYogaNodePool extends ClearableSynchronizedPool { - - private List mMockYogaNodes; - - public MockYogaNodePool() { - super(1024); - mMockYogaNodes = new LinkedList<>(); - } - - public void add(YogaNode... nodes) { - Collections.addAll(mMockYogaNodes, nodes); - } - - @Override - public synchronized YogaNode acquire() { - if (!mMockYogaNodes.isEmpty()) { - return mMockYogaNodes.remove(0); - } - return createMockYogaNode(); - } - - private static YogaNode createMockYogaNode() { - final YogaNode yogaNode = mock(YogaNode.class); - when(yogaNode.clone()).thenReturn(yogaNode); - when(yogaNode.cloneWithNewChildren()).thenReturn(yogaNode); - doAnswer( - new Answer() { - @Override - public Object answer(InvocationOnMock invocation) { - when(yogaNode.isMeasureDefined()).thenReturn(true); - return null; - } - }) - .when(yogaNode) - .setMeasureFunction(any(YogaMeasureFunction.class)); - return yogaNode; - } - } } From aa6239301ab2eae2aefb44b024e18e5d5ee9be99 Mon Sep 17 00:00:00 2001 From: Pascal Hartig Date: Wed, 18 Apr 2018 04:29:45 -0700 Subject: [PATCH 0327/1109] Add getParent() method for easier migration Reviewed By: emilsjolander Differential Revision: D7654526 fbshipit-source-id: efe44807caa97f495c5e5691dedcf281760fa23e --- ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java | 7 +++++++ 1 file 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 59a14d242088b8..fdb5b4be5017c1 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java @@ -239,6 +239,13 @@ YogaNode getOwner() { return mOwner; } + /** @deprecated Use #getOwner() instead. This will be removed in the next version. */ + @Deprecated + @Nullable + YogaNode getParent() { + return getOwner(); + } + public int indexOf(YogaNode child) { return mChildren == null ? -1 : mChildren.indexOf(child); } From 850fd869422d50a990f9ce64a37495cbd851fc47 Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Wed, 18 Apr 2018 12:09:11 -0700 Subject: [PATCH 0328/1109] Bump metro@0.33.0 Reviewed By: davidaurelio Differential Revision: D7661486 fbshipit-source-id: 5186a853eaff139948622e93d851deb9577567dc --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 3509869f9b457c..066c873aa89fc2 100644 --- a/package.json +++ b/package.json @@ -166,8 +166,8 @@ "graceful-fs": "^4.1.3", "inquirer": "^3.0.6", "lodash": "^4.17.5", - "metro": "^0.32.0", - "metro-core": "^0.32.0", + "metro": "^0.33.0", + "metro-core": "^0.33.0", "mime": "^1.3.4", "minimist": "^1.2.0", "mkdirp": "^0.5.1", From af2095842535c05613240215052fbcdd2f34ce64 Mon Sep 17 00:00:00 2001 From: "Andrew Chen (Eng)" Date: Wed, 18 Apr 2018 14:55:52 -0700 Subject: [PATCH 0329/1109] Use real YogaNodes in FabricReconcilerTest Reviewed By: mdvacca Differential Revision: D7664493 fbshipit-source-id: 74b088a91ea4f691cc15b5ea15dd585fe46e2035 --- .../react/fabric/FabricReconcilerTest.java | 80 +++++++------------ 1 file changed, 28 insertions(+), 52 deletions(-) diff --git a/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricReconcilerTest.java b/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricReconcilerTest.java index 23272c23427c31..26def0ca1c2ca0 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricReconcilerTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricReconcilerTest.java @@ -4,22 +4,21 @@ import static org.fest.assertions.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import static org.powermock.api.mockito.PowerMockito.mockStatic; +import com.facebook.react.bridge.CatalystInstance; import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.common.ClearableSynchronizedPool; +import com.facebook.react.bridge.ReactTestHelper; import com.facebook.react.fabric.FabricReconciler; -import com.facebook.react.modules.core.ReactChoreographer; +import com.facebook.react.fabric.FabricUIManager; import com.facebook.react.uimanager.NativeViewHierarchyManager; import com.facebook.react.uimanager.ReactShadowNode; import com.facebook.react.uimanager.ReactShadowNodeImpl; -import com.facebook.react.uimanager.ReactYogaConfigProvider; import com.facebook.react.uimanager.UIViewOperationQueue; import com.facebook.react.uimanager.ViewAtIndex; -import com.facebook.react.uimanager.YogaNodePool; +import com.facebook.react.uimanager.ThemedReactContext; +import com.facebook.react.uimanager.ViewManager; +import com.facebook.react.uimanager.ViewManagerRegistry; import com.facebook.testing.robolectric.v3.WithTestDefaultsRunner; -import com.facebook.yoga.YogaConfig; -import com.facebook.yoga.YogaNode; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -27,34 +26,27 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; import org.robolectric.RuntimeEnvironment; /** Tests {@link FabricReconciler} */ -@PrepareForTest({ - ReactChoreographer.class, - ReactYogaConfigProvider.class, - YogaNodePool.class, -}) @RunWith(WithTestDefaultsRunner.class) -@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"}) public class FabricReconcilerTest { private FabricReconciler mFabricReconciler; + private FabricUIManager mFabricUIManager; private MockUIViewOperationQueue mMockUIViewOperationQueue; @Before public void setUp() { + CatalystInstance catalystInstance = ReactTestHelper.createMockCatalystInstance(); ReactApplicationContext reactContext = new ReactApplicationContext(RuntimeEnvironment.application); + reactContext.initializeWithInstance(catalystInstance); + List viewManagers = new ArrayList<>(); + ViewManagerRegistry viewManagerRegistry = new ViewManagerRegistry(viewManagers); + mFabricUIManager = new FabricUIManager(reactContext, viewManagerRegistry); mMockUIViewOperationQueue = new MockUIViewOperationQueue(reactContext); mFabricReconciler = new FabricReconciler(mMockUIViewOperationQueue); - - setupHacks(); } @Test @@ -98,6 +90,12 @@ public void testVirtualNodes() { assertThat(mMockUIViewOperationQueue.getOperations()).isEqualTo(expectedOperations); } + private void addChildren(ReactShadowNode parent, ReactShadowNode... children) { + for (ReactShadowNode child : children) { + mFabricUIManager.appendChild(parent, child); + } + } + private static ReactShadowNode createNode(int tag) { return createNode(tag, false); } @@ -114,20 +112,26 @@ private static ReactShadowNode createNode(int tag, boolean virtual) { node = new ReactShadowNodeImpl(); } node.setReactTag(tag); + node.setThemedContext(mock(ThemedReactContext.class)); return node; } private static class VirtualReactShadowNode extends ReactShadowNodeImpl { + VirtualReactShadowNode() {} + + VirtualReactShadowNode(VirtualReactShadowNode original) { + super(original); + } + @Override public boolean isVirtual() { return true; } - } - private static void addChildren(ReactShadowNode parent, ReactShadowNode... children) { - for (ReactShadowNode child : children) { - parent.addChildAt(child, parent.getChildCount()); + @Override + public ReactShadowNodeImpl copy() { + return new VirtualReactShadowNode(this); } } @@ -193,32 +197,4 @@ public List getOperations() { return Collections.unmodifiableList(mOperations); } } - - /** Hacks to get tests to start working end to end */ - private void setupHacks() { - // Hack around Yoga by mocking it out until the UnsatisfiedLinkErrors are fixed t14964130 - mockStatic(YogaNodePool.class, ReactYogaConfigProvider.class); - PowerMockito.when(YogaNodePool.get()) - .thenAnswer( - new Answer() { - @Override - public Object answer(InvocationOnMock invocation) throws Exception { - ClearableSynchronizedPool yogaPool = - mock(ClearableSynchronizedPool.class); - YogaNode yogaNode = mock(YogaNode.class); - when(yogaNode.clone()).thenReturn(mock(YogaNode.class)); - when(yogaNode.isMeasureDefined()).thenReturn(true); - when(yogaPool.acquire()).thenReturn(yogaNode); - return yogaPool; - } - }); - PowerMockito.when(ReactYogaConfigProvider.get()) - .thenAnswer( - new Answer() { - @Override - public Object answer(InvocationOnMock invocation) { - return mock(YogaConfig.class); - } - }); - } } From 2ad0a92d388db6ba9a1e699640a3394092dbb521 Mon Sep 17 00:00:00 2001 From: "Andrew Chen (Eng)" Date: Wed, 18 Apr 2018 14:55:54 -0700 Subject: [PATCH 0330/1109] Fix OSS Fabric test build Reviewed By: fkgozali Differential Revision: D7676633 fbshipit-source-id: a7db945395af10d06dddc1fde4bd035aee14b702 --- ReactAndroid/src/test/java/com/facebook/react/fabric/BUCK | 2 -- .../java/com/facebook/react/fabric/FabricReconcilerTest.java | 4 ++-- .../java/com/facebook/react/fabric/FabricUIManagerTest.java | 4 ++-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/ReactAndroid/src/test/java/com/facebook/react/fabric/BUCK b/ReactAndroid/src/test/java/com/facebook/react/fabric/BUCK index 21917d67f81feb..55eb26ebc3e6ff 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/fabric/BUCK +++ b/ReactAndroid/src/test/java/com/facebook/react/fabric/BUCK @@ -13,8 +13,6 @@ rn_robolectric_test( ], deps = [ "xplat//yoga/java:java", - react_native_dep("java/com/facebook/common/executors:executors"), - react_native_dep("java/com/facebook/testing/robolectric/v3:v3"), react_native_dep("third-party/java/assertj:assertj-core"), react_native_dep("third-party/java/fest:fest"), react_native_dep("third-party/java/fest:fest_android"), diff --git a/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricReconcilerTest.java b/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricReconcilerTest.java index 26def0ca1c2ca0..36dfa8267a7e5c 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricReconcilerTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricReconcilerTest.java @@ -18,7 +18,6 @@ import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.ViewManager; import com.facebook.react.uimanager.ViewManagerRegistry; -import com.facebook.testing.robolectric.v3.WithTestDefaultsRunner; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -26,10 +25,11 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; /** Tests {@link FabricReconciler} */ -@RunWith(WithTestDefaultsRunner.class) +@RunWith(RobolectricTestRunner.class) public class FabricReconcilerTest { private FabricReconciler mFabricReconciler; diff --git a/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java b/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java index 540ce011c70851..40c8b2e78d55e7 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java @@ -24,7 +24,6 @@ import com.facebook.react.views.text.ReactRawTextShadowNode; import com.facebook.react.views.text.ReactTextViewManager; import com.facebook.react.views.view.ReactViewManager; -import com.facebook.testing.robolectric.v3.WithTestDefaultsRunner; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -37,10 +36,11 @@ import org.mockito.stubbing.Answer; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; /** Tests {@link FabricUIManager} */ -@RunWith(WithTestDefaultsRunner.class) +@RunWith(RobolectricTestRunner.class) public class FabricUIManagerTest { private FabricUIManager mFabricUIManager; From 908e8850b9335d229fd51e60168dd6c161f7a026 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Wed, 18 Apr 2018 14:59:57 -0700 Subject: [PATCH 0331/1109] Forked RN renderers for FB and OSS (52afbe0...0887c7d) Reviewed By: fkgozali Differential Revision: D7658727 fbshipit-source-id: 2fdd30694b169d180b40bc1059ecc297b07cd18d --- Libraries/Renderer/REVISION | 2 +- .../Renderer/{ => fb}/ReactFabric-dev.js | 28 +- .../Renderer/{ => fb}/ReactFabric-prod.js | 23 +- .../{shims => fb}/ReactFeatureFlags.js | 0 .../{ => fb}/ReactNativeRenderer-dev.js | 28 +- .../{ => fb}/ReactNativeRenderer-prod.js | 23 +- Libraries/Renderer/oss/ReactFabric-dev.js | 13863 +++++++++++++++ Libraries/Renderer/oss/ReactFabric-prod.js | 5876 +++++++ .../Renderer/oss/ReactNativeRenderer-dev.js | 14432 ++++++++++++++++ .../Renderer/oss/ReactNativeRenderer-prod.js | 6311 +++++++ Libraries/Renderer/shims/ReactNativeTypes.js | 7 +- package.json | 6 +- 12 files changed, 40572 insertions(+), 27 deletions(-) rename Libraries/Renderer/{ => fb}/ReactFabric-dev.js (99%) rename Libraries/Renderer/{ => fb}/ReactFabric-prod.js (99%) rename Libraries/Renderer/{shims => fb}/ReactFeatureFlags.js (100%) rename Libraries/Renderer/{ => fb}/ReactNativeRenderer-dev.js (99%) rename Libraries/Renderer/{ => fb}/ReactNativeRenderer-prod.js (99%) create mode 100644 Libraries/Renderer/oss/ReactFabric-dev.js create mode 100644 Libraries/Renderer/oss/ReactFabric-prod.js create mode 100644 Libraries/Renderer/oss/ReactNativeRenderer-dev.js create mode 100644 Libraries/Renderer/oss/ReactNativeRenderer-prod.js diff --git a/Libraries/Renderer/REVISION b/Libraries/Renderer/REVISION index 4d4db61db4a5ee..ba0ce2996c4812 100644 --- a/Libraries/Renderer/REVISION +++ b/Libraries/Renderer/REVISION @@ -1 +1 @@ -52afbe0ebb6fca0fe480e77c6fa8482870ddb2c9 \ No newline at end of file +0887c7d56cb9b83f36dcb490b4245d7bc33bda1f \ No newline at end of file diff --git a/Libraries/Renderer/ReactFabric-dev.js b/Libraries/Renderer/fb/ReactFabric-dev.js similarity index 99% rename from Libraries/Renderer/ReactFabric-dev.js rename to Libraries/Renderer/fb/ReactFabric-dev.js index e933ab8f0bb430..0424315c8ed6b5 100644 --- a/Libraries/Renderer/ReactFabric-dev.js +++ b/Libraries/Renderer/fb/ReactFabric-dev.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @noflow - * @providesModule ReactFabric-dev * @preventMunge */ @@ -2392,7 +2391,7 @@ var injection$2 = { // TODO: this is special because it gets imported during build. -var ReactVersion = "16.3.1"; +var ReactVersion = "16.3.2"; // Modules provided by RN: var emptyObject$1 = {}; @@ -3387,6 +3386,15 @@ function getComponentName(fiber) { case REACT_RETURN_TYPE: return "ReactReturn"; } + if (typeof type === "object" && type !== null) { + switch (type.$$typeof) { + case REACT_FORWARD_REF_TYPE: + var functionName = type.render.displayName || type.render.name || ""; + return functionName !== "" + ? "ForwardRef(" + functionName + ")" + : "ForwardRef"; + } + } return null; } @@ -4735,6 +4743,7 @@ var shouldIgnoreFiber = function(fiber) { case Fragment: case ContextProvider: case ContextConsumer: + case Mode: return true; default: return false; @@ -12377,8 +12386,19 @@ var ReactFiberScheduler = function(config) { } function computeInteractiveExpiration(currentTime) { - // Should complete within ~500ms. 600ms max. - var expirationMs = 500; + var expirationMs = void 0; + // 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. + { + // Should complete within ~500ms. 600ms max. + expirationMs = 500; + } var bucketSizeMs = 100; return computeExpirationBucket(currentTime, expirationMs, bucketSizeMs); } diff --git a/Libraries/Renderer/ReactFabric-prod.js b/Libraries/Renderer/fb/ReactFabric-prod.js similarity index 99% rename from Libraries/Renderer/ReactFabric-prod.js rename to Libraries/Renderer/fb/ReactFabric-prod.js index d264fcf0163716..19ca0dde9e33cf 100644 --- a/Libraries/Renderer/ReactFabric-prod.js +++ b/Libraries/Renderer/fb/ReactFabric-prod.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @noflow - * @providesModule ReactFabric-prod * @preventMunge */ @@ -1242,6 +1241,14 @@ function getComponentName(fiber) { case REACT_RETURN_TYPE: return "ReactReturn"; } + if ("object" === typeof fiber && null !== fiber) + switch (fiber.$$typeof) { + case REACT_FORWARD_REF_TYPE: + return ( + (fiber = fiber.render.displayName || fiber.render.name || ""), + "" !== fiber ? "ForwardRef(" + fiber + ")" : "ForwardRef" + ); + } return null; } function isFiberMountedImpl(fiber) { @@ -2753,15 +2760,17 @@ function ChildReconciler(shouldTrackSideEffects) { currentFirstChild, newChild, expirationTime - ))) + )), + (currentFirstChild["return"] = returnFiber), + (returnFiber = currentFirstChild)) : (deleteRemainingChildren(returnFiber, currentFirstChild), (currentFirstChild = createFiberFromText( newChild, returnFiber.mode, expirationTime - ))), - (currentFirstChild["return"] = returnFiber), - (returnFiber = currentFirstChild), + )), + (currentFirstChild["return"] = returnFiber), + (returnFiber = currentFirstChild)), placeSingleChild(returnFiber) ); if (isArray$1(newChild)) @@ -4768,7 +4777,7 @@ function ReactFiberScheduler(config) { ? isCommitting ? 1 : nextRenderExpirationTime : fiber.mode & 1 ? isBatchingInteractiveUpdates - ? 10 * ((((recalculateCurrentTime() + 50) / 10) | 0) + 1) + ? 10 * ((((recalculateCurrentTime() + 15) / 10) | 0) + 1) : 25 * ((((recalculateCurrentTime() + 500) / 25) | 0) + 1) : 1; isBatchingInteractiveUpdates && @@ -5856,7 +5865,7 @@ ReactFabricRenderer.injectIntoDevTools({ findFiberByHostInstance: getInstanceFromTag, getInspectorDataForViewTag: getInspectorDataForViewTag, bundleType: 0, - version: "16.3.1", + version: "16.3.2", rendererPackageName: "react-native-renderer" }); var ReactFabric$2 = Object.freeze({ default: ReactFabric }), diff --git a/Libraries/Renderer/shims/ReactFeatureFlags.js b/Libraries/Renderer/fb/ReactFeatureFlags.js similarity index 100% rename from Libraries/Renderer/shims/ReactFeatureFlags.js rename to Libraries/Renderer/fb/ReactFeatureFlags.js diff --git a/Libraries/Renderer/ReactNativeRenderer-dev.js b/Libraries/Renderer/fb/ReactNativeRenderer-dev.js similarity index 99% rename from Libraries/Renderer/ReactNativeRenderer-dev.js rename to Libraries/Renderer/fb/ReactNativeRenderer-dev.js index 51e4aa2b0adcd6..bcdfa4c607aaa2 100644 --- a/Libraries/Renderer/ReactNativeRenderer-dev.js +++ b/Libraries/Renderer/fb/ReactNativeRenderer-dev.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @noflow - * @providesModule ReactNativeRenderer-dev * @preventMunge */ @@ -2773,7 +2772,7 @@ function createPortal( // TODO: this is special because it gets imported during build. -var ReactVersion = "16.3.1"; +var ReactVersion = "16.3.2"; var describeComponentFrame = function(name, source, ownerName) { return ( @@ -2808,6 +2807,15 @@ function getComponentName(fiber) { case REACT_RETURN_TYPE: return "ReactReturn"; } + if (typeof type === "object" && type !== null) { + switch (type.$$typeof) { + case REACT_FORWARD_REF_TYPE: + var functionName = type.render.displayName || type.render.name || ""; + return functionName !== "" + ? "ForwardRef(" + functionName + ")" + : "ForwardRef"; + } + } return null; } @@ -5071,6 +5079,7 @@ var shouldIgnoreFiber = function(fiber) { case Fragment: case ContextProvider: case ContextConsumer: + case Mode: return true; default: return false; @@ -12747,8 +12756,19 @@ var ReactFiberScheduler = function(config) { } function computeInteractiveExpiration(currentTime) { - // Should complete within ~500ms. 600ms max. - var expirationMs = 500; + var expirationMs = void 0; + // 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. + { + // Should complete within ~500ms. 600ms max. + expirationMs = 500; + } var bucketSizeMs = 100; return computeExpirationBucket(currentTime, expirationMs, bucketSizeMs); } diff --git a/Libraries/Renderer/ReactNativeRenderer-prod.js b/Libraries/Renderer/fb/ReactNativeRenderer-prod.js similarity index 99% rename from Libraries/Renderer/ReactNativeRenderer-prod.js rename to Libraries/Renderer/fb/ReactNativeRenderer-prod.js index 10e7f6b5fc964f..08b70c789b54dd 100644 --- a/Libraries/Renderer/ReactNativeRenderer-prod.js +++ b/Libraries/Renderer/fb/ReactNativeRenderer-prod.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @noflow - * @providesModule ReactNativeRenderer-prod * @preventMunge */ @@ -1172,6 +1171,14 @@ function getComponentName(fiber) { case REACT_RETURN_TYPE: return "ReactReturn"; } + if ("object" === typeof fiber && null !== fiber) + switch (fiber.$$typeof) { + case REACT_FORWARD_REF_TYPE: + return ( + (fiber = fiber.render.displayName || fiber.render.name || ""), + "" !== fiber ? "ForwardRef(" + fiber + ")" : "ForwardRef" + ); + } return null; } function getStackAddendumByWorkInProgressFiber(workInProgress) { @@ -3009,15 +3016,17 @@ function ChildReconciler(shouldTrackSideEffects) { currentFirstChild, newChild, expirationTime - ))) + )), + (currentFirstChild["return"] = returnFiber), + (returnFiber = currentFirstChild)) : (deleteRemainingChildren(returnFiber, currentFirstChild), (currentFirstChild = createFiberFromText( newChild, returnFiber.mode, expirationTime - ))), - (currentFirstChild["return"] = returnFiber), - (returnFiber = currentFirstChild), + )), + (currentFirstChild["return"] = returnFiber), + (returnFiber = currentFirstChild)), placeSingleChild(returnFiber) ); if (isArray$1(newChild)) @@ -5166,7 +5175,7 @@ function ReactFiberScheduler(config) { ? isCommitting ? 1 : nextRenderExpirationTime : fiber.mode & 1 ? isBatchingInteractiveUpdates - ? 10 * ((((recalculateCurrentTime() + 50) / 10) | 0) + 1) + ? 10 * ((((recalculateCurrentTime() + 15) / 10) | 0) + 1) : 25 * ((((recalculateCurrentTime() + 500) / 25) | 0) + 1) : 1; isBatchingInteractiveUpdates && @@ -6375,7 +6384,7 @@ NativeRenderer.injectIntoDevTools({ findFiberByHostInstance: getInstanceFromTag, getInspectorDataForViewTag: getInspectorDataForViewTag, bundleType: 0, - version: "16.3.1", + version: "16.3.2", rendererPackageName: "react-native-renderer" }); var ReactNativeRenderer$2 = Object.freeze({ default: ReactNativeRenderer }), diff --git a/Libraries/Renderer/oss/ReactFabric-dev.js b/Libraries/Renderer/oss/ReactFabric-dev.js new file mode 100644 index 00000000000000..a24f4f6a50dddb --- /dev/null +++ b/Libraries/Renderer/oss/ReactFabric-dev.js @@ -0,0 +1,13863 @@ +/** + * Copyright (c) 2013-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @noflow + * @providesModule ReactFabric-dev + * @preventMunge + */ + +'use strict'; + +if (__DEV__) { + (function() { +"use strict"; + +require("InitializeCore"); +var invariant = require("fbjs/lib/invariant"); +var warning = require("fbjs/lib/warning"); +var emptyFunction = require("fbjs/lib/emptyFunction"); +var ReactNativeViewConfigRegistry = require("ReactNativeViewConfigRegistry"); +var UIManager = require("UIManager"); +var TextInputState = require("TextInputState"); +var deepDiffer = require("deepDiffer"); +var flattenStyle = require("flattenStyle"); +var React = require("react"); +var emptyObject = require("fbjs/lib/emptyObject"); +var shallowEqual = require("fbjs/lib/shallowEqual"); +var checkPropTypes = require("prop-types/checkPropTypes"); +var deepFreezeAndThrowOnMutationInDev = require("deepFreezeAndThrowOnMutationInDev"); +var FabricUIManager = require("FabricUIManager"); + +var invokeGuardedCallback = function(name, func, context, a, b, c, d, e, f) { + this._hasCaughtError = false; + this._caughtError = null; + var funcArgs = Array.prototype.slice.call(arguments, 3); + try { + func.apply(context, funcArgs); + } catch (error) { + this._caughtError = error; + this._hasCaughtError = true; + } +}; + +{ + // 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 + // untintuitive, 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. + invariant( + typeof document !== "undefined", + "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; + + // 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); + 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 onError(event) { + error = event.error; + didSetError = true; + if (error === null && event.colno === 0 && event.lineno === 0) { + isCrossOriginError = true; + } + } + + // Create a fake event type. + var evtType = "react-" + (name ? name : "invokeguardedcallback"); + + // Attach our event handlers + window.addEventListener("error", onError); + 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 (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._hasCaughtError = true; + this._caughtError = error; + } else { + this._hasCaughtError = false; + this._caughtError = null; + } + + // Remove our event listeners + window.removeEventListener("error", onError); + }; + + invokeGuardedCallback = invokeGuardedCallbackDev; + } +} + +var invokeGuardedCallback$1 = invokeGuardedCallback; + +var ReactErrorUtils = { + // Used by Fiber to simulate a try-catch. + _caughtError: null, + _hasCaughtError: false, + + // Used by event system to capture/rethrow the first error. + _rethrowError: null, + _hasRethrowError: false, + + /** + * 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 + */ + invokeGuardedCallback: function(name, func, context, a, b, c, d, e, f) { + invokeGuardedCallback$1.apply(ReactErrorUtils, 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 + */ + invokeGuardedCallbackAndCatchFirstError: function( + name, + func, + context, + a, + b, + c, + d, + e, + f + ) { + ReactErrorUtils.invokeGuardedCallback.apply(this, arguments); + if (ReactErrorUtils.hasCaughtError()) { + var error = ReactErrorUtils.clearCaughtError(); + if (!ReactErrorUtils._hasRethrowError) { + ReactErrorUtils._hasRethrowError = true; + ReactErrorUtils._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. + */ + rethrowCaughtError: function() { + return rethrowCaughtError.apply(ReactErrorUtils, arguments); + }, + + hasCaughtError: function() { + return ReactErrorUtils._hasCaughtError; + }, + + clearCaughtError: function() { + if (ReactErrorUtils._hasCaughtError) { + var error = ReactErrorUtils._caughtError; + ReactErrorUtils._caughtError = null; + ReactErrorUtils._hasCaughtError = false; + return error; + } else { + invariant( + false, + "clearCaughtError was called but no error was captured. This error " + + "is likely caused by a bug in React. Please file an issue." + ); + } + } +}; + +var rethrowCaughtError = function() { + if (ReactErrorUtils._hasRethrowError) { + var error = ReactErrorUtils._rethrowError; + ReactErrorUtils._rethrowError = null; + ReactErrorUtils._hasRethrowError = false; + throw error; + } +}; + +/** + * 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); + invariant( + pluginIndex > -1, + "EventPluginRegistry: Cannot inject event plugins that do not exist in " + + "the plugin ordering, `%s`.", + pluginName + ); + if (plugins[pluginIndex]) { + continue; + } + invariant( + pluginModule.extractEvents, + "EventPluginRegistry: Event plugins must implement an `extractEvents` " + + "method, but `%s` does not.", + pluginName + ); + plugins[pluginIndex] = pluginModule; + var publishedEvents = pluginModule.eventTypes; + for (var eventName in publishedEvents) { + invariant( + publishEventForPlugin( + publishedEvents[eventName], + pluginModule, + eventName + ), + "EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.", + eventName, + 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) { + invariant( + !eventNameDispatchConfigs.hasOwnProperty(eventName), + "EventPluginHub: More than one plugin attempted to publish the same " + + "event name, `%s`.", + 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) { + invariant( + !registrationNameModules[registrationName], + "EventPluginHub: More than one plugin attempted to publish the same " + + "registration name, `%s`.", + 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) { + invariant( + !eventPluginOrder, + "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 + ) { + invariant( + !namesToPlugins[pluginName], + "EventPluginRegistry: Cannot inject two different event plugins " + + "using the same name, `%s`.", + pluginName + ); + namesToPlugins[pluginName] = pluginModule; + isOrderingDirty = true; + } + } + if (isOrderingDirty) { + recomputePluginOrdering(); + } +} + +var getFiberCurrentPropsFromNode = null; +var getInstanceFromNode = null; +var getNodeFromInstance = null; + +var injection$1 = { + injectComponentTree: function(Injected) { + getFiberCurrentPropsFromNode = Injected.getFiberCurrentPropsFromNode; + getInstanceFromNode = Injected.getInstanceFromNode; + getNodeFromInstance = Injected.getNodeFromInstance; + + { + !(getNodeFromInstance && getInstanceFromNode) + ? warning( + false, + "EventPluginUtils.injection.injectComponentTree(...): Injected " + + "module is missing getNodeFromInstance or getInstanceFromNode." + ) + : void 0; + } + } +}; + +function isEndish(topLevelType) { + return ( + topLevelType === "topMouseUp" || + topLevelType === "topTouchEnd" || + topLevelType === "topTouchCancel" + ); +} + +function isMoveish(topLevelType) { + return topLevelType === "topMouseMove" || topLevelType === "topTouchMove"; +} +function isStartish(topLevelType) { + return topLevelType === "topMouseDown" || topLevelType === "topTouchStart"; +} + +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) + ? warning(false, "EventPluginUtils: Invalid `event`.") + : void 0; + }; +} + +/** + * Standard/simple iteration through an event's collected dispatches. + */ + +/** + * 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; + invariant( + !Array.isArray(dispatchListener), + "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) { + invariant( + next != null, + "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); + } +} + +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; + } + invariant( + !listener || typeof listener === "function", + "Expected `%s` listener to be a function, instead got a value of `%s` type.", + registrationName, + typeof listener + ); + return listener; +} + +var IndeterminateComponent = 0; // Before we know whether it is functional or class +var FunctionalComponent = 1; +var ClassComponent = 2; +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 CallComponent = 7; +var CallHandlerPhase = 8; +var ReturnComponent = 9; +var Fragment = 10; +var Mode = 11; +var ContextConsumer = 12; +var ContextProvider = 13; +var ForwardRef = 14; + +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 ? warning(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 didWarnForAddedNewProperty = false; +var EVENT_POOL_SIZE = 10; + +var shouldBeReleasedProperties = [ + "dispatchConfig", + "_targetInst", + "nativeEvent", + "isDefaultPrevented", + "isPropagationStopped", + "_dispatchListeners", + "_dispatchInstances" +]; + +/** + * @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: emptyFunction.thatReturnsNull, + eventPhase: null, + bubbles: null, + cancelable: null, + timeStamp: function(event) { + return event.timeStamp || Date.now(); + }, + defaultPrevented: null, + isTrusted: null +}; + +/** + * 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; + } + + 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 = emptyFunction.thatReturnsTrue; + } else { + this.isDefaultPrevented = emptyFunction.thatReturnsFalse; + } + this.isPropagationStopped = emptyFunction.thatReturnsFalse; + 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 = emptyFunction.thatReturnsTrue; + }, + + 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 = emptyFunction.thatReturnsTrue; + }, + + /** + * 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 = emptyFunction.thatReturnsTrue; + }, + + /** + * Checks if this event should be released back into the pool. + * + * @return {boolean} True if this should not be released, false otherwise. + */ + isPersistent: emptyFunction.thatReturnsFalse, + + /** + * `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]) + ); + } + } + for (var i = 0; i < shouldBeReleasedProperties.length; i++) { + this[shouldBeReleasedProperties[i]] = null; + } + { + Object.defineProperty( + this, + "nativeEvent", + getPooledWarningPropertyDefinition("nativeEvent", null) + ); + Object.defineProperty( + this, + "preventDefault", + getPooledWarningPropertyDefinition("preventDefault", emptyFunction) + ); + Object.defineProperty( + this, + "stopPropagation", + getPooledWarningPropertyDefinition("stopPropagation", emptyFunction) + ); + } + } +}); + +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; +}; + +/** Proxying after everything set on SyntheticEvent + * to resolve Proxy issue on some WebKit browsers + * in which some Event properties are set to undefined (GH#10010) + */ +{ + var isProxySupported = + typeof Proxy === "function" && + // https://github.com/facebook/react/issues/12011 + !Object.isSealed(new Proxy({}, {})); + + if (isProxySupported) { + /*eslint-disable no-func-assign */ + SyntheticEvent = new Proxy(SyntheticEvent, { + construct: function(target, args) { + return this.apply(target, Object.create(target.prototype), args); + }, + apply: function(constructor, that, args) { + return new Proxy(constructor.apply(that, args), { + set: function(target, prop, value) { + if ( + prop !== "isPersistent" && + !target.constructor.Interface.hasOwnProperty(prop) && + shouldBeReleasedProperties.indexOf(prop) === -1 + ) { + !(didWarnForAddedNewProperty || target.isPersistent()) + ? warning( + false, + "This synthetic event is reused for performance reasons. If you're " + + "seeing this, you're adding a new property in the synthetic event object. " + + "The property is never released. See " + + "https://fb.me/react-event-pooling for more information." + ) + : void 0; + didWarnForAddedNewProperty = true; + } + target[prop] = value; + return true; + } + }); + } + }); + /*eslint-enable no-func-assign */ + } +} + +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$$1 + }; + + function set(val) { + var action = isFunction ? "setting the method" : "setting the property"; + warn(action, "This is effectively a no-op"); + return val; + } + + function get$$1() { + 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 + ? warning( + 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; + invariant( + event instanceof EventConstructor, + "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; +} + +var SyntheticEvent$1 = SyntheticEvent; + +/** + * `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$1.extend({ + touchHistory: function(nativeEvent) { + return null; // Actually doesn't even look at the native event. + } +}); + +/** + * 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; + + invariant(identifier != null, "Touch object is missing identifier."); + { + !(identifier <= MAX_TOUCH_BANK) + ? warning( + 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) + ? warning(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) { + invariant( + next != null, + "accumulate(...): Accumulated items must be 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; + +/** + * Last reported number of active touches. + */ +var previousActiveTouches = 0; + +var changeResponder = function(nextResponderInst, blockHostResponder) { + var oldResponderInst = responderInst; + responderInst = nextResponderInst; + if (ResponderEventPlugin.GlobalResponderHandler !== null) { + ResponderEventPlugin.GlobalResponderHandler.onChange( + oldResponderInst, + nextResponderInst, + blockHostResponder + ); + } +}; + +var eventTypes$1 = { + /** + * On a `touchStart`/`mouseDown`, is it desired that this element become the + * responder? + */ + startShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onStartShouldSetResponder", + captured: "onStartShouldSetResponderCapture" + } + }, + + /** + * 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" + } + }, + + /** + * 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" + } + }, + + /** + * On a `touchMove`/`mouseMove`, is it desired that this element become the + * responder? + */ + moveShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onMoveShouldSetResponder", + captured: "onMoveShouldSetResponderCapture" + } + }, + + /** + * Direct responder events dispatched directly to responder. Do not bubble. + */ + responderStart: { registrationName: "onResponderStart" }, + responderMove: { registrationName: "onResponderMove" }, + responderEnd: { registrationName: "onResponderEnd" }, + responderRelease: { registrationName: "onResponderRelease" }, + responderTerminationRequest: { + registrationName: "onResponderTerminationRequest" + }, + responderGrant: { registrationName: "onResponderGrant" }, + responderReject: { registrationName: "onResponderReject" }, + responderTerminate: { registrationName: "onResponderTerminate" } +}; + +/** + * + * 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$1.startShouldSetResponder + : isMoveish(topLevelType) + ? eventTypes$1.moveShouldSetResponder + : topLevelType === "topSelectionChange" + ? eventTypes$1.selectionChangeShouldSetResponder + : eventTypes$1.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$1.responderGrant, + wantsResponderInst, + nativeEvent, + nativeEventTarget + ); + grantEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + + accumulateDirectDispatches(grantEvent); + var blockHostResponder = executeDirectDispatch(grantEvent) === true; + if (responderInst) { + var terminationRequestEvent = ResponderSyntheticEvent.getPooled( + eventTypes$1.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$1.responderTerminate, + responderInst, + nativeEvent, + nativeEventTarget + ); + terminateEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches(terminateEvent); + extracted = accumulate(extracted, [grantEvent, terminateEvent]); + changeResponder(wantsResponderInst, blockHostResponder); + } else { + var rejectEvent = ResponderSyntheticEvent.getPooled( + eventTypes$1.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 === "topScroll" && !nativeEvent.responderIgnoreScroll) || + (trackedTouchCount > 0 && topLevelType === "topSelectionChange") || + 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$1, + + /** + * 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$1.responderStart + : isResponderTouchMove + ? eventTypes$1.responderMove + : isResponderTouchEnd ? eventTypes$1.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 === "topTouchCancel"; + var isResponderRelease = + responderInst && + !isResponderTerminate && + isEndish(topLevelType) && + noResponderTouches(nativeEvent); + var finalTouch = isResponderTerminate + ? eventTypes$1.responderTerminate + : isResponderRelease ? eventTypes$1.responderRelease : null; + if (finalTouch) { + var finalEvent = ResponderSyntheticEvent.getPooled( + finalTouch, + responderInst, + nativeEvent, + nativeEventTarget + ); + finalEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches(finalEvent); + extracted = accumulate(extracted, finalEvent); + changeResponder(null); + } + + var numberActiveTouches = + ResponderTouchHistoryStore.touchHistory.numberActiveTouches; + if ( + ResponderEventPlugin.GlobalInteractionHandler && + numberActiveTouches !== previousActiveTouches + ) { + ResponderEventPlugin.GlobalInteractionHandler.onChange( + numberActiveTouches + ); + } + previousActiveTouches = numberActiveTouches; + + return extracted; + }, + + GlobalResponderHandler: null, + GlobalInteractionHandler: 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; + }, + + /** + * @param {{onChange: (numberActiveTouches) => void} GlobalInteractionHandler + * Object that handles any change in the number of active touches. + */ + injectGlobalInteractionHandler: function(GlobalInteractionHandler) { + ResponderEventPlugin.GlobalInteractionHandler = GlobalInteractionHandler; + } + } +}; + +var customBubblingEventTypes$1 = + ReactNativeViewConfigRegistry.customBubblingEventTypes; +var customDirectEventTypes$1 = + ReactNativeViewConfigRegistry.customDirectEventTypes; +var eventTypes$2 = ReactNativeViewConfigRegistry.eventTypes; + +var ReactNativeBridgeEventPlugin = { + eventTypes: eventTypes$2, + + /** + * @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$1[topLevelType]; + var directDispatchConfig = customDirectEventTypes$1[topLevelType]; + invariant( + bubbleDispatchConfig || directDispatchConfig, + 'Unsupported top level event type "%s" dispatched', + topLevelType + ); + var event = SyntheticEvent$1.getPooled( + bubbleDispatchConfig || directDispatchConfig, + targetInst, + nativeEvent, + nativeEventTarget + ); + if (bubbleDispatchConfig) { + accumulateTwoPhaseDispatches(event); + } else if (directDispatchConfig) { + accumulateDirectDispatches(event); + } else { + return null; + } + return event; + } +}; + +var instanceCache = {}; +var instanceProps = {}; + +function precacheFiberNode(hostInst, tag) { + instanceCache[tag] = hostInst; +} + +function uncacheFiberNode(tag) { + delete instanceCache[tag]; + delete instanceProps[tag]; +} + +function getInstanceFromTag(tag) { + if (typeof tag === "number") { + return instanceCache[tag] || null; + } else { + // Fabric will invoke event emitters on a direct fiber reference + return tag; + } +} + +function getTagFromInstance(inst) { + var tag = inst.stateNode._nativeTag; + if (tag === undefined) { + tag = inst.stateNode.canonical._nativeTag; + } + invariant(tag, "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; +} + +var ReactNativeComponentTree = Object.freeze({ + precacheFiberNode: precacheFiberNode, + uncacheFiberNode: uncacheFiberNode, + getClosestInstanceFromNode: getInstanceFromTag, + getInstanceFromNode: getInstanceFromTag, + getNodeFromInstance: getTagFromInstance, + getFiberCurrentPropsFromNode: getFiberCurrentPropsFromNode$1, + updateFiberProps: updateFiberProps +}); + +var ReactNativeEventPluginOrder = [ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]; + +// Module provided by RN: +var ReactNativeGlobalResponderHandler = { + onChange: function(from, to, blockNativeResponder) { + if (to !== null) { + var tag = to.stateNode._nativeTag; + UIManager.setJSResponder(tag, blockNativeResponder); + } else { + UIManager.clearJSResponder(); + } + } +}; + +/** + * 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); +injection$1.injectComponentTree(ReactNativeComponentTree); + +ResponderEventPlugin.injection.injectGlobalResponderHandler( + ReactNativeGlobalResponderHandler +); + +/** + * Some important event plugins included by default (without having to require + * them). + */ +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin +}); + +// TODO: The event emitter registration is interfering with the existing +// ReactNative renderer. So disable it for Fabric for now. + +// import * as ReactNativeEventEmitter from './ReactNativeEventEmitter'; + +// Module provided by RN: +// import RCTEventEmitter from 'RCTEventEmitter'; + +/** + * Register the event emitter with the native bridge + */ +// RCTEventEmitter.register(ReactNativeEventEmitter); + +// 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_CALL_TYPE = hasSymbol ? Symbol["for"]("react.call") : 0xeac8; +var REACT_RETURN_TYPE = hasSymbol ? Symbol["for"]("react.return") : 0xeac9; +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_PROVIDER_TYPE = hasSymbol ? Symbol["for"]("react.provider") : 0xeacd; +var REACT_CONTEXT_TYPE = hasSymbol ? Symbol["for"]("react.context") : 0xeace; +var REACT_ASYNC_MODE_TYPE = hasSymbol + ? Symbol["for"]("react.async_mode") + : 0xeacf; +var REACT_FORWARD_REF_TYPE = hasSymbol + ? Symbol["for"]("react.forward_ref") + : 0xead0; + +var MAYBE_ITERATOR_SYMBOL = typeof Symbol === "function" && Symbol.iterator; +var FAUX_ITERATOR_SYMBOL = "@@iterator"; + +function getIteratorFn(maybeIterable) { + if (maybeIterable === null || typeof maybeIterable === "undefined") { + return null; + } + var maybeIterator = + (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || + maybeIterable[FAUX_ITERATOR_SYMBOL]; + if (typeof maybeIterator === "function") { + return maybeIterator; + } + return null; +} + +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 + }; +} + +// 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 _batchedUpdates = function(fn, bookkeeping) { + return fn(bookkeeping); +}; +var _interactiveUpdates = function(fn, a, b) { + return fn(a, b); +}; +var _flushInteractiveUpdates = function() {}; + +var injection$2 = { + injectRenderer: function(renderer) { + _batchedUpdates = renderer.batchedUpdates; + _interactiveUpdates = renderer.interactiveUpdates; + _flushInteractiveUpdates = renderer.flushInteractiveUpdates; + } +}; + +// TODO: this is special because it gets imported during build. + +var ReactVersion = "16.3.2"; + +// Modules provided by RN: +var emptyObject$1 = {}; + +/** + * 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 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. + 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. + 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$1, 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$1, + 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(context, callback) { + return function() { + if (!callback) { + return undefined; + } + if (typeof context.__isMounted === "boolean") { + // TODO(gaearon): this is gross and should be removed. + // It is currently necessary because View uses createClass, + // and so any measure() calls on View (which are done by React + // DevTools) trigger the isMounted() deprecation warning. + if (!context.__isMounted) { + return undefined; + } + // The else branch is important so that we don't + // trigger the deprecation warning by calling isMounted. + } else if (typeof context.isMounted === "function") { + if (!context.isMounted()) { + return undefined; + } + } + 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 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) { + UIManager.measure( + findNodeHandle(this), + mountSafeCallback(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) { + UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback(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 */ + ) { + UIManager.measureLayout( + findNodeHandle(this), + relativeToNativeNode, + mountSafeCallback(this, onFail), + mountSafeCallback(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; + } + + var viewConfig = maybeInstance.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) { + UIManager.updateView( + maybeInstance._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() { + TextInputState.focusTextInput(findNodeHandle(this)); + }, + + /** + * Removes focus from an input or view. This is the opposite of `focus()`. + */ + blur: function() { + 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; + invariant( + !NativeMethodsMixin_DEV.componentWillMount && + !NativeMethodsMixin_DEV.componentWillReceiveProps && + !NativeMethodsMixin_DEV.UNSAFE_componentWillMount && + !NativeMethodsMixin_DEV.UNSAFE_componentWillReceiveProps, + "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(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(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() { + TextInputState.blurTextInput(findNodeHandle(this)); + }; + + /** + * Requests focus. The exact behavior depends on the platform and view. + */ + + ReactNativeComponent.prototype.focus = function focus() { + 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) { + UIManager.measure( + findNodeHandle(this), + mountSafeCallback(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 + ) { + UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback(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 */ + ) { + UIManager.measureLayout( + findNodeHandle(this), + relativeToNativeNode, + mountSafeCallback(this, onFail), + mountSafeCallback(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; + } + + 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) { + UIManager.updateView( + maybeInstance._nativeTag, + viewConfig.uiViewClassName, + updatePayload + ); + } + }; + + return ReactNativeComponent; + })(React.Component); + + // eslint-disable-next-line no-unused-expressions + + return ReactNativeComponent; +}; + +var hasNativePerformanceNow = + typeof performance === "object" && typeof performance.now === "function"; + +var now = hasNativePerformanceNow + ? function() { + return performance.now(); + } + : function() { + return Date.now(); + }; + +var scheduledCallback = null; +var frameDeadline = 0; + +var frameDeadlineObject = { + timeRemaining: function() { + return frameDeadline - now(); + }, + didTimeout: false +}; + +function setTimeoutCallback() { + // TODO (bvaughn) Hard-coded 5ms unblocks initial async testing. + // React API probably changing to boolean rather than time remaining. + // Longer-term plan is to rewrite this using shared memory, + // And just return the value of the bit as the boolean. + frameDeadline = now() + 5; + + var callback = scheduledCallback; + scheduledCallback = null; + if (callback !== null) { + callback(frameDeadlineObject); + } +} + +// RN has a poor polyfill for requestIdleCallback so we aren't using it. +// This implementation is only intended for short-term use anyway. +// We also don't implement cancel functionality b'c Fiber doesn't currently need it. +function scheduleDeferredCallback(callback) { + // We assume only one callback is scheduled at a time b'c that's how Fiber works. + scheduledCallback = callback; + return setTimeout(setTimeoutCallback, 1); +} + +function cancelDeferredCallback(callbackID) { + scheduledCallback = null; + clearTimeout(callbackID); +} + +/** + * `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$1(key) { + return key._reactInternalFiber; +} + +function set(key, value) { + key._reactInternalFiber = value; +} + +var ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; + +var ReactCurrentOwner = ReactInternals.ReactCurrentOwner; +var ReactDebugCurrentFrame = ReactInternals.ReactDebugCurrentFrame; + +function getComponentName(fiber) { + var type = fiber.type; + + if (typeof type === "function") { + return type.displayName || type.name; + } + if (typeof type === "string") { + return type; + } + switch (type) { + case REACT_FRAGMENT_TYPE: + return "ReactFragment"; + case REACT_PORTAL_TYPE: + return "ReactPortal"; + case REACT_CALL_TYPE: + return "ReactCall"; + case REACT_RETURN_TYPE: + return "ReactReturn"; + } + if (typeof type === "object" && type !== null) { + switch (type.$$typeof) { + case REACT_FORWARD_REF_TYPE: + var functionName = type.render.displayName || type.render.name || ""; + return functionName !== "" + ? "ForwardRef(" + functionName + ")" + : "ForwardRef"; + } + } + 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 ErrLog = /* */ 256; +var Snapshot = /* */ 2048; + +// Union of all host effects +var HostEffectMask = /* */ 2559; + +var Incomplete = /* */ 512; +var ShouldCapture = /* */ 1024; + +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.current; + if (owner !== null && owner.tag === ClassComponent) { + var ownerFiber = owner; + var instance = ownerFiber.stateNode; + !instance._warnedAboutRefsInRender + ? warning( + 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) || "A component" + ) + : void 0; + instance._warnedAboutRefsInRender = true; + } + } + + var fiber = get$1(component); + if (!fiber) { + return false; + } + return isFiberMountedImpl(fiber) === MOUNTED; +} + +function assertIsMounted(fiber) { + invariant( + isFiberMountedImpl(fiber) === MOUNTED, + "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); + invariant( + state !== UNMOUNTED, + "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"]; + var parentB = parentA ? parentA.alternate : null; + if (!parentA || !parentB) { + // 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. + invariant(false, "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; + } + invariant( + didFindChild, + "Child was not found in either parent set. This indicates a bug " + + "in React related to the return pointer. Please file an issue." + ); + } + } + + invariant( + a.alternate === b, + "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. + invariant( + a.tag === HostRoot, + "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; +} + +function findCurrentHostFiberWithNoPortals(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.tag !== HostPortal) { + 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; +} + +// 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; + +// TODO: Use an opaque type once ESLint et al support the syntax + +var NoWork = 0; +var Sync = 1; +var Never = MAX_SIGNED_31_BIT_INT; + +var UNIT_SIZE = 10; +var MAGIC_NUMBER_OFFSET = 2; + +// 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 ((ms / UNIT_SIZE) | 0) + MAGIC_NUMBER_OFFSET; +} + +function expirationTimeToMs(expirationTime) { + return (expirationTime - MAGIC_NUMBER_OFFSET) * UNIT_SIZE; +} + +function ceiling(num, precision) { + return (((num / precision) | 0) + 1) * precision; +} + +function computeExpirationBucket(currentTime, expirationInMs, bucketSizeMs) { + return ceiling( + currentTime + expirationInMs / UNIT_SIZE, + bucketSizeMs / UNIT_SIZE + ); +} + +var NoContext = 0; +var AsyncMode = 1; +var StrictMode = 2; + +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.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.mode = mode; + + // Effects + this.effectTag = NoEffect; + this.nextEffect = null; + + this.firstEffect = null; + this.lastEffect = null; + + this.expirationTime = NoWork; + + this.alternate = null; + + { + this._debugID = debugCounter++; + this._debugSource = null; + this._debugOwner = null; + this._debugIsCurrentlyTiming = false; + 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) { + return !!(Component.prototype && Component.prototype.isReactComponent); +} + +// 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.type = current.type; + workInProgress.stateNode = current.stateNode; + + { + // DEV-only fields + workInProgress._debugID = current._debugID; + workInProgress._debugSource = current._debugSource; + workInProgress._debugOwner = current._debugOwner; + } + + 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; + } + + workInProgress.expirationTime = expirationTime; + + workInProgress.child = current.child; + workInProgress.memoizedProps = current.memoizedProps; + workInProgress.memoizedState = current.memoizedState; + workInProgress.updateQueue = current.updateQueue; + + // These will be overridden during the parent's reconciliation + workInProgress.sibling = current.sibling; + workInProgress.index = current.index; + workInProgress.ref = current.ref; + + return workInProgress; +} + +function createHostRootFiber(isAsync) { + var mode = isAsync ? AsyncMode | StrictMode : NoContext; + return createFiber(HostRoot, null, null, mode); +} + +function createFiberFromElement(element, mode, expirationTime) { + var owner = null; + { + owner = element._owner; + } + + var fiber = void 0; + var type = element.type; + var key = element.key; + var pendingProps = element.props; + + var fiberTag = void 0; + if (typeof type === "function") { + fiberTag = shouldConstruct(type) ? ClassComponent : IndeterminateComponent; + } else if (typeof type === "string") { + fiberTag = HostComponent; + } else { + switch (type) { + case REACT_FRAGMENT_TYPE: + return createFiberFromFragment( + pendingProps.children, + mode, + expirationTime, + key + ); + case REACT_ASYNC_MODE_TYPE: + fiberTag = Mode; + mode |= AsyncMode | StrictMode; + break; + case REACT_STRICT_MODE_TYPE: + fiberTag = Mode; + mode |= StrictMode; + break; + case REACT_CALL_TYPE: + fiberTag = CallComponent; + break; + case REACT_RETURN_TYPE: + fiberTag = ReturnComponent; + break; + default: { + if (typeof type === "object" && type !== null) { + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + fiberTag = ContextProvider; + break; + case REACT_CONTEXT_TYPE: + // This is a consumer + fiberTag = ContextConsumer; + break; + case REACT_FORWARD_REF_TYPE: + fiberTag = ForwardRef; + break; + default: + if (typeof type.tag === "number") { + // Currently assumed to be a continuation and therefore is a + // fiber already. + // TODO: The yield system is currently broken for updates in + // some cases. The reified yield stores a fiber, but we don't + // know which fiber that is; the current or a workInProgress? + // When the continuation gets rendered here we don't know if we + // can reuse that fiber or if we need to clone it. There is + // probably a clever way to restructure this. + fiber = type; + fiber.pendingProps = pendingProps; + fiber.expirationTime = expirationTime; + return fiber; + } else { + throwOnInvalidElementType(type, owner); + } + break; + } + } else { + throwOnInvalidElementType(type, owner); + } + } + } + } + + fiber = createFiber(fiberTag, pendingProps, key, mode); + fiber.type = type; + fiber.expirationTime = expirationTime; + + { + fiber._debugSource = element._source; + fiber._debugOwner = element._owner; + } + + return fiber; +} + +function throwOnInvalidElementType(type, owner) { + 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) : null; + if (ownerName) { + info += "\n\nCheck the render method of `" + ownerName + "`."; + } + } + invariant( + false, + "Element type is invalid: expected a string (for built-in " + + "components) or a class/function (for composite components) " + + "but got: %s.%s", + type == null ? type : typeof type, + info + ); +} + +function createFiberFromFragment(elements, mode, expirationTime, key) { + var fiber = createFiber(Fragment, elements, key, mode); + 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); + 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.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.mode = source.mode; + target.effectTag = source.effectTag; + target.nextEffect = source.nextEffect; + target.firstEffect = source.firstEffect; + target.lastEffect = source.lastEffect; + target.expirationTime = source.expirationTime; + target.alternate = source.alternate; + target._debugID = source._debugID; + target._debugSource = source._debugSource; + target._debugOwner = source._debugOwner; + target._debugIsCurrentlyTiming = source._debugIsCurrentlyTiming; + return target; +} + +// TODO: This should be lifted into the renderer. + +function createFiberRoot(containerInfo, isAsync, hydrate) { + // Cyclic construction. This cheats the type system right now because + // stateNode is any. + var uninitializedFiber = createHostRootFiber(isAsync); + var root = { + current: uninitializedFiber, + containerInfo: containerInfo, + pendingChildren: null, + pendingCommitExpirationTime: NoWork, + finishedWork: null, + context: null, + pendingContext: null, + hydrate: hydrate, + remainingExpirationTime: NoWork, + firstBatch: null, + nextScheduledRoot: null + }; + uninitializedFiber.stateNode = root; + return root; +} + +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; + warning(false, "React DevTools encountered an error: %s", err); + } + } + }; +} + +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) { + { + warning( + 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. + { + warning(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); + } +} + +var describeComponentFrame = function(name, source, ownerName) { + return ( + "\n in " + + (name || "Unknown") + + (source + ? " (at " + + source.fileName.replace(/^.*[\\\/]/, "") + + ":" + + source.lineNumber + + ")" + : ownerName ? " (created by " + ownerName + ")" : "") + ); +}; + +function describeFiber(fiber) { + switch (fiber.tag) { + case IndeterminateComponent: + case FunctionalComponent: + case ClassComponent: + case HostComponent: + var owner = fiber._debugOwner; + var source = fiber._debugSource; + var name = getComponentName(fiber); + var ownerName = null; + if (owner) { + ownerName = getComponentName(owner); + } + return describeComponentFrame(name, source, ownerName); + default: + return ""; + } +} + +// This function can only be called with a work-in-progress fiber and +// only during begin or complete phase. Do not call it under any other +// circumstances. +function getStackAddendumByWorkInProgressFiber(workInProgress) { + var info = ""; + var node = workInProgress; + do { + info += describeFiber(node); + // Otherwise this return pointer might point to the wrong tree: + node = node["return"]; + } while (node); + return info; +} + +/** + * 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( + "`warning(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) {} +}; + +{ + var LIFECYCLE_SUGGESTIONS = { + UNSAFE_componentWillMount: "componentDidMount", + UNSAFE_componentWillReceiveProps: "static getDerivedStateFromProps", + UNSAFE_componentWillUpdate: "componentDidUpdate" + }; + + var pendingComponentWillMountWarnings = []; + var pendingComponentWillReceivePropsWarnings = []; + var pendingComponentWillUpdateWarnings = []; + var pendingUnsafeLifecycleWarnings = new Map(); + + // Tracks components we have already warned about. + var didWarnAboutDeprecatedLifecycles = new Set(); + var didWarnAboutUnsafeLifecycles = 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(); + }; + + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = function() { + pendingUnsafeLifecycleWarnings.forEach(function( + lifecycleWarningsMap, + strictRoot + ) { + var lifecyclesWarningMesages = []; + + 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) || "Component"); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + + var formatted = lifecycle.replace("UNSAFE_", ""); + var suggestion = LIFECYCLE_SUGGESTIONS[lifecycle]; + var sortedComponentNames = setToSortedString(componentNames); + + lifecyclesWarningMesages.push( + formatted + + ": Please update the following components to use " + + (suggestion + " instead: " + sortedComponentNames) + ); + } + }); + + if (lifecyclesWarningMesages.length > 0) { + var strictRootComponentStack = getStackAddendumByWorkInProgressFiber( + strictRoot + ); + + warning( + 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, + lifecyclesWarningMesages.join("\n\n") + ); + } + }); + + pendingUnsafeLifecycleWarnings = new Map(); + }; + + var getStrictRoot = function(fiber) { + var maybeStrictRoot = null; + + while (fiber !== null) { + if (fiber.mode & StrictMode) { + maybeStrictRoot = fiber; + } + + fiber = fiber["return"]; + } + + return maybeStrictRoot; + }; + + ReactStrictModeWarnings.flushPendingDeprecationWarnings = function() { + if (pendingComponentWillMountWarnings.length > 0) { + var uniqueNames = new Set(); + pendingComponentWillMountWarnings.forEach(function(fiber) { + uniqueNames.add(getComponentName(fiber) || "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) || "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) || "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 = getStrictRoot(fiber); + + // 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; + } + + // Don't warn about react-lifecycles-compat polyfilled components. + // Note that it is sufficient to check for the presence of a + // single lifecycle, componentWillMount, with the polyfill flag. + if ( + typeof instance.componentWillMount === "function" && + instance.componentWillMount.__suppressDeprecationWarning === true + ) { + 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" || + typeof instance.UNSAFE_componentWillMount === "function" + ) { + unsafeLifecycles.push("UNSAFE_componentWillMount"); + } + if ( + typeof instance.componentWillReceiveProps === "function" || + typeof instance.UNSAFE_componentWillReceiveProps === "function" + ) { + unsafeLifecycles.push("UNSAFE_componentWillReceiveProps"); + } + if ( + typeof instance.componentWillUpdate === "function" || + typeof instance.UNSAFE_componentWillUpdate === "function" + ) { + unsafeLifecycles.push("UNSAFE_componentWillUpdate"); + } + + if (unsafeLifecycles.length > 0) { + unsafeLifecycles.forEach(function(lifecycle) { + warningsForRoot[lifecycle].push(fiber); + }); + } + }; +} + +var debugRenderPhaseSideEffects = false; +var debugRenderPhaseSideEffectsForStrictMode = false; +var enableUserTimingAPI = true; +var enableGetDerivedStateFromCatch = false; +var warnAboutDeprecatedLifecycles = false; +var replayFailedUnitOfWorkWithInvokeGuardedCallback = true; + +// React Fabric uses persistent reconciler. +var enableMutatingReconciler = false; +var enableNoopReconciler = false; +var enablePersistentReconciler = true; + +// Only used in www builds. + +function getCurrentFiberOwnerName() { + { + var fiber = ReactDebugCurrentFiber.current; + if (fiber === null) { + return null; + } + var owner = fiber._debugOwner; + if (owner !== null && typeof owner !== "undefined") { + return getComponentName(owner); + } + } + return null; +} + +function getCurrentFiberStackAddendum() { + { + var fiber = ReactDebugCurrentFiber.current; + if (fiber === null) { + return null; + } + // Safe because if current fiber exists, we are reconciling, + // and it is guaranteed to be the work-in-progress version. + return getStackAddendumByWorkInProgressFiber(fiber); + } + return null; +} + +function resetCurrentFiber() { + ReactDebugCurrentFrame.getCurrentStack = null; + ReactDebugCurrentFiber.current = null; + ReactDebugCurrentFiber.phase = null; +} + +function setCurrentFiber(fiber) { + ReactDebugCurrentFrame.getCurrentStack = getCurrentFiberStackAddendum; + ReactDebugCurrentFiber.current = fiber; + ReactDebugCurrentFiber.phase = null; +} + +function setCurrentPhase(phase) { + ReactDebugCurrentFiber.phase = phase; +} + +var ReactDebugCurrentFiber = { + current: null, + phase: null, + resetCurrentFiber: resetCurrentFiber, + setCurrentFiber: setCurrentFiber, + setCurrentPhase: setCurrentPhase, + getCurrentFiberOwnerName: getCurrentFiberOwnerName, + getCurrentFiberStackAddendum: getCurrentFiberStackAddendum +}; + +// 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$$1) { + var prefix = warning$$1 ? warningEmoji + " " : reactEmoji + " "; + var suffix = warning$$1 ? " Warning: " + warning$$1 : ""; + 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$$1) { + var formattedMarkName = formatMarkName(markName); + var formattedLabel = formatLabel(label, warning$$1); + 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) || "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) || "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$$1) { + var componentName = getComponentName(fiber) || "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$$1); +}; + +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 CallComponent: + case ReturnComponent: + 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, expirationTime) { + if (enableUserTimingAPI) { + if (supportsUserTiming) { + isWaitingForCallback = false; + var warning$$1 = didExpire ? "React was blocked by main thread" : null; + endMark( + "(Waiting for async callback... will force flush in " + + expirationTime + + " ms)", + "(Waiting for async callback...)", + warning$$1 + ); + } + } +} + +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$$1 = "An error was thrown inside this error boundary"; + endFiberMark(fiber, null, warning$$1); + } +} + +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$$1 = hasScheduledUpdateInCurrentPhase + ? "Scheduled a cascading update" + : null; + endFiberMark(currentPhaseFiber, currentPhase, warning$$1); + } + 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$$1 = null; + if (interruptedBy !== null) { + if (interruptedBy.tag === HostRoot) { + warning$$1 = "A top-level update interrupted the previous render"; + } else { + var componentName = getComponentName(interruptedBy) || "Unknown"; + warning$$1 = + "An update to " + componentName + " interrupted the previous render"; + } + } else if (commitCountInCurrentWorkLoop > 1) { + warning$$1 = "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$$1); + } +} + +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$$1 = null; + if (hasScheduledUpdateInCurrentCommit) { + warning$$1 = "Lifecycle hook scheduled a cascading update"; + } else if (commitCountInCurrentWorkLoop > 0) { + warning$$1 = "Caused by a cascading update in earlier commit"; + } + hasScheduledUpdateInCurrentCommit = false; + commitCountInCurrentWorkLoop++; + isCommitting = false; + labelsInCurrentCommit.clear(); + + endMark("(Committing Changes)", "(Committing Changes)", warning$$1); + } +} + +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 didWarnUpdateInsideUpdate = void 0; + +{ + didWarnUpdateInsideUpdate = false; +} + +// Callbacks are not validated until invocation + +// Singly linked-list of updates. When an update is scheduled, it is added to +// the queue of the current fiber and the work-in-progress fiber. The two queues +// are separate but they share a persistent structure. +// +// During reconciliation, updates are removed from the work-in-progress fiber, +// but they remain on the current fiber. That ensures that if a work-in-progress +// is aborted, the aborted updates are recovered by cloning from current. +// +// The work-in-progress queue is always a subset of the current queue. +// +// When the tree is committed, the work-in-progress becomes the current. + +function createUpdateQueue(baseState) { + var queue = { + baseState: baseState, + expirationTime: NoWork, + first: null, + last: null, + callbackList: null, + hasForceUpdate: false, + isInitialized: false, + capturedValues: null + }; + { + queue.isProcessing = false; + } + return queue; +} + +function insertUpdateIntoQueue(queue, update) { + // Append the update to the end of the list. + if (queue.last === null) { + // Queue is empty + queue.first = queue.last = update; + } else { + queue.last.next = update; + queue.last = update; + } + if ( + queue.expirationTime === NoWork || + queue.expirationTime > update.expirationTime + ) { + queue.expirationTime = update.expirationTime; + } +} + +var q1 = void 0; +var q2 = void 0; +function ensureUpdateQueues(fiber) { + q1 = q2 = null; + // We'll have at least one and at most two distinct update queues. + var alternateFiber = fiber.alternate; + var queue1 = fiber.updateQueue; + if (queue1 === null) { + // TODO: We don't know what the base state will be until we begin work. + // It depends on which fiber is the next current. Initialize with an empty + // base state, then set to the memoizedState when rendering. Not super + // happy with this approach. + queue1 = fiber.updateQueue = createUpdateQueue(null); + } + + var queue2 = void 0; + if (alternateFiber !== null) { + queue2 = alternateFiber.updateQueue; + if (queue2 === null) { + queue2 = alternateFiber.updateQueue = createUpdateQueue(null); + } + } else { + queue2 = null; + } + queue2 = queue2 !== queue1 ? queue2 : null; + + // Use module variables instead of returning a tuple + q1 = queue1; + q2 = queue2; +} + +function insertUpdateIntoFiber(fiber, update) { + ensureUpdateQueues(fiber); + var queue1 = q1; + var queue2 = q2; + + // Warn if an update is scheduled from inside an updater function. + { + if ( + (queue1.isProcessing || (queue2 !== null && queue2.isProcessing)) && + !didWarnUpdateInsideUpdate + ) { + warning( + 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; + } + } + + // If there's only one queue, add the update to that queue and exit. + if (queue2 === null) { + insertUpdateIntoQueue(queue1, update); + return; + } + + // If either queue is empty, we need to add to both queues. + if (queue1.last === null || queue2.last === null) { + insertUpdateIntoQueue(queue1, update); + insertUpdateIntoQueue(queue2, update); + return; + } + + // If both lists are not empty, the last update is the same for both lists + // because of structural sharing. So, we should only append to one of + // the lists. + insertUpdateIntoQueue(queue1, update); + // But we still need to update the `last` pointer of queue2. + queue2.last = update; +} + +function getUpdateExpirationTime(fiber) { + switch (fiber.tag) { + case HostRoot: + case ClassComponent: + var updateQueue = fiber.updateQueue; + if (updateQueue === null) { + return NoWork; + } + return updateQueue.expirationTime; + default: + return NoWork; + } +} + +function getStateFromUpdate(update, instance, prevState, props) { + var partialState = update.partialState; + if (typeof partialState === "function") { + return partialState.call(instance, prevState, props); + } else { + return partialState; + } +} + +function processUpdateQueue( + current, + workInProgress, + queue, + instance, + props, + renderExpirationTime +) { + if (current !== null && current.updateQueue === queue) { + // We need to create a work-in-progress queue, by cloning the current queue. + var currentQueue = queue; + queue = workInProgress.updateQueue = { + baseState: currentQueue.baseState, + expirationTime: currentQueue.expirationTime, + first: currentQueue.first, + last: currentQueue.last, + isInitialized: currentQueue.isInitialized, + capturedValues: currentQueue.capturedValues, + // These fields are no longer valid because they were already committed. + // Reset them. + callbackList: null, + hasForceUpdate: false + }; + } + + { + // Set this flag so we can warn if setState is called inside the update + // function of another setState. + queue.isProcessing = true; + } + + // Reset the remaining expiration time. If we skip over any updates, we'll + // increase this accordingly. + queue.expirationTime = NoWork; + + // TODO: We don't know what the base state will be until we begin work. + // It depends on which fiber is the next current. Initialize with an empty + // base state, then set to the memoizedState when rendering. Not super + // happy with this approach. + var state = void 0; + if (queue.isInitialized) { + state = queue.baseState; + } else { + state = queue.baseState = workInProgress.memoizedState; + queue.isInitialized = true; + } + var dontMutatePrevState = true; + var update = queue.first; + var didSkip = false; + while (update !== null) { + var updateExpirationTime = update.expirationTime; + if (updateExpirationTime > renderExpirationTime) { + // This update does not have sufficient priority. Skip it. + var remainingExpirationTime = queue.expirationTime; + if ( + remainingExpirationTime === NoWork || + remainingExpirationTime > updateExpirationTime + ) { + // Update the remaining expiration time. + queue.expirationTime = updateExpirationTime; + } + if (!didSkip) { + didSkip = true; + queue.baseState = state; + } + // Continue to the next update. + update = update.next; + continue; + } + + // This update does have sufficient priority. + + // If no previous updates were skipped, drop this update from the queue by + // advancing the head of the list. + if (!didSkip) { + queue.first = update.next; + if (queue.first === null) { + queue.last = null; + } + } + + // Invoke setState callback an extra time to help detect side-effects. + // Ignore the return value in this case. + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + getStateFromUpdate(update, instance, state, props); + } + + // Process the update + var _partialState = void 0; + if (update.isReplace) { + state = getStateFromUpdate(update, instance, state, props); + dontMutatePrevState = true; + } else { + _partialState = getStateFromUpdate(update, instance, state, props); + if (_partialState) { + if (dontMutatePrevState) { + // $FlowFixMe: Idk how to type this properly. + state = Object.assign({}, state, _partialState); + } else { + state = Object.assign(state, _partialState); + } + dontMutatePrevState = false; + } + } + if (update.isForced) { + queue.hasForceUpdate = true; + } + if (update.callback !== null) { + // Append to list of callbacks. + var _callbackList = queue.callbackList; + if (_callbackList === null) { + _callbackList = queue.callbackList = []; + } + _callbackList.push(update); + } + if (update.capturedValue !== null) { + var _capturedValues = queue.capturedValues; + if (_capturedValues === null) { + queue.capturedValues = [update.capturedValue]; + } else { + _capturedValues.push(update.capturedValue); + } + } + update = update.next; + } + + if (queue.callbackList !== null) { + workInProgress.effectTag |= Callback; + } else if ( + queue.first === null && + !queue.hasForceUpdate && + queue.capturedValues === null + ) { + // The queue is empty. We can reset it. + workInProgress.updateQueue = null; + } + + if (!didSkip) { + didSkip = true; + queue.baseState = state; + } + + { + // No longer processing. + queue.isProcessing = false; + } + + return state; +} + +function commitCallbacks(queue, context) { + var callbackList = queue.callbackList; + if (callbackList === null) { + return; + } + // Set the list to null to make sure they don't get called more than once. + queue.callbackList = null; + for (var i = 0; i < callbackList.length; i++) { + var update = callbackList[i]; + var _callback = update.callback; + // This update might be processed again. Clear the callback so it's only + // called once. + update.callback = null; + invariant( + typeof _callback === "function", + "Invalid argument passed as callback. Expected a function. Instead " + + "received: %s", + _callback + ); + _callback.call(context); + } +} + +var fakeInternalInstance = {}; +var isArray = Array.isArray; + +var didWarnAboutStateAssignmentForComponent = void 0; +var didWarnAboutUndefinedDerivedState = void 0; +var didWarnAboutUninitializedState = void 0; +var didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = void 0; +var didWarnAboutLegacyLifecyclesAndDerivedState = void 0; +var warnOnInvalidCallback = void 0; + +{ + didWarnAboutStateAssignmentForComponent = new Set(); + didWarnAboutUndefinedDerivedState = new Set(); + didWarnAboutUninitializedState = new Set(); + didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = new Set(); + didWarnAboutLegacyLifecyclesAndDerivedState = 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); + warning( + false, + "%s(...): Expected the last optional `callback` argument to be a " + + "function. Instead received: %s.", + callerName, + callback + ); + } + }; + + // 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() { + invariant( + false, + "_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 callGetDerivedStateFromCatch(ctor, capturedValues) { + var resultState = {}; + for (var i = 0; i < capturedValues.length; i++) { + var capturedValue = capturedValues[i]; + var error = capturedValue.value; + var partialState = ctor.getDerivedStateFromCatch.call(null, error); + if (partialState !== null && partialState !== undefined) { + Object.assign(resultState, partialState); + } + } + return resultState; +} + +var ReactFiberClassComponent = function( + legacyContext, + scheduleWork, + computeExpirationForFiber, + memoizeProps, + memoizeState +) { + var cacheContext = legacyContext.cacheContext, + getMaskedContext = legacyContext.getMaskedContext, + getUnmaskedContext = legacyContext.getUnmaskedContext, + isContextConsumer = legacyContext.isContextConsumer, + hasContextChanged = legacyContext.hasContextChanged; + + // Class component state updater + + var updater = { + isMounted: isMounted, + enqueueSetState: function(instance, partialState, callback) { + var fiber = get$1(instance); + callback = callback === undefined ? null : callback; + { + warnOnInvalidCallback(callback, "setState"); + } + var expirationTime = computeExpirationForFiber(fiber); + var update = { + expirationTime: expirationTime, + partialState: partialState, + callback: callback, + isReplace: false, + isForced: false, + capturedValue: null, + next: null + }; + insertUpdateIntoFiber(fiber, update); + scheduleWork(fiber, expirationTime); + }, + enqueueReplaceState: function(instance, state, callback) { + var fiber = get$1(instance); + callback = callback === undefined ? null : callback; + { + warnOnInvalidCallback(callback, "replaceState"); + } + var expirationTime = computeExpirationForFiber(fiber); + var update = { + expirationTime: expirationTime, + partialState: state, + callback: callback, + isReplace: true, + isForced: false, + capturedValue: null, + next: null + }; + insertUpdateIntoFiber(fiber, update); + scheduleWork(fiber, expirationTime); + }, + enqueueForceUpdate: function(instance, callback) { + var fiber = get$1(instance); + callback = callback === undefined ? null : callback; + { + warnOnInvalidCallback(callback, "forceUpdate"); + } + var expirationTime = computeExpirationForFiber(fiber); + var update = { + expirationTime: expirationTime, + partialState: null, + callback: callback, + isReplace: false, + isForced: true, + capturedValue: null, + next: null + }; + insertUpdateIntoFiber(fiber, update); + scheduleWork(fiber, expirationTime); + } + }; + + function checkShouldComponentUpdate( + workInProgress, + oldProps, + newProps, + oldState, + newState, + newContext + ) { + if ( + oldProps === null || + (workInProgress.updateQueue !== null && + workInProgress.updateQueue.hasForceUpdate) + ) { + // If the workInProgress already has an Update effect, return true + return true; + } + + var instance = workInProgress.stateNode; + var ctor = workInProgress.type; + if (typeof instance.shouldComponentUpdate === "function") { + startPhaseTimer(workInProgress, "shouldComponentUpdate"); + var shouldUpdate = instance.shouldComponentUpdate( + newProps, + newState, + newContext + ); + stopPhaseTimer(); + + { + !(shouldUpdate !== undefined) + ? warning( + false, + "%s.shouldComponentUpdate(): Returned undefined instead of a " + + "boolean value. Make sure to return true or false.", + getComponentName(workInProgress) || "Component" + ) + : void 0; + } + + return shouldUpdate; + } + + if (ctor.prototype && ctor.prototype.isPureReactComponent) { + return ( + !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) + ); + } + + return true; + } + + function checkClassInstance(workInProgress) { + var instance = workInProgress.stateNode; + var type = workInProgress.type; + { + var name = getComponentName(workInProgress) || "Component"; + var renderPresent = instance.render; + + if (!renderPresent) { + if (type.prototype && typeof type.prototype.render === "function") { + warning( + false, + "%s(...): No `render` method found on the returned component " + + "instance: did you accidentally return an object from the constructor?", + name + ); + } else { + warning( + 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 + ? warning( + 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 + ? warning( + 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 + ? warning( + false, + "propTypes was defined as an instance property on %s. Use a static " + + "property to define propTypes instead.", + name + ) + : void 0; + var noInstanceContextTypes = !instance.contextTypes; + !noInstanceContextTypes + ? warning( + false, + "contextTypes was defined as an instance property on %s. Use a static " + + "property to define contextTypes instead.", + name + ) + : void 0; + var noComponentShouldUpdate = + typeof instance.componentShouldUpdate !== "function"; + !noComponentShouldUpdate + ? warning( + 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 ( + type.prototype && + type.prototype.isPureReactComponent && + typeof instance.shouldComponentUpdate !== "undefined" + ) { + warning( + 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(workInProgress) || "A pure component" + ); + } + var noComponentDidUnmount = + typeof instance.componentDidUnmount !== "function"; + !noComponentDidUnmount + ? warning( + 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 + ? warning( + 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 + ? warning( + false, + "%s has a method called " + + "componentWillRecieveProps(). Did you mean componentWillReceiveProps()?", + name + ) + : void 0; + var noUnsafeComponentWillRecieveProps = + typeof instance.UNSAFE_componentWillRecieveProps !== "function"; + !noUnsafeComponentWillRecieveProps + ? warning( + false, + "%s has a method called " + + "UNSAFE_componentWillRecieveProps(). Did you mean UNSAFE_componentWillReceiveProps()?", + name + ) + : void 0; + var hasMutatedProps = instance.props !== workInProgress.pendingProps; + !(instance.props === undefined || !hasMutatedProps) + ? warning( + 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 + ? warning( + 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(type) + ) { + didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.add(type); + warning( + false, + "%s: getSnapshotBeforeUpdate() should be used with componentDidUpdate(). " + + "This component defines getSnapshotBeforeUpdate() only.", + getComponentName(workInProgress) + ); + } + + var noInstanceGetDerivedStateFromProps = + typeof instance.getDerivedStateFromProps !== "function"; + !noInstanceGetDerivedStateFromProps + ? warning( + 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.getDerivedStateFromCatch !== "function"; + !noInstanceGetDerivedStateFromCatch + ? warning( + false, + "%s: getDerivedStateFromCatch() is defined as an instance method " + + "and will be ignored. Instead, declare it as a static method.", + name + ) + : void 0; + var noStaticGetSnapshotBeforeUpdate = + typeof type.getSnapshotBeforeUpdate !== "function"; + !noStaticGetSnapshotBeforeUpdate + ? warning( + 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(_state))) { + warning(false, "%s.state: must be set to an object or null", name); + } + if (typeof instance.getChildContext === "function") { + !(typeof type.childContextTypes === "object") + ? warning( + false, + "%s.getChildContext(): childContextTypes must be defined in order to " + + "use getChildContext().", + name + ) + : void 0; + } + } + } + + function resetInputPointers(workInProgress, instance) { + instance.props = workInProgress.memoizedProps; + instance.state = workInProgress.memoizedState; + } + + function adoptClassInstance(workInProgress, instance) { + instance.updater = updater; + 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, props) { + var ctor = workInProgress.type; + var unmaskedContext = getUnmaskedContext(workInProgress); + var needsContext = isContextConsumer(workInProgress); + var context = needsContext + ? getMaskedContext(workInProgress, unmaskedContext) + : emptyObject; + + // 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 = + instance.state !== null && instance.state !== undefined + ? instance.state + : null; + adoptClassInstance(workInProgress, instance); + + { + if ( + typeof ctor.getDerivedStateFromProps === "function" && + state === null + ) { + var componentName = getComponentName(workInProgress) || "Component"; + if (!didWarnAboutUninitializedState.has(componentName)) { + didWarnAboutUninitializedState.add(componentName); + warning( + false, + "%s: Did not properly initialize state during construction. " + + "Expected state to be an object, but it was %s.", + componentName, + instance.state === null ? "null" : "undefined" + ); + } + } + + // 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(workInProgress) || "Component"; + var newApiName = + typeof ctor.getDerivedStateFromProps === "function" + ? "getDerivedStateFromProps()" + : "getSnapshotBeforeUpdate()"; + if ( + !didWarnAboutLegacyLifecyclesAndDerivedState.has(_componentName) + ) { + didWarnAboutLegacyLifecyclesAndDerivedState.add(_componentName); + warning( + 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 : "" + ); + } + } + } + } + + workInProgress.memoizedState = state; + + var partialState = callGetDerivedStateFromProps( + workInProgress, + instance, + props, + state + ); + + if (partialState !== null && partialState !== undefined) { + // Render-phase updates (like this) should not be added to the update queue, + // So that multiple render passes do not enqueue multiple updates. + // Instead, just synchronously merge the returned state into the instance. + workInProgress.memoizedState = Object.assign( + {}, + workInProgress.memoizedState, + partialState + ); + } + + // 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 (needsContext) { + 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) { + { + warning( + false, + "%s.componentWillMount(): Assigning directly to this.state is " + + "deprecated (except inside a component's " + + "constructor). Use setState instead.", + getComponentName(workInProgress) || "Component" + ); + } + updater.enqueueReplaceState(instance, instance.state, null); + } + } + + function callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + newContext + ) { + var oldState = instance.state; + startPhaseTimer(workInProgress, "componentWillReceiveProps"); + if (typeof instance.componentWillReceiveProps === "function") { + instance.componentWillReceiveProps(newProps, newContext); + } + if (typeof instance.UNSAFE_componentWillReceiveProps === "function") { + instance.UNSAFE_componentWillReceiveProps(newProps, newContext); + } + stopPhaseTimer(); + + if (instance.state !== oldState) { + { + var componentName = getComponentName(workInProgress) || "Component"; + if (!didWarnAboutStateAssignmentForComponent.has(componentName)) { + didWarnAboutStateAssignmentForComponent.add(componentName); + warning( + false, + "%s.componentWillReceiveProps(): Assigning directly to " + + "this.state is deprecated (except inside a component's " + + "constructor). Use setState instead.", + componentName + ); + } + } + updater.enqueueReplaceState(instance, instance.state, null); + } + } + + function callGetDerivedStateFromProps( + workInProgress, + instance, + nextProps, + prevState + ) { + var type = workInProgress.type; + + if (typeof type.getDerivedStateFromProps === "function") { + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + // Invoke method an extra time to help detect side-effects. + type.getDerivedStateFromProps.call(null, nextProps, prevState); + } + + var partialState = type.getDerivedStateFromProps.call( + null, + nextProps, + prevState + ); + + { + if (partialState === undefined) { + var componentName = getComponentName(workInProgress) || "Component"; + if (!didWarnAboutUndefinedDerivedState.has(componentName)) { + didWarnAboutUndefinedDerivedState.add(componentName); + warning( + false, + "%s.getDerivedStateFromProps(): A valid state object (or null) must be returned. " + + "You have returned undefined.", + componentName + ); + } + } + } + + return partialState; + } + } + + // Invokes the mount life-cycles on a previously never rendered instance. + function mountClassInstance(workInProgress, renderExpirationTime) { + var ctor = workInProgress.type; + var current = workInProgress.alternate; + + { + checkClassInstance(workInProgress); + } + + var instance = workInProgress.stateNode; + var props = workInProgress.pendingProps; + var unmaskedContext = getUnmaskedContext(workInProgress); + + instance.props = props; + instance.state = workInProgress.memoizedState; + instance.refs = emptyObject; + instance.context = getMaskedContext(workInProgress, unmaskedContext); + + { + if (workInProgress.mode & StrictMode) { + ReactStrictModeWarnings.recordUnsafeLifecycleWarnings( + workInProgress, + instance + ); + } + + if (warnAboutDeprecatedLifecycles) { + ReactStrictModeWarnings.recordDeprecationWarnings( + workInProgress, + instance + ); + } + } + + // 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. + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + instance.state = processUpdateQueue( + current, + workInProgress, + updateQueue, + instance, + props, + renderExpirationTime + ); + } + } + if (typeof instance.componentDidMount === "function") { + workInProgress.effectTag |= Update; + } + } + + function resumeMountClassInstance(workInProgress, renderExpirationTime) { + var ctor = workInProgress.type; + var instance = workInProgress.stateNode; + resetInputPointers(workInProgress, instance); + + var oldProps = workInProgress.memoizedProps; + var newProps = workInProgress.pendingProps; + var oldContext = instance.context; + var newUnmaskedContext = getUnmaskedContext(workInProgress); + var newContext = getMaskedContext(workInProgress, newUnmaskedContext); + + var hasNewLifecycles = + typeof ctor.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 !== newContext) { + callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + newContext + ); + } + } + + // Compute the next state using the memoized state and the update queue. + var oldState = workInProgress.memoizedState; + // TODO: Previous state can be null. + var newState = void 0; + var derivedStateFromCatch = void 0; + if (workInProgress.updateQueue !== null) { + newState = processUpdateQueue( + null, + workInProgress, + workInProgress.updateQueue, + instance, + newProps, + renderExpirationTime + ); + + var updateQueue = workInProgress.updateQueue; + if ( + updateQueue !== null && + updateQueue.capturedValues !== null && + enableGetDerivedStateFromCatch && + typeof ctor.getDerivedStateFromCatch === "function" + ) { + var capturedValues = updateQueue.capturedValues; + // Don't remove these from the update queue yet. We need them in + // finishClassComponent. Do the reset there. + // TODO: This is awkward. Refactor class components. + // updateQueue.capturedValues = null; + derivedStateFromCatch = callGetDerivedStateFromCatch( + ctor, + capturedValues + ); + } + } else { + newState = oldState; + } + + var derivedStateFromProps = void 0; + if (oldProps !== newProps) { + // The prevState parameter should be the partially updated state. + // Otherwise, spreading state in return values could override updates. + derivedStateFromProps = callGetDerivedStateFromProps( + workInProgress, + instance, + newProps, + newState + ); + } + + if (derivedStateFromProps !== null && derivedStateFromProps !== undefined) { + // Render-phase updates (like this) should not be added to the update queue, + // So that multiple render passes do not enqueue multiple updates. + // Instead, just synchronously merge the returned state into the instance. + newState = + newState === null || newState === undefined + ? derivedStateFromProps + : Object.assign({}, newState, derivedStateFromProps); + + // Update the base state of the update queue. + // FIXME: This is getting ridiculous. Refactor plz! + var _updateQueue = workInProgress.updateQueue; + if (_updateQueue !== null) { + _updateQueue.baseState = Object.assign( + {}, + _updateQueue.baseState, + derivedStateFromProps + ); + } + } + if (derivedStateFromCatch !== null && derivedStateFromCatch !== undefined) { + // Render-phase updates (like this) should not be added to the update queue, + // So that multiple render passes do not enqueue multiple updates. + // Instead, just synchronously merge the returned state into the instance. + newState = + newState === null || newState === undefined + ? derivedStateFromCatch + : Object.assign({}, newState, derivedStateFromCatch); + + // Update the base state of the update queue. + // FIXME: This is getting ridiculous. Refactor plz! + var _updateQueue2 = workInProgress.updateQueue; + if (_updateQueue2 !== null) { + _updateQueue2.baseState = Object.assign( + {}, + _updateQueue2.baseState, + derivedStateFromCatch + ); + } + } + + if ( + oldProps === newProps && + oldState === newState && + !hasContextChanged() && + !( + workInProgress.updateQueue !== null && + workInProgress.updateQueue.hasForceUpdate + ) + ) { + // 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; + } + + var shouldUpdate = checkShouldComponentUpdate( + workInProgress, + oldProps, + newProps, + oldState, + newState, + newContext + ); + + 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 props/state to indicate that this work can be reused. + memoizeProps(workInProgress, newProps); + memoizeState(workInProgress, newState); + } + + // Update the existing instance's state, props, and context pointers even + // if shouldComponentUpdate returns false. + instance.props = newProps; + instance.state = newState; + instance.context = newContext; + + return shouldUpdate; + } + + // Invokes the update life-cycles and returns false if it shouldn't rerender. + function updateClassInstance(current, workInProgress, renderExpirationTime) { + var ctor = workInProgress.type; + var instance = workInProgress.stateNode; + resetInputPointers(workInProgress, instance); + + var oldProps = workInProgress.memoizedProps; + var newProps = workInProgress.pendingProps; + var oldContext = instance.context; + var newUnmaskedContext = getUnmaskedContext(workInProgress); + var newContext = getMaskedContext(workInProgress, newUnmaskedContext); + + var hasNewLifecycles = + typeof ctor.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 !== newContext) { + callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + newContext + ); + } + } + + // Compute the next state using the memoized state and the update queue. + var oldState = workInProgress.memoizedState; + // TODO: Previous state can be null. + var newState = void 0; + var derivedStateFromCatch = void 0; + + if (workInProgress.updateQueue !== null) { + newState = processUpdateQueue( + current, + workInProgress, + workInProgress.updateQueue, + instance, + newProps, + renderExpirationTime + ); + + var updateQueue = workInProgress.updateQueue; + if ( + updateQueue !== null && + updateQueue.capturedValues !== null && + enableGetDerivedStateFromCatch && + typeof ctor.getDerivedStateFromCatch === "function" + ) { + var capturedValues = updateQueue.capturedValues; + // Don't remove these from the update queue yet. We need them in + // finishClassComponent. Do the reset there. + // TODO: This is awkward. Refactor class components. + // updateQueue.capturedValues = null; + derivedStateFromCatch = callGetDerivedStateFromCatch( + ctor, + capturedValues + ); + } + } else { + newState = oldState; + } + + var derivedStateFromProps = void 0; + if (oldProps !== newProps) { + // The prevState parameter should be the partially updated state. + // Otherwise, spreading state in return values could override updates. + derivedStateFromProps = callGetDerivedStateFromProps( + workInProgress, + instance, + newProps, + newState + ); + } + + if (derivedStateFromProps !== null && derivedStateFromProps !== undefined) { + // Render-phase updates (like this) should not be added to the update queue, + // So that multiple render passes do not enqueue multiple updates. + // Instead, just synchronously merge the returned state into the instance. + newState = + newState === null || newState === undefined + ? derivedStateFromProps + : Object.assign({}, newState, derivedStateFromProps); + + // Update the base state of the update queue. + // FIXME: This is getting ridiculous. Refactor plz! + var _updateQueue3 = workInProgress.updateQueue; + if (_updateQueue3 !== null) { + _updateQueue3.baseState = Object.assign( + {}, + _updateQueue3.baseState, + derivedStateFromProps + ); + } + } + if (derivedStateFromCatch !== null && derivedStateFromCatch !== undefined) { + // Render-phase updates (like this) should not be added to the update queue, + // So that multiple render passes do not enqueue multiple updates. + // Instead, just synchronously merge the returned state into the instance. + newState = + newState === null || newState === undefined + ? derivedStateFromCatch + : Object.assign({}, newState, derivedStateFromCatch); + + // Update the base state of the update queue. + // FIXME: This is getting ridiculous. Refactor plz! + var _updateQueue4 = workInProgress.updateQueue; + if (_updateQueue4 !== null) { + _updateQueue4.baseState = Object.assign( + {}, + _updateQueue4.baseState, + derivedStateFromCatch + ); + } + } + + if ( + oldProps === newProps && + oldState === newState && + !hasContextChanged() && + !( + workInProgress.updateQueue !== null && + workInProgress.updateQueue.hasForceUpdate + ) + ) { + // 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; + } + + var shouldUpdate = checkShouldComponentUpdate( + workInProgress, + oldProps, + newProps, + oldState, + newState, + newContext + ); + + 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, newContext); + } + if (typeof instance.UNSAFE_componentWillUpdate === "function") { + instance.UNSAFE_componentWillUpdate(newProps, newState, newContext); + } + 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. + memoizeProps(workInProgress, newProps); + memoizeState(workInProgress, newState); + } + + // Update the existing instance's state, props, and context pointers even + // if shouldComponentUpdate returns false. + instance.props = newProps; + instance.state = newState; + instance.context = newContext; + + return shouldUpdate; + } + + return { + adoptClassInstance: adoptClassInstance, + callGetDerivedStateFromProps: callGetDerivedStateFromProps, + constructClassInstance: constructClassInstance, + mountClassInstance: mountClassInstance, + resumeMountClassInstance: resumeMountClassInstance, + updateClassInstance: updateClassInstance + }; +}; + +var getCurrentFiberStackAddendum$1 = + ReactDebugCurrentFiber.getCurrentFiberStackAddendum; + +var didWarnAboutMaps = void 0; +var didWarnAboutStringRefInStrictMode = void 0; +var ownerHasKeyUseWarning = void 0; +var ownerHasFunctionTypeWarning = void 0; +var warnForMissingKey = function(child) {}; + +{ + didWarnAboutMaps = 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; + } + invariant( + typeof child._store === "object", + "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 an array or iterator should have a unique " + + '"key" prop. See https://fb.me/react-warning-keys for ' + + "more information." + + (getCurrentFiberStackAddendum$1() || ""); + if (ownerHasKeyUseWarning[currentComponentErrorInfo]) { + return; + } + ownerHasKeyUseWarning[currentComponentErrorInfo] = true; + + warning( + false, + "Each child in an array or iterator should have a unique " + + '"key" prop. See https://fb.me/react-warning-keys for ' + + "more information.%s", + getCurrentFiberStackAddendum$1() + ); + }; +} + +var isArray$1 = Array.isArray; + +function coerceRef(returnFiber, current, element) { + var mixedRef = element.ref; + if ( + mixedRef !== null && + typeof mixedRef !== "function" && + typeof mixedRef !== "object" + ) { + { + if (returnFiber.mode & StrictMode) { + var componentName = getComponentName(returnFiber) || "Component"; + if (!didWarnAboutStringRefInStrictMode[componentName]) { + warning( + 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, + getStackAddendumByWorkInProgressFiber(returnFiber) + ); + didWarnAboutStringRefInStrictMode[componentName] = true; + } + } + } + + if (element._owner) { + var owner = element._owner; + var inst = void 0; + if (owner) { + var ownerFiber = owner; + invariant( + ownerFiber.tag === ClassComponent, + "Stateless function components cannot have refs." + ); + inst = ownerFiber.stateNode; + } + invariant( + inst, + "Missing owner for string ref %s. This error is likely caused by a " + + "bug in React. Please file an issue.", + mixedRef + ); + var stringRef = "" + mixedRef; + // Check if previous string ref matches new string ref + if ( + current !== null && + current.ref !== null && + current.ref._stringRef === stringRef + ) { + return current.ref; + } + var ref = function(value) { + var refs = inst.refs === emptyObject ? (inst.refs = {}) : inst.refs; + if (value === null) { + delete refs[stringRef]; + } else { + refs[stringRef] = value; + } + }; + ref._stringRef = stringRef; + return ref; + } else { + invariant( + typeof mixedRef === "string", + "Expected ref to be a function or a string." + ); + invariant( + element._owner, + "Element ref was specified as a string (%s) but no owner was set. This could happen for one of" + + " the following reasons:\n" + + "1. You may be adding a ref to a functional component\n" + + "2. You may be adding a ref to a component that was not created inside a component's render method\n" + + "3. You have multiple copies of React loaded\n" + + "See https://fb.me/react-refs-must-have-owner for more information.", + mixedRef + ); + } + } + 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." + + (getCurrentFiberStackAddendum$1() || ""); + } + invariant( + false, + "Objects are not valid as a React child (found: %s).%s", + 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." + + (getCurrentFiberStackAddendum$1() || ""); + + if (ownerHasFunctionTypeWarning[currentComponentErrorInfo]) { + return; + } + ownerHasFunctionTypeWarning[currentComponentErrorInfo] = true; + + warning( + 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.%s", + getCurrentFiberStackAddendum$1() || "" + ); +} + +// 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 = newFiber.alternate; + if (current !== null) { + var oldIndex = current.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, textContent, expirationTime) { + if (current === null || current.tag !== HostText) { + // Insert + var created = createFiberFromText( + textContent, + returnFiber.mode, + expirationTime + ); + created["return"] = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current, textContent, expirationTime); + existing["return"] = returnFiber; + return existing; + } + } + + function updateElement(returnFiber, current, element, expirationTime) { + if (current !== null && current.type === element.type) { + // Move based on index + var existing = useFiber(current, element.props, expirationTime); + existing.ref = coerceRef(returnFiber, current, 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, element); + created["return"] = returnFiber; + return created; + } + } + + function updatePortal(returnFiber, current, portal, expirationTime) { + if ( + current === null || + current.tag !== HostPortal || + current.stateNode.containerInfo !== portal.containerInfo || + current.stateNode.implementation !== portal.implementation + ) { + // Insert + var created = createFiberFromPortal( + portal, + returnFiber.mode, + expirationTime + ); + created["return"] = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current, portal.children || [], expirationTime); + existing["return"] = returnFiber; + return existing; + } + } + + function updateFragment(returnFiber, current, fragment, expirationTime, key) { + if (current === null || current.tag !== Fragment) { + // Insert + var created = createFiberFromFragment( + fragment, + returnFiber.mode, + expirationTime, + key + ); + created["return"] = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current, 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$1(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$1(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$1(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( + 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.%s", + key, + getCurrentFiberStackAddendum$1() + ); + break; + default: + break; + } + } + return knownKeys; + } + + function reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChildren, + expirationTime + ) { + // This algorithm can't optimize by searching from boths 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) { + 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) { + 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); + invariant( + typeof iteratorFn === "function", + "An object is not an iterable. This error is likely caused by a bug in " + + "React. Please file an issue." + ); + + { + // Warn about using Maps as children + if (typeof newChildrenIterable.entries === "function") { + var possibleMap = newChildrenIterable; + if (possibleMap.entries === iteratorFn) { + !didWarnAboutMaps + ? warning( + false, + "Using Maps as children is unsupported and will likely yield " + + "unexpected results. Convert it to a sequence/iterable of keyed " + + "ReactElements instead.%s", + getCurrentFiberStackAddendum$1() + ) + : 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); + invariant(newChildren != null, "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) { + 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.type === 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. + if ( + typeof newChild === "object" && + newChild !== null && + newChild.type === REACT_FRAGMENT_TYPE && + newChild.key === null + ) { + 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$1(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") { + // 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 FunctionalComponent: { + var Component = returnFiber.type; + invariant( + false, + "%s(...): Nothing was returned from render. This usually means a " + + "return statement is missing. Or, to render nothing, " + + "return null.", + Component.displayName || Component.name || "Component" + ); + } + } + } + + // Remaining cases are all treated as empty. + return deleteRemainingChildren(returnFiber, currentFirstChild); + } + + return reconcileChildFibers; +} + +var reconcileChildFibers = ChildReconciler(true); +var mountChildFibers = ChildReconciler(false); + +function cloneChildFibers(current, workInProgress) { + invariant( + current === null || workInProgress.child === current.child, + "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 didWarnAboutBadClass = void 0; +var didWarnAboutGetDerivedStateOnFunctionalComponent = void 0; +var didWarnAboutStatelessRefs = void 0; + +{ + didWarnAboutBadClass = {}; + didWarnAboutGetDerivedStateOnFunctionalComponent = {}; + didWarnAboutStatelessRefs = {}; +} + +var ReactFiberBeginWork = function( + config, + hostContext, + legacyContext, + newContext, + hydrationContext, + scheduleWork, + computeExpirationForFiber +) { + var shouldSetTextContent = config.shouldSetTextContent, + shouldDeprioritizeSubtree = config.shouldDeprioritizeSubtree; + var pushHostContext = hostContext.pushHostContext, + pushHostContainer = hostContext.pushHostContainer; + var pushProvider = newContext.pushProvider; + var getMaskedContext = legacyContext.getMaskedContext, + getUnmaskedContext = legacyContext.getUnmaskedContext, + hasLegacyContextChanged = legacyContext.hasContextChanged, + pushLegacyContextProvider = legacyContext.pushContextProvider, + pushTopLevelContextObject = legacyContext.pushTopLevelContextObject, + invalidateContextProvider = legacyContext.invalidateContextProvider; + var enterHydrationState = hydrationContext.enterHydrationState, + resetHydrationState = hydrationContext.resetHydrationState, + tryToClaimNextHydratableInstance = + hydrationContext.tryToClaimNextHydratableInstance; + + var _ReactFiberClassCompo = ReactFiberClassComponent( + legacyContext, + scheduleWork, + computeExpirationForFiber, + memoizeProps, + memoizeState + ), + adoptClassInstance = _ReactFiberClassCompo.adoptClassInstance, + callGetDerivedStateFromProps = + _ReactFiberClassCompo.callGetDerivedStateFromProps, + constructClassInstance = _ReactFiberClassCompo.constructClassInstance, + mountClassInstance = _ReactFiberClassCompo.mountClassInstance, + resumeMountClassInstance = _ReactFiberClassCompo.resumeMountClassInstance, + updateClassInstance = _ReactFiberClassCompo.updateClassInstance; + + // TODO: Remove this and use reconcileChildrenAtExpirationTime directly. + + function reconcileChildren(current, workInProgress, nextChildren) { + reconcileChildrenAtExpirationTime( + current, + workInProgress, + nextChildren, + workInProgress.expirationTime + ); + } + + function reconcileChildrenAtExpirationTime( + current, + workInProgress, + nextChildren, + renderExpirationTime + ) { + if (current === 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.child, + nextChildren, + renderExpirationTime + ); + } + } + + function updateForwardRef(current, workInProgress) { + var render = workInProgress.type.render; + var nextChildren = render(workInProgress.pendingProps, workInProgress.ref); + reconcileChildren(current, workInProgress, nextChildren); + memoizeProps(workInProgress, nextChildren); + return workInProgress.child; + } + + function updateFragment(current, workInProgress) { + var nextChildren = workInProgress.pendingProps; + if (hasLegacyContextChanged()) { + // Normally we can bail out on props equality but if context has changed + // we don't do the bailout and we have to reuse existing props instead. + } else if (workInProgress.memoizedProps === nextChildren) { + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + reconcileChildren(current, workInProgress, nextChildren); + memoizeProps(workInProgress, nextChildren); + return workInProgress.child; + } + + function updateMode(current, workInProgress) { + var nextChildren = workInProgress.pendingProps.children; + if (hasLegacyContextChanged()) { + // Normally we can bail out on props equality but if context has changed + // we don't do the bailout and we have to reuse existing props instead. + } else if ( + nextChildren === null || + workInProgress.memoizedProps === nextChildren + ) { + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + reconcileChildren(current, workInProgress, nextChildren); + memoizeProps(workInProgress, nextChildren); + return workInProgress.child; + } + + function markRef(current, workInProgress) { + var ref = workInProgress.ref; + if ( + (current === null && ref !== null) || + (current !== null && current.ref !== ref) + ) { + // Schedule a Ref effect + workInProgress.effectTag |= Ref; + } + } + + function updateFunctionalComponent(current, workInProgress) { + var fn = workInProgress.type; + var nextProps = workInProgress.pendingProps; + + if (hasLegacyContextChanged()) { + // Normally we can bail out on props equality but if context has changed + // we don't do the bailout and we have to reuse existing props instead. + } else { + if (workInProgress.memoizedProps === nextProps) { + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + // TODO: consider bringing fn.shouldComponentUpdate() back. + // It used to be here. + } + + var unmaskedContext = getUnmaskedContext(workInProgress); + var context = getMaskedContext(workInProgress, unmaskedContext); + + var nextChildren = void 0; + + { + ReactCurrentOwner.current = workInProgress; + ReactDebugCurrentFiber.setCurrentPhase("render"); + nextChildren = fn(nextProps, context); + ReactDebugCurrentFiber.setCurrentPhase(null); + } + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + reconcileChildren(current, workInProgress, nextChildren); + memoizeProps(workInProgress, nextProps); + return workInProgress.child; + } + + function updateClassComponent(current, workInProgress, renderExpirationTime) { + // 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 = pushLegacyContextProvider(workInProgress); + var shouldUpdate = void 0; + if (current === null) { + if (workInProgress.stateNode === null) { + // In the initial pass we might need to construct the instance. + constructClassInstance(workInProgress, workInProgress.pendingProps); + mountClassInstance(workInProgress, renderExpirationTime); + + shouldUpdate = true; + } else { + // In a resume, we'll already have an instance we can reuse. + shouldUpdate = resumeMountClassInstance( + workInProgress, + renderExpirationTime + ); + } + } else { + shouldUpdate = updateClassInstance( + current, + workInProgress, + renderExpirationTime + ); + } + + // We processed the update queue inside updateClassInstance. It may have + // included some errors that were dispatched during the commit phase. + // TODO: Refactor class components so this is less awkward. + var didCaptureError = false; + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null && updateQueue.capturedValues !== null) { + shouldUpdate = true; + didCaptureError = true; + } + return finishClassComponent( + current, + workInProgress, + shouldUpdate, + hasContext, + didCaptureError, + renderExpirationTime + ); + } + + function finishClassComponent( + current, + workInProgress, + shouldUpdate, + hasContext, + didCaptureError, + renderExpirationTime + ) { + // Refs should update even if shouldComponentUpdate returns false + markRef(current, workInProgress); + + if (!shouldUpdate && !didCaptureError) { + // Context providers should defer to sCU for rendering + if (hasContext) { + invalidateContextProvider(workInProgress, false); + } + + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + + var ctor = workInProgress.type; + var instance = workInProgress.stateNode; + + // Rerender + ReactCurrentOwner.current = workInProgress; + var nextChildren = void 0; + if ( + didCaptureError && + (!enableGetDerivedStateFromCatch || + typeof ctor.getDerivedStateFromCatch !== "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; + } else { + { + ReactDebugCurrentFiber.setCurrentPhase("render"); + nextChildren = instance.render(); + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + instance.render(); + } + ReactDebugCurrentFiber.setCurrentPhase(null); + } + } + + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + if (didCaptureError) { + // If we're recovering from an error, reconcile twice: first to delete + // all the existing children. + reconcileChildrenAtExpirationTime( + current, + workInProgress, + null, + renderExpirationTime + ); + workInProgress.child = null; + // Now we can continue reconciling like normal. This has the effect of + // remounting all children regardless of whether their their + // identity matches. + } + reconcileChildrenAtExpirationTime( + current, + workInProgress, + nextChildren, + renderExpirationTime + ); + // Memoize props and state using the values we just used to render. + // TODO: Restructure so we never read values from the instance. + memoizeState(workInProgress, instance.state); + memoizeProps(workInProgress, instance.props); + + // The context might have changed so we need to recalculate it. + if (hasContext) { + invalidateContextProvider(workInProgress, 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, workInProgress, renderExpirationTime) { + pushHostRootContext(workInProgress); + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + var prevState = workInProgress.memoizedState; + var state = processUpdateQueue( + current, + workInProgress, + updateQueue, + null, + null, + renderExpirationTime + ); + memoizeState(workInProgress, state); + updateQueue = workInProgress.updateQueue; + + var element = void 0; + if (updateQueue !== null && updateQueue.capturedValues !== null) { + // There's an uncaught error. Unmount the whole root. + element = null; + } else if (prevState === state) { + // 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, workInProgress); + } else { + element = state.element; + } + var root = workInProgress.stateNode; + if ( + (current === null || current.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, + element, + renderExpirationTime + ); + } else { + // Otherwise reset hydration state in case we aborted and resumed another + // root. + resetHydrationState(); + reconcileChildren(current, workInProgress, element); + } + memoizeState(workInProgress, state); + return workInProgress.child; + } + resetHydrationState(); + // If there is no update queue, that's a bailout because the root has no props. + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + + function updateHostComponent(current, workInProgress, renderExpirationTime) { + pushHostContext(workInProgress); + + if (current === null) { + tryToClaimNextHydratableInstance(workInProgress); + } + + var type = workInProgress.type; + var memoizedProps = workInProgress.memoizedProps; + var nextProps = workInProgress.pendingProps; + var prevProps = current !== null ? current.memoizedProps : null; + + if (hasLegacyContextChanged()) { + // Normally we can bail out on props equality but if context has changed + // we don't do the bailout and we have to reuse existing props instead. + } else if (memoizedProps === nextProps) { + var isHidden = + workInProgress.mode & AsyncMode && + shouldDeprioritizeSubtree(type, nextProps); + if (isHidden) { + // Before bailing out, make sure we've deprioritized a hidden component. + workInProgress.expirationTime = Never; + } + if (!isHidden || renderExpirationTime !== Never) { + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + // If we're rendering a hidden node at hidden priority, don't bailout. The + // parent is complete, but the children may not be. + } + + 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 && 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, workInProgress); + + // Check the host config to see if the children are offscreen/hidden. + if ( + renderExpirationTime !== Never && + workInProgress.mode & AsyncMode && + shouldDeprioritizeSubtree(type, nextProps) + ) { + // Down-prioritize the children. + workInProgress.expirationTime = Never; + // Bailout and come back to this fiber later. + workInProgress.memoizedProps = nextProps; + return null; + } + + reconcileChildren(current, workInProgress, nextChildren); + memoizeProps(workInProgress, nextProps); + return workInProgress.child; + } + + function updateHostText(current, workInProgress) { + if (current === null) { + tryToClaimNextHydratableInstance(workInProgress); + } + var nextProps = workInProgress.pendingProps; + memoizeProps(workInProgress, nextProps); + // Nothing to do here. This is terminal. We'll do the completion step + // immediately after. + return null; + } + + function mountIndeterminateComponent( + current, + workInProgress, + renderExpirationTime + ) { + invariant( + current === null, + "An indeterminate component should never have mounted. This error is " + + "likely caused by a bug in React. Please file an issue." + ); + var fn = workInProgress.type; + var props = workInProgress.pendingProps; + var unmaskedContext = getUnmaskedContext(workInProgress); + var context = getMaskedContext(workInProgress, unmaskedContext); + + var value = void 0; + + { + if (fn.prototype && typeof fn.prototype.render === "function") { + var componentName = getComponentName(workInProgress) || "Unknown"; + + if (!didWarnAboutBadClass[componentName]) { + warning( + 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; + } + } + ReactCurrentOwner.current = workInProgress; + value = fn(props, context); + } + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + + if ( + typeof value === "object" && + value !== null && + typeof value.render === "function" && + value.$$typeof === undefined + ) { + var Component = workInProgress.type; + + // Proceed under the assumption that this is a class instance + workInProgress.tag = ClassComponent; + + workInProgress.memoizedState = + value.state !== null && value.state !== undefined ? value.state : null; + + if (typeof Component.getDerivedStateFromProps === "function") { + var partialState = callGetDerivedStateFromProps( + workInProgress, + value, + props, + workInProgress.memoizedState + ); + + if (partialState !== null && partialState !== undefined) { + workInProgress.memoizedState = Object.assign( + {}, + workInProgress.memoizedState, + partialState + ); + } + } + + // 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 = pushLegacyContextProvider(workInProgress); + adoptClassInstance(workInProgress, value); + mountClassInstance(workInProgress, renderExpirationTime); + return finishClassComponent( + current, + workInProgress, + true, + hasContext, + false, + renderExpirationTime + ); + } else { + // Proceed under the assumption that this is a functional component + workInProgress.tag = FunctionalComponent; + { + var _Component = workInProgress.type; + + if (_Component) { + !!_Component.childContextTypes + ? warning( + false, + "%s(...): childContextTypes cannot be defined on a functional component.", + _Component.displayName || _Component.name || "Component" + ) + : void 0; + } + if (workInProgress.ref !== null) { + var info = ""; + var ownerName = ReactDebugCurrentFiber.getCurrentFiberOwnerName(); + 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 (!didWarnAboutStatelessRefs[warningKey]) { + didWarnAboutStatelessRefs[warningKey] = true; + warning( + false, + "Stateless function components cannot be given refs. " + + "Attempts to access this ref will fail.%s%s", + info, + ReactDebugCurrentFiber.getCurrentFiberStackAddendum() + ); + } + } + + if (typeof fn.getDerivedStateFromProps === "function") { + var _componentName = getComponentName(workInProgress) || "Unknown"; + + if ( + !didWarnAboutGetDerivedStateOnFunctionalComponent[_componentName] + ) { + warning( + false, + "%s: Stateless functional components do not support getDerivedStateFromProps.", + _componentName + ); + didWarnAboutGetDerivedStateOnFunctionalComponent[ + _componentName + ] = true; + } + } + } + reconcileChildren(current, workInProgress, value); + memoizeProps(workInProgress, props); + return workInProgress.child; + } + } + + function updateCallComponent(current, workInProgress, renderExpirationTime) { + var nextProps = workInProgress.pendingProps; + if (hasLegacyContextChanged()) { + // Normally we can bail out on props equality but if context has changed + // we don't do the bailout and we have to reuse existing props instead. + } else if (workInProgress.memoizedProps === nextProps) { + nextProps = workInProgress.memoizedProps; + // TODO: When bailing out, we might need to return the stateNode instead + // of the child. To check it for work. + // return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + + var nextChildren = nextProps.children; + + // The following is a fork of reconcileChildrenAtExpirationTime but using + // stateNode to store the child. + if (current === null) { + workInProgress.stateNode = mountChildFibers( + workInProgress, + workInProgress.stateNode, + nextChildren, + renderExpirationTime + ); + } else { + workInProgress.stateNode = reconcileChildFibers( + workInProgress, + current.stateNode, + nextChildren, + renderExpirationTime + ); + } + + memoizeProps(workInProgress, nextProps); + // This doesn't take arbitrary time so we could synchronously just begin + // eagerly do the work of workInProgress.child as an optimization. + return workInProgress.stateNode; + } + + function updatePortalComponent( + current, + workInProgress, + renderExpirationTime + ) { + pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); + var nextChildren = workInProgress.pendingProps; + if (hasLegacyContextChanged()) { + // Normally we can bail out on props equality but if context has changed + // we don't do the bailout and we have to reuse existing props instead. + } else if (workInProgress.memoizedProps === nextChildren) { + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + + if (current === 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 + ); + memoizeProps(workInProgress, nextChildren); + } else { + reconcileChildren(current, workInProgress, nextChildren); + memoizeProps(workInProgress, nextChildren); + } + return workInProgress.child; + } + + 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. + switch (fiber.tag) { + case ContextConsumer: + // Check if the context matches. + var observedBits = fiber.stateNode | 0; + if (fiber.type === context && (observedBits & changedBits) !== 0) { + // Update the expiration time of all the ancestors, including + // the alternates. + var node = fiber; + while (node !== null) { + var alternate = node.alternate; + if ( + node.expirationTime === NoWork || + node.expirationTime > renderExpirationTime + ) { + node.expirationTime = renderExpirationTime; + if ( + alternate !== null && + (alternate.expirationTime === NoWork || + alternate.expirationTime > renderExpirationTime) + ) { + alternate.expirationTime = renderExpirationTime; + } + } else if ( + alternate !== null && + (alternate.expirationTime === NoWork || + alternate.expirationTime > renderExpirationTime) + ) { + alternate.expirationTime = renderExpirationTime; + } else { + // Neither alternate was updated, which means the rest of the + // ancestor path already has sufficient priority. + break; + } + node = node["return"]; + } + // Don't scan deeper than a matching consumer. When we render the + // consumer, we'll continue scanning from that point. This way the + // scanning work is time-sliced. + nextFiber = null; + } else { + // Traverse down. + nextFiber = fiber.child; + } + break; + case ContextProvider: + // Don't scan deeper if this is a matching provider + nextFiber = fiber.type === workInProgress.type ? null : fiber.child; + break; + default: + // Traverse down. + nextFiber = fiber.child; + break; + } + 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) { + nextFiber = sibling; + break; + } + // No more siblings. Traverse up. + nextFiber = nextFiber["return"]; + } + } + fiber = nextFiber; + } + } + + function updateContextProvider( + current, + workInProgress, + renderExpirationTime + ) { + var providerType = workInProgress.type; + var context = providerType._context; + + var newProps = workInProgress.pendingProps; + var oldProps = workInProgress.memoizedProps; + + if (hasLegacyContextChanged()) { + // Normally we can bail out on props equality but if context has changed + // we don't do the bailout and we have to reuse existing props instead. + } else if (oldProps === newProps) { + workInProgress.stateNode = 0; + pushProvider(workInProgress); + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + + var newValue = newProps.value; + workInProgress.memoizedProps = newProps; + + var changedBits = void 0; + if (oldProps === null) { + // Initial render + changedBits = MAX_SIGNED_31_BIT_INT; + } else { + if (oldProps.value === newProps.value) { + // No change. Bailout early if children are the same. + if (oldProps.children === newProps.children) { + workInProgress.stateNode = 0; + pushProvider(workInProgress); + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + changedBits = 0; + } else { + var oldValue = oldProps.value; + // Use Object.is to compare the new context value to the old value. + // Inlined Object.is polyfill. + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is + if ( + (oldValue === newValue && + (oldValue !== 0 || 1 / oldValue === 1 / newValue)) || + (oldValue !== oldValue && newValue !== newValue) // eslint-disable-line no-self-compare + ) { + // No change. Bailout early if children are the same. + if (oldProps.children === newProps.children) { + workInProgress.stateNode = 0; + pushProvider(workInProgress); + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + changedBits = 0; + } else { + changedBits = + typeof context._calculateChangedBits === "function" + ? context._calculateChangedBits(oldValue, newValue) + : MAX_SIGNED_31_BIT_INT; + { + !((changedBits & MAX_SIGNED_31_BIT_INT) === changedBits) + ? warning( + false, + "calculateChangedBits: Expected the return value to be a " + + "31-bit integer. Instead received: %s", + changedBits + ) + : void 0; + } + changedBits |= 0; + + if (changedBits === 0) { + // No change. Bailout early if children are the same. + if (oldProps.children === newProps.children) { + workInProgress.stateNode = 0; + pushProvider(workInProgress); + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + } else { + propagateContextChange( + workInProgress, + context, + changedBits, + renderExpirationTime + ); + } + } + } + } + + workInProgress.stateNode = changedBits; + pushProvider(workInProgress); + + var newChildren = newProps.children; + reconcileChildren(current, workInProgress, newChildren); + return workInProgress.child; + } + + function updateContextConsumer( + current, + workInProgress, + renderExpirationTime + ) { + var context = workInProgress.type; + var newProps = workInProgress.pendingProps; + var oldProps = workInProgress.memoizedProps; + + var newValue = context._currentValue; + var changedBits = context._changedBits; + + if (hasLegacyContextChanged()) { + // Normally we can bail out on props equality but if context has changed + // we don't do the bailout and we have to reuse existing props instead. + } else if (changedBits === 0 && oldProps === newProps) { + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + workInProgress.memoizedProps = newProps; + + var observedBits = newProps.unstable_observedBits; + if (observedBits === undefined || observedBits === null) { + // Subscribe to all changes by default + observedBits = MAX_SIGNED_31_BIT_INT; + } + // Store the observedBits on the fiber's stateNode for quick access. + workInProgress.stateNode = observedBits; + + if ((changedBits & observedBits) !== 0) { + // Context change propagation stops at matching consumers, for time- + // slicing. Continue the propagation here. + propagateContextChange( + workInProgress, + context, + changedBits, + renderExpirationTime + ); + } else if (oldProps === newProps) { + // Skip over a memoized parent with a bitmask bailout even + // if we began working on it because of a deeper matching child. + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + // There is no bailout on `children` equality because we expect people + // to often pass a bound method as a child, but it may reference + // `this.state` or `this.props` (and thus needs to re-render on `setState`). + + var render = newProps.children; + + { + !(typeof render === "function") + ? warning( + 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; + } + + var newChildren = render(newValue); + reconcileChildren(current, workInProgress, newChildren); + return workInProgress.child; + } + + /* + function reuseChildrenEffects(returnFiber : Fiber, firstChild : Fiber) { + let child = firstChild; + do { + // Ensure that the first and last effect of the parent corresponds + // to the children's first and last effect. + if (!returnFiber.firstEffect) { + returnFiber.firstEffect = child.firstEffect; + } + if (child.lastEffect) { + if (returnFiber.lastEffect) { + returnFiber.lastEffect.nextEffect = child.firstEffect; + } + returnFiber.lastEffect = child.lastEffect; + } + } while (child = child.sibling); + } + */ + + function bailoutOnAlreadyFinishedWork(current, workInProgress) { + cancelWorkTimer(workInProgress); + + // TODO: We should ideally be able to bail out early if the children have no + // more work to do. However, since we don't have a separation of this + // Fiber's priority and its children yet - we don't know without doing lots + // of the same work we do anyway. Once we have that separation we can just + // bail out here if the children has no more work at this priority level. + // if (workInProgress.priorityOfChildren <= priorityLevel) { + // // If there are side-effects in these children that have not yet been + // // committed we need to ensure that they get properly transferred up. + // if (current && current.child !== workInProgress.child) { + // reuseChildrenEffects(workInProgress, child); + // } + // return null; + // } + + cloneChildFibers(current, workInProgress); + return workInProgress.child; + } + + function bailoutOnLowPriority(current, workInProgress) { + cancelWorkTimer(workInProgress); + + // TODO: Handle HostComponent tags here as well and call pushHostContext()? + // See PR 8590 discussion for context + switch (workInProgress.tag) { + case HostRoot: + pushHostRootContext(workInProgress); + break; + case ClassComponent: + pushLegacyContextProvider(workInProgress); + break; + case HostPortal: + pushHostContainer( + workInProgress, + workInProgress.stateNode.containerInfo + ); + break; + case ContextProvider: + pushProvider(workInProgress); + break; + } + // TODO: What if this is currently in progress? + // How can that happen? How is this not being cloned? + return null; + } + + // TODO: Delete memoizeProps/State and move to reconcile/bailout instead + function memoizeProps(workInProgress, nextProps) { + workInProgress.memoizedProps = nextProps; + } + + function memoizeState(workInProgress, nextState) { + workInProgress.memoizedState = nextState; + // Don't reset the updateQueue, in case there are pending updates. Resetting + // is handled by processUpdateQueue. + } + + function beginWork(current, workInProgress, renderExpirationTime) { + if ( + workInProgress.expirationTime === NoWork || + workInProgress.expirationTime > renderExpirationTime + ) { + return bailoutOnLowPriority(current, workInProgress); + } + + switch (workInProgress.tag) { + case IndeterminateComponent: + return mountIndeterminateComponent( + current, + workInProgress, + renderExpirationTime + ); + case FunctionalComponent: + return updateFunctionalComponent(current, workInProgress); + case ClassComponent: + return updateClassComponent( + current, + workInProgress, + renderExpirationTime + ); + case HostRoot: + return updateHostRoot(current, workInProgress, renderExpirationTime); + case HostComponent: + return updateHostComponent( + current, + workInProgress, + renderExpirationTime + ); + case HostText: + return updateHostText(current, workInProgress); + case CallHandlerPhase: + // This is a restart. Reset the tag to the initial phase. + workInProgress.tag = CallComponent; + // Intentionally fall through since this is now the same. + case CallComponent: + return updateCallComponent( + current, + workInProgress, + renderExpirationTime + ); + case ReturnComponent: + // A return component is just a placeholder, we can just run through the + // next one immediately. + return null; + case HostPortal: + return updatePortalComponent( + current, + workInProgress, + renderExpirationTime + ); + case ForwardRef: + return updateForwardRef(current, workInProgress); + case Fragment: + return updateFragment(current, workInProgress); + case Mode: + return updateMode(current, workInProgress); + case ContextProvider: + return updateContextProvider( + current, + workInProgress, + renderExpirationTime + ); + case ContextConsumer: + return updateContextConsumer( + current, + workInProgress, + renderExpirationTime + ); + default: + invariant( + false, + "Unknown unit of work tag. This error is likely caused by a bug in " + + "React. Please file an issue." + ); + } + } + + return { + beginWork: beginWork + }; +}; + +var ReactFiberCompleteWork = function( + config, + hostContext, + legacyContext, + newContext, + hydrationContext +) { + var createInstance = config.createInstance, + createTextInstance = config.createTextInstance, + appendInitialChild = config.appendInitialChild, + finalizeInitialChildren = config.finalizeInitialChildren, + prepareUpdate = config.prepareUpdate, + mutation = config.mutation, + persistence = config.persistence; + var getRootHostContainer = hostContext.getRootHostContainer, + popHostContext = hostContext.popHostContext, + getHostContext = hostContext.getHostContext, + popHostContainer = hostContext.popHostContainer; + var popLegacyContextProvider = legacyContext.popContextProvider, + popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject; + var popProvider = newContext.popProvider; + var prepareToHydrateHostInstance = + hydrationContext.prepareToHydrateHostInstance, + prepareToHydrateHostTextInstance = + hydrationContext.prepareToHydrateHostTextInstance, + popHydrationState = hydrationContext.popHydrationState; + + function markUpdate(workInProgress) { + // Tag the fiber with an update effect. This turns a Placement into + // a PlacementAndUpdate. + workInProgress.effectTag |= Update; + } + + function markRef(workInProgress) { + workInProgress.effectTag |= Ref; + } + + function appendAllReturns(returns, workInProgress) { + var node = workInProgress.stateNode; + if (node) { + node["return"] = workInProgress; + } + while (node !== null) { + if ( + node.tag === HostComponent || + node.tag === HostText || + node.tag === HostPortal + ) { + invariant(false, "A call cannot have host component children."); + } else if (node.tag === ReturnComponent) { + returns.push(node.pendingProps.value); + } else if (node.child !== null) { + node.child["return"] = node; + node = node.child; + continue; + } + while (node.sibling === null) { + if (node["return"] === null || node["return"] === workInProgress) { + return; + } + node = node["return"]; + } + node.sibling["return"] = node["return"]; + node = node.sibling; + } + } + + function moveCallToHandlerPhase( + current, + workInProgress, + renderExpirationTime + ) { + var props = workInProgress.memoizedProps; + invariant( + props, + "Should be resolved by now. This error is likely caused by a bug in " + + "React. Please file an issue." + ); + + // First step of the call has completed. Now we need to do the second. + // TODO: It would be nice to have a multi stage call represented by a + // single component, or at least tail call optimize nested ones. Currently + // that requires additional fields that we don't want to add to the fiber. + // So this requires nested handlers. + // Note: This doesn't mutate the alternate node. I don't think it needs to + // since this stage is reset for every pass. + workInProgress.tag = CallHandlerPhase; + + // Build up the returns. + // TODO: Compare this to a generator or opaque helpers like Children. + var returns = []; + appendAllReturns(returns, workInProgress); + var fn = props.handler; + var childProps = props.props; + var nextChildren = fn(childProps, returns); + + var currentFirstChild = current !== null ? current.child : null; + workInProgress.child = reconcileChildFibers( + workInProgress, + currentFirstChild, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; + } + + function appendAllChildren(parent, workInProgress) { + // 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; + } + } + + var updateHostContainer = void 0; + var updateHostComponent = void 0; + var updateHostText = void 0; + if (mutation) { + if (enableMutatingReconciler) { + // Mutation mode + updateHostContainer = function(workInProgress) { + // Noop + }; + updateHostComponent = function( + current, + workInProgress, + updatePayload, + 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 = 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 { + invariant(false, "Mutating reconciler is disabled."); + } + } else if (persistence) { + if (enablePersistentReconciler) { + // Persistent host tree mode + var cloneInstance = persistence.cloneInstance, + createContainerChildSet = persistence.createContainerChildSet, + appendChildToContainerChildSet = + persistence.appendChildToContainerChildSet, + finalizeContainerChildren = persistence.finalizeContainerChildren; + + // An unfortunate fork of appendAllChildren because we have two different parent types. + + var appendAllChildrenToContainer = function( + containerChildSet, + workInProgress + ) { + // 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) { + appendChildToContainerChildSet(containerChildSet, 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) { + 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); + portalOrRoot.pendingChildren = newChildSet; + // Schedule an update on the container to swap out the container. + markUpdate(workInProgress); + finalizeContainerChildren(container, newChildSet); + } + }; + updateHostComponent = function( + current, + workInProgress, + updatePayload, + type, + oldProps, + newProps, + rootContainerInstance, + currentHostContext + ) { + // 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; + var currentInstance = current.stateNode; + if (childrenUnchanged && updatePayload === null) { + // No changes, just reuse the existing instance. + // Note that this might release a previous clone. + workInProgress.stateNode = currentInstance; + } else { + var recyclableInstance = workInProgress.stateNode; + 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); + } + } + }; + updateHostText = 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 { + invariant(false, "Persistent reconciler is disabled."); + } + } else { + if (enableNoopReconciler) { + // No host operations + updateHostContainer = function(workInProgress) { + // Noop + }; + updateHostComponent = function( + current, + workInProgress, + updatePayload, + type, + oldProps, + newProps, + rootContainerInstance, + currentHostContext + ) { + // Noop + }; + updateHostText = function(current, workInProgress, oldText, newText) { + // Noop + }; + } else { + invariant(false, "Noop reconciler is disabled."); + } + } + + function completeWork(current, workInProgress, renderExpirationTime) { + var newProps = workInProgress.pendingProps; + switch (workInProgress.tag) { + case FunctionalComponent: + return null; + case ClassComponent: { + // We are leaving this subtree, so pop context if any. + popLegacyContextProvider(workInProgress); + + // If this component caught an error, schedule an error log effect. + var instance = workInProgress.stateNode; + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null && updateQueue.capturedValues !== null) { + workInProgress.effectTag &= ~DidCapture; + if (typeof instance.componentDidCatch === "function") { + workInProgress.effectTag |= ErrLog; + } else { + // Normally we clear this in the commit phase, but since we did not + // schedule an effect, we need to reset it here. + updateQueue.capturedValues = null; + } + } + return null; + } + case HostRoot: { + popHostContainer(workInProgress); + popTopLevelLegacyContextObject(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); + + var _updateQueue = workInProgress.updateQueue; + if (_updateQueue !== null && _updateQueue.capturedValues !== null) { + workInProgress.effectTag |= ErrLog; + } + return null; + } + case HostComponent: { + popHostContext(workInProgress); + var rootContainerInstance = getRootHostContainer(); + var type = workInProgress.type; + if (current !== null && workInProgress.stateNode != null) { + // 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 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 + ); + + updateHostComponent( + current, + workInProgress, + updatePayload, + type, + oldProps, + newProps, + rootContainerInstance, + currentHostContext + ); + + if (current.ref !== workInProgress.ref) { + markRef(workInProgress); + } + } else { + if (!newProps) { + invariant( + workInProgress.stateNode !== null, + "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. + return null; + } + + 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 _instance2 = createInstance( + type, + newProps, + rootContainerInstance, + _currentHostContext, + workInProgress + ); + + appendAllChildren(_instance2, workInProgress); + + // 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( + _instance2, + type, + newProps, + rootContainerInstance, + _currentHostContext + ) + ) { + markUpdate(workInProgress); + } + workInProgress.stateNode = _instance2; + } + + if (workInProgress.ref !== null) { + // If there is a ref on a host node we need to schedule a callback + markRef(workInProgress); + } + } + return null; + } + 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(current, workInProgress, oldText, newText); + } else { + if (typeof newText !== "string") { + invariant( + workInProgress.stateNode !== null, + "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. + return null; + } + var _rootContainerInstance = getRootHostContainer(); + var _currentHostContext2 = getHostContext(); + var _wasHydrated = popHydrationState(workInProgress); + if (_wasHydrated) { + if (prepareToHydrateHostTextInstance(workInProgress)) { + markUpdate(workInProgress); + } + } else { + workInProgress.stateNode = createTextInstance( + newText, + _rootContainerInstance, + _currentHostContext2, + workInProgress + ); + } + } + return null; + } + case CallComponent: + return moveCallToHandlerPhase( + current, + workInProgress, + renderExpirationTime + ); + case CallHandlerPhase: + // Reset the tag to now be a first phase call. + workInProgress.tag = CallComponent; + return null; + case ReturnComponent: + // Does nothing. + return null; + case ForwardRef: + return null; + case Fragment: + return null; + case Mode: + return null; + case HostPortal: + popHostContainer(workInProgress); + updateHostContainer(workInProgress); + return null; + case ContextProvider: + // Pop provider fiber + popProvider(workInProgress); + return null; + case ContextConsumer: + return null; + // Error cases + case IndeterminateComponent: + invariant( + false, + "An indeterminate component should have become determinate before " + + "completing. This error is likely caused by a bug in React. Please " + + "file an issue." + ); + // eslint-disable-next-line no-fallthrough + default: + invariant( + false, + "Unknown unit of work tag. This error is likely caused by a bug in " + + "React. Please file an issue." + ); + } + } + + return { + completeWork: completeWork + }; +}; + +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: getStackAddendumByWorkInProgressFiber(source) + }; +} + +var ReactFiberUnwindWork = function( + hostContext, + legacyContext, + newContext, + scheduleWork, + isAlreadyFailedLegacyErrorBoundary +) { + var popHostContainer = hostContext.popHostContainer, + popHostContext = hostContext.popHostContext; + var popLegacyContextProvider = legacyContext.popContextProvider, + popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject; + var popProvider = newContext.popProvider; + + function throwException(returnFiber, sourceFiber, rawValue) { + // The source fiber did not complete. + sourceFiber.effectTag |= Incomplete; + // Its effect list is no longer valid. + sourceFiber.firstEffect = sourceFiber.lastEffect = null; + + var value = createCapturedValue(rawValue, sourceFiber); + + var workInProgress = returnFiber; + do { + switch (workInProgress.tag) { + case HostRoot: { + // Uncaught error + var errorInfo = value; + ensureUpdateQueues(workInProgress); + var updateQueue = workInProgress.updateQueue; + updateQueue.capturedValues = [errorInfo]; + workInProgress.effectTag |= ShouldCapture; + return; + } + case ClassComponent: + // Capture and retry + var ctor = workInProgress.type; + var _instance = workInProgress.stateNode; + if ( + (workInProgress.effectTag & DidCapture) === NoEffect && + ((typeof ctor.getDerivedStateFromCatch === "function" && + enableGetDerivedStateFromCatch) || + (_instance !== null && + typeof _instance.componentDidCatch === "function" && + !isAlreadyFailedLegacyErrorBoundary(_instance))) + ) { + ensureUpdateQueues(workInProgress); + var _updateQueue = workInProgress.updateQueue; + var capturedValues = _updateQueue.capturedValues; + if (capturedValues === null) { + _updateQueue.capturedValues = [value]; + } else { + capturedValues.push(value); + } + workInProgress.effectTag |= ShouldCapture; + return; + } + break; + default: + break; + } + workInProgress = workInProgress["return"]; + } while (workInProgress !== null); + } + + function unwindWork(workInProgress) { + switch (workInProgress.tag) { + case ClassComponent: { + popLegacyContextProvider(workInProgress); + var effectTag = workInProgress.effectTag; + if (effectTag & ShouldCapture) { + workInProgress.effectTag = (effectTag & ~ShouldCapture) | DidCapture; + return workInProgress; + } + return null; + } + case HostRoot: { + popHostContainer(workInProgress); + popTopLevelLegacyContextObject(workInProgress); + var _effectTag = workInProgress.effectTag; + if (_effectTag & ShouldCapture) { + workInProgress.effectTag = (_effectTag & ~ShouldCapture) | DidCapture; + return workInProgress; + } + return null; + } + case HostComponent: { + popHostContext(workInProgress); + return null; + } + case HostPortal: + popHostContainer(workInProgress); + return null; + case ContextProvider: + popProvider(workInProgress); + return null; + default: + return null; + } + } + + function unwindInterruptedWork(interruptedWork) { + switch (interruptedWork.tag) { + case ClassComponent: { + popLegacyContextProvider(interruptedWork); + break; + } + case HostRoot: { + popHostContainer(interruptedWork); + popTopLevelLegacyContextObject(interruptedWork); + break; + } + case HostComponent: { + popHostContext(interruptedWork); + break; + } + case HostPortal: + popHostContainer(interruptedWork); + break; + case ContextProvider: + popProvider(interruptedWork); + break; + default: + break; + } + } + + return { + throwException: throwException, + unwindWork: unwindWork, + unwindInterruptedWork: unwindInterruptedWork + }; +}; + +// This module is forked in different environments. +// By default, return `true` to log errors to the console. +// Forks can return `false` if this isn't desirable. +function showErrorDialog(capturedError) { + return true; +} + +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 suppressLogging = error && error.suppressReactErrorLogging; + if (suppressLogging) { + return; + } + + { + var componentName = capturedError.componentName, + componentStack = capturedError.componentStack, + errorBoundaryName = capturedError.errorBoundaryName, + errorBoundaryFound = capturedError.errorBoundaryFound, + willRetry = capturedError.willRetry; + + 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 invokeGuardedCallback$3 = ReactErrorUtils.invokeGuardedCallback; +var hasCaughtError$1 = ReactErrorUtils.hasCaughtError; +var clearCaughtError$1 = ReactErrorUtils.clearCaughtError; + +var didWarnAboutUndefinedSnapshotBeforeUpdate = null; +{ + didWarnAboutUndefinedSnapshotBeforeUpdate = new Set(); +} + +function logError(boundary, errorInfo) { + var source = errorInfo.source; + var stack = errorInfo.stack; + if (stack === null) { + stack = getStackAddendumByWorkInProgressFiber(source); + } + + var capturedError = { + componentName: source !== null ? getComponentName(source) : 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); + capturedError.errorBoundaryFound = true; + capturedError.willRetry = true; + } + + try { + logCapturedError(capturedError); + } catch (e) { + // Prevent cycle if logCapturedError() throws. + // A cycle may still occur if logCapturedError renders a component that throws. + var suppressLogging = e && e.suppressReactErrorLogging; + if (!suppressLogging) { + console.error(e); + } + } +} + +var ReactFiberCommitWork = function( + config, + captureError, + scheduleWork, + computeExpirationForFiber, + markLegacyErrorBoundaryAsFailed, + recalculateCurrentTime +) { + var getPublicInstance = config.getPublicInstance, + mutation = config.mutation, + persistence = config.persistence; + + var callComponentWillUnmountWithTimer = function(current, instance) { + startPhaseTimer(current, "componentWillUnmount"); + instance.props = current.memoizedProps; + instance.state = current.memoizedState; + instance.componentWillUnmount(); + stopPhaseTimer(); + }; + + // Capture errors so they don't interrupt unmounting. + function safelyCallComponentWillUnmount(current, instance) { + { + invokeGuardedCallback$3( + null, + callComponentWillUnmountWithTimer, + null, + current, + instance + ); + if (hasCaughtError$1()) { + var unmountError = clearCaughtError$1(); + captureError(current, unmountError); + } + } + } + + function safelyDetachRef(current) { + var ref = current.ref; + if (ref !== null) { + if (typeof ref === "function") { + { + invokeGuardedCallback$3(null, ref, null, null); + if (hasCaughtError$1()) { + var refError = clearCaughtError$1(); + captureError(current, refError); + } + } + } else { + ref.current = null; + } + } + } + + function commitBeforeMutationLifeCycles(current, finishedWork) { + switch (finishedWork.tag) { + case ClassComponent: { + if (finishedWork.effectTag & Snapshot) { + if (current !== null) { + var prevProps = current.memoizedProps; + var prevState = current.memoizedState; + startPhaseTimer(finishedWork, "getSnapshotBeforeUpdate"); + var _instance = finishedWork.stateNode; + _instance.props = finishedWork.memoizedProps; + _instance.state = finishedWork.memoizedState; + var snapshot = _instance.getSnapshotBeforeUpdate( + prevProps, + prevState + ); + { + var didWarnSet = didWarnAboutUndefinedSnapshotBeforeUpdate; + if ( + snapshot === undefined && + !didWarnSet.has(finishedWork.type) + ) { + didWarnSet.add(finishedWork.type); + warning( + false, + "%s.getSnapshotBeforeUpdate(): A snapshot value (or null) " + + "must be returned. You have returned undefined.", + getComponentName(finishedWork) + ); + } + } + _instance.__reactInternalSnapshotBeforeUpdate = snapshot; + stopPhaseTimer(); + } + } + return; + } + case HostRoot: + case HostComponent: + case HostText: + case HostPortal: + // Nothing to do for these component types + return; + default: { + invariant( + false, + "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 commitLifeCycles( + finishedRoot, + current, + finishedWork, + currentTime, + committedExpirationTime + ) { + switch (finishedWork.tag) { + case ClassComponent: { + var _instance2 = finishedWork.stateNode; + if (finishedWork.effectTag & Update) { + if (current === null) { + startPhaseTimer(finishedWork, "componentDidMount"); + _instance2.props = finishedWork.memoizedProps; + _instance2.state = finishedWork.memoizedState; + _instance2.componentDidMount(); + stopPhaseTimer(); + } else { + var prevProps = current.memoizedProps; + var prevState = current.memoizedState; + startPhaseTimer(finishedWork, "componentDidUpdate"); + _instance2.props = finishedWork.memoizedProps; + _instance2.state = finishedWork.memoizedState; + _instance2.componentDidUpdate( + prevProps, + prevState, + _instance2.__reactInternalSnapshotBeforeUpdate + ); + stopPhaseTimer(); + } + } + var updateQueue = finishedWork.updateQueue; + if (updateQueue !== null) { + commitCallbacks(updateQueue, _instance2); + } + return; + } + case HostRoot: { + var _updateQueue = finishedWork.updateQueue; + if (_updateQueue !== null) { + var _instance3 = null; + if (finishedWork.child !== null) { + switch (finishedWork.child.tag) { + case HostComponent: + _instance3 = getPublicInstance(finishedWork.child.stateNode); + break; + case ClassComponent: + _instance3 = finishedWork.child.stateNode; + break; + } + } + commitCallbacks(_updateQueue, _instance3); + } + return; + } + case HostComponent: { + var _instance4 = 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 === null && finishedWork.effectTag & Update) { + var type = finishedWork.type; + var props = finishedWork.memoizedProps; + commitMount(_instance4, 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; + } + default: { + invariant( + false, + "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 commitErrorLogging(finishedWork, onUncaughtError) { + switch (finishedWork.tag) { + case ClassComponent: + { + var ctor = finishedWork.type; + var _instance5 = finishedWork.stateNode; + var updateQueue = finishedWork.updateQueue; + invariant( + updateQueue !== null && updateQueue.capturedValues !== null, + "An error logging effect should not have been scheduled if no errors " + + "were captured. This error is likely caused by a bug in React. " + + "Please file an issue." + ); + var capturedErrors = updateQueue.capturedValues; + updateQueue.capturedValues = null; + + if (typeof ctor.getDerivedStateFromCatch !== "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 getDerivedStateFromCatch is + // not defined. + markLegacyErrorBoundaryAsFailed(_instance5); + } + + _instance5.props = finishedWork.memoizedProps; + _instance5.state = finishedWork.memoizedState; + for (var i = 0; i < capturedErrors.length; i++) { + var errorInfo = capturedErrors[i]; + var _error = errorInfo.value; + var stack = errorInfo.stack; + logError(finishedWork, errorInfo); + _instance5.componentDidCatch(_error, { + componentStack: stack !== null ? stack : "" + }); + } + } + break; + case HostRoot: { + var _updateQueue2 = finishedWork.updateQueue; + invariant( + _updateQueue2 !== null && _updateQueue2.capturedValues !== null, + "An error logging effect should not have been scheduled if no errors " + + "were captured. This error is likely caused by a bug in React. " + + "Please file an issue." + ); + var _capturedErrors = _updateQueue2.capturedValues; + _updateQueue2.capturedValues = null; + for (var _i = 0; _i < _capturedErrors.length; _i++) { + var _errorInfo = _capturedErrors[_i]; + logError(finishedWork, _errorInfo); + onUncaughtError(_errorInfo.value); + } + break; + } + default: + invariant( + false, + "This unit of work tag cannot capture errors. This error is " + + "likely caused by a bug in React. Please file an issue." + ); + } + } + + function commitAttachRef(finishedWork) { + var ref = finishedWork.ref; + if (ref !== null) { + var _instance6 = finishedWork.stateNode; + var instanceToUse = void 0; + switch (finishedWork.tag) { + case HostComponent: + instanceToUse = getPublicInstance(_instance6); + break; + default: + instanceToUse = _instance6; + } + if (typeof ref === "function") { + ref(instanceToUse); + } else { + { + if (!ref.hasOwnProperty("current")) { + warning( + false, + "Unexpected ref object provided for %s. " + + "Use either a ref-setter function or React.createRef().%s", + getComponentName(finishedWork), + getStackAddendumByWorkInProgressFiber(finishedWork) + ); + } + } + + ref.current = instanceToUse; + } + } + } + + function commitDetachRef(current) { + var currentRef = current.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) { + if (typeof onCommitUnmount === "function") { + onCommitUnmount(current); + } + + switch (current.tag) { + case ClassComponent: { + safelyDetachRef(current); + var _instance7 = current.stateNode; + if (typeof _instance7.componentWillUnmount === "function") { + safelyCallComponentWillUnmount(current, _instance7); + } + return; + } + case HostComponent: { + safelyDetachRef(current); + return; + } + case CallComponent: { + commitNestedUnmounts(current.stateNode); + return; + } + case HostPortal: { + // TODO: this is recursive. + // We are also not using this parent because + // the portal will get pushed immediately. + if (enableMutatingReconciler && mutation) { + unmountHostComponents(current); + } else if (enablePersistentReconciler && persistence) { + emptyPortalContainer(current); + } + return; + } + } + } + + 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. + (!mutation || 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) { + // 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["return"] = null; + current.child = null; + if (current.alternate) { + current.alternate.child = null; + current.alternate["return"] = null; + } + } + + var emptyPortalContainer = void 0; + + if (!mutation) { + var commitContainer = void 0; + if (persistence) { + var replaceContainerChildren = persistence.replaceContainerChildren, + createContainerChildSet = persistence.createContainerChildSet; + + emptyPortalContainer = function(current) { + var portal = current.stateNode; + var containerInfo = portal.containerInfo; + + var emptyChildSet = createContainerChildSet(containerInfo); + replaceContainerChildren(containerInfo, emptyChildSet); + }; + commitContainer = function(finishedWork) { + switch (finishedWork.tag) { + case ClassComponent: { + return; + } + case HostComponent: { + return; + } + case HostText: { + return; + } + case HostRoot: + case HostPortal: { + var portalOrRoot = finishedWork.stateNode; + var containerInfo = portalOrRoot.containerInfo, + _pendingChildren = portalOrRoot.pendingChildren; + + replaceContainerChildren(containerInfo, _pendingChildren); + return; + } + default: { + invariant( + false, + "This unit of work tag should not have side-effects. This error is " + + "likely caused by a bug in React. Please file an issue." + ); + } + } + }; + } else { + commitContainer = function(finishedWork) { + // Noop + }; + } + if (enablePersistentReconciler || enableNoopReconciler) { + return { + commitResetTextContent: function(finishedWork) {}, + commitPlacement: function(finishedWork) {}, + commitDeletion: function(current) { + // Detach refs and call componentWillUnmount() on the whole subtree. + commitNestedUnmounts(current); + detachFiber(current); + }, + commitWork: function(current, finishedWork) { + commitContainer(finishedWork); + }, + + commitLifeCycles: commitLifeCycles, + commitBeforeMutationLifeCycles: commitBeforeMutationLifeCycles, + commitErrorLogging: commitErrorLogging, + commitAttachRef: commitAttachRef, + commitDetachRef: commitDetachRef + }; + } else if (persistence) { + invariant(false, "Persistent reconciler is disabled."); + } else { + invariant(false, "Noop reconciler is disabled."); + } + } + var commitMount = mutation.commitMount, + commitUpdate = mutation.commitUpdate, + resetTextContent = mutation.resetTextContent, + commitTextUpdate = mutation.commitTextUpdate, + appendChild = mutation.appendChild, + appendChildToContainer = mutation.appendChildToContainer, + insertBefore = mutation.insertBefore, + insertInContainerBefore = mutation.insertInContainerBefore, + removeChild = mutation.removeChild, + removeChildFromContainer = mutation.removeChildFromContainer; + + function getHostParentFiber(fiber) { + var parent = fiber["return"]; + while (parent !== null) { + if (isHostParent(parent)) { + return parent; + } + parent = parent["return"]; + } + invariant( + false, + "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) { + // 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) { + // Recursively insert all host nodes into the parent. + var parentFiber = getHostParentFiber(finishedWork); + 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: + invariant( + false, + "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 recurse down its + // children to find all the terminal nodes. + var node = finishedWork; + while (true) { + if (node.tag === HostComponent || node.tag === HostText) { + if (before) { + if (isContainer) { + insertInContainerBefore(parent, node.stateNode, before); + } else { + insertBefore(parent, node.stateNode, before); + } + } else { + if (isContainer) { + appendChildToContainer(parent, node.stateNode); + } else { + appendChild(parent, node.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) { + // We only have the top Fiber that was inserted but we need recurse down its + var node = current; + + // Each iteration, currentParent is populated with node's host parent if not + // currentParentIsValid. + var currentParentIsValid = false; + var currentParent = void 0; + var currentParentIsContainer = void 0; + + while (true) { + if (!currentParentIsValid) { + var parent = node["return"]; + findParent: while (true) { + invariant( + parent !== null, + "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 (node.tag === HostPortal) { + // 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; + // Visit children because portals might contain host components. + if (node.child !== null) { + 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) { + return; + } + while (node.sibling === null) { + if (node["return"] === null || node["return"] === current) { + 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) { + // Recursively delete all host nodes from the parent. + // Detach refs and call componentWillUnmount() on the whole subtree. + unmountHostComponents(current); + detachFiber(current); + } + + function commitWork(current, finishedWork) { + switch (finishedWork.tag) { + case ClassComponent: { + return; + } + case HostComponent: { + var _instance8 = finishedWork.stateNode; + if (_instance8 != 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 !== null ? current.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( + _instance8, + updatePayload, + type, + oldProps, + newProps, + finishedWork + ); + } + } + return; + } + case HostText: { + invariant( + finishedWork.stateNode !== null, + "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 !== null ? current.memoizedProps : newText; + commitTextUpdate(textInstance, oldText, newText); + return; + } + case HostRoot: { + return; + } + default: { + invariant( + false, + "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 commitResetTextContent(current) { + resetTextContent(current.stateNode); + } + + if (enableMutatingReconciler) { + return { + commitBeforeMutationLifeCycles: commitBeforeMutationLifeCycles, + commitResetTextContent: commitResetTextContent, + commitPlacement: commitPlacement, + commitDeletion: commitDeletion, + commitWork: commitWork, + commitLifeCycles: commitLifeCycles, + commitErrorLogging: commitErrorLogging, + commitAttachRef: commitAttachRef, + commitDetachRef: commitDetachRef + }; + } else { + invariant(false, "Mutating reconciler is disabled."); + } +}; + +var NO_CONTEXT = {}; + +var ReactFiberHostContext = function(config, stack) { + var getChildHostContext = config.getChildHostContext, + getRootHostContext = config.getRootHostContext; + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop; + + var contextStackCursor = createCursor(NO_CONTEXT); + var contextFiberStackCursor = createCursor(NO_CONTEXT); + var rootInstanceStackCursor = createCursor(NO_CONTEXT); + + function requiredContext(c) { + invariant( + c !== NO_CONTEXT, + "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, NO_CONTEXT, fiber); + var nextRootContext = getRootHostContext(nextRootInstance); + // Now that we know this function doesn't throw, replace it. + pop(contextStackCursor, fiber); + push(contextStackCursor, nextRootContext, fiber); + } + + function popHostContainer(fiber) { + pop(contextStackCursor, fiber); + pop(contextFiberStackCursor, fiber); + pop(rootInstanceStackCursor, fiber); + } + + function getHostContext() { + var context = requiredContext(contextStackCursor.current); + return context; + } + + function pushHostContext(fiber) { + var rootInstance = requiredContext(rootInstanceStackCursor.current); + var context = requiredContext(contextStackCursor.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, 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, fiber); + pop(contextFiberStackCursor, fiber); + } + + return { + getHostContext: getHostContext, + getRootHostContainer: getRootHostContainer, + popHostContainer: popHostContainer, + popHostContext: popHostContext, + pushHostContainer: pushHostContainer, + pushHostContext: pushHostContext + }; +}; + +var ReactFiberHydrationContext = function(config) { + var shouldSetTextContent = config.shouldSetTextContent, + hydration = config.hydration; + + // If this doesn't have hydration mode. + + if (!hydration) { + return { + enterHydrationState: function() { + return false; + }, + resetHydrationState: function() {}, + tryToClaimNextHydratableInstance: function() {}, + prepareToHydrateHostInstance: function() { + invariant( + false, + "Expected prepareToHydrateHostInstance() to never be called. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + }, + prepareToHydrateHostTextInstance: function() { + invariant( + false, + "Expected prepareToHydrateHostTextInstance() to never be called. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + }, + popHydrationState: function(fiber) { + return false; + } + }; + } + + var canHydrateInstance = hydration.canHydrateInstance, + canHydrateTextInstance = hydration.canHydrateTextInstance, + getNextHydratableSibling = hydration.getNextHydratableSibling, + getFirstHydratableChild = hydration.getFirstHydratableChild, + hydrateInstance = hydration.hydrateInstance, + hydrateTextInstance = hydration.hydrateTextInstance, + didNotMatchHydratedContainerTextInstance = + hydration.didNotMatchHydratedContainerTextInstance, + didNotMatchHydratedTextInstance = hydration.didNotMatchHydratedTextInstance, + didNotHydrateContainerInstance = hydration.didNotHydrateContainerInstance, + didNotHydrateInstance = hydration.didNotHydrateInstance, + didNotFindHydratableContainerInstance = + hydration.didNotFindHydratableContainerInstance, + didNotFindHydratableContainerTextInstance = + hydration.didNotFindHydratableContainerTextInstance, + didNotFindHydratableInstance = hydration.didNotFindHydratableInstance, + didNotFindHydratableTextInstance = + hydration.didNotFindHydratableTextInstance; + + // 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) { + var parentInstance = fiber.stateNode.containerInfo; + nextHydratableInstance = getFirstHydratableChild(parentInstance); + hydrationParentFiber = 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; + } + 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; + } + 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; + } + 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; + } + 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(nextInstance); + 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, nextHydratableInstance); + } + hydrationParentFiber = fiber; + nextHydratableInstance = getFirstHydratableChild(nextInstance); + } + + function prepareToHydrateHostInstance( + fiber, + rootContainerInstance, + hostContext + ) { + 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) { + 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 popToNextHostParent(fiber) { + var parent = fiber["return"]; + while ( + parent !== null && + parent.tag !== HostComponent && + parent.tag !== HostRoot + ) { + parent = parent["return"]; + } + hydrationParentFiber = parent; + } + + function popHydrationState(fiber) { + 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() { + hydrationParentFiber = null; + nextHydratableInstance = null; + isHydrating = false; + } + + return { + enterHydrationState: enterHydrationState, + resetHydrationState: resetHydrationState, + tryToClaimNextHydratableInstance: tryToClaimNextHydratableInstance, + prepareToHydrateHostInstance: prepareToHydrateHostInstance, + prepareToHydrateHostTextInstance: prepareToHydrateHostTextInstance, + popHydrationState: popHydrationState + }; +}; + +// 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; + +var warnedAboutMissingGetChildContext = void 0; + +{ + warnedAboutMissingGetChildContext = {}; +} + +var ReactFiberLegacyContext = function(stack) { + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop; + + // A cursor to the current merged context object on the stack. + + var contextStackCursor = createCursor(emptyObject); + // 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 = emptyObject; + + function getUnmaskedContext(workInProgress) { + var hasOwnContext = isContextProvider(workInProgress); + if (hasOwnContext) { + // If the fiber is a context provider itself, when we read its context + // we 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 emptyObject; + } + + // 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(workInProgress) || "Unknown"; + checkPropTypes( + contextTypes, + context, + "context", + name, + ReactDebugCurrentFiber.getCurrentFiberStackAddendum + ); + } + + // 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 isContextConsumer(fiber) { + return fiber.tag === ClassComponent && fiber.type.contextTypes != null; + } + + function isContextProvider(fiber) { + return fiber.tag === ClassComponent && fiber.type.childContextTypes != null; + } + + function popContextProvider(fiber) { + if (!isContextProvider(fiber)) { + return; + } + + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); + } + + function popTopLevelContextObject(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); + } + + function pushTopLevelContextObject(fiber, context, didChange) { + invariant( + contextStackCursor.cursor == null, + "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, parentContext) { + var instance = fiber.stateNode; + var childContextTypes = fiber.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(fiber) || "Unknown"; + + if (!warnedAboutMissingGetChildContext[componentName]) { + warnedAboutMissingGetChildContext[componentName] = true; + warning( + 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; + { + ReactDebugCurrentFiber.setCurrentPhase("getChildContext"); + } + startPhaseTimer(fiber, "getChildContext"); + childContext = instance.getChildContext(); + stopPhaseTimer(); + { + ReactDebugCurrentFiber.setCurrentPhase(null); + } + for (var contextKey in childContext) { + invariant( + contextKey in childContextTypes, + '%s.getChildContext(): key "%s" is not defined in childContextTypes.', + getComponentName(fiber) || "Unknown", + contextKey + ); + } + { + var name = getComponentName(fiber) || "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. + ReactDebugCurrentFiber.getCurrentFiberStackAddendum + ); + } + + return Object.assign({}, parentContext, childContext); + } + + function pushContextProvider(workInProgress) { + if (!isContextProvider(workInProgress)) { + return false; + } + + 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) || + emptyObject; + + // 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, didChange) { + var instance = workInProgress.stateNode; + invariant( + instance, + "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, 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 + invariant( + isFiberMounted(fiber) && fiber.tag === ClassComponent, + "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; + while (node.tag !== HostRoot) { + if (isContextProvider(node)) { + return node.stateNode.__reactInternalMemoizedMergedChildContext; + } + var parent = node["return"]; + invariant( + parent, + "Found unexpected detached subtree parent. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + node = parent; + } + return node.stateNode.context; + } + + return { + getUnmaskedContext: getUnmaskedContext, + cacheContext: cacheContext, + getMaskedContext: getMaskedContext, + hasContextChanged: hasContextChanged, + isContextConsumer: isContextConsumer, + isContextProvider: isContextProvider, + popContextProvider: popContextProvider, + popTopLevelContextObject: popTopLevelContextObject, + pushTopLevelContextObject: pushTopLevelContextObject, + processChildContext: processChildContext, + pushContextProvider: pushContextProvider, + invalidateContextProvider: invalidateContextProvider, + findCurrentUnmaskedContext: findCurrentUnmaskedContext + }; +}; + +var ReactFiberNewContext = function(stack) { + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop; + + var providerCursor = createCursor(null); + var valueCursor = createCursor(null); + var changedBitsCursor = createCursor(0); + + var rendererSigil = void 0; + { + // Use this to detect multiple renderers using the same context + rendererSigil = {}; + } + + function pushProvider(providerFiber) { + var context = providerFiber.type._context; + + push(changedBitsCursor, context._changedBits, providerFiber); + push(valueCursor, context._currentValue, providerFiber); + push(providerCursor, providerFiber, providerFiber); + + context._currentValue = providerFiber.pendingProps.value; + context._changedBits = providerFiber.stateNode; + + { + !( + context._currentRenderer === null || + context._currentRenderer === rendererSigil + ) + ? warning( + false, + "Detected multiple renderers concurrently rendering the " + + "same context provider. This is currently unsupported." + ) + : void 0; + context._currentRenderer = rendererSigil; + } + } + + function popProvider(providerFiber) { + var changedBits = changedBitsCursor.current; + var currentValue = valueCursor.current; + + pop(providerCursor, providerFiber); + pop(valueCursor, providerFiber); + pop(changedBitsCursor, providerFiber); + + var context = providerFiber.type._context; + context._currentValue = currentValue; + context._changedBits = changedBits; + } + + return { + pushProvider: pushProvider, + popProvider: popProvider + }; +}; + +var ReactFiberStack = function() { + var valueStack = []; + + var fiberStack = void 0; + + { + fiberStack = []; + } + + var index = -1; + + function createCursor(defaultValue) { + return { + current: defaultValue + }; + } + + function isEmpty() { + return index === -1; + } + + function pop(cursor, fiber) { + if (index < 0) { + { + warning(false, "Unexpected pop."); + } + return; + } + + { + if (fiber !== fiberStack[index]) { + warning(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; + } + + function checkThatStackIsEmpty() { + { + if (index !== -1) { + warning( + false, + "Expected an empty stack. Something was not reset properly." + ); + } + } + } + + function resetStackAfterFatalErrorInDev() { + { + index = -1; + valueStack.length = 0; + fiberStack.length = 0; + } + } + + return { + createCursor: createCursor, + isEmpty: isEmpty, + pop: pop, + push: push, + checkThatStackIsEmpty: checkThatStackIsEmpty, + resetStackAfterFatalErrorInDev: resetStackAfterFatalErrorInDev + }; +}; + +var invokeGuardedCallback$2 = ReactErrorUtils.invokeGuardedCallback; +var hasCaughtError = ReactErrorUtils.hasCaughtError; +var clearCaughtError = ReactErrorUtils.clearCaughtError; + +var didWarnAboutStateTransition = void 0; +var didWarnSetStateChildContext = void 0; +var warnAboutUpdateOnUnmounted = void 0; +var warnAboutInvalidUpdates = void 0; + +{ + didWarnAboutStateTransition = false; + didWarnSetStateChildContext = false; + var didWarnStateUpdateForUnmountedComponent = {}; + + warnAboutUpdateOnUnmounted = function(fiber) { + // 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) || "ReactClass"; + if (didWarnStateUpdateForUnmountedComponent[componentName]) { + return; + } + warning( + false, + "Can't call setState (or forceUpdate) 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 the " + + "componentWillUnmount method.%s", + getStackAddendumByWorkInProgressFiber(fiber) + ); + didWarnStateUpdateForUnmountedComponent[componentName] = true; + }; + + warnAboutInvalidUpdates = function(instance) { + switch (ReactDebugCurrentFiber.phase) { + case "getChildContext": + if (didWarnSetStateChildContext) { + return; + } + warning( + false, + "setState(...): Cannot call setState() inside getChildContext()" + ); + didWarnSetStateChildContext = true; + break; + case "render": + if (didWarnAboutStateTransition) { + return; + } + warning( + false, + "Cannot update during an existing state transition (such as within " + + "`render` or another component's constructor). Render methods should " + + "be a pure function of props and state; constructor side-effects are " + + "an anti-pattern, but can be moved to `componentWillMount`." + ); + didWarnAboutStateTransition = true; + break; + } + }; +} + +var ReactFiberScheduler = function(config) { + var stack = ReactFiberStack(); + var hostContext = ReactFiberHostContext(config, stack); + var legacyContext = ReactFiberLegacyContext(stack); + var newContext = ReactFiberNewContext(stack); + var popHostContext = hostContext.popHostContext, + popHostContainer = hostContext.popHostContainer; + var popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject, + popLegacyContextProvider = legacyContext.popContextProvider; + var popProvider = newContext.popProvider; + + var hydrationContext = ReactFiberHydrationContext(config); + + var _ReactFiberBeginWork = ReactFiberBeginWork( + config, + hostContext, + legacyContext, + newContext, + hydrationContext, + scheduleWork, + computeExpirationForFiber + ), + beginWork = _ReactFiberBeginWork.beginWork; + + var _ReactFiberCompleteWo = ReactFiberCompleteWork( + config, + hostContext, + legacyContext, + newContext, + hydrationContext + ), + completeWork = _ReactFiberCompleteWo.completeWork; + + var _ReactFiberUnwindWork = ReactFiberUnwindWork( + hostContext, + legacyContext, + newContext, + scheduleWork, + isAlreadyFailedLegacyErrorBoundary + ), + throwException = _ReactFiberUnwindWork.throwException, + unwindWork = _ReactFiberUnwindWork.unwindWork, + unwindInterruptedWork = _ReactFiberUnwindWork.unwindInterruptedWork; + + var _ReactFiberCommitWork = ReactFiberCommitWork( + config, + onCommitPhaseError, + scheduleWork, + computeExpirationForFiber, + markLegacyErrorBoundaryAsFailed, + recalculateCurrentTime + ), + commitBeforeMutationLifeCycles = + _ReactFiberCommitWork.commitBeforeMutationLifeCycles, + commitResetTextContent = _ReactFiberCommitWork.commitResetTextContent, + commitPlacement = _ReactFiberCommitWork.commitPlacement, + commitDeletion = _ReactFiberCommitWork.commitDeletion, + commitWork = _ReactFiberCommitWork.commitWork, + commitLifeCycles = _ReactFiberCommitWork.commitLifeCycles, + commitErrorLogging = _ReactFiberCommitWork.commitErrorLogging, + commitAttachRef = _ReactFiberCommitWork.commitAttachRef, + commitDetachRef = _ReactFiberCommitWork.commitDetachRef; + + var now = config.now, + scheduleDeferredCallback = config.scheduleDeferredCallback, + cancelDeferredCallback = config.cancelDeferredCallback, + prepareForCommit = config.prepareForCommit, + resetAfterCommit = config.resetAfterCommit; + + // Represents the current time in ms. + + var originalStartTimeMs = now(); + var mostRecentCurrentTime = msToExpirationTime(0); + var mostRecentCurrentTimeMs = originalStartTimeMs; + + // Used to ensure computeUniqueAsyncExpiration is monotonically increases. + var lastUniqueAsyncExpiration = 0; + + // Represents the expiration time that incoming updates should use. (If this + // is NoWork, use the default strategy: async updates in async mode, sync + // updates in sync mode.) + var expirationContext = NoWork; + + var isWorking = false; + + // The next work in progress fiber that we're currently working on. + var nextUnitOfWork = null; + var nextRoot = null; + // The time at which we're currently rendering work. + var nextRenderExpirationTime = NoWork; + + // The next fiber with an effect that we're currently committing. + var nextEffect = null; + + var isCommitting = false; + + var isRootReadyForCommit = false; + + var legacyErrorBoundariesThatAlreadyFailed = null; + + // Used for performance tracking. + var interruptedBy = null; + + var stashedWorkInProgressProperties = void 0; + var replayUnitOfWork = void 0; + var isReplayingFailedUnitOfWork = void 0; + var originalReplayError = void 0; + var rethrowOriginalError = void 0; + if (true && replayFailedUnitOfWorkWithInvokeGuardedCallback) { + stashedWorkInProgressProperties = null; + isReplayingFailedUnitOfWork = false; + originalReplayError = null; + replayUnitOfWork = function(failedUnitOfWork, error, isAsync) { + // Restore the original state of the work-in-progress + assignFiberPropertiesInDEV( + failedUnitOfWork, + stashedWorkInProgressProperties + ); + switch (failedUnitOfWork.tag) { + case HostRoot: + popHostContainer(failedUnitOfWork); + popTopLevelLegacyContextObject(failedUnitOfWork); + break; + case HostComponent: + popHostContext(failedUnitOfWork); + break; + case ClassComponent: + popLegacyContextProvider(failedUnitOfWork); + break; + case HostPortal: + popHostContainer(failedUnitOfWork); + break; + case ContextProvider: + popProvider(failedUnitOfWork); + break; + } + // Replay the begin phase. + isReplayingFailedUnitOfWork = true; + originalReplayError = error; + invokeGuardedCallback$2(null, workLoop, null, isAsync); + isReplayingFailedUnitOfWork = false; + originalReplayError = null; + if (hasCaughtError()) { + clearCaughtError(); + } else { + // If the begin phase did not fail the second time, set this pointer + // back to the original value. + nextUnitOfWork = failedUnitOfWork; + } + }; + rethrowOriginalError = function() { + throw originalReplayError; + }; + } + + function resetStack() { + if (nextUnitOfWork !== null) { + var interruptedWork = nextUnitOfWork["return"]; + while (interruptedWork !== null) { + unwindInterruptedWork(interruptedWork); + interruptedWork = interruptedWork["return"]; + } + } + + { + ReactStrictModeWarnings.discardPendingWarnings(); + stack.checkThatStackIsEmpty(); + } + + nextRoot = null; + nextRenderExpirationTime = NoWork; + nextUnitOfWork = null; + + isRootReadyForCommit = false; + } + + function commitAllHostEffects() { + while (nextEffect !== null) { + { + ReactDebugCurrentFiber.setCurrentFiber(nextEffect); + } + recordEffect(); + + var effectTag = nextEffect.effectTag; + + if (effectTag & ContentReset) { + commitResetTextContent(nextEffect); + } + + if (effectTag & Ref) { + var current = nextEffect.alternate; + if (current !== null) { + commitDetachRef(current); + } + } + + // 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; + } + } + nextEffect = nextEffect.nextEffect; + } + + { + ReactDebugCurrentFiber.resetCurrentFiber(); + } + } + + function commitBeforeMutationLifecycles() { + while (nextEffect !== null) { + var effectTag = nextEffect.effectTag; + + if (effectTag & Snapshot) { + recordEffect(); + var current = nextEffect.alternate; + commitBeforeMutationLifeCycles(current, nextEffect); + } + + // Don't cleanup effects yet; + // This will be done by commitAllLifeCycles() + nextEffect = nextEffect.nextEffect; + } + } + + function commitAllLifeCycles( + finishedRoot, + currentTime, + committedExpirationTime + ) { + { + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings(); + + if (warnAboutDeprecatedLifecycles) { + ReactStrictModeWarnings.flushPendingDeprecationWarnings(); + } + } + while (nextEffect !== null) { + var effectTag = nextEffect.effectTag; + + if (effectTag & (Update | Callback)) { + recordEffect(); + var current = nextEffect.alternate; + commitLifeCycles( + finishedRoot, + current, + nextEffect, + currentTime, + committedExpirationTime + ); + } + + if (effectTag & ErrLog) { + commitErrorLogging(nextEffect, onUncaughtError); + } + + if (effectTag & Ref) { + recordEffect(); + commitAttachRef(nextEffect); + } + + var next = nextEffect.nextEffect; + // Ensure that we clean these up so that we don't accidentally keep them. + // I'm not actually sure this matters because we can't reset firstEffect + // and lastEffect since they're on every node, not just the effectful + // ones. So we have to clean everything as we reuse nodes anyway. + nextEffect.nextEffect = null; + // Ensure that we reset the effectTag here so that we can rely on effect + // tags to reason about the current life-cycle. + nextEffect = next; + } + } + + function isAlreadyFailedLegacyErrorBoundary(instance) { + return ( + legacyErrorBoundariesThatAlreadyFailed !== null && + legacyErrorBoundariesThatAlreadyFailed.has(instance) + ); + } + + function markLegacyErrorBoundaryAsFailed(instance) { + if (legacyErrorBoundariesThatAlreadyFailed === null) { + legacyErrorBoundariesThatAlreadyFailed = new Set([instance]); + } else { + legacyErrorBoundariesThatAlreadyFailed.add(instance); + } + } + + function commitRoot(finishedWork) { + isWorking = true; + isCommitting = true; + startCommitTimer(); + + var root = finishedWork.stateNode; + invariant( + root.current !== finishedWork, + "Cannot commit the same tree as before. This is probably a bug " + + "related to the return field. This error is likely caused by a bug " + + "in React. Please file an issue." + ); + var committedExpirationTime = root.pendingCommitExpirationTime; + invariant( + committedExpirationTime !== NoWork, + "Cannot commit an incomplete root. This error is likely caused by a " + + "bug in React. Please file an issue." + ); + root.pendingCommitExpirationTime = NoWork; + + var currentTime = recalculateCurrentTime(); + + // Reset this to null before calling lifecycles + ReactCurrentOwner.current = null; + + 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; + } + + prepareForCommit(root.containerInfo); + + // Invoke instances of getSnapshotBeforeUpdate before mutation. + nextEffect = firstEffect; + startCommitSnapshotEffectsTimer(); + while (nextEffect !== null) { + var didError = false; + var error = void 0; + { + invokeGuardedCallback$2(null, commitBeforeMutationLifecycles, null); + if (hasCaughtError()) { + didError = true; + error = clearCaughtError(); + } + } + if (didError) { + invariant( + nextEffect !== null, + "Should have next effect. This error is likely caused by a bug " + + "in React. Please file an issue." + ); + onCommitPhaseError(nextEffect, error); + // Clean-up + if (nextEffect !== null) { + nextEffect = nextEffect.nextEffect; + } + } + } + stopCommitSnapshotEffectsTimer(); + + // Commit all the side-effects within a tree. We'll do this in two passes. + // The first pass performs all the host insertions, updates, deletions and + // ref unmounts. + nextEffect = firstEffect; + startCommitHostEffectsTimer(); + while (nextEffect !== null) { + var _didError = false; + var _error = void 0; + { + invokeGuardedCallback$2(null, commitAllHostEffects, null); + if (hasCaughtError()) { + _didError = true; + _error = clearCaughtError(); + } + } + if (_didError) { + invariant( + nextEffect !== null, + "Should have next effect. This error is likely caused by a bug " + + "in React. Please file an issue." + ); + onCommitPhaseError(nextEffect, _error); + // Clean-up + if (nextEffect !== null) { + nextEffect = nextEffect.nextEffect; + } + } + } + stopCommitHostEffectsTimer(); + + resetAfterCommit(root.containerInfo); + + // The work-in-progress tree is now the current tree. This must come after + // the first pass of the commit phase, so that the previous tree is still + // current during componentWillUnmount, but before the second pass, so that + // the finished work is current during componentDidMount/Update. + root.current = finishedWork; + + // In the second pass we'll perform all life-cycles and ref callbacks. + // Life-cycles happen as a separate pass so that all placements, updates, + // and deletions in the entire tree have already been invoked. + // This pass also triggers any renderer-specific initial effects. + nextEffect = firstEffect; + startCommitLifeCyclesTimer(); + while (nextEffect !== null) { + var _didError2 = false; + var _error2 = void 0; + { + invokeGuardedCallback$2( + null, + commitAllLifeCycles, + null, + root, + currentTime, + committedExpirationTime + ); + if (hasCaughtError()) { + _didError2 = true; + _error2 = clearCaughtError(); + } + } + if (_didError2) { + invariant( + nextEffect !== null, + "Should have next effect. This error is likely caused by a bug " + + "in React. Please file an issue." + ); + onCommitPhaseError(nextEffect, _error2); + if (nextEffect !== null) { + nextEffect = nextEffect.nextEffect; + } + } + } + + isCommitting = false; + isWorking = false; + stopCommitLifeCyclesTimer(); + stopCommitTimer(); + if (typeof onCommitRoot === "function") { + onCommitRoot(finishedWork.stateNode); + } + if (true && ReactFiberInstrumentation_1.debugTool) { + ReactFiberInstrumentation_1.debugTool.onCommitWork(finishedWork); + } + + var remainingTime = root.current.expirationTime; + if (remainingTime === NoWork) { + // If there's no remaining work, we can clear the set of already failed + // error boundaries. + legacyErrorBoundariesThatAlreadyFailed = null; + } + return remainingTime; + } + + function resetExpirationTime(workInProgress, renderTime) { + if (renderTime !== Never && workInProgress.expirationTime === Never) { + // The children of this component are hidden. Don't bubble their + // expiration times. + return; + } + + // Check for pending updates. + var newExpirationTime = getUpdateExpirationTime(workInProgress); + + // TODO: Calls need to visit stateNode + + // Bubble up the earliest expiration time. + var child = workInProgress.child; + while (child !== null) { + if ( + child.expirationTime !== NoWork && + (newExpirationTime === NoWork || + newExpirationTime > child.expirationTime) + ) { + newExpirationTime = child.expirationTime; + } + child = child.sibling; + } + workInProgress.expirationTime = newExpirationTime; + } + + function completeUnitOfWork(workInProgress) { + // 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. + while (true) { + // 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 = workInProgress.alternate; + { + ReactDebugCurrentFiber.setCurrentFiber(workInProgress); + } + + var returnFiber = workInProgress["return"]; + var siblingFiber = workInProgress.sibling; + + if ((workInProgress.effectTag & Incomplete) === NoEffect) { + // This fiber completed. + var next = completeWork( + current, + workInProgress, + nextRenderExpirationTime + ); + stopWorkTimer(workInProgress); + resetExpirationTime(workInProgress, nextRenderExpirationTime); + { + ReactDebugCurrentFiber.resetCurrentFiber(); + } + + if (next !== null) { + stopWorkTimer(workInProgress); + if (true && ReactFiberInstrumentation_1.debugTool) { + ReactFiberInstrumentation_1.debugTool.onCompleteWork( + workInProgress + ); + } + // If completing this work spawned new work, do that next. We'll come + // back here again. + 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; + } + } + + if (true && ReactFiberInstrumentation_1.debugTool) { + ReactFiberInstrumentation_1.debugTool.onCompleteWork(workInProgress); + } + + if (siblingFiber !== null) { + // If there is more work to do in this returnFiber, do that next. + return siblingFiber; + } else if (returnFiber !== null) { + // If there's no more work in this returnFiber. Complete the returnFiber. + workInProgress = returnFiber; + continue; + } else { + // We've reached the root. + isRootReadyForCommit = true; + return null; + } + } 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); + // Because this fiber did not complete, don't reset its expiration time. + if (workInProgress.effectTag & DidCapture) { + // Restarting an error boundary + stopFailedWorkTimer(workInProgress); + } else { + stopWorkTimer(workInProgress); + } + + { + ReactDebugCurrentFiber.resetCurrentFiber(); + } + + if (_next !== null) { + stopWorkTimer(workInProgress); + if (true && ReactFiberInstrumentation_1.debugTool) { + ReactFiberInstrumentation_1.debugTool.onCompleteWork( + workInProgress + ); + } + // 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. + _next.effectTag &= HostEffectMask; + return _next; + } + + if (returnFiber !== null) { + // Mark the parent fiber as incomplete and clear its effect list. + returnFiber.firstEffect = returnFiber.lastEffect = null; + returnFiber.effectTag |= Incomplete; + } + + if (true && ReactFiberInstrumentation_1.debugTool) { + ReactFiberInstrumentation_1.debugTool.onCompleteWork(workInProgress); + } + + if (siblingFiber !== null) { + // If there is more work to do in this returnFiber, do that next. + return siblingFiber; + } else if (returnFiber !== null) { + // If there's no more work in this returnFiber. Complete the returnFiber. + workInProgress = returnFiber; + continue; + } else { + return null; + } + } + } + + // Without this explicit null return Flow complains of invalid return type + // TODO Remove the above while(true) loop + // eslint-disable-next-line no-unreachable + return null; + } + + function performUnitOfWork(workInProgress) { + // 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 = workInProgress.alternate; + + // See if beginning this work spawns more work. + startWorkTimer(workInProgress); + { + ReactDebugCurrentFiber.setCurrentFiber(workInProgress); + } + + if (true && replayFailedUnitOfWorkWithInvokeGuardedCallback) { + stashedWorkInProgressProperties = assignFiberPropertiesInDEV( + stashedWorkInProgressProperties, + workInProgress + ); + } + var next = beginWork(current, workInProgress, nextRenderExpirationTime); + { + ReactDebugCurrentFiber.resetCurrentFiber(); + if (isReplayingFailedUnitOfWork) { + // Currently replaying a failed unit of work. This should be unreachable, + // because the render phase is meant to be idempotent, and it should + // have thrown again. Since it didn't, rethrow the original error, so + // React's internal stack is not misaligned. + rethrowOriginalError(); + } + } + if (true && ReactFiberInstrumentation_1.debugTool) { + ReactFiberInstrumentation_1.debugTool.onBeginWork(workInProgress); + } + + if (next === null) { + // If this doesn't spawn new work, complete the current work. + next = completeUnitOfWork(workInProgress); + } + + ReactCurrentOwner.current = null; + + return next; + } + + function workLoop(isAsync) { + if (!isAsync) { + // Flush all expired work. + while (nextUnitOfWork !== null) { + nextUnitOfWork = performUnitOfWork(nextUnitOfWork); + } + } else { + // Flush asynchronous work until the deadline runs out of time. + while (nextUnitOfWork !== null && !shouldYield()) { + nextUnitOfWork = performUnitOfWork(nextUnitOfWork); + } + } + } + + function renderRoot(root, expirationTime, isAsync) { + invariant( + !isWorking, + "renderRoot was called recursively. This error is likely caused " + + "by a bug in React. Please file an issue." + ); + isWorking = true; + + // Check if we're starting from a fresh stack, or if we're resuming from + // previously yielded work. + if ( + expirationTime !== nextRenderExpirationTime || + root !== nextRoot || + nextUnitOfWork === null + ) { + // Reset the stack and start working from the root. + resetStack(); + nextRoot = root; + nextRenderExpirationTime = expirationTime; + nextUnitOfWork = createWorkInProgress( + nextRoot.current, + null, + nextRenderExpirationTime + ); + root.pendingCommitExpirationTime = NoWork; + } + + var didFatal = false; + + startWorkLoopTimer(nextUnitOfWork); + + do { + try { + workLoop(isAsync); + } catch (thrownValue) { + if (nextUnitOfWork === null) { + // This is a fatal error. + didFatal = true; + onUncaughtError(thrownValue); + break; + } + + if (true && replayFailedUnitOfWorkWithInvokeGuardedCallback) { + var failedUnitOfWork = nextUnitOfWork; + replayUnitOfWork(failedUnitOfWork, thrownValue, isAsync); + } + + var sourceFiber = nextUnitOfWork; + var returnFiber = sourceFiber["return"]; + if (returnFiber === null) { + // This is the root. The root could capture its own errors. However, + // we don't know if it errors before or after we pushed the host + // context. This information is needed to avoid a stack mismatch. + // Because we're not sure, treat this as a fatal error. We could track + // which phase it fails in, but doesn't seem worth it. At least + // for now. + didFatal = true; + onUncaughtError(thrownValue); + break; + } + throwException(returnFiber, sourceFiber, thrownValue); + nextUnitOfWork = completeUnitOfWork(sourceFiber); + } + break; + } while (true); + + // We're done performing work. Time to clean up. + var didCompleteRoot = false; + isWorking = false; + + // Yield back to main thread. + if (didFatal) { + stopWorkLoopTimer(interruptedBy, didCompleteRoot); + interruptedBy = null; + // There was a fatal error. + { + stack.resetStackAfterFatalErrorInDev(); + } + return null; + } else if (nextUnitOfWork === null) { + // We reached the root. + if (isRootReadyForCommit) { + didCompleteRoot = true; + stopWorkLoopTimer(interruptedBy, didCompleteRoot); + interruptedBy = null; + // The root successfully completed. It's ready for commit. + root.pendingCommitExpirationTime = expirationTime; + var finishedWork = root.current.alternate; + return finishedWork; + } else { + // The root did not complete. + stopWorkLoopTimer(interruptedBy, didCompleteRoot); + interruptedBy = null; + invariant( + false, + "Expired work should have completed. This error is likely caused " + + "by a bug in React. Please file an issue." + ); + } + } else { + stopWorkLoopTimer(interruptedBy, didCompleteRoot); + interruptedBy = null; + // There's more work to do, but we ran out of time. Yield back to + // the renderer. + return null; + } + } + + function scheduleCapture(sourceFiber, boundaryFiber, value, expirationTime) { + // TODO: We only support dispatching errors. + var capturedValue = createCapturedValue(value, sourceFiber); + var update = { + expirationTime: expirationTime, + partialState: null, + callback: null, + isReplace: false, + isForced: false, + capturedValue: capturedValue, + next: null + }; + insertUpdateIntoFiber(boundaryFiber, update); + scheduleWork(boundaryFiber, expirationTime); + } + + function dispatch(sourceFiber, value, expirationTime) { + invariant( + !isWorking || isCommitting, + "dispatch: Cannot dispatch during the render phase." + ); + + // TODO: Handle arrays + + var fiber = sourceFiber["return"]; + while (fiber !== null) { + switch (fiber.tag) { + case ClassComponent: + var ctor = fiber.type; + var instance = fiber.stateNode; + if ( + typeof ctor.getDerivedStateFromCatch === "function" || + (typeof instance.componentDidCatch === "function" && + !isAlreadyFailedLegacyErrorBoundary(instance)) + ) { + scheduleCapture(sourceFiber, fiber, value, expirationTime); + return; + } + break; + // TODO: Handle async boundaries + case HostRoot: + scheduleCapture(sourceFiber, fiber, value, expirationTime); + return; + } + fiber = fiber["return"]; + } + + if (sourceFiber.tag === HostRoot) { + // Error was thrown at the root. There is no parent, so the root + // itself should capture it. + scheduleCapture(sourceFiber, sourceFiber, value, expirationTime); + } + } + + function onCommitPhaseError(fiber, error) { + return dispatch(fiber, error, Sync); + } + + function computeAsyncExpiration(currentTime) { + // Given the current clock time, returns an expiration time. We use rounding + // to batch like updates together. + // Should complete within ~1000ms. 1200ms max. + var expirationMs = 5000; + var bucketSizeMs = 250; + return computeExpirationBucket(currentTime, expirationMs, bucketSizeMs); + } + + function computeInteractiveExpiration(currentTime) { + var expirationMs = void 0; + // 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. + { + // Should complete within ~500ms. 600ms max. + expirationMs = 500; + } + var bucketSizeMs = 100; + return computeExpirationBucket(currentTime, expirationMs, bucketSizeMs); + } + + // Creates a unique async expiration time. + function computeUniqueAsyncExpiration() { + var currentTime = recalculateCurrentTime(); + var result = computeAsyncExpiration(currentTime); + if (result <= lastUniqueAsyncExpiration) { + // Since we assume the current time monotonically increases, we only hit + // this branch when computeUniqueAsyncExpiration is fired multiple times + // within a 200ms window (or whatever the async bucket size is). + result = lastUniqueAsyncExpiration + 1; + } + lastUniqueAsyncExpiration = result; + return lastUniqueAsyncExpiration; + } + + function computeExpirationForFiber(fiber) { + var expirationTime = void 0; + if (expirationContext !== NoWork) { + // An explicit expiration context was set; + expirationTime = expirationContext; + } else if (isWorking) { + if (isCommitting) { + // Updates that occur during the commit phase should have sync priority + // by default. + expirationTime = Sync; + } else { + // Updates during the render phase should expire at the same time as + // the work that is being rendered. + expirationTime = nextRenderExpirationTime; + } + } else { + // No explicit expiration context was set, and we're not currently + // performing work. Calculate a new expiration time. + if (fiber.mode & AsyncMode) { + if (isBatchingInteractiveUpdates) { + // This is an interactive update + var currentTime = recalculateCurrentTime(); + expirationTime = computeInteractiveExpiration(currentTime); + } else { + // This is an async update + var _currentTime = recalculateCurrentTime(); + expirationTime = computeAsyncExpiration(_currentTime); + } + } else { + // This is a sync update + expirationTime = Sync; + } + } + if (isBatchingInteractiveUpdates) { + // This is an interactive update. Keep track of the lowest pending + // interactive expiration time. This allows us to synchronously flush + // all interactive updates when needed. + if ( + lowestPendingInteractiveExpirationTime === NoWork || + expirationTime > lowestPendingInteractiveExpirationTime + ) { + lowestPendingInteractiveExpirationTime = expirationTime; + } + } + return expirationTime; + } + + function scheduleWork(fiber, expirationTime) { + return scheduleWorkImpl(fiber, expirationTime, false); + } + + function scheduleWorkImpl(fiber, expirationTime, isErrorRecovery) { + recordScheduleUpdate(); + + { + if (!isErrorRecovery && fiber.tag === ClassComponent) { + var instance = fiber.stateNode; + warnAboutInvalidUpdates(instance); + } + } + + var node = fiber; + while (node !== null) { + // Walk the parent path to the root and update each node's + // expiration time. + if ( + node.expirationTime === NoWork || + node.expirationTime > expirationTime + ) { + node.expirationTime = expirationTime; + } + if (node.alternate !== null) { + if ( + node.alternate.expirationTime === NoWork || + node.alternate.expirationTime > expirationTime + ) { + node.alternate.expirationTime = expirationTime; + } + } + if (node["return"] === null) { + if (node.tag === HostRoot) { + var root = node.stateNode; + if ( + !isWorking && + nextRenderExpirationTime !== NoWork && + expirationTime < nextRenderExpirationTime + ) { + // This is an interruption. (Used for performance tracking.) + interruptedBy = fiber; + resetStack(); + } + if ( + // If we're in the render phase, we don't need to schedule this root + // for an update, because we'll do it before we exit... + !isWorking || + isCommitting || + // ...unless this is a different root than the one we're rendering. + nextRoot !== root + ) { + // Add this root to the root schedule. + requestWork(root, expirationTime); + } + if (nestedUpdateCount > NESTED_UPDATE_LIMIT) { + invariant( + false, + "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." + ); + } + } else { + { + if (!isErrorRecovery && fiber.tag === ClassComponent) { + warnAboutUpdateOnUnmounted(fiber); + } + } + return; + } + } + node = node["return"]; + } + } + + function recalculateCurrentTime() { + // Subtract initial time so it fits inside 32bits + mostRecentCurrentTimeMs = now() - originalStartTimeMs; + mostRecentCurrentTime = msToExpirationTime(mostRecentCurrentTimeMs); + return mostRecentCurrentTime; + } + + function deferredUpdates(fn) { + var previousExpirationContext = expirationContext; + var currentTime = recalculateCurrentTime(); + expirationContext = computeAsyncExpiration(currentTime); + try { + return fn(); + } finally { + expirationContext = previousExpirationContext; + } + } + function syncUpdates(fn, a, b, c, d) { + var previousExpirationContext = expirationContext; + expirationContext = Sync; + try { + return fn(a, b, c, d); + } finally { + expirationContext = previousExpirationContext; + } + } + + // TODO: Everything below this is written as if it has been lifted to the + // renderers. I'll do this in a follow-up. + + // Linked-list of roots + var firstScheduledRoot = null; + var lastScheduledRoot = null; + + var callbackExpirationTime = NoWork; + var callbackID = -1; + var isRendering = false; + var nextFlushedRoot = null; + var nextFlushedExpirationTime = NoWork; + var lowestPendingInteractiveExpirationTime = NoWork; + var deadlineDidExpire = false; + var hasUnhandledError = false; + var unhandledError = null; + var deadline = null; + + var isBatchingUpdates = false; + var isUnbatchingUpdates = false; + var isBatchingInteractiveUpdates = false; + + var completedBatches = null; + + // Use these to prevent an infinite loop of nested updates + var NESTED_UPDATE_LIMIT = 1000; + var nestedUpdateCount = 0; + + var timeHeuristicForUnitOfWork = 1; + + function scheduleCallbackWithExpiration(expirationTime) { + if (callbackExpirationTime !== NoWork) { + // A callback is already scheduled. Check its expiration time (timeout). + if (expirationTime > callbackExpirationTime) { + // Existing callback has sufficient timeout. Exit. + return; + } else { + // Existing callback has insufficient timeout. Cancel and schedule a + // new one. + cancelDeferredCallback(callbackID); + } + // The request callback timer is already running. Don't start a new one. + } else { + startRequestCallbackTimer(); + } + + // Compute a timeout for the given expiration time. + var currentMs = now() - originalStartTimeMs; + var expirationMs = expirationTimeToMs(expirationTime); + var timeout = expirationMs - currentMs; + + callbackExpirationTime = expirationTime; + callbackID = scheduleDeferredCallback(performAsyncWork, { + timeout: timeout + }); + } + + // requestWork is called by the scheduler whenever a root receives an update. + // It's up to the renderer to call renderRoot at some point in the future. + function requestWork(root, expirationTime) { + addRootToSchedule(root, expirationTime); + + if (isRendering) { + // Prevent reentrancy. Remaining work will be scheduled at the end of + // the currently rendering batch. + return; + } + + if (isBatchingUpdates) { + // Flush work at the end of the batch. + if (isUnbatchingUpdates) { + // ...unless we're inside unbatchedUpdates, in which case we should + // flush it now. + nextFlushedRoot = root; + nextFlushedExpirationTime = Sync; + performWorkOnRoot(root, Sync, false); + } + return; + } + + // TODO: Get rid of Sync and use current time? + if (expirationTime === Sync) { + performSyncWork(); + } else { + scheduleCallbackWithExpiration(expirationTime); + } + } + + function addRootToSchedule(root, expirationTime) { + // Add the root to the schedule. + // Check if this root is already part of the schedule. + if (root.nextScheduledRoot === null) { + // This root is not already scheduled. Add it. + root.remainingExpirationTime = expirationTime; + if (lastScheduledRoot === null) { + firstScheduledRoot = lastScheduledRoot = root; + root.nextScheduledRoot = root; + } else { + lastScheduledRoot.nextScheduledRoot = root; + lastScheduledRoot = root; + lastScheduledRoot.nextScheduledRoot = firstScheduledRoot; + } + } else { + // This root is already scheduled, but its priority may have increased. + var remainingExpirationTime = root.remainingExpirationTime; + if ( + remainingExpirationTime === NoWork || + expirationTime < remainingExpirationTime + ) { + // Update the priority. + root.remainingExpirationTime = expirationTime; + } + } + } + + function findHighestPriorityRoot() { + var highestPriorityWork = NoWork; + var highestPriorityRoot = null; + if (lastScheduledRoot !== null) { + var previousScheduledRoot = lastScheduledRoot; + var root = firstScheduledRoot; + while (root !== null) { + var remainingExpirationTime = root.remainingExpirationTime; + if (remainingExpirationTime === NoWork) { + // This root no longer has work. Remove it from the scheduler. + + // TODO: This check is redudant, but Flow is confused by the branch + // below where we set lastScheduledRoot to null, even though we break + // from the loop right after. + invariant( + previousScheduledRoot !== null && lastScheduledRoot !== null, + "Should have a previous and last root. This error is likely " + + "caused by a bug in React. Please file an issue." + ); + if (root === root.nextScheduledRoot) { + // This is the only root in the list. + root.nextScheduledRoot = null; + firstScheduledRoot = lastScheduledRoot = null; + break; + } else if (root === firstScheduledRoot) { + // This is the first root in the list. + var next = root.nextScheduledRoot; + firstScheduledRoot = next; + lastScheduledRoot.nextScheduledRoot = next; + root.nextScheduledRoot = null; + } else if (root === lastScheduledRoot) { + // This is the last root in the list. + lastScheduledRoot = previousScheduledRoot; + lastScheduledRoot.nextScheduledRoot = firstScheduledRoot; + root.nextScheduledRoot = null; + break; + } else { + previousScheduledRoot.nextScheduledRoot = root.nextScheduledRoot; + root.nextScheduledRoot = null; + } + root = previousScheduledRoot.nextScheduledRoot; + } else { + if ( + highestPriorityWork === NoWork || + remainingExpirationTime < highestPriorityWork + ) { + // Update the priority, if it's higher + highestPriorityWork = remainingExpirationTime; + highestPriorityRoot = root; + } + if (root === lastScheduledRoot) { + break; + } + previousScheduledRoot = root; + root = root.nextScheduledRoot; + } + } + } + + // If the next root is the same as the previous root, this is a nested + // update. To prevent an infinite loop, increment the nested update count. + var previousFlushedRoot = nextFlushedRoot; + if ( + previousFlushedRoot !== null && + previousFlushedRoot === highestPriorityRoot && + highestPriorityWork === Sync + ) { + nestedUpdateCount++; + } else { + // Reset whenever we switch roots. + nestedUpdateCount = 0; + } + nextFlushedRoot = highestPriorityRoot; + nextFlushedExpirationTime = highestPriorityWork; + } + + function performAsyncWork(dl) { + performWork(NoWork, true, dl); + } + + function performSyncWork() { + performWork(Sync, false, null); + } + + function performWork(minExpirationTime, isAsync, dl) { + deadline = dl; + + // Keep working on roots until there's no more work, or until the we reach + // the deadline. + findHighestPriorityRoot(); + + if (enableUserTimingAPI && deadline !== null) { + var didExpire = nextFlushedExpirationTime < recalculateCurrentTime(); + var timeout = expirationTimeToMs(nextFlushedExpirationTime); + stopRequestCallbackTimer(didExpire, timeout); + } + + if (isAsync) { + while ( + nextFlushedRoot !== null && + nextFlushedExpirationTime !== NoWork && + (minExpirationTime === NoWork || + minExpirationTime >= nextFlushedExpirationTime) && + (!deadlineDidExpire || + recalculateCurrentTime() >= nextFlushedExpirationTime) + ) { + performWorkOnRoot( + nextFlushedRoot, + nextFlushedExpirationTime, + !deadlineDidExpire + ); + findHighestPriorityRoot(); + } + } else { + while ( + nextFlushedRoot !== null && + nextFlushedExpirationTime !== NoWork && + (minExpirationTime === NoWork || + minExpirationTime >= nextFlushedExpirationTime) + ) { + performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime, false); + findHighestPriorityRoot(); + } + } + + // We're done flushing work. Either we ran out of time in this callback, + // or there's no more work left with sufficient priority. + + // If we're inside a callback, set this to false since we just completed it. + if (deadline !== null) { + callbackExpirationTime = NoWork; + callbackID = -1; + } + // If there's work left over, schedule a new callback. + if (nextFlushedExpirationTime !== NoWork) { + scheduleCallbackWithExpiration(nextFlushedExpirationTime); + } + + // Clean-up. + deadline = null; + deadlineDidExpire = false; + + finishRendering(); + } + + function flushRoot(root, expirationTime) { + invariant( + !isRendering, + "work.commit(): Cannot commit while already rendering. This likely " + + "means you attempted to commit from inside a lifecycle method." + ); + // Perform work on root as if the given expiration time is the current time. + // This has the effect of synchronously flushing all work up to and + // including the given time. + nextFlushedRoot = root; + nextFlushedExpirationTime = expirationTime; + performWorkOnRoot(root, expirationTime, false); + // Flush any sync work that was scheduled by lifecycles + performSyncWork(); + finishRendering(); + } + + function finishRendering() { + nestedUpdateCount = 0; + + if (completedBatches !== null) { + var batches = completedBatches; + completedBatches = null; + for (var i = 0; i < batches.length; i++) { + var batch = batches[i]; + try { + batch._onComplete(); + } catch (error) { + if (!hasUnhandledError) { + hasUnhandledError = true; + unhandledError = error; + } + } + } + } + + if (hasUnhandledError) { + var error = unhandledError; + unhandledError = null; + hasUnhandledError = false; + throw error; + } + } + + function performWorkOnRoot(root, expirationTime, isAsync) { + invariant( + !isRendering, + "performWorkOnRoot was called recursively. This error is likely caused " + + "by a bug in React. Please file an issue." + ); + + isRendering = true; + + // Check if this is async work or sync/expired work. + if (!isAsync) { + // Flush sync work. + var finishedWork = root.finishedWork; + if (finishedWork !== null) { + // This root is already complete. We can commit it. + completeRoot(root, finishedWork, expirationTime); + } else { + root.finishedWork = null; + finishedWork = renderRoot(root, expirationTime, false); + if (finishedWork !== null) { + // We've completed the root. Commit it. + completeRoot(root, finishedWork, expirationTime); + } + } + } else { + // Flush async work. + var _finishedWork = root.finishedWork; + if (_finishedWork !== null) { + // This root is already complete. We can commit it. + completeRoot(root, _finishedWork, expirationTime); + } else { + root.finishedWork = null; + _finishedWork = renderRoot(root, expirationTime, true); + if (_finishedWork !== null) { + // We've completed the root. Check the deadline one more time + // before committing. + if (!shouldYield()) { + // Still time left. Commit the root. + completeRoot(root, _finishedWork, expirationTime); + } else { + // There's no time left. Mark this root as complete. We'll come + // back and commit it later. + root.finishedWork = _finishedWork; + } + } + } + } + + isRendering = false; + } + + function completeRoot(root, finishedWork, expirationTime) { + // Check if there's a batch that matches this expiration time. + var firstBatch = root.firstBatch; + if (firstBatch !== null && firstBatch._expirationTime <= expirationTime) { + if (completedBatches === null) { + completedBatches = [firstBatch]; + } else { + completedBatches.push(firstBatch); + } + if (firstBatch._defer) { + // This root is blocked from committing by a batch. Unschedule it until + // we receive another update. + root.finishedWork = finishedWork; + root.remainingExpirationTime = NoWork; + return; + } + } + + // Commit the root. + root.finishedWork = null; + root.remainingExpirationTime = commitRoot(finishedWork); + } + + // When working on async work, the reconciler asks the renderer if it should + // yield execution. For DOM, we implement this with requestIdleCallback. + function shouldYield() { + if (deadline === null) { + return false; + } + if (deadline.timeRemaining() > timeHeuristicForUnitOfWork) { + // Disregard deadline.didTimeout. Only expired work should be flushed + // during a timeout. This path is only hit for non-expired work. + return false; + } + deadlineDidExpire = true; + return true; + } + + function onUncaughtError(error) { + invariant( + nextFlushedRoot !== null, + "Should be working on a root. This error is likely caused by a bug in " + + "React. Please file an issue." + ); + // Unschedule this root so we don't work on it again until there's + // another update. + nextFlushedRoot.remainingExpirationTime = NoWork; + if (!hasUnhandledError) { + hasUnhandledError = true; + unhandledError = error; + } + } + + // TODO: Batching should be implemented at the renderer level, not inside + // the reconciler. + function batchedUpdates(fn, a) { + var previousIsBatchingUpdates = isBatchingUpdates; + isBatchingUpdates = true; + try { + return fn(a); + } finally { + isBatchingUpdates = previousIsBatchingUpdates; + if (!isBatchingUpdates && !isRendering) { + performSyncWork(); + } + } + } + + // TODO: Batching should be implemented at the renderer level, not inside + // the reconciler. + function unbatchedUpdates(fn, a) { + if (isBatchingUpdates && !isUnbatchingUpdates) { + isUnbatchingUpdates = true; + try { + return fn(a); + } finally { + isUnbatchingUpdates = false; + } + } + return fn(a); + } + + // TODO: Batching should be implemented at the renderer level, not within + // the reconciler. + function flushSync(fn, a) { + invariant( + !isRendering, + "flushSync was called from inside a lifecycle method. It cannot be " + + "called when React is already rendering." + ); + var previousIsBatchingUpdates = isBatchingUpdates; + isBatchingUpdates = true; + try { + return syncUpdates(fn, a); + } finally { + isBatchingUpdates = previousIsBatchingUpdates; + performSyncWork(); + } + } + + function interactiveUpdates(fn, a, b) { + if (isBatchingInteractiveUpdates) { + return fn(a, b); + } + // If there are any pending interactive updates, synchronously flush them. + // This needs to happen before we read any handlers, because the effect of + // the previous event may influence which handlers are called during + // this event. + if ( + !isBatchingUpdates && + !isRendering && + lowestPendingInteractiveExpirationTime !== NoWork + ) { + // Synchronously flush pending interactive updates. + performWork(lowestPendingInteractiveExpirationTime, false, null); + lowestPendingInteractiveExpirationTime = NoWork; + } + var previousIsBatchingInteractiveUpdates = isBatchingInteractiveUpdates; + var previousIsBatchingUpdates = isBatchingUpdates; + isBatchingInteractiveUpdates = true; + isBatchingUpdates = true; + try { + return fn(a, b); + } finally { + isBatchingInteractiveUpdates = previousIsBatchingInteractiveUpdates; + isBatchingUpdates = previousIsBatchingUpdates; + if (!isBatchingUpdates && !isRendering) { + performSyncWork(); + } + } + } + + function flushInteractiveUpdates() { + if (!isRendering && lowestPendingInteractiveExpirationTime !== NoWork) { + // Synchronously flush pending interactive updates. + performWork(lowestPendingInteractiveExpirationTime, false, null); + lowestPendingInteractiveExpirationTime = NoWork; + } + } + + function flushControlled(fn) { + var previousIsBatchingUpdates = isBatchingUpdates; + isBatchingUpdates = true; + try { + syncUpdates(fn); + } finally { + isBatchingUpdates = previousIsBatchingUpdates; + if (!isBatchingUpdates && !isRendering) { + performWork(Sync, false, null); + } + } + } + + return { + recalculateCurrentTime: recalculateCurrentTime, + computeExpirationForFiber: computeExpirationForFiber, + scheduleWork: scheduleWork, + requestWork: requestWork, + flushRoot: flushRoot, + batchedUpdates: batchedUpdates, + unbatchedUpdates: unbatchedUpdates, + flushSync: flushSync, + flushControlled: flushControlled, + deferredUpdates: deferredUpdates, + syncUpdates: syncUpdates, + interactiveUpdates: interactiveUpdates, + flushInteractiveUpdates: flushInteractiveUpdates, + computeUniqueAsyncExpiration: computeUniqueAsyncExpiration, + legacyContext: legacyContext + }; +}; + +var didWarnAboutNestedUpdates = void 0; + +{ + didWarnAboutNestedUpdates = false; +} + +// 0 is PROD, 1 is DEV. +// Might add PROFILE later. + +var ReactFiberReconciler$1 = function(config) { + var getPublicInstance = config.getPublicInstance; + + var _ReactFiberScheduler = ReactFiberScheduler(config), + computeUniqueAsyncExpiration = + _ReactFiberScheduler.computeUniqueAsyncExpiration, + recalculateCurrentTime = _ReactFiberScheduler.recalculateCurrentTime, + computeExpirationForFiber = _ReactFiberScheduler.computeExpirationForFiber, + scheduleWork = _ReactFiberScheduler.scheduleWork, + requestWork = _ReactFiberScheduler.requestWork, + flushRoot = _ReactFiberScheduler.flushRoot, + batchedUpdates = _ReactFiberScheduler.batchedUpdates, + unbatchedUpdates = _ReactFiberScheduler.unbatchedUpdates, + flushSync = _ReactFiberScheduler.flushSync, + flushControlled = _ReactFiberScheduler.flushControlled, + deferredUpdates = _ReactFiberScheduler.deferredUpdates, + syncUpdates = _ReactFiberScheduler.syncUpdates, + interactiveUpdates = _ReactFiberScheduler.interactiveUpdates, + flushInteractiveUpdates = _ReactFiberScheduler.flushInteractiveUpdates, + legacyContext = _ReactFiberScheduler.legacyContext; + + var findCurrentUnmaskedContext = legacyContext.findCurrentUnmaskedContext, + isContextProvider = legacyContext.isContextProvider, + processChildContext = legacyContext.processChildContext; + + function getContextForSubtree(parentComponent) { + if (!parentComponent) { + return emptyObject; + } + + var fiber = get$1(parentComponent); + var parentContext = findCurrentUnmaskedContext(fiber); + return isContextProvider(fiber) + ? processChildContext(fiber, parentContext) + : parentContext; + } + + function scheduleRootUpdate( + current, + element, + currentTime, + expirationTime, + callback + ) { + { + if ( + ReactDebugCurrentFiber.phase === "render" && + ReactDebugCurrentFiber.current !== null && + !didWarnAboutNestedUpdates + ) { + didWarnAboutNestedUpdates = true; + warning( + 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(ReactDebugCurrentFiber.current) || "Unknown" + ); + } + } + + callback = callback === undefined ? null : callback; + { + !(callback === null || typeof callback === "function") + ? warning( + false, + "render(...): Expected the last optional `callback` argument to be a " + + "function. Instead received: %s.", + callback + ) + : void 0; + } + + var update = { + expirationTime: expirationTime, + partialState: { element: element }, + callback: callback, + isReplace: false, + isForced: false, + capturedValue: null, + next: null + }; + insertUpdateIntoFiber(current, update); + scheduleWork(current, expirationTime); + + return expirationTime; + } + + function updateContainerAtExpirationTime( + element, + container, + parentComponent, + currentTime, + expirationTime, + callback + ) { + // TODO: If this is a nested container, this won't be the root. + var current = container.current; + + { + if (ReactFiberInstrumentation_1.debugTool) { + if (current.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, + element, + currentTime, + expirationTime, + callback + ); + } + + function findHostInstance(component) { + var fiber = get$1(component); + if (fiber === undefined) { + if (typeof component.render === "function") { + invariant(false, "Unable to find node on an unmounted component."); + } else { + invariant( + false, + "Argument appears to not be a ReactComponent. Keys: %s", + Object.keys(component) + ); + } + } + var hostFiber = findCurrentHostFiber(fiber); + if (hostFiber === null) { + return null; + } + return hostFiber.stateNode; + } + + return { + createContainer: function(containerInfo, isAsync, hydrate) { + return createFiberRoot(containerInfo, isAsync, hydrate); + }, + updateContainer: function(element, container, parentComponent, callback) { + var current = container.current; + var currentTime = recalculateCurrentTime(); + var expirationTime = computeExpirationForFiber(current); + return updateContainerAtExpirationTime( + element, + container, + parentComponent, + currentTime, + expirationTime, + callback + ); + }, + updateContainerAtExpirationTime: function( + element, + container, + parentComponent, + expirationTime, + callback + ) { + var currentTime = recalculateCurrentTime(); + return updateContainerAtExpirationTime( + element, + container, + parentComponent, + currentTime, + expirationTime, + callback + ); + }, + + flushRoot: flushRoot, + + requestWork: requestWork, + + computeUniqueAsyncExpiration: computeUniqueAsyncExpiration, + + batchedUpdates: batchedUpdates, + + unbatchedUpdates: unbatchedUpdates, + + deferredUpdates: deferredUpdates, + + syncUpdates: syncUpdates, + + interactiveUpdates: interactiveUpdates, + + flushInteractiveUpdates: flushInteractiveUpdates, + + flushControlled: flushControlled, + + flushSync: flushSync, + + getPublicRootInstance: function(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; + } + }, + + findHostInstance: findHostInstance, + + findHostInstanceWithNoPortals: function(fiber) { + var hostFiber = findCurrentHostFiberWithNoPortals(fiber); + if (hostFiber === null) { + return null; + } + return hostFiber.stateNode; + }, + injectIntoDevTools: function(devToolsConfig) { + var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; + + return injectInternals( + Object.assign({}, devToolsConfig, { + 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); + } + }) + ); + } + }; +}; + +var ReactFiberReconciler$2 = Object.freeze({ + default: ReactFiberReconciler$1 +}); + +var ReactFiberReconciler$3 = + (ReactFiberReconciler$2 && ReactFiberReconciler$1) || ReactFiberReconciler$2; + +// TODO: bundle Flow types with the package. + +// TODO: decide on the top-level export form. +// This is hacky but makes it work with both Rollup and Jest. +var reactReconciler = ReactFiberReconciler$3["default"] + ? ReactFiberReconciler$3["default"] + : ReactFiberReconciler$3; + +function _classCallCheck$1(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } +} + +// Modules provided by RN: +// 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; + +/** + * This is used for refs on host components. + */ + +var ReactFabricHostComponent = (function() { + function ReactFabricHostComponent(tag, viewConfig, props) { + _classCallCheck$1(this, ReactFabricHostComponent); + + this._nativeTag = tag; + this.viewConfig = viewConfig; + this.currentProps = props; + } + + ReactFabricHostComponent.prototype.blur = function blur() { + TextInputState.blurTextInput(this._nativeTag); + }; + + ReactFabricHostComponent.prototype.focus = function focus() { + TextInputState.focusTextInput(this._nativeTag); + }; + + ReactFabricHostComponent.prototype.measure = function measure(callback) { + UIManager.measure(this._nativeTag, mountSafeCallback(this, callback)); + }; + + ReactFabricHostComponent.prototype.measureInWindow = function measureInWindow( + callback + ) { + UIManager.measureInWindow( + this._nativeTag, + mountSafeCallback(this, callback) + ); + }; + + ReactFabricHostComponent.prototype.measureLayout = function measureLayout( + relativeToNativeNode, + onSuccess, + onFail /* currently unused */ + ) { + UIManager.measureLayout( + this._nativeTag, + relativeToNativeNode, + mountSafeCallback(this, onFail), + mountSafeCallback(this, onSuccess) + ); + }; + + ReactFabricHostComponent.prototype.setNativeProps = function setNativeProps( + nativeProps + ) { + { + 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) { + UIManager.updateView( + this._nativeTag, + this.viewConfig.uiViewClassName, + updatePayload + ); + } + }; + + return ReactFabricHostComponent; +})(); + +var ReactFabricRenderer = reactReconciler({ + appendInitialChild: function(parentInstance, child) { + FabricUIManager.appendChild(parentInstance.node, child.node); + }, + createInstance: function( + type, + props, + rootContainerInstance, + hostContext, + internalInstanceHandle + ) { + var tag = nextReactTag; + nextReactTag += 2; + + var viewConfig = ReactNativeViewConfigRegistry.get(type); + + { + for (var key in viewConfig.validAttributes) { + if (props.hasOwnProperty(key)) { + deepFreezeAndThrowOnMutationInDev(props[key]); + } + } + } + + var updatePayload = create(props, viewConfig.validAttributes); + + var node = FabricUIManager.createNode( + tag, // reactTag + viewConfig.uiViewClassName, // viewName + rootContainerInstance, // rootTag + updatePayload, // props + internalInstanceHandle + ); + + var component = new ReactFabricHostComponent(tag, viewConfig, props); + + return { + node: node, + canonical: component + }; + }, + createTextInstance: function( + text, + rootContainerInstance, + hostContext, + internalInstanceHandle + ) { + var tag = nextReactTag; + nextReactTag += 2; + + var node = FabricUIManager.createNode( + tag, // reactTag + "RCTRawText", // viewName + rootContainerInstance, // rootTag + { text: text }, // props + internalInstanceHandle + ); + + return { + node: node + }; + }, + finalizeInitialChildren: function( + parentInstance, + type, + props, + rootContainerInstance + ) { + return false; + }, + getRootHostContext: function() { + return emptyObject; + }, + getChildHostContext: function() { + return emptyObject; + }, + getPublicInstance: function(instance) { + return instance.canonical; + }, + + now: now, + + prepareForCommit: function() { + // Noop + }, + prepareUpdate: function( + 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. + return updatePayload; + }, + resetAfterCommit: function() { + // Noop + }, + + scheduleDeferredCallback: scheduleDeferredCallback, + cancelDeferredCallback: cancelDeferredCallback, + + shouldDeprioritizeSubtree: function(type, props) { + return false; + }, + shouldSetTextContent: function(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; + }, + + persistence: { + cloneInstance: function( + instance, + updatePayload, + type, + oldProps, + newProps, + internalInstanceHandle, + keepChildren, + recyclableInstance + ) { + var node = instance.node; + var clone = void 0; + if (keepChildren) { + if (updatePayload !== null) { + clone = FabricUIManager.cloneNodeWithNewProps(node, updatePayload); + } else { + clone = FabricUIManager.cloneNode(node); + } + } else { + if (updatePayload !== null) { + clone = FabricUIManager.cloneNodeWithNewChildrenAndProps( + node, + updatePayload + ); + } else { + clone = FabricUIManager.cloneNodeWithNewChildren(node); + } + } + return { + node: clone, + canonical: instance.canonical + }; + }, + createContainerChildSet: function(container) { + return FabricUIManager.createChildSet(container); + }, + appendChildToContainerChildSet: function(childSet, child) { + FabricUIManager.appendChildToSet(childSet, child.node); + }, + finalizeContainerChildren: function(container, newChildren) { + FabricUIManager.completeRoot(container, newChildren); + }, + replaceContainerChildren: function(container, newChildren) {} + } +}); + +// Module provided by RN: +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; + } + return emptyObject; + }; + + 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), + getInspectorData: function(findNodeHandle) { + return { + measure: function(callback) { + return 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, + 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 findHostInstance = ReactFabricRenderer.findHostInstance; + +function findNodeHandle(componentOrHandle) { + { + var owner = ReactCurrentOwner.current; + if (owner !== null && owner.stateNode !== null) { + !owner.stateNode._warnedAboutRefsInRender + ? warning( + 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) || "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 = findHostInstance(componentOrHandle); + if (hostInstance == null) { + return hostInstance; + } + if (hostInstance.canonical) { + // Fabric + return hostInstance.canonical._nativeTag; + } + return hostInstance._nativeTag; +} + +injection$2.injectRenderer(ReactFabricRenderer); + +var roots = new Map(); + +var ReactFabric = { + NativeComponent: ReactNativeComponent(findNodeHandle, findHostInstance), + + findNodeHandle: findNodeHandle, + + 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 = ReactFabricRenderer.createContainer(containerTag, false, false); + roots.set(containerTag, root); + } + ReactFabricRenderer.updateContainer(element, root, null, callback); + + return ReactFabricRenderer.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? + ReactFabricRenderer.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), + // Used by react-native-github/Libraries/ components + ReactNativeComponentTree: ReactNativeComponentTree + } +}; + +{ + // $FlowFixMe + Object.assign( + ReactFabric.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, + { + // TODO: none of these work since Fiber. Remove these dependencies. + // Used by RCTRenderingPerf, Systrace: + ReactDebugTool: { + addHook: function() {}, + removeHook: function() {} + }, + // Used by ReactPerfStallHandler, RCTRenderingPerf: + ReactPerf: { + start: function() {}, + stop: function() {}, + printInclusive: function() {}, + printWasted: function() {} + } + } + ); +} + +ReactFabricRenderer.injectIntoDevTools({ + findFiberByHostInstance: getInstanceFromTag, + 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["default"] + : ReactFabric$3; + +module.exports = fabric; + + })(); +} diff --git a/Libraries/Renderer/oss/ReactFabric-prod.js b/Libraries/Renderer/oss/ReactFabric-prod.js new file mode 100644 index 00000000000000..48099a5351cbf3 --- /dev/null +++ b/Libraries/Renderer/oss/ReactFabric-prod.js @@ -0,0 +1,5876 @@ +/** + * Copyright (c) 2013-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @noflow + * @providesModule ReactFabric-prod + * @preventMunge + */ + +"use strict"; +require("InitializeCore"); +var invariant = require("fbjs/lib/invariant"), + emptyFunction = require("fbjs/lib/emptyFunction"), + ReactNativeViewConfigRegistry = require("ReactNativeViewConfigRegistry"), + UIManager = require("UIManager"), + TextInputState = require("TextInputState"), + deepDiffer = require("deepDiffer"), + flattenStyle = require("flattenStyle"), + React = require("react"), + emptyObject = require("fbjs/lib/emptyObject"), + shallowEqual = require("fbjs/lib/shallowEqual"), + FabricUIManager = require("FabricUIManager"), + eventPluginOrder = null, + namesToPlugins = {}; +function recomputePluginOrdering() { + if (eventPluginOrder) + for (var pluginName in namesToPlugins) { + var pluginModule = namesToPlugins[pluginName], + pluginIndex = eventPluginOrder.indexOf(pluginName); + invariant( + -1 < pluginIndex, + "EventPluginRegistry: Cannot inject event plugins that do not exist in the plugin ordering, `%s`.", + pluginName + ); + if (!plugins[pluginIndex]) { + invariant( + pluginModule.extractEvents, + "EventPluginRegistry: Event plugins must implement an `extractEvents` method, but `%s` does not.", + pluginName + ); + 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; + invariant( + !eventNameDispatchConfigs.hasOwnProperty(eventName$jscomp$0), + "EventPluginHub: More than one plugin attempted to publish the same event name, `%s`.", + 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); + invariant( + JSCompiler_inline_result, + "EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.", + eventName, + pluginName + ); + } + } + } +} +function publishRegistrationName(registrationName, pluginModule) { + invariant( + !registrationNameModules[registrationName], + "EventPluginHub: More than one plugin attempted to publish the same registration name, `%s`.", + registrationName + ); + registrationNameModules[registrationName] = pluginModule; +} +var plugins = [], + eventNameDispatchConfigs = {}, + registrationNameModules = {}, + getFiberCurrentPropsFromNode = null, + getInstanceFromNode = null, + getNodeFromInstance = null; +function isEndish(topLevelType) { + return ( + "topMouseUp" === topLevelType || + "topTouchEnd" === topLevelType || + "topTouchCancel" === topLevelType + ); +} +function isMoveish(topLevelType) { + return "topMouseMove" === topLevelType || "topTouchMove" === topLevelType; +} +function isStartish(topLevelType) { + return "topMouseDown" === topLevelType || "topTouchStart" === topLevelType; +} +function executeDirectDispatch(event) { + var dispatchListener = event._dispatchListeners, + dispatchInstance = event._dispatchInstances; + invariant( + !Array.isArray(dispatchListener), + "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) { + invariant( + null != next, + "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 injection = { + injectEventPluginOrder: function(injectedEventPluginOrder) { + invariant( + !eventPluginOrder, + "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]; + (namesToPlugins.hasOwnProperty(pluginName) && + namesToPlugins[pluginName] === pluginModule) || + (invariant( + !namesToPlugins[pluginName], + "EventPluginRegistry: Cannot inject two different event plugins using the same name, `%s`.", + 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; + invariant( + !listener || "function" === typeof listener, + "Expected `%s` listener to be a function, instead got a value of `%s` type.", + registrationName, + typeof listener + ); + 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 + ))); + } + } +} +var shouldBeReleasedProperties = "dispatchConfig _targetInst nativeEvent isDefaultPrevented isPropagationStopped _dispatchListeners _dispatchInstances".split( + " " + ), + EventInterface = { + type: null, + target: null, + currentTarget: emptyFunction.thatReturnsNull, + eventPhase: null, + bubbles: null, + cancelable: null, + timeStamp: function(event) { + return event.timeStamp || Date.now(); + }, + defaultPrevented: null, + isTrusted: null + }; +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) + ? emptyFunction.thatReturnsTrue + : emptyFunction.thatReturnsFalse; + this.isPropagationStopped = emptyFunction.thatReturnsFalse; + 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 = emptyFunction.thatReturnsTrue)); + }, + stopPropagation: function() { + var event = this.nativeEvent; + event && + (event.stopPropagation + ? event.stopPropagation() + : "unknown" !== typeof event.cancelBubble && (event.cancelBubble = !0), + (this.isPropagationStopped = emptyFunction.thatReturnsTrue)); + }, + persist: function() { + this.isPersistent = emptyFunction.thatReturnsTrue; + }, + isPersistent: emptyFunction.thatReturnsFalse, + destructor: function() { + var Interface = this.constructor.Interface, + propName; + for (propName in Interface) this[propName] = null; + for ( + Interface = 0; + Interface < shouldBeReleasedProperties.length; + Interface++ + ) + this[shouldBeReleasedProperties[Interface]] = null; + } +}); +SyntheticEvent.Interface = EventInterface; +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) { + invariant( + event instanceof this, + "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; + } + }), + touchBank = [], + touchHistory = { + touchBank: touchBank, + numberActiveTouches: 0, + indexOfSingleActiveTouch: -1, + mostRecentTimeStamp: 0 + }; +function timestampForTouch(touch) { + return touch.timeStamp || touch.timestamp; +} +function getTouchIdentifier(_ref) { + _ref = _ref.identifier; + invariant(null != _ref, "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 ( + isEndish(topLevelType) && + (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) { + invariant( + null != next, + "accumulate(...): Accumulated items must be 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, + previousActiveTouches = 0; +function changeResponder(nextResponderInst, blockHostResponder) { + var oldResponderInst = responderInst; + responderInst = nextResponderInst; + if (null !== ResponderEventPlugin.GlobalResponderHandler) + ResponderEventPlugin.GlobalResponderHandler.onChange( + oldResponderInst, + nextResponderInst, + blockHostResponder + ); +} +var eventTypes$1 = { + startShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onStartShouldSetResponder", + captured: "onStartShouldSetResponderCapture" + } + }, + scrollShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onScrollShouldSetResponder", + captured: "onScrollShouldSetResponderCapture" + } + }, + selectionChangeShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onSelectionChangeShouldSetResponder", + captured: "onSelectionChangeShouldSetResponderCapture" + } + }, + moveShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onMoveShouldSetResponder", + captured: "onMoveShouldSetResponderCapture" + } + }, + responderStart: { registrationName: "onResponderStart" }, + responderMove: { registrationName: "onResponderMove" }, + responderEnd: { registrationName: "onResponderEnd" }, + responderRelease: { registrationName: "onResponderRelease" }, + responderTerminationRequest: { + registrationName: "onResponderTerminationRequest" + }, + responderGrant: { registrationName: "onResponderGrant" }, + responderReject: { registrationName: "onResponderReject" }, + responderTerminate: { registrationName: "onResponderTerminate" } + }, + ResponderEventPlugin = { + _getResponder: function() { + return responderInst; + }, + eventTypes: eventTypes$1, + extractEvents: function( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) { + if (isStartish(topLevelType)) trackedTouchCount += 1; + else if (isEndish(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$1.startShouldSetResponder + : isMoveish(topLevelType) + ? eventTypes$1.moveShouldSetResponder + : "topSelectionChange" === topLevelType + ? eventTypes$1.selectionChangeShouldSetResponder + : eventTypes$1.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$1.responderGrant, + JSCompiler_temp, + nativeEvent, + nativeEventTarget + )), + (targetInst.touchHistory = ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(targetInst, accumulateDirectDispatchesSingle), + (depthA = !0 === executeDirectDispatch(targetInst)), + responderInst + ? ((tempA = ResponderSyntheticEvent.getPooled( + eventTypes$1.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$1.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$1.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 && isEndish(topLevelType); + if ( + (JSCompiler_temp$jscomp$0 = JSCompiler_temp$jscomp$0 + ? eventTypes$1.responderStart + : targetInst + ? eventTypes$1.responderMove + : depthA ? eventTypes$1.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 && isEndish(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$1.responderTerminate + : topLevelType ? eventTypes$1.responderRelease : null) + ) + (nativeEvent = ResponderSyntheticEvent.getPooled( + topLevelType, + responderInst, + nativeEvent, + nativeEventTarget + )), + (nativeEvent.touchHistory = ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(nativeEvent, accumulateDirectDispatchesSingle), + (JSCompiler_temp = accumulate(JSCompiler_temp, nativeEvent)), + changeResponder(null); + nativeEvent = ResponderTouchHistoryStore.touchHistory.numberActiveTouches; + if ( + ResponderEventPlugin.GlobalInteractionHandler && + nativeEvent !== previousActiveTouches + ) + ResponderEventPlugin.GlobalInteractionHandler.onChange(nativeEvent); + previousActiveTouches = nativeEvent; + return JSCompiler_temp; + }, + GlobalResponderHandler: null, + GlobalInteractionHandler: null, + injection: { + injectGlobalResponderHandler: function(GlobalResponderHandler) { + ResponderEventPlugin.GlobalResponderHandler = GlobalResponderHandler; + }, + injectGlobalInteractionHandler: function(GlobalInteractionHandler) { + ResponderEventPlugin.GlobalInteractionHandler = GlobalInteractionHandler; + } + } + }, + customBubblingEventTypes$1 = + ReactNativeViewConfigRegistry.customBubblingEventTypes, + customDirectEventTypes$1 = + ReactNativeViewConfigRegistry.customDirectEventTypes, + ReactNativeBridgeEventPlugin = { + eventTypes: ReactNativeViewConfigRegistry.eventTypes, + extractEvents: function( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) { + if (null == targetInst) return null; + var bubbleDispatchConfig = customBubblingEventTypes$1[topLevelType], + directDispatchConfig = customDirectEventTypes$1[topLevelType]; + invariant( + bubbleDispatchConfig || directDispatchConfig, + 'Unsupported top level event type "%s" dispatched', + topLevelType + ); + topLevelType = SyntheticEvent.getPooled( + bubbleDispatchConfig || directDispatchConfig, + targetInst, + nativeEvent, + nativeEventTarget + ); + if (bubbleDispatchConfig) + forEachAccumulated(topLevelType, accumulateTwoPhaseDispatchesSingle); + else if (directDispatchConfig) + forEachAccumulated(topLevelType, accumulateDirectDispatchesSingle); + else return null; + return topLevelType; + } + }, + instanceCache = {}, + instanceProps = {}; +function getInstanceFromTag(tag) { + return "number" === typeof tag ? instanceCache[tag] || null : tag; +} +var ReactNativeComponentTree = Object.freeze({ + precacheFiberNode: function(hostInst, tag) { + instanceCache[tag] = hostInst; + }, + uncacheFiberNode: function(tag) { + delete instanceCache[tag]; + delete instanceProps[tag]; + }, + getClosestInstanceFromNode: getInstanceFromTag, + getInstanceFromNode: getInstanceFromTag, + getNodeFromInstance: function(inst) { + var tag = inst.stateNode._nativeTag; + void 0 === tag && (tag = inst.stateNode.canonical._nativeTag); + invariant(tag, "All native instances should have a tag."); + return tag; + }, + getFiberCurrentPropsFromNode: function(stateNode) { + return instanceProps[stateNode._nativeTag] || null; + }, + updateFiberProps: function(tag, props) { + instanceProps[tag] = props; + } +}); +injection.injectEventPluginOrder([ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]); +getFiberCurrentPropsFromNode = + ReactNativeComponentTree.getFiberCurrentPropsFromNode; +getInstanceFromNode = ReactNativeComponentTree.getInstanceFromNode; +getNodeFromInstance = ReactNativeComponentTree.getNodeFromInstance; +ResponderEventPlugin.injection.injectGlobalResponderHandler({ + onChange: function(from, to, blockNativeResponder) { + null !== to + ? UIManager.setJSResponder(to.stateNode._nativeTag, blockNativeResponder) + : UIManager.clearJSResponder(); + } +}); +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin +}); +var hasSymbol = "function" === typeof Symbol && Symbol["for"], + REACT_ELEMENT_TYPE = hasSymbol ? Symbol["for"]("react.element") : 60103, + REACT_CALL_TYPE = hasSymbol ? Symbol["for"]("react.call") : 60104, + REACT_RETURN_TYPE = hasSymbol ? Symbol["for"]("react.return") : 60105, + 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_PROVIDER_TYPE = hasSymbol ? Symbol["for"]("react.provider") : 60109, + REACT_CONTEXT_TYPE = hasSymbol ? Symbol["for"]("react.context") : 60110, + REACT_ASYNC_MODE_TYPE = hasSymbol ? Symbol["for"]("react.async_mode") : 60111, + REACT_FORWARD_REF_TYPE = hasSymbol + ? Symbol["for"]("react.forward_ref") + : 60112, + MAYBE_ITERATOR_SYMBOL = "function" === typeof Symbol && Symbol.iterator; +function getIteratorFn(maybeIterable) { + if (null === maybeIterable || "undefined" === typeof maybeIterable) + return null; + maybeIterable = + (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || + maybeIterable["@@iterator"]; + return "function" === typeof maybeIterable ? maybeIterable : null; +} +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 + }; +} +var emptyObject$1 = {}, + 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, + flattenStyle(prevProp), + nextProp, + validAttributes + ) + : diffProperties( + updatePayload, + prevProp, + flattenStyle(nextProp), + validAttributes + ); +} +function addNestedProperty(updatePayload, nextProp, validAttributes) { + if (!nextProp) return updatePayload; + if (!Array.isArray(nextProp)) + return diffProperties( + updatePayload, + emptyObject$1, + 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$1, + 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 || + 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 || + 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(context, callback) { + return function() { + if (callback) { + if ("boolean" === typeof context.__isMounted) { + if (!context.__isMounted) return; + } else if ( + "function" === typeof context.isMounted && + !context.isMounted() + ) + return; + return callback.apply(context, arguments); + } + }; +} +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 now = + "object" === typeof performance && "function" === typeof performance.now + ? function() { + return performance.now(); + } + : function() { + return Date.now(); + }, + scheduledCallback = null, + frameDeadline = 0, + frameDeadlineObject = { + timeRemaining: function() { + return frameDeadline - now(); + }, + didTimeout: !1 + }; +function setTimeoutCallback() { + frameDeadline = now() + 5; + var callback = scheduledCallback; + scheduledCallback = null; + null !== callback && callback(frameDeadlineObject); +} +var ReactCurrentOwner = + React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner; +function getComponentName(fiber) { + fiber = fiber.type; + if ("function" === typeof fiber) return fiber.displayName || fiber.name; + if ("string" === typeof fiber) return fiber; + switch (fiber) { + case REACT_FRAGMENT_TYPE: + return "ReactFragment"; + case REACT_PORTAL_TYPE: + return "ReactPortal"; + case REACT_CALL_TYPE: + return "ReactCall"; + case REACT_RETURN_TYPE: + return "ReactReturn"; + } + if ("object" === typeof fiber && null !== fiber) + switch (fiber.$$typeof) { + case REACT_FORWARD_REF_TYPE: + return ( + (fiber = fiber.render.displayName || fiber.render.name || ""), + "" !== fiber ? "ForwardRef(" + fiber + ")" : "ForwardRef" + ); + } + 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 isMounted(component) { + return (component = component._reactInternalFiber) + ? 2 === isFiberMountedImpl(component) + : !1; +} +function assertIsMounted(fiber) { + invariant( + 2 === isFiberMountedImpl(fiber), + "Unable to find node on an unmounted component." + ); +} +function findCurrentFiberUsingSlowPath(fiber) { + var alternate = fiber.alternate; + if (!alternate) + return ( + (alternate = isFiberMountedImpl(fiber)), + invariant( + 3 !== alternate, + "Unable to find node on an unmounted component." + ), + 1 === alternate ? null : fiber + ); + for (var a = fiber, b = alternate; ; ) { + var parentA = a["return"], + parentB = parentA ? parentA.alternate : null; + if (!parentA || !parentB) break; + if (parentA.child === parentB.child) { + for (var child = parentA.child; child; ) { + if (child === a) return assertIsMounted(parentA), fiber; + if (child === b) return assertIsMounted(parentA), alternate; + child = child.sibling; + } + invariant(!1, "Unable to find node on an unmounted component."); + } + if (a["return"] !== b["return"]) (a = parentA), (b = parentB); + else { + child = !1; + for (var _child = parentA.child; _child; ) { + if (_child === a) { + child = !0; + a = parentA; + b = parentB; + break; + } + if (_child === b) { + child = !0; + b = parentA; + a = parentB; + break; + } + _child = _child.sibling; + } + if (!child) { + for (_child = parentB.child; _child; ) { + if (_child === a) { + child = !0; + a = parentB; + b = parentA; + break; + } + if (_child === b) { + child = !0; + b = parentB; + a = parentA; + break; + } + _child = _child.sibling; + } + invariant( + child, + "Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue." + ); + } + } + invariant( + a.alternate === b, + "Return fibers should always be each others' alternates. This error is likely caused by a bug in React. Please file an issue." + ); + } + invariant(3 === a.tag, "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 findCurrentHostFiberWithNoPortals(parent) { + parent = findCurrentFiberUsingSlowPath(parent); + if (!parent) return null; + for (var node = parent; ; ) { + if (5 === node.tag || 6 === node.tag) return node; + if (node.child && 4 !== node.tag) + (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 FiberNode(tag, pendingProps, key, mode) { + this.tag = tag; + this.key = key; + this.stateNode = this.type = null; + this.sibling = this.child = this["return"] = null; + this.index = 0; + this.ref = null; + this.pendingProps = pendingProps; + this.memoizedState = this.updateQueue = this.memoizedProps = null; + this.mode = mode; + this.effectTag = 0; + this.lastEffect = this.firstEffect = this.nextEffect = null; + this.expirationTime = 0; + this.alternate = null; +} +function createWorkInProgress(current, pendingProps, expirationTime) { + var workInProgress = current.alternate; + null === workInProgress + ? ((workInProgress = new FiberNode( + current.tag, + pendingProps, + current.key, + current.mode + )), + (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.expirationTime = expirationTime; + workInProgress.child = current.child; + workInProgress.memoizedProps = current.memoizedProps; + workInProgress.memoizedState = current.memoizedState; + workInProgress.updateQueue = current.updateQueue; + workInProgress.sibling = current.sibling; + workInProgress.index = current.index; + workInProgress.ref = current.ref; + return workInProgress; +} +function createFiberFromElement(element, mode, expirationTime) { + var type = element.type, + key = element.key; + element = element.props; + var fiberTag = void 0; + if ("function" === typeof type) + fiberTag = type.prototype && type.prototype.isReactComponent ? 2 : 0; + else if ("string" === typeof type) fiberTag = 5; + else + switch (type) { + case REACT_FRAGMENT_TYPE: + return createFiberFromFragment( + element.children, + mode, + expirationTime, + key + ); + case REACT_ASYNC_MODE_TYPE: + fiberTag = 11; + mode |= 3; + break; + case REACT_STRICT_MODE_TYPE: + fiberTag = 11; + mode |= 2; + break; + case REACT_CALL_TYPE: + fiberTag = 7; + break; + case REACT_RETURN_TYPE: + fiberTag = 9; + break; + default: + if ("object" === typeof type && null !== type) + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + fiberTag = 13; + break; + case REACT_CONTEXT_TYPE: + fiberTag = 12; + break; + case REACT_FORWARD_REF_TYPE: + fiberTag = 14; + break; + default: + if ("number" === typeof type.tag) + return ( + (mode = type), + (mode.pendingProps = element), + (mode.expirationTime = expirationTime), + mode + ); + throwOnInvalidElementType(type, null); + } + else throwOnInvalidElementType(type, null); + } + mode = new FiberNode(fiberTag, element, key, mode); + mode.type = type; + mode.expirationTime = expirationTime; + return mode; +} +function throwOnInvalidElementType(type) { + invariant( + !1, + "Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: %s.%s", + null == type ? type : typeof type, + "" + ); +} +function createFiberFromFragment(elements, mode, expirationTime, key) { + elements = new FiberNode(10, elements, key, mode); + elements.expirationTime = expirationTime; + return elements; +} +function createFiberFromText(content, mode, expirationTime) { + content = new FiberNode(6, content, null, mode); + content.expirationTime = expirationTime; + return content; +} +function createFiberFromPortal(portal, mode, expirationTime) { + mode = new FiberNode( + 4, + null !== portal.children ? portal.children : [], + portal.key, + mode + ); + mode.expirationTime = expirationTime; + mode.stateNode = { + containerInfo: portal.containerInfo, + pendingChildren: null, + implementation: portal.implementation + }; + return mode; +} +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; +} +function onCommitRoot(root) { + "function" === typeof onCommitFiberRoot && onCommitFiberRoot(root); +} +function onCommitUnmount(fiber) { + "function" === typeof onCommitFiberUnmount && onCommitFiberUnmount(fiber); +} +function getStackAddendumByWorkInProgressFiber(workInProgress) { + var info = ""; + do { + a: switch (workInProgress.tag) { + case 0: + case 1: + case 2: + case 5: + var owner = workInProgress._debugOwner, + source = workInProgress._debugSource; + var JSCompiler_inline_result = getComponentName(workInProgress); + var ownerName = null; + owner && (ownerName = getComponentName(owner)); + owner = source; + JSCompiler_inline_result = + "\n in " + + (JSCompiler_inline_result || "Unknown") + + (owner + ? " (at " + + owner.fileName.replace(/^.*[\\\/]/, "") + + ":" + + owner.lineNumber + + ")" + : ownerName ? " (created by " + ownerName + ")" : ""); + break a; + default: + JSCompiler_inline_result = ""; + } + info += JSCompiler_inline_result; + workInProgress = workInProgress["return"]; + } while (workInProgress); + return info; +} +new Set(); +function createUpdateQueue(baseState) { + return { + baseState: baseState, + expirationTime: 0, + first: null, + last: null, + callbackList: null, + hasForceUpdate: !1, + isInitialized: !1, + capturedValues: null + }; +} +function insertUpdateIntoQueue(queue, update) { + null === queue.last + ? (queue.first = queue.last = update) + : ((queue.last.next = update), (queue.last = update)); + if ( + 0 === queue.expirationTime || + queue.expirationTime > update.expirationTime + ) + queue.expirationTime = update.expirationTime; +} +var q1 = void 0, + q2 = void 0; +function ensureUpdateQueues(fiber) { + q1 = q2 = null; + var alternateFiber = fiber.alternate, + queue1 = fiber.updateQueue; + null === queue1 && (queue1 = fiber.updateQueue = createUpdateQueue(null)); + null !== alternateFiber + ? ((fiber = alternateFiber.updateQueue), + null === fiber && + (fiber = alternateFiber.updateQueue = createUpdateQueue(null))) + : (fiber = null); + q1 = queue1; + q2 = fiber !== queue1 ? fiber : null; +} +function insertUpdateIntoFiber(fiber, update) { + ensureUpdateQueues(fiber); + fiber = q1; + var queue2 = q2; + null === queue2 + ? insertUpdateIntoQueue(fiber, update) + : null === fiber.last || null === queue2.last + ? (insertUpdateIntoQueue(fiber, update), + insertUpdateIntoQueue(queue2, update)) + : (insertUpdateIntoQueue(fiber, update), (queue2.last = update)); +} +function getStateFromUpdate(update, instance, prevState, props) { + update = update.partialState; + return "function" === typeof update + ? update.call(instance, prevState, props) + : update; +} +function processUpdateQueue( + current, + workInProgress, + queue, + instance, + props, + renderExpirationTime +) { + null !== current && + current.updateQueue === queue && + (queue = workInProgress.updateQueue = { + baseState: queue.baseState, + expirationTime: queue.expirationTime, + first: queue.first, + last: queue.last, + isInitialized: queue.isInitialized, + capturedValues: queue.capturedValues, + callbackList: null, + hasForceUpdate: !1 + }); + queue.expirationTime = 0; + queue.isInitialized + ? (current = queue.baseState) + : ((current = queue.baseState = workInProgress.memoizedState), + (queue.isInitialized = !0)); + for ( + var dontMutatePrevState = !0, update = queue.first, didSkip = !1; + null !== update; + + ) { + var updateExpirationTime = update.expirationTime; + if (updateExpirationTime > renderExpirationTime) { + var remainingExpirationTime = queue.expirationTime; + if ( + 0 === remainingExpirationTime || + remainingExpirationTime > updateExpirationTime + ) + queue.expirationTime = updateExpirationTime; + didSkip || ((didSkip = !0), (queue.baseState = current)); + } else { + didSkip || + ((queue.first = update.next), + null === queue.first && (queue.last = null)); + if (update.isReplace) + (current = getStateFromUpdate(update, instance, current, props)), + (dontMutatePrevState = !0); + else if ( + (updateExpirationTime = getStateFromUpdate( + update, + instance, + current, + props + )) + ) + (current = dontMutatePrevState + ? Object.assign({}, current, updateExpirationTime) + : Object.assign(current, updateExpirationTime)), + (dontMutatePrevState = !1); + update.isForced && (queue.hasForceUpdate = !0); + null !== update.callback && + ((updateExpirationTime = queue.callbackList), + null === updateExpirationTime && + (updateExpirationTime = queue.callbackList = []), + updateExpirationTime.push(update)); + null !== update.capturedValue && + ((updateExpirationTime = queue.capturedValues), + null === updateExpirationTime + ? (queue.capturedValues = [update.capturedValue]) + : updateExpirationTime.push(update.capturedValue)); + } + update = update.next; + } + null !== queue.callbackList + ? (workInProgress.effectTag |= 32) + : null !== queue.first || + queue.hasForceUpdate || + null !== queue.capturedValues || + (workInProgress.updateQueue = null); + didSkip || (queue.baseState = current); + return current; +} +function commitCallbacks(queue, context) { + var callbackList = queue.callbackList; + if (null !== callbackList) + for ( + queue.callbackList = null, queue = 0; + queue < callbackList.length; + queue++ + ) { + var update = callbackList[queue], + _callback = update.callback; + update.callback = null; + invariant( + "function" === typeof _callback, + "Invalid argument passed as callback. Expected a function. Instead received: %s", + _callback + ); + _callback.call(context); + } +} +function ReactFiberClassComponent( + legacyContext, + scheduleWork, + computeExpirationForFiber, + memoizeProps, + memoizeState +) { + function checkShouldComponentUpdate( + workInProgress, + oldProps, + newProps, + oldState, + newState, + newContext + ) { + if ( + null === oldProps || + (null !== workInProgress.updateQueue && + workInProgress.updateQueue.hasForceUpdate) + ) + return !0; + var instance = workInProgress.stateNode; + workInProgress = workInProgress.type; + return "function" === typeof instance.shouldComponentUpdate + ? instance.shouldComponentUpdate(newProps, newState, newContext) + : workInProgress.prototype && + workInProgress.prototype.isPureReactComponent + ? !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) + : !0; + } + function adoptClassInstance(workInProgress, instance) { + instance.updater = updater; + workInProgress.stateNode = instance; + instance._reactInternalFiber = workInProgress; + } + function callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + newContext + ) { + workInProgress = instance.state; + "function" === typeof instance.componentWillReceiveProps && + instance.componentWillReceiveProps(newProps, newContext); + "function" === typeof instance.UNSAFE_componentWillReceiveProps && + instance.UNSAFE_componentWillReceiveProps(newProps, newContext); + instance.state !== workInProgress && + updater.enqueueReplaceState(instance, instance.state, null); + } + function callGetDerivedStateFromProps( + workInProgress, + instance, + nextProps, + prevState + ) { + workInProgress = workInProgress.type; + if ("function" === typeof workInProgress.getDerivedStateFromProps) + return workInProgress.getDerivedStateFromProps.call( + null, + nextProps, + prevState + ); + } + var cacheContext = legacyContext.cacheContext, + getMaskedContext = legacyContext.getMaskedContext, + getUnmaskedContext = legacyContext.getUnmaskedContext, + isContextConsumer = legacyContext.isContextConsumer, + hasContextChanged = legacyContext.hasContextChanged, + updater = { + isMounted: isMounted, + enqueueSetState: function(instance, partialState, callback) { + instance = instance._reactInternalFiber; + callback = void 0 === callback ? null : callback; + var expirationTime = computeExpirationForFiber(instance); + insertUpdateIntoFiber(instance, { + expirationTime: expirationTime, + partialState: partialState, + callback: callback, + isReplace: !1, + isForced: !1, + capturedValue: null, + next: null + }); + scheduleWork(instance, expirationTime); + }, + enqueueReplaceState: function(instance, state, callback) { + instance = instance._reactInternalFiber; + callback = void 0 === callback ? null : callback; + var expirationTime = computeExpirationForFiber(instance); + insertUpdateIntoFiber(instance, { + expirationTime: expirationTime, + partialState: state, + callback: callback, + isReplace: !0, + isForced: !1, + capturedValue: null, + next: null + }); + scheduleWork(instance, expirationTime); + }, + enqueueForceUpdate: function(instance, callback) { + instance = instance._reactInternalFiber; + callback = void 0 === callback ? null : callback; + var expirationTime = computeExpirationForFiber(instance); + insertUpdateIntoFiber(instance, { + expirationTime: expirationTime, + partialState: null, + callback: callback, + isReplace: !1, + isForced: !0, + capturedValue: null, + next: null + }); + scheduleWork(instance, expirationTime); + } + }; + return { + adoptClassInstance: adoptClassInstance, + callGetDerivedStateFromProps: callGetDerivedStateFromProps, + constructClassInstance: function(workInProgress, props) { + var ctor = workInProgress.type, + unmaskedContext = getUnmaskedContext(workInProgress), + needsContext = isContextConsumer(workInProgress), + context = needsContext + ? getMaskedContext(workInProgress, unmaskedContext) + : emptyObject; + ctor = new ctor(props, context); + var state = + null !== ctor.state && void 0 !== ctor.state ? ctor.state : null; + adoptClassInstance(workInProgress, ctor); + workInProgress.memoizedState = state; + props = callGetDerivedStateFromProps(workInProgress, ctor, props, state); + null !== props && + void 0 !== props && + (workInProgress.memoizedState = Object.assign( + {}, + workInProgress.memoizedState, + props + )); + needsContext && cacheContext(workInProgress, unmaskedContext, context); + return ctor; + }, + mountClassInstance: function(workInProgress, renderExpirationTime) { + var ctor = workInProgress.type, + current = workInProgress.alternate, + instance = workInProgress.stateNode, + props = workInProgress.pendingProps, + unmaskedContext = getUnmaskedContext(workInProgress); + instance.props = props; + instance.state = workInProgress.memoizedState; + instance.refs = emptyObject; + instance.context = getMaskedContext(workInProgress, unmaskedContext); + "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 && + updater.enqueueReplaceState(instance, instance.state, null), + (ctor = workInProgress.updateQueue), + null !== ctor && + (instance.state = processUpdateQueue( + current, + workInProgress, + ctor, + instance, + props, + renderExpirationTime + ))); + "function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4); + }, + resumeMountClassInstance: function(workInProgress, renderExpirationTime) { + var ctor = workInProgress.type, + instance = workInProgress.stateNode; + instance.props = workInProgress.memoizedProps; + instance.state = workInProgress.memoizedState; + var oldProps = workInProgress.memoizedProps, + newProps = workInProgress.pendingProps, + oldContext = instance.context, + newUnmaskedContext = getUnmaskedContext(workInProgress); + newUnmaskedContext = getMaskedContext(workInProgress, newUnmaskedContext); + (ctor = + "function" === typeof ctor.getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate) || + ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && + "function" !== typeof instance.componentWillReceiveProps) || + ((oldProps !== newProps || oldContext !== newUnmaskedContext) && + callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + newUnmaskedContext + )); + oldContext = workInProgress.memoizedState; + renderExpirationTime = + null !== workInProgress.updateQueue + ? processUpdateQueue( + null, + workInProgress, + workInProgress.updateQueue, + instance, + newProps, + renderExpirationTime + ) + : oldContext; + var derivedStateFromProps = void 0; + oldProps !== newProps && + (derivedStateFromProps = callGetDerivedStateFromProps( + workInProgress, + instance, + newProps, + renderExpirationTime + )); + if (null !== derivedStateFromProps && void 0 !== derivedStateFromProps) { + renderExpirationTime = + null === renderExpirationTime || void 0 === renderExpirationTime + ? derivedStateFromProps + : Object.assign({}, renderExpirationTime, derivedStateFromProps); + var _updateQueue = workInProgress.updateQueue; + null !== _updateQueue && + (_updateQueue.baseState = Object.assign( + {}, + _updateQueue.baseState, + derivedStateFromProps + )); + } + if ( + !( + oldProps !== newProps || + oldContext !== renderExpirationTime || + hasContextChanged() || + (null !== workInProgress.updateQueue && + workInProgress.updateQueue.hasForceUpdate) + ) + ) + return ( + "function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4), + !1 + ); + (oldProps = checkShouldComponentUpdate( + workInProgress, + oldProps, + newProps, + oldContext, + renderExpirationTime, + newUnmaskedContext + )) + ? (ctor || + ("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), + memoizeProps(workInProgress, newProps), + memoizeState(workInProgress, renderExpirationTime)); + instance.props = newProps; + instance.state = renderExpirationTime; + instance.context = newUnmaskedContext; + return oldProps; + }, + updateClassInstance: function( + current, + workInProgress, + renderExpirationTime + ) { + var ctor = workInProgress.type, + instance = workInProgress.stateNode; + instance.props = workInProgress.memoizedProps; + instance.state = workInProgress.memoizedState; + var oldProps = workInProgress.memoizedProps, + newProps = workInProgress.pendingProps, + oldContext = instance.context, + newUnmaskedContext = getUnmaskedContext(workInProgress); + newUnmaskedContext = getMaskedContext(workInProgress, newUnmaskedContext); + (ctor = + "function" === typeof ctor.getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate) || + ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && + "function" !== typeof instance.componentWillReceiveProps) || + ((oldProps !== newProps || oldContext !== newUnmaskedContext) && + callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + newUnmaskedContext + )); + oldContext = workInProgress.memoizedState; + renderExpirationTime = + null !== workInProgress.updateQueue + ? processUpdateQueue( + current, + workInProgress, + workInProgress.updateQueue, + instance, + newProps, + renderExpirationTime + ) + : oldContext; + var derivedStateFromProps = void 0; + oldProps !== newProps && + (derivedStateFromProps = callGetDerivedStateFromProps( + workInProgress, + instance, + newProps, + renderExpirationTime + )); + if (null !== derivedStateFromProps && void 0 !== derivedStateFromProps) { + renderExpirationTime = + null === renderExpirationTime || void 0 === renderExpirationTime + ? derivedStateFromProps + : Object.assign({}, renderExpirationTime, derivedStateFromProps); + var _updateQueue3 = workInProgress.updateQueue; + null !== _updateQueue3 && + (_updateQueue3.baseState = Object.assign( + {}, + _updateQueue3.baseState, + derivedStateFromProps + )); + } + if ( + !( + oldProps !== newProps || + oldContext !== renderExpirationTime || + hasContextChanged() || + (null !== workInProgress.updateQueue && + workInProgress.updateQueue.hasForceUpdate) + ) + ) + return ( + "function" !== typeof instance.componentDidUpdate || + (oldProps === current.memoizedProps && + oldContext === current.memoizedState) || + (workInProgress.effectTag |= 4), + "function" !== typeof instance.getSnapshotBeforeUpdate || + (oldProps === current.memoizedProps && + oldContext === current.memoizedState) || + (workInProgress.effectTag |= 2048), + !1 + ); + (derivedStateFromProps = checkShouldComponentUpdate( + workInProgress, + oldProps, + newProps, + oldContext, + renderExpirationTime, + newUnmaskedContext + )) + ? (ctor || + ("function" !== typeof instance.UNSAFE_componentWillUpdate && + "function" !== typeof instance.componentWillUpdate) || + ("function" === typeof instance.componentWillUpdate && + instance.componentWillUpdate( + newProps, + renderExpirationTime, + newUnmaskedContext + ), + "function" === typeof instance.UNSAFE_componentWillUpdate && + instance.UNSAFE_componentWillUpdate( + newProps, + renderExpirationTime, + newUnmaskedContext + )), + "function" === typeof instance.componentDidUpdate && + (workInProgress.effectTag |= 4), + "function" === typeof instance.getSnapshotBeforeUpdate && + (workInProgress.effectTag |= 2048)) + : ("function" !== typeof instance.componentDidUpdate || + (oldProps === current.memoizedProps && + oldContext === current.memoizedState) || + (workInProgress.effectTag |= 4), + "function" !== typeof instance.getSnapshotBeforeUpdate || + (oldProps === current.memoizedProps && + oldContext === current.memoizedState) || + (workInProgress.effectTag |= 2048), + memoizeProps(workInProgress, newProps), + memoizeState(workInProgress, renderExpirationTime)); + instance.props = newProps; + instance.state = renderExpirationTime; + instance.context = newUnmaskedContext; + return derivedStateFromProps; + } + }; +} +var isArray$1 = Array.isArray; +function coerceRef(returnFiber, current, element) { + returnFiber = element.ref; + if ( + null !== returnFiber && + "function" !== typeof returnFiber && + "object" !== typeof returnFiber + ) { + if (element._owner) { + element = element._owner; + var inst = void 0; + element && + (invariant( + 2 === element.tag, + "Stateless function components cannot have refs." + ), + (inst = element.stateNode)); + invariant( + inst, + "Missing owner for string ref %s. This error is likely caused by a bug in React. Please file an issue.", + returnFiber + ); + var stringRef = "" + returnFiber; + if ( + null !== current && + null !== current.ref && + current.ref._stringRef === stringRef + ) + return current.ref; + current = function(value) { + var refs = inst.refs === emptyObject ? (inst.refs = {}) : inst.refs; + null === value ? delete refs[stringRef] : (refs[stringRef] = value); + }; + current._stringRef = stringRef; + return current; + } + invariant( + "string" === typeof returnFiber, + "Expected ref to be a function or a string." + ); + invariant( + element._owner, + "Element ref was specified as a string (%s) but no owner was set. This could happen for one of the following reasons:\n1. You may be adding a ref to a functional 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.", + returnFiber + ); + } + return returnFiber; +} +function throwOnInvalidObjectType(returnFiber, newChild) { + "textarea" !== returnFiber.type && + invariant( + !1, + "Objects are not valid as a React child (found: %s).%s", + "[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, textContent, expirationTime) { + if (null === current || 6 !== current.tag) + return ( + (current = createFiberFromText( + textContent, + returnFiber.mode, + expirationTime + )), + (current["return"] = returnFiber), + current + ); + current = useFiber(current, textContent, expirationTime); + current["return"] = returnFiber; + return current; + } + function updateElement(returnFiber, current, element, expirationTime) { + if (null !== current && current.type === element.type) + return ( + (expirationTime = useFiber(current, element.props, expirationTime)), + (expirationTime.ref = coerceRef(returnFiber, current, element)), + (expirationTime["return"] = returnFiber), + expirationTime + ); + expirationTime = createFiberFromElement( + element, + returnFiber.mode, + expirationTime + ); + expirationTime.ref = coerceRef(returnFiber, current, element); + expirationTime["return"] = returnFiber; + return expirationTime; + } + function updatePortal(returnFiber, current, portal, expirationTime) { + if ( + null === current || + 4 !== current.tag || + current.stateNode.containerInfo !== portal.containerInfo || + current.stateNode.implementation !== portal.implementation + ) + return ( + (current = createFiberFromPortal( + portal, + returnFiber.mode, + expirationTime + )), + (current["return"] = returnFiber), + current + ); + current = useFiber(current, portal.children || [], expirationTime); + current["return"] = returnFiber; + return current; + } + function updateFragment(returnFiber, current, fragment, expirationTime, key) { + if (null === current || 10 !== current.tag) + return ( + (current = createFiberFromFragment( + fragment, + returnFiber.mode, + expirationTime, + key + )), + (current["return"] = returnFiber), + current + ); + current = useFiber(current, fragment, expirationTime); + current["return"] = returnFiber; + return current; + } + 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 = createFiberFromElement( + newChild, + 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$1(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$1(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$1(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++) + if ( + (oldFiber = createChild( + returnFiber, + newChildren[newIdx], + expirationTime + )) + ) + (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++ + ) + if ( + (nextOldFiber = updateFromMap( + oldFiber, + returnFiber, + newIdx, + newChildren[newIdx], + expirationTime + )) + ) { + if (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); + invariant( + "function" === typeof iteratorFn, + "An object is not an iterable. This error is likely caused by a bug in React. Please file an issue." + ); + newChildrenIterable = iteratorFn.call(newChildrenIterable); + invariant( + null != newChildrenIterable, + "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) { + 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() + ) + if ( + ((step = updateFromMap( + oldFiber, + returnFiber, + newIdx, + step.value, + expirationTime + )), + null !== step) + ) { + if (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) { + "object" === typeof newChild && + null !== newChild && + newChild.type === REACT_FRAGMENT_TYPE && + null === newChild.key && + (newChild = newChild.props.children); + var isObject = "object" === typeof newChild && null !== newChild; + if (isObject) + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + a: { + var key = newChild.key; + for (isObject = currentFirstChild; null !== isObject; ) { + if (isObject.key === key) + if ( + 10 === isObject.tag + ? newChild.type === REACT_FRAGMENT_TYPE + : isObject.type === newChild.type + ) { + deleteRemainingChildren(returnFiber, isObject.sibling); + currentFirstChild = useFiber( + isObject, + newChild.type === REACT_FRAGMENT_TYPE + ? newChild.props.children + : newChild.props, + expirationTime + ); + currentFirstChild.ref = coerceRef( + returnFiber, + isObject, + newChild + ); + currentFirstChild["return"] = returnFiber; + returnFiber = currentFirstChild; + break a; + } else { + deleteRemainingChildren(returnFiber, isObject); + break; + } + else deleteChild(returnFiber, isObject); + isObject = isObject.sibling; + } + newChild.type === REACT_FRAGMENT_TYPE + ? ((currentFirstChild = createFiberFromFragment( + newChild.props.children, + returnFiber.mode, + expirationTime, + newChild.key + )), + (currentFirstChild["return"] = returnFiber), + (returnFiber = currentFirstChild)) + : ((expirationTime = createFiberFromElement( + newChild, + returnFiber.mode, + expirationTime + )), + (expirationTime.ref = coerceRef( + returnFiber, + currentFirstChild, + newChild + )), + (expirationTime["return"] = returnFiber), + (returnFiber = expirationTime)); + } + return placeSingleChild(returnFiber); + case REACT_PORTAL_TYPE: + a: { + for (isObject = newChild.key; null !== currentFirstChild; ) { + if (currentFirstChild.key === isObject) + 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; + } else { + 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$1(newChild)) + return reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ); + if (getIteratorFn(newChild)) + return reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ); + isObject && throwOnInvalidObjectType(returnFiber, newChild); + if ("undefined" === typeof newChild) + switch (returnFiber.tag) { + case 2: + case 1: + (expirationTime = returnFiber.type), + invariant( + !1, + "%s(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.", + expirationTime.displayName || expirationTime.name || "Component" + ); + } + return deleteRemainingChildren(returnFiber, currentFirstChild); + }; +} +var reconcileChildFibers = ChildReconciler(!0), + mountChildFibers = ChildReconciler(!1); +function ReactFiberBeginWork( + config, + hostContext, + legacyContext, + newContext, + hydrationContext, + scheduleWork, + computeExpirationForFiber +) { + function reconcileChildren(current, workInProgress, nextChildren) { + reconcileChildrenAtExpirationTime( + current, + workInProgress, + nextChildren, + workInProgress.expirationTime + ); + } + function reconcileChildrenAtExpirationTime( + current, + workInProgress, + nextChildren, + renderExpirationTime + ) { + workInProgress.child = + null === current + ? mountChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ) + : reconcileChildFibers( + workInProgress, + current.child, + nextChildren, + renderExpirationTime + ); + } + function markRef(current, workInProgress) { + var ref = workInProgress.ref; + if ( + (null === current && null !== ref) || + (null !== current && current.ref !== ref) + ) + workInProgress.effectTag |= 128; + } + function finishClassComponent( + current, + workInProgress, + shouldUpdate, + hasContext, + didCaptureError, + renderExpirationTime + ) { + markRef(current, workInProgress); + if (!shouldUpdate && !didCaptureError) + return ( + hasContext && invalidateContextProvider(workInProgress, !1), + bailoutOnAlreadyFinishedWork(current, workInProgress) + ); + shouldUpdate = workInProgress.stateNode; + ReactCurrentOwner.current = workInProgress; + var nextChildren = didCaptureError ? null : shouldUpdate.render(); + workInProgress.effectTag |= 1; + didCaptureError && + (reconcileChildrenAtExpirationTime( + current, + workInProgress, + null, + renderExpirationTime + ), + (workInProgress.child = null)); + reconcileChildrenAtExpirationTime( + current, + workInProgress, + nextChildren, + renderExpirationTime + ); + workInProgress.memoizedState = shouldUpdate.state; + workInProgress.memoizedProps = shouldUpdate.props; + hasContext && invalidateContextProvider(workInProgress, !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 propagateContextChange( + workInProgress, + context, + changedBits, + renderExpirationTime + ) { + var fiber = workInProgress.child; + for ( + null !== fiber && (fiber["return"] = workInProgress); + null !== fiber; + + ) { + switch (fiber.tag) { + case 12: + var nextFiber = fiber.stateNode | 0; + if (fiber.type === context && 0 !== (nextFiber & changedBits)) { + for (nextFiber = fiber; null !== nextFiber; ) { + var alternate = nextFiber.alternate; + if ( + 0 === nextFiber.expirationTime || + nextFiber.expirationTime > renderExpirationTime + ) + (nextFiber.expirationTime = renderExpirationTime), + null !== alternate && + (0 === alternate.expirationTime || + alternate.expirationTime > renderExpirationTime) && + (alternate.expirationTime = renderExpirationTime); + else if ( + null !== alternate && + (0 === alternate.expirationTime || + alternate.expirationTime > renderExpirationTime) + ) + alternate.expirationTime = renderExpirationTime; + else break; + nextFiber = nextFiber["return"]; + } + nextFiber = null; + } else nextFiber = fiber.child; + break; + case 13: + nextFiber = fiber.type === workInProgress.type ? null : fiber.child; + break; + default: + nextFiber = fiber.child; + } + if (null !== nextFiber) nextFiber["return"] = fiber; + else + for (nextFiber = fiber; null !== nextFiber; ) { + if (nextFiber === workInProgress) { + nextFiber = null; + break; + } + fiber = nextFiber.sibling; + if (null !== fiber) { + nextFiber = fiber; + break; + } + nextFiber = nextFiber["return"]; + } + fiber = nextFiber; + } + } + function updateContextProvider( + current, + workInProgress, + renderExpirationTime + ) { + var context = workInProgress.type._context, + newProps = workInProgress.pendingProps, + oldProps = workInProgress.memoizedProps; + if (!hasLegacyContextChanged() && oldProps === newProps) + return ( + (workInProgress.stateNode = 0), + pushProvider(workInProgress), + bailoutOnAlreadyFinishedWork(current, workInProgress) + ); + var newValue = newProps.value; + workInProgress.memoizedProps = newProps; + if (null === oldProps) newValue = 1073741823; + else if (oldProps.value === newProps.value) { + if (oldProps.children === newProps.children) + return ( + (workInProgress.stateNode = 0), + pushProvider(workInProgress), + bailoutOnAlreadyFinishedWork(current, workInProgress) + ); + newValue = 0; + } else { + var oldValue = oldProps.value; + if ( + (oldValue === newValue && + (0 !== oldValue || 1 / oldValue === 1 / newValue)) || + (oldValue !== oldValue && newValue !== newValue) + ) { + if (oldProps.children === newProps.children) + return ( + (workInProgress.stateNode = 0), + pushProvider(workInProgress), + bailoutOnAlreadyFinishedWork(current, workInProgress) + ); + newValue = 0; + } else if ( + ((newValue = + "function" === typeof context._calculateChangedBits + ? context._calculateChangedBits(oldValue, newValue) + : 1073741823), + (newValue |= 0), + 0 === newValue) + ) { + if (oldProps.children === newProps.children) + return ( + (workInProgress.stateNode = 0), + pushProvider(workInProgress), + bailoutOnAlreadyFinishedWork(current, workInProgress) + ); + } else + propagateContextChange( + workInProgress, + context, + newValue, + renderExpirationTime + ); + } + workInProgress.stateNode = newValue; + pushProvider(workInProgress); + reconcileChildren(current, workInProgress, newProps.children); + return workInProgress.child; + } + function bailoutOnAlreadyFinishedWork(current, workInProgress) { + invariant( + null === current || workInProgress.child === current.child, + "Resuming work not yet implemented." + ); + if (null !== workInProgress.child) { + current = workInProgress.child; + var newChild = createWorkInProgress( + current, + current.pendingProps, + current.expirationTime + ); + workInProgress.child = newChild; + for (newChild["return"] = workInProgress; null !== current.sibling; ) + (current = current.sibling), + (newChild = newChild.sibling = createWorkInProgress( + current, + current.pendingProps, + current.expirationTime + )), + (newChild["return"] = workInProgress); + newChild.sibling = null; + } + return workInProgress.child; + } + var shouldSetTextContent = config.shouldSetTextContent, + shouldDeprioritizeSubtree = config.shouldDeprioritizeSubtree, + pushHostContext = hostContext.pushHostContext, + pushHostContainer = hostContext.pushHostContainer, + pushProvider = newContext.pushProvider, + getMaskedContext = legacyContext.getMaskedContext, + getUnmaskedContext = legacyContext.getUnmaskedContext, + hasLegacyContextChanged = legacyContext.hasContextChanged, + pushLegacyContextProvider = legacyContext.pushContextProvider, + pushTopLevelContextObject = legacyContext.pushTopLevelContextObject, + invalidateContextProvider = legacyContext.invalidateContextProvider, + enterHydrationState = hydrationContext.enterHydrationState, + resetHydrationState = hydrationContext.resetHydrationState, + tryToClaimNextHydratableInstance = + hydrationContext.tryToClaimNextHydratableInstance; + config = ReactFiberClassComponent( + legacyContext, + scheduleWork, + computeExpirationForFiber, + function(workInProgress, nextProps) { + workInProgress.memoizedProps = nextProps; + }, + function(workInProgress, nextState) { + workInProgress.memoizedState = nextState; + } + ); + var adoptClassInstance = config.adoptClassInstance, + callGetDerivedStateFromProps = config.callGetDerivedStateFromProps, + constructClassInstance = config.constructClassInstance, + mountClassInstance = config.mountClassInstance, + resumeMountClassInstance = config.resumeMountClassInstance, + updateClassInstance = config.updateClassInstance; + return { + beginWork: function(current, workInProgress, renderExpirationTime) { + if ( + 0 === workInProgress.expirationTime || + workInProgress.expirationTime > renderExpirationTime + ) { + switch (workInProgress.tag) { + case 3: + pushHostRootContext(workInProgress); + break; + case 2: + pushLegacyContextProvider(workInProgress); + break; + case 4: + pushHostContainer( + workInProgress, + workInProgress.stateNode.containerInfo + ); + break; + case 13: + pushProvider(workInProgress); + } + return null; + } + switch (workInProgress.tag) { + case 0: + invariant( + null === current, + "An indeterminate component should never have mounted. This error is likely caused by a bug in React. Please file an issue." + ); + var fn = workInProgress.type, + props = workInProgress.pendingProps, + unmaskedContext = getUnmaskedContext(workInProgress); + unmaskedContext = getMaskedContext(workInProgress, unmaskedContext); + fn = fn(props, unmaskedContext); + workInProgress.effectTag |= 1; + "object" === typeof fn && + null !== fn && + "function" === typeof fn.render && + void 0 === fn.$$typeof + ? ((unmaskedContext = workInProgress.type), + (workInProgress.tag = 2), + (workInProgress.memoizedState = + null !== fn.state && void 0 !== fn.state ? fn.state : null), + "function" === typeof unmaskedContext.getDerivedStateFromProps && + ((props = callGetDerivedStateFromProps( + workInProgress, + fn, + props, + workInProgress.memoizedState + )), + null !== props && + void 0 !== props && + (workInProgress.memoizedState = Object.assign( + {}, + workInProgress.memoizedState, + props + ))), + (props = pushLegacyContextProvider(workInProgress)), + adoptClassInstance(workInProgress, fn), + mountClassInstance(workInProgress, renderExpirationTime), + (current = finishClassComponent( + current, + workInProgress, + !0, + props, + !1, + renderExpirationTime + ))) + : ((workInProgress.tag = 1), + reconcileChildren(current, workInProgress, fn), + (workInProgress.memoizedProps = props), + (current = workInProgress.child)); + return current; + case 1: + return ( + (props = workInProgress.type), + (renderExpirationTime = workInProgress.pendingProps), + hasLegacyContextChanged() || + workInProgress.memoizedProps !== renderExpirationTime + ? ((fn = getUnmaskedContext(workInProgress)), + (fn = getMaskedContext(workInProgress, fn)), + (props = props(renderExpirationTime, fn)), + (workInProgress.effectTag |= 1), + reconcileChildren(current, workInProgress, props), + (workInProgress.memoizedProps = renderExpirationTime), + (current = workInProgress.child)) + : (current = bailoutOnAlreadyFinishedWork( + current, + workInProgress + )), + current + ); + case 2: + props = pushLegacyContextProvider(workInProgress); + null === current + ? null === workInProgress.stateNode + ? (constructClassInstance( + workInProgress, + workInProgress.pendingProps + ), + mountClassInstance(workInProgress, renderExpirationTime), + (fn = !0)) + : (fn = resumeMountClassInstance( + workInProgress, + renderExpirationTime + )) + : (fn = updateClassInstance( + current, + workInProgress, + renderExpirationTime + )); + unmaskedContext = !1; + var updateQueue = workInProgress.updateQueue; + null !== updateQueue && + null !== updateQueue.capturedValues && + (unmaskedContext = fn = !0); + return finishClassComponent( + current, + workInProgress, + fn, + props, + unmaskedContext, + renderExpirationTime + ); + case 3: + a: if ( + (pushHostRootContext(workInProgress), + (fn = workInProgress.updateQueue), + null !== fn) + ) { + unmaskedContext = workInProgress.memoizedState; + props = processUpdateQueue( + current, + workInProgress, + fn, + null, + null, + renderExpirationTime + ); + workInProgress.memoizedState = props; + fn = workInProgress.updateQueue; + if (null !== fn && null !== fn.capturedValues) fn = null; + else if (unmaskedContext === props) { + resetHydrationState(); + current = bailoutOnAlreadyFinishedWork(current, workInProgress); + break a; + } else fn = props.element; + unmaskedContext = workInProgress.stateNode; + (null === current || null === current.child) && + unmaskedContext.hydrate && + enterHydrationState(workInProgress) + ? ((workInProgress.effectTag |= 2), + (workInProgress.child = mountChildFibers( + workInProgress, + null, + fn, + renderExpirationTime + ))) + : (resetHydrationState(), + reconcileChildren(current, workInProgress, fn)); + workInProgress.memoizedState = props; + current = workInProgress.child; + } else + resetHydrationState(), + (current = bailoutOnAlreadyFinishedWork(current, workInProgress)); + return current; + case 5: + a: { + pushHostContext(workInProgress); + null === current && + tryToClaimNextHydratableInstance(workInProgress); + props = workInProgress.type; + updateQueue = workInProgress.memoizedProps; + fn = workInProgress.pendingProps; + unmaskedContext = null !== current ? current.memoizedProps : null; + if (!hasLegacyContextChanged() && updateQueue === fn) { + if ( + (updateQueue = + workInProgress.mode & 1 && + shouldDeprioritizeSubtree(props, fn)) + ) + workInProgress.expirationTime = 1073741823; + if (!updateQueue || 1073741823 !== renderExpirationTime) { + current = bailoutOnAlreadyFinishedWork(current, workInProgress); + break a; + } + } + updateQueue = fn.children; + shouldSetTextContent(props, fn) + ? (updateQueue = null) + : unmaskedContext && + shouldSetTextContent(props, unmaskedContext) && + (workInProgress.effectTag |= 16); + markRef(current, workInProgress); + 1073741823 !== renderExpirationTime && + workInProgress.mode & 1 && + shouldDeprioritizeSubtree(props, fn) + ? ((workInProgress.expirationTime = 1073741823), + (workInProgress.memoizedProps = fn), + (current = null)) + : (reconcileChildren(current, workInProgress, updateQueue), + (workInProgress.memoizedProps = fn), + (current = workInProgress.child)); + } + return current; + case 6: + return ( + null === current && + tryToClaimNextHydratableInstance(workInProgress), + (workInProgress.memoizedProps = workInProgress.pendingProps), + null + ); + case 8: + workInProgress.tag = 7; + case 7: + return ( + (props = workInProgress.pendingProps), + hasLegacyContextChanged() || + workInProgress.memoizedProps !== props || + (props = workInProgress.memoizedProps), + (fn = props.children), + (workInProgress.stateNode = + null === current + ? mountChildFibers( + workInProgress, + workInProgress.stateNode, + fn, + renderExpirationTime + ) + : reconcileChildFibers( + workInProgress, + current.stateNode, + fn, + renderExpirationTime + )), + (workInProgress.memoizedProps = props), + workInProgress.stateNode + ); + case 9: + return null; + case 4: + return ( + pushHostContainer( + workInProgress, + workInProgress.stateNode.containerInfo + ), + (props = workInProgress.pendingProps), + hasLegacyContextChanged() || workInProgress.memoizedProps !== props + ? (null === current + ? (workInProgress.child = reconcileChildFibers( + workInProgress, + null, + props, + renderExpirationTime + )) + : reconcileChildren(current, workInProgress, props), + (workInProgress.memoizedProps = props), + (current = workInProgress.child)) + : (current = bailoutOnAlreadyFinishedWork( + current, + workInProgress + )), + current + ); + case 14: + return ( + (renderExpirationTime = workInProgress.type.render), + (renderExpirationTime = renderExpirationTime( + workInProgress.pendingProps, + workInProgress.ref + )), + reconcileChildren(current, workInProgress, renderExpirationTime), + (workInProgress.memoizedProps = renderExpirationTime), + workInProgress.child + ); + case 10: + return ( + (renderExpirationTime = workInProgress.pendingProps), + hasLegacyContextChanged() || + workInProgress.memoizedProps !== renderExpirationTime + ? (reconcileChildren( + current, + workInProgress, + renderExpirationTime + ), + (workInProgress.memoizedProps = renderExpirationTime), + (current = workInProgress.child)) + : (current = bailoutOnAlreadyFinishedWork( + current, + workInProgress + )), + current + ); + case 11: + return ( + (renderExpirationTime = workInProgress.pendingProps.children), + hasLegacyContextChanged() || + (null !== renderExpirationTime && + workInProgress.memoizedProps !== renderExpirationTime) + ? (reconcileChildren( + current, + workInProgress, + renderExpirationTime + ), + (workInProgress.memoizedProps = renderExpirationTime), + (current = workInProgress.child)) + : (current = bailoutOnAlreadyFinishedWork( + current, + workInProgress + )), + current + ); + case 13: + return updateContextProvider( + current, + workInProgress, + renderExpirationTime + ); + case 12: + a: { + fn = workInProgress.type; + unmaskedContext = workInProgress.pendingProps; + updateQueue = workInProgress.memoizedProps; + props = fn._currentValue; + var changedBits = fn._changedBits; + if ( + hasLegacyContextChanged() || + 0 !== changedBits || + updateQueue !== unmaskedContext + ) { + workInProgress.memoizedProps = unmaskedContext; + var observedBits = unmaskedContext.unstable_observedBits; + if (void 0 === observedBits || null === observedBits) + observedBits = 1073741823; + workInProgress.stateNode = observedBits; + if (0 !== (changedBits & observedBits)) + propagateContextChange( + workInProgress, + fn, + changedBits, + renderExpirationTime + ); + else if (updateQueue === unmaskedContext) { + current = bailoutOnAlreadyFinishedWork(current, workInProgress); + break a; + } + renderExpirationTime = unmaskedContext.children; + renderExpirationTime = renderExpirationTime(props); + reconcileChildren(current, workInProgress, renderExpirationTime); + current = workInProgress.child; + } else + current = bailoutOnAlreadyFinishedWork(current, workInProgress); + } + return current; + default: + invariant( + !1, + "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." + ); + } + } + }; +} +function ReactFiberCompleteWork( + config, + hostContext, + legacyContext, + newContext, + hydrationContext +) { + function markUpdate(workInProgress) { + workInProgress.effectTag |= 4; + } + function appendAllChildren(parent, workInProgress) { + for (var node = workInProgress.child; null !== node; ) { + if (5 === node.tag || 6 === node.tag) + appendInitialChild(parent, 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; + } + } + var createInstance = config.createInstance, + createTextInstance = config.createTextInstance, + appendInitialChild = config.appendInitialChild, + finalizeInitialChildren = config.finalizeInitialChildren, + prepareUpdate = config.prepareUpdate, + persistence = config.persistence, + getRootHostContainer = hostContext.getRootHostContainer, + popHostContext = hostContext.popHostContext, + getHostContext = hostContext.getHostContext, + popHostContainer = hostContext.popHostContainer, + popLegacyContextProvider = legacyContext.popContextProvider, + popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject, + popProvider = newContext.popProvider, + prepareToHydrateHostInstance = + hydrationContext.prepareToHydrateHostInstance, + prepareToHydrateHostTextInstance = + hydrationContext.prepareToHydrateHostTextInstance, + popHydrationState = hydrationContext.popHydrationState, + updateHostContainer = void 0, + updateHostComponent = void 0, + updateHostText = void 0; + if (config.mutation) invariant(!1, "Mutating reconciler is disabled."); + else if (persistence) { + var cloneInstance = persistence.cloneInstance, + createContainerChildSet = persistence.createContainerChildSet, + appendChildToContainerChildSet = + persistence.appendChildToContainerChildSet, + finalizeContainerChildren = persistence.finalizeContainerChildren; + updateHostContainer = function(workInProgress) { + var portalOrRoot = workInProgress.stateNode; + if (null !== workInProgress.firstEffect) { + var container = portalOrRoot.containerInfo, + newChildSet = createContainerChildSet(container); + a: for (var node = workInProgress.child; null !== node; ) { + if (5 === node.tag || 6 === node.tag) + appendChildToContainerChildSet(newChildSet, node.stateNode); + else if (4 !== node.tag && null !== node.child) { + node.child["return"] = node; + node = node.child; + continue; + } + if (node === workInProgress) break a; + for (; null === node.sibling; ) { + if (null === node["return"] || node["return"] === workInProgress) + break a; + node = node["return"]; + } + node.sibling["return"] = node["return"]; + node = node.sibling; + } + portalOrRoot.pendingChildren = newChildSet; + markUpdate(workInProgress); + finalizeContainerChildren(container, newChildSet); + } + }; + updateHostComponent = function( + current, + workInProgress, + updatePayload, + type, + oldProps, + newProps, + rootContainerInstance, + currentHostContext + ) { + var childrenUnchanged = null === workInProgress.firstEffect; + current = current.stateNode; + childrenUnchanged && null === updatePayload + ? (workInProgress.stateNode = current) + : ((updatePayload = cloneInstance( + current, + updatePayload, + type, + oldProps, + newProps, + workInProgress, + childrenUnchanged, + workInProgress.stateNode + )), + finalizeInitialChildren( + updatePayload, + type, + newProps, + rootContainerInstance, + currentHostContext + ) && markUpdate(workInProgress), + (workInProgress.stateNode = updatePayload), + childrenUnchanged + ? markUpdate(workInProgress) + : appendAllChildren(updatePayload, workInProgress)); + }; + updateHostText = function(current, workInProgress, oldText, newText) { + oldText !== newText && + ((current = getRootHostContainer()), + (oldText = getHostContext()), + (workInProgress.stateNode = createTextInstance( + newText, + current, + oldText, + workInProgress + )), + markUpdate(workInProgress)); + }; + } else invariant(!1, "Noop reconciler is disabled."); + return { + completeWork: function(current, workInProgress, renderExpirationTime) { + var newProps = workInProgress.pendingProps; + switch (workInProgress.tag) { + case 1: + return null; + case 2: + return ( + popLegacyContextProvider(workInProgress), + (current = workInProgress.stateNode), + (newProps = workInProgress.updateQueue), + null !== newProps && + null !== newProps.capturedValues && + ((workInProgress.effectTag &= -65), + "function" === typeof current.componentDidCatch + ? (workInProgress.effectTag |= 256) + : (newProps.capturedValues = null)), + null + ); + case 3: + popHostContainer(workInProgress); + popTopLevelLegacyContextObject(workInProgress); + newProps = workInProgress.stateNode; + newProps.pendingContext && + ((newProps.context = newProps.pendingContext), + (newProps.pendingContext = null)); + if (null === current || null === current.child) + popHydrationState(workInProgress), (workInProgress.effectTag &= -3); + updateHostContainer(workInProgress); + current = workInProgress.updateQueue; + null !== current && + null !== current.capturedValues && + (workInProgress.effectTag |= 256); + return null; + case 5: + popHostContext(workInProgress); + renderExpirationTime = getRootHostContainer(); + var type = workInProgress.type; + if (null !== current && null != workInProgress.stateNode) { + var oldProps = current.memoizedProps, + _instance = workInProgress.stateNode, + currentHostContext = getHostContext(); + _instance = prepareUpdate( + _instance, + type, + oldProps, + newProps, + renderExpirationTime, + currentHostContext + ); + updateHostComponent( + current, + workInProgress, + _instance, + type, + oldProps, + newProps, + renderExpirationTime, + currentHostContext + ); + current.ref !== workInProgress.ref && + (workInProgress.effectTag |= 128); + } else { + if (!newProps) + return ( + invariant( + null !== workInProgress.stateNode, + "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." + ), + null + ); + current = getHostContext(); + popHydrationState(workInProgress) + ? prepareToHydrateHostInstance( + workInProgress, + renderExpirationTime, + current + ) && markUpdate(workInProgress) + : ((oldProps = createInstance( + type, + newProps, + renderExpirationTime, + current, + workInProgress + )), + appendAllChildren(oldProps, workInProgress), + finalizeInitialChildren( + oldProps, + type, + newProps, + renderExpirationTime, + current + ) && markUpdate(workInProgress), + (workInProgress.stateNode = oldProps)); + null !== workInProgress.ref && (workInProgress.effectTag |= 128); + } + return null; + case 6: + if (current && null != workInProgress.stateNode) + updateHostText( + current, + workInProgress, + current.memoizedProps, + newProps + ); + else { + if ("string" !== typeof newProps) + return ( + invariant( + null !== workInProgress.stateNode, + "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." + ), + null + ); + current = getRootHostContainer(); + renderExpirationTime = getHostContext(); + popHydrationState(workInProgress) + ? prepareToHydrateHostTextInstance(workInProgress) && + markUpdate(workInProgress) + : (workInProgress.stateNode = createTextInstance( + newProps, + current, + renderExpirationTime, + workInProgress + )); + } + return null; + case 7: + newProps = workInProgress.memoizedProps; + invariant( + newProps, + "Should be resolved by now. This error is likely caused by a bug in React. Please file an issue." + ); + workInProgress.tag = 8; + type = []; + a: for ( + (oldProps = workInProgress.stateNode) && + (oldProps["return"] = workInProgress); + null !== oldProps; + + ) { + if (5 === oldProps.tag || 6 === oldProps.tag || 4 === oldProps.tag) + invariant(!1, "A call cannot have host component children."); + else if (9 === oldProps.tag) type.push(oldProps.pendingProps.value); + else if (null !== oldProps.child) { + oldProps.child["return"] = oldProps; + oldProps = oldProps.child; + continue; + } + for (; null === oldProps.sibling; ) { + if ( + null === oldProps["return"] || + oldProps["return"] === workInProgress + ) + break a; + oldProps = oldProps["return"]; + } + oldProps.sibling["return"] = oldProps["return"]; + oldProps = oldProps.sibling; + } + oldProps = newProps.handler; + newProps = oldProps(newProps.props, type); + workInProgress.child = reconcileChildFibers( + workInProgress, + null !== current ? current.child : null, + newProps, + renderExpirationTime + ); + return workInProgress.child; + case 8: + return (workInProgress.tag = 7), null; + case 9: + return null; + case 14: + return null; + case 10: + return null; + case 11: + return null; + case 4: + return ( + popHostContainer(workInProgress), + updateHostContainer(workInProgress), + null + ); + case 13: + return popProvider(workInProgress), null; + case 12: + return null; + case 0: + invariant( + !1, + "An indeterminate component should have become determinate before completing. This error is likely caused by a bug in React. Please file an issue." + ); + default: + invariant( + !1, + "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." + ); + } + } + }; +} +function ReactFiberUnwindWork( + hostContext, + legacyContext, + newContext, + scheduleWork, + isAlreadyFailedLegacyErrorBoundary +) { + var popHostContainer = hostContext.popHostContainer, + popHostContext = hostContext.popHostContext, + popLegacyContextProvider = legacyContext.popContextProvider, + popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject, + popProvider = newContext.popProvider; + return { + throwException: function(returnFiber, sourceFiber, rawValue) { + sourceFiber.effectTag |= 512; + sourceFiber.firstEffect = sourceFiber.lastEffect = null; + sourceFiber = { + value: rawValue, + source: sourceFiber, + stack: getStackAddendumByWorkInProgressFiber(sourceFiber) + }; + do { + switch (returnFiber.tag) { + case 3: + ensureUpdateQueues(returnFiber); + returnFiber.updateQueue.capturedValues = [sourceFiber]; + returnFiber.effectTag |= 1024; + return; + case 2: + if ( + ((rawValue = returnFiber.stateNode), + 0 === (returnFiber.effectTag & 64) && + null !== rawValue && + "function" === typeof rawValue.componentDidCatch && + !isAlreadyFailedLegacyErrorBoundary(rawValue)) + ) { + ensureUpdateQueues(returnFiber); + rawValue = returnFiber.updateQueue; + var capturedValues = rawValue.capturedValues; + null === capturedValues + ? (rawValue.capturedValues = [sourceFiber]) + : capturedValues.push(sourceFiber); + returnFiber.effectTag |= 1024; + return; + } + } + returnFiber = returnFiber["return"]; + } while (null !== returnFiber); + }, + unwindWork: function(workInProgress) { + switch (workInProgress.tag) { + case 2: + popLegacyContextProvider(workInProgress); + var effectTag = workInProgress.effectTag; + return effectTag & 1024 + ? ((workInProgress.effectTag = (effectTag & -1025) | 64), + workInProgress) + : null; + case 3: + return ( + popHostContainer(workInProgress), + popTopLevelLegacyContextObject(workInProgress), + (effectTag = workInProgress.effectTag), + effectTag & 1024 + ? ((workInProgress.effectTag = (effectTag & -1025) | 64), + workInProgress) + : null + ); + case 5: + return popHostContext(workInProgress), null; + case 4: + return popHostContainer(workInProgress), null; + case 13: + return popProvider(workInProgress), null; + default: + return null; + } + }, + unwindInterruptedWork: function(interruptedWork) { + switch (interruptedWork.tag) { + case 2: + popLegacyContextProvider(interruptedWork); + break; + case 3: + popHostContainer(interruptedWork); + popTopLevelLegacyContextObject(interruptedWork); + break; + case 5: + popHostContext(interruptedWork); + break; + case 4: + popHostContainer(interruptedWork); + break; + case 13: + popProvider(interruptedWork); + } + } + }; +} +function logError(boundary, errorInfo) { + var source = errorInfo.source; + null === errorInfo.stack && getStackAddendumByWorkInProgressFiber(source); + null !== source && getComponentName(source); + errorInfo = errorInfo.value; + null !== boundary && 2 === boundary.tag && getComponentName(boundary); + try { + (errorInfo && errorInfo.suppressReactErrorLogging) || + console.error(errorInfo); + } catch (e) { + (e && e.suppressReactErrorLogging) || console.error(e); + } +} +function ReactFiberCommitWork( + config, + captureError, + scheduleWork, + computeExpirationForFiber, + markLegacyErrorBoundaryAsFailed +) { + function safelyDetachRef(current) { + var ref = current.ref; + if (null !== ref) + if ("function" === typeof ref) + try { + ref(null); + } catch (refError) { + captureError(current, refError); + } + else ref.current = null; + } + function commitBeforeMutationLifeCycles(current, finishedWork) { + switch (finishedWork.tag) { + case 2: + if (finishedWork.effectTag & 2048 && null !== current) { + var prevProps = current.memoizedProps, + prevState = current.memoizedState; + current = finishedWork.stateNode; + current.props = finishedWork.memoizedProps; + current.state = finishedWork.memoizedState; + finishedWork = current.getSnapshotBeforeUpdate(prevProps, prevState); + current.__reactInternalSnapshotBeforeUpdate = finishedWork; + } + break; + case 3: + case 5: + case 6: + case 4: + break; + default: + invariant( + !1, + "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 commitLifeCycles(finishedRoot, current, finishedWork) { + switch (finishedWork.tag) { + case 2: + finishedRoot = finishedWork.stateNode; + if (finishedWork.effectTag & 4) + if (null === current) + (finishedRoot.props = finishedWork.memoizedProps), + (finishedRoot.state = finishedWork.memoizedState), + finishedRoot.componentDidMount(); + else { + var prevProps = current.memoizedProps; + current = current.memoizedState; + finishedRoot.props = finishedWork.memoizedProps; + finishedRoot.state = finishedWork.memoizedState; + finishedRoot.componentDidUpdate( + prevProps, + current, + finishedRoot.__reactInternalSnapshotBeforeUpdate + ); + } + finishedWork = finishedWork.updateQueue; + null !== finishedWork && commitCallbacks(finishedWork, finishedRoot); + break; + case 3: + current = finishedWork.updateQueue; + if (null !== current) { + finishedRoot = null; + if (null !== finishedWork.child) + switch (finishedWork.child.tag) { + case 5: + finishedRoot = getPublicInstance(finishedWork.child.stateNode); + break; + case 2: + finishedRoot = finishedWork.child.stateNode; + } + commitCallbacks(current, finishedRoot); + } + break; + case 5: + finishedRoot = finishedWork.stateNode; + null === current && + finishedWork.effectTag & 4 && + commitMount( + finishedRoot, + finishedWork.type, + finishedWork.memoizedProps, + finishedWork + ); + break; + case 6: + break; + case 4: + break; + default: + invariant( + !1, + "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 commitErrorLogging(finishedWork, onUncaughtError) { + switch (finishedWork.tag) { + case 2: + var ctor = finishedWork.type; + onUncaughtError = finishedWork.stateNode; + var updateQueue = finishedWork.updateQueue; + invariant( + null !== updateQueue && null !== updateQueue.capturedValues, + "An error logging effect should not have been scheduled if no errors were captured. This error is likely caused by a bug in React. Please file an issue." + ); + var capturedErrors = updateQueue.capturedValues; + updateQueue.capturedValues = null; + "function" !== typeof ctor.getDerivedStateFromCatch && + markLegacyErrorBoundaryAsFailed(onUncaughtError); + onUncaughtError.props = finishedWork.memoizedProps; + onUncaughtError.state = finishedWork.memoizedState; + for (ctor = 0; ctor < capturedErrors.length; ctor++) { + updateQueue = capturedErrors[ctor]; + var _error = updateQueue.value, + stack = updateQueue.stack; + logError(finishedWork, updateQueue); + onUncaughtError.componentDidCatch(_error, { + componentStack: null !== stack ? stack : "" + }); + } + break; + case 3: + ctor = finishedWork.updateQueue; + invariant( + null !== ctor && null !== ctor.capturedValues, + "An error logging effect should not have been scheduled if no errors were captured. This error is likely caused by a bug in React. Please file an issue." + ); + capturedErrors = ctor.capturedValues; + ctor.capturedValues = null; + for (ctor = 0; ctor < capturedErrors.length; ctor++) + (updateQueue = capturedErrors[ctor]), + logError(finishedWork, updateQueue), + onUncaughtError(updateQueue.value); + break; + default: + invariant( + !1, + "This unit of work tag cannot capture errors. This error is likely caused by a bug in React. Please file an issue." + ); + } + } + function commitAttachRef(finishedWork) { + var ref = finishedWork.ref; + if (null !== ref) { + var _instance6 = finishedWork.stateNode; + switch (finishedWork.tag) { + case 5: + finishedWork = getPublicInstance(_instance6); + break; + default: + finishedWork = _instance6; + } + "function" === typeof ref + ? ref(finishedWork) + : (ref.current = finishedWork); + } + } + function commitDetachRef(current) { + current = current.ref; + null !== current && + ("function" === typeof current + ? current(null) + : (current.current = null)); + } + function commitNestedUnmounts(root) { + for (var node = root; ; ) { + var current = node; + "function" === typeof onCommitUnmount && onCommitUnmount(current); + switch (current.tag) { + case 2: + safelyDetachRef(current); + var _instance7 = current.stateNode; + if ("function" === typeof _instance7.componentWillUnmount) + try { + (_instance7.props = current.memoizedProps), + (_instance7.state = current.memoizedState), + _instance7.componentWillUnmount(); + } catch (unmountError) { + captureError(current, unmountError); + } + break; + case 5: + safelyDetachRef(current); + break; + case 7: + commitNestedUnmounts(current.stateNode); + break; + case 4: + persistence && emptyPortalContainer(current); + } + if (null === node.child || (mutation && 4 === node.tag)) { + if (node === root) break; + for (; null === node.sibling; ) { + if (null === node["return"] || node["return"] === root) return; + node = node["return"]; + } + node.sibling["return"] = node["return"]; + node = node.sibling; + } else (node.child["return"] = node), (node = node.child); + } + } + var getPublicInstance = config.getPublicInstance, + mutation = config.mutation, + persistence = config.persistence, + emptyPortalContainer = void 0; + if (!mutation) { + var commitContainer = void 0; + if (persistence) { + var replaceContainerChildren = persistence.replaceContainerChildren, + createContainerChildSet = persistence.createContainerChildSet; + emptyPortalContainer = function(current) { + current = current.stateNode.containerInfo; + var emptyChildSet = createContainerChildSet(current); + replaceContainerChildren(current, emptyChildSet); + }; + commitContainer = function(finishedWork) { + switch (finishedWork.tag) { + case 2: + break; + case 5: + break; + case 6: + break; + case 3: + case 4: + finishedWork = finishedWork.stateNode; + replaceContainerChildren( + finishedWork.containerInfo, + finishedWork.pendingChildren + ); + break; + default: + invariant( + !1, + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + }; + } else commitContainer = function() {}; + return { + commitResetTextContent: function() {}, + commitPlacement: function() {}, + commitDeletion: function(current) { + commitNestedUnmounts(current); + current["return"] = null; + current.child = null; + current.alternate && + ((current.alternate.child = null), + (current.alternate["return"] = null)); + }, + commitWork: function(current, finishedWork) { + commitContainer(finishedWork); + }, + commitLifeCycles: commitLifeCycles, + commitBeforeMutationLifeCycles: commitBeforeMutationLifeCycles, + commitErrorLogging: commitErrorLogging, + commitAttachRef: commitAttachRef, + commitDetachRef: commitDetachRef + }; + } + var commitMount = mutation.commitMount; + invariant(!1, "Mutating reconciler is disabled."); +} +var NO_CONTEXT = {}; +function ReactFiberHostContext(config, stack) { + function requiredContext(c) { + invariant( + c !== NO_CONTEXT, + "Expected host context to exist. This error is likely caused by a bug in React. Please file an issue." + ); + return c; + } + var getChildHostContext = config.getChildHostContext, + getRootHostContext = config.getRootHostContext; + config = stack.createCursor; + var push = stack.push, + pop = stack.pop, + contextStackCursor = config(NO_CONTEXT), + contextFiberStackCursor = config(NO_CONTEXT), + rootInstanceStackCursor = config(NO_CONTEXT); + return { + getHostContext: function() { + return requiredContext(contextStackCursor.current); + }, + getRootHostContainer: function() { + return requiredContext(rootInstanceStackCursor.current); + }, + popHostContainer: function(fiber) { + pop(contextStackCursor, fiber); + pop(contextFiberStackCursor, fiber); + pop(rootInstanceStackCursor, fiber); + }, + popHostContext: function(fiber) { + contextFiberStackCursor.current === fiber && + (pop(contextStackCursor, fiber), pop(contextFiberStackCursor, fiber)); + }, + pushHostContainer: function(fiber, nextRootInstance) { + push(rootInstanceStackCursor, nextRootInstance, fiber); + push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor, NO_CONTEXT, fiber); + nextRootInstance = getRootHostContext(nextRootInstance); + pop(contextStackCursor, fiber); + push(contextStackCursor, nextRootInstance, fiber); + }, + pushHostContext: function(fiber) { + var rootInstance = requiredContext(rootInstanceStackCursor.current), + context = requiredContext(contextStackCursor.current); + rootInstance = getChildHostContext(context, fiber.type, rootInstance); + context !== rootInstance && + (push(contextFiberStackCursor, fiber, fiber), + push(contextStackCursor, rootInstance, fiber)); + } + }; +} +function ReactFiberHydrationContext(config) { + function deleteHydratableInstance(returnFiber, instance) { + var fiber = new FiberNode(5, null, null, 0); + fiber.type = "DELETED"; + fiber.stateNode = instance; + fiber["return"] = returnFiber; + fiber.effectTag = 8; + null !== returnFiber.lastEffect + ? ((returnFiber.lastEffect.nextEffect = fiber), + (returnFiber.lastEffect = fiber)) + : (returnFiber.firstEffect = returnFiber.lastEffect = fiber); + } + function tryHydrate(fiber, nextInstance) { + switch (fiber.tag) { + case 5: + return ( + (nextInstance = canHydrateInstance( + nextInstance, + fiber.type, + fiber.pendingProps + )), + null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1 + ); + case 6: + return ( + (nextInstance = canHydrateTextInstance( + nextInstance, + fiber.pendingProps + )), + null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1 + ); + default: + return !1; + } + } + function popToNextHostParent(fiber) { + for ( + fiber = fiber["return"]; + null !== fiber && 5 !== fiber.tag && 3 !== fiber.tag; + + ) + fiber = fiber["return"]; + hydrationParentFiber = fiber; + } + var shouldSetTextContent = config.shouldSetTextContent; + config = config.hydration; + if (!config) + return { + enterHydrationState: function() { + return !1; + }, + resetHydrationState: function() {}, + tryToClaimNextHydratableInstance: function() {}, + prepareToHydrateHostInstance: function() { + invariant( + !1, + "Expected prepareToHydrateHostInstance() to never be called. This error is likely caused by a bug in React. Please file an issue." + ); + }, + prepareToHydrateHostTextInstance: function() { + invariant( + !1, + "Expected prepareToHydrateHostTextInstance() to never be called. This error is likely caused by a bug in React. Please file an issue." + ); + }, + popHydrationState: function() { + return !1; + } + }; + var canHydrateInstance = config.canHydrateInstance, + canHydrateTextInstance = config.canHydrateTextInstance, + getNextHydratableSibling = config.getNextHydratableSibling, + getFirstHydratableChild = config.getFirstHydratableChild, + hydrateInstance = config.hydrateInstance, + hydrateTextInstance = config.hydrateTextInstance, + hydrationParentFiber = null, + nextHydratableInstance = null, + isHydrating = !1; + return { + enterHydrationState: function(fiber) { + nextHydratableInstance = getFirstHydratableChild( + fiber.stateNode.containerInfo + ); + hydrationParentFiber = fiber; + return (isHydrating = !0); + }, + resetHydrationState: function() { + nextHydratableInstance = hydrationParentFiber = null; + isHydrating = !1; + }, + tryToClaimNextHydratableInstance: function(fiber) { + if (isHydrating) { + var nextInstance = nextHydratableInstance; + if (nextInstance) { + if (!tryHydrate(fiber, nextInstance)) { + nextInstance = getNextHydratableSibling(nextInstance); + if (!nextInstance || !tryHydrate(fiber, nextInstance)) { + fiber.effectTag |= 2; + isHydrating = !1; + hydrationParentFiber = fiber; + return; + } + deleteHydratableInstance( + hydrationParentFiber, + nextHydratableInstance + ); + } + hydrationParentFiber = fiber; + nextHydratableInstance = getFirstHydratableChild(nextInstance); + } else + (fiber.effectTag |= 2), + (isHydrating = !1), + (hydrationParentFiber = fiber); + } + }, + prepareToHydrateHostInstance: function( + fiber, + rootContainerInstance, + hostContext + ) { + rootContainerInstance = hydrateInstance( + fiber.stateNode, + fiber.type, + fiber.memoizedProps, + rootContainerInstance, + hostContext, + fiber + ); + fiber.updateQueue = rootContainerInstance; + return null !== rootContainerInstance ? !0 : !1; + }, + prepareToHydrateHostTextInstance: function(fiber) { + return hydrateTextInstance(fiber.stateNode, fiber.memoizedProps, fiber); + }, + popHydrationState: function(fiber) { + if (fiber !== hydrationParentFiber) return !1; + if (!isHydrating) + return popToNextHostParent(fiber), (isHydrating = !0), !1; + var type = fiber.type; + if ( + 5 !== fiber.tag || + ("head" !== type && + "body" !== type && + !shouldSetTextContent(type, fiber.memoizedProps)) + ) + for (type = nextHydratableInstance; type; ) + deleteHydratableInstance(fiber, type), + (type = getNextHydratableSibling(type)); + popToNextHostParent(fiber); + nextHydratableInstance = hydrationParentFiber + ? getNextHydratableSibling(fiber.stateNode) + : null; + return !0; + } + }; +} +function ReactFiberLegacyContext(stack) { + function cacheContext(workInProgress, unmaskedContext, maskedContext) { + workInProgress = workInProgress.stateNode; + workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; + workInProgress.__reactInternalMemoizedMaskedChildContext = maskedContext; + } + function isContextProvider(fiber) { + return 2 === fiber.tag && null != fiber.type.childContextTypes; + } + function processChildContext(fiber, parentContext) { + var instance = fiber.stateNode, + childContextTypes = fiber.type.childContextTypes; + if ("function" !== typeof instance.getChildContext) return parentContext; + instance = instance.getChildContext(); + for (var contextKey in instance) + invariant( + contextKey in childContextTypes, + '%s.getChildContext(): key "%s" is not defined in childContextTypes.', + getComponentName(fiber) || "Unknown", + contextKey + ); + return Object.assign({}, parentContext, instance); + } + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop, + contextStackCursor = createCursor(emptyObject), + didPerformWorkStackCursor = createCursor(!1), + previousContext = emptyObject; + return { + getUnmaskedContext: function(workInProgress) { + return isContextProvider(workInProgress) + ? previousContext + : contextStackCursor.current; + }, + cacheContext: cacheContext, + getMaskedContext: function(workInProgress, unmaskedContext) { + var contextTypes = workInProgress.type.contextTypes; + if (!contextTypes) return emptyObject; + var instance = workInProgress.stateNode; + if ( + instance && + instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext + ) + return instance.__reactInternalMemoizedMaskedChildContext; + var context = {}, + key; + for (key in contextTypes) context[key] = unmaskedContext[key]; + instance && cacheContext(workInProgress, unmaskedContext, context); + return context; + }, + hasContextChanged: function() { + return didPerformWorkStackCursor.current; + }, + isContextConsumer: function(fiber) { + return 2 === fiber.tag && null != fiber.type.contextTypes; + }, + isContextProvider: isContextProvider, + popContextProvider: function(fiber) { + isContextProvider(fiber) && + (pop(didPerformWorkStackCursor, fiber), pop(contextStackCursor, fiber)); + }, + popTopLevelContextObject: function(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); + }, + pushTopLevelContextObject: function(fiber, context, didChange) { + invariant( + null == contextStackCursor.cursor, + "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); + }, + processChildContext: processChildContext, + pushContextProvider: function(workInProgress) { + if (!isContextProvider(workInProgress)) return !1; + var instance = workInProgress.stateNode; + instance = + (instance && instance.__reactInternalMemoizedMergedChildContext) || + emptyObject; + previousContext = contextStackCursor.current; + push(contextStackCursor, instance, workInProgress); + push( + didPerformWorkStackCursor, + didPerformWorkStackCursor.current, + workInProgress + ); + return !0; + }, + invalidateContextProvider: function(workInProgress, didChange) { + var instance = workInProgress.stateNode; + invariant( + instance, + "Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue." + ); + if (didChange) { + var mergedContext = processChildContext( + workInProgress, + previousContext + ); + instance.__reactInternalMemoizedMergedChildContext = mergedContext; + pop(didPerformWorkStackCursor, workInProgress); + pop(contextStackCursor, workInProgress); + push(contextStackCursor, mergedContext, workInProgress); + } else pop(didPerformWorkStackCursor, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); + }, + findCurrentUnmaskedContext: function(fiber) { + for ( + invariant( + 2 === isFiberMountedImpl(fiber) && 2 === fiber.tag, + "Expected subtree parent to be a mounted class component. This error is likely caused by a bug in React. Please file an issue." + ); + 3 !== fiber.tag; + + ) { + if (isContextProvider(fiber)) + return fiber.stateNode.__reactInternalMemoizedMergedChildContext; + fiber = fiber["return"]; + invariant( + fiber, + "Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + return fiber.stateNode.context; + } + }; +} +function ReactFiberNewContext(stack) { + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop, + providerCursor = createCursor(null), + valueCursor = createCursor(null), + changedBitsCursor = createCursor(0); + return { + pushProvider: function(providerFiber) { + var context = providerFiber.type._context; + push(changedBitsCursor, context._changedBits, providerFiber); + push(valueCursor, context._currentValue, providerFiber); + push(providerCursor, providerFiber, providerFiber); + context._currentValue = providerFiber.pendingProps.value; + context._changedBits = providerFiber.stateNode; + }, + popProvider: function(providerFiber) { + var changedBits = changedBitsCursor.current, + currentValue = valueCursor.current; + pop(providerCursor, providerFiber); + pop(valueCursor, providerFiber); + pop(changedBitsCursor, providerFiber); + providerFiber = providerFiber.type._context; + providerFiber._currentValue = currentValue; + providerFiber._changedBits = changedBits; + } + }; +} +function ReactFiberStack() { + var valueStack = [], + index = -1; + return { + createCursor: function(defaultValue) { + return { current: defaultValue }; + }, + isEmpty: function() { + return -1 === index; + }, + pop: function(cursor) { + 0 > index || + ((cursor.current = valueStack[index]), + (valueStack[index] = null), + index--); + }, + push: function(cursor, value) { + index++; + valueStack[index] = cursor.current; + cursor.current = value; + }, + checkThatStackIsEmpty: function() {}, + resetStackAfterFatalErrorInDev: function() {} + }; +} +function ReactFiberScheduler(config) { + function resetStack() { + if (null !== nextUnitOfWork) + for ( + var interruptedWork = nextUnitOfWork["return"]; + null !== interruptedWork; + + ) + unwindInterruptedWork(interruptedWork), + (interruptedWork = interruptedWork["return"]); + nextRoot = null; + nextRenderExpirationTime = 0; + nextUnitOfWork = null; + isRootReadyForCommit = !1; + } + function isAlreadyFailedLegacyErrorBoundary(instance) { + return ( + null !== legacyErrorBoundariesThatAlreadyFailed && + legacyErrorBoundariesThatAlreadyFailed.has(instance) + ); + } + function completeUnitOfWork(workInProgress$jscomp$0) { + for (;;) { + var current = workInProgress$jscomp$0.alternate, + returnFiber = workInProgress$jscomp$0["return"], + siblingFiber = workInProgress$jscomp$0.sibling; + if (0 === (workInProgress$jscomp$0.effectTag & 512)) { + current = completeWork( + current, + workInProgress$jscomp$0, + nextRenderExpirationTime + ); + var workInProgress = workInProgress$jscomp$0; + if ( + 1073741823 === nextRenderExpirationTime || + 1073741823 !== workInProgress.expirationTime + ) { + b: switch (workInProgress.tag) { + case 3: + case 2: + var newExpirationTime = workInProgress.updateQueue; + newExpirationTime = + null === newExpirationTime + ? 0 + : newExpirationTime.expirationTime; + break b; + default: + newExpirationTime = 0; + } + for (var child = workInProgress.child; null !== child; ) + 0 !== child.expirationTime && + (0 === newExpirationTime || + newExpirationTime > child.expirationTime) && + (newExpirationTime = child.expirationTime), + (child = child.sibling); + workInProgress.expirationTime = newExpirationTime; + } + if (null !== current) return current; + null !== returnFiber && + 0 === (returnFiber.effectTag & 512) && + (null === returnFiber.firstEffect && + (returnFiber.firstEffect = workInProgress$jscomp$0.firstEffect), + null !== workInProgress$jscomp$0.lastEffect && + (null !== returnFiber.lastEffect && + (returnFiber.lastEffect.nextEffect = + workInProgress$jscomp$0.firstEffect), + (returnFiber.lastEffect = workInProgress$jscomp$0.lastEffect)), + 1 < workInProgress$jscomp$0.effectTag && + (null !== returnFiber.lastEffect + ? (returnFiber.lastEffect.nextEffect = workInProgress$jscomp$0) + : (returnFiber.firstEffect = workInProgress$jscomp$0), + (returnFiber.lastEffect = workInProgress$jscomp$0))); + if (null !== siblingFiber) return siblingFiber; + if (null !== returnFiber) workInProgress$jscomp$0 = returnFiber; + else { + isRootReadyForCommit = !0; + break; + } + } else { + workInProgress$jscomp$0 = unwindWork(workInProgress$jscomp$0); + if (null !== workInProgress$jscomp$0) + return ( + (workInProgress$jscomp$0.effectTag &= 2559), workInProgress$jscomp$0 + ); + null !== returnFiber && + ((returnFiber.firstEffect = returnFiber.lastEffect = null), + (returnFiber.effectTag |= 512)); + if (null !== siblingFiber) return siblingFiber; + if (null !== returnFiber) workInProgress$jscomp$0 = returnFiber; + else break; + } + } + return null; + } + function performUnitOfWork(workInProgress) { + var next = beginWork( + workInProgress.alternate, + workInProgress, + nextRenderExpirationTime + ); + null === next && (next = completeUnitOfWork(workInProgress)); + ReactCurrentOwner.current = null; + return next; + } + function renderRoot(root, expirationTime, isAsync) { + invariant( + !isWorking, + "renderRoot was called recursively. This error is likely caused by a bug in React. Please file an issue." + ); + isWorking = !0; + if ( + expirationTime !== nextRenderExpirationTime || + root !== nextRoot || + null === nextUnitOfWork + ) + resetStack(), + (nextRoot = root), + (nextRenderExpirationTime = expirationTime), + (nextUnitOfWork = createWorkInProgress( + nextRoot.current, + null, + nextRenderExpirationTime + )), + (root.pendingCommitExpirationTime = 0); + var didFatal = !1; + do { + try { + if (isAsync) + for (; null !== nextUnitOfWork && !shouldYield(); ) + nextUnitOfWork = performUnitOfWork(nextUnitOfWork); + else + for (; null !== nextUnitOfWork; ) + nextUnitOfWork = performUnitOfWork(nextUnitOfWork); + } catch (thrownValue) { + if (null === nextUnitOfWork) { + didFatal = !0; + onUncaughtError(thrownValue); + break; + } + isAsync = nextUnitOfWork; + var returnFiber = isAsync["return"]; + if (null === returnFiber) { + didFatal = !0; + onUncaughtError(thrownValue); + break; + } + throwException(returnFiber, isAsync, thrownValue); + nextUnitOfWork = completeUnitOfWork(isAsync); + } + break; + } while (1); + isWorking = !1; + if (didFatal || null !== nextUnitOfWork) return null; + if (isRootReadyForCommit) + return ( + (root.pendingCommitExpirationTime = expirationTime), + root.current.alternate + ); + invariant( + !1, + "Expired work should have completed. This error is likely caused by a bug in React. Please file an issue." + ); + } + function scheduleCapture(sourceFiber, boundaryFiber, value, expirationTime) { + sourceFiber = { + value: value, + source: sourceFiber, + stack: getStackAddendumByWorkInProgressFiber(sourceFiber) + }; + insertUpdateIntoFiber(boundaryFiber, { + expirationTime: expirationTime, + partialState: null, + callback: null, + isReplace: !1, + isForced: !1, + capturedValue: sourceFiber, + next: null + }); + scheduleWork(boundaryFiber, expirationTime); + } + function onCommitPhaseError(fiber$jscomp$0, error) { + a: { + invariant( + !isWorking || isCommitting, + "dispatch: Cannot dispatch during the render phase." + ); + for (var fiber = fiber$jscomp$0["return"]; null !== fiber; ) { + switch (fiber.tag) { + case 2: + var instance = fiber.stateNode; + if ( + "function" === typeof fiber.type.getDerivedStateFromCatch || + ("function" === typeof instance.componentDidCatch && + !isAlreadyFailedLegacyErrorBoundary(instance)) + ) { + scheduleCapture(fiber$jscomp$0, fiber, error, 1); + fiber$jscomp$0 = void 0; + break a; + } + break; + case 3: + scheduleCapture(fiber$jscomp$0, fiber, error, 1); + fiber$jscomp$0 = void 0; + break a; + } + fiber = fiber["return"]; + } + 3 === fiber$jscomp$0.tag && + scheduleCapture(fiber$jscomp$0, fiber$jscomp$0, error, 1); + fiber$jscomp$0 = void 0; + } + return fiber$jscomp$0; + } + function computeExpirationForFiber(fiber) { + fiber = + 0 !== expirationContext + ? expirationContext + : isWorking + ? isCommitting ? 1 : nextRenderExpirationTime + : fiber.mode & 1 + ? isBatchingInteractiveUpdates + ? 10 * ((((recalculateCurrentTime() + 15) / 10) | 0) + 1) + : 25 * ((((recalculateCurrentTime() + 500) / 25) | 0) + 1) + : 1; + isBatchingInteractiveUpdates && + (0 === lowestPendingInteractiveExpirationTime || + fiber > lowestPendingInteractiveExpirationTime) && + (lowestPendingInteractiveExpirationTime = fiber); + return fiber; + } + function scheduleWork(fiber, expirationTime) { + a: { + for (; null !== fiber; ) { + if (0 === fiber.expirationTime || fiber.expirationTime > expirationTime) + fiber.expirationTime = expirationTime; + null !== fiber.alternate && + (0 === fiber.alternate.expirationTime || + fiber.alternate.expirationTime > expirationTime) && + (fiber.alternate.expirationTime = expirationTime); + if (null === fiber["return"]) + if (3 === fiber.tag) { + var root = fiber.stateNode; + !isWorking && + 0 !== nextRenderExpirationTime && + expirationTime < nextRenderExpirationTime && + resetStack(); + (isWorking && !isCommitting && nextRoot === root) || + requestWork(root, expirationTime); + nestedUpdateCount > NESTED_UPDATE_LIMIT && + invariant( + !1, + "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." + ); + } else { + expirationTime = void 0; + break a; + } + fiber = fiber["return"]; + } + expirationTime = void 0; + } + return expirationTime; + } + function recalculateCurrentTime() { + mostRecentCurrentTimeMs = now() - originalStartTimeMs; + return (mostRecentCurrentTime = ((mostRecentCurrentTimeMs / 10) | 0) + 2); + } + function syncUpdates(fn, a, b, c, d) { + var previousExpirationContext = expirationContext; + expirationContext = 1; + try { + return fn(a, b, c, d); + } finally { + expirationContext = previousExpirationContext; + } + } + function scheduleCallbackWithExpiration(expirationTime) { + if (0 !== callbackExpirationTime) { + if (expirationTime > callbackExpirationTime) return; + cancelDeferredCallback(callbackID); + } + var currentMs = now() - originalStartTimeMs; + callbackExpirationTime = expirationTime; + callbackID = scheduleDeferredCallback(performAsyncWork, { + timeout: 10 * (expirationTime - 2) - currentMs + }); + } + function requestWork(root, expirationTime) { + if (null === root.nextScheduledRoot) + (root.remainingExpirationTime = expirationTime), + null === lastScheduledRoot + ? ((firstScheduledRoot = lastScheduledRoot = root), + (root.nextScheduledRoot = root)) + : ((lastScheduledRoot = lastScheduledRoot.nextScheduledRoot = root), + (lastScheduledRoot.nextScheduledRoot = firstScheduledRoot)); + else { + var remainingExpirationTime = root.remainingExpirationTime; + if ( + 0 === remainingExpirationTime || + expirationTime < remainingExpirationTime + ) + root.remainingExpirationTime = expirationTime; + } + isRendering || + (isBatchingUpdates + ? isUnbatchingUpdates && + ((nextFlushedRoot = root), + (nextFlushedExpirationTime = 1), + performWorkOnRoot(root, 1, !1)) + : 1 === expirationTime + ? performSyncWork() + : scheduleCallbackWithExpiration(expirationTime)); + } + function findHighestPriorityRoot() { + var highestPriorityWork = 0, + highestPriorityRoot = null; + if (null !== lastScheduledRoot) + for ( + var previousScheduledRoot = lastScheduledRoot, + root = firstScheduledRoot; + null !== root; + + ) { + var remainingExpirationTime = root.remainingExpirationTime; + if (0 === remainingExpirationTime) { + invariant( + null !== previousScheduledRoot && null !== lastScheduledRoot, + "Should have a previous and last root. This error is likely caused by a bug in React. Please file an issue." + ); + if (root === root.nextScheduledRoot) { + firstScheduledRoot = lastScheduledRoot = root.nextScheduledRoot = null; + break; + } else if (root === firstScheduledRoot) + (firstScheduledRoot = remainingExpirationTime = + root.nextScheduledRoot), + (lastScheduledRoot.nextScheduledRoot = remainingExpirationTime), + (root.nextScheduledRoot = null); + else if (root === lastScheduledRoot) { + lastScheduledRoot = previousScheduledRoot; + lastScheduledRoot.nextScheduledRoot = firstScheduledRoot; + root.nextScheduledRoot = null; + break; + } else + (previousScheduledRoot.nextScheduledRoot = root.nextScheduledRoot), + (root.nextScheduledRoot = null); + root = previousScheduledRoot.nextScheduledRoot; + } else { + if ( + 0 === highestPriorityWork || + remainingExpirationTime < highestPriorityWork + ) + (highestPriorityWork = remainingExpirationTime), + (highestPriorityRoot = root); + if (root === lastScheduledRoot) break; + previousScheduledRoot = root; + root = root.nextScheduledRoot; + } + } + previousScheduledRoot = nextFlushedRoot; + null !== previousScheduledRoot && + previousScheduledRoot === highestPriorityRoot && + 1 === highestPriorityWork + ? nestedUpdateCount++ + : (nestedUpdateCount = 0); + nextFlushedRoot = highestPriorityRoot; + nextFlushedExpirationTime = highestPriorityWork; + } + function performAsyncWork(dl) { + performWork(0, !0, dl); + } + function performSyncWork() { + performWork(1, !1, null); + } + function performWork(minExpirationTime, isAsync, dl) { + deadline = dl; + findHighestPriorityRoot(); + if (isAsync) + for ( + ; + null !== nextFlushedRoot && + 0 !== nextFlushedExpirationTime && + (0 === minExpirationTime || + minExpirationTime >= nextFlushedExpirationTime) && + (!deadlineDidExpire || + recalculateCurrentTime() >= nextFlushedExpirationTime); + + ) + performWorkOnRoot( + nextFlushedRoot, + nextFlushedExpirationTime, + !deadlineDidExpire + ), + findHighestPriorityRoot(); + else + for ( + ; + null !== nextFlushedRoot && + 0 !== nextFlushedExpirationTime && + (0 === minExpirationTime || + minExpirationTime >= nextFlushedExpirationTime); + + ) + performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime, !1), + findHighestPriorityRoot(); + null !== deadline && ((callbackExpirationTime = 0), (callbackID = -1)); + 0 !== nextFlushedExpirationTime && + scheduleCallbackWithExpiration(nextFlushedExpirationTime); + deadline = null; + deadlineDidExpire = !1; + finishRendering(); + } + function finishRendering() { + nestedUpdateCount = 0; + if (null !== completedBatches) { + var batches = completedBatches; + completedBatches = null; + for (var i = 0; i < batches.length; i++) { + var batch = batches[i]; + try { + batch._onComplete(); + } catch (error) { + hasUnhandledError || + ((hasUnhandledError = !0), (unhandledError = error)); + } + } + } + if (hasUnhandledError) + throw ((batches = unhandledError), + (unhandledError = null), + (hasUnhandledError = !1), + batches); + } + function performWorkOnRoot(root, expirationTime, isAsync) { + invariant( + !isRendering, + "performWorkOnRoot was called recursively. This error is likely caused by a bug in React. Please file an issue." + ); + isRendering = !0; + isAsync + ? ((isAsync = root.finishedWork), + null !== isAsync + ? completeRoot(root, isAsync, expirationTime) + : ((root.finishedWork = null), + (isAsync = renderRoot(root, expirationTime, !0)), + null !== isAsync && + (shouldYield() + ? (root.finishedWork = isAsync) + : completeRoot(root, isAsync, expirationTime)))) + : ((isAsync = root.finishedWork), + null !== isAsync + ? completeRoot(root, isAsync, expirationTime) + : ((root.finishedWork = null), + (isAsync = renderRoot(root, expirationTime, !1)), + null !== isAsync && completeRoot(root, isAsync, expirationTime))); + isRendering = !1; + } + function completeRoot(root, finishedWork, expirationTime) { + var firstBatch = root.firstBatch; + if ( + null !== firstBatch && + firstBatch._expirationTime <= expirationTime && + (null === completedBatches + ? (completedBatches = [firstBatch]) + : completedBatches.push(firstBatch), + firstBatch._defer) + ) { + root.finishedWork = finishedWork; + root.remainingExpirationTime = 0; + return; + } + root.finishedWork = null; + isCommitting = isWorking = !0; + expirationTime = finishedWork.stateNode; + invariant( + expirationTime.current !== finishedWork, + "Cannot commit the same tree as before. This is probably a bug related to the return field. This error is likely caused by a bug in React. Please file an issue." + ); + firstBatch = expirationTime.pendingCommitExpirationTime; + invariant( + 0 !== firstBatch, + "Cannot commit an incomplete root. This error is likely caused by a bug in React. Please file an issue." + ); + expirationTime.pendingCommitExpirationTime = 0; + var currentTime = recalculateCurrentTime(); + ReactCurrentOwner.current = null; + if (1 < finishedWork.effectTag) + if (null !== finishedWork.lastEffect) { + finishedWork.lastEffect.nextEffect = finishedWork; + var firstEffect = finishedWork.firstEffect; + } else firstEffect = finishedWork; + else firstEffect = finishedWork.firstEffect; + prepareForCommit(expirationTime.containerInfo); + for (nextEffect = firstEffect; null !== nextEffect; ) { + var didError = !1, + error = void 0; + try { + for (; null !== nextEffect; ) + nextEffect.effectTag & 2048 && + commitBeforeMutationLifeCycles(nextEffect.alternate, nextEffect), + (nextEffect = nextEffect.nextEffect); + } catch (e) { + (didError = !0), (error = e); + } + didError && + (invariant( + null !== nextEffect, + "Should have next effect. This error is likely caused by a bug in React. Please file an issue." + ), + onCommitPhaseError(nextEffect, error), + null !== nextEffect && (nextEffect = nextEffect.nextEffect)); + } + for (nextEffect = firstEffect; null !== nextEffect; ) { + didError = !1; + error = void 0; + try { + for (; null !== nextEffect; ) { + var effectTag = nextEffect.effectTag; + effectTag & 16 && commitResetTextContent(nextEffect); + if (effectTag & 128) { + var current = nextEffect.alternate; + null !== current && commitDetachRef(current); + } + 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: + commitDeletion(nextEffect); + } + nextEffect = nextEffect.nextEffect; + } + } catch (e) { + (didError = !0), (error = e); + } + didError && + (invariant( + null !== nextEffect, + "Should have next effect. This error is likely caused by a bug in React. Please file an issue." + ), + onCommitPhaseError(nextEffect, error), + null !== nextEffect && (nextEffect = nextEffect.nextEffect)); + } + resetAfterCommit(expirationTime.containerInfo); + expirationTime.current = finishedWork; + for (nextEffect = firstEffect; null !== nextEffect; ) { + effectTag = !1; + current = void 0; + try { + for ( + firstEffect = expirationTime, + didError = currentTime, + error = firstBatch; + null !== nextEffect; + + ) { + var effectTag$jscomp$0 = nextEffect.effectTag; + effectTag$jscomp$0 & 36 && + commitLifeCycles( + firstEffect, + nextEffect.alternate, + nextEffect, + didError, + error + ); + effectTag$jscomp$0 & 256 && + commitErrorLogging(nextEffect, onUncaughtError); + effectTag$jscomp$0 & 128 && commitAttachRef(nextEffect); + var next = nextEffect.nextEffect; + nextEffect.nextEffect = null; + nextEffect = next; + } + } catch (e) { + (effectTag = !0), (current = e); + } + effectTag && + (invariant( + null !== nextEffect, + "Should have next effect. This error is likely caused by a bug in React. Please file an issue." + ), + onCommitPhaseError(nextEffect, current), + null !== nextEffect && (nextEffect = nextEffect.nextEffect)); + } + isWorking = isCommitting = !1; + "function" === typeof onCommitRoot && onCommitRoot(finishedWork.stateNode); + finishedWork = expirationTime.current.expirationTime; + 0 === finishedWork && (legacyErrorBoundariesThatAlreadyFailed = null); + root.remainingExpirationTime = finishedWork; + } + function shouldYield() { + return null === deadline || + deadline.timeRemaining() > timeHeuristicForUnitOfWork + ? !1 + : (deadlineDidExpire = !0); + } + function onUncaughtError(error) { + invariant( + null !== nextFlushedRoot, + "Should be working on a root. This error is likely caused by a bug in React. Please file an issue." + ); + nextFlushedRoot.remainingExpirationTime = 0; + hasUnhandledError || ((hasUnhandledError = !0), (unhandledError = error)); + } + var stack = ReactFiberStack(), + hostContext = ReactFiberHostContext(config, stack), + legacyContext = ReactFiberLegacyContext(stack); + stack = ReactFiberNewContext(stack); + var hydrationContext = ReactFiberHydrationContext(config), + beginWork = ReactFiberBeginWork( + config, + hostContext, + legacyContext, + stack, + hydrationContext, + scheduleWork, + computeExpirationForFiber + ).beginWork, + completeWork = ReactFiberCompleteWork( + config, + hostContext, + legacyContext, + stack, + hydrationContext + ).completeWork; + hostContext = ReactFiberUnwindWork( + hostContext, + legacyContext, + stack, + scheduleWork, + isAlreadyFailedLegacyErrorBoundary + ); + var throwException = hostContext.throwException, + unwindWork = hostContext.unwindWork, + unwindInterruptedWork = hostContext.unwindInterruptedWork; + hostContext = ReactFiberCommitWork( + config, + onCommitPhaseError, + scheduleWork, + computeExpirationForFiber, + function(instance) { + null === legacyErrorBoundariesThatAlreadyFailed + ? (legacyErrorBoundariesThatAlreadyFailed = new Set([instance])) + : legacyErrorBoundariesThatAlreadyFailed.add(instance); + }, + recalculateCurrentTime + ); + var commitBeforeMutationLifeCycles = + hostContext.commitBeforeMutationLifeCycles, + commitResetTextContent = hostContext.commitResetTextContent, + commitPlacement = hostContext.commitPlacement, + commitDeletion = hostContext.commitDeletion, + commitWork = hostContext.commitWork, + commitLifeCycles = hostContext.commitLifeCycles, + commitErrorLogging = hostContext.commitErrorLogging, + commitAttachRef = hostContext.commitAttachRef, + commitDetachRef = hostContext.commitDetachRef, + now = config.now, + scheduleDeferredCallback = config.scheduleDeferredCallback, + cancelDeferredCallback = config.cancelDeferredCallback, + prepareForCommit = config.prepareForCommit, + resetAfterCommit = config.resetAfterCommit, + originalStartTimeMs = now(), + mostRecentCurrentTime = 2, + mostRecentCurrentTimeMs = originalStartTimeMs, + lastUniqueAsyncExpiration = 0, + expirationContext = 0, + isWorking = !1, + nextUnitOfWork = null, + nextRoot = null, + nextRenderExpirationTime = 0, + nextEffect = null, + isCommitting = !1, + isRootReadyForCommit = !1, + legacyErrorBoundariesThatAlreadyFailed = null, + firstScheduledRoot = null, + lastScheduledRoot = null, + callbackExpirationTime = 0, + callbackID = -1, + isRendering = !1, + nextFlushedRoot = null, + nextFlushedExpirationTime = 0, + lowestPendingInteractiveExpirationTime = 0, + deadlineDidExpire = !1, + hasUnhandledError = !1, + unhandledError = null, + deadline = null, + isBatchingUpdates = !1, + isUnbatchingUpdates = !1, + isBatchingInteractiveUpdates = !1, + completedBatches = null, + NESTED_UPDATE_LIMIT = 1e3, + nestedUpdateCount = 0, + timeHeuristicForUnitOfWork = 1; + return { + recalculateCurrentTime: recalculateCurrentTime, + computeExpirationForFiber: computeExpirationForFiber, + scheduleWork: scheduleWork, + requestWork: requestWork, + flushRoot: function(root, expirationTime) { + invariant( + !isRendering, + "work.commit(): Cannot commit while already rendering. This likely means you attempted to commit from inside a lifecycle method." + ); + nextFlushedRoot = root; + nextFlushedExpirationTime = expirationTime; + performWorkOnRoot(root, expirationTime, !1); + performSyncWork(); + finishRendering(); + }, + batchedUpdates: function(fn, a) { + var previousIsBatchingUpdates = isBatchingUpdates; + isBatchingUpdates = !0; + try { + return fn(a); + } finally { + (isBatchingUpdates = previousIsBatchingUpdates) || + isRendering || + performSyncWork(); + } + }, + unbatchedUpdates: function(fn, a) { + if (isBatchingUpdates && !isUnbatchingUpdates) { + isUnbatchingUpdates = !0; + try { + return fn(a); + } finally { + isUnbatchingUpdates = !1; + } + } + return fn(a); + }, + flushSync: function(fn, a) { + invariant( + !isRendering, + "flushSync was called from inside a lifecycle method. It cannot be called when React is already rendering." + ); + var previousIsBatchingUpdates = isBatchingUpdates; + isBatchingUpdates = !0; + try { + return syncUpdates(fn, a); + } finally { + (isBatchingUpdates = previousIsBatchingUpdates), performSyncWork(); + } + }, + flushControlled: function(fn) { + var previousIsBatchingUpdates = isBatchingUpdates; + isBatchingUpdates = !0; + try { + syncUpdates(fn); + } finally { + (isBatchingUpdates = previousIsBatchingUpdates) || + isRendering || + performWork(1, !1, null); + } + }, + deferredUpdates: function(fn) { + var previousExpirationContext = expirationContext; + expirationContext = + 25 * ((((recalculateCurrentTime() + 500) / 25) | 0) + 1); + try { + return fn(); + } finally { + expirationContext = previousExpirationContext; + } + }, + syncUpdates: syncUpdates, + interactiveUpdates: function(fn, a, b) { + if (isBatchingInteractiveUpdates) return fn(a, b); + isBatchingUpdates || + isRendering || + 0 === lowestPendingInteractiveExpirationTime || + (performWork(lowestPendingInteractiveExpirationTime, !1, null), + (lowestPendingInteractiveExpirationTime = 0)); + var previousIsBatchingInteractiveUpdates = isBatchingInteractiveUpdates, + previousIsBatchingUpdates = isBatchingUpdates; + isBatchingUpdates = isBatchingInteractiveUpdates = !0; + try { + return fn(a, b); + } finally { + (isBatchingInteractiveUpdates = previousIsBatchingInteractiveUpdates), + (isBatchingUpdates = previousIsBatchingUpdates) || + isRendering || + performSyncWork(); + } + }, + flushInteractiveUpdates: function() { + isRendering || + 0 === lowestPendingInteractiveExpirationTime || + (performWork(lowestPendingInteractiveExpirationTime, !1, null), + (lowestPendingInteractiveExpirationTime = 0)); + }, + computeUniqueAsyncExpiration: function() { + var result = 25 * ((((recalculateCurrentTime() + 500) / 25) | 0) + 1); + result <= lastUniqueAsyncExpiration && + (result = lastUniqueAsyncExpiration + 1); + return (lastUniqueAsyncExpiration = result); + }, + legacyContext: legacyContext + }; +} +function ReactFiberReconciler$1(config) { + function updateContainerAtExpirationTime( + element, + container, + parentComponent, + currentTime, + expirationTime, + callback + ) { + currentTime = container.current; + if (parentComponent) { + parentComponent = parentComponent._reactInternalFiber; + var parentContext = findCurrentUnmaskedContext(parentComponent); + parentComponent = isContextProvider(parentComponent) + ? processChildContext(parentComponent, parentContext) + : parentContext; + } else parentComponent = emptyObject; + null === container.context + ? (container.context = parentComponent) + : (container.pendingContext = parentComponent); + container = callback; + insertUpdateIntoFiber(currentTime, { + expirationTime: expirationTime, + partialState: { element: element }, + callback: void 0 === container ? null : container, + isReplace: !1, + isForced: !1, + capturedValue: null, + next: null + }); + scheduleWork(currentTime, expirationTime); + return expirationTime; + } + var getPublicInstance = config.getPublicInstance; + config = ReactFiberScheduler(config); + var recalculateCurrentTime = config.recalculateCurrentTime, + computeExpirationForFiber = config.computeExpirationForFiber, + scheduleWork = config.scheduleWork, + legacyContext = config.legacyContext, + findCurrentUnmaskedContext = legacyContext.findCurrentUnmaskedContext, + isContextProvider = legacyContext.isContextProvider, + processChildContext = legacyContext.processChildContext; + return { + createContainer: function(containerInfo, isAsync, hydrate) { + isAsync = new FiberNode(3, null, null, isAsync ? 3 : 0); + containerInfo = { + current: isAsync, + containerInfo: containerInfo, + pendingChildren: null, + pendingCommitExpirationTime: 0, + finishedWork: null, + context: null, + pendingContext: null, + hydrate: hydrate, + remainingExpirationTime: 0, + firstBatch: null, + nextScheduledRoot: null + }; + return (isAsync.stateNode = containerInfo); + }, + updateContainer: function(element, container, parentComponent, callback) { + var current = container.current, + currentTime = recalculateCurrentTime(); + current = computeExpirationForFiber(current); + return updateContainerAtExpirationTime( + element, + container, + parentComponent, + currentTime, + current, + callback + ); + }, + updateContainerAtExpirationTime: function( + element, + container, + parentComponent, + expirationTime, + callback + ) { + var currentTime = recalculateCurrentTime(); + return updateContainerAtExpirationTime( + element, + container, + parentComponent, + currentTime, + expirationTime, + callback + ); + }, + flushRoot: config.flushRoot, + requestWork: config.requestWork, + computeUniqueAsyncExpiration: config.computeUniqueAsyncExpiration, + batchedUpdates: config.batchedUpdates, + unbatchedUpdates: config.unbatchedUpdates, + deferredUpdates: config.deferredUpdates, + syncUpdates: config.syncUpdates, + interactiveUpdates: config.interactiveUpdates, + flushInteractiveUpdates: config.flushInteractiveUpdates, + flushControlled: config.flushControlled, + flushSync: config.flushSync, + getPublicRootInstance: function(container) { + container = container.current; + if (!container.child) return null; + switch (container.child.tag) { + case 5: + return getPublicInstance(container.child.stateNode); + default: + return container.child.stateNode; + } + }, + findHostInstance: function(component) { + var fiber = component._reactInternalFiber; + void 0 === fiber && + ("function" === typeof component.render + ? invariant(!1, "Unable to find node on an unmounted component.") + : invariant( + !1, + "Argument appears to not be a ReactComponent. Keys: %s", + Object.keys(component) + )); + component = findCurrentHostFiber(fiber); + return null === component ? null : component.stateNode; + }, + findHostInstanceWithNoPortals: function(fiber) { + fiber = findCurrentHostFiberWithNoPortals(fiber); + return null === fiber ? null : fiber.stateNode; + }, + injectIntoDevTools: function(devToolsConfig) { + var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; + return injectInternals( + Object.assign({}, devToolsConfig, { + findHostInstanceByFiber: function(fiber) { + fiber = findCurrentHostFiber(fiber); + return null === fiber ? null : fiber.stateNode; + }, + findFiberByHostInstance: function(instance) { + return findFiberByHostInstance + ? findFiberByHostInstance(instance) + : null; + } + }) + ); + } + }; +} +var ReactFiberReconciler$2 = Object.freeze({ default: ReactFiberReconciler$1 }), + ReactFiberReconciler$3 = + (ReactFiberReconciler$2 && ReactFiberReconciler$1) || + ReactFiberReconciler$2, + reactReconciler = ReactFiberReconciler$3["default"] + ? ReactFiberReconciler$3["default"] + : ReactFiberReconciler$3, + nextReactTag = 2, + ReactFabricHostComponent = (function() { + function ReactFabricHostComponent(tag, viewConfig, props) { + if (!(this instanceof ReactFabricHostComponent)) + throw new TypeError("Cannot call a class as a function"); + this._nativeTag = tag; + this.viewConfig = viewConfig; + this.currentProps = props; + } + ReactFabricHostComponent.prototype.blur = function() { + TextInputState.blurTextInput(this._nativeTag); + }; + ReactFabricHostComponent.prototype.focus = function() { + TextInputState.focusTextInput(this._nativeTag); + }; + ReactFabricHostComponent.prototype.measure = function(callback) { + UIManager.measure(this._nativeTag, mountSafeCallback(this, callback)); + }; + ReactFabricHostComponent.prototype.measureInWindow = function(callback) { + UIManager.measureInWindow( + this._nativeTag, + mountSafeCallback(this, callback) + ); + }; + ReactFabricHostComponent.prototype.measureLayout = function( + relativeToNativeNode, + onSuccess, + onFail + ) { + UIManager.measureLayout( + this._nativeTag, + relativeToNativeNode, + mountSafeCallback(this, onFail), + mountSafeCallback(this, onSuccess) + ); + }; + ReactFabricHostComponent.prototype.setNativeProps = function(nativeProps) { + nativeProps = diffProperties( + null, + emptyObject$1, + nativeProps, + this.viewConfig.validAttributes + ); + null != nativeProps && + UIManager.updateView( + this._nativeTag, + this.viewConfig.uiViewClassName, + nativeProps + ); + }; + return ReactFabricHostComponent; + })(), + ReactFabricRenderer = reactReconciler({ + appendInitialChild: function(parentInstance, child) { + FabricUIManager.appendChild(parentInstance.node, child.node); + }, + createInstance: function( + type, + props, + rootContainerInstance, + hostContext, + internalInstanceHandle + ) { + hostContext = nextReactTag; + nextReactTag += 2; + type = ReactNativeViewConfigRegistry.get(type); + var updatePayload = diffProperties( + null, + emptyObject$1, + props, + type.validAttributes + ); + rootContainerInstance = FabricUIManager.createNode( + hostContext, + type.uiViewClassName, + rootContainerInstance, + updatePayload, + internalInstanceHandle + ); + props = new ReactFabricHostComponent(hostContext, type, props); + return { node: rootContainerInstance, canonical: props }; + }, + createTextInstance: function( + text, + rootContainerInstance, + hostContext, + internalInstanceHandle + ) { + hostContext = nextReactTag; + nextReactTag += 2; + return { + node: FabricUIManager.createNode( + hostContext, + "RCTRawText", + rootContainerInstance, + { text: text }, + internalInstanceHandle + ) + }; + }, + finalizeInitialChildren: function() { + return !1; + }, + getRootHostContext: function() { + return emptyObject; + }, + getChildHostContext: function() { + return emptyObject; + }, + getPublicInstance: function(instance) { + return instance.canonical; + }, + now: now, + prepareForCommit: function() {}, + prepareUpdate: function(instance, type, oldProps, newProps) { + return diffProperties( + null, + oldProps, + newProps, + instance.canonical.viewConfig.validAttributes + ); + }, + resetAfterCommit: function() {}, + scheduleDeferredCallback: function(callback) { + scheduledCallback = callback; + return setTimeout(setTimeoutCallback, 1); + }, + cancelDeferredCallback: function(callbackID) { + scheduledCallback = null; + clearTimeout(callbackID); + }, + shouldDeprioritizeSubtree: function() { + return !1; + }, + shouldSetTextContent: function() { + return !1; + }, + persistence: { + cloneInstance: function( + instance, + updatePayload, + type, + oldProps, + newProps, + internalInstanceHandle, + keepChildren + ) { + type = instance.node; + return { + node: keepChildren + ? null !== updatePayload + ? FabricUIManager.cloneNodeWithNewProps(type, updatePayload) + : FabricUIManager.cloneNode(type) + : null !== updatePayload + ? FabricUIManager.cloneNodeWithNewChildrenAndProps( + type, + updatePayload + ) + : FabricUIManager.cloneNodeWithNewChildren(type), + canonical: instance.canonical + }; + }, + createContainerChildSet: function(container) { + return FabricUIManager.createChildSet(container); + }, + appendChildToContainerChildSet: function(childSet, child) { + FabricUIManager.appendChildToSet(childSet, child.node); + }, + finalizeContainerChildren: function(container, newChildren) { + FabricUIManager.completeRoot(container, newChildren); + }, + replaceContainerChildren: function() {} + } + }), + getInspectorDataForViewTag = void 0; +getInspectorDataForViewTag = function() { + invariant(!1, "getInspectorDataForViewTag() is not available in production"); +}; +var findHostInstance = ReactFabricRenderer.findHostInstance; +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; +} +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() { + TextInputState.blurTextInput(findNodeHandle(this)); + }; + ReactNativeComponent.prototype.focus = function() { + TextInputState.focusTextInput(findNodeHandle(this)); + }; + ReactNativeComponent.prototype.measure = function(callback) { + UIManager.measure( + findNodeHandle(this), + mountSafeCallback(this, callback) + ); + }; + ReactNativeComponent.prototype.measureInWindow = function(callback) { + UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback(this, callback) + ); + }; + ReactNativeComponent.prototype.measureLayout = function( + relativeToNativeNode, + onSuccess, + onFail + ) { + UIManager.measureLayout( + findNodeHandle(this), + relativeToNativeNode, + mountSafeCallback(this, onFail), + mountSafeCallback(this, onSuccess) + ); + }; + ReactNativeComponent.prototype.setNativeProps = function(nativeProps) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + if (null != maybeInstance) { + var viewConfig = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + nativeProps = diffProperties( + null, + emptyObject$1, + nativeProps, + viewConfig.validAttributes + ); + null != nativeProps && + UIManager.updateView( + maybeInstance._nativeTag, + viewConfig.uiViewClassName, + nativeProps + ); + } + }; + return ReactNativeComponent; + })(React.Component); + })(findNodeHandle, findHostInstance), + findNodeHandle: findNodeHandle, + render: function(element, containerTag, callback) { + var root = roots.get(containerTag); + root || + ((root = ReactFabricRenderer.createContainer(containerTag, !1, !1)), + roots.set(containerTag, root)); + ReactFabricRenderer.updateContainer(element, root, null, callback); + return ReactFabricRenderer.getPublicRootInstance(root); + }, + unmountComponentAtNode: function(containerTag) { + var root = roots.get(containerTag); + root && + ReactFabricRenderer.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) { + UIManager.measure( + findNodeHandle(this), + mountSafeCallback(this, callback) + ); + }, + measureInWindow: function(callback) { + UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback(this, callback) + ); + }, + measureLayout: function(relativeToNativeNode, onSuccess, onFail) { + UIManager.measureLayout( + findNodeHandle(this), + relativeToNativeNode, + mountSafeCallback(this, onFail), + mountSafeCallback(this, onSuccess) + ); + }, + setNativeProps: function(nativeProps) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + if (null != maybeInstance) { + var viewConfig = maybeInstance.viewConfig; + nativeProps = diffProperties( + null, + emptyObject$1, + nativeProps, + viewConfig.validAttributes + ); + null != nativeProps && + UIManager.updateView( + maybeInstance._nativeTag, + viewConfig.uiViewClassName, + nativeProps + ); + } + }, + focus: function() { + TextInputState.focusTextInput(findNodeHandle(this)); + }, + blur: function() { + TextInputState.blurTextInput(findNodeHandle(this)); + } + }; + })(findNodeHandle, findHostInstance), + ReactNativeComponentTree: ReactNativeComponentTree + } + }; +ReactFabricRenderer.injectIntoDevTools({ + findFiberByHostInstance: getInstanceFromTag, + getInspectorDataForViewTag: getInspectorDataForViewTag, + bundleType: 0, + version: "16.3.2", + rendererPackageName: "react-native-renderer" +}); +var ReactFabric$2 = Object.freeze({ default: ReactFabric }), + ReactFabric$3 = (ReactFabric$2 && ReactFabric) || ReactFabric$2; +module.exports = ReactFabric$3["default"] + ? ReactFabric$3["default"] + : ReactFabric$3; diff --git a/Libraries/Renderer/oss/ReactNativeRenderer-dev.js b/Libraries/Renderer/oss/ReactNativeRenderer-dev.js new file mode 100644 index 00000000000000..9e14a0c266e9db --- /dev/null +++ b/Libraries/Renderer/oss/ReactNativeRenderer-dev.js @@ -0,0 +1,14432 @@ +/** + * Copyright (c) 2013-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @noflow + * @providesModule ReactNativeRenderer-dev + * @preventMunge + */ + +'use strict'; + +if (__DEV__) { + (function() { +"use strict"; + +require("InitializeCore"); +var invariant = require("fbjs/lib/invariant"); +var warning = require("fbjs/lib/warning"); +var emptyFunction = require("fbjs/lib/emptyFunction"); +var ReactNativeViewConfigRegistry = require("ReactNativeViewConfigRegistry"); +var UIManager = require("UIManager"); +var RCTEventEmitter = require("RCTEventEmitter"); +var TextInputState = require("TextInputState"); +var deepDiffer = require("deepDiffer"); +var flattenStyle = require("flattenStyle"); +var React = require("react"); +var emptyObject = require("fbjs/lib/emptyObject"); +var shallowEqual = require("fbjs/lib/shallowEqual"); +var ExceptionsManager = require("ExceptionsManager"); +var checkPropTypes = require("prop-types/checkPropTypes"); +var deepFreezeAndThrowOnMutationInDev = require("deepFreezeAndThrowOnMutationInDev"); + +var invokeGuardedCallback = function(name, func, context, a, b, c, d, e, f) { + this._hasCaughtError = false; + this._caughtError = null; + var funcArgs = Array.prototype.slice.call(arguments, 3); + try { + func.apply(context, funcArgs); + } catch (error) { + this._caughtError = error; + this._hasCaughtError = true; + } +}; + +{ + // 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 + // untintuitive, 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. + invariant( + typeof document !== "undefined", + "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; + + // 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); + 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 onError(event) { + error = event.error; + didSetError = true; + if (error === null && event.colno === 0 && event.lineno === 0) { + isCrossOriginError = true; + } + } + + // Create a fake event type. + var evtType = "react-" + (name ? name : "invokeguardedcallback"); + + // Attach our event handlers + window.addEventListener("error", onError); + 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 (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._hasCaughtError = true; + this._caughtError = error; + } else { + this._hasCaughtError = false; + this._caughtError = null; + } + + // Remove our event listeners + window.removeEventListener("error", onError); + }; + + invokeGuardedCallback = invokeGuardedCallbackDev; + } +} + +var invokeGuardedCallback$1 = invokeGuardedCallback; + +var ReactErrorUtils = { + // Used by Fiber to simulate a try-catch. + _caughtError: null, + _hasCaughtError: false, + + // Used by event system to capture/rethrow the first error. + _rethrowError: null, + _hasRethrowError: false, + + /** + * 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 + */ + invokeGuardedCallback: function(name, func, context, a, b, c, d, e, f) { + invokeGuardedCallback$1.apply(ReactErrorUtils, 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 + */ + invokeGuardedCallbackAndCatchFirstError: function( + name, + func, + context, + a, + b, + c, + d, + e, + f + ) { + ReactErrorUtils.invokeGuardedCallback.apply(this, arguments); + if (ReactErrorUtils.hasCaughtError()) { + var error = ReactErrorUtils.clearCaughtError(); + if (!ReactErrorUtils._hasRethrowError) { + ReactErrorUtils._hasRethrowError = true; + ReactErrorUtils._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. + */ + rethrowCaughtError: function() { + return rethrowCaughtError.apply(ReactErrorUtils, arguments); + }, + + hasCaughtError: function() { + return ReactErrorUtils._hasCaughtError; + }, + + clearCaughtError: function() { + if (ReactErrorUtils._hasCaughtError) { + var error = ReactErrorUtils._caughtError; + ReactErrorUtils._caughtError = null; + ReactErrorUtils._hasCaughtError = false; + return error; + } else { + invariant( + false, + "clearCaughtError was called but no error was captured. This error " + + "is likely caused by a bug in React. Please file an issue." + ); + } + } +}; + +var rethrowCaughtError = function() { + if (ReactErrorUtils._hasRethrowError) { + var error = ReactErrorUtils._rethrowError; + ReactErrorUtils._rethrowError = null; + ReactErrorUtils._hasRethrowError = false; + throw error; + } +}; + +/** + * 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); + invariant( + pluginIndex > -1, + "EventPluginRegistry: Cannot inject event plugins that do not exist in " + + "the plugin ordering, `%s`.", + pluginName + ); + if (plugins[pluginIndex]) { + continue; + } + invariant( + pluginModule.extractEvents, + "EventPluginRegistry: Event plugins must implement an `extractEvents` " + + "method, but `%s` does not.", + pluginName + ); + plugins[pluginIndex] = pluginModule; + var publishedEvents = pluginModule.eventTypes; + for (var eventName in publishedEvents) { + invariant( + publishEventForPlugin( + publishedEvents[eventName], + pluginModule, + eventName + ), + "EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.", + eventName, + 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) { + invariant( + !eventNameDispatchConfigs.hasOwnProperty(eventName), + "EventPluginHub: More than one plugin attempted to publish the same " + + "event name, `%s`.", + 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) { + invariant( + !registrationNameModules[registrationName], + "EventPluginHub: More than one plugin attempted to publish the same " + + "registration name, `%s`.", + 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) { + invariant( + !eventPluginOrder, + "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 + ) { + invariant( + !namesToPlugins[pluginName], + "EventPluginRegistry: Cannot inject two different event plugins " + + "using the same name, `%s`.", + pluginName + ); + namesToPlugins[pluginName] = pluginModule; + isOrderingDirty = true; + } + } + if (isOrderingDirty) { + recomputePluginOrdering(); + } +} + +var getFiberCurrentPropsFromNode = null; +var getInstanceFromNode = null; +var getNodeFromInstance = null; + +var injection$1 = { + injectComponentTree: function(Injected) { + getFiberCurrentPropsFromNode = Injected.getFiberCurrentPropsFromNode; + getInstanceFromNode = Injected.getInstanceFromNode; + getNodeFromInstance = Injected.getNodeFromInstance; + + { + !(getNodeFromInstance && getInstanceFromNode) + ? warning( + false, + "EventPluginUtils.injection.injectComponentTree(...): Injected " + + "module is missing getNodeFromInstance or getInstanceFromNode." + ) + : void 0; + } + } +}; + +function isEndish(topLevelType) { + return ( + topLevelType === "topMouseUp" || + topLevelType === "topTouchEnd" || + topLevelType === "topTouchCancel" + ); +} + +function isMoveish(topLevelType) { + return topLevelType === "topMouseMove" || topLevelType === "topTouchMove"; +} +function isStartish(topLevelType) { + return topLevelType === "topMouseDown" || topLevelType === "topTouchStart"; +} + +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) + ? warning(false, "EventPluginUtils: Invalid `event`.") + : void 0; + }; +} + +/** + * Dispatch the event to the listener. + * @param {SyntheticEvent} event SyntheticEvent to handle + * @param {boolean} simulated If the event is simulated (changes exn behavior) + * @param {function} listener Application-level callback + * @param {*} inst Internal component instance + */ +function executeDispatch(event, simulated, listener, inst) { + var type = event.type || "unknown-event"; + event.currentTarget = getNodeFromInstance(inst); + ReactErrorUtils.invokeGuardedCallbackAndCatchFirstError( + type, + listener, + undefined, + event + ); + event.currentTarget = null; +} + +/** + * Standard/simple iteration through an event's collected dispatches. + */ +function executeDispatchesInOrder(event, simulated) { + 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, + simulated, + dispatchListeners[i], + dispatchInstances[i] + ); + } + } else if (dispatchListeners) { + executeDispatch(event, simulated, 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; + invariant( + !Array.isArray(dispatchListener), + "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) { + invariant( + next != null, + "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. + * @param {boolean} simulated If the event is simulated (changes exn behavior) + * @private + */ +var executeDispatchesAndRelease = function(event, simulated) { + if (event) { + executeDispatchesInOrder(event, simulated); + + if (!event.isPersistent()) { + event.constructor.release(event); + } + } +}; +var executeDispatchesAndReleaseSimulated = function(e) { + return executeDispatchesAndRelease(e, true); +}; +var executeDispatchesAndReleaseTopLevel = function(e) { + return executeDispatchesAndRelease(e, false); +}; + +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; + } + invariant( + !listener || typeof listener === "function", + "Expected `%s` listener to be a function, instead got a value of `%s` type.", + registrationName, + typeof listener + ); + return listener; +} + +/** + * Allows registered plugins an opportunity to extract events from top-level + * native browser events. + * + * @return {*} An accumulation of synthetic events. + * @internal + */ +function extractEvents( + 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 runEventsInBatch(events, simulated) { + 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; + } + + if (simulated) { + forEachAccumulated( + processingEventQueue, + executeDispatchesAndReleaseSimulated + ); + } else { + forEachAccumulated( + processingEventQueue, + executeDispatchesAndReleaseTopLevel + ); + } + invariant( + !eventQueue, + "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. + ReactErrorUtils.rethrowCaughtError(); +} + +function runExtractedEventsInBatch( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget +) { + var events = extractEvents( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ); + runEventsInBatch(events, false); +} + +var IndeterminateComponent = 0; // Before we know whether it is functional or class +var FunctionalComponent = 1; +var ClassComponent = 2; +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 CallComponent = 7; +var CallHandlerPhase = 8; +var ReturnComponent = 9; +var Fragment = 10; +var Mode = 11; +var ContextConsumer = 12; +var ContextProvider = 13; +var ForwardRef = 14; + +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 ? warning(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 didWarnForAddedNewProperty = false; +var EVENT_POOL_SIZE = 10; + +var shouldBeReleasedProperties = [ + "dispatchConfig", + "_targetInst", + "nativeEvent", + "isDefaultPrevented", + "isPropagationStopped", + "_dispatchListeners", + "_dispatchInstances" +]; + +/** + * @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: emptyFunction.thatReturnsNull, + eventPhase: null, + bubbles: null, + cancelable: null, + timeStamp: function(event) { + return event.timeStamp || Date.now(); + }, + defaultPrevented: null, + isTrusted: null +}; + +/** + * 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; + } + + 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 = emptyFunction.thatReturnsTrue; + } else { + this.isDefaultPrevented = emptyFunction.thatReturnsFalse; + } + this.isPropagationStopped = emptyFunction.thatReturnsFalse; + 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 = emptyFunction.thatReturnsTrue; + }, + + 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 = emptyFunction.thatReturnsTrue; + }, + + /** + * 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 = emptyFunction.thatReturnsTrue; + }, + + /** + * Checks if this event should be released back into the pool. + * + * @return {boolean} True if this should not be released, false otherwise. + */ + isPersistent: emptyFunction.thatReturnsFalse, + + /** + * `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]) + ); + } + } + for (var i = 0; i < shouldBeReleasedProperties.length; i++) { + this[shouldBeReleasedProperties[i]] = null; + } + { + Object.defineProperty( + this, + "nativeEvent", + getPooledWarningPropertyDefinition("nativeEvent", null) + ); + Object.defineProperty( + this, + "preventDefault", + getPooledWarningPropertyDefinition("preventDefault", emptyFunction) + ); + Object.defineProperty( + this, + "stopPropagation", + getPooledWarningPropertyDefinition("stopPropagation", emptyFunction) + ); + } + } +}); + +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; +}; + +/** Proxying after everything set on SyntheticEvent + * to resolve Proxy issue on some WebKit browsers + * in which some Event properties are set to undefined (GH#10010) + */ +{ + var isProxySupported = + typeof Proxy === "function" && + // https://github.com/facebook/react/issues/12011 + !Object.isSealed(new Proxy({}, {})); + + if (isProxySupported) { + /*eslint-disable no-func-assign */ + SyntheticEvent = new Proxy(SyntheticEvent, { + construct: function(target, args) { + return this.apply(target, Object.create(target.prototype), args); + }, + apply: function(constructor, that, args) { + return new Proxy(constructor.apply(that, args), { + set: function(target, prop, value) { + if ( + prop !== "isPersistent" && + !target.constructor.Interface.hasOwnProperty(prop) && + shouldBeReleasedProperties.indexOf(prop) === -1 + ) { + !(didWarnForAddedNewProperty || target.isPersistent()) + ? warning( + false, + "This synthetic event is reused for performance reasons. If you're " + + "seeing this, you're adding a new property in the synthetic event object. " + + "The property is never released. See " + + "https://fb.me/react-event-pooling for more information." + ) + : void 0; + didWarnForAddedNewProperty = true; + } + target[prop] = value; + return true; + } + }); + } + }); + /*eslint-enable no-func-assign */ + } +} + +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$$1 + }; + + function set(val) { + var action = isFunction ? "setting the method" : "setting the property"; + warn(action, "This is effectively a no-op"); + return val; + } + + function get$$1() { + 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 + ? warning( + 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; + invariant( + event instanceof EventConstructor, + "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; +} + +var SyntheticEvent$1 = SyntheticEvent; + +/** + * `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$1.extend({ + touchHistory: function(nativeEvent) { + return null; // Actually doesn't even look at the native event. + } +}); + +/** + * 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; + + invariant(identifier != null, "Touch object is missing identifier."); + { + !(identifier <= MAX_TOUCH_BANK) + ? warning( + 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) + ? warning(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) { + invariant( + next != null, + "accumulate(...): Accumulated items must be 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; + +/** + * Last reported number of active touches. + */ +var previousActiveTouches = 0; + +var changeResponder = function(nextResponderInst, blockHostResponder) { + var oldResponderInst = responderInst; + responderInst = nextResponderInst; + if (ResponderEventPlugin.GlobalResponderHandler !== null) { + ResponderEventPlugin.GlobalResponderHandler.onChange( + oldResponderInst, + nextResponderInst, + blockHostResponder + ); + } +}; + +var eventTypes$1 = { + /** + * On a `touchStart`/`mouseDown`, is it desired that this element become the + * responder? + */ + startShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onStartShouldSetResponder", + captured: "onStartShouldSetResponderCapture" + } + }, + + /** + * 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" + } + }, + + /** + * 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" + } + }, + + /** + * On a `touchMove`/`mouseMove`, is it desired that this element become the + * responder? + */ + moveShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onMoveShouldSetResponder", + captured: "onMoveShouldSetResponderCapture" + } + }, + + /** + * Direct responder events dispatched directly to responder. Do not bubble. + */ + responderStart: { registrationName: "onResponderStart" }, + responderMove: { registrationName: "onResponderMove" }, + responderEnd: { registrationName: "onResponderEnd" }, + responderRelease: { registrationName: "onResponderRelease" }, + responderTerminationRequest: { + registrationName: "onResponderTerminationRequest" + }, + responderGrant: { registrationName: "onResponderGrant" }, + responderReject: { registrationName: "onResponderReject" }, + responderTerminate: { registrationName: "onResponderTerminate" } +}; + +/** + * + * 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$1.startShouldSetResponder + : isMoveish(topLevelType) + ? eventTypes$1.moveShouldSetResponder + : topLevelType === "topSelectionChange" + ? eventTypes$1.selectionChangeShouldSetResponder + : eventTypes$1.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$1.responderGrant, + wantsResponderInst, + nativeEvent, + nativeEventTarget + ); + grantEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + + accumulateDirectDispatches(grantEvent); + var blockHostResponder = executeDirectDispatch(grantEvent) === true; + if (responderInst) { + var terminationRequestEvent = ResponderSyntheticEvent.getPooled( + eventTypes$1.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$1.responderTerminate, + responderInst, + nativeEvent, + nativeEventTarget + ); + terminateEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches(terminateEvent); + extracted = accumulate(extracted, [grantEvent, terminateEvent]); + changeResponder(wantsResponderInst, blockHostResponder); + } else { + var rejectEvent = ResponderSyntheticEvent.getPooled( + eventTypes$1.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 === "topScroll" && !nativeEvent.responderIgnoreScroll) || + (trackedTouchCount > 0 && topLevelType === "topSelectionChange") || + 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$1, + + /** + * 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$1.responderStart + : isResponderTouchMove + ? eventTypes$1.responderMove + : isResponderTouchEnd ? eventTypes$1.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 === "topTouchCancel"; + var isResponderRelease = + responderInst && + !isResponderTerminate && + isEndish(topLevelType) && + noResponderTouches(nativeEvent); + var finalTouch = isResponderTerminate + ? eventTypes$1.responderTerminate + : isResponderRelease ? eventTypes$1.responderRelease : null; + if (finalTouch) { + var finalEvent = ResponderSyntheticEvent.getPooled( + finalTouch, + responderInst, + nativeEvent, + nativeEventTarget + ); + finalEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches(finalEvent); + extracted = accumulate(extracted, finalEvent); + changeResponder(null); + } + + var numberActiveTouches = + ResponderTouchHistoryStore.touchHistory.numberActiveTouches; + if ( + ResponderEventPlugin.GlobalInteractionHandler && + numberActiveTouches !== previousActiveTouches + ) { + ResponderEventPlugin.GlobalInteractionHandler.onChange( + numberActiveTouches + ); + } + previousActiveTouches = numberActiveTouches; + + return extracted; + }, + + GlobalResponderHandler: null, + GlobalInteractionHandler: 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; + }, + + /** + * @param {{onChange: (numberActiveTouches) => void} GlobalInteractionHandler + * Object that handles any change in the number of active touches. + */ + injectGlobalInteractionHandler: function(GlobalInteractionHandler) { + ResponderEventPlugin.GlobalInteractionHandler = GlobalInteractionHandler; + } + } +}; + +var customBubblingEventTypes$1 = + ReactNativeViewConfigRegistry.customBubblingEventTypes; +var customDirectEventTypes$1 = + ReactNativeViewConfigRegistry.customDirectEventTypes; +var eventTypes$2 = ReactNativeViewConfigRegistry.eventTypes; + +var ReactNativeBridgeEventPlugin = { + eventTypes: eventTypes$2, + + /** + * @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$1[topLevelType]; + var directDispatchConfig = customDirectEventTypes$1[topLevelType]; + invariant( + bubbleDispatchConfig || directDispatchConfig, + 'Unsupported top level event type "%s" dispatched', + topLevelType + ); + var event = SyntheticEvent$1.getPooled( + bubbleDispatchConfig || directDispatchConfig, + targetInst, + nativeEvent, + nativeEventTarget + ); + if (bubbleDispatchConfig) { + accumulateTwoPhaseDispatches(event); + } else if (directDispatchConfig) { + accumulateDirectDispatches(event); + } else { + return null; + } + return event; + } +}; + +var instanceCache = {}; +var instanceProps = {}; + +function precacheFiberNode(hostInst, tag) { + instanceCache[tag] = hostInst; +} + +function uncacheFiberNode(tag) { + delete instanceCache[tag]; + delete instanceProps[tag]; +} + +function getInstanceFromTag(tag) { + if (typeof tag === "number") { + return instanceCache[tag] || null; + } else { + // Fabric will invoke event emitters on a direct fiber reference + return tag; + } +} + +function getTagFromInstance(inst) { + var tag = inst.stateNode._nativeTag; + if (tag === undefined) { + tag = inst.stateNode.canonical._nativeTag; + } + invariant(tag, "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; +} + +var ReactNativeComponentTree = Object.freeze({ + precacheFiberNode: precacheFiberNode, + uncacheFiberNode: uncacheFiberNode, + getClosestInstanceFromNode: getInstanceFromTag, + getInstanceFromNode: getInstanceFromTag, + getNodeFromInstance: getTagFromInstance, + getFiberCurrentPropsFromNode: getFiberCurrentPropsFromNode$1, + updateFiberProps: updateFiberProps +}); + +var ReactNativeEventPluginOrder = [ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]; + +// Module provided by RN: +var ReactNativeGlobalResponderHandler = { + onChange: function(from, to, blockNativeResponder) { + if (to !== null) { + var tag = to.stateNode._nativeTag; + UIManager.setJSResponder(tag, blockNativeResponder); + } else { + UIManager.clearJSResponder(); + } + } +}; + +/** + * 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); +injection$1.injectComponentTree(ReactNativeComponentTree); + +ResponderEventPlugin.injection.injectGlobalResponderHandler( + ReactNativeGlobalResponderHandler +); + +/** + * Some important event plugins included by default (without having to require + * them). + */ +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin +}); + +// Use to restore controlled state after a change event has fired. + +var fiberHostComponent = 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; + } + invariant( + fiberHostComponent && + typeof fiberHostComponent.restoreControlledState === "function", + "Fiber needs to be injected to handle a fiber target for controlled " + + "events. This error is likely caused by a bug in React. Please file an issue." + ); + var props = getFiberCurrentPropsFromNode(internalInstance.stateNode); + fiberHostComponent.restoreControlledState( + 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 _batchedUpdates = function(fn, bookkeeping) { + return fn(bookkeeping); +}; +var _interactiveUpdates = function(fn, a, b) { + return fn(a, b); +}; +var _flushInteractiveUpdates = 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 _batchedUpdates(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. + _flushInteractiveUpdates(); + restoreStateIfNeeded(); + } + } +} + +var injection$2 = { + injectRenderer: function(renderer) { + _batchedUpdates = renderer.batchedUpdates; + _interactiveUpdates = renderer.interactiveUpdates; + _flushInteractiveUpdates = renderer.flushInteractiveUpdates; + } +}; + +/** + * 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() { + runExtractedEventsInBatch( + 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) { + { + warning( + 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); + } +} + +var ReactNativeEventEmitter = Object.freeze({ + getListener: getListener, + registrationNames: registrationNameModules, + _receiveRootNodeIDEvent: _receiveRootNodeIDEvent, + receiveEvent: receiveEvent, + receiveTouches: receiveTouches +}); + +// Module provided by RN: +/** + * Register the event emitter with the native bridge + */ +RCTEventEmitter.register(ReactNativeEventEmitter); + +// 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_CALL_TYPE = hasSymbol ? Symbol["for"]("react.call") : 0xeac8; +var REACT_RETURN_TYPE = hasSymbol ? Symbol["for"]("react.return") : 0xeac9; +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_PROVIDER_TYPE = hasSymbol ? Symbol["for"]("react.provider") : 0xeacd; +var REACT_CONTEXT_TYPE = hasSymbol ? Symbol["for"]("react.context") : 0xeace; +var REACT_ASYNC_MODE_TYPE = hasSymbol + ? Symbol["for"]("react.async_mode") + : 0xeacf; +var REACT_FORWARD_REF_TYPE = hasSymbol + ? Symbol["for"]("react.forward_ref") + : 0xead0; + +var MAYBE_ITERATOR_SYMBOL = typeof Symbol === "function" && Symbol.iterator; +var FAUX_ITERATOR_SYMBOL = "@@iterator"; + +function getIteratorFn(maybeIterable) { + if (maybeIterable === null || typeof maybeIterable === "undefined") { + return null; + } + var maybeIterator = + (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || + maybeIterable[FAUX_ITERATOR_SYMBOL]; + if (typeof maybeIterator === "function") { + return maybeIterator; + } + return null; +} + +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.3.2"; + +var describeComponentFrame = function(name, source, ownerName) { + return ( + "\n in " + + (name || "Unknown") + + (source + ? " (at " + + source.fileName.replace(/^.*[\\\/]/, "") + + ":" + + source.lineNumber + + ")" + : ownerName ? " (created by " + ownerName + ")" : "") + ); +}; + +function getComponentName(fiber) { + var type = fiber.type; + + if (typeof type === "function") { + return type.displayName || type.name; + } + if (typeof type === "string") { + return type; + } + switch (type) { + case REACT_FRAGMENT_TYPE: + return "ReactFragment"; + case REACT_PORTAL_TYPE: + return "ReactPortal"; + case REACT_CALL_TYPE: + return "ReactCall"; + case REACT_RETURN_TYPE: + return "ReactReturn"; + } + if (typeof type === "object" && type !== null) { + switch (type.$$typeof) { + case REACT_FORWARD_REF_TYPE: + var functionName = type.render.displayName || type.render.name || ""; + return functionName !== "" + ? "ForwardRef(" + functionName + ")" + : "ForwardRef"; + } + } + return null; +} + +function describeFiber(fiber) { + switch (fiber.tag) { + case IndeterminateComponent: + case FunctionalComponent: + case ClassComponent: + case HostComponent: + var owner = fiber._debugOwner; + var source = fiber._debugSource; + var name = getComponentName(fiber); + var ownerName = null; + if (owner) { + ownerName = getComponentName(owner); + } + return describeComponentFrame(name, source, ownerName); + default: + return ""; + } +} + +// This function can only be called with a work-in-progress fiber and +// only during begin or complete phase. Do not call it under any other +// circumstances. +function getStackAddendumByWorkInProgressFiber(workInProgress) { + var info = ""; + var node = workInProgress; + do { + info += describeFiber(node); + // Otherwise this return pointer might point to the wrong tree: + node = node["return"]; + } while (node); + return info; +} + +// Modules provided by RN: +var emptyObject$1 = {}; + +/** + * 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 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. + 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. + 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$1, 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$1, + 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(context, callback) { + return function() { + if (!callback) { + return undefined; + } + if (typeof context.__isMounted === "boolean") { + // TODO(gaearon): this is gross and should be removed. + // It is currently necessary because View uses createClass, + // and so any measure() calls on View (which are done by React + // DevTools) trigger the isMounted() deprecation warning. + if (!context.__isMounted) { + return undefined; + } + // The else branch is important so that we don't + // trigger the deprecation warning by calling isMounted. + } else if (typeof context.isMounted === "function") { + if (!context.isMounted()) { + return undefined; + } + } + 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 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) { + UIManager.measure( + findNodeHandle(this), + mountSafeCallback(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) { + UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback(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 */ + ) { + UIManager.measureLayout( + findNodeHandle(this), + relativeToNativeNode, + mountSafeCallback(this, onFail), + mountSafeCallback(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; + } + + var viewConfig = maybeInstance.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) { + UIManager.updateView( + maybeInstance._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() { + TextInputState.focusTextInput(findNodeHandle(this)); + }, + + /** + * Removes focus from an input or view. This is the opposite of `focus()`. + */ + blur: function() { + 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; + invariant( + !NativeMethodsMixin_DEV.componentWillMount && + !NativeMethodsMixin_DEV.componentWillReceiveProps && + !NativeMethodsMixin_DEV.UNSAFE_componentWillMount && + !NativeMethodsMixin_DEV.UNSAFE_componentWillReceiveProps, + "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(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(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() { + TextInputState.blurTextInput(findNodeHandle(this)); + }; + + /** + * Requests focus. The exact behavior depends on the platform and view. + */ + + ReactNativeComponent.prototype.focus = function focus() { + 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) { + UIManager.measure( + findNodeHandle(this), + mountSafeCallback(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 + ) { + UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback(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 */ + ) { + UIManager.measureLayout( + findNodeHandle(this), + relativeToNativeNode, + mountSafeCallback(this, onFail), + mountSafeCallback(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; + } + + 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) { + UIManager.updateView( + maybeInstance._nativeTag, + viewConfig.uiViewClassName, + updatePayload + ); + } + }; + + return ReactNativeComponent; + })(React.Component); + + // eslint-disable-next-line no-unused-expressions + + return ReactNativeComponent; +}; + +/** + * `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$1(key) { + return key._reactInternalFiber; +} + +function set(key, value) { + key._reactInternalFiber = value; +} + +var ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; + +var ReactCurrentOwner = ReactInternals.ReactCurrentOwner; +var ReactDebugCurrentFrame = ReactInternals.ReactDebugCurrentFrame; + +// 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 ErrLog = /* */ 256; +var Snapshot = /* */ 2048; + +// Union of all host effects +var HostEffectMask = /* */ 2559; + +var Incomplete = /* */ 512; +var ShouldCapture = /* */ 1024; + +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.current; + if (owner !== null && owner.tag === ClassComponent) { + var ownerFiber = owner; + var instance = ownerFiber.stateNode; + !instance._warnedAboutRefsInRender + ? warning( + 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) || "A component" + ) + : void 0; + instance._warnedAboutRefsInRender = true; + } + } + + var fiber = get$1(component); + if (!fiber) { + return false; + } + return isFiberMountedImpl(fiber) === MOUNTED; +} + +function assertIsMounted(fiber) { + invariant( + isFiberMountedImpl(fiber) === MOUNTED, + "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); + invariant( + state !== UNMOUNTED, + "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"]; + var parentB = parentA ? parentA.alternate : null; + if (!parentA || !parentB) { + // 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. + invariant(false, "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; + } + invariant( + didFindChild, + "Child was not found in either parent set. This indicates a bug " + + "in React related to the return pointer. Please file an issue." + ); + } + } + + invariant( + a.alternate === b, + "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. + invariant( + a.tag === HostRoot, + "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; +} + +function findCurrentHostFiberWithNoPortals(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.tag !== HostPortal) { + 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; +} + +// 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; + +// TODO: Use an opaque type once ESLint et al support the syntax + +var NoWork = 0; +var Sync = 1; +var Never = MAX_SIGNED_31_BIT_INT; + +var UNIT_SIZE = 10; +var MAGIC_NUMBER_OFFSET = 2; + +// 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 ((ms / UNIT_SIZE) | 0) + MAGIC_NUMBER_OFFSET; +} + +function expirationTimeToMs(expirationTime) { + return (expirationTime - MAGIC_NUMBER_OFFSET) * UNIT_SIZE; +} + +function ceiling(num, precision) { + return (((num / precision) | 0) + 1) * precision; +} + +function computeExpirationBucket(currentTime, expirationInMs, bucketSizeMs) { + return ceiling( + currentTime + expirationInMs / UNIT_SIZE, + bucketSizeMs / UNIT_SIZE + ); +} + +var NoContext = 0; +var AsyncMode = 1; +var StrictMode = 2; + +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.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.mode = mode; + + // Effects + this.effectTag = NoEffect; + this.nextEffect = null; + + this.firstEffect = null; + this.lastEffect = null; + + this.expirationTime = NoWork; + + this.alternate = null; + + { + this._debugID = debugCounter++; + this._debugSource = null; + this._debugOwner = null; + this._debugIsCurrentlyTiming = false; + 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) { + return !!(Component.prototype && Component.prototype.isReactComponent); +} + +// 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.type = current.type; + workInProgress.stateNode = current.stateNode; + + { + // DEV-only fields + workInProgress._debugID = current._debugID; + workInProgress._debugSource = current._debugSource; + workInProgress._debugOwner = current._debugOwner; + } + + 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; + } + + workInProgress.expirationTime = expirationTime; + + workInProgress.child = current.child; + workInProgress.memoizedProps = current.memoizedProps; + workInProgress.memoizedState = current.memoizedState; + workInProgress.updateQueue = current.updateQueue; + + // These will be overridden during the parent's reconciliation + workInProgress.sibling = current.sibling; + workInProgress.index = current.index; + workInProgress.ref = current.ref; + + return workInProgress; +} + +function createHostRootFiber(isAsync) { + var mode = isAsync ? AsyncMode | StrictMode : NoContext; + return createFiber(HostRoot, null, null, mode); +} + +function createFiberFromElement(element, mode, expirationTime) { + var owner = null; + { + owner = element._owner; + } + + var fiber = void 0; + var type = element.type; + var key = element.key; + var pendingProps = element.props; + + var fiberTag = void 0; + if (typeof type === "function") { + fiberTag = shouldConstruct(type) ? ClassComponent : IndeterminateComponent; + } else if (typeof type === "string") { + fiberTag = HostComponent; + } else { + switch (type) { + case REACT_FRAGMENT_TYPE: + return createFiberFromFragment( + pendingProps.children, + mode, + expirationTime, + key + ); + case REACT_ASYNC_MODE_TYPE: + fiberTag = Mode; + mode |= AsyncMode | StrictMode; + break; + case REACT_STRICT_MODE_TYPE: + fiberTag = Mode; + mode |= StrictMode; + break; + case REACT_CALL_TYPE: + fiberTag = CallComponent; + break; + case REACT_RETURN_TYPE: + fiberTag = ReturnComponent; + break; + default: { + if (typeof type === "object" && type !== null) { + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + fiberTag = ContextProvider; + break; + case REACT_CONTEXT_TYPE: + // This is a consumer + fiberTag = ContextConsumer; + break; + case REACT_FORWARD_REF_TYPE: + fiberTag = ForwardRef; + break; + default: + if (typeof type.tag === "number") { + // Currently assumed to be a continuation and therefore is a + // fiber already. + // TODO: The yield system is currently broken for updates in + // some cases. The reified yield stores a fiber, but we don't + // know which fiber that is; the current or a workInProgress? + // When the continuation gets rendered here we don't know if we + // can reuse that fiber or if we need to clone it. There is + // probably a clever way to restructure this. + fiber = type; + fiber.pendingProps = pendingProps; + fiber.expirationTime = expirationTime; + return fiber; + } else { + throwOnInvalidElementType(type, owner); + } + break; + } + } else { + throwOnInvalidElementType(type, owner); + } + } + } + } + + fiber = createFiber(fiberTag, pendingProps, key, mode); + fiber.type = type; + fiber.expirationTime = expirationTime; + + { + fiber._debugSource = element._source; + fiber._debugOwner = element._owner; + } + + return fiber; +} + +function throwOnInvalidElementType(type, owner) { + 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) : null; + if (ownerName) { + info += "\n\nCheck the render method of `" + ownerName + "`."; + } + } + invariant( + false, + "Element type is invalid: expected a string (for built-in " + + "components) or a class/function (for composite components) " + + "but got: %s.%s", + type == null ? type : typeof type, + info + ); +} + +function createFiberFromFragment(elements, mode, expirationTime, key) { + var fiber = createFiber(Fragment, elements, key, mode); + 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); + 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.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.mode = source.mode; + target.effectTag = source.effectTag; + target.nextEffect = source.nextEffect; + target.firstEffect = source.firstEffect; + target.lastEffect = source.lastEffect; + target.expirationTime = source.expirationTime; + target.alternate = source.alternate; + target._debugID = source._debugID; + target._debugSource = source._debugSource; + target._debugOwner = source._debugOwner; + target._debugIsCurrentlyTiming = source._debugIsCurrentlyTiming; + return target; +} + +// TODO: This should be lifted into the renderer. + +function createFiberRoot(containerInfo, isAsync, hydrate) { + // Cyclic construction. This cheats the type system right now because + // stateNode is any. + var uninitializedFiber = createHostRootFiber(isAsync); + var root = { + current: uninitializedFiber, + containerInfo: containerInfo, + pendingChildren: null, + pendingCommitExpirationTime: NoWork, + finishedWork: null, + context: null, + pendingContext: null, + hydrate: hydrate, + remainingExpirationTime: NoWork, + firstBatch: null, + nextScheduledRoot: null + }; + uninitializedFiber.stateNode = root; + return root; +} + +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; + warning(false, "React DevTools encountered an error: %s", err); + } + } + }; +} + +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) { + { + warning( + 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. + { + warning(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); + } +} + +/** + * 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( + "`warning(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) {} +}; + +{ + var LIFECYCLE_SUGGESTIONS = { + UNSAFE_componentWillMount: "componentDidMount", + UNSAFE_componentWillReceiveProps: "static getDerivedStateFromProps", + UNSAFE_componentWillUpdate: "componentDidUpdate" + }; + + var pendingComponentWillMountWarnings = []; + var pendingComponentWillReceivePropsWarnings = []; + var pendingComponentWillUpdateWarnings = []; + var pendingUnsafeLifecycleWarnings = new Map(); + + // Tracks components we have already warned about. + var didWarnAboutDeprecatedLifecycles = new Set(); + var didWarnAboutUnsafeLifecycles = 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(); + }; + + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = function() { + pendingUnsafeLifecycleWarnings.forEach(function( + lifecycleWarningsMap, + strictRoot + ) { + var lifecyclesWarningMesages = []; + + 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) || "Component"); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + + var formatted = lifecycle.replace("UNSAFE_", ""); + var suggestion = LIFECYCLE_SUGGESTIONS[lifecycle]; + var sortedComponentNames = setToSortedString(componentNames); + + lifecyclesWarningMesages.push( + formatted + + ": Please update the following components to use " + + (suggestion + " instead: " + sortedComponentNames) + ); + } + }); + + if (lifecyclesWarningMesages.length > 0) { + var strictRootComponentStack = getStackAddendumByWorkInProgressFiber( + strictRoot + ); + + warning( + 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, + lifecyclesWarningMesages.join("\n\n") + ); + } + }); + + pendingUnsafeLifecycleWarnings = new Map(); + }; + + var getStrictRoot = function(fiber) { + var maybeStrictRoot = null; + + while (fiber !== null) { + if (fiber.mode & StrictMode) { + maybeStrictRoot = fiber; + } + + fiber = fiber["return"]; + } + + return maybeStrictRoot; + }; + + ReactStrictModeWarnings.flushPendingDeprecationWarnings = function() { + if (pendingComponentWillMountWarnings.length > 0) { + var uniqueNames = new Set(); + pendingComponentWillMountWarnings.forEach(function(fiber) { + uniqueNames.add(getComponentName(fiber) || "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) || "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) || "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 = getStrictRoot(fiber); + + // 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; + } + + // Don't warn about react-lifecycles-compat polyfilled components. + // Note that it is sufficient to check for the presence of a + // single lifecycle, componentWillMount, with the polyfill flag. + if ( + typeof instance.componentWillMount === "function" && + instance.componentWillMount.__suppressDeprecationWarning === true + ) { + 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" || + typeof instance.UNSAFE_componentWillMount === "function" + ) { + unsafeLifecycles.push("UNSAFE_componentWillMount"); + } + if ( + typeof instance.componentWillReceiveProps === "function" || + typeof instance.UNSAFE_componentWillReceiveProps === "function" + ) { + unsafeLifecycles.push("UNSAFE_componentWillReceiveProps"); + } + if ( + typeof instance.componentWillUpdate === "function" || + typeof instance.UNSAFE_componentWillUpdate === "function" + ) { + unsafeLifecycles.push("UNSAFE_componentWillUpdate"); + } + + if (unsafeLifecycles.length > 0) { + unsafeLifecycles.forEach(function(lifecycle) { + warningsForRoot[lifecycle].push(fiber); + }); + } + }; +} + +var debugRenderPhaseSideEffects = false; +var debugRenderPhaseSideEffectsForStrictMode = false; +var enableGetDerivedStateFromCatch = false; +var enableMutatingReconciler = true; +var enableNoopReconciler = false; +var enablePersistentReconciler = false; +var enableUserTimingAPI = true; +var replayFailedUnitOfWorkWithInvokeGuardedCallback = true; +var warnAboutDeprecatedLifecycles = false; + +// Only used in www builds. + +function getCurrentFiberOwnerName() { + { + var fiber = ReactDebugCurrentFiber.current; + if (fiber === null) { + return null; + } + var owner = fiber._debugOwner; + if (owner !== null && typeof owner !== "undefined") { + return getComponentName(owner); + } + } + return null; +} + +function getCurrentFiberStackAddendum() { + { + var fiber = ReactDebugCurrentFiber.current; + if (fiber === null) { + return null; + } + // Safe because if current fiber exists, we are reconciling, + // and it is guaranteed to be the work-in-progress version. + return getStackAddendumByWorkInProgressFiber(fiber); + } + return null; +} + +function resetCurrentFiber() { + ReactDebugCurrentFrame.getCurrentStack = null; + ReactDebugCurrentFiber.current = null; + ReactDebugCurrentFiber.phase = null; +} + +function setCurrentFiber(fiber) { + ReactDebugCurrentFrame.getCurrentStack = getCurrentFiberStackAddendum; + ReactDebugCurrentFiber.current = fiber; + ReactDebugCurrentFiber.phase = null; +} + +function setCurrentPhase(phase) { + ReactDebugCurrentFiber.phase = phase; +} + +var ReactDebugCurrentFiber = { + current: null, + phase: null, + resetCurrentFiber: resetCurrentFiber, + setCurrentFiber: setCurrentFiber, + setCurrentPhase: setCurrentPhase, + getCurrentFiberOwnerName: getCurrentFiberOwnerName, + getCurrentFiberStackAddendum: getCurrentFiberStackAddendum +}; + +// 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$$1) { + var prefix = warning$$1 ? warningEmoji + " " : reactEmoji + " "; + var suffix = warning$$1 ? " Warning: " + warning$$1 : ""; + 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$$1) { + var formattedMarkName = formatMarkName(markName); + var formattedLabel = formatLabel(label, warning$$1); + 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) || "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) || "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$$1) { + var componentName = getComponentName(fiber) || "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$$1); +}; + +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 CallComponent: + case ReturnComponent: + 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, expirationTime) { + if (enableUserTimingAPI) { + if (supportsUserTiming) { + isWaitingForCallback = false; + var warning$$1 = didExpire ? "React was blocked by main thread" : null; + endMark( + "(Waiting for async callback... will force flush in " + + expirationTime + + " ms)", + "(Waiting for async callback...)", + warning$$1 + ); + } + } +} + +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$$1 = "An error was thrown inside this error boundary"; + endFiberMark(fiber, null, warning$$1); + } +} + +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$$1 = hasScheduledUpdateInCurrentPhase + ? "Scheduled a cascading update" + : null; + endFiberMark(currentPhaseFiber, currentPhase, warning$$1); + } + 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$$1 = null; + if (interruptedBy !== null) { + if (interruptedBy.tag === HostRoot) { + warning$$1 = "A top-level update interrupted the previous render"; + } else { + var componentName = getComponentName(interruptedBy) || "Unknown"; + warning$$1 = + "An update to " + componentName + " interrupted the previous render"; + } + } else if (commitCountInCurrentWorkLoop > 1) { + warning$$1 = "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$$1); + } +} + +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$$1 = null; + if (hasScheduledUpdateInCurrentCommit) { + warning$$1 = "Lifecycle hook scheduled a cascading update"; + } else if (commitCountInCurrentWorkLoop > 0) { + warning$$1 = "Caused by a cascading update in earlier commit"; + } + hasScheduledUpdateInCurrentCommit = false; + commitCountInCurrentWorkLoop++; + isCommitting = false; + labelsInCurrentCommit.clear(); + + endMark("(Committing Changes)", "(Committing Changes)", warning$$1); + } +} + +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 didWarnUpdateInsideUpdate = void 0; + +{ + didWarnUpdateInsideUpdate = false; +} + +// Callbacks are not validated until invocation + +// Singly linked-list of updates. When an update is scheduled, it is added to +// the queue of the current fiber and the work-in-progress fiber. The two queues +// are separate but they share a persistent structure. +// +// During reconciliation, updates are removed from the work-in-progress fiber, +// but they remain on the current fiber. That ensures that if a work-in-progress +// is aborted, the aborted updates are recovered by cloning from current. +// +// The work-in-progress queue is always a subset of the current queue. +// +// When the tree is committed, the work-in-progress becomes the current. + +function createUpdateQueue(baseState) { + var queue = { + baseState: baseState, + expirationTime: NoWork, + first: null, + last: null, + callbackList: null, + hasForceUpdate: false, + isInitialized: false, + capturedValues: null + }; + { + queue.isProcessing = false; + } + return queue; +} + +function insertUpdateIntoQueue(queue, update) { + // Append the update to the end of the list. + if (queue.last === null) { + // Queue is empty + queue.first = queue.last = update; + } else { + queue.last.next = update; + queue.last = update; + } + if ( + queue.expirationTime === NoWork || + queue.expirationTime > update.expirationTime + ) { + queue.expirationTime = update.expirationTime; + } +} + +var q1 = void 0; +var q2 = void 0; +function ensureUpdateQueues(fiber) { + q1 = q2 = null; + // We'll have at least one and at most two distinct update queues. + var alternateFiber = fiber.alternate; + var queue1 = fiber.updateQueue; + if (queue1 === null) { + // TODO: We don't know what the base state will be until we begin work. + // It depends on which fiber is the next current. Initialize with an empty + // base state, then set to the memoizedState when rendering. Not super + // happy with this approach. + queue1 = fiber.updateQueue = createUpdateQueue(null); + } + + var queue2 = void 0; + if (alternateFiber !== null) { + queue2 = alternateFiber.updateQueue; + if (queue2 === null) { + queue2 = alternateFiber.updateQueue = createUpdateQueue(null); + } + } else { + queue2 = null; + } + queue2 = queue2 !== queue1 ? queue2 : null; + + // Use module variables instead of returning a tuple + q1 = queue1; + q2 = queue2; +} + +function insertUpdateIntoFiber(fiber, update) { + ensureUpdateQueues(fiber); + var queue1 = q1; + var queue2 = q2; + + // Warn if an update is scheduled from inside an updater function. + { + if ( + (queue1.isProcessing || (queue2 !== null && queue2.isProcessing)) && + !didWarnUpdateInsideUpdate + ) { + warning( + 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; + } + } + + // If there's only one queue, add the update to that queue and exit. + if (queue2 === null) { + insertUpdateIntoQueue(queue1, update); + return; + } + + // If either queue is empty, we need to add to both queues. + if (queue1.last === null || queue2.last === null) { + insertUpdateIntoQueue(queue1, update); + insertUpdateIntoQueue(queue2, update); + return; + } + + // If both lists are not empty, the last update is the same for both lists + // because of structural sharing. So, we should only append to one of + // the lists. + insertUpdateIntoQueue(queue1, update); + // But we still need to update the `last` pointer of queue2. + queue2.last = update; +} + +function getUpdateExpirationTime(fiber) { + switch (fiber.tag) { + case HostRoot: + case ClassComponent: + var updateQueue = fiber.updateQueue; + if (updateQueue === null) { + return NoWork; + } + return updateQueue.expirationTime; + default: + return NoWork; + } +} + +function getStateFromUpdate(update, instance, prevState, props) { + var partialState = update.partialState; + if (typeof partialState === "function") { + return partialState.call(instance, prevState, props); + } else { + return partialState; + } +} + +function processUpdateQueue( + current, + workInProgress, + queue, + instance, + props, + renderExpirationTime +) { + if (current !== null && current.updateQueue === queue) { + // We need to create a work-in-progress queue, by cloning the current queue. + var currentQueue = queue; + queue = workInProgress.updateQueue = { + baseState: currentQueue.baseState, + expirationTime: currentQueue.expirationTime, + first: currentQueue.first, + last: currentQueue.last, + isInitialized: currentQueue.isInitialized, + capturedValues: currentQueue.capturedValues, + // These fields are no longer valid because they were already committed. + // Reset them. + callbackList: null, + hasForceUpdate: false + }; + } + + { + // Set this flag so we can warn if setState is called inside the update + // function of another setState. + queue.isProcessing = true; + } + + // Reset the remaining expiration time. If we skip over any updates, we'll + // increase this accordingly. + queue.expirationTime = NoWork; + + // TODO: We don't know what the base state will be until we begin work. + // It depends on which fiber is the next current. Initialize with an empty + // base state, then set to the memoizedState when rendering. Not super + // happy with this approach. + var state = void 0; + if (queue.isInitialized) { + state = queue.baseState; + } else { + state = queue.baseState = workInProgress.memoizedState; + queue.isInitialized = true; + } + var dontMutatePrevState = true; + var update = queue.first; + var didSkip = false; + while (update !== null) { + var updateExpirationTime = update.expirationTime; + if (updateExpirationTime > renderExpirationTime) { + // This update does not have sufficient priority. Skip it. + var remainingExpirationTime = queue.expirationTime; + if ( + remainingExpirationTime === NoWork || + remainingExpirationTime > updateExpirationTime + ) { + // Update the remaining expiration time. + queue.expirationTime = updateExpirationTime; + } + if (!didSkip) { + didSkip = true; + queue.baseState = state; + } + // Continue to the next update. + update = update.next; + continue; + } + + // This update does have sufficient priority. + + // If no previous updates were skipped, drop this update from the queue by + // advancing the head of the list. + if (!didSkip) { + queue.first = update.next; + if (queue.first === null) { + queue.last = null; + } + } + + // Invoke setState callback an extra time to help detect side-effects. + // Ignore the return value in this case. + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + getStateFromUpdate(update, instance, state, props); + } + + // Process the update + var _partialState = void 0; + if (update.isReplace) { + state = getStateFromUpdate(update, instance, state, props); + dontMutatePrevState = true; + } else { + _partialState = getStateFromUpdate(update, instance, state, props); + if (_partialState) { + if (dontMutatePrevState) { + // $FlowFixMe: Idk how to type this properly. + state = Object.assign({}, state, _partialState); + } else { + state = Object.assign(state, _partialState); + } + dontMutatePrevState = false; + } + } + if (update.isForced) { + queue.hasForceUpdate = true; + } + if (update.callback !== null) { + // Append to list of callbacks. + var _callbackList = queue.callbackList; + if (_callbackList === null) { + _callbackList = queue.callbackList = []; + } + _callbackList.push(update); + } + if (update.capturedValue !== null) { + var _capturedValues = queue.capturedValues; + if (_capturedValues === null) { + queue.capturedValues = [update.capturedValue]; + } else { + _capturedValues.push(update.capturedValue); + } + } + update = update.next; + } + + if (queue.callbackList !== null) { + workInProgress.effectTag |= Callback; + } else if ( + queue.first === null && + !queue.hasForceUpdate && + queue.capturedValues === null + ) { + // The queue is empty. We can reset it. + workInProgress.updateQueue = null; + } + + if (!didSkip) { + didSkip = true; + queue.baseState = state; + } + + { + // No longer processing. + queue.isProcessing = false; + } + + return state; +} + +function commitCallbacks(queue, context) { + var callbackList = queue.callbackList; + if (callbackList === null) { + return; + } + // Set the list to null to make sure they don't get called more than once. + queue.callbackList = null; + for (var i = 0; i < callbackList.length; i++) { + var update = callbackList[i]; + var _callback = update.callback; + // This update might be processed again. Clear the callback so it's only + // called once. + update.callback = null; + invariant( + typeof _callback === "function", + "Invalid argument passed as callback. Expected a function. Instead " + + "received: %s", + _callback + ); + _callback.call(context); + } +} + +var fakeInternalInstance = {}; +var isArray = Array.isArray; + +var didWarnAboutStateAssignmentForComponent = void 0; +var didWarnAboutUndefinedDerivedState = void 0; +var didWarnAboutUninitializedState = void 0; +var didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = void 0; +var didWarnAboutLegacyLifecyclesAndDerivedState = void 0; +var warnOnInvalidCallback = void 0; + +{ + didWarnAboutStateAssignmentForComponent = new Set(); + didWarnAboutUndefinedDerivedState = new Set(); + didWarnAboutUninitializedState = new Set(); + didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = new Set(); + didWarnAboutLegacyLifecyclesAndDerivedState = 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); + warning( + false, + "%s(...): Expected the last optional `callback` argument to be a " + + "function. Instead received: %s.", + callerName, + callback + ); + } + }; + + // 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() { + invariant( + false, + "_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 callGetDerivedStateFromCatch(ctor, capturedValues) { + var resultState = {}; + for (var i = 0; i < capturedValues.length; i++) { + var capturedValue = capturedValues[i]; + var error = capturedValue.value; + var partialState = ctor.getDerivedStateFromCatch.call(null, error); + if (partialState !== null && partialState !== undefined) { + Object.assign(resultState, partialState); + } + } + return resultState; +} + +var ReactFiberClassComponent = function( + legacyContext, + scheduleWork, + computeExpirationForFiber, + memoizeProps, + memoizeState +) { + var cacheContext = legacyContext.cacheContext, + getMaskedContext = legacyContext.getMaskedContext, + getUnmaskedContext = legacyContext.getUnmaskedContext, + isContextConsumer = legacyContext.isContextConsumer, + hasContextChanged = legacyContext.hasContextChanged; + + // Class component state updater + + var updater = { + isMounted: isMounted, + enqueueSetState: function(instance, partialState, callback) { + var fiber = get$1(instance); + callback = callback === undefined ? null : callback; + { + warnOnInvalidCallback(callback, "setState"); + } + var expirationTime = computeExpirationForFiber(fiber); + var update = { + expirationTime: expirationTime, + partialState: partialState, + callback: callback, + isReplace: false, + isForced: false, + capturedValue: null, + next: null + }; + insertUpdateIntoFiber(fiber, update); + scheduleWork(fiber, expirationTime); + }, + enqueueReplaceState: function(instance, state, callback) { + var fiber = get$1(instance); + callback = callback === undefined ? null : callback; + { + warnOnInvalidCallback(callback, "replaceState"); + } + var expirationTime = computeExpirationForFiber(fiber); + var update = { + expirationTime: expirationTime, + partialState: state, + callback: callback, + isReplace: true, + isForced: false, + capturedValue: null, + next: null + }; + insertUpdateIntoFiber(fiber, update); + scheduleWork(fiber, expirationTime); + }, + enqueueForceUpdate: function(instance, callback) { + var fiber = get$1(instance); + callback = callback === undefined ? null : callback; + { + warnOnInvalidCallback(callback, "forceUpdate"); + } + var expirationTime = computeExpirationForFiber(fiber); + var update = { + expirationTime: expirationTime, + partialState: null, + callback: callback, + isReplace: false, + isForced: true, + capturedValue: null, + next: null + }; + insertUpdateIntoFiber(fiber, update); + scheduleWork(fiber, expirationTime); + } + }; + + function checkShouldComponentUpdate( + workInProgress, + oldProps, + newProps, + oldState, + newState, + newContext + ) { + if ( + oldProps === null || + (workInProgress.updateQueue !== null && + workInProgress.updateQueue.hasForceUpdate) + ) { + // If the workInProgress already has an Update effect, return true + return true; + } + + var instance = workInProgress.stateNode; + var ctor = workInProgress.type; + if (typeof instance.shouldComponentUpdate === "function") { + startPhaseTimer(workInProgress, "shouldComponentUpdate"); + var shouldUpdate = instance.shouldComponentUpdate( + newProps, + newState, + newContext + ); + stopPhaseTimer(); + + { + !(shouldUpdate !== undefined) + ? warning( + false, + "%s.shouldComponentUpdate(): Returned undefined instead of a " + + "boolean value. Make sure to return true or false.", + getComponentName(workInProgress) || "Component" + ) + : void 0; + } + + return shouldUpdate; + } + + if (ctor.prototype && ctor.prototype.isPureReactComponent) { + return ( + !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) + ); + } + + return true; + } + + function checkClassInstance(workInProgress) { + var instance = workInProgress.stateNode; + var type = workInProgress.type; + { + var name = getComponentName(workInProgress) || "Component"; + var renderPresent = instance.render; + + if (!renderPresent) { + if (type.prototype && typeof type.prototype.render === "function") { + warning( + false, + "%s(...): No `render` method found on the returned component " + + "instance: did you accidentally return an object from the constructor?", + name + ); + } else { + warning( + 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 + ? warning( + 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 + ? warning( + 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 + ? warning( + false, + "propTypes was defined as an instance property on %s. Use a static " + + "property to define propTypes instead.", + name + ) + : void 0; + var noInstanceContextTypes = !instance.contextTypes; + !noInstanceContextTypes + ? warning( + false, + "contextTypes was defined as an instance property on %s. Use a static " + + "property to define contextTypes instead.", + name + ) + : void 0; + var noComponentShouldUpdate = + typeof instance.componentShouldUpdate !== "function"; + !noComponentShouldUpdate + ? warning( + 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 ( + type.prototype && + type.prototype.isPureReactComponent && + typeof instance.shouldComponentUpdate !== "undefined" + ) { + warning( + 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(workInProgress) || "A pure component" + ); + } + var noComponentDidUnmount = + typeof instance.componentDidUnmount !== "function"; + !noComponentDidUnmount + ? warning( + 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 + ? warning( + 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 + ? warning( + false, + "%s has a method called " + + "componentWillRecieveProps(). Did you mean componentWillReceiveProps()?", + name + ) + : void 0; + var noUnsafeComponentWillRecieveProps = + typeof instance.UNSAFE_componentWillRecieveProps !== "function"; + !noUnsafeComponentWillRecieveProps + ? warning( + false, + "%s has a method called " + + "UNSAFE_componentWillRecieveProps(). Did you mean UNSAFE_componentWillReceiveProps()?", + name + ) + : void 0; + var hasMutatedProps = instance.props !== workInProgress.pendingProps; + !(instance.props === undefined || !hasMutatedProps) + ? warning( + 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 + ? warning( + 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(type) + ) { + didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.add(type); + warning( + false, + "%s: getSnapshotBeforeUpdate() should be used with componentDidUpdate(). " + + "This component defines getSnapshotBeforeUpdate() only.", + getComponentName(workInProgress) + ); + } + + var noInstanceGetDerivedStateFromProps = + typeof instance.getDerivedStateFromProps !== "function"; + !noInstanceGetDerivedStateFromProps + ? warning( + 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.getDerivedStateFromCatch !== "function"; + !noInstanceGetDerivedStateFromCatch + ? warning( + false, + "%s: getDerivedStateFromCatch() is defined as an instance method " + + "and will be ignored. Instead, declare it as a static method.", + name + ) + : void 0; + var noStaticGetSnapshotBeforeUpdate = + typeof type.getSnapshotBeforeUpdate !== "function"; + !noStaticGetSnapshotBeforeUpdate + ? warning( + 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(_state))) { + warning(false, "%s.state: must be set to an object or null", name); + } + if (typeof instance.getChildContext === "function") { + !(typeof type.childContextTypes === "object") + ? warning( + false, + "%s.getChildContext(): childContextTypes must be defined in order to " + + "use getChildContext().", + name + ) + : void 0; + } + } + } + + function resetInputPointers(workInProgress, instance) { + instance.props = workInProgress.memoizedProps; + instance.state = workInProgress.memoizedState; + } + + function adoptClassInstance(workInProgress, instance) { + instance.updater = updater; + 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, props) { + var ctor = workInProgress.type; + var unmaskedContext = getUnmaskedContext(workInProgress); + var needsContext = isContextConsumer(workInProgress); + var context = needsContext + ? getMaskedContext(workInProgress, unmaskedContext) + : emptyObject; + + // 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 = + instance.state !== null && instance.state !== undefined + ? instance.state + : null; + adoptClassInstance(workInProgress, instance); + + { + if ( + typeof ctor.getDerivedStateFromProps === "function" && + state === null + ) { + var componentName = getComponentName(workInProgress) || "Component"; + if (!didWarnAboutUninitializedState.has(componentName)) { + didWarnAboutUninitializedState.add(componentName); + warning( + false, + "%s: Did not properly initialize state during construction. " + + "Expected state to be an object, but it was %s.", + componentName, + instance.state === null ? "null" : "undefined" + ); + } + } + + // 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(workInProgress) || "Component"; + var newApiName = + typeof ctor.getDerivedStateFromProps === "function" + ? "getDerivedStateFromProps()" + : "getSnapshotBeforeUpdate()"; + if ( + !didWarnAboutLegacyLifecyclesAndDerivedState.has(_componentName) + ) { + didWarnAboutLegacyLifecyclesAndDerivedState.add(_componentName); + warning( + 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 : "" + ); + } + } + } + } + + workInProgress.memoizedState = state; + + var partialState = callGetDerivedStateFromProps( + workInProgress, + instance, + props, + state + ); + + if (partialState !== null && partialState !== undefined) { + // Render-phase updates (like this) should not be added to the update queue, + // So that multiple render passes do not enqueue multiple updates. + // Instead, just synchronously merge the returned state into the instance. + workInProgress.memoizedState = Object.assign( + {}, + workInProgress.memoizedState, + partialState + ); + } + + // 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 (needsContext) { + 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) { + { + warning( + false, + "%s.componentWillMount(): Assigning directly to this.state is " + + "deprecated (except inside a component's " + + "constructor). Use setState instead.", + getComponentName(workInProgress) || "Component" + ); + } + updater.enqueueReplaceState(instance, instance.state, null); + } + } + + function callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + newContext + ) { + var oldState = instance.state; + startPhaseTimer(workInProgress, "componentWillReceiveProps"); + if (typeof instance.componentWillReceiveProps === "function") { + instance.componentWillReceiveProps(newProps, newContext); + } + if (typeof instance.UNSAFE_componentWillReceiveProps === "function") { + instance.UNSAFE_componentWillReceiveProps(newProps, newContext); + } + stopPhaseTimer(); + + if (instance.state !== oldState) { + { + var componentName = getComponentName(workInProgress) || "Component"; + if (!didWarnAboutStateAssignmentForComponent.has(componentName)) { + didWarnAboutStateAssignmentForComponent.add(componentName); + warning( + false, + "%s.componentWillReceiveProps(): Assigning directly to " + + "this.state is deprecated (except inside a component's " + + "constructor). Use setState instead.", + componentName + ); + } + } + updater.enqueueReplaceState(instance, instance.state, null); + } + } + + function callGetDerivedStateFromProps( + workInProgress, + instance, + nextProps, + prevState + ) { + var type = workInProgress.type; + + if (typeof type.getDerivedStateFromProps === "function") { + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + // Invoke method an extra time to help detect side-effects. + type.getDerivedStateFromProps.call(null, nextProps, prevState); + } + + var partialState = type.getDerivedStateFromProps.call( + null, + nextProps, + prevState + ); + + { + if (partialState === undefined) { + var componentName = getComponentName(workInProgress) || "Component"; + if (!didWarnAboutUndefinedDerivedState.has(componentName)) { + didWarnAboutUndefinedDerivedState.add(componentName); + warning( + false, + "%s.getDerivedStateFromProps(): A valid state object (or null) must be returned. " + + "You have returned undefined.", + componentName + ); + } + } + } + + return partialState; + } + } + + // Invokes the mount life-cycles on a previously never rendered instance. + function mountClassInstance(workInProgress, renderExpirationTime) { + var ctor = workInProgress.type; + var current = workInProgress.alternate; + + { + checkClassInstance(workInProgress); + } + + var instance = workInProgress.stateNode; + var props = workInProgress.pendingProps; + var unmaskedContext = getUnmaskedContext(workInProgress); + + instance.props = props; + instance.state = workInProgress.memoizedState; + instance.refs = emptyObject; + instance.context = getMaskedContext(workInProgress, unmaskedContext); + + { + if (workInProgress.mode & StrictMode) { + ReactStrictModeWarnings.recordUnsafeLifecycleWarnings( + workInProgress, + instance + ); + } + + if (warnAboutDeprecatedLifecycles) { + ReactStrictModeWarnings.recordDeprecationWarnings( + workInProgress, + instance + ); + } + } + + // 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. + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + instance.state = processUpdateQueue( + current, + workInProgress, + updateQueue, + instance, + props, + renderExpirationTime + ); + } + } + if (typeof instance.componentDidMount === "function") { + workInProgress.effectTag |= Update; + } + } + + function resumeMountClassInstance(workInProgress, renderExpirationTime) { + var ctor = workInProgress.type; + var instance = workInProgress.stateNode; + resetInputPointers(workInProgress, instance); + + var oldProps = workInProgress.memoizedProps; + var newProps = workInProgress.pendingProps; + var oldContext = instance.context; + var newUnmaskedContext = getUnmaskedContext(workInProgress); + var newContext = getMaskedContext(workInProgress, newUnmaskedContext); + + var hasNewLifecycles = + typeof ctor.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 !== newContext) { + callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + newContext + ); + } + } + + // Compute the next state using the memoized state and the update queue. + var oldState = workInProgress.memoizedState; + // TODO: Previous state can be null. + var newState = void 0; + var derivedStateFromCatch = void 0; + if (workInProgress.updateQueue !== null) { + newState = processUpdateQueue( + null, + workInProgress, + workInProgress.updateQueue, + instance, + newProps, + renderExpirationTime + ); + + var updateQueue = workInProgress.updateQueue; + if ( + updateQueue !== null && + updateQueue.capturedValues !== null && + enableGetDerivedStateFromCatch && + typeof ctor.getDerivedStateFromCatch === "function" + ) { + var capturedValues = updateQueue.capturedValues; + // Don't remove these from the update queue yet. We need them in + // finishClassComponent. Do the reset there. + // TODO: This is awkward. Refactor class components. + // updateQueue.capturedValues = null; + derivedStateFromCatch = callGetDerivedStateFromCatch( + ctor, + capturedValues + ); + } + } else { + newState = oldState; + } + + var derivedStateFromProps = void 0; + if (oldProps !== newProps) { + // The prevState parameter should be the partially updated state. + // Otherwise, spreading state in return values could override updates. + derivedStateFromProps = callGetDerivedStateFromProps( + workInProgress, + instance, + newProps, + newState + ); + } + + if (derivedStateFromProps !== null && derivedStateFromProps !== undefined) { + // Render-phase updates (like this) should not be added to the update queue, + // So that multiple render passes do not enqueue multiple updates. + // Instead, just synchronously merge the returned state into the instance. + newState = + newState === null || newState === undefined + ? derivedStateFromProps + : Object.assign({}, newState, derivedStateFromProps); + + // Update the base state of the update queue. + // FIXME: This is getting ridiculous. Refactor plz! + var _updateQueue = workInProgress.updateQueue; + if (_updateQueue !== null) { + _updateQueue.baseState = Object.assign( + {}, + _updateQueue.baseState, + derivedStateFromProps + ); + } + } + if (derivedStateFromCatch !== null && derivedStateFromCatch !== undefined) { + // Render-phase updates (like this) should not be added to the update queue, + // So that multiple render passes do not enqueue multiple updates. + // Instead, just synchronously merge the returned state into the instance. + newState = + newState === null || newState === undefined + ? derivedStateFromCatch + : Object.assign({}, newState, derivedStateFromCatch); + + // Update the base state of the update queue. + // FIXME: This is getting ridiculous. Refactor plz! + var _updateQueue2 = workInProgress.updateQueue; + if (_updateQueue2 !== null) { + _updateQueue2.baseState = Object.assign( + {}, + _updateQueue2.baseState, + derivedStateFromCatch + ); + } + } + + if ( + oldProps === newProps && + oldState === newState && + !hasContextChanged() && + !( + workInProgress.updateQueue !== null && + workInProgress.updateQueue.hasForceUpdate + ) + ) { + // 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; + } + + var shouldUpdate = checkShouldComponentUpdate( + workInProgress, + oldProps, + newProps, + oldState, + newState, + newContext + ); + + 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 props/state to indicate that this work can be reused. + memoizeProps(workInProgress, newProps); + memoizeState(workInProgress, newState); + } + + // Update the existing instance's state, props, and context pointers even + // if shouldComponentUpdate returns false. + instance.props = newProps; + instance.state = newState; + instance.context = newContext; + + return shouldUpdate; + } + + // Invokes the update life-cycles and returns false if it shouldn't rerender. + function updateClassInstance(current, workInProgress, renderExpirationTime) { + var ctor = workInProgress.type; + var instance = workInProgress.stateNode; + resetInputPointers(workInProgress, instance); + + var oldProps = workInProgress.memoizedProps; + var newProps = workInProgress.pendingProps; + var oldContext = instance.context; + var newUnmaskedContext = getUnmaskedContext(workInProgress); + var newContext = getMaskedContext(workInProgress, newUnmaskedContext); + + var hasNewLifecycles = + typeof ctor.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 !== newContext) { + callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + newContext + ); + } + } + + // Compute the next state using the memoized state and the update queue. + var oldState = workInProgress.memoizedState; + // TODO: Previous state can be null. + var newState = void 0; + var derivedStateFromCatch = void 0; + + if (workInProgress.updateQueue !== null) { + newState = processUpdateQueue( + current, + workInProgress, + workInProgress.updateQueue, + instance, + newProps, + renderExpirationTime + ); + + var updateQueue = workInProgress.updateQueue; + if ( + updateQueue !== null && + updateQueue.capturedValues !== null && + enableGetDerivedStateFromCatch && + typeof ctor.getDerivedStateFromCatch === "function" + ) { + var capturedValues = updateQueue.capturedValues; + // Don't remove these from the update queue yet. We need them in + // finishClassComponent. Do the reset there. + // TODO: This is awkward. Refactor class components. + // updateQueue.capturedValues = null; + derivedStateFromCatch = callGetDerivedStateFromCatch( + ctor, + capturedValues + ); + } + } else { + newState = oldState; + } + + var derivedStateFromProps = void 0; + if (oldProps !== newProps) { + // The prevState parameter should be the partially updated state. + // Otherwise, spreading state in return values could override updates. + derivedStateFromProps = callGetDerivedStateFromProps( + workInProgress, + instance, + newProps, + newState + ); + } + + if (derivedStateFromProps !== null && derivedStateFromProps !== undefined) { + // Render-phase updates (like this) should not be added to the update queue, + // So that multiple render passes do not enqueue multiple updates. + // Instead, just synchronously merge the returned state into the instance. + newState = + newState === null || newState === undefined + ? derivedStateFromProps + : Object.assign({}, newState, derivedStateFromProps); + + // Update the base state of the update queue. + // FIXME: This is getting ridiculous. Refactor plz! + var _updateQueue3 = workInProgress.updateQueue; + if (_updateQueue3 !== null) { + _updateQueue3.baseState = Object.assign( + {}, + _updateQueue3.baseState, + derivedStateFromProps + ); + } + } + if (derivedStateFromCatch !== null && derivedStateFromCatch !== undefined) { + // Render-phase updates (like this) should not be added to the update queue, + // So that multiple render passes do not enqueue multiple updates. + // Instead, just synchronously merge the returned state into the instance. + newState = + newState === null || newState === undefined + ? derivedStateFromCatch + : Object.assign({}, newState, derivedStateFromCatch); + + // Update the base state of the update queue. + // FIXME: This is getting ridiculous. Refactor plz! + var _updateQueue4 = workInProgress.updateQueue; + if (_updateQueue4 !== null) { + _updateQueue4.baseState = Object.assign( + {}, + _updateQueue4.baseState, + derivedStateFromCatch + ); + } + } + + if ( + oldProps === newProps && + oldState === newState && + !hasContextChanged() && + !( + workInProgress.updateQueue !== null && + workInProgress.updateQueue.hasForceUpdate + ) + ) { + // 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; + } + + var shouldUpdate = checkShouldComponentUpdate( + workInProgress, + oldProps, + newProps, + oldState, + newState, + newContext + ); + + 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, newContext); + } + if (typeof instance.UNSAFE_componentWillUpdate === "function") { + instance.UNSAFE_componentWillUpdate(newProps, newState, newContext); + } + 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. + memoizeProps(workInProgress, newProps); + memoizeState(workInProgress, newState); + } + + // Update the existing instance's state, props, and context pointers even + // if shouldComponentUpdate returns false. + instance.props = newProps; + instance.state = newState; + instance.context = newContext; + + return shouldUpdate; + } + + return { + adoptClassInstance: adoptClassInstance, + callGetDerivedStateFromProps: callGetDerivedStateFromProps, + constructClassInstance: constructClassInstance, + mountClassInstance: mountClassInstance, + resumeMountClassInstance: resumeMountClassInstance, + updateClassInstance: updateClassInstance + }; +}; + +var getCurrentFiberStackAddendum$1 = + ReactDebugCurrentFiber.getCurrentFiberStackAddendum; + +var didWarnAboutMaps = void 0; +var didWarnAboutStringRefInStrictMode = void 0; +var ownerHasKeyUseWarning = void 0; +var ownerHasFunctionTypeWarning = void 0; +var warnForMissingKey = function(child) {}; + +{ + didWarnAboutMaps = 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; + } + invariant( + typeof child._store === "object", + "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 an array or iterator should have a unique " + + '"key" prop. See https://fb.me/react-warning-keys for ' + + "more information." + + (getCurrentFiberStackAddendum$1() || ""); + if (ownerHasKeyUseWarning[currentComponentErrorInfo]) { + return; + } + ownerHasKeyUseWarning[currentComponentErrorInfo] = true; + + warning( + false, + "Each child in an array or iterator should have a unique " + + '"key" prop. See https://fb.me/react-warning-keys for ' + + "more information.%s", + getCurrentFiberStackAddendum$1() + ); + }; +} + +var isArray$1 = Array.isArray; + +function coerceRef(returnFiber, current, element) { + var mixedRef = element.ref; + if ( + mixedRef !== null && + typeof mixedRef !== "function" && + typeof mixedRef !== "object" + ) { + { + if (returnFiber.mode & StrictMode) { + var componentName = getComponentName(returnFiber) || "Component"; + if (!didWarnAboutStringRefInStrictMode[componentName]) { + warning( + 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, + getStackAddendumByWorkInProgressFiber(returnFiber) + ); + didWarnAboutStringRefInStrictMode[componentName] = true; + } + } + } + + if (element._owner) { + var owner = element._owner; + var inst = void 0; + if (owner) { + var ownerFiber = owner; + invariant( + ownerFiber.tag === ClassComponent, + "Stateless function components cannot have refs." + ); + inst = ownerFiber.stateNode; + } + invariant( + inst, + "Missing owner for string ref %s. This error is likely caused by a " + + "bug in React. Please file an issue.", + mixedRef + ); + var stringRef = "" + mixedRef; + // Check if previous string ref matches new string ref + if ( + current !== null && + current.ref !== null && + current.ref._stringRef === stringRef + ) { + return current.ref; + } + var ref = function(value) { + var refs = inst.refs === emptyObject ? (inst.refs = {}) : inst.refs; + if (value === null) { + delete refs[stringRef]; + } else { + refs[stringRef] = value; + } + }; + ref._stringRef = stringRef; + return ref; + } else { + invariant( + typeof mixedRef === "string", + "Expected ref to be a function or a string." + ); + invariant( + element._owner, + "Element ref was specified as a string (%s) but no owner was set. This could happen for one of" + + " the following reasons:\n" + + "1. You may be adding a ref to a functional component\n" + + "2. You may be adding a ref to a component that was not created inside a component's render method\n" + + "3. You have multiple copies of React loaded\n" + + "See https://fb.me/react-refs-must-have-owner for more information.", + mixedRef + ); + } + } + 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." + + (getCurrentFiberStackAddendum$1() || ""); + } + invariant( + false, + "Objects are not valid as a React child (found: %s).%s", + 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." + + (getCurrentFiberStackAddendum$1() || ""); + + if (ownerHasFunctionTypeWarning[currentComponentErrorInfo]) { + return; + } + ownerHasFunctionTypeWarning[currentComponentErrorInfo] = true; + + warning( + 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.%s", + getCurrentFiberStackAddendum$1() || "" + ); +} + +// 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 = newFiber.alternate; + if (current !== null) { + var oldIndex = current.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, textContent, expirationTime) { + if (current === null || current.tag !== HostText) { + // Insert + var created = createFiberFromText( + textContent, + returnFiber.mode, + expirationTime + ); + created["return"] = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current, textContent, expirationTime); + existing["return"] = returnFiber; + return existing; + } + } + + function updateElement(returnFiber, current, element, expirationTime) { + if (current !== null && current.type === element.type) { + // Move based on index + var existing = useFiber(current, element.props, expirationTime); + existing.ref = coerceRef(returnFiber, current, 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, element); + created["return"] = returnFiber; + return created; + } + } + + function updatePortal(returnFiber, current, portal, expirationTime) { + if ( + current === null || + current.tag !== HostPortal || + current.stateNode.containerInfo !== portal.containerInfo || + current.stateNode.implementation !== portal.implementation + ) { + // Insert + var created = createFiberFromPortal( + portal, + returnFiber.mode, + expirationTime + ); + created["return"] = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current, portal.children || [], expirationTime); + existing["return"] = returnFiber; + return existing; + } + } + + function updateFragment(returnFiber, current, fragment, expirationTime, key) { + if (current === null || current.tag !== Fragment) { + // Insert + var created = createFiberFromFragment( + fragment, + returnFiber.mode, + expirationTime, + key + ); + created["return"] = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current, 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$1(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$1(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$1(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( + 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.%s", + key, + getCurrentFiberStackAddendum$1() + ); + break; + default: + break; + } + } + return knownKeys; + } + + function reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChildren, + expirationTime + ) { + // This algorithm can't optimize by searching from boths 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) { + 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) { + 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); + invariant( + typeof iteratorFn === "function", + "An object is not an iterable. This error is likely caused by a bug in " + + "React. Please file an issue." + ); + + { + // Warn about using Maps as children + if (typeof newChildrenIterable.entries === "function") { + var possibleMap = newChildrenIterable; + if (possibleMap.entries === iteratorFn) { + !didWarnAboutMaps + ? warning( + false, + "Using Maps as children is unsupported and will likely yield " + + "unexpected results. Convert it to a sequence/iterable of keyed " + + "ReactElements instead.%s", + getCurrentFiberStackAddendum$1() + ) + : 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); + invariant(newChildren != null, "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) { + 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.type === 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. + if ( + typeof newChild === "object" && + newChild !== null && + newChild.type === REACT_FRAGMENT_TYPE && + newChild.key === null + ) { + 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$1(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") { + // 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 FunctionalComponent: { + var Component = returnFiber.type; + invariant( + false, + "%s(...): Nothing was returned from render. This usually means a " + + "return statement is missing. Or, to render nothing, " + + "return null.", + Component.displayName || Component.name || "Component" + ); + } + } + } + + // Remaining cases are all treated as empty. + return deleteRemainingChildren(returnFiber, currentFirstChild); + } + + return reconcileChildFibers; +} + +var reconcileChildFibers = ChildReconciler(true); +var mountChildFibers = ChildReconciler(false); + +function cloneChildFibers(current, workInProgress) { + invariant( + current === null || workInProgress.child === current.child, + "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 didWarnAboutBadClass = void 0; +var didWarnAboutGetDerivedStateOnFunctionalComponent = void 0; +var didWarnAboutStatelessRefs = void 0; + +{ + didWarnAboutBadClass = {}; + didWarnAboutGetDerivedStateOnFunctionalComponent = {}; + didWarnAboutStatelessRefs = {}; +} + +var ReactFiberBeginWork = function( + config, + hostContext, + legacyContext, + newContext, + hydrationContext, + scheduleWork, + computeExpirationForFiber +) { + var shouldSetTextContent = config.shouldSetTextContent, + shouldDeprioritizeSubtree = config.shouldDeprioritizeSubtree; + var pushHostContext = hostContext.pushHostContext, + pushHostContainer = hostContext.pushHostContainer; + var pushProvider = newContext.pushProvider; + var getMaskedContext = legacyContext.getMaskedContext, + getUnmaskedContext = legacyContext.getUnmaskedContext, + hasLegacyContextChanged = legacyContext.hasContextChanged, + pushLegacyContextProvider = legacyContext.pushContextProvider, + pushTopLevelContextObject = legacyContext.pushTopLevelContextObject, + invalidateContextProvider = legacyContext.invalidateContextProvider; + var enterHydrationState = hydrationContext.enterHydrationState, + resetHydrationState = hydrationContext.resetHydrationState, + tryToClaimNextHydratableInstance = + hydrationContext.tryToClaimNextHydratableInstance; + + var _ReactFiberClassCompo = ReactFiberClassComponent( + legacyContext, + scheduleWork, + computeExpirationForFiber, + memoizeProps, + memoizeState + ), + adoptClassInstance = _ReactFiberClassCompo.adoptClassInstance, + callGetDerivedStateFromProps = + _ReactFiberClassCompo.callGetDerivedStateFromProps, + constructClassInstance = _ReactFiberClassCompo.constructClassInstance, + mountClassInstance = _ReactFiberClassCompo.mountClassInstance, + resumeMountClassInstance = _ReactFiberClassCompo.resumeMountClassInstance, + updateClassInstance = _ReactFiberClassCompo.updateClassInstance; + + // TODO: Remove this and use reconcileChildrenAtExpirationTime directly. + + function reconcileChildren(current, workInProgress, nextChildren) { + reconcileChildrenAtExpirationTime( + current, + workInProgress, + nextChildren, + workInProgress.expirationTime + ); + } + + function reconcileChildrenAtExpirationTime( + current, + workInProgress, + nextChildren, + renderExpirationTime + ) { + if (current === 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.child, + nextChildren, + renderExpirationTime + ); + } + } + + function updateForwardRef(current, workInProgress) { + var render = workInProgress.type.render; + var nextChildren = render(workInProgress.pendingProps, workInProgress.ref); + reconcileChildren(current, workInProgress, nextChildren); + memoizeProps(workInProgress, nextChildren); + return workInProgress.child; + } + + function updateFragment(current, workInProgress) { + var nextChildren = workInProgress.pendingProps; + if (hasLegacyContextChanged()) { + // Normally we can bail out on props equality but if context has changed + // we don't do the bailout and we have to reuse existing props instead. + } else if (workInProgress.memoizedProps === nextChildren) { + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + reconcileChildren(current, workInProgress, nextChildren); + memoizeProps(workInProgress, nextChildren); + return workInProgress.child; + } + + function updateMode(current, workInProgress) { + var nextChildren = workInProgress.pendingProps.children; + if (hasLegacyContextChanged()) { + // Normally we can bail out on props equality but if context has changed + // we don't do the bailout and we have to reuse existing props instead. + } else if ( + nextChildren === null || + workInProgress.memoizedProps === nextChildren + ) { + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + reconcileChildren(current, workInProgress, nextChildren); + memoizeProps(workInProgress, nextChildren); + return workInProgress.child; + } + + function markRef(current, workInProgress) { + var ref = workInProgress.ref; + if ( + (current === null && ref !== null) || + (current !== null && current.ref !== ref) + ) { + // Schedule a Ref effect + workInProgress.effectTag |= Ref; + } + } + + function updateFunctionalComponent(current, workInProgress) { + var fn = workInProgress.type; + var nextProps = workInProgress.pendingProps; + + if (hasLegacyContextChanged()) { + // Normally we can bail out on props equality but if context has changed + // we don't do the bailout and we have to reuse existing props instead. + } else { + if (workInProgress.memoizedProps === nextProps) { + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + // TODO: consider bringing fn.shouldComponentUpdate() back. + // It used to be here. + } + + var unmaskedContext = getUnmaskedContext(workInProgress); + var context = getMaskedContext(workInProgress, unmaskedContext); + + var nextChildren = void 0; + + { + ReactCurrentOwner.current = workInProgress; + ReactDebugCurrentFiber.setCurrentPhase("render"); + nextChildren = fn(nextProps, context); + ReactDebugCurrentFiber.setCurrentPhase(null); + } + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + reconcileChildren(current, workInProgress, nextChildren); + memoizeProps(workInProgress, nextProps); + return workInProgress.child; + } + + function updateClassComponent(current, workInProgress, renderExpirationTime) { + // 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 = pushLegacyContextProvider(workInProgress); + var shouldUpdate = void 0; + if (current === null) { + if (workInProgress.stateNode === null) { + // In the initial pass we might need to construct the instance. + constructClassInstance(workInProgress, workInProgress.pendingProps); + mountClassInstance(workInProgress, renderExpirationTime); + + shouldUpdate = true; + } else { + // In a resume, we'll already have an instance we can reuse. + shouldUpdate = resumeMountClassInstance( + workInProgress, + renderExpirationTime + ); + } + } else { + shouldUpdate = updateClassInstance( + current, + workInProgress, + renderExpirationTime + ); + } + + // We processed the update queue inside updateClassInstance. It may have + // included some errors that were dispatched during the commit phase. + // TODO: Refactor class components so this is less awkward. + var didCaptureError = false; + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null && updateQueue.capturedValues !== null) { + shouldUpdate = true; + didCaptureError = true; + } + return finishClassComponent( + current, + workInProgress, + shouldUpdate, + hasContext, + didCaptureError, + renderExpirationTime + ); + } + + function finishClassComponent( + current, + workInProgress, + shouldUpdate, + hasContext, + didCaptureError, + renderExpirationTime + ) { + // Refs should update even if shouldComponentUpdate returns false + markRef(current, workInProgress); + + if (!shouldUpdate && !didCaptureError) { + // Context providers should defer to sCU for rendering + if (hasContext) { + invalidateContextProvider(workInProgress, false); + } + + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + + var ctor = workInProgress.type; + var instance = workInProgress.stateNode; + + // Rerender + ReactCurrentOwner.current = workInProgress; + var nextChildren = void 0; + if ( + didCaptureError && + (!enableGetDerivedStateFromCatch || + typeof ctor.getDerivedStateFromCatch !== "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; + } else { + { + ReactDebugCurrentFiber.setCurrentPhase("render"); + nextChildren = instance.render(); + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + instance.render(); + } + ReactDebugCurrentFiber.setCurrentPhase(null); + } + } + + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + if (didCaptureError) { + // If we're recovering from an error, reconcile twice: first to delete + // all the existing children. + reconcileChildrenAtExpirationTime( + current, + workInProgress, + null, + renderExpirationTime + ); + workInProgress.child = null; + // Now we can continue reconciling like normal. This has the effect of + // remounting all children regardless of whether their their + // identity matches. + } + reconcileChildrenAtExpirationTime( + current, + workInProgress, + nextChildren, + renderExpirationTime + ); + // Memoize props and state using the values we just used to render. + // TODO: Restructure so we never read values from the instance. + memoizeState(workInProgress, instance.state); + memoizeProps(workInProgress, instance.props); + + // The context might have changed so we need to recalculate it. + if (hasContext) { + invalidateContextProvider(workInProgress, 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, workInProgress, renderExpirationTime) { + pushHostRootContext(workInProgress); + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + var prevState = workInProgress.memoizedState; + var state = processUpdateQueue( + current, + workInProgress, + updateQueue, + null, + null, + renderExpirationTime + ); + memoizeState(workInProgress, state); + updateQueue = workInProgress.updateQueue; + + var element = void 0; + if (updateQueue !== null && updateQueue.capturedValues !== null) { + // There's an uncaught error. Unmount the whole root. + element = null; + } else if (prevState === state) { + // 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, workInProgress); + } else { + element = state.element; + } + var root = workInProgress.stateNode; + if ( + (current === null || current.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, + element, + renderExpirationTime + ); + } else { + // Otherwise reset hydration state in case we aborted and resumed another + // root. + resetHydrationState(); + reconcileChildren(current, workInProgress, element); + } + memoizeState(workInProgress, state); + return workInProgress.child; + } + resetHydrationState(); + // If there is no update queue, that's a bailout because the root has no props. + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + + function updateHostComponent(current, workInProgress, renderExpirationTime) { + pushHostContext(workInProgress); + + if (current === null) { + tryToClaimNextHydratableInstance(workInProgress); + } + + var type = workInProgress.type; + var memoizedProps = workInProgress.memoizedProps; + var nextProps = workInProgress.pendingProps; + var prevProps = current !== null ? current.memoizedProps : null; + + if (hasLegacyContextChanged()) { + // Normally we can bail out on props equality but if context has changed + // we don't do the bailout and we have to reuse existing props instead. + } else if (memoizedProps === nextProps) { + var isHidden = + workInProgress.mode & AsyncMode && + shouldDeprioritizeSubtree(type, nextProps); + if (isHidden) { + // Before bailing out, make sure we've deprioritized a hidden component. + workInProgress.expirationTime = Never; + } + if (!isHidden || renderExpirationTime !== Never) { + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + // If we're rendering a hidden node at hidden priority, don't bailout. The + // parent is complete, but the children may not be. + } + + 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 && 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, workInProgress); + + // Check the host config to see if the children are offscreen/hidden. + if ( + renderExpirationTime !== Never && + workInProgress.mode & AsyncMode && + shouldDeprioritizeSubtree(type, nextProps) + ) { + // Down-prioritize the children. + workInProgress.expirationTime = Never; + // Bailout and come back to this fiber later. + workInProgress.memoizedProps = nextProps; + return null; + } + + reconcileChildren(current, workInProgress, nextChildren); + memoizeProps(workInProgress, nextProps); + return workInProgress.child; + } + + function updateHostText(current, workInProgress) { + if (current === null) { + tryToClaimNextHydratableInstance(workInProgress); + } + var nextProps = workInProgress.pendingProps; + memoizeProps(workInProgress, nextProps); + // Nothing to do here. This is terminal. We'll do the completion step + // immediately after. + return null; + } + + function mountIndeterminateComponent( + current, + workInProgress, + renderExpirationTime + ) { + invariant( + current === null, + "An indeterminate component should never have mounted. This error is " + + "likely caused by a bug in React. Please file an issue." + ); + var fn = workInProgress.type; + var props = workInProgress.pendingProps; + var unmaskedContext = getUnmaskedContext(workInProgress); + var context = getMaskedContext(workInProgress, unmaskedContext); + + var value = void 0; + + { + if (fn.prototype && typeof fn.prototype.render === "function") { + var componentName = getComponentName(workInProgress) || "Unknown"; + + if (!didWarnAboutBadClass[componentName]) { + warning( + 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; + } + } + ReactCurrentOwner.current = workInProgress; + value = fn(props, context); + } + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + + if ( + typeof value === "object" && + value !== null && + typeof value.render === "function" && + value.$$typeof === undefined + ) { + var Component = workInProgress.type; + + // Proceed under the assumption that this is a class instance + workInProgress.tag = ClassComponent; + + workInProgress.memoizedState = + value.state !== null && value.state !== undefined ? value.state : null; + + if (typeof Component.getDerivedStateFromProps === "function") { + var partialState = callGetDerivedStateFromProps( + workInProgress, + value, + props, + workInProgress.memoizedState + ); + + if (partialState !== null && partialState !== undefined) { + workInProgress.memoizedState = Object.assign( + {}, + workInProgress.memoizedState, + partialState + ); + } + } + + // 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 = pushLegacyContextProvider(workInProgress); + adoptClassInstance(workInProgress, value); + mountClassInstance(workInProgress, renderExpirationTime); + return finishClassComponent( + current, + workInProgress, + true, + hasContext, + false, + renderExpirationTime + ); + } else { + // Proceed under the assumption that this is a functional component + workInProgress.tag = FunctionalComponent; + { + var _Component = workInProgress.type; + + if (_Component) { + !!_Component.childContextTypes + ? warning( + false, + "%s(...): childContextTypes cannot be defined on a functional component.", + _Component.displayName || _Component.name || "Component" + ) + : void 0; + } + if (workInProgress.ref !== null) { + var info = ""; + var ownerName = ReactDebugCurrentFiber.getCurrentFiberOwnerName(); + 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 (!didWarnAboutStatelessRefs[warningKey]) { + didWarnAboutStatelessRefs[warningKey] = true; + warning( + false, + "Stateless function components cannot be given refs. " + + "Attempts to access this ref will fail.%s%s", + info, + ReactDebugCurrentFiber.getCurrentFiberStackAddendum() + ); + } + } + + if (typeof fn.getDerivedStateFromProps === "function") { + var _componentName = getComponentName(workInProgress) || "Unknown"; + + if ( + !didWarnAboutGetDerivedStateOnFunctionalComponent[_componentName] + ) { + warning( + false, + "%s: Stateless functional components do not support getDerivedStateFromProps.", + _componentName + ); + didWarnAboutGetDerivedStateOnFunctionalComponent[ + _componentName + ] = true; + } + } + } + reconcileChildren(current, workInProgress, value); + memoizeProps(workInProgress, props); + return workInProgress.child; + } + } + + function updateCallComponent(current, workInProgress, renderExpirationTime) { + var nextProps = workInProgress.pendingProps; + if (hasLegacyContextChanged()) { + // Normally we can bail out on props equality but if context has changed + // we don't do the bailout and we have to reuse existing props instead. + } else if (workInProgress.memoizedProps === nextProps) { + nextProps = workInProgress.memoizedProps; + // TODO: When bailing out, we might need to return the stateNode instead + // of the child. To check it for work. + // return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + + var nextChildren = nextProps.children; + + // The following is a fork of reconcileChildrenAtExpirationTime but using + // stateNode to store the child. + if (current === null) { + workInProgress.stateNode = mountChildFibers( + workInProgress, + workInProgress.stateNode, + nextChildren, + renderExpirationTime + ); + } else { + workInProgress.stateNode = reconcileChildFibers( + workInProgress, + current.stateNode, + nextChildren, + renderExpirationTime + ); + } + + memoizeProps(workInProgress, nextProps); + // This doesn't take arbitrary time so we could synchronously just begin + // eagerly do the work of workInProgress.child as an optimization. + return workInProgress.stateNode; + } + + function updatePortalComponent( + current, + workInProgress, + renderExpirationTime + ) { + pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); + var nextChildren = workInProgress.pendingProps; + if (hasLegacyContextChanged()) { + // Normally we can bail out on props equality but if context has changed + // we don't do the bailout and we have to reuse existing props instead. + } else if (workInProgress.memoizedProps === nextChildren) { + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + + if (current === 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 + ); + memoizeProps(workInProgress, nextChildren); + } else { + reconcileChildren(current, workInProgress, nextChildren); + memoizeProps(workInProgress, nextChildren); + } + return workInProgress.child; + } + + 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. + switch (fiber.tag) { + case ContextConsumer: + // Check if the context matches. + var observedBits = fiber.stateNode | 0; + if (fiber.type === context && (observedBits & changedBits) !== 0) { + // Update the expiration time of all the ancestors, including + // the alternates. + var node = fiber; + while (node !== null) { + var alternate = node.alternate; + if ( + node.expirationTime === NoWork || + node.expirationTime > renderExpirationTime + ) { + node.expirationTime = renderExpirationTime; + if ( + alternate !== null && + (alternate.expirationTime === NoWork || + alternate.expirationTime > renderExpirationTime) + ) { + alternate.expirationTime = renderExpirationTime; + } + } else if ( + alternate !== null && + (alternate.expirationTime === NoWork || + alternate.expirationTime > renderExpirationTime) + ) { + alternate.expirationTime = renderExpirationTime; + } else { + // Neither alternate was updated, which means the rest of the + // ancestor path already has sufficient priority. + break; + } + node = node["return"]; + } + // Don't scan deeper than a matching consumer. When we render the + // consumer, we'll continue scanning from that point. This way the + // scanning work is time-sliced. + nextFiber = null; + } else { + // Traverse down. + nextFiber = fiber.child; + } + break; + case ContextProvider: + // Don't scan deeper if this is a matching provider + nextFiber = fiber.type === workInProgress.type ? null : fiber.child; + break; + default: + // Traverse down. + nextFiber = fiber.child; + break; + } + 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) { + nextFiber = sibling; + break; + } + // No more siblings. Traverse up. + nextFiber = nextFiber["return"]; + } + } + fiber = nextFiber; + } + } + + function updateContextProvider( + current, + workInProgress, + renderExpirationTime + ) { + var providerType = workInProgress.type; + var context = providerType._context; + + var newProps = workInProgress.pendingProps; + var oldProps = workInProgress.memoizedProps; + + if (hasLegacyContextChanged()) { + // Normally we can bail out on props equality but if context has changed + // we don't do the bailout and we have to reuse existing props instead. + } else if (oldProps === newProps) { + workInProgress.stateNode = 0; + pushProvider(workInProgress); + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + + var newValue = newProps.value; + workInProgress.memoizedProps = newProps; + + var changedBits = void 0; + if (oldProps === null) { + // Initial render + changedBits = MAX_SIGNED_31_BIT_INT; + } else { + if (oldProps.value === newProps.value) { + // No change. Bailout early if children are the same. + if (oldProps.children === newProps.children) { + workInProgress.stateNode = 0; + pushProvider(workInProgress); + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + changedBits = 0; + } else { + var oldValue = oldProps.value; + // Use Object.is to compare the new context value to the old value. + // Inlined Object.is polyfill. + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is + if ( + (oldValue === newValue && + (oldValue !== 0 || 1 / oldValue === 1 / newValue)) || + (oldValue !== oldValue && newValue !== newValue) // eslint-disable-line no-self-compare + ) { + // No change. Bailout early if children are the same. + if (oldProps.children === newProps.children) { + workInProgress.stateNode = 0; + pushProvider(workInProgress); + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + changedBits = 0; + } else { + changedBits = + typeof context._calculateChangedBits === "function" + ? context._calculateChangedBits(oldValue, newValue) + : MAX_SIGNED_31_BIT_INT; + { + !((changedBits & MAX_SIGNED_31_BIT_INT) === changedBits) + ? warning( + false, + "calculateChangedBits: Expected the return value to be a " + + "31-bit integer. Instead received: %s", + changedBits + ) + : void 0; + } + changedBits |= 0; + + if (changedBits === 0) { + // No change. Bailout early if children are the same. + if (oldProps.children === newProps.children) { + workInProgress.stateNode = 0; + pushProvider(workInProgress); + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + } else { + propagateContextChange( + workInProgress, + context, + changedBits, + renderExpirationTime + ); + } + } + } + } + + workInProgress.stateNode = changedBits; + pushProvider(workInProgress); + + var newChildren = newProps.children; + reconcileChildren(current, workInProgress, newChildren); + return workInProgress.child; + } + + function updateContextConsumer( + current, + workInProgress, + renderExpirationTime + ) { + var context = workInProgress.type; + var newProps = workInProgress.pendingProps; + var oldProps = workInProgress.memoizedProps; + + var newValue = context._currentValue; + var changedBits = context._changedBits; + + if (hasLegacyContextChanged()) { + // Normally we can bail out on props equality but if context has changed + // we don't do the bailout and we have to reuse existing props instead. + } else if (changedBits === 0 && oldProps === newProps) { + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + workInProgress.memoizedProps = newProps; + + var observedBits = newProps.unstable_observedBits; + if (observedBits === undefined || observedBits === null) { + // Subscribe to all changes by default + observedBits = MAX_SIGNED_31_BIT_INT; + } + // Store the observedBits on the fiber's stateNode for quick access. + workInProgress.stateNode = observedBits; + + if ((changedBits & observedBits) !== 0) { + // Context change propagation stops at matching consumers, for time- + // slicing. Continue the propagation here. + propagateContextChange( + workInProgress, + context, + changedBits, + renderExpirationTime + ); + } else if (oldProps === newProps) { + // Skip over a memoized parent with a bitmask bailout even + // if we began working on it because of a deeper matching child. + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + // There is no bailout on `children` equality because we expect people + // to often pass a bound method as a child, but it may reference + // `this.state` or `this.props` (and thus needs to re-render on `setState`). + + var render = newProps.children; + + { + !(typeof render === "function") + ? warning( + 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; + } + + var newChildren = render(newValue); + reconcileChildren(current, workInProgress, newChildren); + return workInProgress.child; + } + + /* + function reuseChildrenEffects(returnFiber : Fiber, firstChild : Fiber) { + let child = firstChild; + do { + // Ensure that the first and last effect of the parent corresponds + // to the children's first and last effect. + if (!returnFiber.firstEffect) { + returnFiber.firstEffect = child.firstEffect; + } + if (child.lastEffect) { + if (returnFiber.lastEffect) { + returnFiber.lastEffect.nextEffect = child.firstEffect; + } + returnFiber.lastEffect = child.lastEffect; + } + } while (child = child.sibling); + } + */ + + function bailoutOnAlreadyFinishedWork(current, workInProgress) { + cancelWorkTimer(workInProgress); + + // TODO: We should ideally be able to bail out early if the children have no + // more work to do. However, since we don't have a separation of this + // Fiber's priority and its children yet - we don't know without doing lots + // of the same work we do anyway. Once we have that separation we can just + // bail out here if the children has no more work at this priority level. + // if (workInProgress.priorityOfChildren <= priorityLevel) { + // // If there are side-effects in these children that have not yet been + // // committed we need to ensure that they get properly transferred up. + // if (current && current.child !== workInProgress.child) { + // reuseChildrenEffects(workInProgress, child); + // } + // return null; + // } + + cloneChildFibers(current, workInProgress); + return workInProgress.child; + } + + function bailoutOnLowPriority(current, workInProgress) { + cancelWorkTimer(workInProgress); + + // TODO: Handle HostComponent tags here as well and call pushHostContext()? + // See PR 8590 discussion for context + switch (workInProgress.tag) { + case HostRoot: + pushHostRootContext(workInProgress); + break; + case ClassComponent: + pushLegacyContextProvider(workInProgress); + break; + case HostPortal: + pushHostContainer( + workInProgress, + workInProgress.stateNode.containerInfo + ); + break; + case ContextProvider: + pushProvider(workInProgress); + break; + } + // TODO: What if this is currently in progress? + // How can that happen? How is this not being cloned? + return null; + } + + // TODO: Delete memoizeProps/State and move to reconcile/bailout instead + function memoizeProps(workInProgress, nextProps) { + workInProgress.memoizedProps = nextProps; + } + + function memoizeState(workInProgress, nextState) { + workInProgress.memoizedState = nextState; + // Don't reset the updateQueue, in case there are pending updates. Resetting + // is handled by processUpdateQueue. + } + + function beginWork(current, workInProgress, renderExpirationTime) { + if ( + workInProgress.expirationTime === NoWork || + workInProgress.expirationTime > renderExpirationTime + ) { + return bailoutOnLowPriority(current, workInProgress); + } + + switch (workInProgress.tag) { + case IndeterminateComponent: + return mountIndeterminateComponent( + current, + workInProgress, + renderExpirationTime + ); + case FunctionalComponent: + return updateFunctionalComponent(current, workInProgress); + case ClassComponent: + return updateClassComponent( + current, + workInProgress, + renderExpirationTime + ); + case HostRoot: + return updateHostRoot(current, workInProgress, renderExpirationTime); + case HostComponent: + return updateHostComponent( + current, + workInProgress, + renderExpirationTime + ); + case HostText: + return updateHostText(current, workInProgress); + case CallHandlerPhase: + // This is a restart. Reset the tag to the initial phase. + workInProgress.tag = CallComponent; + // Intentionally fall through since this is now the same. + case CallComponent: + return updateCallComponent( + current, + workInProgress, + renderExpirationTime + ); + case ReturnComponent: + // A return component is just a placeholder, we can just run through the + // next one immediately. + return null; + case HostPortal: + return updatePortalComponent( + current, + workInProgress, + renderExpirationTime + ); + case ForwardRef: + return updateForwardRef(current, workInProgress); + case Fragment: + return updateFragment(current, workInProgress); + case Mode: + return updateMode(current, workInProgress); + case ContextProvider: + return updateContextProvider( + current, + workInProgress, + renderExpirationTime + ); + case ContextConsumer: + return updateContextConsumer( + current, + workInProgress, + renderExpirationTime + ); + default: + invariant( + false, + "Unknown unit of work tag. This error is likely caused by a bug in " + + "React. Please file an issue." + ); + } + } + + return { + beginWork: beginWork + }; +}; + +var ReactFiberCompleteWork = function( + config, + hostContext, + legacyContext, + newContext, + hydrationContext +) { + var createInstance = config.createInstance, + createTextInstance = config.createTextInstance, + appendInitialChild = config.appendInitialChild, + finalizeInitialChildren = config.finalizeInitialChildren, + prepareUpdate = config.prepareUpdate, + mutation = config.mutation, + persistence = config.persistence; + var getRootHostContainer = hostContext.getRootHostContainer, + popHostContext = hostContext.popHostContext, + getHostContext = hostContext.getHostContext, + popHostContainer = hostContext.popHostContainer; + var popLegacyContextProvider = legacyContext.popContextProvider, + popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject; + var popProvider = newContext.popProvider; + var prepareToHydrateHostInstance = + hydrationContext.prepareToHydrateHostInstance, + prepareToHydrateHostTextInstance = + hydrationContext.prepareToHydrateHostTextInstance, + popHydrationState = hydrationContext.popHydrationState; + + function markUpdate(workInProgress) { + // Tag the fiber with an update effect. This turns a Placement into + // a PlacementAndUpdate. + workInProgress.effectTag |= Update; + } + + function markRef(workInProgress) { + workInProgress.effectTag |= Ref; + } + + function appendAllReturns(returns, workInProgress) { + var node = workInProgress.stateNode; + if (node) { + node["return"] = workInProgress; + } + while (node !== null) { + if ( + node.tag === HostComponent || + node.tag === HostText || + node.tag === HostPortal + ) { + invariant(false, "A call cannot have host component children."); + } else if (node.tag === ReturnComponent) { + returns.push(node.pendingProps.value); + } else if (node.child !== null) { + node.child["return"] = node; + node = node.child; + continue; + } + while (node.sibling === null) { + if (node["return"] === null || node["return"] === workInProgress) { + return; + } + node = node["return"]; + } + node.sibling["return"] = node["return"]; + node = node.sibling; + } + } + + function moveCallToHandlerPhase( + current, + workInProgress, + renderExpirationTime + ) { + var props = workInProgress.memoizedProps; + invariant( + props, + "Should be resolved by now. This error is likely caused by a bug in " + + "React. Please file an issue." + ); + + // First step of the call has completed. Now we need to do the second. + // TODO: It would be nice to have a multi stage call represented by a + // single component, or at least tail call optimize nested ones. Currently + // that requires additional fields that we don't want to add to the fiber. + // So this requires nested handlers. + // Note: This doesn't mutate the alternate node. I don't think it needs to + // since this stage is reset for every pass. + workInProgress.tag = CallHandlerPhase; + + // Build up the returns. + // TODO: Compare this to a generator or opaque helpers like Children. + var returns = []; + appendAllReturns(returns, workInProgress); + var fn = props.handler; + var childProps = props.props; + var nextChildren = fn(childProps, returns); + + var currentFirstChild = current !== null ? current.child : null; + workInProgress.child = reconcileChildFibers( + workInProgress, + currentFirstChild, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; + } + + function appendAllChildren(parent, workInProgress) { + // 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; + } + } + + var updateHostContainer = void 0; + var updateHostComponent = void 0; + var updateHostText = void 0; + if (mutation) { + if (enableMutatingReconciler) { + // Mutation mode + updateHostContainer = function(workInProgress) { + // Noop + }; + updateHostComponent = function( + current, + workInProgress, + updatePayload, + 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 = 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 { + invariant(false, "Mutating reconciler is disabled."); + } + } else if (persistence) { + if (enablePersistentReconciler) { + // Persistent host tree mode + var cloneInstance = persistence.cloneInstance, + createContainerChildSet = persistence.createContainerChildSet, + appendChildToContainerChildSet = + persistence.appendChildToContainerChildSet, + finalizeContainerChildren = persistence.finalizeContainerChildren; + + // An unfortunate fork of appendAllChildren because we have two different parent types. + + var appendAllChildrenToContainer = function( + containerChildSet, + workInProgress + ) { + // 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) { + appendChildToContainerChildSet(containerChildSet, 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) { + 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); + portalOrRoot.pendingChildren = newChildSet; + // Schedule an update on the container to swap out the container. + markUpdate(workInProgress); + finalizeContainerChildren(container, newChildSet); + } + }; + updateHostComponent = function( + current, + workInProgress, + updatePayload, + type, + oldProps, + newProps, + rootContainerInstance, + currentHostContext + ) { + // 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; + var currentInstance = current.stateNode; + if (childrenUnchanged && updatePayload === null) { + // No changes, just reuse the existing instance. + // Note that this might release a previous clone. + workInProgress.stateNode = currentInstance; + } else { + var recyclableInstance = workInProgress.stateNode; + 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); + } + } + }; + updateHostText = 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 { + invariant(false, "Persistent reconciler is disabled."); + } + } else { + if (enableNoopReconciler) { + // No host operations + updateHostContainer = function(workInProgress) { + // Noop + }; + updateHostComponent = function( + current, + workInProgress, + updatePayload, + type, + oldProps, + newProps, + rootContainerInstance, + currentHostContext + ) { + // Noop + }; + updateHostText = function(current, workInProgress, oldText, newText) { + // Noop + }; + } else { + invariant(false, "Noop reconciler is disabled."); + } + } + + function completeWork(current, workInProgress, renderExpirationTime) { + var newProps = workInProgress.pendingProps; + switch (workInProgress.tag) { + case FunctionalComponent: + return null; + case ClassComponent: { + // We are leaving this subtree, so pop context if any. + popLegacyContextProvider(workInProgress); + + // If this component caught an error, schedule an error log effect. + var instance = workInProgress.stateNode; + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null && updateQueue.capturedValues !== null) { + workInProgress.effectTag &= ~DidCapture; + if (typeof instance.componentDidCatch === "function") { + workInProgress.effectTag |= ErrLog; + } else { + // Normally we clear this in the commit phase, but since we did not + // schedule an effect, we need to reset it here. + updateQueue.capturedValues = null; + } + } + return null; + } + case HostRoot: { + popHostContainer(workInProgress); + popTopLevelLegacyContextObject(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); + + var _updateQueue = workInProgress.updateQueue; + if (_updateQueue !== null && _updateQueue.capturedValues !== null) { + workInProgress.effectTag |= ErrLog; + } + return null; + } + case HostComponent: { + popHostContext(workInProgress); + var rootContainerInstance = getRootHostContainer(); + var type = workInProgress.type; + if (current !== null && workInProgress.stateNode != null) { + // 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 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 + ); + + updateHostComponent( + current, + workInProgress, + updatePayload, + type, + oldProps, + newProps, + rootContainerInstance, + currentHostContext + ); + + if (current.ref !== workInProgress.ref) { + markRef(workInProgress); + } + } else { + if (!newProps) { + invariant( + workInProgress.stateNode !== null, + "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. + return null; + } + + 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 _instance2 = createInstance( + type, + newProps, + rootContainerInstance, + _currentHostContext, + workInProgress + ); + + appendAllChildren(_instance2, workInProgress); + + // 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( + _instance2, + type, + newProps, + rootContainerInstance, + _currentHostContext + ) + ) { + markUpdate(workInProgress); + } + workInProgress.stateNode = _instance2; + } + + if (workInProgress.ref !== null) { + // If there is a ref on a host node we need to schedule a callback + markRef(workInProgress); + } + } + return null; + } + 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(current, workInProgress, oldText, newText); + } else { + if (typeof newText !== "string") { + invariant( + workInProgress.stateNode !== null, + "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. + return null; + } + var _rootContainerInstance = getRootHostContainer(); + var _currentHostContext2 = getHostContext(); + var _wasHydrated = popHydrationState(workInProgress); + if (_wasHydrated) { + if (prepareToHydrateHostTextInstance(workInProgress)) { + markUpdate(workInProgress); + } + } else { + workInProgress.stateNode = createTextInstance( + newText, + _rootContainerInstance, + _currentHostContext2, + workInProgress + ); + } + } + return null; + } + case CallComponent: + return moveCallToHandlerPhase( + current, + workInProgress, + renderExpirationTime + ); + case CallHandlerPhase: + // Reset the tag to now be a first phase call. + workInProgress.tag = CallComponent; + return null; + case ReturnComponent: + // Does nothing. + return null; + case ForwardRef: + return null; + case Fragment: + return null; + case Mode: + return null; + case HostPortal: + popHostContainer(workInProgress); + updateHostContainer(workInProgress); + return null; + case ContextProvider: + // Pop provider fiber + popProvider(workInProgress); + return null; + case ContextConsumer: + return null; + // Error cases + case IndeterminateComponent: + invariant( + false, + "An indeterminate component should have become determinate before " + + "completing. This error is likely caused by a bug in React. Please " + + "file an issue." + ); + // eslint-disable-next-line no-fallthrough + default: + invariant( + false, + "Unknown unit of work tag. This error is likely caused by a bug in " + + "React. Please file an issue." + ); + } + } + + return { + completeWork: completeWork + }; +}; + +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: getStackAddendumByWorkInProgressFiber(source) + }; +} + +var ReactFiberUnwindWork = function( + hostContext, + legacyContext, + newContext, + scheduleWork, + isAlreadyFailedLegacyErrorBoundary +) { + var popHostContainer = hostContext.popHostContainer, + popHostContext = hostContext.popHostContext; + var popLegacyContextProvider = legacyContext.popContextProvider, + popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject; + var popProvider = newContext.popProvider; + + function throwException(returnFiber, sourceFiber, rawValue) { + // The source fiber did not complete. + sourceFiber.effectTag |= Incomplete; + // Its effect list is no longer valid. + sourceFiber.firstEffect = sourceFiber.lastEffect = null; + + var value = createCapturedValue(rawValue, sourceFiber); + + var workInProgress = returnFiber; + do { + switch (workInProgress.tag) { + case HostRoot: { + // Uncaught error + var errorInfo = value; + ensureUpdateQueues(workInProgress); + var updateQueue = workInProgress.updateQueue; + updateQueue.capturedValues = [errorInfo]; + workInProgress.effectTag |= ShouldCapture; + return; + } + case ClassComponent: + // Capture and retry + var ctor = workInProgress.type; + var _instance = workInProgress.stateNode; + if ( + (workInProgress.effectTag & DidCapture) === NoEffect && + ((typeof ctor.getDerivedStateFromCatch === "function" && + enableGetDerivedStateFromCatch) || + (_instance !== null && + typeof _instance.componentDidCatch === "function" && + !isAlreadyFailedLegacyErrorBoundary(_instance))) + ) { + ensureUpdateQueues(workInProgress); + var _updateQueue = workInProgress.updateQueue; + var capturedValues = _updateQueue.capturedValues; + if (capturedValues === null) { + _updateQueue.capturedValues = [value]; + } else { + capturedValues.push(value); + } + workInProgress.effectTag |= ShouldCapture; + return; + } + break; + default: + break; + } + workInProgress = workInProgress["return"]; + } while (workInProgress !== null); + } + + function unwindWork(workInProgress) { + switch (workInProgress.tag) { + case ClassComponent: { + popLegacyContextProvider(workInProgress); + var effectTag = workInProgress.effectTag; + if (effectTag & ShouldCapture) { + workInProgress.effectTag = (effectTag & ~ShouldCapture) | DidCapture; + return workInProgress; + } + return null; + } + case HostRoot: { + popHostContainer(workInProgress); + popTopLevelLegacyContextObject(workInProgress); + var _effectTag = workInProgress.effectTag; + if (_effectTag & ShouldCapture) { + workInProgress.effectTag = (_effectTag & ~ShouldCapture) | DidCapture; + return workInProgress; + } + return null; + } + case HostComponent: { + popHostContext(workInProgress); + return null; + } + case HostPortal: + popHostContainer(workInProgress); + return null; + case ContextProvider: + popProvider(workInProgress); + return null; + default: + return null; + } + } + + function unwindInterruptedWork(interruptedWork) { + switch (interruptedWork.tag) { + case ClassComponent: { + popLegacyContextProvider(interruptedWork); + break; + } + case HostRoot: { + popHostContainer(interruptedWork); + popTopLevelLegacyContextObject(interruptedWork); + break; + } + case HostComponent: { + popHostContext(interruptedWork); + break; + } + case HostPortal: + popHostContainer(interruptedWork); + break; + case ContextProvider: + popProvider(interruptedWork); + break; + default: + break; + } + } + + return { + throwException: throwException, + unwindWork: unwindWork, + unwindInterruptedWork: unwindInterruptedWork + }; +}; + +// 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); + } + + 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 suppressLogging = error && error.suppressReactErrorLogging; + if (suppressLogging) { + return; + } + + { + var componentName = capturedError.componentName, + componentStack = capturedError.componentStack, + errorBoundaryName = capturedError.errorBoundaryName, + errorBoundaryFound = capturedError.errorBoundaryFound, + willRetry = capturedError.willRetry; + + 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 invokeGuardedCallback$3 = ReactErrorUtils.invokeGuardedCallback; +var hasCaughtError$1 = ReactErrorUtils.hasCaughtError; +var clearCaughtError$1 = ReactErrorUtils.clearCaughtError; + +var didWarnAboutUndefinedSnapshotBeforeUpdate = null; +{ + didWarnAboutUndefinedSnapshotBeforeUpdate = new Set(); +} + +function logError(boundary, errorInfo) { + var source = errorInfo.source; + var stack = errorInfo.stack; + if (stack === null) { + stack = getStackAddendumByWorkInProgressFiber(source); + } + + var capturedError = { + componentName: source !== null ? getComponentName(source) : 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); + capturedError.errorBoundaryFound = true; + capturedError.willRetry = true; + } + + try { + logCapturedError(capturedError); + } catch (e) { + // Prevent cycle if logCapturedError() throws. + // A cycle may still occur if logCapturedError renders a component that throws. + var suppressLogging = e && e.suppressReactErrorLogging; + if (!suppressLogging) { + console.error(e); + } + } +} + +var ReactFiberCommitWork = function( + config, + captureError, + scheduleWork, + computeExpirationForFiber, + markLegacyErrorBoundaryAsFailed, + recalculateCurrentTime +) { + var getPublicInstance = config.getPublicInstance, + mutation = config.mutation, + persistence = config.persistence; + + var callComponentWillUnmountWithTimer = function(current, instance) { + startPhaseTimer(current, "componentWillUnmount"); + instance.props = current.memoizedProps; + instance.state = current.memoizedState; + instance.componentWillUnmount(); + stopPhaseTimer(); + }; + + // Capture errors so they don't interrupt unmounting. + function safelyCallComponentWillUnmount(current, instance) { + { + invokeGuardedCallback$3( + null, + callComponentWillUnmountWithTimer, + null, + current, + instance + ); + if (hasCaughtError$1()) { + var unmountError = clearCaughtError$1(); + captureError(current, unmountError); + } + } + } + + function safelyDetachRef(current) { + var ref = current.ref; + if (ref !== null) { + if (typeof ref === "function") { + { + invokeGuardedCallback$3(null, ref, null, null); + if (hasCaughtError$1()) { + var refError = clearCaughtError$1(); + captureError(current, refError); + } + } + } else { + ref.current = null; + } + } + } + + function commitBeforeMutationLifeCycles(current, finishedWork) { + switch (finishedWork.tag) { + case ClassComponent: { + if (finishedWork.effectTag & Snapshot) { + if (current !== null) { + var prevProps = current.memoizedProps; + var prevState = current.memoizedState; + startPhaseTimer(finishedWork, "getSnapshotBeforeUpdate"); + var _instance = finishedWork.stateNode; + _instance.props = finishedWork.memoizedProps; + _instance.state = finishedWork.memoizedState; + var snapshot = _instance.getSnapshotBeforeUpdate( + prevProps, + prevState + ); + { + var didWarnSet = didWarnAboutUndefinedSnapshotBeforeUpdate; + if ( + snapshot === undefined && + !didWarnSet.has(finishedWork.type) + ) { + didWarnSet.add(finishedWork.type); + warning( + false, + "%s.getSnapshotBeforeUpdate(): A snapshot value (or null) " + + "must be returned. You have returned undefined.", + getComponentName(finishedWork) + ); + } + } + _instance.__reactInternalSnapshotBeforeUpdate = snapshot; + stopPhaseTimer(); + } + } + return; + } + case HostRoot: + case HostComponent: + case HostText: + case HostPortal: + // Nothing to do for these component types + return; + default: { + invariant( + false, + "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 commitLifeCycles( + finishedRoot, + current, + finishedWork, + currentTime, + committedExpirationTime + ) { + switch (finishedWork.tag) { + case ClassComponent: { + var _instance2 = finishedWork.stateNode; + if (finishedWork.effectTag & Update) { + if (current === null) { + startPhaseTimer(finishedWork, "componentDidMount"); + _instance2.props = finishedWork.memoizedProps; + _instance2.state = finishedWork.memoizedState; + _instance2.componentDidMount(); + stopPhaseTimer(); + } else { + var prevProps = current.memoizedProps; + var prevState = current.memoizedState; + startPhaseTimer(finishedWork, "componentDidUpdate"); + _instance2.props = finishedWork.memoizedProps; + _instance2.state = finishedWork.memoizedState; + _instance2.componentDidUpdate( + prevProps, + prevState, + _instance2.__reactInternalSnapshotBeforeUpdate + ); + stopPhaseTimer(); + } + } + var updateQueue = finishedWork.updateQueue; + if (updateQueue !== null) { + commitCallbacks(updateQueue, _instance2); + } + return; + } + case HostRoot: { + var _updateQueue = finishedWork.updateQueue; + if (_updateQueue !== null) { + var _instance3 = null; + if (finishedWork.child !== null) { + switch (finishedWork.child.tag) { + case HostComponent: + _instance3 = getPublicInstance(finishedWork.child.stateNode); + break; + case ClassComponent: + _instance3 = finishedWork.child.stateNode; + break; + } + } + commitCallbacks(_updateQueue, _instance3); + } + return; + } + case HostComponent: { + var _instance4 = 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 === null && finishedWork.effectTag & Update) { + var type = finishedWork.type; + var props = finishedWork.memoizedProps; + commitMount(_instance4, 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; + } + default: { + invariant( + false, + "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 commitErrorLogging(finishedWork, onUncaughtError) { + switch (finishedWork.tag) { + case ClassComponent: + { + var ctor = finishedWork.type; + var _instance5 = finishedWork.stateNode; + var updateQueue = finishedWork.updateQueue; + invariant( + updateQueue !== null && updateQueue.capturedValues !== null, + "An error logging effect should not have been scheduled if no errors " + + "were captured. This error is likely caused by a bug in React. " + + "Please file an issue." + ); + var capturedErrors = updateQueue.capturedValues; + updateQueue.capturedValues = null; + + if (typeof ctor.getDerivedStateFromCatch !== "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 getDerivedStateFromCatch is + // not defined. + markLegacyErrorBoundaryAsFailed(_instance5); + } + + _instance5.props = finishedWork.memoizedProps; + _instance5.state = finishedWork.memoizedState; + for (var i = 0; i < capturedErrors.length; i++) { + var errorInfo = capturedErrors[i]; + var _error = errorInfo.value; + var stack = errorInfo.stack; + logError(finishedWork, errorInfo); + _instance5.componentDidCatch(_error, { + componentStack: stack !== null ? stack : "" + }); + } + } + break; + case HostRoot: { + var _updateQueue2 = finishedWork.updateQueue; + invariant( + _updateQueue2 !== null && _updateQueue2.capturedValues !== null, + "An error logging effect should not have been scheduled if no errors " + + "were captured. This error is likely caused by a bug in React. " + + "Please file an issue." + ); + var _capturedErrors = _updateQueue2.capturedValues; + _updateQueue2.capturedValues = null; + for (var _i = 0; _i < _capturedErrors.length; _i++) { + var _errorInfo = _capturedErrors[_i]; + logError(finishedWork, _errorInfo); + onUncaughtError(_errorInfo.value); + } + break; + } + default: + invariant( + false, + "This unit of work tag cannot capture errors. This error is " + + "likely caused by a bug in React. Please file an issue." + ); + } + } + + function commitAttachRef(finishedWork) { + var ref = finishedWork.ref; + if (ref !== null) { + var _instance6 = finishedWork.stateNode; + var instanceToUse = void 0; + switch (finishedWork.tag) { + case HostComponent: + instanceToUse = getPublicInstance(_instance6); + break; + default: + instanceToUse = _instance6; + } + if (typeof ref === "function") { + ref(instanceToUse); + } else { + { + if (!ref.hasOwnProperty("current")) { + warning( + false, + "Unexpected ref object provided for %s. " + + "Use either a ref-setter function or React.createRef().%s", + getComponentName(finishedWork), + getStackAddendumByWorkInProgressFiber(finishedWork) + ); + } + } + + ref.current = instanceToUse; + } + } + } + + function commitDetachRef(current) { + var currentRef = current.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) { + if (typeof onCommitUnmount === "function") { + onCommitUnmount(current); + } + + switch (current.tag) { + case ClassComponent: { + safelyDetachRef(current); + var _instance7 = current.stateNode; + if (typeof _instance7.componentWillUnmount === "function") { + safelyCallComponentWillUnmount(current, _instance7); + } + return; + } + case HostComponent: { + safelyDetachRef(current); + return; + } + case CallComponent: { + commitNestedUnmounts(current.stateNode); + return; + } + case HostPortal: { + // TODO: this is recursive. + // We are also not using this parent because + // the portal will get pushed immediately. + if (enableMutatingReconciler && mutation) { + unmountHostComponents(current); + } else if (enablePersistentReconciler && persistence) { + emptyPortalContainer(current); + } + return; + } + } + } + + 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. + (!mutation || 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) { + // 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["return"] = null; + current.child = null; + if (current.alternate) { + current.alternate.child = null; + current.alternate["return"] = null; + } + } + + var emptyPortalContainer = void 0; + + if (!mutation) { + var commitContainer = void 0; + if (persistence) { + var replaceContainerChildren = persistence.replaceContainerChildren, + createContainerChildSet = persistence.createContainerChildSet; + + emptyPortalContainer = function(current) { + var portal = current.stateNode; + var containerInfo = portal.containerInfo; + + var emptyChildSet = createContainerChildSet(containerInfo); + replaceContainerChildren(containerInfo, emptyChildSet); + }; + commitContainer = function(finishedWork) { + switch (finishedWork.tag) { + case ClassComponent: { + return; + } + case HostComponent: { + return; + } + case HostText: { + return; + } + case HostRoot: + case HostPortal: { + var portalOrRoot = finishedWork.stateNode; + var containerInfo = portalOrRoot.containerInfo, + _pendingChildren = portalOrRoot.pendingChildren; + + replaceContainerChildren(containerInfo, _pendingChildren); + return; + } + default: { + invariant( + false, + "This unit of work tag should not have side-effects. This error is " + + "likely caused by a bug in React. Please file an issue." + ); + } + } + }; + } else { + commitContainer = function(finishedWork) { + // Noop + }; + } + if (enablePersistentReconciler || enableNoopReconciler) { + return { + commitResetTextContent: function(finishedWork) {}, + commitPlacement: function(finishedWork) {}, + commitDeletion: function(current) { + // Detach refs and call componentWillUnmount() on the whole subtree. + commitNestedUnmounts(current); + detachFiber(current); + }, + commitWork: function(current, finishedWork) { + commitContainer(finishedWork); + }, + + commitLifeCycles: commitLifeCycles, + commitBeforeMutationLifeCycles: commitBeforeMutationLifeCycles, + commitErrorLogging: commitErrorLogging, + commitAttachRef: commitAttachRef, + commitDetachRef: commitDetachRef + }; + } else if (persistence) { + invariant(false, "Persistent reconciler is disabled."); + } else { + invariant(false, "Noop reconciler is disabled."); + } + } + var commitMount = mutation.commitMount, + commitUpdate = mutation.commitUpdate, + resetTextContent = mutation.resetTextContent, + commitTextUpdate = mutation.commitTextUpdate, + appendChild = mutation.appendChild, + appendChildToContainer = mutation.appendChildToContainer, + insertBefore = mutation.insertBefore, + insertInContainerBefore = mutation.insertInContainerBefore, + removeChild = mutation.removeChild, + removeChildFromContainer = mutation.removeChildFromContainer; + + function getHostParentFiber(fiber) { + var parent = fiber["return"]; + while (parent !== null) { + if (isHostParent(parent)) { + return parent; + } + parent = parent["return"]; + } + invariant( + false, + "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) { + // 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) { + // Recursively insert all host nodes into the parent. + var parentFiber = getHostParentFiber(finishedWork); + 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: + invariant( + false, + "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 recurse down its + // children to find all the terminal nodes. + var node = finishedWork; + while (true) { + if (node.tag === HostComponent || node.tag === HostText) { + if (before) { + if (isContainer) { + insertInContainerBefore(parent, node.stateNode, before); + } else { + insertBefore(parent, node.stateNode, before); + } + } else { + if (isContainer) { + appendChildToContainer(parent, node.stateNode); + } else { + appendChild(parent, node.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) { + // We only have the top Fiber that was inserted but we need recurse down its + var node = current; + + // Each iteration, currentParent is populated with node's host parent if not + // currentParentIsValid. + var currentParentIsValid = false; + var currentParent = void 0; + var currentParentIsContainer = void 0; + + while (true) { + if (!currentParentIsValid) { + var parent = node["return"]; + findParent: while (true) { + invariant( + parent !== null, + "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 (node.tag === HostPortal) { + // 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; + // Visit children because portals might contain host components. + if (node.child !== null) { + 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) { + return; + } + while (node.sibling === null) { + if (node["return"] === null || node["return"] === current) { + 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) { + // Recursively delete all host nodes from the parent. + // Detach refs and call componentWillUnmount() on the whole subtree. + unmountHostComponents(current); + detachFiber(current); + } + + function commitWork(current, finishedWork) { + switch (finishedWork.tag) { + case ClassComponent: { + return; + } + case HostComponent: { + var _instance8 = finishedWork.stateNode; + if (_instance8 != 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 !== null ? current.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( + _instance8, + updatePayload, + type, + oldProps, + newProps, + finishedWork + ); + } + } + return; + } + case HostText: { + invariant( + finishedWork.stateNode !== null, + "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 !== null ? current.memoizedProps : newText; + commitTextUpdate(textInstance, oldText, newText); + return; + } + case HostRoot: { + return; + } + default: { + invariant( + false, + "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 commitResetTextContent(current) { + resetTextContent(current.stateNode); + } + + if (enableMutatingReconciler) { + return { + commitBeforeMutationLifeCycles: commitBeforeMutationLifeCycles, + commitResetTextContent: commitResetTextContent, + commitPlacement: commitPlacement, + commitDeletion: commitDeletion, + commitWork: commitWork, + commitLifeCycles: commitLifeCycles, + commitErrorLogging: commitErrorLogging, + commitAttachRef: commitAttachRef, + commitDetachRef: commitDetachRef + }; + } else { + invariant(false, "Mutating reconciler is disabled."); + } +}; + +var NO_CONTEXT = {}; + +var ReactFiberHostContext = function(config, stack) { + var getChildHostContext = config.getChildHostContext, + getRootHostContext = config.getRootHostContext; + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop; + + var contextStackCursor = createCursor(NO_CONTEXT); + var contextFiberStackCursor = createCursor(NO_CONTEXT); + var rootInstanceStackCursor = createCursor(NO_CONTEXT); + + function requiredContext(c) { + invariant( + c !== NO_CONTEXT, + "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, NO_CONTEXT, fiber); + var nextRootContext = getRootHostContext(nextRootInstance); + // Now that we know this function doesn't throw, replace it. + pop(contextStackCursor, fiber); + push(contextStackCursor, nextRootContext, fiber); + } + + function popHostContainer(fiber) { + pop(contextStackCursor, fiber); + pop(contextFiberStackCursor, fiber); + pop(rootInstanceStackCursor, fiber); + } + + function getHostContext() { + var context = requiredContext(contextStackCursor.current); + return context; + } + + function pushHostContext(fiber) { + var rootInstance = requiredContext(rootInstanceStackCursor.current); + var context = requiredContext(contextStackCursor.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, 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, fiber); + pop(contextFiberStackCursor, fiber); + } + + return { + getHostContext: getHostContext, + getRootHostContainer: getRootHostContainer, + popHostContainer: popHostContainer, + popHostContext: popHostContext, + pushHostContainer: pushHostContainer, + pushHostContext: pushHostContext + }; +}; + +var ReactFiberHydrationContext = function(config) { + var shouldSetTextContent = config.shouldSetTextContent, + hydration = config.hydration; + + // If this doesn't have hydration mode. + + if (!hydration) { + return { + enterHydrationState: function() { + return false; + }, + resetHydrationState: function() {}, + tryToClaimNextHydratableInstance: function() {}, + prepareToHydrateHostInstance: function() { + invariant( + false, + "Expected prepareToHydrateHostInstance() to never be called. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + }, + prepareToHydrateHostTextInstance: function() { + invariant( + false, + "Expected prepareToHydrateHostTextInstance() to never be called. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + }, + popHydrationState: function(fiber) { + return false; + } + }; + } + + var canHydrateInstance = hydration.canHydrateInstance, + canHydrateTextInstance = hydration.canHydrateTextInstance, + getNextHydratableSibling = hydration.getNextHydratableSibling, + getFirstHydratableChild = hydration.getFirstHydratableChild, + hydrateInstance = hydration.hydrateInstance, + hydrateTextInstance = hydration.hydrateTextInstance, + didNotMatchHydratedContainerTextInstance = + hydration.didNotMatchHydratedContainerTextInstance, + didNotMatchHydratedTextInstance = hydration.didNotMatchHydratedTextInstance, + didNotHydrateContainerInstance = hydration.didNotHydrateContainerInstance, + didNotHydrateInstance = hydration.didNotHydrateInstance, + didNotFindHydratableContainerInstance = + hydration.didNotFindHydratableContainerInstance, + didNotFindHydratableContainerTextInstance = + hydration.didNotFindHydratableContainerTextInstance, + didNotFindHydratableInstance = hydration.didNotFindHydratableInstance, + didNotFindHydratableTextInstance = + hydration.didNotFindHydratableTextInstance; + + // 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) { + var parentInstance = fiber.stateNode.containerInfo; + nextHydratableInstance = getFirstHydratableChild(parentInstance); + hydrationParentFiber = 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; + } + 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; + } + 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; + } + 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; + } + 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(nextInstance); + 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, nextHydratableInstance); + } + hydrationParentFiber = fiber; + nextHydratableInstance = getFirstHydratableChild(nextInstance); + } + + function prepareToHydrateHostInstance( + fiber, + rootContainerInstance, + hostContext + ) { + 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) { + 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 popToNextHostParent(fiber) { + var parent = fiber["return"]; + while ( + parent !== null && + parent.tag !== HostComponent && + parent.tag !== HostRoot + ) { + parent = parent["return"]; + } + hydrationParentFiber = parent; + } + + function popHydrationState(fiber) { + 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() { + hydrationParentFiber = null; + nextHydratableInstance = null; + isHydrating = false; + } + + return { + enterHydrationState: enterHydrationState, + resetHydrationState: resetHydrationState, + tryToClaimNextHydratableInstance: tryToClaimNextHydratableInstance, + prepareToHydrateHostInstance: prepareToHydrateHostInstance, + prepareToHydrateHostTextInstance: prepareToHydrateHostTextInstance, + popHydrationState: popHydrationState + }; +}; + +// 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; + +var warnedAboutMissingGetChildContext = void 0; + +{ + warnedAboutMissingGetChildContext = {}; +} + +var ReactFiberLegacyContext = function(stack) { + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop; + + // A cursor to the current merged context object on the stack. + + var contextStackCursor = createCursor(emptyObject); + // 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 = emptyObject; + + function getUnmaskedContext(workInProgress) { + var hasOwnContext = isContextProvider(workInProgress); + if (hasOwnContext) { + // If the fiber is a context provider itself, when we read its context + // we 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 emptyObject; + } + + // 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(workInProgress) || "Unknown"; + checkPropTypes( + contextTypes, + context, + "context", + name, + ReactDebugCurrentFiber.getCurrentFiberStackAddendum + ); + } + + // 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 isContextConsumer(fiber) { + return fiber.tag === ClassComponent && fiber.type.contextTypes != null; + } + + function isContextProvider(fiber) { + return fiber.tag === ClassComponent && fiber.type.childContextTypes != null; + } + + function popContextProvider(fiber) { + if (!isContextProvider(fiber)) { + return; + } + + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); + } + + function popTopLevelContextObject(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); + } + + function pushTopLevelContextObject(fiber, context, didChange) { + invariant( + contextStackCursor.cursor == null, + "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, parentContext) { + var instance = fiber.stateNode; + var childContextTypes = fiber.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(fiber) || "Unknown"; + + if (!warnedAboutMissingGetChildContext[componentName]) { + warnedAboutMissingGetChildContext[componentName] = true; + warning( + 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; + { + ReactDebugCurrentFiber.setCurrentPhase("getChildContext"); + } + startPhaseTimer(fiber, "getChildContext"); + childContext = instance.getChildContext(); + stopPhaseTimer(); + { + ReactDebugCurrentFiber.setCurrentPhase(null); + } + for (var contextKey in childContext) { + invariant( + contextKey in childContextTypes, + '%s.getChildContext(): key "%s" is not defined in childContextTypes.', + getComponentName(fiber) || "Unknown", + contextKey + ); + } + { + var name = getComponentName(fiber) || "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. + ReactDebugCurrentFiber.getCurrentFiberStackAddendum + ); + } + + return Object.assign({}, parentContext, childContext); + } + + function pushContextProvider(workInProgress) { + if (!isContextProvider(workInProgress)) { + return false; + } + + 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) || + emptyObject; + + // 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, didChange) { + var instance = workInProgress.stateNode; + invariant( + instance, + "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, 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 + invariant( + isFiberMounted(fiber) && fiber.tag === ClassComponent, + "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; + while (node.tag !== HostRoot) { + if (isContextProvider(node)) { + return node.stateNode.__reactInternalMemoizedMergedChildContext; + } + var parent = node["return"]; + invariant( + parent, + "Found unexpected detached subtree parent. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + node = parent; + } + return node.stateNode.context; + } + + return { + getUnmaskedContext: getUnmaskedContext, + cacheContext: cacheContext, + getMaskedContext: getMaskedContext, + hasContextChanged: hasContextChanged, + isContextConsumer: isContextConsumer, + isContextProvider: isContextProvider, + popContextProvider: popContextProvider, + popTopLevelContextObject: popTopLevelContextObject, + pushTopLevelContextObject: pushTopLevelContextObject, + processChildContext: processChildContext, + pushContextProvider: pushContextProvider, + invalidateContextProvider: invalidateContextProvider, + findCurrentUnmaskedContext: findCurrentUnmaskedContext + }; +}; + +var ReactFiberNewContext = function(stack) { + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop; + + var providerCursor = createCursor(null); + var valueCursor = createCursor(null); + var changedBitsCursor = createCursor(0); + + var rendererSigil = void 0; + { + // Use this to detect multiple renderers using the same context + rendererSigil = {}; + } + + function pushProvider(providerFiber) { + var context = providerFiber.type._context; + + push(changedBitsCursor, context._changedBits, providerFiber); + push(valueCursor, context._currentValue, providerFiber); + push(providerCursor, providerFiber, providerFiber); + + context._currentValue = providerFiber.pendingProps.value; + context._changedBits = providerFiber.stateNode; + + { + !( + context._currentRenderer === null || + context._currentRenderer === rendererSigil + ) + ? warning( + false, + "Detected multiple renderers concurrently rendering the " + + "same context provider. This is currently unsupported." + ) + : void 0; + context._currentRenderer = rendererSigil; + } + } + + function popProvider(providerFiber) { + var changedBits = changedBitsCursor.current; + var currentValue = valueCursor.current; + + pop(providerCursor, providerFiber); + pop(valueCursor, providerFiber); + pop(changedBitsCursor, providerFiber); + + var context = providerFiber.type._context; + context._currentValue = currentValue; + context._changedBits = changedBits; + } + + return { + pushProvider: pushProvider, + popProvider: popProvider + }; +}; + +var ReactFiberStack = function() { + var valueStack = []; + + var fiberStack = void 0; + + { + fiberStack = []; + } + + var index = -1; + + function createCursor(defaultValue) { + return { + current: defaultValue + }; + } + + function isEmpty() { + return index === -1; + } + + function pop(cursor, fiber) { + if (index < 0) { + { + warning(false, "Unexpected pop."); + } + return; + } + + { + if (fiber !== fiberStack[index]) { + warning(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; + } + + function checkThatStackIsEmpty() { + { + if (index !== -1) { + warning( + false, + "Expected an empty stack. Something was not reset properly." + ); + } + } + } + + function resetStackAfterFatalErrorInDev() { + { + index = -1; + valueStack.length = 0; + fiberStack.length = 0; + } + } + + return { + createCursor: createCursor, + isEmpty: isEmpty, + pop: pop, + push: push, + checkThatStackIsEmpty: checkThatStackIsEmpty, + resetStackAfterFatalErrorInDev: resetStackAfterFatalErrorInDev + }; +}; + +var invokeGuardedCallback$2 = ReactErrorUtils.invokeGuardedCallback; +var hasCaughtError = ReactErrorUtils.hasCaughtError; +var clearCaughtError = ReactErrorUtils.clearCaughtError; + +var didWarnAboutStateTransition = void 0; +var didWarnSetStateChildContext = void 0; +var warnAboutUpdateOnUnmounted = void 0; +var warnAboutInvalidUpdates = void 0; + +{ + didWarnAboutStateTransition = false; + didWarnSetStateChildContext = false; + var didWarnStateUpdateForUnmountedComponent = {}; + + warnAboutUpdateOnUnmounted = function(fiber) { + // 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) || "ReactClass"; + if (didWarnStateUpdateForUnmountedComponent[componentName]) { + return; + } + warning( + false, + "Can't call setState (or forceUpdate) 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 the " + + "componentWillUnmount method.%s", + getStackAddendumByWorkInProgressFiber(fiber) + ); + didWarnStateUpdateForUnmountedComponent[componentName] = true; + }; + + warnAboutInvalidUpdates = function(instance) { + switch (ReactDebugCurrentFiber.phase) { + case "getChildContext": + if (didWarnSetStateChildContext) { + return; + } + warning( + false, + "setState(...): Cannot call setState() inside getChildContext()" + ); + didWarnSetStateChildContext = true; + break; + case "render": + if (didWarnAboutStateTransition) { + return; + } + warning( + false, + "Cannot update during an existing state transition (such as within " + + "`render` or another component's constructor). Render methods should " + + "be a pure function of props and state; constructor side-effects are " + + "an anti-pattern, but can be moved to `componentWillMount`." + ); + didWarnAboutStateTransition = true; + break; + } + }; +} + +var ReactFiberScheduler = function(config) { + var stack = ReactFiberStack(); + var hostContext = ReactFiberHostContext(config, stack); + var legacyContext = ReactFiberLegacyContext(stack); + var newContext = ReactFiberNewContext(stack); + var popHostContext = hostContext.popHostContext, + popHostContainer = hostContext.popHostContainer; + var popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject, + popLegacyContextProvider = legacyContext.popContextProvider; + var popProvider = newContext.popProvider; + + var hydrationContext = ReactFiberHydrationContext(config); + + var _ReactFiberBeginWork = ReactFiberBeginWork( + config, + hostContext, + legacyContext, + newContext, + hydrationContext, + scheduleWork, + computeExpirationForFiber + ), + beginWork = _ReactFiberBeginWork.beginWork; + + var _ReactFiberCompleteWo = ReactFiberCompleteWork( + config, + hostContext, + legacyContext, + newContext, + hydrationContext + ), + completeWork = _ReactFiberCompleteWo.completeWork; + + var _ReactFiberUnwindWork = ReactFiberUnwindWork( + hostContext, + legacyContext, + newContext, + scheduleWork, + isAlreadyFailedLegacyErrorBoundary + ), + throwException = _ReactFiberUnwindWork.throwException, + unwindWork = _ReactFiberUnwindWork.unwindWork, + unwindInterruptedWork = _ReactFiberUnwindWork.unwindInterruptedWork; + + var _ReactFiberCommitWork = ReactFiberCommitWork( + config, + onCommitPhaseError, + scheduleWork, + computeExpirationForFiber, + markLegacyErrorBoundaryAsFailed, + recalculateCurrentTime + ), + commitBeforeMutationLifeCycles = + _ReactFiberCommitWork.commitBeforeMutationLifeCycles, + commitResetTextContent = _ReactFiberCommitWork.commitResetTextContent, + commitPlacement = _ReactFiberCommitWork.commitPlacement, + commitDeletion = _ReactFiberCommitWork.commitDeletion, + commitWork = _ReactFiberCommitWork.commitWork, + commitLifeCycles = _ReactFiberCommitWork.commitLifeCycles, + commitErrorLogging = _ReactFiberCommitWork.commitErrorLogging, + commitAttachRef = _ReactFiberCommitWork.commitAttachRef, + commitDetachRef = _ReactFiberCommitWork.commitDetachRef; + + var now = config.now, + scheduleDeferredCallback = config.scheduleDeferredCallback, + cancelDeferredCallback = config.cancelDeferredCallback, + prepareForCommit = config.prepareForCommit, + resetAfterCommit = config.resetAfterCommit; + + // Represents the current time in ms. + + var originalStartTimeMs = now(); + var mostRecentCurrentTime = msToExpirationTime(0); + var mostRecentCurrentTimeMs = originalStartTimeMs; + + // Used to ensure computeUniqueAsyncExpiration is monotonically increases. + var lastUniqueAsyncExpiration = 0; + + // Represents the expiration time that incoming updates should use. (If this + // is NoWork, use the default strategy: async updates in async mode, sync + // updates in sync mode.) + var expirationContext = NoWork; + + var isWorking = false; + + // The next work in progress fiber that we're currently working on. + var nextUnitOfWork = null; + var nextRoot = null; + // The time at which we're currently rendering work. + var nextRenderExpirationTime = NoWork; + + // The next fiber with an effect that we're currently committing. + var nextEffect = null; + + var isCommitting = false; + + var isRootReadyForCommit = false; + + var legacyErrorBoundariesThatAlreadyFailed = null; + + // Used for performance tracking. + var interruptedBy = null; + + var stashedWorkInProgressProperties = void 0; + var replayUnitOfWork = void 0; + var isReplayingFailedUnitOfWork = void 0; + var originalReplayError = void 0; + var rethrowOriginalError = void 0; + if (true && replayFailedUnitOfWorkWithInvokeGuardedCallback) { + stashedWorkInProgressProperties = null; + isReplayingFailedUnitOfWork = false; + originalReplayError = null; + replayUnitOfWork = function(failedUnitOfWork, error, isAsync) { + // Restore the original state of the work-in-progress + assignFiberPropertiesInDEV( + failedUnitOfWork, + stashedWorkInProgressProperties + ); + switch (failedUnitOfWork.tag) { + case HostRoot: + popHostContainer(failedUnitOfWork); + popTopLevelLegacyContextObject(failedUnitOfWork); + break; + case HostComponent: + popHostContext(failedUnitOfWork); + break; + case ClassComponent: + popLegacyContextProvider(failedUnitOfWork); + break; + case HostPortal: + popHostContainer(failedUnitOfWork); + break; + case ContextProvider: + popProvider(failedUnitOfWork); + break; + } + // Replay the begin phase. + isReplayingFailedUnitOfWork = true; + originalReplayError = error; + invokeGuardedCallback$2(null, workLoop, null, isAsync); + isReplayingFailedUnitOfWork = false; + originalReplayError = null; + if (hasCaughtError()) { + clearCaughtError(); + } else { + // If the begin phase did not fail the second time, set this pointer + // back to the original value. + nextUnitOfWork = failedUnitOfWork; + } + }; + rethrowOriginalError = function() { + throw originalReplayError; + }; + } + + function resetStack() { + if (nextUnitOfWork !== null) { + var interruptedWork = nextUnitOfWork["return"]; + while (interruptedWork !== null) { + unwindInterruptedWork(interruptedWork); + interruptedWork = interruptedWork["return"]; + } + } + + { + ReactStrictModeWarnings.discardPendingWarnings(); + stack.checkThatStackIsEmpty(); + } + + nextRoot = null; + nextRenderExpirationTime = NoWork; + nextUnitOfWork = null; + + isRootReadyForCommit = false; + } + + function commitAllHostEffects() { + while (nextEffect !== null) { + { + ReactDebugCurrentFiber.setCurrentFiber(nextEffect); + } + recordEffect(); + + var effectTag = nextEffect.effectTag; + + if (effectTag & ContentReset) { + commitResetTextContent(nextEffect); + } + + if (effectTag & Ref) { + var current = nextEffect.alternate; + if (current !== null) { + commitDetachRef(current); + } + } + + // 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; + } + } + nextEffect = nextEffect.nextEffect; + } + + { + ReactDebugCurrentFiber.resetCurrentFiber(); + } + } + + function commitBeforeMutationLifecycles() { + while (nextEffect !== null) { + var effectTag = nextEffect.effectTag; + + if (effectTag & Snapshot) { + recordEffect(); + var current = nextEffect.alternate; + commitBeforeMutationLifeCycles(current, nextEffect); + } + + // Don't cleanup effects yet; + // This will be done by commitAllLifeCycles() + nextEffect = nextEffect.nextEffect; + } + } + + function commitAllLifeCycles( + finishedRoot, + currentTime, + committedExpirationTime + ) { + { + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings(); + + if (warnAboutDeprecatedLifecycles) { + ReactStrictModeWarnings.flushPendingDeprecationWarnings(); + } + } + while (nextEffect !== null) { + var effectTag = nextEffect.effectTag; + + if (effectTag & (Update | Callback)) { + recordEffect(); + var current = nextEffect.alternate; + commitLifeCycles( + finishedRoot, + current, + nextEffect, + currentTime, + committedExpirationTime + ); + } + + if (effectTag & ErrLog) { + commitErrorLogging(nextEffect, onUncaughtError); + } + + if (effectTag & Ref) { + recordEffect(); + commitAttachRef(nextEffect); + } + + var next = nextEffect.nextEffect; + // Ensure that we clean these up so that we don't accidentally keep them. + // I'm not actually sure this matters because we can't reset firstEffect + // and lastEffect since they're on every node, not just the effectful + // ones. So we have to clean everything as we reuse nodes anyway. + nextEffect.nextEffect = null; + // Ensure that we reset the effectTag here so that we can rely on effect + // tags to reason about the current life-cycle. + nextEffect = next; + } + } + + function isAlreadyFailedLegacyErrorBoundary(instance) { + return ( + legacyErrorBoundariesThatAlreadyFailed !== null && + legacyErrorBoundariesThatAlreadyFailed.has(instance) + ); + } + + function markLegacyErrorBoundaryAsFailed(instance) { + if (legacyErrorBoundariesThatAlreadyFailed === null) { + legacyErrorBoundariesThatAlreadyFailed = new Set([instance]); + } else { + legacyErrorBoundariesThatAlreadyFailed.add(instance); + } + } + + function commitRoot(finishedWork) { + isWorking = true; + isCommitting = true; + startCommitTimer(); + + var root = finishedWork.stateNode; + invariant( + root.current !== finishedWork, + "Cannot commit the same tree as before. This is probably a bug " + + "related to the return field. This error is likely caused by a bug " + + "in React. Please file an issue." + ); + var committedExpirationTime = root.pendingCommitExpirationTime; + invariant( + committedExpirationTime !== NoWork, + "Cannot commit an incomplete root. This error is likely caused by a " + + "bug in React. Please file an issue." + ); + root.pendingCommitExpirationTime = NoWork; + + var currentTime = recalculateCurrentTime(); + + // Reset this to null before calling lifecycles + ReactCurrentOwner.current = null; + + 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; + } + + prepareForCommit(root.containerInfo); + + // Invoke instances of getSnapshotBeforeUpdate before mutation. + nextEffect = firstEffect; + startCommitSnapshotEffectsTimer(); + while (nextEffect !== null) { + var didError = false; + var error = void 0; + { + invokeGuardedCallback$2(null, commitBeforeMutationLifecycles, null); + if (hasCaughtError()) { + didError = true; + error = clearCaughtError(); + } + } + if (didError) { + invariant( + nextEffect !== null, + "Should have next effect. This error is likely caused by a bug " + + "in React. Please file an issue." + ); + onCommitPhaseError(nextEffect, error); + // Clean-up + if (nextEffect !== null) { + nextEffect = nextEffect.nextEffect; + } + } + } + stopCommitSnapshotEffectsTimer(); + + // Commit all the side-effects within a tree. We'll do this in two passes. + // The first pass performs all the host insertions, updates, deletions and + // ref unmounts. + nextEffect = firstEffect; + startCommitHostEffectsTimer(); + while (nextEffect !== null) { + var _didError = false; + var _error = void 0; + { + invokeGuardedCallback$2(null, commitAllHostEffects, null); + if (hasCaughtError()) { + _didError = true; + _error = clearCaughtError(); + } + } + if (_didError) { + invariant( + nextEffect !== null, + "Should have next effect. This error is likely caused by a bug " + + "in React. Please file an issue." + ); + onCommitPhaseError(nextEffect, _error); + // Clean-up + if (nextEffect !== null) { + nextEffect = nextEffect.nextEffect; + } + } + } + stopCommitHostEffectsTimer(); + + resetAfterCommit(root.containerInfo); + + // The work-in-progress tree is now the current tree. This must come after + // the first pass of the commit phase, so that the previous tree is still + // current during componentWillUnmount, but before the second pass, so that + // the finished work is current during componentDidMount/Update. + root.current = finishedWork; + + // In the second pass we'll perform all life-cycles and ref callbacks. + // Life-cycles happen as a separate pass so that all placements, updates, + // and deletions in the entire tree have already been invoked. + // This pass also triggers any renderer-specific initial effects. + nextEffect = firstEffect; + startCommitLifeCyclesTimer(); + while (nextEffect !== null) { + var _didError2 = false; + var _error2 = void 0; + { + invokeGuardedCallback$2( + null, + commitAllLifeCycles, + null, + root, + currentTime, + committedExpirationTime + ); + if (hasCaughtError()) { + _didError2 = true; + _error2 = clearCaughtError(); + } + } + if (_didError2) { + invariant( + nextEffect !== null, + "Should have next effect. This error is likely caused by a bug " + + "in React. Please file an issue." + ); + onCommitPhaseError(nextEffect, _error2); + if (nextEffect !== null) { + nextEffect = nextEffect.nextEffect; + } + } + } + + isCommitting = false; + isWorking = false; + stopCommitLifeCyclesTimer(); + stopCommitTimer(); + if (typeof onCommitRoot === "function") { + onCommitRoot(finishedWork.stateNode); + } + if (true && ReactFiberInstrumentation_1.debugTool) { + ReactFiberInstrumentation_1.debugTool.onCommitWork(finishedWork); + } + + var remainingTime = root.current.expirationTime; + if (remainingTime === NoWork) { + // If there's no remaining work, we can clear the set of already failed + // error boundaries. + legacyErrorBoundariesThatAlreadyFailed = null; + } + return remainingTime; + } + + function resetExpirationTime(workInProgress, renderTime) { + if (renderTime !== Never && workInProgress.expirationTime === Never) { + // The children of this component are hidden. Don't bubble their + // expiration times. + return; + } + + // Check for pending updates. + var newExpirationTime = getUpdateExpirationTime(workInProgress); + + // TODO: Calls need to visit stateNode + + // Bubble up the earliest expiration time. + var child = workInProgress.child; + while (child !== null) { + if ( + child.expirationTime !== NoWork && + (newExpirationTime === NoWork || + newExpirationTime > child.expirationTime) + ) { + newExpirationTime = child.expirationTime; + } + child = child.sibling; + } + workInProgress.expirationTime = newExpirationTime; + } + + function completeUnitOfWork(workInProgress) { + // 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. + while (true) { + // 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 = workInProgress.alternate; + { + ReactDebugCurrentFiber.setCurrentFiber(workInProgress); + } + + var returnFiber = workInProgress["return"]; + var siblingFiber = workInProgress.sibling; + + if ((workInProgress.effectTag & Incomplete) === NoEffect) { + // This fiber completed. + var next = completeWork( + current, + workInProgress, + nextRenderExpirationTime + ); + stopWorkTimer(workInProgress); + resetExpirationTime(workInProgress, nextRenderExpirationTime); + { + ReactDebugCurrentFiber.resetCurrentFiber(); + } + + if (next !== null) { + stopWorkTimer(workInProgress); + if (true && ReactFiberInstrumentation_1.debugTool) { + ReactFiberInstrumentation_1.debugTool.onCompleteWork( + workInProgress + ); + } + // If completing this work spawned new work, do that next. We'll come + // back here again. + 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; + } + } + + if (true && ReactFiberInstrumentation_1.debugTool) { + ReactFiberInstrumentation_1.debugTool.onCompleteWork(workInProgress); + } + + if (siblingFiber !== null) { + // If there is more work to do in this returnFiber, do that next. + return siblingFiber; + } else if (returnFiber !== null) { + // If there's no more work in this returnFiber. Complete the returnFiber. + workInProgress = returnFiber; + continue; + } else { + // We've reached the root. + isRootReadyForCommit = true; + return null; + } + } 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); + // Because this fiber did not complete, don't reset its expiration time. + if (workInProgress.effectTag & DidCapture) { + // Restarting an error boundary + stopFailedWorkTimer(workInProgress); + } else { + stopWorkTimer(workInProgress); + } + + { + ReactDebugCurrentFiber.resetCurrentFiber(); + } + + if (_next !== null) { + stopWorkTimer(workInProgress); + if (true && ReactFiberInstrumentation_1.debugTool) { + ReactFiberInstrumentation_1.debugTool.onCompleteWork( + workInProgress + ); + } + // 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. + _next.effectTag &= HostEffectMask; + return _next; + } + + if (returnFiber !== null) { + // Mark the parent fiber as incomplete and clear its effect list. + returnFiber.firstEffect = returnFiber.lastEffect = null; + returnFiber.effectTag |= Incomplete; + } + + if (true && ReactFiberInstrumentation_1.debugTool) { + ReactFiberInstrumentation_1.debugTool.onCompleteWork(workInProgress); + } + + if (siblingFiber !== null) { + // If there is more work to do in this returnFiber, do that next. + return siblingFiber; + } else if (returnFiber !== null) { + // If there's no more work in this returnFiber. Complete the returnFiber. + workInProgress = returnFiber; + continue; + } else { + return null; + } + } + } + + // Without this explicit null return Flow complains of invalid return type + // TODO Remove the above while(true) loop + // eslint-disable-next-line no-unreachable + return null; + } + + function performUnitOfWork(workInProgress) { + // 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 = workInProgress.alternate; + + // See if beginning this work spawns more work. + startWorkTimer(workInProgress); + { + ReactDebugCurrentFiber.setCurrentFiber(workInProgress); + } + + if (true && replayFailedUnitOfWorkWithInvokeGuardedCallback) { + stashedWorkInProgressProperties = assignFiberPropertiesInDEV( + stashedWorkInProgressProperties, + workInProgress + ); + } + var next = beginWork(current, workInProgress, nextRenderExpirationTime); + { + ReactDebugCurrentFiber.resetCurrentFiber(); + if (isReplayingFailedUnitOfWork) { + // Currently replaying a failed unit of work. This should be unreachable, + // because the render phase is meant to be idempotent, and it should + // have thrown again. Since it didn't, rethrow the original error, so + // React's internal stack is not misaligned. + rethrowOriginalError(); + } + } + if (true && ReactFiberInstrumentation_1.debugTool) { + ReactFiberInstrumentation_1.debugTool.onBeginWork(workInProgress); + } + + if (next === null) { + // If this doesn't spawn new work, complete the current work. + next = completeUnitOfWork(workInProgress); + } + + ReactCurrentOwner.current = null; + + return next; + } + + function workLoop(isAsync) { + if (!isAsync) { + // Flush all expired work. + while (nextUnitOfWork !== null) { + nextUnitOfWork = performUnitOfWork(nextUnitOfWork); + } + } else { + // Flush asynchronous work until the deadline runs out of time. + while (nextUnitOfWork !== null && !shouldYield()) { + nextUnitOfWork = performUnitOfWork(nextUnitOfWork); + } + } + } + + function renderRoot(root, expirationTime, isAsync) { + invariant( + !isWorking, + "renderRoot was called recursively. This error is likely caused " + + "by a bug in React. Please file an issue." + ); + isWorking = true; + + // Check if we're starting from a fresh stack, or if we're resuming from + // previously yielded work. + if ( + expirationTime !== nextRenderExpirationTime || + root !== nextRoot || + nextUnitOfWork === null + ) { + // Reset the stack and start working from the root. + resetStack(); + nextRoot = root; + nextRenderExpirationTime = expirationTime; + nextUnitOfWork = createWorkInProgress( + nextRoot.current, + null, + nextRenderExpirationTime + ); + root.pendingCommitExpirationTime = NoWork; + } + + var didFatal = false; + + startWorkLoopTimer(nextUnitOfWork); + + do { + try { + workLoop(isAsync); + } catch (thrownValue) { + if (nextUnitOfWork === null) { + // This is a fatal error. + didFatal = true; + onUncaughtError(thrownValue); + break; + } + + if (true && replayFailedUnitOfWorkWithInvokeGuardedCallback) { + var failedUnitOfWork = nextUnitOfWork; + replayUnitOfWork(failedUnitOfWork, thrownValue, isAsync); + } + + var sourceFiber = nextUnitOfWork; + var returnFiber = sourceFiber["return"]; + if (returnFiber === null) { + // This is the root. The root could capture its own errors. However, + // we don't know if it errors before or after we pushed the host + // context. This information is needed to avoid a stack mismatch. + // Because we're not sure, treat this as a fatal error. We could track + // which phase it fails in, but doesn't seem worth it. At least + // for now. + didFatal = true; + onUncaughtError(thrownValue); + break; + } + throwException(returnFiber, sourceFiber, thrownValue); + nextUnitOfWork = completeUnitOfWork(sourceFiber); + } + break; + } while (true); + + // We're done performing work. Time to clean up. + var didCompleteRoot = false; + isWorking = false; + + // Yield back to main thread. + if (didFatal) { + stopWorkLoopTimer(interruptedBy, didCompleteRoot); + interruptedBy = null; + // There was a fatal error. + { + stack.resetStackAfterFatalErrorInDev(); + } + return null; + } else if (nextUnitOfWork === null) { + // We reached the root. + if (isRootReadyForCommit) { + didCompleteRoot = true; + stopWorkLoopTimer(interruptedBy, didCompleteRoot); + interruptedBy = null; + // The root successfully completed. It's ready for commit. + root.pendingCommitExpirationTime = expirationTime; + var finishedWork = root.current.alternate; + return finishedWork; + } else { + // The root did not complete. + stopWorkLoopTimer(interruptedBy, didCompleteRoot); + interruptedBy = null; + invariant( + false, + "Expired work should have completed. This error is likely caused " + + "by a bug in React. Please file an issue." + ); + } + } else { + stopWorkLoopTimer(interruptedBy, didCompleteRoot); + interruptedBy = null; + // There's more work to do, but we ran out of time. Yield back to + // the renderer. + return null; + } + } + + function scheduleCapture(sourceFiber, boundaryFiber, value, expirationTime) { + // TODO: We only support dispatching errors. + var capturedValue = createCapturedValue(value, sourceFiber); + var update = { + expirationTime: expirationTime, + partialState: null, + callback: null, + isReplace: false, + isForced: false, + capturedValue: capturedValue, + next: null + }; + insertUpdateIntoFiber(boundaryFiber, update); + scheduleWork(boundaryFiber, expirationTime); + } + + function dispatch(sourceFiber, value, expirationTime) { + invariant( + !isWorking || isCommitting, + "dispatch: Cannot dispatch during the render phase." + ); + + // TODO: Handle arrays + + var fiber = sourceFiber["return"]; + while (fiber !== null) { + switch (fiber.tag) { + case ClassComponent: + var ctor = fiber.type; + var instance = fiber.stateNode; + if ( + typeof ctor.getDerivedStateFromCatch === "function" || + (typeof instance.componentDidCatch === "function" && + !isAlreadyFailedLegacyErrorBoundary(instance)) + ) { + scheduleCapture(sourceFiber, fiber, value, expirationTime); + return; + } + break; + // TODO: Handle async boundaries + case HostRoot: + scheduleCapture(sourceFiber, fiber, value, expirationTime); + return; + } + fiber = fiber["return"]; + } + + if (sourceFiber.tag === HostRoot) { + // Error was thrown at the root. There is no parent, so the root + // itself should capture it. + scheduleCapture(sourceFiber, sourceFiber, value, expirationTime); + } + } + + function onCommitPhaseError(fiber, error) { + return dispatch(fiber, error, Sync); + } + + function computeAsyncExpiration(currentTime) { + // Given the current clock time, returns an expiration time. We use rounding + // to batch like updates together. + // Should complete within ~1000ms. 1200ms max. + var expirationMs = 5000; + var bucketSizeMs = 250; + return computeExpirationBucket(currentTime, expirationMs, bucketSizeMs); + } + + function computeInteractiveExpiration(currentTime) { + var expirationMs = void 0; + // 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. + { + // Should complete within ~500ms. 600ms max. + expirationMs = 500; + } + var bucketSizeMs = 100; + return computeExpirationBucket(currentTime, expirationMs, bucketSizeMs); + } + + // Creates a unique async expiration time. + function computeUniqueAsyncExpiration() { + var currentTime = recalculateCurrentTime(); + var result = computeAsyncExpiration(currentTime); + if (result <= lastUniqueAsyncExpiration) { + // Since we assume the current time monotonically increases, we only hit + // this branch when computeUniqueAsyncExpiration is fired multiple times + // within a 200ms window (or whatever the async bucket size is). + result = lastUniqueAsyncExpiration + 1; + } + lastUniqueAsyncExpiration = result; + return lastUniqueAsyncExpiration; + } + + function computeExpirationForFiber(fiber) { + var expirationTime = void 0; + if (expirationContext !== NoWork) { + // An explicit expiration context was set; + expirationTime = expirationContext; + } else if (isWorking) { + if (isCommitting) { + // Updates that occur during the commit phase should have sync priority + // by default. + expirationTime = Sync; + } else { + // Updates during the render phase should expire at the same time as + // the work that is being rendered. + expirationTime = nextRenderExpirationTime; + } + } else { + // No explicit expiration context was set, and we're not currently + // performing work. Calculate a new expiration time. + if (fiber.mode & AsyncMode) { + if (isBatchingInteractiveUpdates) { + // This is an interactive update + var currentTime = recalculateCurrentTime(); + expirationTime = computeInteractiveExpiration(currentTime); + } else { + // This is an async update + var _currentTime = recalculateCurrentTime(); + expirationTime = computeAsyncExpiration(_currentTime); + } + } else { + // This is a sync update + expirationTime = Sync; + } + } + if (isBatchingInteractiveUpdates) { + // This is an interactive update. Keep track of the lowest pending + // interactive expiration time. This allows us to synchronously flush + // all interactive updates when needed. + if ( + lowestPendingInteractiveExpirationTime === NoWork || + expirationTime > lowestPendingInteractiveExpirationTime + ) { + lowestPendingInteractiveExpirationTime = expirationTime; + } + } + return expirationTime; + } + + function scheduleWork(fiber, expirationTime) { + return scheduleWorkImpl(fiber, expirationTime, false); + } + + function scheduleWorkImpl(fiber, expirationTime, isErrorRecovery) { + recordScheduleUpdate(); + + { + if (!isErrorRecovery && fiber.tag === ClassComponent) { + var instance = fiber.stateNode; + warnAboutInvalidUpdates(instance); + } + } + + var node = fiber; + while (node !== null) { + // Walk the parent path to the root and update each node's + // expiration time. + if ( + node.expirationTime === NoWork || + node.expirationTime > expirationTime + ) { + node.expirationTime = expirationTime; + } + if (node.alternate !== null) { + if ( + node.alternate.expirationTime === NoWork || + node.alternate.expirationTime > expirationTime + ) { + node.alternate.expirationTime = expirationTime; + } + } + if (node["return"] === null) { + if (node.tag === HostRoot) { + var root = node.stateNode; + if ( + !isWorking && + nextRenderExpirationTime !== NoWork && + expirationTime < nextRenderExpirationTime + ) { + // This is an interruption. (Used for performance tracking.) + interruptedBy = fiber; + resetStack(); + } + if ( + // If we're in the render phase, we don't need to schedule this root + // for an update, because we'll do it before we exit... + !isWorking || + isCommitting || + // ...unless this is a different root than the one we're rendering. + nextRoot !== root + ) { + // Add this root to the root schedule. + requestWork(root, expirationTime); + } + if (nestedUpdateCount > NESTED_UPDATE_LIMIT) { + invariant( + false, + "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." + ); + } + } else { + { + if (!isErrorRecovery && fiber.tag === ClassComponent) { + warnAboutUpdateOnUnmounted(fiber); + } + } + return; + } + } + node = node["return"]; + } + } + + function recalculateCurrentTime() { + // Subtract initial time so it fits inside 32bits + mostRecentCurrentTimeMs = now() - originalStartTimeMs; + mostRecentCurrentTime = msToExpirationTime(mostRecentCurrentTimeMs); + return mostRecentCurrentTime; + } + + function deferredUpdates(fn) { + var previousExpirationContext = expirationContext; + var currentTime = recalculateCurrentTime(); + expirationContext = computeAsyncExpiration(currentTime); + try { + return fn(); + } finally { + expirationContext = previousExpirationContext; + } + } + function syncUpdates(fn, a, b, c, d) { + var previousExpirationContext = expirationContext; + expirationContext = Sync; + try { + return fn(a, b, c, d); + } finally { + expirationContext = previousExpirationContext; + } + } + + // TODO: Everything below this is written as if it has been lifted to the + // renderers. I'll do this in a follow-up. + + // Linked-list of roots + var firstScheduledRoot = null; + var lastScheduledRoot = null; + + var callbackExpirationTime = NoWork; + var callbackID = -1; + var isRendering = false; + var nextFlushedRoot = null; + var nextFlushedExpirationTime = NoWork; + var lowestPendingInteractiveExpirationTime = NoWork; + var deadlineDidExpire = false; + var hasUnhandledError = false; + var unhandledError = null; + var deadline = null; + + var isBatchingUpdates = false; + var isUnbatchingUpdates = false; + var isBatchingInteractiveUpdates = false; + + var completedBatches = null; + + // Use these to prevent an infinite loop of nested updates + var NESTED_UPDATE_LIMIT = 1000; + var nestedUpdateCount = 0; + + var timeHeuristicForUnitOfWork = 1; + + function scheduleCallbackWithExpiration(expirationTime) { + if (callbackExpirationTime !== NoWork) { + // A callback is already scheduled. Check its expiration time (timeout). + if (expirationTime > callbackExpirationTime) { + // Existing callback has sufficient timeout. Exit. + return; + } else { + // Existing callback has insufficient timeout. Cancel and schedule a + // new one. + cancelDeferredCallback(callbackID); + } + // The request callback timer is already running. Don't start a new one. + } else { + startRequestCallbackTimer(); + } + + // Compute a timeout for the given expiration time. + var currentMs = now() - originalStartTimeMs; + var expirationMs = expirationTimeToMs(expirationTime); + var timeout = expirationMs - currentMs; + + callbackExpirationTime = expirationTime; + callbackID = scheduleDeferredCallback(performAsyncWork, { + timeout: timeout + }); + } + + // requestWork is called by the scheduler whenever a root receives an update. + // It's up to the renderer to call renderRoot at some point in the future. + function requestWork(root, expirationTime) { + addRootToSchedule(root, expirationTime); + + if (isRendering) { + // Prevent reentrancy. Remaining work will be scheduled at the end of + // the currently rendering batch. + return; + } + + if (isBatchingUpdates) { + // Flush work at the end of the batch. + if (isUnbatchingUpdates) { + // ...unless we're inside unbatchedUpdates, in which case we should + // flush it now. + nextFlushedRoot = root; + nextFlushedExpirationTime = Sync; + performWorkOnRoot(root, Sync, false); + } + return; + } + + // TODO: Get rid of Sync and use current time? + if (expirationTime === Sync) { + performSyncWork(); + } else { + scheduleCallbackWithExpiration(expirationTime); + } + } + + function addRootToSchedule(root, expirationTime) { + // Add the root to the schedule. + // Check if this root is already part of the schedule. + if (root.nextScheduledRoot === null) { + // This root is not already scheduled. Add it. + root.remainingExpirationTime = expirationTime; + if (lastScheduledRoot === null) { + firstScheduledRoot = lastScheduledRoot = root; + root.nextScheduledRoot = root; + } else { + lastScheduledRoot.nextScheduledRoot = root; + lastScheduledRoot = root; + lastScheduledRoot.nextScheduledRoot = firstScheduledRoot; + } + } else { + // This root is already scheduled, but its priority may have increased. + var remainingExpirationTime = root.remainingExpirationTime; + if ( + remainingExpirationTime === NoWork || + expirationTime < remainingExpirationTime + ) { + // Update the priority. + root.remainingExpirationTime = expirationTime; + } + } + } + + function findHighestPriorityRoot() { + var highestPriorityWork = NoWork; + var highestPriorityRoot = null; + if (lastScheduledRoot !== null) { + var previousScheduledRoot = lastScheduledRoot; + var root = firstScheduledRoot; + while (root !== null) { + var remainingExpirationTime = root.remainingExpirationTime; + if (remainingExpirationTime === NoWork) { + // This root no longer has work. Remove it from the scheduler. + + // TODO: This check is redudant, but Flow is confused by the branch + // below where we set lastScheduledRoot to null, even though we break + // from the loop right after. + invariant( + previousScheduledRoot !== null && lastScheduledRoot !== null, + "Should have a previous and last root. This error is likely " + + "caused by a bug in React. Please file an issue." + ); + if (root === root.nextScheduledRoot) { + // This is the only root in the list. + root.nextScheduledRoot = null; + firstScheduledRoot = lastScheduledRoot = null; + break; + } else if (root === firstScheduledRoot) { + // This is the first root in the list. + var next = root.nextScheduledRoot; + firstScheduledRoot = next; + lastScheduledRoot.nextScheduledRoot = next; + root.nextScheduledRoot = null; + } else if (root === lastScheduledRoot) { + // This is the last root in the list. + lastScheduledRoot = previousScheduledRoot; + lastScheduledRoot.nextScheduledRoot = firstScheduledRoot; + root.nextScheduledRoot = null; + break; + } else { + previousScheduledRoot.nextScheduledRoot = root.nextScheduledRoot; + root.nextScheduledRoot = null; + } + root = previousScheduledRoot.nextScheduledRoot; + } else { + if ( + highestPriorityWork === NoWork || + remainingExpirationTime < highestPriorityWork + ) { + // Update the priority, if it's higher + highestPriorityWork = remainingExpirationTime; + highestPriorityRoot = root; + } + if (root === lastScheduledRoot) { + break; + } + previousScheduledRoot = root; + root = root.nextScheduledRoot; + } + } + } + + // If the next root is the same as the previous root, this is a nested + // update. To prevent an infinite loop, increment the nested update count. + var previousFlushedRoot = nextFlushedRoot; + if ( + previousFlushedRoot !== null && + previousFlushedRoot === highestPriorityRoot && + highestPriorityWork === Sync + ) { + nestedUpdateCount++; + } else { + // Reset whenever we switch roots. + nestedUpdateCount = 0; + } + nextFlushedRoot = highestPriorityRoot; + nextFlushedExpirationTime = highestPriorityWork; + } + + function performAsyncWork(dl) { + performWork(NoWork, true, dl); + } + + function performSyncWork() { + performWork(Sync, false, null); + } + + function performWork(minExpirationTime, isAsync, dl) { + deadline = dl; + + // Keep working on roots until there's no more work, or until the we reach + // the deadline. + findHighestPriorityRoot(); + + if (enableUserTimingAPI && deadline !== null) { + var didExpire = nextFlushedExpirationTime < recalculateCurrentTime(); + var timeout = expirationTimeToMs(nextFlushedExpirationTime); + stopRequestCallbackTimer(didExpire, timeout); + } + + if (isAsync) { + while ( + nextFlushedRoot !== null && + nextFlushedExpirationTime !== NoWork && + (minExpirationTime === NoWork || + minExpirationTime >= nextFlushedExpirationTime) && + (!deadlineDidExpire || + recalculateCurrentTime() >= nextFlushedExpirationTime) + ) { + performWorkOnRoot( + nextFlushedRoot, + nextFlushedExpirationTime, + !deadlineDidExpire + ); + findHighestPriorityRoot(); + } + } else { + while ( + nextFlushedRoot !== null && + nextFlushedExpirationTime !== NoWork && + (minExpirationTime === NoWork || + minExpirationTime >= nextFlushedExpirationTime) + ) { + performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime, false); + findHighestPriorityRoot(); + } + } + + // We're done flushing work. Either we ran out of time in this callback, + // or there's no more work left with sufficient priority. + + // If we're inside a callback, set this to false since we just completed it. + if (deadline !== null) { + callbackExpirationTime = NoWork; + callbackID = -1; + } + // If there's work left over, schedule a new callback. + if (nextFlushedExpirationTime !== NoWork) { + scheduleCallbackWithExpiration(nextFlushedExpirationTime); + } + + // Clean-up. + deadline = null; + deadlineDidExpire = false; + + finishRendering(); + } + + function flushRoot(root, expirationTime) { + invariant( + !isRendering, + "work.commit(): Cannot commit while already rendering. This likely " + + "means you attempted to commit from inside a lifecycle method." + ); + // Perform work on root as if the given expiration time is the current time. + // This has the effect of synchronously flushing all work up to and + // including the given time. + nextFlushedRoot = root; + nextFlushedExpirationTime = expirationTime; + performWorkOnRoot(root, expirationTime, false); + // Flush any sync work that was scheduled by lifecycles + performSyncWork(); + finishRendering(); + } + + function finishRendering() { + nestedUpdateCount = 0; + + if (completedBatches !== null) { + var batches = completedBatches; + completedBatches = null; + for (var i = 0; i < batches.length; i++) { + var batch = batches[i]; + try { + batch._onComplete(); + } catch (error) { + if (!hasUnhandledError) { + hasUnhandledError = true; + unhandledError = error; + } + } + } + } + + if (hasUnhandledError) { + var error = unhandledError; + unhandledError = null; + hasUnhandledError = false; + throw error; + } + } + + function performWorkOnRoot(root, expirationTime, isAsync) { + invariant( + !isRendering, + "performWorkOnRoot was called recursively. This error is likely caused " + + "by a bug in React. Please file an issue." + ); + + isRendering = true; + + // Check if this is async work or sync/expired work. + if (!isAsync) { + // Flush sync work. + var finishedWork = root.finishedWork; + if (finishedWork !== null) { + // This root is already complete. We can commit it. + completeRoot(root, finishedWork, expirationTime); + } else { + root.finishedWork = null; + finishedWork = renderRoot(root, expirationTime, false); + if (finishedWork !== null) { + // We've completed the root. Commit it. + completeRoot(root, finishedWork, expirationTime); + } + } + } else { + // Flush async work. + var _finishedWork = root.finishedWork; + if (_finishedWork !== null) { + // This root is already complete. We can commit it. + completeRoot(root, _finishedWork, expirationTime); + } else { + root.finishedWork = null; + _finishedWork = renderRoot(root, expirationTime, true); + if (_finishedWork !== null) { + // We've completed the root. Check the deadline one more time + // before committing. + if (!shouldYield()) { + // Still time left. Commit the root. + completeRoot(root, _finishedWork, expirationTime); + } else { + // There's no time left. Mark this root as complete. We'll come + // back and commit it later. + root.finishedWork = _finishedWork; + } + } + } + } + + isRendering = false; + } + + function completeRoot(root, finishedWork, expirationTime) { + // Check if there's a batch that matches this expiration time. + var firstBatch = root.firstBatch; + if (firstBatch !== null && firstBatch._expirationTime <= expirationTime) { + if (completedBatches === null) { + completedBatches = [firstBatch]; + } else { + completedBatches.push(firstBatch); + } + if (firstBatch._defer) { + // This root is blocked from committing by a batch. Unschedule it until + // we receive another update. + root.finishedWork = finishedWork; + root.remainingExpirationTime = NoWork; + return; + } + } + + // Commit the root. + root.finishedWork = null; + root.remainingExpirationTime = commitRoot(finishedWork); + } + + // When working on async work, the reconciler asks the renderer if it should + // yield execution. For DOM, we implement this with requestIdleCallback. + function shouldYield() { + if (deadline === null) { + return false; + } + if (deadline.timeRemaining() > timeHeuristicForUnitOfWork) { + // Disregard deadline.didTimeout. Only expired work should be flushed + // during a timeout. This path is only hit for non-expired work. + return false; + } + deadlineDidExpire = true; + return true; + } + + function onUncaughtError(error) { + invariant( + nextFlushedRoot !== null, + "Should be working on a root. This error is likely caused by a bug in " + + "React. Please file an issue." + ); + // Unschedule this root so we don't work on it again until there's + // another update. + nextFlushedRoot.remainingExpirationTime = NoWork; + if (!hasUnhandledError) { + hasUnhandledError = true; + unhandledError = error; + } + } + + // TODO: Batching should be implemented at the renderer level, not inside + // the reconciler. + function batchedUpdates(fn, a) { + var previousIsBatchingUpdates = isBatchingUpdates; + isBatchingUpdates = true; + try { + return fn(a); + } finally { + isBatchingUpdates = previousIsBatchingUpdates; + if (!isBatchingUpdates && !isRendering) { + performSyncWork(); + } + } + } + + // TODO: Batching should be implemented at the renderer level, not inside + // the reconciler. + function unbatchedUpdates(fn, a) { + if (isBatchingUpdates && !isUnbatchingUpdates) { + isUnbatchingUpdates = true; + try { + return fn(a); + } finally { + isUnbatchingUpdates = false; + } + } + return fn(a); + } + + // TODO: Batching should be implemented at the renderer level, not within + // the reconciler. + function flushSync(fn, a) { + invariant( + !isRendering, + "flushSync was called from inside a lifecycle method. It cannot be " + + "called when React is already rendering." + ); + var previousIsBatchingUpdates = isBatchingUpdates; + isBatchingUpdates = true; + try { + return syncUpdates(fn, a); + } finally { + isBatchingUpdates = previousIsBatchingUpdates; + performSyncWork(); + } + } + + function interactiveUpdates(fn, a, b) { + if (isBatchingInteractiveUpdates) { + return fn(a, b); + } + // If there are any pending interactive updates, synchronously flush them. + // This needs to happen before we read any handlers, because the effect of + // the previous event may influence which handlers are called during + // this event. + if ( + !isBatchingUpdates && + !isRendering && + lowestPendingInteractiveExpirationTime !== NoWork + ) { + // Synchronously flush pending interactive updates. + performWork(lowestPendingInteractiveExpirationTime, false, null); + lowestPendingInteractiveExpirationTime = NoWork; + } + var previousIsBatchingInteractiveUpdates = isBatchingInteractiveUpdates; + var previousIsBatchingUpdates = isBatchingUpdates; + isBatchingInteractiveUpdates = true; + isBatchingUpdates = true; + try { + return fn(a, b); + } finally { + isBatchingInteractiveUpdates = previousIsBatchingInteractiveUpdates; + isBatchingUpdates = previousIsBatchingUpdates; + if (!isBatchingUpdates && !isRendering) { + performSyncWork(); + } + } + } + + function flushInteractiveUpdates() { + if (!isRendering && lowestPendingInteractiveExpirationTime !== NoWork) { + // Synchronously flush pending interactive updates. + performWork(lowestPendingInteractiveExpirationTime, false, null); + lowestPendingInteractiveExpirationTime = NoWork; + } + } + + function flushControlled(fn) { + var previousIsBatchingUpdates = isBatchingUpdates; + isBatchingUpdates = true; + try { + syncUpdates(fn); + } finally { + isBatchingUpdates = previousIsBatchingUpdates; + if (!isBatchingUpdates && !isRendering) { + performWork(Sync, false, null); + } + } + } + + return { + recalculateCurrentTime: recalculateCurrentTime, + computeExpirationForFiber: computeExpirationForFiber, + scheduleWork: scheduleWork, + requestWork: requestWork, + flushRoot: flushRoot, + batchedUpdates: batchedUpdates, + unbatchedUpdates: unbatchedUpdates, + flushSync: flushSync, + flushControlled: flushControlled, + deferredUpdates: deferredUpdates, + syncUpdates: syncUpdates, + interactiveUpdates: interactiveUpdates, + flushInteractiveUpdates: flushInteractiveUpdates, + computeUniqueAsyncExpiration: computeUniqueAsyncExpiration, + legacyContext: legacyContext + }; +}; + +var didWarnAboutNestedUpdates = void 0; + +{ + didWarnAboutNestedUpdates = false; +} + +// 0 is PROD, 1 is DEV. +// Might add PROFILE later. + +var ReactFiberReconciler$1 = function(config) { + var getPublicInstance = config.getPublicInstance; + + var _ReactFiberScheduler = ReactFiberScheduler(config), + computeUniqueAsyncExpiration = + _ReactFiberScheduler.computeUniqueAsyncExpiration, + recalculateCurrentTime = _ReactFiberScheduler.recalculateCurrentTime, + computeExpirationForFiber = _ReactFiberScheduler.computeExpirationForFiber, + scheduleWork = _ReactFiberScheduler.scheduleWork, + requestWork = _ReactFiberScheduler.requestWork, + flushRoot = _ReactFiberScheduler.flushRoot, + batchedUpdates = _ReactFiberScheduler.batchedUpdates, + unbatchedUpdates = _ReactFiberScheduler.unbatchedUpdates, + flushSync = _ReactFiberScheduler.flushSync, + flushControlled = _ReactFiberScheduler.flushControlled, + deferredUpdates = _ReactFiberScheduler.deferredUpdates, + syncUpdates = _ReactFiberScheduler.syncUpdates, + interactiveUpdates = _ReactFiberScheduler.interactiveUpdates, + flushInteractiveUpdates = _ReactFiberScheduler.flushInteractiveUpdates, + legacyContext = _ReactFiberScheduler.legacyContext; + + var findCurrentUnmaskedContext = legacyContext.findCurrentUnmaskedContext, + isContextProvider = legacyContext.isContextProvider, + processChildContext = legacyContext.processChildContext; + + function getContextForSubtree(parentComponent) { + if (!parentComponent) { + return emptyObject; + } + + var fiber = get$1(parentComponent); + var parentContext = findCurrentUnmaskedContext(fiber); + return isContextProvider(fiber) + ? processChildContext(fiber, parentContext) + : parentContext; + } + + function scheduleRootUpdate( + current, + element, + currentTime, + expirationTime, + callback + ) { + { + if ( + ReactDebugCurrentFiber.phase === "render" && + ReactDebugCurrentFiber.current !== null && + !didWarnAboutNestedUpdates + ) { + didWarnAboutNestedUpdates = true; + warning( + 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(ReactDebugCurrentFiber.current) || "Unknown" + ); + } + } + + callback = callback === undefined ? null : callback; + { + !(callback === null || typeof callback === "function") + ? warning( + false, + "render(...): Expected the last optional `callback` argument to be a " + + "function. Instead received: %s.", + callback + ) + : void 0; + } + + var update = { + expirationTime: expirationTime, + partialState: { element: element }, + callback: callback, + isReplace: false, + isForced: false, + capturedValue: null, + next: null + }; + insertUpdateIntoFiber(current, update); + scheduleWork(current, expirationTime); + + return expirationTime; + } + + function updateContainerAtExpirationTime( + element, + container, + parentComponent, + currentTime, + expirationTime, + callback + ) { + // TODO: If this is a nested container, this won't be the root. + var current = container.current; + + { + if (ReactFiberInstrumentation_1.debugTool) { + if (current.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, + element, + currentTime, + expirationTime, + callback + ); + } + + function findHostInstance(component) { + var fiber = get$1(component); + if (fiber === undefined) { + if (typeof component.render === "function") { + invariant(false, "Unable to find node on an unmounted component."); + } else { + invariant( + false, + "Argument appears to not be a ReactComponent. Keys: %s", + Object.keys(component) + ); + } + } + var hostFiber = findCurrentHostFiber(fiber); + if (hostFiber === null) { + return null; + } + return hostFiber.stateNode; + } + + return { + createContainer: function(containerInfo, isAsync, hydrate) { + return createFiberRoot(containerInfo, isAsync, hydrate); + }, + updateContainer: function(element, container, parentComponent, callback) { + var current = container.current; + var currentTime = recalculateCurrentTime(); + var expirationTime = computeExpirationForFiber(current); + return updateContainerAtExpirationTime( + element, + container, + parentComponent, + currentTime, + expirationTime, + callback + ); + }, + updateContainerAtExpirationTime: function( + element, + container, + parentComponent, + expirationTime, + callback + ) { + var currentTime = recalculateCurrentTime(); + return updateContainerAtExpirationTime( + element, + container, + parentComponent, + currentTime, + expirationTime, + callback + ); + }, + + flushRoot: flushRoot, + + requestWork: requestWork, + + computeUniqueAsyncExpiration: computeUniqueAsyncExpiration, + + batchedUpdates: batchedUpdates, + + unbatchedUpdates: unbatchedUpdates, + + deferredUpdates: deferredUpdates, + + syncUpdates: syncUpdates, + + interactiveUpdates: interactiveUpdates, + + flushInteractiveUpdates: flushInteractiveUpdates, + + flushControlled: flushControlled, + + flushSync: flushSync, + + getPublicRootInstance: function(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; + } + }, + + findHostInstance: findHostInstance, + + findHostInstanceWithNoPortals: function(fiber) { + var hostFiber = findCurrentHostFiberWithNoPortals(fiber); + if (hostFiber === null) { + return null; + } + return hostFiber.stateNode; + }, + injectIntoDevTools: function(devToolsConfig) { + var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; + + return injectInternals( + Object.assign({}, devToolsConfig, { + 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); + } + }) + ); + } + }; +}; + +var ReactFiberReconciler$2 = Object.freeze({ + default: ReactFiberReconciler$1 +}); + +var ReactFiberReconciler$3 = + (ReactFiberReconciler$2 && ReactFiberReconciler$1) || ReactFiberReconciler$2; + +// TODO: bundle Flow types with the package. + +// TODO: decide on the top-level export form. +// This is hacky but makes it work with both Rollup and Jest. +var reactReconciler = ReactFiberReconciler$3["default"] + ? ReactFiberReconciler$3["default"] + : ReactFiberReconciler$3; + +function _classCallCheck$1(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$1(this, ReactNativeFiberHostComponent); + + this._nativeTag = tag; + this._children = []; + this.viewConfig = viewConfig; + } + + ReactNativeFiberHostComponent.prototype.blur = function blur() { + TextInputState.blurTextInput(this._nativeTag); + }; + + ReactNativeFiberHostComponent.prototype.focus = function focus() { + TextInputState.focusTextInput(this._nativeTag); + }; + + ReactNativeFiberHostComponent.prototype.measure = function measure(callback) { + UIManager.measure(this._nativeTag, mountSafeCallback(this, callback)); + }; + + ReactNativeFiberHostComponent.prototype.measureInWindow = function measureInWindow( + callback + ) { + UIManager.measureInWindow( + this._nativeTag, + mountSafeCallback(this, callback) + ); + }; + + ReactNativeFiberHostComponent.prototype.measureLayout = function measureLayout( + relativeToNativeNode, + onSuccess, + onFail /* currently unused */ + ) { + UIManager.measureLayout( + this._nativeTag, + relativeToNativeNode, + mountSafeCallback(this, onFail), + mountSafeCallback(this, onSuccess) + ); + }; + + ReactNativeFiberHostComponent.prototype.setNativeProps = function setNativeProps( + nativeProps + ) { + { + 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) { + UIManager.updateView( + this._nativeTag, + this.viewConfig.uiViewClassName, + updatePayload + ); + } + }; + + return ReactNativeFiberHostComponent; +})(); + +var hasNativePerformanceNow = + typeof performance === "object" && typeof performance.now === "function"; + +var now = hasNativePerformanceNow + ? function() { + return performance.now(); + } + : function() { + return Date.now(); + }; + +var scheduledCallback = null; +var frameDeadline = 0; + +var frameDeadlineObject = { + timeRemaining: function() { + return frameDeadline - now(); + }, + didTimeout: false +}; + +function setTimeoutCallback() { + // TODO (bvaughn) Hard-coded 5ms unblocks initial async testing. + // React API probably changing to boolean rather than time remaining. + // Longer-term plan is to rewrite this using shared memory, + // And just return the value of the bit as the boolean. + frameDeadline = now() + 5; + + var callback = scheduledCallback; + scheduledCallback = null; + if (callback !== null) { + callback(frameDeadlineObject); + } +} + +// RN has a poor polyfill for requestIdleCallback so we aren't using it. +// This implementation is only intended for short-term use anyway. +// We also don't implement cancel functionality b'c Fiber doesn't currently need it. +function scheduleDeferredCallback(callback) { + // We assume only one callback is scheduled at a time b'c that's how Fiber works. + scheduledCallback = callback; + return setTimeout(setTimeoutCallback, 1); +} + +function cancelDeferredCallback(callbackID) { + scheduledCallback = null; + clearTimeout(callbackID); +} + +// Modules provided by RN: +// 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); + } +} + +var NativeRenderer = reactReconciler({ + appendInitialChild: function(parentInstance, child) { + parentInstance._children.push(child); + }, + createInstance: function( + type, + props, + rootContainerInstance, + hostContext, + internalInstanceHandle + ) { + var tag = allocateTag(); + var viewConfig = ReactNativeViewConfigRegistry.get(type); + + { + for (var key in viewConfig.validAttributes) { + if (props.hasOwnProperty(key)) { + deepFreezeAndThrowOnMutationInDev(props[key]); + } + } + } + + var updatePayload = create(props, viewConfig.validAttributes); + + UIManager.createView( + tag, // reactTag + viewConfig.uiViewClassName, // viewName + rootContainerInstance, // rootTag + updatePayload + ); + + 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; + }, + createTextInstance: function( + text, + rootContainerInstance, + hostContext, + internalInstanceHandle + ) { + var tag = allocateTag(); + + UIManager.createView( + tag, // reactTag + "RCTRawText", // viewName + rootContainerInstance, // rootTag + { text: text } + ); + + precacheFiberNode(internalInstanceHandle, tag); + + return tag; + }, + finalizeInitialChildren: function( + parentInstance, + type, + props, + rootContainerInstance + ) { + // 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; + }); + + UIManager.setChildren( + parentInstance._nativeTag, // containerTag + nativeTags + ); + + return false; + }, + getRootHostContext: function() { + return emptyObject; + }, + getChildHostContext: function() { + return emptyObject; + }, + getPublicInstance: function(instance) { + return instance; + }, + + now: now, + + prepareForCommit: function() { + // Noop + }, + prepareUpdate: function( + instance, + type, + oldProps, + newProps, + rootContainerInstance, + hostContext + ) { + return emptyObject; + }, + resetAfterCommit: function() { + // Noop + }, + + scheduleDeferredCallback: scheduleDeferredCallback, + cancelDeferredCallback: cancelDeferredCallback, + + shouldDeprioritizeSubtree: function(type, props) { + return false; + }, + shouldSetTextContent: function(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: { + appendChild: function(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); + + UIManager.manageChildren( + parentInstance._nativeTag, // containerTag + [index], // moveFromIndices + [children.length - 1], // moveToIndices + [], // addChildReactTags + [], // addAtIndices + [] + ); + } else { + children.push(child); + + UIManager.manageChildren( + parentInstance._nativeTag, // containerTag + [], // moveFromIndices + [], // moveToIndices + [childTag], // addChildReactTags + [children.length - 1], // addAtIndices + [] + ); + } + }, + appendChildToContainer: function(parentInstance, child) { + var childTag = typeof child === "number" ? child : child._nativeTag; + UIManager.setChildren( + parentInstance, // containerTag + [childTag] + ); + }, + commitTextUpdate: function(textInstance, oldText, newText) { + UIManager.updateView( + textInstance, // reactTag + "RCTRawText", // viewName + { text: newText } + ); + }, + commitMount: function(instance, type, newProps, internalInstanceHandle) { + // Noop + }, + commitUpdate: function( + 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) { + UIManager.updateView( + instance._nativeTag, // reactTag + viewConfig.uiViewClassName, // viewName + updatePayload + ); + } + }, + insertBefore: function(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); + + UIManager.manageChildren( + parentInstance._nativeTag, // containerID + [index], // moveFromIndices + [beforeChildIndex], // moveToIndices + [], // addChildReactTags + [], // addAtIndices + [] + ); + } else { + var _beforeChildIndex = children.indexOf(beforeChild); + children.splice(_beforeChildIndex, 0, child); + + var childTag = typeof child === "number" ? child : child._nativeTag; + + UIManager.manageChildren( + parentInstance._nativeTag, // containerID + [], // moveFromIndices + [], // moveToIndices + [childTag], // addChildReactTags + [_beforeChildIndex], // addAtIndices + [] + ); + } + }, + insertInContainerBefore: function(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. + invariant( + typeof parentInstance !== "number", + "Container does not support insertBefore operation" + ); + }, + removeChild: function(parentInstance, child) { + recursivelyUncacheFiberNode(child); + var children = parentInstance._children; + var index = children.indexOf(child); + + children.splice(index, 1); + + UIManager.manageChildren( + parentInstance._nativeTag, // containerID + [], // moveFromIndices + [], // moveToIndices + [], // addChildReactTags + [], // addAtIndices + [index] + ); + }, + removeChildFromContainer: function(parentInstance, child) { + recursivelyUncacheFiberNode(child); + UIManager.manageChildren( + parentInstance, // containerID + [], // moveFromIndices + [], // moveToIndices + [], // addChildReactTags + [], // addAtIndices + [0] + ); + }, + resetTextContent: function(instance) { + // Noop + } + } +}); + +// Module provided by RN: +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; + } + return emptyObject; + }; + + 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), + getInspectorData: function(findNodeHandle) { + return { + measure: function(callback) { + return 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, + 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: +var findHostInstance = NativeRenderer.findHostInstance; + +function findNodeHandle(componentOrHandle) { + { + var owner = ReactCurrentOwner.current; + if (owner !== null && owner.stateNode !== null) { + !owner.stateNode._warnedAboutRefsInRender + ? warning( + 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) || "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 = findHostInstance(componentOrHandle); + if (hostInstance == null) { + return hostInstance; + } + if (hostInstance.canonical) { + // Fabric + return hostInstance.canonical._nativeTag; + } + return hostInstance._nativeTag; +} + +injection$2.injectRenderer(NativeRenderer); + +function computeComponentStackForErrorReporting(reactTag) { + var fiber = getInstanceFromTag(reactTag); + if (!fiber) { + return ""; + } + return getStackAddendumByWorkInProgressFiber(fiber); +} + +var roots = new Map(); + +var ReactNativeRenderer = { + NativeComponent: ReactNativeComponent(findNodeHandle, findHostInstance), + + findNodeHandle: findNodeHandle, + + 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 = NativeRenderer.createContainer(containerTag, false, false); + roots.set(containerTag, root); + } + NativeRenderer.updateContainer(element, root, null, callback); + + return NativeRenderer.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? + NativeRenderer.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 + 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), + // Used by react-native-github/Libraries/ components + ReactNativeComponentTree: ReactNativeComponentTree, // ScrollResponder + computeComponentStackForErrorReporting: computeComponentStackForErrorReporting + } +}; + +{ + // $FlowFixMe + Object.assign( + ReactNativeRenderer.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, + { + // TODO: none of these work since Fiber. Remove these dependencies. + // Used by RCTRenderingPerf, Systrace: + ReactDebugTool: { + addHook: function() {}, + removeHook: function() {} + }, + // Used by ReactPerfStallHandler, RCTRenderingPerf: + ReactPerf: { + start: function() {}, + stop: function() {}, + printInclusive: function() {}, + printWasted: function() {} + } + } + ); +} + +NativeRenderer.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["default"] + : ReactNativeRenderer$3; + +module.exports = reactNativeRenderer; + + })(); +} diff --git a/Libraries/Renderer/oss/ReactNativeRenderer-prod.js b/Libraries/Renderer/oss/ReactNativeRenderer-prod.js new file mode 100644 index 00000000000000..32b4729f3c96f8 --- /dev/null +++ b/Libraries/Renderer/oss/ReactNativeRenderer-prod.js @@ -0,0 +1,6311 @@ +/** + * Copyright (c) 2013-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @noflow + * @providesModule ReactNativeRenderer-prod + * @preventMunge + */ + +"use strict"; +require("InitializeCore"); +var invariant = require("fbjs/lib/invariant"), + emptyFunction = require("fbjs/lib/emptyFunction"), + ReactNativeViewConfigRegistry = require("ReactNativeViewConfigRegistry"), + UIManager = require("UIManager"), + RCTEventEmitter = require("RCTEventEmitter"), + TextInputState = require("TextInputState"), + deepDiffer = require("deepDiffer"), + flattenStyle = require("flattenStyle"), + React = require("react"), + emptyObject = require("fbjs/lib/emptyObject"), + shallowEqual = require("fbjs/lib/shallowEqual"), + ExceptionsManager = require("ExceptionsManager"); +function invokeGuardedCallback(name, func, context, a, b, c, d, e, f) { + this._hasCaughtError = !1; + this._caughtError = null; + var funcArgs = Array.prototype.slice.call(arguments, 3); + try { + func.apply(context, funcArgs); + } catch (error) { + (this._caughtError = error), (this._hasCaughtError = !0); + } +} +var ReactErrorUtils = { + _caughtError: null, + _hasCaughtError: !1, + _rethrowError: null, + _hasRethrowError: !1, + invokeGuardedCallback: function(name, func, context, a, b, c, d, e, f) { + invokeGuardedCallback.apply(ReactErrorUtils, arguments); + }, + invokeGuardedCallbackAndCatchFirstError: function( + name, + func, + context, + a, + b, + c, + d, + e, + f + ) { + ReactErrorUtils.invokeGuardedCallback.apply(this, arguments); + if (ReactErrorUtils.hasCaughtError()) { + var error = ReactErrorUtils.clearCaughtError(); + ReactErrorUtils._hasRethrowError || + ((ReactErrorUtils._hasRethrowError = !0), + (ReactErrorUtils._rethrowError = error)); + } + }, + rethrowCaughtError: function() { + return rethrowCaughtError.apply(ReactErrorUtils, arguments); + }, + hasCaughtError: function() { + return ReactErrorUtils._hasCaughtError; + }, + clearCaughtError: function() { + if (ReactErrorUtils._hasCaughtError) { + var error = ReactErrorUtils._caughtError; + ReactErrorUtils._caughtError = null; + ReactErrorUtils._hasCaughtError = !1; + return error; + } + invariant( + !1, + "clearCaughtError was called but no error was captured. This error is likely caused by a bug in React. Please file an issue." + ); + } +}; +function rethrowCaughtError() { + if (ReactErrorUtils._hasRethrowError) { + var error = ReactErrorUtils._rethrowError; + ReactErrorUtils._rethrowError = null; + ReactErrorUtils._hasRethrowError = !1; + throw error; + } +} +var eventPluginOrder = null, + namesToPlugins = {}; +function recomputePluginOrdering() { + if (eventPluginOrder) + for (var pluginName in namesToPlugins) { + var pluginModule = namesToPlugins[pluginName], + pluginIndex = eventPluginOrder.indexOf(pluginName); + invariant( + -1 < pluginIndex, + "EventPluginRegistry: Cannot inject event plugins that do not exist in the plugin ordering, `%s`.", + pluginName + ); + if (!plugins[pluginIndex]) { + invariant( + pluginModule.extractEvents, + "EventPluginRegistry: Event plugins must implement an `extractEvents` method, but `%s` does not.", + pluginName + ); + 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; + invariant( + !eventNameDispatchConfigs.hasOwnProperty(eventName$jscomp$0), + "EventPluginHub: More than one plugin attempted to publish the same event name, `%s`.", + 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); + invariant( + JSCompiler_inline_result, + "EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.", + eventName, + pluginName + ); + } + } + } +} +function publishRegistrationName(registrationName, pluginModule) { + invariant( + !registrationNameModules[registrationName], + "EventPluginHub: More than one plugin attempted to publish the same registration name, `%s`.", + registrationName + ); + registrationNameModules[registrationName] = pluginModule; +} +var plugins = [], + eventNameDispatchConfigs = {}, + registrationNameModules = {}, + getFiberCurrentPropsFromNode = null, + getInstanceFromNode = null, + getNodeFromInstance = null; +function isEndish(topLevelType) { + return ( + "topMouseUp" === topLevelType || + "topTouchEnd" === topLevelType || + "topTouchCancel" === topLevelType + ); +} +function isMoveish(topLevelType) { + return "topMouseMove" === topLevelType || "topTouchMove" === topLevelType; +} +function isStartish(topLevelType) { + return "topMouseDown" === topLevelType || "topTouchStart" === topLevelType; +} +function executeDispatch(event, simulated, listener, inst) { + simulated = event.type || "unknown-event"; + event.currentTarget = getNodeFromInstance(inst); + ReactErrorUtils.invokeGuardedCallbackAndCatchFirstError( + simulated, + listener, + void 0, + event + ); + event.currentTarget = null; +} +function executeDirectDispatch(event) { + var dispatchListener = event._dispatchListeners, + dispatchInstance = event._dispatchInstances; + invariant( + !Array.isArray(dispatchListener), + "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) { + invariant( + null != next, + "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, !1, dispatchListeners[i], dispatchInstances[i]); + else + dispatchListeners && + executeDispatch(e, !1, dispatchListeners, dispatchInstances); + e._dispatchListeners = null; + e._dispatchInstances = null; + e.isPersistent() || e.constructor.release(e); + } +} +var injection = { + injectEventPluginOrder: function(injectedEventPluginOrder) { + invariant( + !eventPluginOrder, + "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]; + (namesToPlugins.hasOwnProperty(pluginName) && + namesToPlugins[pluginName] === pluginModule) || + (invariant( + !namesToPlugins[pluginName], + "EventPluginRegistry: Cannot inject two different event plugins using the same name, `%s`.", + 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; + invariant( + !listener || "function" === typeof listener, + "Expected `%s` listener to be a function, instead got a value of `%s` type.", + registrationName, + typeof listener + ); + 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 + ))); + } + } +} +var shouldBeReleasedProperties = "dispatchConfig _targetInst nativeEvent isDefaultPrevented isPropagationStopped _dispatchListeners _dispatchInstances".split( + " " + ), + EventInterface = { + type: null, + target: null, + currentTarget: emptyFunction.thatReturnsNull, + eventPhase: null, + bubbles: null, + cancelable: null, + timeStamp: function(event) { + return event.timeStamp || Date.now(); + }, + defaultPrevented: null, + isTrusted: null + }; +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) + ? emptyFunction.thatReturnsTrue + : emptyFunction.thatReturnsFalse; + this.isPropagationStopped = emptyFunction.thatReturnsFalse; + 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 = emptyFunction.thatReturnsTrue)); + }, + stopPropagation: function() { + var event = this.nativeEvent; + event && + (event.stopPropagation + ? event.stopPropagation() + : "unknown" !== typeof event.cancelBubble && (event.cancelBubble = !0), + (this.isPropagationStopped = emptyFunction.thatReturnsTrue)); + }, + persist: function() { + this.isPersistent = emptyFunction.thatReturnsTrue; + }, + isPersistent: emptyFunction.thatReturnsFalse, + destructor: function() { + var Interface = this.constructor.Interface, + propName; + for (propName in Interface) this[propName] = null; + for ( + Interface = 0; + Interface < shouldBeReleasedProperties.length; + Interface++ + ) + this[shouldBeReleasedProperties[Interface]] = null; + } +}); +SyntheticEvent.Interface = EventInterface; +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) { + invariant( + event instanceof this, + "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; + } + }), + touchBank = [], + touchHistory = { + touchBank: touchBank, + numberActiveTouches: 0, + indexOfSingleActiveTouch: -1, + mostRecentTimeStamp: 0 + }; +function timestampForTouch(touch) { + return touch.timeStamp || touch.timestamp; +} +function getTouchIdentifier(_ref) { + _ref = _ref.identifier; + invariant(null != _ref, "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 ( + isEndish(topLevelType) && + (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) { + invariant( + null != next, + "accumulate(...): Accumulated items must be 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, + previousActiveTouches = 0; +function changeResponder(nextResponderInst, blockHostResponder) { + var oldResponderInst = responderInst; + responderInst = nextResponderInst; + if (null !== ResponderEventPlugin.GlobalResponderHandler) + ResponderEventPlugin.GlobalResponderHandler.onChange( + oldResponderInst, + nextResponderInst, + blockHostResponder + ); +} +var eventTypes$1 = { + startShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onStartShouldSetResponder", + captured: "onStartShouldSetResponderCapture" + } + }, + scrollShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onScrollShouldSetResponder", + captured: "onScrollShouldSetResponderCapture" + } + }, + selectionChangeShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onSelectionChangeShouldSetResponder", + captured: "onSelectionChangeShouldSetResponderCapture" + } + }, + moveShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onMoveShouldSetResponder", + captured: "onMoveShouldSetResponderCapture" + } + }, + responderStart: { registrationName: "onResponderStart" }, + responderMove: { registrationName: "onResponderMove" }, + responderEnd: { registrationName: "onResponderEnd" }, + responderRelease: { registrationName: "onResponderRelease" }, + responderTerminationRequest: { + registrationName: "onResponderTerminationRequest" + }, + responderGrant: { registrationName: "onResponderGrant" }, + responderReject: { registrationName: "onResponderReject" }, + responderTerminate: { registrationName: "onResponderTerminate" } + }, + ResponderEventPlugin = { + _getResponder: function() { + return responderInst; + }, + eventTypes: eventTypes$1, + extractEvents: function( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) { + if (isStartish(topLevelType)) trackedTouchCount += 1; + else if (isEndish(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$1.startShouldSetResponder + : isMoveish(topLevelType) + ? eventTypes$1.moveShouldSetResponder + : "topSelectionChange" === topLevelType + ? eventTypes$1.selectionChangeShouldSetResponder + : eventTypes$1.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$1.responderGrant, + JSCompiler_temp, + nativeEvent, + nativeEventTarget + )), + (targetInst.touchHistory = ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(targetInst, accumulateDirectDispatchesSingle), + (depthA = !0 === executeDirectDispatch(targetInst)), + responderInst + ? ((tempA = ResponderSyntheticEvent.getPooled( + eventTypes$1.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$1.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$1.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 && isEndish(topLevelType); + if ( + (JSCompiler_temp$jscomp$0 = JSCompiler_temp$jscomp$0 + ? eventTypes$1.responderStart + : targetInst + ? eventTypes$1.responderMove + : depthA ? eventTypes$1.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 && isEndish(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$1.responderTerminate + : topLevelType ? eventTypes$1.responderRelease : null) + ) + (nativeEvent = ResponderSyntheticEvent.getPooled( + topLevelType, + responderInst, + nativeEvent, + nativeEventTarget + )), + (nativeEvent.touchHistory = ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(nativeEvent, accumulateDirectDispatchesSingle), + (JSCompiler_temp = accumulate(JSCompiler_temp, nativeEvent)), + changeResponder(null); + nativeEvent = ResponderTouchHistoryStore.touchHistory.numberActiveTouches; + if ( + ResponderEventPlugin.GlobalInteractionHandler && + nativeEvent !== previousActiveTouches + ) + ResponderEventPlugin.GlobalInteractionHandler.onChange(nativeEvent); + previousActiveTouches = nativeEvent; + return JSCompiler_temp; + }, + GlobalResponderHandler: null, + GlobalInteractionHandler: null, + injection: { + injectGlobalResponderHandler: function(GlobalResponderHandler) { + ResponderEventPlugin.GlobalResponderHandler = GlobalResponderHandler; + }, + injectGlobalInteractionHandler: function(GlobalInteractionHandler) { + ResponderEventPlugin.GlobalInteractionHandler = GlobalInteractionHandler; + } + } + }, + customBubblingEventTypes$1 = + ReactNativeViewConfigRegistry.customBubblingEventTypes, + customDirectEventTypes$1 = + ReactNativeViewConfigRegistry.customDirectEventTypes, + ReactNativeBridgeEventPlugin = { + eventTypes: ReactNativeViewConfigRegistry.eventTypes, + extractEvents: function( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) { + if (null == targetInst) return null; + var bubbleDispatchConfig = customBubblingEventTypes$1[topLevelType], + directDispatchConfig = customDirectEventTypes$1[topLevelType]; + invariant( + bubbleDispatchConfig || directDispatchConfig, + 'Unsupported top level event type "%s" dispatched', + topLevelType + ); + topLevelType = SyntheticEvent.getPooled( + bubbleDispatchConfig || directDispatchConfig, + targetInst, + nativeEvent, + nativeEventTarget + ); + if (bubbleDispatchConfig) + forEachAccumulated(topLevelType, accumulateTwoPhaseDispatchesSingle); + else if (directDispatchConfig) + forEachAccumulated(topLevelType, accumulateDirectDispatchesSingle); + else return null; + return topLevelType; + } + }, + instanceCache = {}, + instanceProps = {}; +function uncacheFiberNode(tag) { + delete instanceCache[tag]; + delete instanceProps[tag]; +} +function getInstanceFromTag(tag) { + return "number" === typeof tag ? instanceCache[tag] || null : tag; +} +var ReactNativeComponentTree = Object.freeze({ + precacheFiberNode: function(hostInst, tag) { + instanceCache[tag] = hostInst; + }, + uncacheFiberNode: uncacheFiberNode, + getClosestInstanceFromNode: getInstanceFromTag, + getInstanceFromNode: getInstanceFromTag, + getNodeFromInstance: function(inst) { + var tag = inst.stateNode._nativeTag; + void 0 === tag && (tag = inst.stateNode.canonical._nativeTag); + invariant(tag, "All native instances should have a tag."); + return tag; + }, + getFiberCurrentPropsFromNode: function(stateNode) { + return instanceProps[stateNode._nativeTag] || null; + }, + updateFiberProps: function(tag, props) { + instanceProps[tag] = props; + } +}); +injection.injectEventPluginOrder([ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]); +getFiberCurrentPropsFromNode = + ReactNativeComponentTree.getFiberCurrentPropsFromNode; +getInstanceFromNode = ReactNativeComponentTree.getInstanceFromNode; +getNodeFromInstance = ReactNativeComponentTree.getNodeFromInstance; +ResponderEventPlugin.injection.injectGlobalResponderHandler({ + onChange: function(from, to, blockNativeResponder) { + null !== to + ? UIManager.setJSResponder(to.stateNode._nativeTag, blockNativeResponder) + : UIManager.clearJSResponder(); + } +}); +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin +}); +var restoreTarget = null, + restoreQueue = null; +function restoreStateOfTarget(target) { + if ((target = getInstanceFromNode(target))) { + invariant( + null, + "Fiber needs to be injected to handle a fiber target for controlled events. This error is likely caused by a bug in React. Please file an issue." + ); + var props = getFiberCurrentPropsFromNode(target.stateNode); + null.restoreControlledState(target.stateNode, target.type, props); + } +} +function _batchedUpdates(fn, bookkeeping) { + return fn(bookkeeping); +} +function _flushInteractiveUpdates() {} +var isBatching = !1; +function batchedUpdates(fn, bookkeeping) { + if (isBatching) return fn(bookkeeping); + isBatching = !0; + try { + return _batchedUpdates(fn, bookkeeping); + } finally { + if (((isBatching = !1), null !== restoreTarget || null !== restoreQueue)) + if ( + (_flushInteractiveUpdates(), + 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; + events && + (forEachAccumulated(events, executeDispatchesAndReleaseTopLevel), + invariant( + !eventQueue, + "processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented." + ), + ReactErrorUtils.rethrowCaughtError()); + }); +} +var ReactNativeEventEmitter = Object.freeze({ + getListener: getListener, + registrationNames: registrationNameModules, + _receiveRootNodeIDEvent: _receiveRootNodeIDEvent, + 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); + } + } +}); +RCTEventEmitter.register(ReactNativeEventEmitter); +var hasSymbol = "function" === typeof Symbol && Symbol["for"], + REACT_ELEMENT_TYPE = hasSymbol ? Symbol["for"]("react.element") : 60103, + REACT_CALL_TYPE = hasSymbol ? Symbol["for"]("react.call") : 60104, + REACT_RETURN_TYPE = hasSymbol ? Symbol["for"]("react.return") : 60105, + 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_PROVIDER_TYPE = hasSymbol ? Symbol["for"]("react.provider") : 60109, + REACT_CONTEXT_TYPE = hasSymbol ? Symbol["for"]("react.context") : 60110, + REACT_ASYNC_MODE_TYPE = hasSymbol ? Symbol["for"]("react.async_mode") : 60111, + REACT_FORWARD_REF_TYPE = hasSymbol + ? Symbol["for"]("react.forward_ref") + : 60112, + MAYBE_ITERATOR_SYMBOL = "function" === typeof Symbol && Symbol.iterator; +function getIteratorFn(maybeIterable) { + if (null === maybeIterable || "undefined" === typeof maybeIterable) + return null; + maybeIterable = + (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || + maybeIterable["@@iterator"]; + return "function" === typeof maybeIterable ? maybeIterable : null; +} +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 getComponentName(fiber) { + fiber = fiber.type; + if ("function" === typeof fiber) return fiber.displayName || fiber.name; + if ("string" === typeof fiber) return fiber; + switch (fiber) { + case REACT_FRAGMENT_TYPE: + return "ReactFragment"; + case REACT_PORTAL_TYPE: + return "ReactPortal"; + case REACT_CALL_TYPE: + return "ReactCall"; + case REACT_RETURN_TYPE: + return "ReactReturn"; + } + if ("object" === typeof fiber && null !== fiber) + switch (fiber.$$typeof) { + case REACT_FORWARD_REF_TYPE: + return ( + (fiber = fiber.render.displayName || fiber.render.name || ""), + "" !== fiber ? "ForwardRef(" + fiber + ")" : "ForwardRef" + ); + } + return null; +} +function getStackAddendumByWorkInProgressFiber(workInProgress) { + var info = ""; + do { + a: switch (workInProgress.tag) { + case 0: + case 1: + case 2: + case 5: + var owner = workInProgress._debugOwner, + source = workInProgress._debugSource; + var JSCompiler_inline_result = getComponentName(workInProgress); + var ownerName = null; + owner && (ownerName = getComponentName(owner)); + owner = source; + JSCompiler_inline_result = + "\n in " + + (JSCompiler_inline_result || "Unknown") + + (owner + ? " (at " + + owner.fileName.replace(/^.*[\\\/]/, "") + + ":" + + owner.lineNumber + + ")" + : ownerName ? " (created by " + ownerName + ")" : ""); + break a; + default: + JSCompiler_inline_result = ""; + } + info += JSCompiler_inline_result; + workInProgress = workInProgress["return"]; + } while (workInProgress); + return info; +} +var emptyObject$1 = {}, + 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, + flattenStyle(prevProp), + nextProp, + validAttributes + ) + : diffProperties( + updatePayload, + prevProp, + flattenStyle(nextProp), + validAttributes + ); +} +function addNestedProperty(updatePayload, nextProp, validAttributes) { + if (!nextProp) return updatePayload; + if (!Array.isArray(nextProp)) + return diffProperties( + updatePayload, + emptyObject$1, + 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$1, + 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 || + 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 || + 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(context, callback) { + return function() { + if (callback) { + if ("boolean" === typeof context.__isMounted) { + if (!context.__isMounted) return; + } else if ( + "function" === typeof context.isMounted && + !context.isMounted() + ) + return; + return callback.apply(context, arguments); + } + }; +} +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 ReactCurrentOwner = + React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner; +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 isMounted(component) { + return (component = component._reactInternalFiber) + ? 2 === isFiberMountedImpl(component) + : !1; +} +function assertIsMounted(fiber) { + invariant( + 2 === isFiberMountedImpl(fiber), + "Unable to find node on an unmounted component." + ); +} +function findCurrentFiberUsingSlowPath(fiber) { + var alternate = fiber.alternate; + if (!alternate) + return ( + (alternate = isFiberMountedImpl(fiber)), + invariant( + 3 !== alternate, + "Unable to find node on an unmounted component." + ), + 1 === alternate ? null : fiber + ); + for (var a = fiber, b = alternate; ; ) { + var parentA = a["return"], + parentB = parentA ? parentA.alternate : null; + if (!parentA || !parentB) break; + if (parentA.child === parentB.child) { + for (var child = parentA.child; child; ) { + if (child === a) return assertIsMounted(parentA), fiber; + if (child === b) return assertIsMounted(parentA), alternate; + child = child.sibling; + } + invariant(!1, "Unable to find node on an unmounted component."); + } + if (a["return"] !== b["return"]) (a = parentA), (b = parentB); + else { + child = !1; + for (var _child = parentA.child; _child; ) { + if (_child === a) { + child = !0; + a = parentA; + b = parentB; + break; + } + if (_child === b) { + child = !0; + b = parentA; + a = parentB; + break; + } + _child = _child.sibling; + } + if (!child) { + for (_child = parentB.child; _child; ) { + if (_child === a) { + child = !0; + a = parentB; + b = parentA; + break; + } + if (_child === b) { + child = !0; + b = parentB; + a = parentA; + break; + } + _child = _child.sibling; + } + invariant( + child, + "Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue." + ); + } + } + invariant( + a.alternate === b, + "Return fibers should always be each others' alternates. This error is likely caused by a bug in React. Please file an issue." + ); + } + invariant(3 === a.tag, "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 findCurrentHostFiberWithNoPortals(parent) { + parent = findCurrentFiberUsingSlowPath(parent); + if (!parent) return null; + for (var node = parent; ; ) { + if (5 === node.tag || 6 === node.tag) return node; + if (node.child && 4 !== node.tag) + (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 FiberNode(tag, pendingProps, key, mode) { + this.tag = tag; + this.key = key; + this.stateNode = this.type = null; + this.sibling = this.child = this["return"] = null; + this.index = 0; + this.ref = null; + this.pendingProps = pendingProps; + this.memoizedState = this.updateQueue = this.memoizedProps = null; + this.mode = mode; + this.effectTag = 0; + this.lastEffect = this.firstEffect = this.nextEffect = null; + this.expirationTime = 0; + this.alternate = null; +} +function createWorkInProgress(current, pendingProps, expirationTime) { + var workInProgress = current.alternate; + null === workInProgress + ? ((workInProgress = new FiberNode( + current.tag, + pendingProps, + current.key, + current.mode + )), + (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.expirationTime = expirationTime; + workInProgress.child = current.child; + workInProgress.memoizedProps = current.memoizedProps; + workInProgress.memoizedState = current.memoizedState; + workInProgress.updateQueue = current.updateQueue; + workInProgress.sibling = current.sibling; + workInProgress.index = current.index; + workInProgress.ref = current.ref; + return workInProgress; +} +function createFiberFromElement(element, mode, expirationTime) { + var type = element.type, + key = element.key; + element = element.props; + var fiberTag = void 0; + if ("function" === typeof type) + fiberTag = type.prototype && type.prototype.isReactComponent ? 2 : 0; + else if ("string" === typeof type) fiberTag = 5; + else + switch (type) { + case REACT_FRAGMENT_TYPE: + return createFiberFromFragment( + element.children, + mode, + expirationTime, + key + ); + case REACT_ASYNC_MODE_TYPE: + fiberTag = 11; + mode |= 3; + break; + case REACT_STRICT_MODE_TYPE: + fiberTag = 11; + mode |= 2; + break; + case REACT_CALL_TYPE: + fiberTag = 7; + break; + case REACT_RETURN_TYPE: + fiberTag = 9; + break; + default: + if ("object" === typeof type && null !== type) + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + fiberTag = 13; + break; + case REACT_CONTEXT_TYPE: + fiberTag = 12; + break; + case REACT_FORWARD_REF_TYPE: + fiberTag = 14; + break; + default: + if ("number" === typeof type.tag) + return ( + (mode = type), + (mode.pendingProps = element), + (mode.expirationTime = expirationTime), + mode + ); + throwOnInvalidElementType(type, null); + } + else throwOnInvalidElementType(type, null); + } + mode = new FiberNode(fiberTag, element, key, mode); + mode.type = type; + mode.expirationTime = expirationTime; + return mode; +} +function throwOnInvalidElementType(type) { + invariant( + !1, + "Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: %s.%s", + null == type ? type : typeof type, + "" + ); +} +function createFiberFromFragment(elements, mode, expirationTime, key) { + elements = new FiberNode(10, elements, key, mode); + elements.expirationTime = expirationTime; + return elements; +} +function createFiberFromText(content, mode, expirationTime) { + content = new FiberNode(6, content, null, mode); + content.expirationTime = expirationTime; + return content; +} +function createFiberFromPortal(portal, mode, expirationTime) { + mode = new FiberNode( + 4, + null !== portal.children ? portal.children : [], + portal.key, + mode + ); + mode.expirationTime = expirationTime; + mode.stateNode = { + containerInfo: portal.containerInfo, + pendingChildren: null, + implementation: portal.implementation + }; + return mode; +} +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; +} +function onCommitRoot(root) { + "function" === typeof onCommitFiberRoot && onCommitFiberRoot(root); +} +function onCommitUnmount(fiber) { + "function" === typeof onCommitFiberUnmount && onCommitFiberUnmount(fiber); +} +new Set(); +function createUpdateQueue(baseState) { + return { + baseState: baseState, + expirationTime: 0, + first: null, + last: null, + callbackList: null, + hasForceUpdate: !1, + isInitialized: !1, + capturedValues: null + }; +} +function insertUpdateIntoQueue(queue, update) { + null === queue.last + ? (queue.first = queue.last = update) + : ((queue.last.next = update), (queue.last = update)); + if ( + 0 === queue.expirationTime || + queue.expirationTime > update.expirationTime + ) + queue.expirationTime = update.expirationTime; +} +var q1 = void 0, + q2 = void 0; +function ensureUpdateQueues(fiber) { + q1 = q2 = null; + var alternateFiber = fiber.alternate, + queue1 = fiber.updateQueue; + null === queue1 && (queue1 = fiber.updateQueue = createUpdateQueue(null)); + null !== alternateFiber + ? ((fiber = alternateFiber.updateQueue), + null === fiber && + (fiber = alternateFiber.updateQueue = createUpdateQueue(null))) + : (fiber = null); + q1 = queue1; + q2 = fiber !== queue1 ? fiber : null; +} +function insertUpdateIntoFiber(fiber, update) { + ensureUpdateQueues(fiber); + fiber = q1; + var queue2 = q2; + null === queue2 + ? insertUpdateIntoQueue(fiber, update) + : null === fiber.last || null === queue2.last + ? (insertUpdateIntoQueue(fiber, update), + insertUpdateIntoQueue(queue2, update)) + : (insertUpdateIntoQueue(fiber, update), (queue2.last = update)); +} +function getStateFromUpdate(update, instance, prevState, props) { + update = update.partialState; + return "function" === typeof update + ? update.call(instance, prevState, props) + : update; +} +function processUpdateQueue( + current, + workInProgress, + queue, + instance, + props, + renderExpirationTime +) { + null !== current && + current.updateQueue === queue && + (queue = workInProgress.updateQueue = { + baseState: queue.baseState, + expirationTime: queue.expirationTime, + first: queue.first, + last: queue.last, + isInitialized: queue.isInitialized, + capturedValues: queue.capturedValues, + callbackList: null, + hasForceUpdate: !1 + }); + queue.expirationTime = 0; + queue.isInitialized + ? (current = queue.baseState) + : ((current = queue.baseState = workInProgress.memoizedState), + (queue.isInitialized = !0)); + for ( + var dontMutatePrevState = !0, update = queue.first, didSkip = !1; + null !== update; + + ) { + var updateExpirationTime = update.expirationTime; + if (updateExpirationTime > renderExpirationTime) { + var remainingExpirationTime = queue.expirationTime; + if ( + 0 === remainingExpirationTime || + remainingExpirationTime > updateExpirationTime + ) + queue.expirationTime = updateExpirationTime; + didSkip || ((didSkip = !0), (queue.baseState = current)); + } else { + didSkip || + ((queue.first = update.next), + null === queue.first && (queue.last = null)); + if (update.isReplace) + (current = getStateFromUpdate(update, instance, current, props)), + (dontMutatePrevState = !0); + else if ( + (updateExpirationTime = getStateFromUpdate( + update, + instance, + current, + props + )) + ) + (current = dontMutatePrevState + ? Object.assign({}, current, updateExpirationTime) + : Object.assign(current, updateExpirationTime)), + (dontMutatePrevState = !1); + update.isForced && (queue.hasForceUpdate = !0); + null !== update.callback && + ((updateExpirationTime = queue.callbackList), + null === updateExpirationTime && + (updateExpirationTime = queue.callbackList = []), + updateExpirationTime.push(update)); + null !== update.capturedValue && + ((updateExpirationTime = queue.capturedValues), + null === updateExpirationTime + ? (queue.capturedValues = [update.capturedValue]) + : updateExpirationTime.push(update.capturedValue)); + } + update = update.next; + } + null !== queue.callbackList + ? (workInProgress.effectTag |= 32) + : null !== queue.first || + queue.hasForceUpdate || + null !== queue.capturedValues || + (workInProgress.updateQueue = null); + didSkip || (queue.baseState = current); + return current; +} +function commitCallbacks(queue, context) { + var callbackList = queue.callbackList; + if (null !== callbackList) + for ( + queue.callbackList = null, queue = 0; + queue < callbackList.length; + queue++ + ) { + var update = callbackList[queue], + _callback = update.callback; + update.callback = null; + invariant( + "function" === typeof _callback, + "Invalid argument passed as callback. Expected a function. Instead received: %s", + _callback + ); + _callback.call(context); + } +} +function ReactFiberClassComponent( + legacyContext, + scheduleWork, + computeExpirationForFiber, + memoizeProps, + memoizeState +) { + function checkShouldComponentUpdate( + workInProgress, + oldProps, + newProps, + oldState, + newState, + newContext + ) { + if ( + null === oldProps || + (null !== workInProgress.updateQueue && + workInProgress.updateQueue.hasForceUpdate) + ) + return !0; + var instance = workInProgress.stateNode; + workInProgress = workInProgress.type; + return "function" === typeof instance.shouldComponentUpdate + ? instance.shouldComponentUpdate(newProps, newState, newContext) + : workInProgress.prototype && + workInProgress.prototype.isPureReactComponent + ? !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) + : !0; + } + function adoptClassInstance(workInProgress, instance) { + instance.updater = updater; + workInProgress.stateNode = instance; + instance._reactInternalFiber = workInProgress; + } + function callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + newContext + ) { + workInProgress = instance.state; + "function" === typeof instance.componentWillReceiveProps && + instance.componentWillReceiveProps(newProps, newContext); + "function" === typeof instance.UNSAFE_componentWillReceiveProps && + instance.UNSAFE_componentWillReceiveProps(newProps, newContext); + instance.state !== workInProgress && + updater.enqueueReplaceState(instance, instance.state, null); + } + function callGetDerivedStateFromProps( + workInProgress, + instance, + nextProps, + prevState + ) { + workInProgress = workInProgress.type; + if ("function" === typeof workInProgress.getDerivedStateFromProps) + return workInProgress.getDerivedStateFromProps.call( + null, + nextProps, + prevState + ); + } + var cacheContext = legacyContext.cacheContext, + getMaskedContext = legacyContext.getMaskedContext, + getUnmaskedContext = legacyContext.getUnmaskedContext, + isContextConsumer = legacyContext.isContextConsumer, + hasContextChanged = legacyContext.hasContextChanged, + updater = { + isMounted: isMounted, + enqueueSetState: function(instance, partialState, callback) { + instance = instance._reactInternalFiber; + callback = void 0 === callback ? null : callback; + var expirationTime = computeExpirationForFiber(instance); + insertUpdateIntoFiber(instance, { + expirationTime: expirationTime, + partialState: partialState, + callback: callback, + isReplace: !1, + isForced: !1, + capturedValue: null, + next: null + }); + scheduleWork(instance, expirationTime); + }, + enqueueReplaceState: function(instance, state, callback) { + instance = instance._reactInternalFiber; + callback = void 0 === callback ? null : callback; + var expirationTime = computeExpirationForFiber(instance); + insertUpdateIntoFiber(instance, { + expirationTime: expirationTime, + partialState: state, + callback: callback, + isReplace: !0, + isForced: !1, + capturedValue: null, + next: null + }); + scheduleWork(instance, expirationTime); + }, + enqueueForceUpdate: function(instance, callback) { + instance = instance._reactInternalFiber; + callback = void 0 === callback ? null : callback; + var expirationTime = computeExpirationForFiber(instance); + insertUpdateIntoFiber(instance, { + expirationTime: expirationTime, + partialState: null, + callback: callback, + isReplace: !1, + isForced: !0, + capturedValue: null, + next: null + }); + scheduleWork(instance, expirationTime); + } + }; + return { + adoptClassInstance: adoptClassInstance, + callGetDerivedStateFromProps: callGetDerivedStateFromProps, + constructClassInstance: function(workInProgress, props) { + var ctor = workInProgress.type, + unmaskedContext = getUnmaskedContext(workInProgress), + needsContext = isContextConsumer(workInProgress), + context = needsContext + ? getMaskedContext(workInProgress, unmaskedContext) + : emptyObject; + ctor = new ctor(props, context); + var state = + null !== ctor.state && void 0 !== ctor.state ? ctor.state : null; + adoptClassInstance(workInProgress, ctor); + workInProgress.memoizedState = state; + props = callGetDerivedStateFromProps(workInProgress, ctor, props, state); + null !== props && + void 0 !== props && + (workInProgress.memoizedState = Object.assign( + {}, + workInProgress.memoizedState, + props + )); + needsContext && cacheContext(workInProgress, unmaskedContext, context); + return ctor; + }, + mountClassInstance: function(workInProgress, renderExpirationTime) { + var ctor = workInProgress.type, + current = workInProgress.alternate, + instance = workInProgress.stateNode, + props = workInProgress.pendingProps, + unmaskedContext = getUnmaskedContext(workInProgress); + instance.props = props; + instance.state = workInProgress.memoizedState; + instance.refs = emptyObject; + instance.context = getMaskedContext(workInProgress, unmaskedContext); + "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 && + updater.enqueueReplaceState(instance, instance.state, null), + (ctor = workInProgress.updateQueue), + null !== ctor && + (instance.state = processUpdateQueue( + current, + workInProgress, + ctor, + instance, + props, + renderExpirationTime + ))); + "function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4); + }, + resumeMountClassInstance: function(workInProgress, renderExpirationTime) { + var ctor = workInProgress.type, + instance = workInProgress.stateNode; + instance.props = workInProgress.memoizedProps; + instance.state = workInProgress.memoizedState; + var oldProps = workInProgress.memoizedProps, + newProps = workInProgress.pendingProps, + oldContext = instance.context, + newUnmaskedContext = getUnmaskedContext(workInProgress); + newUnmaskedContext = getMaskedContext(workInProgress, newUnmaskedContext); + (ctor = + "function" === typeof ctor.getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate) || + ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && + "function" !== typeof instance.componentWillReceiveProps) || + ((oldProps !== newProps || oldContext !== newUnmaskedContext) && + callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + newUnmaskedContext + )); + oldContext = workInProgress.memoizedState; + renderExpirationTime = + null !== workInProgress.updateQueue + ? processUpdateQueue( + null, + workInProgress, + workInProgress.updateQueue, + instance, + newProps, + renderExpirationTime + ) + : oldContext; + var derivedStateFromProps = void 0; + oldProps !== newProps && + (derivedStateFromProps = callGetDerivedStateFromProps( + workInProgress, + instance, + newProps, + renderExpirationTime + )); + if (null !== derivedStateFromProps && void 0 !== derivedStateFromProps) { + renderExpirationTime = + null === renderExpirationTime || void 0 === renderExpirationTime + ? derivedStateFromProps + : Object.assign({}, renderExpirationTime, derivedStateFromProps); + var _updateQueue = workInProgress.updateQueue; + null !== _updateQueue && + (_updateQueue.baseState = Object.assign( + {}, + _updateQueue.baseState, + derivedStateFromProps + )); + } + if ( + !( + oldProps !== newProps || + oldContext !== renderExpirationTime || + hasContextChanged() || + (null !== workInProgress.updateQueue && + workInProgress.updateQueue.hasForceUpdate) + ) + ) + return ( + "function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4), + !1 + ); + (oldProps = checkShouldComponentUpdate( + workInProgress, + oldProps, + newProps, + oldContext, + renderExpirationTime, + newUnmaskedContext + )) + ? (ctor || + ("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), + memoizeProps(workInProgress, newProps), + memoizeState(workInProgress, renderExpirationTime)); + instance.props = newProps; + instance.state = renderExpirationTime; + instance.context = newUnmaskedContext; + return oldProps; + }, + updateClassInstance: function( + current, + workInProgress, + renderExpirationTime + ) { + var ctor = workInProgress.type, + instance = workInProgress.stateNode; + instance.props = workInProgress.memoizedProps; + instance.state = workInProgress.memoizedState; + var oldProps = workInProgress.memoizedProps, + newProps = workInProgress.pendingProps, + oldContext = instance.context, + newUnmaskedContext = getUnmaskedContext(workInProgress); + newUnmaskedContext = getMaskedContext(workInProgress, newUnmaskedContext); + (ctor = + "function" === typeof ctor.getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate) || + ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && + "function" !== typeof instance.componentWillReceiveProps) || + ((oldProps !== newProps || oldContext !== newUnmaskedContext) && + callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + newUnmaskedContext + )); + oldContext = workInProgress.memoizedState; + renderExpirationTime = + null !== workInProgress.updateQueue + ? processUpdateQueue( + current, + workInProgress, + workInProgress.updateQueue, + instance, + newProps, + renderExpirationTime + ) + : oldContext; + var derivedStateFromProps = void 0; + oldProps !== newProps && + (derivedStateFromProps = callGetDerivedStateFromProps( + workInProgress, + instance, + newProps, + renderExpirationTime + )); + if (null !== derivedStateFromProps && void 0 !== derivedStateFromProps) { + renderExpirationTime = + null === renderExpirationTime || void 0 === renderExpirationTime + ? derivedStateFromProps + : Object.assign({}, renderExpirationTime, derivedStateFromProps); + var _updateQueue3 = workInProgress.updateQueue; + null !== _updateQueue3 && + (_updateQueue3.baseState = Object.assign( + {}, + _updateQueue3.baseState, + derivedStateFromProps + )); + } + if ( + !( + oldProps !== newProps || + oldContext !== renderExpirationTime || + hasContextChanged() || + (null !== workInProgress.updateQueue && + workInProgress.updateQueue.hasForceUpdate) + ) + ) + return ( + "function" !== typeof instance.componentDidUpdate || + (oldProps === current.memoizedProps && + oldContext === current.memoizedState) || + (workInProgress.effectTag |= 4), + "function" !== typeof instance.getSnapshotBeforeUpdate || + (oldProps === current.memoizedProps && + oldContext === current.memoizedState) || + (workInProgress.effectTag |= 2048), + !1 + ); + (derivedStateFromProps = checkShouldComponentUpdate( + workInProgress, + oldProps, + newProps, + oldContext, + renderExpirationTime, + newUnmaskedContext + )) + ? (ctor || + ("function" !== typeof instance.UNSAFE_componentWillUpdate && + "function" !== typeof instance.componentWillUpdate) || + ("function" === typeof instance.componentWillUpdate && + instance.componentWillUpdate( + newProps, + renderExpirationTime, + newUnmaskedContext + ), + "function" === typeof instance.UNSAFE_componentWillUpdate && + instance.UNSAFE_componentWillUpdate( + newProps, + renderExpirationTime, + newUnmaskedContext + )), + "function" === typeof instance.componentDidUpdate && + (workInProgress.effectTag |= 4), + "function" === typeof instance.getSnapshotBeforeUpdate && + (workInProgress.effectTag |= 2048)) + : ("function" !== typeof instance.componentDidUpdate || + (oldProps === current.memoizedProps && + oldContext === current.memoizedState) || + (workInProgress.effectTag |= 4), + "function" !== typeof instance.getSnapshotBeforeUpdate || + (oldProps === current.memoizedProps && + oldContext === current.memoizedState) || + (workInProgress.effectTag |= 2048), + memoizeProps(workInProgress, newProps), + memoizeState(workInProgress, renderExpirationTime)); + instance.props = newProps; + instance.state = renderExpirationTime; + instance.context = newUnmaskedContext; + return derivedStateFromProps; + } + }; +} +var isArray$1 = Array.isArray; +function coerceRef(returnFiber, current, element) { + returnFiber = element.ref; + if ( + null !== returnFiber && + "function" !== typeof returnFiber && + "object" !== typeof returnFiber + ) { + if (element._owner) { + element = element._owner; + var inst = void 0; + element && + (invariant( + 2 === element.tag, + "Stateless function components cannot have refs." + ), + (inst = element.stateNode)); + invariant( + inst, + "Missing owner for string ref %s. This error is likely caused by a bug in React. Please file an issue.", + returnFiber + ); + var stringRef = "" + returnFiber; + if ( + null !== current && + null !== current.ref && + current.ref._stringRef === stringRef + ) + return current.ref; + current = function(value) { + var refs = inst.refs === emptyObject ? (inst.refs = {}) : inst.refs; + null === value ? delete refs[stringRef] : (refs[stringRef] = value); + }; + current._stringRef = stringRef; + return current; + } + invariant( + "string" === typeof returnFiber, + "Expected ref to be a function or a string." + ); + invariant( + element._owner, + "Element ref was specified as a string (%s) but no owner was set. This could happen for one of the following reasons:\n1. You may be adding a ref to a functional 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.", + returnFiber + ); + } + return returnFiber; +} +function throwOnInvalidObjectType(returnFiber, newChild) { + "textarea" !== returnFiber.type && + invariant( + !1, + "Objects are not valid as a React child (found: %s).%s", + "[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, textContent, expirationTime) { + if (null === current || 6 !== current.tag) + return ( + (current = createFiberFromText( + textContent, + returnFiber.mode, + expirationTime + )), + (current["return"] = returnFiber), + current + ); + current = useFiber(current, textContent, expirationTime); + current["return"] = returnFiber; + return current; + } + function updateElement(returnFiber, current, element, expirationTime) { + if (null !== current && current.type === element.type) + return ( + (expirationTime = useFiber(current, element.props, expirationTime)), + (expirationTime.ref = coerceRef(returnFiber, current, element)), + (expirationTime["return"] = returnFiber), + expirationTime + ); + expirationTime = createFiberFromElement( + element, + returnFiber.mode, + expirationTime + ); + expirationTime.ref = coerceRef(returnFiber, current, element); + expirationTime["return"] = returnFiber; + return expirationTime; + } + function updatePortal(returnFiber, current, portal, expirationTime) { + if ( + null === current || + 4 !== current.tag || + current.stateNode.containerInfo !== portal.containerInfo || + current.stateNode.implementation !== portal.implementation + ) + return ( + (current = createFiberFromPortal( + portal, + returnFiber.mode, + expirationTime + )), + (current["return"] = returnFiber), + current + ); + current = useFiber(current, portal.children || [], expirationTime); + current["return"] = returnFiber; + return current; + } + function updateFragment(returnFiber, current, fragment, expirationTime, key) { + if (null === current || 10 !== current.tag) + return ( + (current = createFiberFromFragment( + fragment, + returnFiber.mode, + expirationTime, + key + )), + (current["return"] = returnFiber), + current + ); + current = useFiber(current, fragment, expirationTime); + current["return"] = returnFiber; + return current; + } + 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 = createFiberFromElement( + newChild, + 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$1(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$1(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$1(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++) + if ( + (oldFiber = createChild( + returnFiber, + newChildren[newIdx], + expirationTime + )) + ) + (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++ + ) + if ( + (nextOldFiber = updateFromMap( + oldFiber, + returnFiber, + newIdx, + newChildren[newIdx], + expirationTime + )) + ) { + if (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); + invariant( + "function" === typeof iteratorFn, + "An object is not an iterable. This error is likely caused by a bug in React. Please file an issue." + ); + newChildrenIterable = iteratorFn.call(newChildrenIterable); + invariant( + null != newChildrenIterable, + "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) { + 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() + ) + if ( + ((step = updateFromMap( + oldFiber, + returnFiber, + newIdx, + step.value, + expirationTime + )), + null !== step) + ) { + if (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) { + "object" === typeof newChild && + null !== newChild && + newChild.type === REACT_FRAGMENT_TYPE && + null === newChild.key && + (newChild = newChild.props.children); + var isObject = "object" === typeof newChild && null !== newChild; + if (isObject) + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + a: { + var key = newChild.key; + for (isObject = currentFirstChild; null !== isObject; ) { + if (isObject.key === key) + if ( + 10 === isObject.tag + ? newChild.type === REACT_FRAGMENT_TYPE + : isObject.type === newChild.type + ) { + deleteRemainingChildren(returnFiber, isObject.sibling); + currentFirstChild = useFiber( + isObject, + newChild.type === REACT_FRAGMENT_TYPE + ? newChild.props.children + : newChild.props, + expirationTime + ); + currentFirstChild.ref = coerceRef( + returnFiber, + isObject, + newChild + ); + currentFirstChild["return"] = returnFiber; + returnFiber = currentFirstChild; + break a; + } else { + deleteRemainingChildren(returnFiber, isObject); + break; + } + else deleteChild(returnFiber, isObject); + isObject = isObject.sibling; + } + newChild.type === REACT_FRAGMENT_TYPE + ? ((currentFirstChild = createFiberFromFragment( + newChild.props.children, + returnFiber.mode, + expirationTime, + newChild.key + )), + (currentFirstChild["return"] = returnFiber), + (returnFiber = currentFirstChild)) + : ((expirationTime = createFiberFromElement( + newChild, + returnFiber.mode, + expirationTime + )), + (expirationTime.ref = coerceRef( + returnFiber, + currentFirstChild, + newChild + )), + (expirationTime["return"] = returnFiber), + (returnFiber = expirationTime)); + } + return placeSingleChild(returnFiber); + case REACT_PORTAL_TYPE: + a: { + for (isObject = newChild.key; null !== currentFirstChild; ) { + if (currentFirstChild.key === isObject) + 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; + } else { + 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$1(newChild)) + return reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ); + if (getIteratorFn(newChild)) + return reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ); + isObject && throwOnInvalidObjectType(returnFiber, newChild); + if ("undefined" === typeof newChild) + switch (returnFiber.tag) { + case 2: + case 1: + (expirationTime = returnFiber.type), + invariant( + !1, + "%s(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.", + expirationTime.displayName || expirationTime.name || "Component" + ); + } + return deleteRemainingChildren(returnFiber, currentFirstChild); + }; +} +var reconcileChildFibers = ChildReconciler(!0), + mountChildFibers = ChildReconciler(!1); +function ReactFiberBeginWork( + config, + hostContext, + legacyContext, + newContext, + hydrationContext, + scheduleWork, + computeExpirationForFiber +) { + function reconcileChildren(current, workInProgress, nextChildren) { + reconcileChildrenAtExpirationTime( + current, + workInProgress, + nextChildren, + workInProgress.expirationTime + ); + } + function reconcileChildrenAtExpirationTime( + current, + workInProgress, + nextChildren, + renderExpirationTime + ) { + workInProgress.child = + null === current + ? mountChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ) + : reconcileChildFibers( + workInProgress, + current.child, + nextChildren, + renderExpirationTime + ); + } + function markRef(current, workInProgress) { + var ref = workInProgress.ref; + if ( + (null === current && null !== ref) || + (null !== current && current.ref !== ref) + ) + workInProgress.effectTag |= 128; + } + function finishClassComponent( + current, + workInProgress, + shouldUpdate, + hasContext, + didCaptureError, + renderExpirationTime + ) { + markRef(current, workInProgress); + if (!shouldUpdate && !didCaptureError) + return ( + hasContext && invalidateContextProvider(workInProgress, !1), + bailoutOnAlreadyFinishedWork(current, workInProgress) + ); + shouldUpdate = workInProgress.stateNode; + ReactCurrentOwner.current = workInProgress; + var nextChildren = didCaptureError ? null : shouldUpdate.render(); + workInProgress.effectTag |= 1; + didCaptureError && + (reconcileChildrenAtExpirationTime( + current, + workInProgress, + null, + renderExpirationTime + ), + (workInProgress.child = null)); + reconcileChildrenAtExpirationTime( + current, + workInProgress, + nextChildren, + renderExpirationTime + ); + workInProgress.memoizedState = shouldUpdate.state; + workInProgress.memoizedProps = shouldUpdate.props; + hasContext && invalidateContextProvider(workInProgress, !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 propagateContextChange( + workInProgress, + context, + changedBits, + renderExpirationTime + ) { + var fiber = workInProgress.child; + for ( + null !== fiber && (fiber["return"] = workInProgress); + null !== fiber; + + ) { + switch (fiber.tag) { + case 12: + var nextFiber = fiber.stateNode | 0; + if (fiber.type === context && 0 !== (nextFiber & changedBits)) { + for (nextFiber = fiber; null !== nextFiber; ) { + var alternate = nextFiber.alternate; + if ( + 0 === nextFiber.expirationTime || + nextFiber.expirationTime > renderExpirationTime + ) + (nextFiber.expirationTime = renderExpirationTime), + null !== alternate && + (0 === alternate.expirationTime || + alternate.expirationTime > renderExpirationTime) && + (alternate.expirationTime = renderExpirationTime); + else if ( + null !== alternate && + (0 === alternate.expirationTime || + alternate.expirationTime > renderExpirationTime) + ) + alternate.expirationTime = renderExpirationTime; + else break; + nextFiber = nextFiber["return"]; + } + nextFiber = null; + } else nextFiber = fiber.child; + break; + case 13: + nextFiber = fiber.type === workInProgress.type ? null : fiber.child; + break; + default: + nextFiber = fiber.child; + } + if (null !== nextFiber) nextFiber["return"] = fiber; + else + for (nextFiber = fiber; null !== nextFiber; ) { + if (nextFiber === workInProgress) { + nextFiber = null; + break; + } + fiber = nextFiber.sibling; + if (null !== fiber) { + nextFiber = fiber; + break; + } + nextFiber = nextFiber["return"]; + } + fiber = nextFiber; + } + } + function updateContextProvider( + current, + workInProgress, + renderExpirationTime + ) { + var context = workInProgress.type._context, + newProps = workInProgress.pendingProps, + oldProps = workInProgress.memoizedProps; + if (!hasLegacyContextChanged() && oldProps === newProps) + return ( + (workInProgress.stateNode = 0), + pushProvider(workInProgress), + bailoutOnAlreadyFinishedWork(current, workInProgress) + ); + var newValue = newProps.value; + workInProgress.memoizedProps = newProps; + if (null === oldProps) newValue = 1073741823; + else if (oldProps.value === newProps.value) { + if (oldProps.children === newProps.children) + return ( + (workInProgress.stateNode = 0), + pushProvider(workInProgress), + bailoutOnAlreadyFinishedWork(current, workInProgress) + ); + newValue = 0; + } else { + var oldValue = oldProps.value; + if ( + (oldValue === newValue && + (0 !== oldValue || 1 / oldValue === 1 / newValue)) || + (oldValue !== oldValue && newValue !== newValue) + ) { + if (oldProps.children === newProps.children) + return ( + (workInProgress.stateNode = 0), + pushProvider(workInProgress), + bailoutOnAlreadyFinishedWork(current, workInProgress) + ); + newValue = 0; + } else if ( + ((newValue = + "function" === typeof context._calculateChangedBits + ? context._calculateChangedBits(oldValue, newValue) + : 1073741823), + (newValue |= 0), + 0 === newValue) + ) { + if (oldProps.children === newProps.children) + return ( + (workInProgress.stateNode = 0), + pushProvider(workInProgress), + bailoutOnAlreadyFinishedWork(current, workInProgress) + ); + } else + propagateContextChange( + workInProgress, + context, + newValue, + renderExpirationTime + ); + } + workInProgress.stateNode = newValue; + pushProvider(workInProgress); + reconcileChildren(current, workInProgress, newProps.children); + return workInProgress.child; + } + function bailoutOnAlreadyFinishedWork(current, workInProgress) { + invariant( + null === current || workInProgress.child === current.child, + "Resuming work not yet implemented." + ); + if (null !== workInProgress.child) { + current = workInProgress.child; + var newChild = createWorkInProgress( + current, + current.pendingProps, + current.expirationTime + ); + workInProgress.child = newChild; + for (newChild["return"] = workInProgress; null !== current.sibling; ) + (current = current.sibling), + (newChild = newChild.sibling = createWorkInProgress( + current, + current.pendingProps, + current.expirationTime + )), + (newChild["return"] = workInProgress); + newChild.sibling = null; + } + return workInProgress.child; + } + var shouldSetTextContent = config.shouldSetTextContent, + shouldDeprioritizeSubtree = config.shouldDeprioritizeSubtree, + pushHostContext = hostContext.pushHostContext, + pushHostContainer = hostContext.pushHostContainer, + pushProvider = newContext.pushProvider, + getMaskedContext = legacyContext.getMaskedContext, + getUnmaskedContext = legacyContext.getUnmaskedContext, + hasLegacyContextChanged = legacyContext.hasContextChanged, + pushLegacyContextProvider = legacyContext.pushContextProvider, + pushTopLevelContextObject = legacyContext.pushTopLevelContextObject, + invalidateContextProvider = legacyContext.invalidateContextProvider, + enterHydrationState = hydrationContext.enterHydrationState, + resetHydrationState = hydrationContext.resetHydrationState, + tryToClaimNextHydratableInstance = + hydrationContext.tryToClaimNextHydratableInstance; + config = ReactFiberClassComponent( + legacyContext, + scheduleWork, + computeExpirationForFiber, + function(workInProgress, nextProps) { + workInProgress.memoizedProps = nextProps; + }, + function(workInProgress, nextState) { + workInProgress.memoizedState = nextState; + } + ); + var adoptClassInstance = config.adoptClassInstance, + callGetDerivedStateFromProps = config.callGetDerivedStateFromProps, + constructClassInstance = config.constructClassInstance, + mountClassInstance = config.mountClassInstance, + resumeMountClassInstance = config.resumeMountClassInstance, + updateClassInstance = config.updateClassInstance; + return { + beginWork: function(current, workInProgress, renderExpirationTime) { + if ( + 0 === workInProgress.expirationTime || + workInProgress.expirationTime > renderExpirationTime + ) { + switch (workInProgress.tag) { + case 3: + pushHostRootContext(workInProgress); + break; + case 2: + pushLegacyContextProvider(workInProgress); + break; + case 4: + pushHostContainer( + workInProgress, + workInProgress.stateNode.containerInfo + ); + break; + case 13: + pushProvider(workInProgress); + } + return null; + } + switch (workInProgress.tag) { + case 0: + invariant( + null === current, + "An indeterminate component should never have mounted. This error is likely caused by a bug in React. Please file an issue." + ); + var fn = workInProgress.type, + props = workInProgress.pendingProps, + unmaskedContext = getUnmaskedContext(workInProgress); + unmaskedContext = getMaskedContext(workInProgress, unmaskedContext); + fn = fn(props, unmaskedContext); + workInProgress.effectTag |= 1; + "object" === typeof fn && + null !== fn && + "function" === typeof fn.render && + void 0 === fn.$$typeof + ? ((unmaskedContext = workInProgress.type), + (workInProgress.tag = 2), + (workInProgress.memoizedState = + null !== fn.state && void 0 !== fn.state ? fn.state : null), + "function" === typeof unmaskedContext.getDerivedStateFromProps && + ((props = callGetDerivedStateFromProps( + workInProgress, + fn, + props, + workInProgress.memoizedState + )), + null !== props && + void 0 !== props && + (workInProgress.memoizedState = Object.assign( + {}, + workInProgress.memoizedState, + props + ))), + (props = pushLegacyContextProvider(workInProgress)), + adoptClassInstance(workInProgress, fn), + mountClassInstance(workInProgress, renderExpirationTime), + (current = finishClassComponent( + current, + workInProgress, + !0, + props, + !1, + renderExpirationTime + ))) + : ((workInProgress.tag = 1), + reconcileChildren(current, workInProgress, fn), + (workInProgress.memoizedProps = props), + (current = workInProgress.child)); + return current; + case 1: + return ( + (props = workInProgress.type), + (renderExpirationTime = workInProgress.pendingProps), + hasLegacyContextChanged() || + workInProgress.memoizedProps !== renderExpirationTime + ? ((fn = getUnmaskedContext(workInProgress)), + (fn = getMaskedContext(workInProgress, fn)), + (props = props(renderExpirationTime, fn)), + (workInProgress.effectTag |= 1), + reconcileChildren(current, workInProgress, props), + (workInProgress.memoizedProps = renderExpirationTime), + (current = workInProgress.child)) + : (current = bailoutOnAlreadyFinishedWork( + current, + workInProgress + )), + current + ); + case 2: + props = pushLegacyContextProvider(workInProgress); + null === current + ? null === workInProgress.stateNode + ? (constructClassInstance( + workInProgress, + workInProgress.pendingProps + ), + mountClassInstance(workInProgress, renderExpirationTime), + (fn = !0)) + : (fn = resumeMountClassInstance( + workInProgress, + renderExpirationTime + )) + : (fn = updateClassInstance( + current, + workInProgress, + renderExpirationTime + )); + unmaskedContext = !1; + var updateQueue = workInProgress.updateQueue; + null !== updateQueue && + null !== updateQueue.capturedValues && + (unmaskedContext = fn = !0); + return finishClassComponent( + current, + workInProgress, + fn, + props, + unmaskedContext, + renderExpirationTime + ); + case 3: + a: if ( + (pushHostRootContext(workInProgress), + (fn = workInProgress.updateQueue), + null !== fn) + ) { + unmaskedContext = workInProgress.memoizedState; + props = processUpdateQueue( + current, + workInProgress, + fn, + null, + null, + renderExpirationTime + ); + workInProgress.memoizedState = props; + fn = workInProgress.updateQueue; + if (null !== fn && null !== fn.capturedValues) fn = null; + else if (unmaskedContext === props) { + resetHydrationState(); + current = bailoutOnAlreadyFinishedWork(current, workInProgress); + break a; + } else fn = props.element; + unmaskedContext = workInProgress.stateNode; + (null === current || null === current.child) && + unmaskedContext.hydrate && + enterHydrationState(workInProgress) + ? ((workInProgress.effectTag |= 2), + (workInProgress.child = mountChildFibers( + workInProgress, + null, + fn, + renderExpirationTime + ))) + : (resetHydrationState(), + reconcileChildren(current, workInProgress, fn)); + workInProgress.memoizedState = props; + current = workInProgress.child; + } else + resetHydrationState(), + (current = bailoutOnAlreadyFinishedWork(current, workInProgress)); + return current; + case 5: + a: { + pushHostContext(workInProgress); + null === current && + tryToClaimNextHydratableInstance(workInProgress); + props = workInProgress.type; + updateQueue = workInProgress.memoizedProps; + fn = workInProgress.pendingProps; + unmaskedContext = null !== current ? current.memoizedProps : null; + if (!hasLegacyContextChanged() && updateQueue === fn) { + if ( + (updateQueue = + workInProgress.mode & 1 && + shouldDeprioritizeSubtree(props, fn)) + ) + workInProgress.expirationTime = 1073741823; + if (!updateQueue || 1073741823 !== renderExpirationTime) { + current = bailoutOnAlreadyFinishedWork(current, workInProgress); + break a; + } + } + updateQueue = fn.children; + shouldSetTextContent(props, fn) + ? (updateQueue = null) + : unmaskedContext && + shouldSetTextContent(props, unmaskedContext) && + (workInProgress.effectTag |= 16); + markRef(current, workInProgress); + 1073741823 !== renderExpirationTime && + workInProgress.mode & 1 && + shouldDeprioritizeSubtree(props, fn) + ? ((workInProgress.expirationTime = 1073741823), + (workInProgress.memoizedProps = fn), + (current = null)) + : (reconcileChildren(current, workInProgress, updateQueue), + (workInProgress.memoizedProps = fn), + (current = workInProgress.child)); + } + return current; + case 6: + return ( + null === current && + tryToClaimNextHydratableInstance(workInProgress), + (workInProgress.memoizedProps = workInProgress.pendingProps), + null + ); + case 8: + workInProgress.tag = 7; + case 7: + return ( + (props = workInProgress.pendingProps), + hasLegacyContextChanged() || + workInProgress.memoizedProps !== props || + (props = workInProgress.memoizedProps), + (fn = props.children), + (workInProgress.stateNode = + null === current + ? mountChildFibers( + workInProgress, + workInProgress.stateNode, + fn, + renderExpirationTime + ) + : reconcileChildFibers( + workInProgress, + current.stateNode, + fn, + renderExpirationTime + )), + (workInProgress.memoizedProps = props), + workInProgress.stateNode + ); + case 9: + return null; + case 4: + return ( + pushHostContainer( + workInProgress, + workInProgress.stateNode.containerInfo + ), + (props = workInProgress.pendingProps), + hasLegacyContextChanged() || workInProgress.memoizedProps !== props + ? (null === current + ? (workInProgress.child = reconcileChildFibers( + workInProgress, + null, + props, + renderExpirationTime + )) + : reconcileChildren(current, workInProgress, props), + (workInProgress.memoizedProps = props), + (current = workInProgress.child)) + : (current = bailoutOnAlreadyFinishedWork( + current, + workInProgress + )), + current + ); + case 14: + return ( + (renderExpirationTime = workInProgress.type.render), + (renderExpirationTime = renderExpirationTime( + workInProgress.pendingProps, + workInProgress.ref + )), + reconcileChildren(current, workInProgress, renderExpirationTime), + (workInProgress.memoizedProps = renderExpirationTime), + workInProgress.child + ); + case 10: + return ( + (renderExpirationTime = workInProgress.pendingProps), + hasLegacyContextChanged() || + workInProgress.memoizedProps !== renderExpirationTime + ? (reconcileChildren( + current, + workInProgress, + renderExpirationTime + ), + (workInProgress.memoizedProps = renderExpirationTime), + (current = workInProgress.child)) + : (current = bailoutOnAlreadyFinishedWork( + current, + workInProgress + )), + current + ); + case 11: + return ( + (renderExpirationTime = workInProgress.pendingProps.children), + hasLegacyContextChanged() || + (null !== renderExpirationTime && + workInProgress.memoizedProps !== renderExpirationTime) + ? (reconcileChildren( + current, + workInProgress, + renderExpirationTime + ), + (workInProgress.memoizedProps = renderExpirationTime), + (current = workInProgress.child)) + : (current = bailoutOnAlreadyFinishedWork( + current, + workInProgress + )), + current + ); + case 13: + return updateContextProvider( + current, + workInProgress, + renderExpirationTime + ); + case 12: + a: { + fn = workInProgress.type; + unmaskedContext = workInProgress.pendingProps; + updateQueue = workInProgress.memoizedProps; + props = fn._currentValue; + var changedBits = fn._changedBits; + if ( + hasLegacyContextChanged() || + 0 !== changedBits || + updateQueue !== unmaskedContext + ) { + workInProgress.memoizedProps = unmaskedContext; + var observedBits = unmaskedContext.unstable_observedBits; + if (void 0 === observedBits || null === observedBits) + observedBits = 1073741823; + workInProgress.stateNode = observedBits; + if (0 !== (changedBits & observedBits)) + propagateContextChange( + workInProgress, + fn, + changedBits, + renderExpirationTime + ); + else if (updateQueue === unmaskedContext) { + current = bailoutOnAlreadyFinishedWork(current, workInProgress); + break a; + } + renderExpirationTime = unmaskedContext.children; + renderExpirationTime = renderExpirationTime(props); + reconcileChildren(current, workInProgress, renderExpirationTime); + current = workInProgress.child; + } else + current = bailoutOnAlreadyFinishedWork(current, workInProgress); + } + return current; + default: + invariant( + !1, + "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." + ); + } + } + }; +} +function ReactFiberCompleteWork( + config, + hostContext, + legacyContext, + newContext, + hydrationContext +) { + function markUpdate(workInProgress) { + workInProgress.effectTag |= 4; + } + var createInstance = config.createInstance, + createTextInstance = config.createTextInstance, + appendInitialChild = config.appendInitialChild, + finalizeInitialChildren = config.finalizeInitialChildren, + prepareUpdate = config.prepareUpdate, + persistence = config.persistence, + getRootHostContainer = hostContext.getRootHostContainer, + popHostContext = hostContext.popHostContext, + getHostContext = hostContext.getHostContext, + popHostContainer = hostContext.popHostContainer, + popLegacyContextProvider = legacyContext.popContextProvider, + popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject, + popProvider = newContext.popProvider, + prepareToHydrateHostInstance = + hydrationContext.prepareToHydrateHostInstance, + prepareToHydrateHostTextInstance = + hydrationContext.prepareToHydrateHostTextInstance, + popHydrationState = hydrationContext.popHydrationState, + updateHostContainer = void 0, + updateHostComponent = void 0, + updateHostText = void 0; + config.mutation + ? ((updateHostContainer = function() {}), + (updateHostComponent = function(current, workInProgress, updatePayload) { + (workInProgress.updateQueue = updatePayload) && + markUpdate(workInProgress); + }), + (updateHostText = function(current, workInProgress, oldText, newText) { + oldText !== newText && markUpdate(workInProgress); + })) + : persistence + ? invariant(!1, "Persistent reconciler is disabled.") + : invariant(!1, "Noop reconciler is disabled."); + return { + completeWork: function(current, workInProgress, renderExpirationTime) { + var newProps = workInProgress.pendingProps; + switch (workInProgress.tag) { + case 1: + return null; + case 2: + return ( + popLegacyContextProvider(workInProgress), + (current = workInProgress.stateNode), + (newProps = workInProgress.updateQueue), + null !== newProps && + null !== newProps.capturedValues && + ((workInProgress.effectTag &= -65), + "function" === typeof current.componentDidCatch + ? (workInProgress.effectTag |= 256) + : (newProps.capturedValues = null)), + null + ); + case 3: + popHostContainer(workInProgress); + popTopLevelLegacyContextObject(workInProgress); + newProps = workInProgress.stateNode; + newProps.pendingContext && + ((newProps.context = newProps.pendingContext), + (newProps.pendingContext = null)); + if (null === current || null === current.child) + popHydrationState(workInProgress), (workInProgress.effectTag &= -3); + updateHostContainer(workInProgress); + current = workInProgress.updateQueue; + null !== current && + null !== current.capturedValues && + (workInProgress.effectTag |= 256); + return null; + case 5: + popHostContext(workInProgress); + renderExpirationTime = getRootHostContainer(); + var type = workInProgress.type; + if (null !== current && null != workInProgress.stateNode) { + var oldProps = current.memoizedProps, + _instance = workInProgress.stateNode, + currentHostContext = getHostContext(); + _instance = prepareUpdate( + _instance, + type, + oldProps, + newProps, + renderExpirationTime, + currentHostContext + ); + updateHostComponent( + current, + workInProgress, + _instance, + type, + oldProps, + newProps, + renderExpirationTime, + currentHostContext + ); + current.ref !== workInProgress.ref && + (workInProgress.effectTag |= 128); + } else { + if (!newProps) + return ( + invariant( + null !== workInProgress.stateNode, + "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." + ), + null + ); + current = getHostContext(); + if (popHydrationState(workInProgress)) + prepareToHydrateHostInstance( + workInProgress, + renderExpirationTime, + current + ) && markUpdate(workInProgress); + else { + oldProps = createInstance( + type, + newProps, + renderExpirationTime, + current, + workInProgress + ); + a: for ( + currentHostContext = workInProgress.child; + null !== currentHostContext; + + ) { + if ( + 5 === currentHostContext.tag || + 6 === currentHostContext.tag + ) + appendInitialChild(oldProps, currentHostContext.stateNode); + else if ( + 4 !== currentHostContext.tag && + null !== currentHostContext.child + ) { + currentHostContext.child["return"] = currentHostContext; + currentHostContext = currentHostContext.child; + continue; + } + if (currentHostContext === workInProgress) break; + for (; null === currentHostContext.sibling; ) { + if ( + null === currentHostContext["return"] || + currentHostContext["return"] === workInProgress + ) + break a; + currentHostContext = currentHostContext["return"]; + } + currentHostContext.sibling["return"] = + currentHostContext["return"]; + currentHostContext = currentHostContext.sibling; + } + finalizeInitialChildren( + oldProps, + type, + newProps, + renderExpirationTime, + current + ) && markUpdate(workInProgress); + workInProgress.stateNode = oldProps; + } + null !== workInProgress.ref && (workInProgress.effectTag |= 128); + } + return null; + case 6: + if (current && null != workInProgress.stateNode) + updateHostText( + current, + workInProgress, + current.memoizedProps, + newProps + ); + else { + if ("string" !== typeof newProps) + return ( + invariant( + null !== workInProgress.stateNode, + "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." + ), + null + ); + current = getRootHostContainer(); + renderExpirationTime = getHostContext(); + popHydrationState(workInProgress) + ? prepareToHydrateHostTextInstance(workInProgress) && + markUpdate(workInProgress) + : (workInProgress.stateNode = createTextInstance( + newProps, + current, + renderExpirationTime, + workInProgress + )); + } + return null; + case 7: + newProps = workInProgress.memoizedProps; + invariant( + newProps, + "Should be resolved by now. This error is likely caused by a bug in React. Please file an issue." + ); + workInProgress.tag = 8; + type = []; + a: for ( + (oldProps = workInProgress.stateNode) && + (oldProps["return"] = workInProgress); + null !== oldProps; + + ) { + if (5 === oldProps.tag || 6 === oldProps.tag || 4 === oldProps.tag) + invariant(!1, "A call cannot have host component children."); + else if (9 === oldProps.tag) type.push(oldProps.pendingProps.value); + else if (null !== oldProps.child) { + oldProps.child["return"] = oldProps; + oldProps = oldProps.child; + continue; + } + for (; null === oldProps.sibling; ) { + if ( + null === oldProps["return"] || + oldProps["return"] === workInProgress + ) + break a; + oldProps = oldProps["return"]; + } + oldProps.sibling["return"] = oldProps["return"]; + oldProps = oldProps.sibling; + } + oldProps = newProps.handler; + newProps = oldProps(newProps.props, type); + workInProgress.child = reconcileChildFibers( + workInProgress, + null !== current ? current.child : null, + newProps, + renderExpirationTime + ); + return workInProgress.child; + case 8: + return (workInProgress.tag = 7), null; + case 9: + return null; + case 14: + return null; + case 10: + return null; + case 11: + return null; + case 4: + return ( + popHostContainer(workInProgress), + updateHostContainer(workInProgress), + null + ); + case 13: + return popProvider(workInProgress), null; + case 12: + return null; + case 0: + invariant( + !1, + "An indeterminate component should have become determinate before completing. This error is likely caused by a bug in React. Please file an issue." + ); + default: + invariant( + !1, + "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." + ); + } + } + }; +} +function ReactFiberUnwindWork( + hostContext, + legacyContext, + newContext, + scheduleWork, + isAlreadyFailedLegacyErrorBoundary +) { + var popHostContainer = hostContext.popHostContainer, + popHostContext = hostContext.popHostContext, + popLegacyContextProvider = legacyContext.popContextProvider, + popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject, + popProvider = newContext.popProvider; + return { + throwException: function(returnFiber, sourceFiber, rawValue) { + sourceFiber.effectTag |= 512; + sourceFiber.firstEffect = sourceFiber.lastEffect = null; + sourceFiber = { + value: rawValue, + source: sourceFiber, + stack: getStackAddendumByWorkInProgressFiber(sourceFiber) + }; + do { + switch (returnFiber.tag) { + case 3: + ensureUpdateQueues(returnFiber); + returnFiber.updateQueue.capturedValues = [sourceFiber]; + returnFiber.effectTag |= 1024; + return; + case 2: + if ( + ((rawValue = returnFiber.stateNode), + 0 === (returnFiber.effectTag & 64) && + null !== rawValue && + "function" === typeof rawValue.componentDidCatch && + !isAlreadyFailedLegacyErrorBoundary(rawValue)) + ) { + ensureUpdateQueues(returnFiber); + rawValue = returnFiber.updateQueue; + var capturedValues = rawValue.capturedValues; + null === capturedValues + ? (rawValue.capturedValues = [sourceFiber]) + : capturedValues.push(sourceFiber); + returnFiber.effectTag |= 1024; + return; + } + } + returnFiber = returnFiber["return"]; + } while (null !== returnFiber); + }, + unwindWork: function(workInProgress) { + switch (workInProgress.tag) { + case 2: + popLegacyContextProvider(workInProgress); + var effectTag = workInProgress.effectTag; + return effectTag & 1024 + ? ((workInProgress.effectTag = (effectTag & -1025) | 64), + workInProgress) + : null; + case 3: + return ( + popHostContainer(workInProgress), + popTopLevelLegacyContextObject(workInProgress), + (effectTag = workInProgress.effectTag), + effectTag & 1024 + ? ((workInProgress.effectTag = (effectTag & -1025) | 64), + workInProgress) + : null + ); + case 5: + return popHostContext(workInProgress), null; + case 4: + return popHostContainer(workInProgress), null; + case 13: + return popProvider(workInProgress), null; + default: + return null; + } + }, + unwindInterruptedWork: function(interruptedWork) { + switch (interruptedWork.tag) { + case 2: + popLegacyContextProvider(interruptedWork); + break; + case 3: + popHostContainer(interruptedWork); + popTopLevelLegacyContextObject(interruptedWork); + break; + case 5: + popHostContext(interruptedWork); + break; + case 4: + popHostContainer(interruptedWork); + break; + case 13: + popProvider(interruptedWork); + } + } + }; +} +function logError(boundary, errorInfo) { + var source = errorInfo.source, + stack = errorInfo.stack; + null === stack && (stack = getStackAddendumByWorkInProgressFiber(source)); + null !== source && getComponentName(source); + source = null !== stack ? stack : ""; + errorInfo = errorInfo.value; + null !== boundary && 2 === boundary.tag && getComponentName(boundary); + try { + if (errorInfo instanceof Error) { + var message = errorInfo.message, + name = errorInfo.name; + var errorToHandle = errorInfo; + try { + errorToHandle.message = + (message ? name + ": " + message : name) + + "\n\nThis error is located at:" + + source; + } catch (e) {} + } else + errorToHandle = + "string" === typeof errorInfo + ? Error(errorInfo + "\n\nThis error is located at:" + source) + : Error("Unspecified error at:" + source); + ExceptionsManager.handleException(errorToHandle, !1); + } catch (e) { + (e && e.suppressReactErrorLogging) || console.error(e); + } +} +function ReactFiberCommitWork( + config, + captureError, + scheduleWork, + computeExpirationForFiber, + markLegacyErrorBoundaryAsFailed +) { + function safelyDetachRef(current) { + var ref = current.ref; + if (null !== ref) + if ("function" === typeof ref) + try { + ref(null); + } catch (refError) { + captureError(current, refError); + } + else ref.current = null; + } + function commitUnmount(current) { + "function" === typeof onCommitUnmount && onCommitUnmount(current); + switch (current.tag) { + case 2: + safelyDetachRef(current); + var _instance7 = current.stateNode; + if ("function" === typeof _instance7.componentWillUnmount) + try { + (_instance7.props = current.memoizedProps), + (_instance7.state = current.memoizedState), + _instance7.componentWillUnmount(); + } catch (unmountError) { + captureError(current, unmountError); + } + break; + case 5: + safelyDetachRef(current); + break; + case 7: + commitNestedUnmounts(current.stateNode); + break; + case 4: + mutation && unmountHostComponents(current); + } + } + function commitNestedUnmounts(root) { + for (var node = root; ; ) + if ( + (commitUnmount(node), + null === node.child || (mutation && 4 === node.tag)) + ) { + if (node === root) break; + for (; null === node.sibling; ) { + if (null === node["return"] || node["return"] === root) return; + node = node["return"]; + } + node.sibling["return"] = node["return"]; + node = node.sibling; + } else (node.child["return"] = node), (node = node.child); + } + function isHostParent(fiber) { + return 5 === fiber.tag || 3 === fiber.tag || 4 === fiber.tag; + } + function unmountHostComponents(current) { + for ( + var node = current, + currentParentIsValid = !1, + currentParent = void 0, + currentParentIsContainer = void 0; + ; + + ) { + if (!currentParentIsValid) { + currentParentIsValid = node["return"]; + a: for (;;) { + invariant( + null !== currentParentIsValid, + "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) + commitNestedUnmounts(node), + currentParentIsContainer + ? removeChildFromContainer(currentParent, node.stateNode) + : removeChild(currentParent, node.stateNode); + else if ( + (4 === node.tag + ? (currentParent = node.stateNode.containerInfo) + : commitUnmount(node), + null !== node.child) + ) { + node.child["return"] = node; + node = node.child; + continue; + } + if (node === current) break; + for (; null === node.sibling; ) { + if (null === node["return"] || node["return"] === current) return; + node = node["return"]; + 4 === node.tag && (currentParentIsValid = !1); + } + node.sibling["return"] = node["return"]; + node = node.sibling; + } + } + var getPublicInstance = config.getPublicInstance, + mutation = config.mutation; + config = config.persistence; + mutation || + (config + ? invariant(!1, "Persistent reconciler is disabled.") + : invariant(!1, "Noop reconciler is disabled.")); + var commitMount = mutation.commitMount, + commitUpdate = mutation.commitUpdate, + resetTextContent = mutation.resetTextContent, + commitTextUpdate = mutation.commitTextUpdate, + appendChild = mutation.appendChild, + appendChildToContainer = mutation.appendChildToContainer, + insertBefore = mutation.insertBefore, + insertInContainerBefore = mutation.insertInContainerBefore, + removeChild = mutation.removeChild, + removeChildFromContainer = mutation.removeChildFromContainer; + return { + commitBeforeMutationLifeCycles: function(current, finishedWork) { + switch (finishedWork.tag) { + case 2: + if (finishedWork.effectTag & 2048 && null !== current) { + var prevProps = current.memoizedProps, + prevState = current.memoizedState; + current = finishedWork.stateNode; + current.props = finishedWork.memoizedProps; + current.state = finishedWork.memoizedState; + finishedWork = current.getSnapshotBeforeUpdate( + prevProps, + prevState + ); + current.__reactInternalSnapshotBeforeUpdate = finishedWork; + } + break; + case 3: + case 5: + case 6: + case 4: + break; + default: + invariant( + !1, + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + }, + commitResetTextContent: function(current) { + resetTextContent(current.stateNode); + }, + commitPlacement: function(finishedWork) { + a: { + for (var parent = finishedWork["return"]; null !== parent; ) { + if (isHostParent(parent)) { + var parentFiber = parent; + break a; + } + parent = parent["return"]; + } + invariant( + !1, + "Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue." + ); + parentFiber = void 0; + } + var isContainer = (parent = void 0); + switch (parentFiber.tag) { + case 5: + parent = parentFiber.stateNode; + isContainer = !1; + break; + case 3: + parent = parentFiber.stateNode.containerInfo; + isContainer = !0; + break; + case 4: + parent = parentFiber.stateNode.containerInfo; + isContainer = !0; + break; + default: + invariant( + !1, + "Invalid host parent fiber. This error is likely caused by a bug in React. Please file an issue." + ); + } + parentFiber.effectTag & 16 && + (resetTextContent(parent), (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; + + ) { + 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) + parentFiber + ? isContainer + ? insertInContainerBefore(parent, node.stateNode, parentFiber) + : insertBefore(parent, node.stateNode, parentFiber) + : isContainer + ? appendChildToContainer(parent, node.stateNode) + : appendChild(parent, node.stateNode); + 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; + } + }, + commitDeletion: function(current) { + unmountHostComponents(current); + current["return"] = null; + current.child = null; + current.alternate && + ((current.alternate.child = null), + (current.alternate["return"] = null)); + }, + commitWork: function(current, finishedWork) { + switch (finishedWork.tag) { + case 2: + break; + case 5: + var _instance8 = finishedWork.stateNode; + if (null != _instance8) { + var newProps = finishedWork.memoizedProps; + current = null !== current ? current.memoizedProps : newProps; + var type = finishedWork.type, + updatePayload = finishedWork.updateQueue; + finishedWork.updateQueue = null; + null !== updatePayload && + commitUpdate( + _instance8, + updatePayload, + type, + current, + newProps, + finishedWork + ); + } + break; + case 6: + invariant( + null !== finishedWork.stateNode, + "This should have a text node initialized. This error is likely caused by a bug in React. Please file an issue." + ); + _instance8 = finishedWork.memoizedProps; + commitTextUpdate( + finishedWork.stateNode, + null !== current ? current.memoizedProps : _instance8, + _instance8 + ); + break; + case 3: + break; + default: + invariant( + !1, + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + }, + commitLifeCycles: function(finishedRoot, current, finishedWork) { + switch (finishedWork.tag) { + case 2: + finishedRoot = finishedWork.stateNode; + if (finishedWork.effectTag & 4) + if (null === current) + (finishedRoot.props = finishedWork.memoizedProps), + (finishedRoot.state = finishedWork.memoizedState), + finishedRoot.componentDidMount(); + else { + var prevProps = current.memoizedProps; + current = current.memoizedState; + finishedRoot.props = finishedWork.memoizedProps; + finishedRoot.state = finishedWork.memoizedState; + finishedRoot.componentDidUpdate( + prevProps, + current, + finishedRoot.__reactInternalSnapshotBeforeUpdate + ); + } + finishedWork = finishedWork.updateQueue; + null !== finishedWork && commitCallbacks(finishedWork, finishedRoot); + break; + case 3: + current = finishedWork.updateQueue; + if (null !== current) { + finishedRoot = null; + if (null !== finishedWork.child) + switch (finishedWork.child.tag) { + case 5: + finishedRoot = getPublicInstance( + finishedWork.child.stateNode + ); + break; + case 2: + finishedRoot = finishedWork.child.stateNode; + } + commitCallbacks(current, finishedRoot); + } + break; + case 5: + finishedRoot = finishedWork.stateNode; + null === current && + finishedWork.effectTag & 4 && + commitMount( + finishedRoot, + finishedWork.type, + finishedWork.memoizedProps, + finishedWork + ); + break; + case 6: + break; + case 4: + break; + default: + invariant( + !1, + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + }, + commitErrorLogging: function(finishedWork, onUncaughtError) { + switch (finishedWork.tag) { + case 2: + var ctor = finishedWork.type; + onUncaughtError = finishedWork.stateNode; + var updateQueue = finishedWork.updateQueue; + invariant( + null !== updateQueue && null !== updateQueue.capturedValues, + "An error logging effect should not have been scheduled if no errors were captured. This error is likely caused by a bug in React. Please file an issue." + ); + var capturedErrors = updateQueue.capturedValues; + updateQueue.capturedValues = null; + "function" !== typeof ctor.getDerivedStateFromCatch && + markLegacyErrorBoundaryAsFailed(onUncaughtError); + onUncaughtError.props = finishedWork.memoizedProps; + onUncaughtError.state = finishedWork.memoizedState; + for (ctor = 0; ctor < capturedErrors.length; ctor++) { + updateQueue = capturedErrors[ctor]; + var _error = updateQueue.value, + stack = updateQueue.stack; + logError(finishedWork, updateQueue); + onUncaughtError.componentDidCatch(_error, { + componentStack: null !== stack ? stack : "" + }); + } + break; + case 3: + ctor = finishedWork.updateQueue; + invariant( + null !== ctor && null !== ctor.capturedValues, + "An error logging effect should not have been scheduled if no errors were captured. This error is likely caused by a bug in React. Please file an issue." + ); + capturedErrors = ctor.capturedValues; + ctor.capturedValues = null; + for (ctor = 0; ctor < capturedErrors.length; ctor++) + (updateQueue = capturedErrors[ctor]), + logError(finishedWork, updateQueue), + onUncaughtError(updateQueue.value); + break; + default: + invariant( + !1, + "This unit of work tag cannot capture errors. This error is likely caused by a bug in React. Please file an issue." + ); + } + }, + commitAttachRef: function(finishedWork) { + var ref = finishedWork.ref; + if (null !== ref) { + var _instance6 = finishedWork.stateNode; + switch (finishedWork.tag) { + case 5: + finishedWork = getPublicInstance(_instance6); + break; + default: + finishedWork = _instance6; + } + "function" === typeof ref + ? ref(finishedWork) + : (ref.current = finishedWork); + } + }, + commitDetachRef: function(current) { + current = current.ref; + null !== current && + ("function" === typeof current + ? current(null) + : (current.current = null)); + } + }; +} +var NO_CONTEXT = {}; +function ReactFiberHostContext(config, stack) { + function requiredContext(c) { + invariant( + c !== NO_CONTEXT, + "Expected host context to exist. This error is likely caused by a bug in React. Please file an issue." + ); + return c; + } + var getChildHostContext = config.getChildHostContext, + getRootHostContext = config.getRootHostContext; + config = stack.createCursor; + var push = stack.push, + pop = stack.pop, + contextStackCursor = config(NO_CONTEXT), + contextFiberStackCursor = config(NO_CONTEXT), + rootInstanceStackCursor = config(NO_CONTEXT); + return { + getHostContext: function() { + return requiredContext(contextStackCursor.current); + }, + getRootHostContainer: function() { + return requiredContext(rootInstanceStackCursor.current); + }, + popHostContainer: function(fiber) { + pop(contextStackCursor, fiber); + pop(contextFiberStackCursor, fiber); + pop(rootInstanceStackCursor, fiber); + }, + popHostContext: function(fiber) { + contextFiberStackCursor.current === fiber && + (pop(contextStackCursor, fiber), pop(contextFiberStackCursor, fiber)); + }, + pushHostContainer: function(fiber, nextRootInstance) { + push(rootInstanceStackCursor, nextRootInstance, fiber); + push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor, NO_CONTEXT, fiber); + nextRootInstance = getRootHostContext(nextRootInstance); + pop(contextStackCursor, fiber); + push(contextStackCursor, nextRootInstance, fiber); + }, + pushHostContext: function(fiber) { + var rootInstance = requiredContext(rootInstanceStackCursor.current), + context = requiredContext(contextStackCursor.current); + rootInstance = getChildHostContext(context, fiber.type, rootInstance); + context !== rootInstance && + (push(contextFiberStackCursor, fiber, fiber), + push(contextStackCursor, rootInstance, fiber)); + } + }; +} +function ReactFiberHydrationContext(config) { + function deleteHydratableInstance(returnFiber, instance) { + var fiber = new FiberNode(5, null, null, 0); + fiber.type = "DELETED"; + fiber.stateNode = instance; + fiber["return"] = returnFiber; + fiber.effectTag = 8; + null !== returnFiber.lastEffect + ? ((returnFiber.lastEffect.nextEffect = fiber), + (returnFiber.lastEffect = fiber)) + : (returnFiber.firstEffect = returnFiber.lastEffect = fiber); + } + function tryHydrate(fiber, nextInstance) { + switch (fiber.tag) { + case 5: + return ( + (nextInstance = canHydrateInstance( + nextInstance, + fiber.type, + fiber.pendingProps + )), + null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1 + ); + case 6: + return ( + (nextInstance = canHydrateTextInstance( + nextInstance, + fiber.pendingProps + )), + null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1 + ); + default: + return !1; + } + } + function popToNextHostParent(fiber) { + for ( + fiber = fiber["return"]; + null !== fiber && 5 !== fiber.tag && 3 !== fiber.tag; + + ) + fiber = fiber["return"]; + hydrationParentFiber = fiber; + } + var shouldSetTextContent = config.shouldSetTextContent; + config = config.hydration; + if (!config) + return { + enterHydrationState: function() { + return !1; + }, + resetHydrationState: function() {}, + tryToClaimNextHydratableInstance: function() {}, + prepareToHydrateHostInstance: function() { + invariant( + !1, + "Expected prepareToHydrateHostInstance() to never be called. This error is likely caused by a bug in React. Please file an issue." + ); + }, + prepareToHydrateHostTextInstance: function() { + invariant( + !1, + "Expected prepareToHydrateHostTextInstance() to never be called. This error is likely caused by a bug in React. Please file an issue." + ); + }, + popHydrationState: function() { + return !1; + } + }; + var canHydrateInstance = config.canHydrateInstance, + canHydrateTextInstance = config.canHydrateTextInstance, + getNextHydratableSibling = config.getNextHydratableSibling, + getFirstHydratableChild = config.getFirstHydratableChild, + hydrateInstance = config.hydrateInstance, + hydrateTextInstance = config.hydrateTextInstance, + hydrationParentFiber = null, + nextHydratableInstance = null, + isHydrating = !1; + return { + enterHydrationState: function(fiber) { + nextHydratableInstance = getFirstHydratableChild( + fiber.stateNode.containerInfo + ); + hydrationParentFiber = fiber; + return (isHydrating = !0); + }, + resetHydrationState: function() { + nextHydratableInstance = hydrationParentFiber = null; + isHydrating = !1; + }, + tryToClaimNextHydratableInstance: function(fiber) { + if (isHydrating) { + var nextInstance = nextHydratableInstance; + if (nextInstance) { + if (!tryHydrate(fiber, nextInstance)) { + nextInstance = getNextHydratableSibling(nextInstance); + if (!nextInstance || !tryHydrate(fiber, nextInstance)) { + fiber.effectTag |= 2; + isHydrating = !1; + hydrationParentFiber = fiber; + return; + } + deleteHydratableInstance( + hydrationParentFiber, + nextHydratableInstance + ); + } + hydrationParentFiber = fiber; + nextHydratableInstance = getFirstHydratableChild(nextInstance); + } else + (fiber.effectTag |= 2), + (isHydrating = !1), + (hydrationParentFiber = fiber); + } + }, + prepareToHydrateHostInstance: function( + fiber, + rootContainerInstance, + hostContext + ) { + rootContainerInstance = hydrateInstance( + fiber.stateNode, + fiber.type, + fiber.memoizedProps, + rootContainerInstance, + hostContext, + fiber + ); + fiber.updateQueue = rootContainerInstance; + return null !== rootContainerInstance ? !0 : !1; + }, + prepareToHydrateHostTextInstance: function(fiber) { + return hydrateTextInstance(fiber.stateNode, fiber.memoizedProps, fiber); + }, + popHydrationState: function(fiber) { + if (fiber !== hydrationParentFiber) return !1; + if (!isHydrating) + return popToNextHostParent(fiber), (isHydrating = !0), !1; + var type = fiber.type; + if ( + 5 !== fiber.tag || + ("head" !== type && + "body" !== type && + !shouldSetTextContent(type, fiber.memoizedProps)) + ) + for (type = nextHydratableInstance; type; ) + deleteHydratableInstance(fiber, type), + (type = getNextHydratableSibling(type)); + popToNextHostParent(fiber); + nextHydratableInstance = hydrationParentFiber + ? getNextHydratableSibling(fiber.stateNode) + : null; + return !0; + } + }; +} +function ReactFiberLegacyContext(stack) { + function cacheContext(workInProgress, unmaskedContext, maskedContext) { + workInProgress = workInProgress.stateNode; + workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; + workInProgress.__reactInternalMemoizedMaskedChildContext = maskedContext; + } + function isContextProvider(fiber) { + return 2 === fiber.tag && null != fiber.type.childContextTypes; + } + function processChildContext(fiber, parentContext) { + var instance = fiber.stateNode, + childContextTypes = fiber.type.childContextTypes; + if ("function" !== typeof instance.getChildContext) return parentContext; + instance = instance.getChildContext(); + for (var contextKey in instance) + invariant( + contextKey in childContextTypes, + '%s.getChildContext(): key "%s" is not defined in childContextTypes.', + getComponentName(fiber) || "Unknown", + contextKey + ); + return Object.assign({}, parentContext, instance); + } + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop, + contextStackCursor = createCursor(emptyObject), + didPerformWorkStackCursor = createCursor(!1), + previousContext = emptyObject; + return { + getUnmaskedContext: function(workInProgress) { + return isContextProvider(workInProgress) + ? previousContext + : contextStackCursor.current; + }, + cacheContext: cacheContext, + getMaskedContext: function(workInProgress, unmaskedContext) { + var contextTypes = workInProgress.type.contextTypes; + if (!contextTypes) return emptyObject; + var instance = workInProgress.stateNode; + if ( + instance && + instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext + ) + return instance.__reactInternalMemoizedMaskedChildContext; + var context = {}, + key; + for (key in contextTypes) context[key] = unmaskedContext[key]; + instance && cacheContext(workInProgress, unmaskedContext, context); + return context; + }, + hasContextChanged: function() { + return didPerformWorkStackCursor.current; + }, + isContextConsumer: function(fiber) { + return 2 === fiber.tag && null != fiber.type.contextTypes; + }, + isContextProvider: isContextProvider, + popContextProvider: function(fiber) { + isContextProvider(fiber) && + (pop(didPerformWorkStackCursor, fiber), pop(contextStackCursor, fiber)); + }, + popTopLevelContextObject: function(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); + }, + pushTopLevelContextObject: function(fiber, context, didChange) { + invariant( + null == contextStackCursor.cursor, + "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); + }, + processChildContext: processChildContext, + pushContextProvider: function(workInProgress) { + if (!isContextProvider(workInProgress)) return !1; + var instance = workInProgress.stateNode; + instance = + (instance && instance.__reactInternalMemoizedMergedChildContext) || + emptyObject; + previousContext = contextStackCursor.current; + push(contextStackCursor, instance, workInProgress); + push( + didPerformWorkStackCursor, + didPerformWorkStackCursor.current, + workInProgress + ); + return !0; + }, + invalidateContextProvider: function(workInProgress, didChange) { + var instance = workInProgress.stateNode; + invariant( + instance, + "Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue." + ); + if (didChange) { + var mergedContext = processChildContext( + workInProgress, + previousContext + ); + instance.__reactInternalMemoizedMergedChildContext = mergedContext; + pop(didPerformWorkStackCursor, workInProgress); + pop(contextStackCursor, workInProgress); + push(contextStackCursor, mergedContext, workInProgress); + } else pop(didPerformWorkStackCursor, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); + }, + findCurrentUnmaskedContext: function(fiber) { + for ( + invariant( + 2 === isFiberMountedImpl(fiber) && 2 === fiber.tag, + "Expected subtree parent to be a mounted class component. This error is likely caused by a bug in React. Please file an issue." + ); + 3 !== fiber.tag; + + ) { + if (isContextProvider(fiber)) + return fiber.stateNode.__reactInternalMemoizedMergedChildContext; + fiber = fiber["return"]; + invariant( + fiber, + "Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + return fiber.stateNode.context; + } + }; +} +function ReactFiberNewContext(stack) { + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop, + providerCursor = createCursor(null), + valueCursor = createCursor(null), + changedBitsCursor = createCursor(0); + return { + pushProvider: function(providerFiber) { + var context = providerFiber.type._context; + push(changedBitsCursor, context._changedBits, providerFiber); + push(valueCursor, context._currentValue, providerFiber); + push(providerCursor, providerFiber, providerFiber); + context._currentValue = providerFiber.pendingProps.value; + context._changedBits = providerFiber.stateNode; + }, + popProvider: function(providerFiber) { + var changedBits = changedBitsCursor.current, + currentValue = valueCursor.current; + pop(providerCursor, providerFiber); + pop(valueCursor, providerFiber); + pop(changedBitsCursor, providerFiber); + providerFiber = providerFiber.type._context; + providerFiber._currentValue = currentValue; + providerFiber._changedBits = changedBits; + } + }; +} +function ReactFiberStack() { + var valueStack = [], + index = -1; + return { + createCursor: function(defaultValue) { + return { current: defaultValue }; + }, + isEmpty: function() { + return -1 === index; + }, + pop: function(cursor) { + 0 > index || + ((cursor.current = valueStack[index]), + (valueStack[index] = null), + index--); + }, + push: function(cursor, value) { + index++; + valueStack[index] = cursor.current; + cursor.current = value; + }, + checkThatStackIsEmpty: function() {}, + resetStackAfterFatalErrorInDev: function() {} + }; +} +function ReactFiberScheduler(config) { + function resetStack() { + if (null !== nextUnitOfWork) + for ( + var interruptedWork = nextUnitOfWork["return"]; + null !== interruptedWork; + + ) + unwindInterruptedWork(interruptedWork), + (interruptedWork = interruptedWork["return"]); + nextRoot = null; + nextRenderExpirationTime = 0; + nextUnitOfWork = null; + isRootReadyForCommit = !1; + } + function isAlreadyFailedLegacyErrorBoundary(instance) { + return ( + null !== legacyErrorBoundariesThatAlreadyFailed && + legacyErrorBoundariesThatAlreadyFailed.has(instance) + ); + } + function completeUnitOfWork(workInProgress$jscomp$0) { + for (;;) { + var current = workInProgress$jscomp$0.alternate, + returnFiber = workInProgress$jscomp$0["return"], + siblingFiber = workInProgress$jscomp$0.sibling; + if (0 === (workInProgress$jscomp$0.effectTag & 512)) { + current = completeWork( + current, + workInProgress$jscomp$0, + nextRenderExpirationTime + ); + var workInProgress = workInProgress$jscomp$0; + if ( + 1073741823 === nextRenderExpirationTime || + 1073741823 !== workInProgress.expirationTime + ) { + b: switch (workInProgress.tag) { + case 3: + case 2: + var newExpirationTime = workInProgress.updateQueue; + newExpirationTime = + null === newExpirationTime + ? 0 + : newExpirationTime.expirationTime; + break b; + default: + newExpirationTime = 0; + } + for (var child = workInProgress.child; null !== child; ) + 0 !== child.expirationTime && + (0 === newExpirationTime || + newExpirationTime > child.expirationTime) && + (newExpirationTime = child.expirationTime), + (child = child.sibling); + workInProgress.expirationTime = newExpirationTime; + } + if (null !== current) return current; + null !== returnFiber && + 0 === (returnFiber.effectTag & 512) && + (null === returnFiber.firstEffect && + (returnFiber.firstEffect = workInProgress$jscomp$0.firstEffect), + null !== workInProgress$jscomp$0.lastEffect && + (null !== returnFiber.lastEffect && + (returnFiber.lastEffect.nextEffect = + workInProgress$jscomp$0.firstEffect), + (returnFiber.lastEffect = workInProgress$jscomp$0.lastEffect)), + 1 < workInProgress$jscomp$0.effectTag && + (null !== returnFiber.lastEffect + ? (returnFiber.lastEffect.nextEffect = workInProgress$jscomp$0) + : (returnFiber.firstEffect = workInProgress$jscomp$0), + (returnFiber.lastEffect = workInProgress$jscomp$0))); + if (null !== siblingFiber) return siblingFiber; + if (null !== returnFiber) workInProgress$jscomp$0 = returnFiber; + else { + isRootReadyForCommit = !0; + break; + } + } else { + workInProgress$jscomp$0 = unwindWork(workInProgress$jscomp$0); + if (null !== workInProgress$jscomp$0) + return ( + (workInProgress$jscomp$0.effectTag &= 2559), workInProgress$jscomp$0 + ); + null !== returnFiber && + ((returnFiber.firstEffect = returnFiber.lastEffect = null), + (returnFiber.effectTag |= 512)); + if (null !== siblingFiber) return siblingFiber; + if (null !== returnFiber) workInProgress$jscomp$0 = returnFiber; + else break; + } + } + return null; + } + function performUnitOfWork(workInProgress) { + var next = beginWork( + workInProgress.alternate, + workInProgress, + nextRenderExpirationTime + ); + null === next && (next = completeUnitOfWork(workInProgress)); + ReactCurrentOwner.current = null; + return next; + } + function renderRoot(root, expirationTime, isAsync) { + invariant( + !isWorking, + "renderRoot was called recursively. This error is likely caused by a bug in React. Please file an issue." + ); + isWorking = !0; + if ( + expirationTime !== nextRenderExpirationTime || + root !== nextRoot || + null === nextUnitOfWork + ) + resetStack(), + (nextRoot = root), + (nextRenderExpirationTime = expirationTime), + (nextUnitOfWork = createWorkInProgress( + nextRoot.current, + null, + nextRenderExpirationTime + )), + (root.pendingCommitExpirationTime = 0); + var didFatal = !1; + do { + try { + if (isAsync) + for (; null !== nextUnitOfWork && !shouldYield(); ) + nextUnitOfWork = performUnitOfWork(nextUnitOfWork); + else + for (; null !== nextUnitOfWork; ) + nextUnitOfWork = performUnitOfWork(nextUnitOfWork); + } catch (thrownValue) { + if (null === nextUnitOfWork) { + didFatal = !0; + onUncaughtError(thrownValue); + break; + } + isAsync = nextUnitOfWork; + var returnFiber = isAsync["return"]; + if (null === returnFiber) { + didFatal = !0; + onUncaughtError(thrownValue); + break; + } + throwException(returnFiber, isAsync, thrownValue); + nextUnitOfWork = completeUnitOfWork(isAsync); + } + break; + } while (1); + isWorking = !1; + if (didFatal || null !== nextUnitOfWork) return null; + if (isRootReadyForCommit) + return ( + (root.pendingCommitExpirationTime = expirationTime), + root.current.alternate + ); + invariant( + !1, + "Expired work should have completed. This error is likely caused by a bug in React. Please file an issue." + ); + } + function scheduleCapture(sourceFiber, boundaryFiber, value, expirationTime) { + sourceFiber = { + value: value, + source: sourceFiber, + stack: getStackAddendumByWorkInProgressFiber(sourceFiber) + }; + insertUpdateIntoFiber(boundaryFiber, { + expirationTime: expirationTime, + partialState: null, + callback: null, + isReplace: !1, + isForced: !1, + capturedValue: sourceFiber, + next: null + }); + scheduleWork(boundaryFiber, expirationTime); + } + function onCommitPhaseError(fiber$jscomp$0, error) { + a: { + invariant( + !isWorking || isCommitting, + "dispatch: Cannot dispatch during the render phase." + ); + for (var fiber = fiber$jscomp$0["return"]; null !== fiber; ) { + switch (fiber.tag) { + case 2: + var instance = fiber.stateNode; + if ( + "function" === typeof fiber.type.getDerivedStateFromCatch || + ("function" === typeof instance.componentDidCatch && + !isAlreadyFailedLegacyErrorBoundary(instance)) + ) { + scheduleCapture(fiber$jscomp$0, fiber, error, 1); + fiber$jscomp$0 = void 0; + break a; + } + break; + case 3: + scheduleCapture(fiber$jscomp$0, fiber, error, 1); + fiber$jscomp$0 = void 0; + break a; + } + fiber = fiber["return"]; + } + 3 === fiber$jscomp$0.tag && + scheduleCapture(fiber$jscomp$0, fiber$jscomp$0, error, 1); + fiber$jscomp$0 = void 0; + } + return fiber$jscomp$0; + } + function computeExpirationForFiber(fiber) { + fiber = + 0 !== expirationContext + ? expirationContext + : isWorking + ? isCommitting ? 1 : nextRenderExpirationTime + : fiber.mode & 1 + ? isBatchingInteractiveUpdates + ? 10 * ((((recalculateCurrentTime() + 15) / 10) | 0) + 1) + : 25 * ((((recalculateCurrentTime() + 500) / 25) | 0) + 1) + : 1; + isBatchingInteractiveUpdates && + (0 === lowestPendingInteractiveExpirationTime || + fiber > lowestPendingInteractiveExpirationTime) && + (lowestPendingInteractiveExpirationTime = fiber); + return fiber; + } + function scheduleWork(fiber, expirationTime) { + a: { + for (; null !== fiber; ) { + if (0 === fiber.expirationTime || fiber.expirationTime > expirationTime) + fiber.expirationTime = expirationTime; + null !== fiber.alternate && + (0 === fiber.alternate.expirationTime || + fiber.alternate.expirationTime > expirationTime) && + (fiber.alternate.expirationTime = expirationTime); + if (null === fiber["return"]) + if (3 === fiber.tag) { + var root = fiber.stateNode; + !isWorking && + 0 !== nextRenderExpirationTime && + expirationTime < nextRenderExpirationTime && + resetStack(); + (isWorking && !isCommitting && nextRoot === root) || + requestWork(root, expirationTime); + nestedUpdateCount > NESTED_UPDATE_LIMIT && + invariant( + !1, + "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." + ); + } else { + expirationTime = void 0; + break a; + } + fiber = fiber["return"]; + } + expirationTime = void 0; + } + return expirationTime; + } + function recalculateCurrentTime() { + mostRecentCurrentTimeMs = now() - originalStartTimeMs; + return (mostRecentCurrentTime = ((mostRecentCurrentTimeMs / 10) | 0) + 2); + } + function syncUpdates(fn, a, b, c, d) { + var previousExpirationContext = expirationContext; + expirationContext = 1; + try { + return fn(a, b, c, d); + } finally { + expirationContext = previousExpirationContext; + } + } + function scheduleCallbackWithExpiration(expirationTime) { + if (0 !== callbackExpirationTime) { + if (expirationTime > callbackExpirationTime) return; + cancelDeferredCallback(callbackID); + } + var currentMs = now() - originalStartTimeMs; + callbackExpirationTime = expirationTime; + callbackID = scheduleDeferredCallback(performAsyncWork, { + timeout: 10 * (expirationTime - 2) - currentMs + }); + } + function requestWork(root, expirationTime) { + if (null === root.nextScheduledRoot) + (root.remainingExpirationTime = expirationTime), + null === lastScheduledRoot + ? ((firstScheduledRoot = lastScheduledRoot = root), + (root.nextScheduledRoot = root)) + : ((lastScheduledRoot = lastScheduledRoot.nextScheduledRoot = root), + (lastScheduledRoot.nextScheduledRoot = firstScheduledRoot)); + else { + var remainingExpirationTime = root.remainingExpirationTime; + if ( + 0 === remainingExpirationTime || + expirationTime < remainingExpirationTime + ) + root.remainingExpirationTime = expirationTime; + } + isRendering || + (isBatchingUpdates + ? isUnbatchingUpdates && + ((nextFlushedRoot = root), + (nextFlushedExpirationTime = 1), + performWorkOnRoot(root, 1, !1)) + : 1 === expirationTime + ? performSyncWork() + : scheduleCallbackWithExpiration(expirationTime)); + } + function findHighestPriorityRoot() { + var highestPriorityWork = 0, + highestPriorityRoot = null; + if (null !== lastScheduledRoot) + for ( + var previousScheduledRoot = lastScheduledRoot, + root = firstScheduledRoot; + null !== root; + + ) { + var remainingExpirationTime = root.remainingExpirationTime; + if (0 === remainingExpirationTime) { + invariant( + null !== previousScheduledRoot && null !== lastScheduledRoot, + "Should have a previous and last root. This error is likely caused by a bug in React. Please file an issue." + ); + if (root === root.nextScheduledRoot) { + firstScheduledRoot = lastScheduledRoot = root.nextScheduledRoot = null; + break; + } else if (root === firstScheduledRoot) + (firstScheduledRoot = remainingExpirationTime = + root.nextScheduledRoot), + (lastScheduledRoot.nextScheduledRoot = remainingExpirationTime), + (root.nextScheduledRoot = null); + else if (root === lastScheduledRoot) { + lastScheduledRoot = previousScheduledRoot; + lastScheduledRoot.nextScheduledRoot = firstScheduledRoot; + root.nextScheduledRoot = null; + break; + } else + (previousScheduledRoot.nextScheduledRoot = root.nextScheduledRoot), + (root.nextScheduledRoot = null); + root = previousScheduledRoot.nextScheduledRoot; + } else { + if ( + 0 === highestPriorityWork || + remainingExpirationTime < highestPriorityWork + ) + (highestPriorityWork = remainingExpirationTime), + (highestPriorityRoot = root); + if (root === lastScheduledRoot) break; + previousScheduledRoot = root; + root = root.nextScheduledRoot; + } + } + previousScheduledRoot = nextFlushedRoot; + null !== previousScheduledRoot && + previousScheduledRoot === highestPriorityRoot && + 1 === highestPriorityWork + ? nestedUpdateCount++ + : (nestedUpdateCount = 0); + nextFlushedRoot = highestPriorityRoot; + nextFlushedExpirationTime = highestPriorityWork; + } + function performAsyncWork(dl) { + performWork(0, !0, dl); + } + function performSyncWork() { + performWork(1, !1, null); + } + function performWork(minExpirationTime, isAsync, dl) { + deadline = dl; + findHighestPriorityRoot(); + if (isAsync) + for ( + ; + null !== nextFlushedRoot && + 0 !== nextFlushedExpirationTime && + (0 === minExpirationTime || + minExpirationTime >= nextFlushedExpirationTime) && + (!deadlineDidExpire || + recalculateCurrentTime() >= nextFlushedExpirationTime); + + ) + performWorkOnRoot( + nextFlushedRoot, + nextFlushedExpirationTime, + !deadlineDidExpire + ), + findHighestPriorityRoot(); + else + for ( + ; + null !== nextFlushedRoot && + 0 !== nextFlushedExpirationTime && + (0 === minExpirationTime || + minExpirationTime >= nextFlushedExpirationTime); + + ) + performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime, !1), + findHighestPriorityRoot(); + null !== deadline && ((callbackExpirationTime = 0), (callbackID = -1)); + 0 !== nextFlushedExpirationTime && + scheduleCallbackWithExpiration(nextFlushedExpirationTime); + deadline = null; + deadlineDidExpire = !1; + finishRendering(); + } + function finishRendering() { + nestedUpdateCount = 0; + if (null !== completedBatches) { + var batches = completedBatches; + completedBatches = null; + for (var i = 0; i < batches.length; i++) { + var batch = batches[i]; + try { + batch._onComplete(); + } catch (error) { + hasUnhandledError || + ((hasUnhandledError = !0), (unhandledError = error)); + } + } + } + if (hasUnhandledError) + throw ((batches = unhandledError), + (unhandledError = null), + (hasUnhandledError = !1), + batches); + } + function performWorkOnRoot(root, expirationTime, isAsync) { + invariant( + !isRendering, + "performWorkOnRoot was called recursively. This error is likely caused by a bug in React. Please file an issue." + ); + isRendering = !0; + isAsync + ? ((isAsync = root.finishedWork), + null !== isAsync + ? completeRoot(root, isAsync, expirationTime) + : ((root.finishedWork = null), + (isAsync = renderRoot(root, expirationTime, !0)), + null !== isAsync && + (shouldYield() + ? (root.finishedWork = isAsync) + : completeRoot(root, isAsync, expirationTime)))) + : ((isAsync = root.finishedWork), + null !== isAsync + ? completeRoot(root, isAsync, expirationTime) + : ((root.finishedWork = null), + (isAsync = renderRoot(root, expirationTime, !1)), + null !== isAsync && completeRoot(root, isAsync, expirationTime))); + isRendering = !1; + } + function completeRoot(root, finishedWork, expirationTime) { + var firstBatch = root.firstBatch; + if ( + null !== firstBatch && + firstBatch._expirationTime <= expirationTime && + (null === completedBatches + ? (completedBatches = [firstBatch]) + : completedBatches.push(firstBatch), + firstBatch._defer) + ) { + root.finishedWork = finishedWork; + root.remainingExpirationTime = 0; + return; + } + root.finishedWork = null; + isCommitting = isWorking = !0; + expirationTime = finishedWork.stateNode; + invariant( + expirationTime.current !== finishedWork, + "Cannot commit the same tree as before. This is probably a bug related to the return field. This error is likely caused by a bug in React. Please file an issue." + ); + firstBatch = expirationTime.pendingCommitExpirationTime; + invariant( + 0 !== firstBatch, + "Cannot commit an incomplete root. This error is likely caused by a bug in React. Please file an issue." + ); + expirationTime.pendingCommitExpirationTime = 0; + var currentTime = recalculateCurrentTime(); + ReactCurrentOwner.current = null; + if (1 < finishedWork.effectTag) + if (null !== finishedWork.lastEffect) { + finishedWork.lastEffect.nextEffect = finishedWork; + var firstEffect = finishedWork.firstEffect; + } else firstEffect = finishedWork; + else firstEffect = finishedWork.firstEffect; + prepareForCommit(expirationTime.containerInfo); + for (nextEffect = firstEffect; null !== nextEffect; ) { + var didError = !1, + error = void 0; + try { + for (; null !== nextEffect; ) + nextEffect.effectTag & 2048 && + commitBeforeMutationLifeCycles(nextEffect.alternate, nextEffect), + (nextEffect = nextEffect.nextEffect); + } catch (e) { + (didError = !0), (error = e); + } + didError && + (invariant( + null !== nextEffect, + "Should have next effect. This error is likely caused by a bug in React. Please file an issue." + ), + onCommitPhaseError(nextEffect, error), + null !== nextEffect && (nextEffect = nextEffect.nextEffect)); + } + for (nextEffect = firstEffect; null !== nextEffect; ) { + didError = !1; + error = void 0; + try { + for (; null !== nextEffect; ) { + var effectTag = nextEffect.effectTag; + effectTag & 16 && commitResetTextContent(nextEffect); + if (effectTag & 128) { + var current = nextEffect.alternate; + null !== current && commitDetachRef(current); + } + 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: + commitDeletion(nextEffect); + } + nextEffect = nextEffect.nextEffect; + } + } catch (e) { + (didError = !0), (error = e); + } + didError && + (invariant( + null !== nextEffect, + "Should have next effect. This error is likely caused by a bug in React. Please file an issue." + ), + onCommitPhaseError(nextEffect, error), + null !== nextEffect && (nextEffect = nextEffect.nextEffect)); + } + resetAfterCommit(expirationTime.containerInfo); + expirationTime.current = finishedWork; + for (nextEffect = firstEffect; null !== nextEffect; ) { + effectTag = !1; + current = void 0; + try { + for ( + firstEffect = expirationTime, + didError = currentTime, + error = firstBatch; + null !== nextEffect; + + ) { + var effectTag$jscomp$0 = nextEffect.effectTag; + effectTag$jscomp$0 & 36 && + commitLifeCycles( + firstEffect, + nextEffect.alternate, + nextEffect, + didError, + error + ); + effectTag$jscomp$0 & 256 && + commitErrorLogging(nextEffect, onUncaughtError); + effectTag$jscomp$0 & 128 && commitAttachRef(nextEffect); + var next = nextEffect.nextEffect; + nextEffect.nextEffect = null; + nextEffect = next; + } + } catch (e) { + (effectTag = !0), (current = e); + } + effectTag && + (invariant( + null !== nextEffect, + "Should have next effect. This error is likely caused by a bug in React. Please file an issue." + ), + onCommitPhaseError(nextEffect, current), + null !== nextEffect && (nextEffect = nextEffect.nextEffect)); + } + isWorking = isCommitting = !1; + "function" === typeof onCommitRoot && onCommitRoot(finishedWork.stateNode); + finishedWork = expirationTime.current.expirationTime; + 0 === finishedWork && (legacyErrorBoundariesThatAlreadyFailed = null); + root.remainingExpirationTime = finishedWork; + } + function shouldYield() { + return null === deadline || + deadline.timeRemaining() > timeHeuristicForUnitOfWork + ? !1 + : (deadlineDidExpire = !0); + } + function onUncaughtError(error) { + invariant( + null !== nextFlushedRoot, + "Should be working on a root. This error is likely caused by a bug in React. Please file an issue." + ); + nextFlushedRoot.remainingExpirationTime = 0; + hasUnhandledError || ((hasUnhandledError = !0), (unhandledError = error)); + } + var stack = ReactFiberStack(), + hostContext = ReactFiberHostContext(config, stack), + legacyContext = ReactFiberLegacyContext(stack); + stack = ReactFiberNewContext(stack); + var hydrationContext = ReactFiberHydrationContext(config), + beginWork = ReactFiberBeginWork( + config, + hostContext, + legacyContext, + stack, + hydrationContext, + scheduleWork, + computeExpirationForFiber + ).beginWork, + completeWork = ReactFiberCompleteWork( + config, + hostContext, + legacyContext, + stack, + hydrationContext + ).completeWork; + hostContext = ReactFiberUnwindWork( + hostContext, + legacyContext, + stack, + scheduleWork, + isAlreadyFailedLegacyErrorBoundary + ); + var throwException = hostContext.throwException, + unwindWork = hostContext.unwindWork, + unwindInterruptedWork = hostContext.unwindInterruptedWork; + hostContext = ReactFiberCommitWork( + config, + onCommitPhaseError, + scheduleWork, + computeExpirationForFiber, + function(instance) { + null === legacyErrorBoundariesThatAlreadyFailed + ? (legacyErrorBoundariesThatAlreadyFailed = new Set([instance])) + : legacyErrorBoundariesThatAlreadyFailed.add(instance); + }, + recalculateCurrentTime + ); + var commitBeforeMutationLifeCycles = + hostContext.commitBeforeMutationLifeCycles, + commitResetTextContent = hostContext.commitResetTextContent, + commitPlacement = hostContext.commitPlacement, + commitDeletion = hostContext.commitDeletion, + commitWork = hostContext.commitWork, + commitLifeCycles = hostContext.commitLifeCycles, + commitErrorLogging = hostContext.commitErrorLogging, + commitAttachRef = hostContext.commitAttachRef, + commitDetachRef = hostContext.commitDetachRef, + now = config.now, + scheduleDeferredCallback = config.scheduleDeferredCallback, + cancelDeferredCallback = config.cancelDeferredCallback, + prepareForCommit = config.prepareForCommit, + resetAfterCommit = config.resetAfterCommit, + originalStartTimeMs = now(), + mostRecentCurrentTime = 2, + mostRecentCurrentTimeMs = originalStartTimeMs, + lastUniqueAsyncExpiration = 0, + expirationContext = 0, + isWorking = !1, + nextUnitOfWork = null, + nextRoot = null, + nextRenderExpirationTime = 0, + nextEffect = null, + isCommitting = !1, + isRootReadyForCommit = !1, + legacyErrorBoundariesThatAlreadyFailed = null, + firstScheduledRoot = null, + lastScheduledRoot = null, + callbackExpirationTime = 0, + callbackID = -1, + isRendering = !1, + nextFlushedRoot = null, + nextFlushedExpirationTime = 0, + lowestPendingInteractiveExpirationTime = 0, + deadlineDidExpire = !1, + hasUnhandledError = !1, + unhandledError = null, + deadline = null, + isBatchingUpdates = !1, + isUnbatchingUpdates = !1, + isBatchingInteractiveUpdates = !1, + completedBatches = null, + NESTED_UPDATE_LIMIT = 1e3, + nestedUpdateCount = 0, + timeHeuristicForUnitOfWork = 1; + return { + recalculateCurrentTime: recalculateCurrentTime, + computeExpirationForFiber: computeExpirationForFiber, + scheduleWork: scheduleWork, + requestWork: requestWork, + flushRoot: function(root, expirationTime) { + invariant( + !isRendering, + "work.commit(): Cannot commit while already rendering. This likely means you attempted to commit from inside a lifecycle method." + ); + nextFlushedRoot = root; + nextFlushedExpirationTime = expirationTime; + performWorkOnRoot(root, expirationTime, !1); + performSyncWork(); + finishRendering(); + }, + batchedUpdates: function(fn, a) { + var previousIsBatchingUpdates = isBatchingUpdates; + isBatchingUpdates = !0; + try { + return fn(a); + } finally { + (isBatchingUpdates = previousIsBatchingUpdates) || + isRendering || + performSyncWork(); + } + }, + unbatchedUpdates: function(fn, a) { + if (isBatchingUpdates && !isUnbatchingUpdates) { + isUnbatchingUpdates = !0; + try { + return fn(a); + } finally { + isUnbatchingUpdates = !1; + } + } + return fn(a); + }, + flushSync: function(fn, a) { + invariant( + !isRendering, + "flushSync was called from inside a lifecycle method. It cannot be called when React is already rendering." + ); + var previousIsBatchingUpdates = isBatchingUpdates; + isBatchingUpdates = !0; + try { + return syncUpdates(fn, a); + } finally { + (isBatchingUpdates = previousIsBatchingUpdates), performSyncWork(); + } + }, + flushControlled: function(fn) { + var previousIsBatchingUpdates = isBatchingUpdates; + isBatchingUpdates = !0; + try { + syncUpdates(fn); + } finally { + (isBatchingUpdates = previousIsBatchingUpdates) || + isRendering || + performWork(1, !1, null); + } + }, + deferredUpdates: function(fn) { + var previousExpirationContext = expirationContext; + expirationContext = + 25 * ((((recalculateCurrentTime() + 500) / 25) | 0) + 1); + try { + return fn(); + } finally { + expirationContext = previousExpirationContext; + } + }, + syncUpdates: syncUpdates, + interactiveUpdates: function(fn, a, b) { + if (isBatchingInteractiveUpdates) return fn(a, b); + isBatchingUpdates || + isRendering || + 0 === lowestPendingInteractiveExpirationTime || + (performWork(lowestPendingInteractiveExpirationTime, !1, null), + (lowestPendingInteractiveExpirationTime = 0)); + var previousIsBatchingInteractiveUpdates = isBatchingInteractiveUpdates, + previousIsBatchingUpdates = isBatchingUpdates; + isBatchingUpdates = isBatchingInteractiveUpdates = !0; + try { + return fn(a, b); + } finally { + (isBatchingInteractiveUpdates = previousIsBatchingInteractiveUpdates), + (isBatchingUpdates = previousIsBatchingUpdates) || + isRendering || + performSyncWork(); + } + }, + flushInteractiveUpdates: function() { + isRendering || + 0 === lowestPendingInteractiveExpirationTime || + (performWork(lowestPendingInteractiveExpirationTime, !1, null), + (lowestPendingInteractiveExpirationTime = 0)); + }, + computeUniqueAsyncExpiration: function() { + var result = 25 * ((((recalculateCurrentTime() + 500) / 25) | 0) + 1); + result <= lastUniqueAsyncExpiration && + (result = lastUniqueAsyncExpiration + 1); + return (lastUniqueAsyncExpiration = result); + }, + legacyContext: legacyContext + }; +} +function ReactFiberReconciler$1(config) { + function updateContainerAtExpirationTime( + element, + container, + parentComponent, + currentTime, + expirationTime, + callback + ) { + currentTime = container.current; + if (parentComponent) { + parentComponent = parentComponent._reactInternalFiber; + var parentContext = findCurrentUnmaskedContext(parentComponent); + parentComponent = isContextProvider(parentComponent) + ? processChildContext(parentComponent, parentContext) + : parentContext; + } else parentComponent = emptyObject; + null === container.context + ? (container.context = parentComponent) + : (container.pendingContext = parentComponent); + container = callback; + insertUpdateIntoFiber(currentTime, { + expirationTime: expirationTime, + partialState: { element: element }, + callback: void 0 === container ? null : container, + isReplace: !1, + isForced: !1, + capturedValue: null, + next: null + }); + scheduleWork(currentTime, expirationTime); + return expirationTime; + } + var getPublicInstance = config.getPublicInstance; + config = ReactFiberScheduler(config); + var recalculateCurrentTime = config.recalculateCurrentTime, + computeExpirationForFiber = config.computeExpirationForFiber, + scheduleWork = config.scheduleWork, + legacyContext = config.legacyContext, + findCurrentUnmaskedContext = legacyContext.findCurrentUnmaskedContext, + isContextProvider = legacyContext.isContextProvider, + processChildContext = legacyContext.processChildContext; + return { + createContainer: function(containerInfo, isAsync, hydrate) { + isAsync = new FiberNode(3, null, null, isAsync ? 3 : 0); + containerInfo = { + current: isAsync, + containerInfo: containerInfo, + pendingChildren: null, + pendingCommitExpirationTime: 0, + finishedWork: null, + context: null, + pendingContext: null, + hydrate: hydrate, + remainingExpirationTime: 0, + firstBatch: null, + nextScheduledRoot: null + }; + return (isAsync.stateNode = containerInfo); + }, + updateContainer: function(element, container, parentComponent, callback) { + var current = container.current, + currentTime = recalculateCurrentTime(); + current = computeExpirationForFiber(current); + return updateContainerAtExpirationTime( + element, + container, + parentComponent, + currentTime, + current, + callback + ); + }, + updateContainerAtExpirationTime: function( + element, + container, + parentComponent, + expirationTime, + callback + ) { + var currentTime = recalculateCurrentTime(); + return updateContainerAtExpirationTime( + element, + container, + parentComponent, + currentTime, + expirationTime, + callback + ); + }, + flushRoot: config.flushRoot, + requestWork: config.requestWork, + computeUniqueAsyncExpiration: config.computeUniqueAsyncExpiration, + batchedUpdates: config.batchedUpdates, + unbatchedUpdates: config.unbatchedUpdates, + deferredUpdates: config.deferredUpdates, + syncUpdates: config.syncUpdates, + interactiveUpdates: config.interactiveUpdates, + flushInteractiveUpdates: config.flushInteractiveUpdates, + flushControlled: config.flushControlled, + flushSync: config.flushSync, + getPublicRootInstance: function(container) { + container = container.current; + if (!container.child) return null; + switch (container.child.tag) { + case 5: + return getPublicInstance(container.child.stateNode); + default: + return container.child.stateNode; + } + }, + findHostInstance: function(component) { + var fiber = component._reactInternalFiber; + void 0 === fiber && + ("function" === typeof component.render + ? invariant(!1, "Unable to find node on an unmounted component.") + : invariant( + !1, + "Argument appears to not be a ReactComponent. Keys: %s", + Object.keys(component) + )); + component = findCurrentHostFiber(fiber); + return null === component ? null : component.stateNode; + }, + findHostInstanceWithNoPortals: function(fiber) { + fiber = findCurrentHostFiberWithNoPortals(fiber); + return null === fiber ? null : fiber.stateNode; + }, + injectIntoDevTools: function(devToolsConfig) { + var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; + return injectInternals( + Object.assign({}, devToolsConfig, { + findHostInstanceByFiber: function(fiber) { + fiber = findCurrentHostFiber(fiber); + return null === fiber ? null : fiber.stateNode; + }, + findFiberByHostInstance: function(instance) { + return findFiberByHostInstance + ? findFiberByHostInstance(instance) + : null; + } + }) + ); + } + }; +} +var ReactFiberReconciler$2 = Object.freeze({ default: ReactFiberReconciler$1 }), + ReactFiberReconciler$3 = + (ReactFiberReconciler$2 && ReactFiberReconciler$1) || + ReactFiberReconciler$2, + reactReconciler = ReactFiberReconciler$3["default"] + ? ReactFiberReconciler$3["default"] + : ReactFiberReconciler$3, + 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() { + TextInputState.blurTextInput(this._nativeTag); + }; + ReactNativeFiberHostComponent.prototype.focus = function() { + TextInputState.focusTextInput(this._nativeTag); + }; + ReactNativeFiberHostComponent.prototype.measure = function(callback) { + UIManager.measure(this._nativeTag, mountSafeCallback(this, callback)); + }; + ReactNativeFiberHostComponent.prototype.measureInWindow = function( + callback + ) { + UIManager.measureInWindow( + this._nativeTag, + mountSafeCallback(this, callback) + ); + }; + ReactNativeFiberHostComponent.prototype.measureLayout = function( + relativeToNativeNode, + onSuccess, + onFail + ) { + UIManager.measureLayout( + this._nativeTag, + relativeToNativeNode, + mountSafeCallback(this, onFail), + mountSafeCallback(this, onSuccess) + ); + }; + ReactNativeFiberHostComponent.prototype.setNativeProps = function( + nativeProps + ) { + nativeProps = diffProperties( + null, + emptyObject$1, + nativeProps, + this.viewConfig.validAttributes + ); + null != nativeProps && + UIManager.updateView( + this._nativeTag, + this.viewConfig.uiViewClassName, + nativeProps + ); + }; + return ReactNativeFiberHostComponent; + })(), + now = + "object" === typeof performance && "function" === typeof performance.now + ? function() { + return performance.now(); + } + : function() { + return Date.now(); + }, + scheduledCallback = null, + frameDeadline = 0, + frameDeadlineObject = { + timeRemaining: function() { + return frameDeadline - now(); + }, + didTimeout: !1 + }; +function setTimeoutCallback() { + frameDeadline = now() + 5; + var callback = scheduledCallback; + scheduledCallback = null; + null !== callback && callback(frameDeadlineObject); +} +var nextReactTag = 3; +function allocateTag() { + var tag = nextReactTag; + 1 === tag % 10 && (tag += 2); + nextReactTag = tag + 2; + return tag; +} +function recursivelyUncacheFiberNode(node) { + "number" === typeof node + ? uncacheFiberNode(node) + : (uncacheFiberNode(node._nativeTag), + node._children.forEach(recursivelyUncacheFiberNode)); +} +var NativeRenderer = reactReconciler({ + appendInitialChild: function(parentInstance, child) { + parentInstance._children.push(child); + }, + createInstance: function( + type, + props, + rootContainerInstance, + hostContext, + internalInstanceHandle + ) { + hostContext = allocateTag(); + type = ReactNativeViewConfigRegistry.get(type); + var updatePayload = diffProperties( + null, + emptyObject$1, + props, + type.validAttributes + ); + UIManager.createView( + hostContext, + type.uiViewClassName, + rootContainerInstance, + updatePayload + ); + rootContainerInstance = new ReactNativeFiberHostComponent( + hostContext, + type + ); + instanceCache[hostContext] = internalInstanceHandle; + instanceProps[hostContext] = props; + return rootContainerInstance; + }, + createTextInstance: function( + text, + rootContainerInstance, + hostContext, + internalInstanceHandle + ) { + hostContext = allocateTag(); + UIManager.createView(hostContext, "RCTRawText", rootContainerInstance, { + text: text + }); + instanceCache[hostContext] = internalInstanceHandle; + return hostContext; + }, + finalizeInitialChildren: function(parentInstance) { + if (0 === parentInstance._children.length) return !1; + var nativeTags = parentInstance._children.map(function(child) { + return "number" === typeof child ? child : child._nativeTag; + }); + UIManager.setChildren(parentInstance._nativeTag, nativeTags); + return !1; + }, + getRootHostContext: function() { + return emptyObject; + }, + getChildHostContext: function() { + return emptyObject; + }, + getPublicInstance: function(instance) { + return instance; + }, + now: now, + prepareForCommit: function() {}, + prepareUpdate: function() { + return emptyObject; + }, + resetAfterCommit: function() {}, + scheduleDeferredCallback: function(callback) { + scheduledCallback = callback; + return setTimeout(setTimeoutCallback, 1); + }, + cancelDeferredCallback: function(callbackID) { + scheduledCallback = null; + clearTimeout(callbackID); + }, + shouldDeprioritizeSubtree: function() { + return !1; + }, + shouldSetTextContent: function() { + return !1; + }, + mutation: { + appendChild: function(parentInstance, child) { + var childTag = "number" === typeof child ? child : child._nativeTag, + children = parentInstance._children, + index = children.indexOf(child); + 0 <= index + ? (children.splice(index, 1), + children.push(child), + UIManager.manageChildren( + parentInstance._nativeTag, + [index], + [children.length - 1], + [], + [], + [] + )) + : (children.push(child), + UIManager.manageChildren( + parentInstance._nativeTag, + [], + [], + [childTag], + [children.length - 1], + [] + )); + }, + appendChildToContainer: function(parentInstance, child) { + UIManager.setChildren(parentInstance, [ + "number" === typeof child ? child : child._nativeTag + ]); + }, + commitTextUpdate: function(textInstance, oldText, newText) { + UIManager.updateView(textInstance, "RCTRawText", { text: newText }); + }, + commitMount: function() {}, + commitUpdate: function( + instance, + updatePayloadTODO, + type, + oldProps, + newProps + ) { + updatePayloadTODO = instance.viewConfig; + instanceProps[instance._nativeTag] = newProps; + oldProps = diffProperties( + null, + oldProps, + newProps, + updatePayloadTODO.validAttributes + ); + null != oldProps && + UIManager.updateView( + instance._nativeTag, + updatePayloadTODO.uiViewClassName, + oldProps + ); + }, + insertBefore: function(parentInstance, child, beforeChild) { + var children = parentInstance._children, + index = children.indexOf(child); + 0 <= index + ? (children.splice(index, 1), + (beforeChild = children.indexOf(beforeChild)), + children.splice(beforeChild, 0, child), + UIManager.manageChildren( + parentInstance._nativeTag, + [index], + [beforeChild], + [], + [], + [] + )) + : ((index = children.indexOf(beforeChild)), + children.splice(index, 0, child), + UIManager.manageChildren( + parentInstance._nativeTag, + [], + [], + ["number" === typeof child ? child : child._nativeTag], + [index], + [] + )); + }, + insertInContainerBefore: function(parentInstance) { + invariant( + "number" !== typeof parentInstance, + "Container does not support insertBefore operation" + ); + }, + removeChild: function(parentInstance, child) { + recursivelyUncacheFiberNode(child); + var children = parentInstance._children; + child = children.indexOf(child); + children.splice(child, 1); + UIManager.manageChildren( + parentInstance._nativeTag, + [], + [], + [], + [], + [child] + ); + }, + removeChildFromContainer: function(parentInstance, child) { + recursivelyUncacheFiberNode(child); + UIManager.manageChildren(parentInstance, [], [], [], [], [0]); + }, + resetTextContent: function() {} + } + }), + getInspectorDataForViewTag = void 0; +getInspectorDataForViewTag = function() { + invariant(!1, "getInspectorDataForViewTag() is not available in production"); +}; +var findHostInstance = NativeRenderer.findHostInstance; +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; +} +_batchedUpdates = NativeRenderer.batchedUpdates; +_flushInteractiveUpdates = NativeRenderer.flushInteractiveUpdates; +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() { + TextInputState.blurTextInput(findNodeHandle(this)); + }; + ReactNativeComponent.prototype.focus = function() { + TextInputState.focusTextInput(findNodeHandle(this)); + }; + ReactNativeComponent.prototype.measure = function(callback) { + UIManager.measure( + findNodeHandle(this), + mountSafeCallback(this, callback) + ); + }; + ReactNativeComponent.prototype.measureInWindow = function(callback) { + UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback(this, callback) + ); + }; + ReactNativeComponent.prototype.measureLayout = function( + relativeToNativeNode, + onSuccess, + onFail + ) { + UIManager.measureLayout( + findNodeHandle(this), + relativeToNativeNode, + mountSafeCallback(this, onFail), + mountSafeCallback(this, onSuccess) + ); + }; + ReactNativeComponent.prototype.setNativeProps = function(nativeProps) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + if (null != maybeInstance) { + var viewConfig = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + nativeProps = diffProperties( + null, + emptyObject$1, + nativeProps, + viewConfig.validAttributes + ); + null != nativeProps && + UIManager.updateView( + maybeInstance._nativeTag, + viewConfig.uiViewClassName, + nativeProps + ); + } + }; + return ReactNativeComponent; + })(React.Component); + })(findNodeHandle, findHostInstance), + findNodeHandle: findNodeHandle, + render: function(element, containerTag, callback) { + var root = roots.get(containerTag); + root || + ((root = NativeRenderer.createContainer(containerTag, !1, !1)), + roots.set(containerTag, root)); + NativeRenderer.updateContainer(element, root, null, callback); + return NativeRenderer.getPublicRootInstance(root); + }, + unmountComponentAtNode: function(containerTag) { + var root = roots.get(containerTag); + root && + NativeRenderer.updateContainer(null, root, null, function() { + roots["delete"](containerTag); + }); + }, + unmountComponentAtNodeAndRemoveContainer: function(containerTag) { + ReactNativeRenderer.unmountComponentAtNode(containerTag); + 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) { + UIManager.measure( + findNodeHandle(this), + mountSafeCallback(this, callback) + ); + }, + measureInWindow: function(callback) { + UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback(this, callback) + ); + }, + measureLayout: function(relativeToNativeNode, onSuccess, onFail) { + UIManager.measureLayout( + findNodeHandle(this), + relativeToNativeNode, + mountSafeCallback(this, onFail), + mountSafeCallback(this, onSuccess) + ); + }, + setNativeProps: function(nativeProps) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + if (null != maybeInstance) { + var viewConfig = maybeInstance.viewConfig; + nativeProps = diffProperties( + null, + emptyObject$1, + nativeProps, + viewConfig.validAttributes + ); + null != nativeProps && + UIManager.updateView( + maybeInstance._nativeTag, + viewConfig.uiViewClassName, + nativeProps + ); + } + }, + focus: function() { + TextInputState.focusTextInput(findNodeHandle(this)); + }, + blur: function() { + TextInputState.blurTextInput(findNodeHandle(this)); + } + }; + })(findNodeHandle, findHostInstance), + ReactNativeComponentTree: ReactNativeComponentTree, + computeComponentStackForErrorReporting: function(reactTag) { + return (reactTag = getInstanceFromTag(reactTag)) + ? getStackAddendumByWorkInProgressFiber(reactTag) + : ""; + } + } + }; +NativeRenderer.injectIntoDevTools({ + findFiberByHostInstance: getInstanceFromTag, + getInspectorDataForViewTag: getInspectorDataForViewTag, + bundleType: 0, + version: "16.3.2", + rendererPackageName: "react-native-renderer" +}); +var ReactNativeRenderer$2 = Object.freeze({ default: ReactNativeRenderer }), + ReactNativeRenderer$3 = + (ReactNativeRenderer$2 && ReactNativeRenderer) || ReactNativeRenderer$2; +module.exports = ReactNativeRenderer$3["default"] + ? ReactNativeRenderer$3["default"] + : ReactNativeRenderer$3; diff --git a/Libraries/Renderer/shims/ReactNativeTypes.js b/Libraries/Renderer/shims/ReactNativeTypes.js index 1f7f5d0015a2ad..bf94119739334d 100644 --- a/Libraries/Renderer/shims/ReactNativeTypes.js +++ b/Libraries/Renderer/shims/ReactNativeTypes.js @@ -77,6 +77,11 @@ type SecretInternalsType = { // And how much information to fill in for the above types. }; +type SecretInternalsFabricType = { + NativeMethodsMixin: NativeMethodsMixinType, + ReactNativeComponentTree: any, +}; + /** * Flat ReactNative renderer bundles are too big for Flow to parse efficiently. * Provide minimal Flow typing for the high-level RN API and call it a day. @@ -106,5 +111,5 @@ export type ReactFabricType = { ): any, unmountComponentAtNode(containerTag: number): any, - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: SecretInternalsType, + __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: SecretInternalsFabricType, }; diff --git a/package.json b/package.json index 066c873aa89fc2..c28da3b6dc120f 100644 --- a/package.json +++ b/package.json @@ -142,7 +142,7 @@ "react-native": "local-cli/wrong-react-native.js" }, "peerDependencies": { - "react": "16.3.1" + "react": "16.3.2" }, "dependencies": { "absolute-path": "^0.0.0", @@ -210,8 +210,8 @@ "jest": "23.0.0-alpha.4", "jest-junit": "3.6.0", "prettier": "1.9.1", - "react": "16.3.1", - "react-test-renderer": "16.3.1", + "react": "16.3.2", + "react-test-renderer": "16.3.2", "shelljs": "^0.7.8", "sinon": "^2.2.0" } From b92b38acf9c7e5c8c16e082e898716c840fa3e89 Mon Sep 17 00:00:00 2001 From: Hugo Sousa Date: Wed, 18 Apr 2018 17:37:26 -0700 Subject: [PATCH 0332/1109] Remove extra space in source_files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: This was causing tvOS builds to fail because .m files weren’t being included. - Add `tvOS` subspec to your project with a tvOS target. - Build - Profit. [TVOS] [BREAKING] [React.podspec] - Fix building for tvOS with CocoaPods Closes https://github.com/facebook/react-native/pull/18812 Differential Revision: D7680224 Pulled By: hramos fbshipit-source-id: c6c3b6fb0acd2004579d85c3f72e4edd88e26ed8 --- React.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/React.podspec b/React.podspec index 027016aa07cbd7..030989c3d31714 100644 --- a/React.podspec +++ b/React.podspec @@ -105,7 +105,7 @@ Pod::Spec.new do |s| s.subspec "tvOS" do |ss| ss.dependency "React/Core" - ss.source_files = "React/**/RCTTV*.{h, m}" + ss.source_files = "React/**/RCTTV*.{h,m}" end s.subspec "jschelpers" do |ss| From 4fcd9970bd2dfb24890bc87e9c82e16dab71ec09 Mon Sep 17 00:00:00 2001 From: "Andrew Chen (Eng)" Date: Wed, 18 Apr 2018 18:10:22 -0700 Subject: [PATCH 0333/1109] Fix crash when reloading with Perf Monitor enabled Reviewed By: mdvacca Differential Revision: D7678392 fbshipit-source-id: 5fcf3bda545896f48543a95d4885c6492fac961e --- .../devsupport/DebugOverlayController.java | 44 +++++++++++-------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DebugOverlayController.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DebugOverlayController.java index b56cbfc7e8c719..9450e27dc4bb0a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DebugOverlayController.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DebugOverlayController.java @@ -21,6 +21,7 @@ import com.facebook.common.logging.FLog; import com.facebook.react.bridge.ReactContext; +import com.facebook.react.bridge.UiThreadUtil; import com.facebook.react.common.ReactConstants; import javax.annotation.Nullable; @@ -94,25 +95,30 @@ public DebugOverlayController(ReactContext reactContext) { mWindowManager = (WindowManager) reactContext.getSystemService(Context.WINDOW_SERVICE); } - public void setFpsDebugViewVisible(boolean fpsDebugViewVisible) { - if (fpsDebugViewVisible && mFPSDebugViewContainer == null) { - if (!permissionCheck(mReactContext)) { - FLog.d(ReactConstants.TAG, "Wait for overlay permission to be set"); - return; - } - mFPSDebugViewContainer = new FpsView(mReactContext); - WindowManager.LayoutParams params = new WindowManager.LayoutParams( - WindowManager.LayoutParams.MATCH_PARENT, - WindowManager.LayoutParams.MATCH_PARENT, - WindowOverlayCompat.TYPE_SYSTEM_OVERLAY, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + public void setFpsDebugViewVisible(final boolean fpsDebugViewVisible) { + UiThreadUtil.runOnUiThread(new Runnable() { + @Override + public void run() { + if (fpsDebugViewVisible && mFPSDebugViewContainer == null) { + if (!permissionCheck(mReactContext)) { + FLog.d(ReactConstants.TAG, "Wait for overlay permission to be set"); + return; + } + mFPSDebugViewContainer = new FpsView(mReactContext); + WindowManager.LayoutParams params = new WindowManager.LayoutParams( + WindowManager.LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.MATCH_PARENT, + WindowOverlayCompat.TYPE_SYSTEM_OVERLAY, + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, - PixelFormat.TRANSLUCENT); - mWindowManager.addView(mFPSDebugViewContainer, params); - } else if (!fpsDebugViewVisible && mFPSDebugViewContainer != null) { - mFPSDebugViewContainer.removeAllViews(); - mWindowManager.removeView(mFPSDebugViewContainer); - mFPSDebugViewContainer = null; - } + PixelFormat.TRANSLUCENT); + mWindowManager.addView(mFPSDebugViewContainer, params); + } else if (!fpsDebugViewVisible && mFPSDebugViewContainer != null) { + mFPSDebugViewContainer.removeAllViews(); + mWindowManager.removeView(mFPSDebugViewContainer); + mFPSDebugViewContainer = null; + } + } + }); } } From 49655c6eb38e4354e368a5fbc387bc7981f1d9bd Mon Sep 17 00:00:00 2001 From: David Vacca Date: Wed, 18 Apr 2018 18:13:12 -0700 Subject: [PATCH 0334/1109] Fix BadtokenException thrown when opening Android Catalyst app Reviewed By: achen1 Differential Revision: D7676053 fbshipit-source-id: e0cf9541de131b7c21de9a2647e4270f78b0a107 --- .../devsupport/DevLoadingViewController.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 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 7641b25a3d9d07..bc6e6c3b7a7f7a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevLoadingViewController.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevLoadingViewController.java @@ -7,6 +7,7 @@ package com.facebook.react.devsupport; +import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.graphics.Color; @@ -33,6 +34,7 @@ /** * Controller to display loading messages on top of the screen. All methods are thread safe. */ +@TargetApi(Build.VERSION_CODES.CUPCAKE) public class DevLoadingViewController { private static final int COLOR_DARK_GREEN = Color.parseColor("#035900"); @@ -158,18 +160,16 @@ private void showInternal() { topOffset = rectangle.top; } - mDevLoadingPopup = new PopupWindow( - mDevLoadingView, - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT); + mDevLoadingPopup = new PopupWindow(currentActivity); mDevLoadingPopup.setTouchable(false); + mDevLoadingPopup.setWidth(ViewGroup.LayoutParams.MATCH_PARENT); + mDevLoadingPopup.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT); mDevLoadingPopup.showAtLocation( - currentActivity.getWindow().getDecorView(), - Gravity.NO_GRAVITY, - - 0, - topOffset); + currentActivity.getWindow().getDecorView(), + Gravity.NO_GRAVITY, + 0, + topOffset); } private void hideInternal() { From 7e824867ca9f6acb2e15905a44fdf887308d5b91 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Wed, 18 Apr 2018 18:17:50 -0700 Subject: [PATCH 0335/1109] Make Spacing cloneable Reviewed By: achen1 Differential Revision: D7626745 fbshipit-source-id: ca6070a99d561ee5d5dd27456116dd2de75d2bf3 --- .../react/uimanager/ReactShadowNodeImpl.java | 4 +++- .../java/com/facebook/react/uimanager/Spacing.java | 12 ++++++++++-- .../facebook/react/fabric/FabricUIManagerTest.java | 13 +++++++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java index d0eb127f6e29e4..a8118b1841d0b8 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java @@ -106,7 +106,7 @@ public YogaNode cloneNode(YogaNode oldYogaNode, private int mScreenY; private int mScreenWidth; private int mScreenHeight; - private final Spacing mDefaultPadding = new Spacing(0); + private final Spacing mDefaultPadding; private final float[] mPadding = new float[Spacing.ALL + 1]; private final boolean[] mPaddingIsPercent = new boolean[Spacing.ALL + 1]; private YogaNode mYogaNode; @@ -115,6 +115,7 @@ public YogaNode cloneNode(YogaNode oldYogaNode, private @Nullable ReactStylesDiffMap mNewProps; public ReactShadowNodeImpl() { + mDefaultPadding = new Spacing(0); if (!isVirtual()) { YogaNode node = YogaNodePool.get().acquire(); mYogaNode = node == null ? new YogaNode(sYogaConfig) : node; @@ -133,6 +134,7 @@ protected ReactShadowNodeImpl(ReactShadowNodeImpl original) { mShouldNotifyOnLayout = original.mShouldNotifyOnLayout; mIsLayoutOnly = original.mIsLayoutOnly; mNativeParent = original.mNativeParent; + mDefaultPadding = new Spacing(original.mDefaultPadding); // Cloned nodes should be always updated. mNodeUpdated = true; // "cached" screen coordinates are not cloned because FabricJS not always clone the last diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/Spacing.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/Spacing.java index 53bea8824d7607..e386db4db66420 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/Spacing.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/Spacing.java @@ -68,9 +68,9 @@ public class Spacing { 256, /*ALL*/ }; - private final float[] mSpacing = newFullSpacingArray(); + private final float[] mSpacing; private int mValueFlags = 0; - private float mDefaultValue; + private final float mDefaultValue; private boolean mHasAliasesSet; public Spacing() { @@ -79,6 +79,14 @@ public Spacing() { public Spacing(float defaultValue) { mDefaultValue = defaultValue; + mSpacing = newFullSpacingArray(); + } + + public Spacing(Spacing original) { + mDefaultValue = original.mDefaultValue; + mSpacing = Arrays.copyOf(original.mSpacing, original.mSpacing.length); + mValueFlags = original.mValueFlags; + mHasAliasesSet = original.mHasAliasesSet; } /** diff --git a/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java b/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java index 40c8b2e78d55e7..441003004bd119 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java @@ -29,6 +29,7 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; +import org.fest.assertions.data.Offset; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -113,6 +114,18 @@ public void testCloneNode() { assertThat(clonedNode.getChildAt(0)).isEqualTo(child); } + @Test + public void testDefaultSpacingCloning() { + ReactShadowNode node = createViewNode(); + node.setDefaultPadding(Spacing.LEFT, 10); + + ReactShadowNode clonedNode = mFabricUIManager.cloneNode(node); + + node.setDefaultPadding(Spacing.LEFT, 20); + assertThat(clonedNode.getStylePadding(Spacing.LEFT).value).isEqualTo(10f, Offset.offset(0.01f)); + assertThat(node.getStylePadding(Spacing.LEFT).value).isEqualTo(20f, Offset.offset(0.01f)); + } + @Test public void testCloneVirtualNode() { ReactRawTextShadowNode node = new ReactRawTextShadowNode(); From 3c0b8922e2c45760cd5635f4402563ae95ac5628 Mon Sep 17 00:00:00 2001 From: Peter van der Zee Date: Thu, 19 Apr 2018 02:30:39 -0700 Subject: [PATCH 0336/1109] Upgrade Prettier to v1.12.1 on fbsource Reviewed By: benjaffe, ryanmce, yungsters Differential Revision: D7652946 fbshipit-source-id: 396d45c675e93f2298cd2920d927630c81867447 --- Libraries/Image/Image.android.js | 16 ++++++++++------ Libraries/Lists/VirtualizedList.js | 8 +++++--- Libraries/StyleSheet/StyleSheetTypes.js | 10 ++++++---- package.json | 2 +- 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/Libraries/Image/Image.android.js b/Libraries/Image/Image.android.js index 870b31cd8f92cb..4c8fa6e7fd173d 100644 --- a/Libraries/Image/Image.android.js +++ b/Libraries/Image/Image.android.js @@ -75,8 +75,8 @@ var Image = createReactClass({ */ blurRadius: PropTypes.number, /** - * See https://facebook.github.io/react-native/docs/image.html#defaultsource - */ + * See https://facebook.github.io/react-native/docs/image.html#defaultsource + */ defaultSource: PropTypes.number, /** * See https://facebook.github.io/react-native/docs/image.html#loadingindicatorsource @@ -123,7 +123,13 @@ var Image = createReactClass({ * * See https://facebook.github.io/react-native/docs/image.html#resizemode */ - resizeMode: PropTypes.oneOf(['cover', 'contain', 'stretch', 'repeat', 'center']), + resizeMode: PropTypes.oneOf([ + 'cover', + 'contain', + 'stretch', + 'repeat', + 'center', + ]), }, statics: { @@ -254,9 +260,7 @@ var Image = createReactClass({ ), src: sources, headers: source.headers, - defaultSrc: defaultSource - ? defaultSource.uri - : null, + defaultSrc: defaultSource ? defaultSource.uri : null, loadingIndicatorSrc: loadingIndicatorSource ? loadingIndicatorSource.uri : null, diff --git a/Libraries/Lists/VirtualizedList.js b/Libraries/Lists/VirtualizedList.js index 2b1b83ff41bb0b..30e8777eaee43d 100644 --- a/Libraries/Lists/VirtualizedList.js +++ b/Libraries/Lists/VirtualizedList.js @@ -852,14 +852,14 @@ class VirtualizedList extends React.PureComponent { ); } } else if (ListEmptyComponent) { - const element: React.Element = (React.isValidElement( + const element: React.Element = ((React.isValidElement( ListEmptyComponent, ) ? ( ListEmptyComponent ) : ( // $FlowFixMe - ): any); + )): any); cells.push( React.cloneElement(element, { key: '$empty', @@ -1670,7 +1670,9 @@ class CellRenderer extends React.Component< ? horizontal ? [{flexDirection: 'row-reverse'}, inversionStyle] : [{flexDirection: 'column-reverse'}, inversionStyle] - : horizontal ? [{flexDirection: 'row'}, inversionStyle] : inversionStyle; + : horizontal + ? [{flexDirection: 'row'}, inversionStyle] + : inversionStyle; if (!CellRendererComponent) { return ( diff --git a/Libraries/StyleSheet/StyleSheetTypes.js b/Libraries/StyleSheet/StyleSheetTypes.js index ffec5b54bc7937..a176ca1e810785 100644 --- a/Libraries/StyleSheet/StyleSheetTypes.js +++ b/Libraries/StyleSheet/StyleSheetTypes.js @@ -103,14 +103,16 @@ export type ____TransformStyle_Internal = $ReadOnly<{| | {|+translateX: number | AnimatedNode|} | {|+translateY: number | AnimatedNode|} | {| - +translate: [number | AnimatedNode, number | AnimatedNode] | AnimatedNode, - |} + +translate: + | [number | AnimatedNode, number | AnimatedNode] + | AnimatedNode, + |} | {|+skewX: string|} | {|+skewY: string|} // TODO: what is the actual type it expects? | {| - +matrix: $ReadOnlyArray | AnimatedNode, - |}, + +matrix: $ReadOnlyArray | AnimatedNode, + |}, >, |}>; diff --git a/package.json b/package.json index c28da3b6dc120f..8cadfda93457f0 100644 --- a/package.json +++ b/package.json @@ -209,7 +209,7 @@ "flow-bin": "^0.70.0", "jest": "23.0.0-alpha.4", "jest-junit": "3.6.0", - "prettier": "1.9.1", + "prettier": "1.12.1", "react": "16.3.2", "react-test-renderer": "16.3.2", "shelljs": "^0.7.8", From 34bd776af2f2529009188fced91083203a48fd40 Mon Sep 17 00:00:00 2001 From: Peter van der Zee Date: Thu, 19 Apr 2018 03:53:40 -0700 Subject: [PATCH 0337/1109] Bump babel-preset-react-native version to 5.0.0 for Babel 7 Reviewed By: rafeca Differential Revision: D7685340 fbshipit-source-id: f229fb5da71f2f1d277d3d55eaa0f400aa76471b --- babel-preset/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/babel-preset/package.json b/babel-preset/package.json index 066af5f61b1537..120c8b7a68ee2e 100644 --- a/babel-preset/package.json +++ b/babel-preset/package.json @@ -1,6 +1,6 @@ { "name": "babel-preset-react-native", - "version": "4.0.0", + "version": "5.0.0", "description": "Babel preset for React Native applications", "main": "index.js", "repository": "https://github.com/facebook/react-native/tree/master/babel-preset", From 0f2e46e84b1513039e4bc6633ba04e69a44ed8ed Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Thu, 19 Apr 2018 08:14:59 -0700 Subject: [PATCH 0338/1109] Remove `Color` workspace Reviewed By: mjesun Differential Revision: D7637457 fbshipit-source-id: befee31c649edde654c05e7ba889f7c55b105b86 --- Libraries/Color/package.json | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 Libraries/Color/package.json diff --git a/Libraries/Color/package.json b/Libraries/Color/package.json deleted file mode 100644 index 1781e2e3d60bc2..00000000000000 --- a/Libraries/Color/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "Color", - "private": true, - "version": "0.0.0" -} From d408de0438bc186cf460f01c075a055cbb96dcda Mon Sep 17 00:00:00 2001 From: Peter van der Zee Date: Thu, 19 Apr 2018 09:09:05 -0700 Subject: [PATCH 0339/1109] Drop confusing comment Summary: Just removing a comment As per https://github.com/facebook/react-native/commit/f8d6b97140cffe8d18b2558f94570c8d1b410d5c#r28569388 While the comment was more to notify about this in general, I suppose it doesn't matter. Reviewed By: rafeca Differential Revision: D7685277 fbshipit-source-id: 2d526aeccc2e89b42ae25cbce21af5fe96f1348d --- babel-preset/configs/main.js | 1 - jest/preprocessor.js | 1 - 2 files changed, 2 deletions(-) diff --git a/babel-preset/configs/main.js b/babel-preset/configs/main.js index d17db86969f797..0b972f595b7428 100644 --- a/babel-preset/configs/main.js +++ b/babel-preset/configs/main.js @@ -15,7 +15,6 @@ const defaultPlugins = [ [ require('@babel/plugin-proposal-class-properties'), // use `this.foo = bar` instead of `this.defineProperty('foo', ...)` - // (Makes the properties enumerable) {loose: true}, ], [require('@babel/plugin-transform-computed-properties')], diff --git a/jest/preprocessor.js b/jest/preprocessor.js index a7c52411f19017..5e43175de95ed0 100644 --- a/jest/preprocessor.js +++ b/jest/preprocessor.js @@ -62,7 +62,6 @@ module.exports = { [ require('@babel/plugin-proposal-class-properties'), // use `this.foo = bar` instead of `this.defineProperty('foo', ...)` - // (Makes the properties enumerable) {loose: true}, ], [require('@babel/plugin-transform-computed-properties')], From c18684a2931ea407fef58755304c0b3f57c0dbef Mon Sep 17 00:00:00 2001 From: Peter van der Zee Date: Thu, 19 Apr 2018 09:09:06 -0700 Subject: [PATCH 0340/1109] Fix the metro paths for files detected as nodejs Summary: Fix the path lookup for files to be considered to run in nodejs. Reviewed By: mjesun Differential Revision: D7685278 fbshipit-source-id: c921d40b60d795820448842aec464e7ff82b6eab --- jest/preprocessor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jest/preprocessor.js b/jest/preprocessor.js index 5e43175de95ed0..563ad0389b22b8 100644 --- a/jest/preprocessor.js +++ b/jest/preprocessor.js @@ -24,7 +24,7 @@ const generate = require('@babel/generator').default; const nodeFiles = RegExp([ '/local-cli/', - '/metro(-bundler)?/', + '/metro(?:-[^\/]*)?/', // metro, metro-core, metro-source-map, metro-etc ].join('|')); const nodeOptions = babelRegisterOnly.config([nodeFiles]); From da57ae740d30b1c8d1616028139eb96e82157170 Mon Sep 17 00:00:00 2001 From: Peter van der Zee Date: Thu, 19 Apr 2018 09:09:08 -0700 Subject: [PATCH 0341/1109] Add `ast: true` to transform options for jest Summary: This should (at least partially) fix testing for OSS as per https://github.com/facebook/react-native/commit/f8d6b97140cffe8d18b2558f94570c8d1b410d5c#r28647044 Might be related to not locking down the Babel version, will do that in a different commit. Reviewed By: mjesun Differential Revision: D7685279 fbshipit-source-id: f00febfad2cec31b7e11996ee8efa2c96b44477b --- jest/preprocessor.js | 1 + 1 file changed, 1 insertion(+) diff --git a/jest/preprocessor.js b/jest/preprocessor.js index 563ad0389b22b8..18ef328e5f440e 100644 --- a/jest/preprocessor.js +++ b/jest/preprocessor.js @@ -46,6 +46,7 @@ module.exports = { localPath: file, options: { assetDataPlugins: [], + ast: true, // needed for open source (?) https://github.com/facebook/react-native/commit/f8d6b97140cffe8d18b2558f94570c8d1b410d5c#r28647044 dev: true, inlineRequires: true, minify: false, From 864235636787cf7888938070df5dec030547df19 Mon Sep 17 00:00:00 2001 From: Peter van der Zee Date: Thu, 19 Apr 2018 09:09:10 -0700 Subject: [PATCH 0342/1109] Drop workspace from metro lookup Summary: Fix the path lookup for metro root. Reviewed By: mjesun Differential Revision: D7685280 fbshipit-source-id: 8d506bbf9c5af297d4050d2fa73475fd280bb186 --- setupBabel.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setupBabel.js b/setupBabel.js index 0b21ffe31f5c7d..6bac7dde43aead 100644 --- a/setupBabel.js +++ b/setupBabel.js @@ -23,8 +23,8 @@ function buildRegExps(basePath, dirPaths) { folderPath => folderPath === 'metro' // metro uses flow (for example) which needs to be stripped out w/babel. - // it'll resolve to .../metro/packages/metro/src/index.js we want root - ? path.resolve(require.resolve('metro'), '..', '..', '..', '..') + // it'll resolve to .../metro/src/index.js we want root + ? path.resolve(require.resolve('metro'), '..') // Babel `only` option works with forward slashes in the RegExp so replace // backslashes for Windows. : folderPath instanceof RegExp From 3aa453d975794faa38f21a78c232628c6f4233db Mon Sep 17 00:00:00 2001 From: Peter van der Zee Date: Thu, 19 Apr 2018 09:53:11 -0700 Subject: [PATCH 0343/1109] Add sourceType as a new mandatory option Summary: The `sourceType` option is a new mandatory option for Babel which determines whether to parse the file with the module or script goal. The value "disambiguous" determines this state by parsing. See https://github.com/babel/babel/pull/7417 Reviewed By: mjesun Differential Revision: D7685610 fbshipit-source-id: 3958c5ad396592bb1d790e2df4ce315737421a2f --- jest/preprocessor.js | 1 + 1 file changed, 1 insertion(+) diff --git a/jest/preprocessor.js b/jest/preprocessor.js index 18ef328e5f440e..170f7091c30824 100644 --- a/jest/preprocessor.js +++ b/jest/preprocessor.js @@ -53,6 +53,7 @@ module.exports = { platform: '', projectRoot: '', retainLines: true, + sourceType: 'unambiguous', // b7 required. detects module vs script mode }, src, plugins: [ From dc836780cbe71c5152a4861bd6a2dba1549bc53f Mon Sep 17 00:00:00 2001 From: David Vacca Date: Thu, 19 Apr 2018 10:46:33 -0700 Subject: [PATCH 0344/1109] Make ShadowNodeRegistry thread safe Reviewed By: achen1 Differential Revision: D7679621 fbshipit-source-id: 1003578edcf9107b736d876dac969f22f9e62b6d --- .../com/facebook/react/uimanager/ShadowNodeRegistry.java | 4 +--- .../com/facebook/react/uimanager/UIImplementation.java | 7 ++++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ShadowNodeRegistry.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ShadowNodeRegistry.java index 1b3cebc1fb2495..bc68ab32607933 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ShadowNodeRegistry.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ShadowNodeRegistry.java @@ -28,9 +28,7 @@ public ShadowNodeRegistry() { } public void addRootNode(ReactShadowNode node) { - // TODO(6242243): This should be asserted... but UIManagerModule is - // thread-unsafe and calls this on the wrong thread. - //mThreadAsserter.assertNow(); + mThreadAsserter.assertNow(); int tag = node.getReactTag(); mTagsToCSSNodes.put(tag, node); mRootTags.put(tag, true); diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java index 186a4d4357c325..5f124ab88ab4e1 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java @@ -205,7 +205,12 @@ public void register int heightMeasureSpec = rootView.getHeightMeasureSpec(); updateRootView(rootCSSNode, widthMeasureSpec, heightMeasureSpec); - mShadowNodeRegistry.addRootNode(rootCSSNode); + context.runOnNativeModulesQueueThread(new Runnable() { + @Override + public void run() { + mShadowNodeRegistry.addRootNode(rootCSSNode); + } + }); // register it within NativeViewHierarchyManager mOperationsQueue.addRootView(tag, rootView, context); From 60b05133baafe9ec4020d5ddf99b71a2302ba3dc Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Thu, 19 Apr 2018 11:03:50 -0700 Subject: [PATCH 0345/1109] Unforked renderApplication() Summary: This allows toggling fabric renderer via the same renderApplication() Reviewed By: mdvacca Differential Revision: D7682524 fbshipit-source-id: 59be1d2bea15f5e13e64e2d72304d79f9cb7d084 --- Libraries/ReactNative/AppContainer.js | 4 +- Libraries/ReactNative/AppRegistry.js | 19 +------ Libraries/ReactNative/renderApplication.js | 8 ++- Libraries/ReactNative/renderFabricSurface.js | 59 -------------------- 4 files changed, 10 insertions(+), 80 deletions(-) delete mode 100644 Libraries/ReactNative/renderFabricSurface.js diff --git a/Libraries/ReactNative/AppContainer.js b/Libraries/ReactNative/AppContainer.js index 3060d6de450049..cb1ea048e4adbc 100644 --- a/Libraries/ReactNative/AppContainer.js +++ b/Libraries/ReactNative/AppContainer.js @@ -27,7 +27,6 @@ type Props = {| * suppresses an error when upgrading Flow's support for React. To see the * error delete this comment and run Flow. */ children?: React.Children, - fabric?: boolean, rootTag: number, WrapperComponent?: ?React.ComponentType<*>, |}; @@ -91,8 +90,7 @@ class AppContainer extends React.Component { render(): React.Node { let yellowBox = null; if (__DEV__) { - if (!global.__RCTProfileIsProfiling && !this.props.fabric) { - // TODO: Fabric doesn't support YellowBox. + if (!global.__RCTProfileIsProfiling) { const YellowBox = require('YellowBox'); yellowBox = ; } diff --git a/Libraries/ReactNative/AppRegistry.js b/Libraries/ReactNative/AppRegistry.js index 8ddfb64118d043..efe8e5584f2f0a 100644 --- a/Libraries/ReactNative/AppRegistry.js +++ b/Libraries/ReactNative/AppRegistry.js @@ -20,10 +20,6 @@ const infoLog = require('infoLog'); const invariant = require('fbjs/lib/invariant'); const renderApplication = require('renderApplication'); -// Renderer provider must be supplied by each app. If none, traditional -// renderApplication() will be used. -let fabricRendererProvider: ?() => typeof renderApplication = null; - type Task = (taskData: any) => Promise; type TaskProvider = () => Task; export type ComponentProvider = () => React$ComponentType; @@ -102,19 +98,12 @@ const AppRegistry = { runnables[appKey] = { componentProvider, run: appParameters => { - let renderFunc = renderApplication; - if (appParameters.fabric) { - invariant( - fabricRendererProvider != null, - 'A Fabric renderer provider must be set to render Fabric components', - ); - renderFunc = fabricRendererProvider(); - } - renderFunc( + renderApplication( componentProviderInstrumentationHook(componentProvider), appParameters.initialProps, appParameters.rootTag, wrapperComponentProvider && wrapperComponentProvider(appParameters), + appParameters.fabric, ); }, }; @@ -249,10 +238,6 @@ const AppRegistry = { NativeModules.HeadlessJsTaskSupport.notifyTaskFinished(taskId); }); }, - - setFabricRendererProvider(provider: () => typeof renderApplication): void { - fabricRendererProvider = provider; - }, }; BatchedBridge.registerCallableModule('AppRegistry', AppRegistry); diff --git a/Libraries/ReactNative/renderApplication.js b/Libraries/ReactNative/renderApplication.js index 896c88207eb068..8abfed260402b5 100644 --- a/Libraries/ReactNative/renderApplication.js +++ b/Libraries/ReactNative/renderApplication.js @@ -13,6 +13,7 @@ const AppContainer = require('AppContainer'); const React = require('React'); +const ReactFabric = require('ReactFabric'); const ReactNative = require('ReactNative'); const invariant = require('fbjs/lib/invariant'); @@ -25,6 +26,7 @@ function renderApplication( initialProps: Props, rootTag: any, WrapperComponent?: ?React.ComponentType<*>, + fabric?: boolean, ) { invariant(rootTag, 'Expect to have a valid rootTag, instead got ', rootTag); @@ -49,7 +51,11 @@ function renderApplication( renderable = {renderable}; } - ReactNative.render(renderable, rootTag); + if (fabric) { + ReactFabric.render(renderable, rootTag); + } else { + ReactNative.render(renderable, rootTag); + } } module.exports = renderApplication; diff --git a/Libraries/ReactNative/renderFabricSurface.js b/Libraries/ReactNative/renderFabricSurface.js deleted file mode 100644 index 0279f1759926d6..00000000000000 --- a/Libraries/ReactNative/renderFabricSurface.js +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule renderFabricSurface - * @format - * @flow - */ - -'use strict'; - -const AppContainer = require('AppContainer'); -const React = require('React'); -const ReactFabric = require('ReactFabric'); - -const invariant = require('fbjs/lib/invariant'); - -// require BackHandler so it sets the default handler that exits the app if no listeners respond -require('BackHandler'); - -// Note: this is a fork of renderApplication.js to simply invoke ReactFabric. -function renderFabricSurface( - RootComponent: React.ComponentType, - initialProps: Props, - rootTag: any, - WrapperComponent?: ?React.ComponentType<*>, -) { - invariant(rootTag, 'Expect to have a valid rootTag, instead got ', rootTag); - - let renderable = ( - - - - ); - - // If the root component is async, the user probably wants the initial render - // to be async also. To do this, wrap AppContainer with an async marker. - // For more info see https://fb.me/is-component-async - if ( - /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an - * error found when Flow v0.68 was deployed. To see the error delete this - * comment and run Flow. */ - RootComponent.prototype != null && - RootComponent.prototype.unstable_isAsyncReactComponent === true - ) { - // $FlowFixMe This is not yet part of the official public API - const AsyncMode = React.unstable_AsyncMode; - renderable = {renderable}; - } - - ReactFabric.render(renderable, rootTag); -} - -module.exports = renderFabricSurface; From c5ca26a0e5c0660196300ee34d6007c63879611f Mon Sep 17 00:00:00 2001 From: Himabindu Gadupudi Date: Thu, 19 Apr 2018 11:06:28 -0700 Subject: [PATCH 0346/1109] Correct draw path dimensions while doing even border Reviewed By: achen1 Differential Revision: D7678473 fbshipit-source-id: 8aa5eb29d22379eaabf9951a901e237fb7569632 --- .../view/ReactViewBackgroundDrawable.java | 227 +++++++++++------- 1 file changed, 139 insertions(+), 88 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java index 9e374b4c502ecb..1a31a0cc38bd37 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java @@ -90,9 +90,11 @@ private static enum BorderStyle { private @Nullable Path mOuterClipPathForBorderRadius; private @Nullable Path mPathForBorderRadiusOutline; private @Nullable Path mPathForBorder; + private @Nullable Path mCenterDrawPath; private @Nullable RectF mInnerClipTempRectForBorderRadius; private @Nullable RectF mOuterClipTempRectForBorderRadius; private @Nullable RectF mTempRectForBorderRadiusOutline; + private @Nullable RectF mTempRectForCenterDrawPath; private @Nullable PointF mInnerTopLeftCorner; private @Nullable PointF mInnerTopRightCorner; private @Nullable PointF mInnerBottomRightCorner; @@ -343,110 +345,130 @@ private void drawRoundedBackgroundWithBorders(Canvas canvas) { || borderWidth.bottom > 0 || borderWidth.left > 0 || borderWidth.right > 0) { - mPaint.setStyle(Paint.Style.FILL); - // Draw border - canvas.clipPath(mOuterClipPathForBorderRadius, Region.Op.INTERSECT); - canvas.clipPath(mInnerClipPathForBorderRadius, Region.Op.DIFFERENCE); + //If it's a full and even border draw inner rect path with stroke + final float fullBorderWidth = getFullBorderWidth(); + if (borderWidth.top == fullBorderWidth && + borderWidth.bottom == fullBorderWidth && + borderWidth.left == fullBorderWidth && + borderWidth.right == fullBorderWidth) { + if (fullBorderWidth > 0) { + int borderColor = getBorderColor(Spacing.ALL); + mPaint.setColor(ColorUtil.multiplyColorAlpha(borderColor, mAlpha)); + mPaint.setStyle(Paint.Style.STROKE); + mPaint.setStrokeWidth(fullBorderWidth); + canvas.drawPath(mCenterDrawPath, mPaint); + } + } + //In the case of uneven border widths/colors draw quadrilateral in each direction + else { + mPaint.setStyle(Paint.Style.FILL); - int colorLeft = getBorderColor(Spacing.LEFT); - int colorTop = getBorderColor(Spacing.TOP); - int colorRight = getBorderColor(Spacing.RIGHT); - int colorBottom = getBorderColor(Spacing.BOTTOM); + // Draw border + canvas.clipPath(mOuterClipPathForBorderRadius, Region.Op.INTERSECT); + canvas.clipPath(mInnerClipPathForBorderRadius, Region.Op.DIFFERENCE); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - final boolean isRTL = getResolvedLayoutDirection() == View.LAYOUT_DIRECTION_RTL; - int colorStart = getBorderColor(Spacing.START); - int colorEnd = getBorderColor(Spacing.END); + int colorLeft = getBorderColor(Spacing.LEFT); + int colorTop = getBorderColor(Spacing.TOP); + int colorRight = getBorderColor(Spacing.RIGHT); + int colorBottom = getBorderColor(Spacing.BOTTOM); - if (I18nUtil.getInstance().doLeftAndRightSwapInRTL(mContext)) { - if (!isBorderColorDefined(Spacing.START)) { - colorStart = colorLeft; - } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + final boolean isRTL = getResolvedLayoutDirection() == View.LAYOUT_DIRECTION_RTL; + int colorStart = getBorderColor(Spacing.START); + int colorEnd = getBorderColor(Spacing.END); - if (!isBorderColorDefined(Spacing.END)) { - colorEnd = colorRight; - } + if (I18nUtil.getInstance().doLeftAndRightSwapInRTL(mContext)) { + if (!isBorderColorDefined(Spacing.START)) { + colorStart = colorLeft; + } - final int directionAwareColorLeft = isRTL ? colorEnd : colorStart; - final int directionAwareColorRight = isRTL ? colorStart : colorEnd; + if (!isBorderColorDefined(Spacing.END)) { + colorEnd = colorRight; + } - colorLeft = directionAwareColorLeft; - colorRight = directionAwareColorRight; - } else { - final int directionAwareColorLeft = isRTL ? colorEnd : colorStart; - final int directionAwareColorRight = isRTL ? colorStart : colorEnd; + final int directionAwareColorLeft = isRTL ? colorEnd : colorStart; + final int directionAwareColorRight = isRTL ? colorStart : colorEnd; - final boolean isColorStartDefined = isBorderColorDefined(Spacing.START); - final boolean isColorEndDefined = isBorderColorDefined(Spacing.END); - final boolean isDirectionAwareColorLeftDefined = isRTL ? isColorEndDefined : isColorStartDefined; - final boolean isDirectionAwareColorRightDefined = isRTL ? isColorStartDefined : isColorEndDefined; - - if (isDirectionAwareColorLeftDefined) { colorLeft = directionAwareColorLeft; - } - - if (isDirectionAwareColorRightDefined) { colorRight = directionAwareColorRight; + } else { + final int directionAwareColorLeft = isRTL ? colorEnd : colorStart; + final int directionAwareColorRight = isRTL ? colorStart : colorEnd; + + final boolean isColorStartDefined = isBorderColorDefined(Spacing.START); + final boolean isColorEndDefined = isBorderColorDefined(Spacing.END); + final boolean isDirectionAwareColorLeftDefined = + isRTL ? isColorEndDefined : isColorStartDefined; + final boolean isDirectionAwareColorRightDefined = + isRTL ? isColorStartDefined : isColorEndDefined; + + if (isDirectionAwareColorLeftDefined) { + colorLeft = directionAwareColorLeft; + } + + if (isDirectionAwareColorRightDefined) { + colorRight = directionAwareColorRight; + } } } - } - final float left = mOuterClipTempRectForBorderRadius.left; - final float right = mOuterClipTempRectForBorderRadius.right; - final float top = mOuterClipTempRectForBorderRadius.top; - final float bottom = mOuterClipTempRectForBorderRadius.bottom; - - if (borderWidth.left > 0) { - final float x1 = left; - final float y1 = top; - final float x2 = mInnerTopLeftCorner.x; - final float y2 = mInnerTopLeftCorner.y; - final float x3 = mInnerBottomLeftCorner.x; - final float y3 = mInnerBottomLeftCorner.y; - final float x4 = left; - final float y4 = bottom; - - drawQuadrilateral(canvas, colorLeft, x1, y1, x2, y2, x3, y3, x4, y4); - } + final float left = mOuterClipTempRectForBorderRadius.left; + final float right = mOuterClipTempRectForBorderRadius.right; + final float top = mOuterClipTempRectForBorderRadius.top; + final float bottom = mOuterClipTempRectForBorderRadius.bottom; - if (borderWidth.top > 0) { - final float x1 = left; - final float y1 = top; - final float x2 = mInnerTopLeftCorner.x; - final float y2 = mInnerTopLeftCorner.y; - final float x3 = mInnerTopRightCorner.x; - final float y3 = mInnerTopRightCorner.y; - final float x4 = right; - final float y4 = top; - - drawQuadrilateral(canvas, colorTop, x1, y1, x2, y2, x3, y3, x4, y4); - } + if (borderWidth.left > 0) { + final float x1 = left; + final float y1 = top; + final float x2 = mInnerTopLeftCorner.x; + final float y2 = mInnerTopLeftCorner.y; + final float x3 = mInnerBottomLeftCorner.x; + final float y3 = mInnerBottomLeftCorner.y; + final float x4 = left; + final float y4 = bottom; - if (borderWidth.right > 0) { - final float x1 = right; - final float y1 = top; - final float x2 = mInnerTopRightCorner.x; - final float y2 = mInnerTopRightCorner.y; - final float x3 = mInnerBottomRightCorner.x; - final float y3 = mInnerBottomRightCorner.y; - final float x4 = right; - final float y4 = bottom; - - drawQuadrilateral(canvas, colorRight, x1, y1, x2, y2, x3, y3, x4, y4); - } + drawQuadrilateral(canvas, colorLeft, x1, y1, x2, y2, x3, y3, x4, y4); + } + + if (borderWidth.top > 0) { + final float x1 = left; + final float y1 = top; + final float x2 = mInnerTopLeftCorner.x; + final float y2 = mInnerTopLeftCorner.y; + final float x3 = mInnerTopRightCorner.x; + final float y3 = mInnerTopRightCorner.y; + final float x4 = right; + final float y4 = top; + + drawQuadrilateral(canvas, colorTop, x1, y1, x2, y2, x3, y3, x4, y4); + } + + if (borderWidth.right > 0) { + final float x1 = right; + final float y1 = top; + final float x2 = mInnerTopRightCorner.x; + final float y2 = mInnerTopRightCorner.y; + final float x3 = mInnerBottomRightCorner.x; + final float y3 = mInnerBottomRightCorner.y; + final float x4 = right; + final float y4 = bottom; - if (borderWidth.bottom > 0) { - final float x1 = left; - final float y1 = bottom; - final float x2 = mInnerBottomLeftCorner.x; - final float y2 = mInnerBottomLeftCorner.y; - final float x3 = mInnerBottomRightCorner.x; - final float y3 = mInnerBottomRightCorner.y; - final float x4 = right; - final float y4 = bottom; - - drawQuadrilateral(canvas, colorBottom, x1, y1, x2, y2, x3, y3, x4, y4); + drawQuadrilateral(canvas, colorRight, x1, y1, x2, y2, x3, y3, x4, y4); + } + + if (borderWidth.bottom > 0) { + final float x1 = left; + final float y1 = bottom; + final float x2 = mInnerBottomLeftCorner.x; + final float y2 = mInnerBottomLeftCorner.y; + final float x3 = mInnerBottomRightCorner.x; + final float y3 = mInnerBottomRightCorner.y; + final float x4 = right; + final float y4 = bottom; + + drawQuadrilateral(canvas, colorBottom, x1, y1, x2, y2, x3, y3, x4, y4); + } } } @@ -472,6 +494,10 @@ private void updatePath() { mPathForBorderRadiusOutline = new Path(); } + if (mCenterDrawPath == null) { + mCenterDrawPath = new Path(); + } + if (mInnerClipTempRectForBorderRadius == null) { mInnerClipTempRectForBorderRadius = new RectF(); } @@ -484,13 +510,24 @@ private void updatePath() { mTempRectForBorderRadiusOutline = new RectF(); } + if (mTempRectForCenterDrawPath == null) { + mTempRectForCenterDrawPath = new RectF(); + } + mInnerClipPathForBorderRadius.reset(); mOuterClipPathForBorderRadius.reset(); mPathForBorderRadiusOutline.reset(); + mCenterDrawPath.reset(); mInnerClipTempRectForBorderRadius.set(getBounds()); mOuterClipTempRectForBorderRadius.set(getBounds()); mTempRectForBorderRadiusOutline.set(getBounds()); + mTempRectForCenterDrawPath.set(getBounds()); + + float fullBorderWidth = getFullBorderWidth(); + if (fullBorderWidth > 0) { + mTempRectForCenterDrawPath.inset(fullBorderWidth * 0.5f, fullBorderWidth * 0.5f); + } final RectF borderWidth = getDirectionAwareBorderInsets(); @@ -623,6 +660,20 @@ private void updatePath() { }, Path.Direction.CW); + mCenterDrawPath.addRoundRect( + mTempRectForCenterDrawPath, + new float[] { + innerTopLeftRadiusX + extraRadiusForOutline, + innerTopLeftRadiusY + extraRadiusForOutline, + innerTopRightRadiusX + extraRadiusForOutline, + innerTopRightRadiusY + extraRadiusForOutline, + innerBottomRightRadiusX + extraRadiusForOutline, + innerBottomRightRadiusY + extraRadiusForOutline, + innerBottomLeftRadiusX + extraRadiusForOutline, + innerBottomLeftRadiusY + extraRadiusForOutline + }, + Path.Direction.CW); + /** * Rounded Multi-Colored Border Algorithm: * From 654435d1ed9e584e65fff601e1fa50591e042664 Mon Sep 17 00:00:00 2001 From: Knott Wittawat Date: Thu, 19 Apr 2018 13:13:10 -0700 Subject: [PATCH 0347/1109] Fix VoiceOver not identifying the header correctly Reviewed By: sophiebits Differential Revision: D7678644 fbshipit-source-id: ee6c57f2a603eed1c41f22a4142474ab6957ccdf --- Libraries/Text/TextProps.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Libraries/Text/TextProps.js b/Libraries/Text/TextProps.js index 20eb363765e215..effc8b05480b92 100644 --- a/Libraries/Text/TextProps.js +++ b/Libraries/Text/TextProps.js @@ -11,6 +11,8 @@ 'use strict'; +import type {AccessibilityTrait} from 'ViewAccessibility'; + import type {Node} from 'react'; import type {LayoutEvent, PressEvent} from 'CoreEventTypes'; @@ -28,6 +30,7 @@ type PressRetentionOffset = { */ export type TextProps = $ReadOnly<{ accessible?: ?boolean, + accessibilityTraits?: AccessibilityTrait | Array, allowFontScaling?: ?boolean, children?: Node, ellipsizeMode?: 'clip' | 'head' | 'middle' | 'tail', From d69e55060fd76d91eccc45905d250a9fce4b2c49 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Thu, 19 Apr 2018 15:42:49 -0700 Subject: [PATCH 0348/1109] RN: Support `flexWrap: 'wrap-reverse'` Reviewed By: fkgozali Differential Revision: D7684403 fbshipit-source-id: 6c247ba86b8ad1bb4dcc8f44f5609c939afe0f06 --- Libraries/StyleSheet/LayoutPropTypes.js | 3 ++- Libraries/StyleSheet/StyleSheetTypes.js | 2 +- React/Base/RCTConvert.m | 3 ++- .../java/com/facebook/react/uimanager/LayoutShadowNode.java | 4 ++++ 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Libraries/StyleSheet/LayoutPropTypes.js b/Libraries/StyleSheet/LayoutPropTypes.js index 5921334c5b7cea..02ec8733f6bbd8 100644 --- a/Libraries/StyleSheet/LayoutPropTypes.js +++ b/Libraries/StyleSheet/LayoutPropTypes.js @@ -432,7 +432,8 @@ var LayoutPropTypes = { */ flexWrap: ReactPropTypes.oneOf([ 'wrap', - 'nowrap' + 'nowrap', + 'wrap-reverse' ]), /** `justifyContent` aligns children in the main direction. diff --git a/Libraries/StyleSheet/StyleSheetTypes.js b/Libraries/StyleSheet/StyleSheetTypes.js index a176ca1e810785..1134c252deeb81 100644 --- a/Libraries/StyleSheet/StyleSheetTypes.js +++ b/Libraries/StyleSheet/StyleSheetTypes.js @@ -57,7 +57,7 @@ export type ____LayoutStyle_Internal = $ReadOnly<{| borderTopWidth?: number, position?: 'absolute' | 'relative', flexDirection?: 'row' | 'row-reverse' | 'column' | 'column-reverse', - flexWrap?: 'wrap' | 'nowrap', + flexWrap?: 'wrap' | 'nowrap' | 'wrap-reverse', justifyContent?: | 'flex-start' | 'flex-end' diff --git a/React/Base/RCTConvert.m b/React/Base/RCTConvert.m index 173c9047530491..7528259fda00ad 100644 --- a/React/Base/RCTConvert.m +++ b/React/Base/RCTConvert.m @@ -685,7 +685,8 @@ + (NSPropertyList)NSPropertyList:(id)json RCT_ENUM_CONVERTER(YGWrap, (@{ @"wrap": @(YGWrapWrap), - @"nowrap": @(YGWrapNoWrap) + @"nowrap": @(YGWrapNoWrap), + @"wrap-reverse": @(YGWrapWrapReverse) }), YGWrapNoWrap, intValue) RCT_ENUM_CONVERTER(RCTPointerEvents, (@{ diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java index 86c1a7832ba778..ae85bbdccd7646 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java @@ -315,6 +315,10 @@ public void setFlexWrap(@Nullable String flexWrap) { setFlexWrap(YogaWrap.WRAP); break; } + case "wrap-reverse": { + setFlexWrap(YogaWrap.WRAP_REVERSE); + break; + } default: { throw new JSApplicationIllegalArgumentException( "invalid value for flexWrap: " + flexWrap); From 2e7dfd5213a664bb6aaac19f6449985d977b605b Mon Sep 17 00:00:00 2001 From: Peter van der Zee Date: Fri, 20 Apr 2018 05:06:41 -0700 Subject: [PATCH 0349/1109] Lock down Babel to 7-beta.40 Summary: This will lock down the plugins to babel version 7-beta.40 Reviewed By: davidaurelio Differential Revision: D7707160 fbshipit-source-id: 6aec7f98348cac6ddd680c73ea4e36e0fb23e2a8 --- babel-preset/package.json | 50 +++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/babel-preset/package.json b/babel-preset/package.json index 120c8b7a68ee2e..ce1c169a82f960 100644 --- a/babel-preset/package.json +++ b/babel-preset/package.json @@ -15,31 +15,31 @@ }, "homepage": "https://github.com/facebook/react-native/tree/master/babel-preset/README.md", "dependencies": { - "@babel/plugin-proposal-class-properties": "^7.0.0-beta", - "@babel/plugin-proposal-object-rest-spread": "^7.0.0-beta", - "@babel/plugin-transform-arrow-functions": "^7.0.0-beta", - "@babel/plugin-transform-block-scoping": "^7.0.0-beta", - "@babel/plugin-transform-classes": "^7.0.0-beta", - "@babel/plugin-transform-computed-properties": "^7.0.0-beta", - "@babel/plugin-transform-destructuring": "^7.0.0-beta", - "@babel/plugin-transform-exponentiation-operator": "^7.0.0-beta", - "@babel/plugin-transform-flow-strip-types": "^7.0.0-beta", - "@babel/plugin-transform-for-of": "^7.0.0-beta", - "@babel/plugin-transform-function-name": "^7.0.0-beta", - "@babel/plugin-transform-literals": "^7.0.0-beta", - "@babel/plugin-transform-modules-commonjs": "^7.0.0-beta", - "@babel/plugin-transform-object-assign": "^7.0.0-beta", - "@babel/plugin-transform-parameters": "^7.0.0-beta", - "@babel/plugin-transform-shorthand-properties": "^7.0.0-beta", - "@babel/plugin-transform-react-display-name": "^7.0.0-beta", - "@babel/plugin-transform-react-jsx": "^7.0.0-beta", - "@babel/plugin-transform-react-jsx-source": "^7.0.0-beta", - "@babel/plugin-transform-regenerator": "^7.0.0-beta", - "@babel/plugin-transform-spread": "^7.0.0-beta", - "@babel/plugin-transform-sticky-regex": "^7.0.0-beta", - "@babel/plugin-transform-unicode-regex": "^7.0.0-beta", - "@babel/plugin-transform-template-literals": "^7.0.0-beta", - "@babel/template": "^7.0.0-beta", + "@babel/plugin-proposal-class-properties": "7.0.0-beta.40", + "@babel/plugin-proposal-object-rest-spread": "7.0.0-beta.40", + "@babel/plugin-transform-arrow-functions": "7.0.0-beta.40", + "@babel/plugin-transform-block-scoping": "7.0.0-beta.40", + "@babel/plugin-transform-classes": "7.0.0-beta.40", + "@babel/plugin-transform-computed-properties": "7.0.0-beta.40", + "@babel/plugin-transform-destructuring": "7.0.0-beta.40", + "@babel/plugin-transform-exponentiation-operator": "7.0.0-beta.40", + "@babel/plugin-transform-flow-strip-types": "7.0.0-beta.40", + "@babel/plugin-transform-for-of": "7.0.0-beta.40", + "@babel/plugin-transform-function-name": "7.0.0-beta.40", + "@babel/plugin-transform-literals": "7.0.0-beta.40", + "@babel/plugin-transform-modules-commonjs": "7.0.0-beta.40", + "@babel/plugin-transform-object-assign": "7.0.0-beta.40", + "@babel/plugin-transform-parameters": "7.0.0-beta.40", + "@babel/plugin-transform-react-display-name": "7.0.0-beta.40", + "@babel/plugin-transform-react-jsx": "7.0.0-beta.40", + "@babel/plugin-transform-react-jsx-source": "7.0.0-beta.40", + "@babel/plugin-transform-regenerator": "7.0.0-beta.40", + "@babel/plugin-transform-shorthand-properties": "7.0.0-beta.40", + "@babel/plugin-transform-spread": "7.0.0-beta.40", + "@babel/plugin-transform-sticky-regex": "7.0.0-beta.40", + "@babel/plugin-transform-template-literals": "7.0.0-beta.40", + "@babel/plugin-transform-unicode-regex": "7.0.0-beta.40", + "@babel/template": "7.0.0-beta.40", "metro-babel7-plugin-react-transform": "0.32.0" } } From 5fd92f90af4abb3bada372aed0ec376dc6d66891 Mon Sep 17 00:00:00 2001 From: Jean Lauliac Date: Fri, 20 Apr 2018 06:31:26 -0700 Subject: [PATCH 0350/1109] cxxreact: executors: insert ID of segment reliably into the bundle path Reviewed By: fromcelticpark Differential Revision: D7623232 fbshipit-source-id: df833d18f0445d52e3098b58aac347a2e9aa0040 --- React/React.xcodeproj/project.pbxproj | 4 ++++ ReactCommon/cxxreact/Android.mk | 1 + ReactCommon/cxxreact/BUCK | 1 + ReactCommon/cxxreact/JSCExecutor.cpp | 9 ++++++--- ReactCommon/cxxreact/JSCUtils.cpp | 2 ++ ReactCommon/cxxreact/JSExecutor.cpp | 22 ++++++++++++++++++++++ ReactCommon/cxxreact/JSExecutor.h | 4 ++++ 7 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 ReactCommon/cxxreact/JSExecutor.cpp diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj index 5232e06f72a0b2..8c89419471d0ff 100644 --- a/React/React.xcodeproj/project.pbxproj +++ b/React/React.xcodeproj/project.pbxproj @@ -1215,6 +1215,7 @@ CF2731C11E7B8DE40044CA4F /* RCTDeviceInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = CF2731BF1E7B8DE40044CA4F /* RCTDeviceInfo.m */; }; CF2731C21E7B8DEF0044CA4F /* RCTDeviceInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = CF2731BE1E7B8DE40044CA4F /* RCTDeviceInfo.h */; }; CF2731C31E7B8DF30044CA4F /* RCTDeviceInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = CF2731BF1E7B8DE40044CA4F /* RCTDeviceInfo.m */; }; + E223624420875A8000108244 /* JSExecutor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E223624320875A8000108244 /* JSExecutor.cpp */; }; E9B20B7B1B500126007A2DA7 /* RCTAccessibilityManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E9B20B7A1B500126007A2DA7 /* RCTAccessibilityManager.m */; }; EBF21BBC1FC498270052F4D5 /* InspectorInterfaces.h in Headers */ = {isa = PBXBuildFile; fileRef = EBF21BBA1FC498270052F4D5 /* InspectorInterfaces.h */; }; EBF21BBD1FC498270052F4D5 /* InspectorInterfaces.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EBF21BBB1FC498270052F4D5 /* InspectorInterfaces.cpp */; }; @@ -2305,6 +2306,7 @@ C6D380191F71D75B00621378 /* RAMBundleRegistry.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = RAMBundleRegistry.cpp; sourceTree = ""; }; CF2731BE1E7B8DE40044CA4F /* RCTDeviceInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTDeviceInfo.h; sourceTree = ""; }; CF2731BF1E7B8DE40044CA4F /* RCTDeviceInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDeviceInfo.m; sourceTree = ""; }; + E223624320875A8000108244 /* JSExecutor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSExecutor.cpp; sourceTree = ""; }; E3BBC8EB1ADE6F47001BBD81 /* RCTTextDecorationLineType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTTextDecorationLineType.h; sourceTree = ""; }; E9B20B791B500126007A2DA7 /* RCTAccessibilityManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAccessibilityManager.h; sourceTree = ""; }; E9B20B7A1B500126007A2DA7 /* RCTAccessibilityManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAccessibilityManager.m; sourceTree = ""; }; @@ -3034,6 +3036,7 @@ AC70D2EA1DE489FC002E6351 /* cxxreact */ = { isa = PBXGroup; children = ( + E223624320875A8000108244 /* JSExecutor.cpp */, 3D92B0A71E03699D0018521A /* CxxModule.h */, 3D92B0A81E03699D0018521A /* CxxNativeModule.cpp */, 3D92B0A91E03699D0018521A /* CxxNativeModule.h */, @@ -4440,6 +4443,7 @@ buildActionMask = 2147483647; files = ( 13134C9A1E296B2A00B9F3CB /* RCTCxxMethod.mm in Sources */, + E223624420875A8000108244 /* JSExecutor.cpp in Sources */, 59500D451F71C63F00B122B7 /* RCTUIManagerUtils.m in Sources */, 597633361F4E021D005BE8A4 /* RCTShadowView+Internal.m in Sources */, 13723B501A82FD3C00F88898 /* RCTStatusBarManager.m in Sources */, diff --git a/ReactCommon/cxxreact/Android.mk b/ReactCommon/cxxreact/Android.mk index 56ffdb1b3c5298..1c22c761e6ef93 100644 --- a/ReactCommon/cxxreact/Android.mk +++ b/ReactCommon/cxxreact/Android.mk @@ -17,6 +17,7 @@ LOCAL_SRC_FILES := \ JSCSamplingProfiler.cpp \ JSCTracing.cpp \ JSCUtils.cpp \ + JSExecutor.cpp \ JSIndexedRAMBundle.cpp \ MethodCall.cpp \ ModuleRegistry.cpp \ diff --git a/ReactCommon/cxxreact/BUCK b/ReactCommon/cxxreact/BUCK index 8bf767e828974a..14aa2e3c999dc9 100644 --- a/ReactCommon/cxxreact/BUCK +++ b/ReactCommon/cxxreact/BUCK @@ -89,6 +89,7 @@ CXXREACT_PUBLIC_HEADERS = [ "JSExecutor.h", "JSCExecutor.h", "JSCNativeModules.h", + "JSCUtils.h", "JSIndexedRAMBundle.h", "JSModulesUnbundle.h", "MessageQueueThread.h", diff --git a/ReactCommon/cxxreact/JSCExecutor.cpp b/ReactCommon/cxxreact/JSCExecutor.cpp index a7d8c72cbf7048..01a68fb4d5a7dc 100644 --- a/ReactCommon/cxxreact/JSCExecutor.cpp +++ b/ReactCommon/cxxreact/JSCExecutor.cpp @@ -458,13 +458,16 @@ namespace facebook { m_bundleRegistry = std::move(bundleRegistry); } - void JSCExecutor::registerBundle(uint32_t bundleId, const std::string& bundlePath) { + void JSCExecutor::registerBundle( + uint32_t bundleId, + const std::string& bundlePath) { if (m_bundleRegistry) { m_bundleRegistry->registerBundle(bundleId, bundlePath); } else { - auto sourceUrl = String(m_context, bundlePath.c_str()); + auto stPath = JSCExecutor::getSyntheticBundlePath(bundleId, bundlePath); + auto sourceUrlStr = String(m_context, stPath.c_str()); auto source = adoptString(JSBigFileString::fromPath(bundlePath)); - evaluateScript(m_context, source, sourceUrl); + evaluateScript(m_context, source, sourceUrlStr); } } diff --git a/ReactCommon/cxxreact/JSCUtils.cpp b/ReactCommon/cxxreact/JSCUtils.cpp index 8681faa443f418..45cc591bf76d19 100644 --- a/ReactCommon/cxxreact/JSCUtils.cpp +++ b/ReactCommon/cxxreact/JSCUtils.cpp @@ -2,6 +2,8 @@ #include "JSCUtils.h" +#include "RAMBundleRegistry.h" + #include namespace facebook { diff --git a/ReactCommon/cxxreact/JSExecutor.cpp b/ReactCommon/cxxreact/JSExecutor.cpp new file mode 100644 index 00000000000000..9548f9664acb8e --- /dev/null +++ b/ReactCommon/cxxreact/JSExecutor.cpp @@ -0,0 +1,22 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include "JSExecutor.h" + +#include "RAMBundleRegistry.h" + +#include + +namespace facebook { +namespace react { + +std::string JSExecutor::getSyntheticBundlePath( + uint32_t bundleId, + const std::string& bundlePath) { + if (bundleId == RAMBundleRegistry::MAIN_BUNDLE_ID) { + return bundlePath; + } + return folly::to("seg-", bundleId, ".js"); +} + +} +} diff --git a/ReactCommon/cxxreact/JSExecutor.h b/ReactCommon/cxxreact/JSExecutor.h index 85b4bfcb0364ee..35338cd0876bb5 100644 --- a/ReactCommon/cxxreact/JSExecutor.h +++ b/ReactCommon/cxxreact/JSExecutor.h @@ -101,6 +101,10 @@ class JSExecutor { virtual void destroy() {} virtual ~JSExecutor() {} + + static std::string getSyntheticBundlePath( + uint32_t bundleId, + const std::string& bundlePath); }; } } From 11f102373d74669d57fd048c4288beca7f47059e Mon Sep 17 00:00:00 2001 From: Miguel Jimenez Esun Date: Fri, 20 Apr 2018 07:24:14 -0700 Subject: [PATCH 0351/1109] Clean server.js and runServer.js Reviewed By: davidaurelio Differential Revision: D7628734 fbshipit-source-id: 3788b35b0f9b5034d9152c5c3b297313fbec231a --- local-cli/server/runServer.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/local-cli/server/runServer.js b/local-cli/server/runServer.js index 1ccedf77765ed3..47c11535bdf4b5 100644 --- a/local-cli/server/runServer.js +++ b/local-cli/server/runServer.js @@ -43,9 +43,6 @@ const statusPageMiddleware = require('./middleware/statusPageMiddleware.js'); const systraceProfileMiddleware = require('./middleware/systraceProfileMiddleware.js'); const webSocketProxy = require('./util/webSocketProxy.js'); -/* $FlowFixMe(site=react_native_oss) */ -const TransformCaching = require('metro/src/lib/TransformCaching'); - const {ASSET_REGISTRY_PATH} = require('../core/Constants'); import type {ConfigT} from 'metro'; @@ -191,7 +188,6 @@ function getPackagerServer(args, config, reporter) { getPolyfills: config.getPolyfills, getRunModuleStatement: config.getRunModuleStatement, getTransformOptions: config.getTransformOptions, - globalTransformCache: null, hasteImplModulePath: config.hasteImplModulePath, maxWorkers: args.maxWorkers, platforms: defaultPlatforms.concat(args.platforms), @@ -205,7 +201,6 @@ function getPackagerServer(args, config, reporter) { resolveRequest: config.resolveRequest, sourceExts: args.sourceExts.concat(defaultSourceExts), transformModulePath: transformModulePath, - transformCache: TransformCaching.useTempDir(), verbose: args.verbose, watch: !args.nonPersistent, workerPath: config.getWorkerPath(), From fc694fef6663f8fefc529caa27ac8467c77773aa Mon Sep 17 00:00:00 2001 From: Miguel Jimenez Esun Date: Fri, 20 Apr 2018 07:24:20 -0700 Subject: [PATCH 0352/1109] Clean buildBundle.js, index.js and Flow types Reviewed By: davidaurelio Differential Revision: D7628725 fbshipit-source-id: 3873e5c7a0c9b988335dcf9b8a11fcf0598a9f50 --- local-cli/bundle/buildBundle.js | 1 - 1 file changed, 1 deletion(-) diff --git a/local-cli/bundle/buildBundle.js b/local-cli/bundle/buildBundle.js index 5b1f5be0653425..99c45ddc08db5c 100644 --- a/local-cli/bundle/buildBundle.js +++ b/local-cli/bundle/buildBundle.js @@ -90,7 +90,6 @@ async function buildBundle( getPolyfills: config.getPolyfills, getRunModuleStatement: config.getRunModuleStatement, getTransformOptions: config.getTransformOptions, - globalTransformCache: null, hasteImplModulePath: config.hasteImplModulePath, maxWorkers: args.maxWorkers, platforms: defaultPlatforms.concat(platforms), From 9bbe736f23657e9acc263e480d59ac7def260e9d Mon Sep 17 00:00:00 2001 From: Peter Ammon Date: Fri, 20 Apr 2018 08:56:02 -0700 Subject: [PATCH 0353/1109] Teach JS stack-parsing regex about alternative formats Reviewed By: adamjernst Differential Revision: D7706535 fbshipit-source-id: 83cc2defbcad3faa6bdbf4a5b2072b9c023e1c04 --- React/Base/RCTJSStackFrame.m | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/React/Base/RCTJSStackFrame.m b/React/Base/RCTJSStackFrame.m index 60976f673ba542..a60d78b1093b4c 100644 --- a/React/Base/RCTJSStackFrame.m +++ b/React/Base/RCTJSStackFrame.m @@ -10,13 +10,40 @@ #import "RCTLog.h" #import "RCTUtils.h" +/** +* The RegEx used to parse Error.stack. +* +* JavaScriptCore has the following format: +* +* Exception: Error: argh +* func1@/path/to/file.js:2:18 +* func2@/path/to/file.js:6:8 +* eval@[native code] +* global code@/path/to/file.js:13:5 +* +* Another supported format: +* +* Error: argh +* at func1 (/path/to/file.js:2:18) +* at func2 (/path/to/file.js:6:8) +* at eval (native) +* at global (/path/to/file.js:13:5) +*/ static NSRegularExpression *RCTJSStackFrameRegex() { static dispatch_once_t onceToken; static NSRegularExpression *_regex; dispatch_once(&onceToken, ^{ + NSString *pattern = + @"\\s*(?:at)?\\s*" // Skip leading "at" and whitespace, noncapturing + @"(.+?)" // Capture the function name (group 1) + @"\\s*[@(]" // Skip whitespace, then @ or ( + @"(.*):" // Capture the file name (group 2), then colon + @"(\\d+):(\\d+)" // Line and column number (groups 3 and 4) + @"\\)?$" // Optional closing paren and EOL + ; NSError *regexError; - _regex = [NSRegularExpression regularExpressionWithPattern:@"^(?:([^@]+)@)?(.*):(\\d+):(\\d+)$" options:0 error:®exError]; + _regex = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:®exError]; if (regexError) { RCTLogError(@"Failed to build regex: %@", [regexError localizedDescription]); } From cf1569c556d28779edbba92edb658a881a68516c Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Fri, 20 Apr 2018 09:17:39 -0700 Subject: [PATCH 0354/1109] Export the hmr plugin directly Summary: This will allow to configure the HMR plugin directly from `.babelrc` again, instead of having to create a bridge file: https://github.com/rafeca/metro-sample-app/blob/master/metro-babel7-plugin-react-transform.js#L3 Reviewed By: davidaurelio Differential Revision: D7707314 fbshipit-source-id: 4c5612e1e5d27874807f2dce50d99ec0f6354bbc --- babel-preset/configs/hmr.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/babel-preset/configs/hmr.js b/babel-preset/configs/hmr.js index cdf5a022c202eb..e2b4a0f3dec0e0 100644 --- a/babel-preset/configs/hmr.js +++ b/babel-preset/configs/hmr.js @@ -24,7 +24,7 @@ module.exports = function(options, filename) { return { plugins: [ [ - require('metro-babel7-plugin-react-transform').default, + require('metro-babel7-plugin-react-transform'), { transforms: [{ transform: transform, From e512a4ae300ff1057f98e2e6375a432efa8c0241 Mon Sep 17 00:00:00 2001 From: Naris Siamwalla Date: Fri, 20 Apr 2018 09:40:06 -0700 Subject: [PATCH 0355/1109] Fix dtor declaration for clang-6 Reviewed By: smeenai Differential Revision: D7690428 fbshipit-source-id: 4b02a6f6cbccda3446f0a19b1b35c266a33560bd --- ReactCommon/fabric/uimanager/Scheduler.h | 2 +- ReactCommon/fabric/uimanager/SchedulerDelegate.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ReactCommon/fabric/uimanager/Scheduler.h b/ReactCommon/fabric/uimanager/Scheduler.h index 4f4ff203b54a92..b48d6e848af4c7 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.h +++ b/ReactCommon/fabric/uimanager/Scheduler.h @@ -29,7 +29,7 @@ class Scheduler: public: Scheduler(); - ~Scheduler(); + virtual ~Scheduler(); #pragma mark - Root Nodes Managerment diff --git a/ReactCommon/fabric/uimanager/SchedulerDelegate.h b/ReactCommon/fabric/uimanager/SchedulerDelegate.h index 2fe3da02ace154..3f2d9bf5fd248e 100644 --- a/ReactCommon/fabric/uimanager/SchedulerDelegate.h +++ b/ReactCommon/fabric/uimanager/SchedulerDelegate.h @@ -16,6 +16,9 @@ namespace react { */ class SchedulerDelegate { public: + + virtual ~SchedulerDelegate() = default; + /* * Called right after Scheduler computed (and laid out) a new updated version * of the tree and calculated a set of mutation instructions which are From bc8e42a5e6a2c0161d5820e62047f5103b94a33f Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Fri, 20 Apr 2018 10:18:05 -0700 Subject: [PATCH 0356/1109] Removed fb-specific RN bundle. This should not have been synced. --- Libraries/Renderer/fb/ReactFabric-dev.js | 13862 --------------- Libraries/Renderer/fb/ReactFabric-prod.js | 5875 ------- Libraries/Renderer/fb/ReactFeatureFlags.js | 18 - .../Renderer/fb/ReactNativeRenderer-dev.js | 14437 ---------------- .../Renderer/fb/ReactNativeRenderer-prod.js | 6395 ------- 5 files changed, 40587 deletions(-) delete mode 100644 Libraries/Renderer/fb/ReactFabric-dev.js delete mode 100644 Libraries/Renderer/fb/ReactFabric-prod.js delete mode 100644 Libraries/Renderer/fb/ReactFeatureFlags.js delete mode 100644 Libraries/Renderer/fb/ReactNativeRenderer-dev.js delete mode 100644 Libraries/Renderer/fb/ReactNativeRenderer-prod.js diff --git a/Libraries/Renderer/fb/ReactFabric-dev.js b/Libraries/Renderer/fb/ReactFabric-dev.js deleted file mode 100644 index 0424315c8ed6b5..00000000000000 --- a/Libraries/Renderer/fb/ReactFabric-dev.js +++ /dev/null @@ -1,13862 +0,0 @@ -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @noflow - * @preventMunge - */ - -'use strict'; - -if (__DEV__) { - (function() { -"use strict"; - -require("InitializeCore"); -var invariant = require("fbjs/lib/invariant"); -var warning = require("fbjs/lib/warning"); -var emptyFunction = require("fbjs/lib/emptyFunction"); -var ReactNativeViewConfigRegistry = require("ReactNativeViewConfigRegistry"); -var UIManager = require("UIManager"); -var TextInputState = require("TextInputState"); -var deepDiffer = require("deepDiffer"); -var flattenStyle = require("flattenStyle"); -var React = require("react"); -var emptyObject = require("fbjs/lib/emptyObject"); -var shallowEqual = require("fbjs/lib/shallowEqual"); -var checkPropTypes = require("prop-types/checkPropTypes"); -var deepFreezeAndThrowOnMutationInDev = require("deepFreezeAndThrowOnMutationInDev"); -var FabricUIManager = require("FabricUIManager"); - -var invokeGuardedCallback = function(name, func, context, a, b, c, d, e, f) { - this._hasCaughtError = false; - this._caughtError = null; - var funcArgs = Array.prototype.slice.call(arguments, 3); - try { - func.apply(context, funcArgs); - } catch (error) { - this._caughtError = error; - this._hasCaughtError = true; - } -}; - -{ - // 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 - // untintuitive, 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. - invariant( - typeof document !== "undefined", - "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; - - // 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); - 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 onError(event) { - error = event.error; - didSetError = true; - if (error === null && event.colno === 0 && event.lineno === 0) { - isCrossOriginError = true; - } - } - - // Create a fake event type. - var evtType = "react-" + (name ? name : "invokeguardedcallback"); - - // Attach our event handlers - window.addEventListener("error", onError); - 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 (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._hasCaughtError = true; - this._caughtError = error; - } else { - this._hasCaughtError = false; - this._caughtError = null; - } - - // Remove our event listeners - window.removeEventListener("error", onError); - }; - - invokeGuardedCallback = invokeGuardedCallbackDev; - } -} - -var invokeGuardedCallback$1 = invokeGuardedCallback; - -var ReactErrorUtils = { - // Used by Fiber to simulate a try-catch. - _caughtError: null, - _hasCaughtError: false, - - // Used by event system to capture/rethrow the first error. - _rethrowError: null, - _hasRethrowError: false, - - /** - * 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 - */ - invokeGuardedCallback: function(name, func, context, a, b, c, d, e, f) { - invokeGuardedCallback$1.apply(ReactErrorUtils, 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 - */ - invokeGuardedCallbackAndCatchFirstError: function( - name, - func, - context, - a, - b, - c, - d, - e, - f - ) { - ReactErrorUtils.invokeGuardedCallback.apply(this, arguments); - if (ReactErrorUtils.hasCaughtError()) { - var error = ReactErrorUtils.clearCaughtError(); - if (!ReactErrorUtils._hasRethrowError) { - ReactErrorUtils._hasRethrowError = true; - ReactErrorUtils._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. - */ - rethrowCaughtError: function() { - return rethrowCaughtError.apply(ReactErrorUtils, arguments); - }, - - hasCaughtError: function() { - return ReactErrorUtils._hasCaughtError; - }, - - clearCaughtError: function() { - if (ReactErrorUtils._hasCaughtError) { - var error = ReactErrorUtils._caughtError; - ReactErrorUtils._caughtError = null; - ReactErrorUtils._hasCaughtError = false; - return error; - } else { - invariant( - false, - "clearCaughtError was called but no error was captured. This error " + - "is likely caused by a bug in React. Please file an issue." - ); - } - } -}; - -var rethrowCaughtError = function() { - if (ReactErrorUtils._hasRethrowError) { - var error = ReactErrorUtils._rethrowError; - ReactErrorUtils._rethrowError = null; - ReactErrorUtils._hasRethrowError = false; - throw error; - } -}; - -/** - * 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); - invariant( - pluginIndex > -1, - "EventPluginRegistry: Cannot inject event plugins that do not exist in " + - "the plugin ordering, `%s`.", - pluginName - ); - if (plugins[pluginIndex]) { - continue; - } - invariant( - pluginModule.extractEvents, - "EventPluginRegistry: Event plugins must implement an `extractEvents` " + - "method, but `%s` does not.", - pluginName - ); - plugins[pluginIndex] = pluginModule; - var publishedEvents = pluginModule.eventTypes; - for (var eventName in publishedEvents) { - invariant( - publishEventForPlugin( - publishedEvents[eventName], - pluginModule, - eventName - ), - "EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.", - eventName, - 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) { - invariant( - !eventNameDispatchConfigs.hasOwnProperty(eventName), - "EventPluginHub: More than one plugin attempted to publish the same " + - "event name, `%s`.", - 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) { - invariant( - !registrationNameModules[registrationName], - "EventPluginHub: More than one plugin attempted to publish the same " + - "registration name, `%s`.", - 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) { - invariant( - !eventPluginOrder, - "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 - ) { - invariant( - !namesToPlugins[pluginName], - "EventPluginRegistry: Cannot inject two different event plugins " + - "using the same name, `%s`.", - pluginName - ); - namesToPlugins[pluginName] = pluginModule; - isOrderingDirty = true; - } - } - if (isOrderingDirty) { - recomputePluginOrdering(); - } -} - -var getFiberCurrentPropsFromNode = null; -var getInstanceFromNode = null; -var getNodeFromInstance = null; - -var injection$1 = { - injectComponentTree: function(Injected) { - getFiberCurrentPropsFromNode = Injected.getFiberCurrentPropsFromNode; - getInstanceFromNode = Injected.getInstanceFromNode; - getNodeFromInstance = Injected.getNodeFromInstance; - - { - !(getNodeFromInstance && getInstanceFromNode) - ? warning( - false, - "EventPluginUtils.injection.injectComponentTree(...): Injected " + - "module is missing getNodeFromInstance or getInstanceFromNode." - ) - : void 0; - } - } -}; - -function isEndish(topLevelType) { - return ( - topLevelType === "topMouseUp" || - topLevelType === "topTouchEnd" || - topLevelType === "topTouchCancel" - ); -} - -function isMoveish(topLevelType) { - return topLevelType === "topMouseMove" || topLevelType === "topTouchMove"; -} -function isStartish(topLevelType) { - return topLevelType === "topMouseDown" || topLevelType === "topTouchStart"; -} - -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) - ? warning(false, "EventPluginUtils: Invalid `event`.") - : void 0; - }; -} - -/** - * Standard/simple iteration through an event's collected dispatches. - */ - -/** - * 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; - invariant( - !Array.isArray(dispatchListener), - "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) { - invariant( - next != null, - "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); - } -} - -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; - } - invariant( - !listener || typeof listener === "function", - "Expected `%s` listener to be a function, instead got a value of `%s` type.", - registrationName, - typeof listener - ); - return listener; -} - -var IndeterminateComponent = 0; // Before we know whether it is functional or class -var FunctionalComponent = 1; -var ClassComponent = 2; -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 CallComponent = 7; -var CallHandlerPhase = 8; -var ReturnComponent = 9; -var Fragment = 10; -var Mode = 11; -var ContextConsumer = 12; -var ContextProvider = 13; -var ForwardRef = 14; - -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 ? warning(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 didWarnForAddedNewProperty = false; -var EVENT_POOL_SIZE = 10; - -var shouldBeReleasedProperties = [ - "dispatchConfig", - "_targetInst", - "nativeEvent", - "isDefaultPrevented", - "isPropagationStopped", - "_dispatchListeners", - "_dispatchInstances" -]; - -/** - * @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: emptyFunction.thatReturnsNull, - eventPhase: null, - bubbles: null, - cancelable: null, - timeStamp: function(event) { - return event.timeStamp || Date.now(); - }, - defaultPrevented: null, - isTrusted: null -}; - -/** - * 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; - } - - 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 = emptyFunction.thatReturnsTrue; - } else { - this.isDefaultPrevented = emptyFunction.thatReturnsFalse; - } - this.isPropagationStopped = emptyFunction.thatReturnsFalse; - 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 = emptyFunction.thatReturnsTrue; - }, - - 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 = emptyFunction.thatReturnsTrue; - }, - - /** - * 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 = emptyFunction.thatReturnsTrue; - }, - - /** - * Checks if this event should be released back into the pool. - * - * @return {boolean} True if this should not be released, false otherwise. - */ - isPersistent: emptyFunction.thatReturnsFalse, - - /** - * `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]) - ); - } - } - for (var i = 0; i < shouldBeReleasedProperties.length; i++) { - this[shouldBeReleasedProperties[i]] = null; - } - { - Object.defineProperty( - this, - "nativeEvent", - getPooledWarningPropertyDefinition("nativeEvent", null) - ); - Object.defineProperty( - this, - "preventDefault", - getPooledWarningPropertyDefinition("preventDefault", emptyFunction) - ); - Object.defineProperty( - this, - "stopPropagation", - getPooledWarningPropertyDefinition("stopPropagation", emptyFunction) - ); - } - } -}); - -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; -}; - -/** Proxying after everything set on SyntheticEvent - * to resolve Proxy issue on some WebKit browsers - * in which some Event properties are set to undefined (GH#10010) - */ -{ - var isProxySupported = - typeof Proxy === "function" && - // https://github.com/facebook/react/issues/12011 - !Object.isSealed(new Proxy({}, {})); - - if (isProxySupported) { - /*eslint-disable no-func-assign */ - SyntheticEvent = new Proxy(SyntheticEvent, { - construct: function(target, args) { - return this.apply(target, Object.create(target.prototype), args); - }, - apply: function(constructor, that, args) { - return new Proxy(constructor.apply(that, args), { - set: function(target, prop, value) { - if ( - prop !== "isPersistent" && - !target.constructor.Interface.hasOwnProperty(prop) && - shouldBeReleasedProperties.indexOf(prop) === -1 - ) { - !(didWarnForAddedNewProperty || target.isPersistent()) - ? warning( - false, - "This synthetic event is reused for performance reasons. If you're " + - "seeing this, you're adding a new property in the synthetic event object. " + - "The property is never released. See " + - "https://fb.me/react-event-pooling for more information." - ) - : void 0; - didWarnForAddedNewProperty = true; - } - target[prop] = value; - return true; - } - }); - } - }); - /*eslint-enable no-func-assign */ - } -} - -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$$1 - }; - - function set(val) { - var action = isFunction ? "setting the method" : "setting the property"; - warn(action, "This is effectively a no-op"); - return val; - } - - function get$$1() { - 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 - ? warning( - 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; - invariant( - event instanceof EventConstructor, - "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; -} - -var SyntheticEvent$1 = SyntheticEvent; - -/** - * `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$1.extend({ - touchHistory: function(nativeEvent) { - return null; // Actually doesn't even look at the native event. - } -}); - -/** - * 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; - - invariant(identifier != null, "Touch object is missing identifier."); - { - !(identifier <= MAX_TOUCH_BANK) - ? warning( - 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) - ? warning(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) { - invariant( - next != null, - "accumulate(...): Accumulated items must be 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; - -/** - * Last reported number of active touches. - */ -var previousActiveTouches = 0; - -var changeResponder = function(nextResponderInst, blockHostResponder) { - var oldResponderInst = responderInst; - responderInst = nextResponderInst; - if (ResponderEventPlugin.GlobalResponderHandler !== null) { - ResponderEventPlugin.GlobalResponderHandler.onChange( - oldResponderInst, - nextResponderInst, - blockHostResponder - ); - } -}; - -var eventTypes$1 = { - /** - * On a `touchStart`/`mouseDown`, is it desired that this element become the - * responder? - */ - startShouldSetResponder: { - phasedRegistrationNames: { - bubbled: "onStartShouldSetResponder", - captured: "onStartShouldSetResponderCapture" - } - }, - - /** - * 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" - } - }, - - /** - * 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" - } - }, - - /** - * On a `touchMove`/`mouseMove`, is it desired that this element become the - * responder? - */ - moveShouldSetResponder: { - phasedRegistrationNames: { - bubbled: "onMoveShouldSetResponder", - captured: "onMoveShouldSetResponderCapture" - } - }, - - /** - * Direct responder events dispatched directly to responder. Do not bubble. - */ - responderStart: { registrationName: "onResponderStart" }, - responderMove: { registrationName: "onResponderMove" }, - responderEnd: { registrationName: "onResponderEnd" }, - responderRelease: { registrationName: "onResponderRelease" }, - responderTerminationRequest: { - registrationName: "onResponderTerminationRequest" - }, - responderGrant: { registrationName: "onResponderGrant" }, - responderReject: { registrationName: "onResponderReject" }, - responderTerminate: { registrationName: "onResponderTerminate" } -}; - -/** - * - * 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$1.startShouldSetResponder - : isMoveish(topLevelType) - ? eventTypes$1.moveShouldSetResponder - : topLevelType === "topSelectionChange" - ? eventTypes$1.selectionChangeShouldSetResponder - : eventTypes$1.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$1.responderGrant, - wantsResponderInst, - nativeEvent, - nativeEventTarget - ); - grantEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; - - accumulateDirectDispatches(grantEvent); - var blockHostResponder = executeDirectDispatch(grantEvent) === true; - if (responderInst) { - var terminationRequestEvent = ResponderSyntheticEvent.getPooled( - eventTypes$1.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$1.responderTerminate, - responderInst, - nativeEvent, - nativeEventTarget - ); - terminateEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; - accumulateDirectDispatches(terminateEvent); - extracted = accumulate(extracted, [grantEvent, terminateEvent]); - changeResponder(wantsResponderInst, blockHostResponder); - } else { - var rejectEvent = ResponderSyntheticEvent.getPooled( - eventTypes$1.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 === "topScroll" && !nativeEvent.responderIgnoreScroll) || - (trackedTouchCount > 0 && topLevelType === "topSelectionChange") || - 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$1, - - /** - * 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$1.responderStart - : isResponderTouchMove - ? eventTypes$1.responderMove - : isResponderTouchEnd ? eventTypes$1.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 === "topTouchCancel"; - var isResponderRelease = - responderInst && - !isResponderTerminate && - isEndish(topLevelType) && - noResponderTouches(nativeEvent); - var finalTouch = isResponderTerminate - ? eventTypes$1.responderTerminate - : isResponderRelease ? eventTypes$1.responderRelease : null; - if (finalTouch) { - var finalEvent = ResponderSyntheticEvent.getPooled( - finalTouch, - responderInst, - nativeEvent, - nativeEventTarget - ); - finalEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; - accumulateDirectDispatches(finalEvent); - extracted = accumulate(extracted, finalEvent); - changeResponder(null); - } - - var numberActiveTouches = - ResponderTouchHistoryStore.touchHistory.numberActiveTouches; - if ( - ResponderEventPlugin.GlobalInteractionHandler && - numberActiveTouches !== previousActiveTouches - ) { - ResponderEventPlugin.GlobalInteractionHandler.onChange( - numberActiveTouches - ); - } - previousActiveTouches = numberActiveTouches; - - return extracted; - }, - - GlobalResponderHandler: null, - GlobalInteractionHandler: 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; - }, - - /** - * @param {{onChange: (numberActiveTouches) => void} GlobalInteractionHandler - * Object that handles any change in the number of active touches. - */ - injectGlobalInteractionHandler: function(GlobalInteractionHandler) { - ResponderEventPlugin.GlobalInteractionHandler = GlobalInteractionHandler; - } - } -}; - -var customBubblingEventTypes$1 = - ReactNativeViewConfigRegistry.customBubblingEventTypes; -var customDirectEventTypes$1 = - ReactNativeViewConfigRegistry.customDirectEventTypes; -var eventTypes$2 = ReactNativeViewConfigRegistry.eventTypes; - -var ReactNativeBridgeEventPlugin = { - eventTypes: eventTypes$2, - - /** - * @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$1[topLevelType]; - var directDispatchConfig = customDirectEventTypes$1[topLevelType]; - invariant( - bubbleDispatchConfig || directDispatchConfig, - 'Unsupported top level event type "%s" dispatched', - topLevelType - ); - var event = SyntheticEvent$1.getPooled( - bubbleDispatchConfig || directDispatchConfig, - targetInst, - nativeEvent, - nativeEventTarget - ); - if (bubbleDispatchConfig) { - accumulateTwoPhaseDispatches(event); - } else if (directDispatchConfig) { - accumulateDirectDispatches(event); - } else { - return null; - } - return event; - } -}; - -var instanceCache = {}; -var instanceProps = {}; - -function precacheFiberNode(hostInst, tag) { - instanceCache[tag] = hostInst; -} - -function uncacheFiberNode(tag) { - delete instanceCache[tag]; - delete instanceProps[tag]; -} - -function getInstanceFromTag(tag) { - if (typeof tag === "number") { - return instanceCache[tag] || null; - } else { - // Fabric will invoke event emitters on a direct fiber reference - return tag; - } -} - -function getTagFromInstance(inst) { - var tag = inst.stateNode._nativeTag; - if (tag === undefined) { - tag = inst.stateNode.canonical._nativeTag; - } - invariant(tag, "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; -} - -var ReactNativeComponentTree = Object.freeze({ - precacheFiberNode: precacheFiberNode, - uncacheFiberNode: uncacheFiberNode, - getClosestInstanceFromNode: getInstanceFromTag, - getInstanceFromNode: getInstanceFromTag, - getNodeFromInstance: getTagFromInstance, - getFiberCurrentPropsFromNode: getFiberCurrentPropsFromNode$1, - updateFiberProps: updateFiberProps -}); - -var ReactNativeEventPluginOrder = [ - "ResponderEventPlugin", - "ReactNativeBridgeEventPlugin" -]; - -// Module provided by RN: -var ReactNativeGlobalResponderHandler = { - onChange: function(from, to, blockNativeResponder) { - if (to !== null) { - var tag = to.stateNode._nativeTag; - UIManager.setJSResponder(tag, blockNativeResponder); - } else { - UIManager.clearJSResponder(); - } - } -}; - -/** - * 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); -injection$1.injectComponentTree(ReactNativeComponentTree); - -ResponderEventPlugin.injection.injectGlobalResponderHandler( - ReactNativeGlobalResponderHandler -); - -/** - * Some important event plugins included by default (without having to require - * them). - */ -injection.injectEventPluginsByName({ - ResponderEventPlugin: ResponderEventPlugin, - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin -}); - -// TODO: The event emitter registration is interfering with the existing -// ReactNative renderer. So disable it for Fabric for now. - -// import * as ReactNativeEventEmitter from './ReactNativeEventEmitter'; - -// Module provided by RN: -// import RCTEventEmitter from 'RCTEventEmitter'; - -/** - * Register the event emitter with the native bridge - */ -// RCTEventEmitter.register(ReactNativeEventEmitter); - -// 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_CALL_TYPE = hasSymbol ? Symbol["for"]("react.call") : 0xeac8; -var REACT_RETURN_TYPE = hasSymbol ? Symbol["for"]("react.return") : 0xeac9; -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_PROVIDER_TYPE = hasSymbol ? Symbol["for"]("react.provider") : 0xeacd; -var REACT_CONTEXT_TYPE = hasSymbol ? Symbol["for"]("react.context") : 0xeace; -var REACT_ASYNC_MODE_TYPE = hasSymbol - ? Symbol["for"]("react.async_mode") - : 0xeacf; -var REACT_FORWARD_REF_TYPE = hasSymbol - ? Symbol["for"]("react.forward_ref") - : 0xead0; - -var MAYBE_ITERATOR_SYMBOL = typeof Symbol === "function" && Symbol.iterator; -var FAUX_ITERATOR_SYMBOL = "@@iterator"; - -function getIteratorFn(maybeIterable) { - if (maybeIterable === null || typeof maybeIterable === "undefined") { - return null; - } - var maybeIterator = - (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || - maybeIterable[FAUX_ITERATOR_SYMBOL]; - if (typeof maybeIterator === "function") { - return maybeIterator; - } - return null; -} - -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 - }; -} - -// 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 _batchedUpdates = function(fn, bookkeeping) { - return fn(bookkeeping); -}; -var _interactiveUpdates = function(fn, a, b) { - return fn(a, b); -}; -var _flushInteractiveUpdates = function() {}; - -var injection$2 = { - injectRenderer: function(renderer) { - _batchedUpdates = renderer.batchedUpdates; - _interactiveUpdates = renderer.interactiveUpdates; - _flushInteractiveUpdates = renderer.flushInteractiveUpdates; - } -}; - -// TODO: this is special because it gets imported during build. - -var ReactVersion = "16.3.2"; - -// Modules provided by RN: -var emptyObject$1 = {}; - -/** - * 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 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. - 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. - 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$1, 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$1, - 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(context, callback) { - return function() { - if (!callback) { - return undefined; - } - if (typeof context.__isMounted === "boolean") { - // TODO(gaearon): this is gross and should be removed. - // It is currently necessary because View uses createClass, - // and so any measure() calls on View (which are done by React - // DevTools) trigger the isMounted() deprecation warning. - if (!context.__isMounted) { - return undefined; - } - // The else branch is important so that we don't - // trigger the deprecation warning by calling isMounted. - } else if (typeof context.isMounted === "function") { - if (!context.isMounted()) { - return undefined; - } - } - 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 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) { - UIManager.measure( - findNodeHandle(this), - mountSafeCallback(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) { - UIManager.measureInWindow( - findNodeHandle(this), - mountSafeCallback(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 */ - ) { - UIManager.measureLayout( - findNodeHandle(this), - relativeToNativeNode, - mountSafeCallback(this, onFail), - mountSafeCallback(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; - } - - var viewConfig = maybeInstance.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) { - UIManager.updateView( - maybeInstance._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() { - TextInputState.focusTextInput(findNodeHandle(this)); - }, - - /** - * Removes focus from an input or view. This is the opposite of `focus()`. - */ - blur: function() { - 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; - invariant( - !NativeMethodsMixin_DEV.componentWillMount && - !NativeMethodsMixin_DEV.componentWillReceiveProps && - !NativeMethodsMixin_DEV.UNSAFE_componentWillMount && - !NativeMethodsMixin_DEV.UNSAFE_componentWillReceiveProps, - "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(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(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() { - TextInputState.blurTextInput(findNodeHandle(this)); - }; - - /** - * Requests focus. The exact behavior depends on the platform and view. - */ - - ReactNativeComponent.prototype.focus = function focus() { - 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) { - UIManager.measure( - findNodeHandle(this), - mountSafeCallback(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 - ) { - UIManager.measureInWindow( - findNodeHandle(this), - mountSafeCallback(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 */ - ) { - UIManager.measureLayout( - findNodeHandle(this), - relativeToNativeNode, - mountSafeCallback(this, onFail), - mountSafeCallback(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; - } - - 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) { - UIManager.updateView( - maybeInstance._nativeTag, - viewConfig.uiViewClassName, - updatePayload - ); - } - }; - - return ReactNativeComponent; - })(React.Component); - - // eslint-disable-next-line no-unused-expressions - - return ReactNativeComponent; -}; - -var hasNativePerformanceNow = - typeof performance === "object" && typeof performance.now === "function"; - -var now = hasNativePerformanceNow - ? function() { - return performance.now(); - } - : function() { - return Date.now(); - }; - -var scheduledCallback = null; -var frameDeadline = 0; - -var frameDeadlineObject = { - timeRemaining: function() { - return frameDeadline - now(); - }, - didTimeout: false -}; - -function setTimeoutCallback() { - // TODO (bvaughn) Hard-coded 5ms unblocks initial async testing. - // React API probably changing to boolean rather than time remaining. - // Longer-term plan is to rewrite this using shared memory, - // And just return the value of the bit as the boolean. - frameDeadline = now() + 5; - - var callback = scheduledCallback; - scheduledCallback = null; - if (callback !== null) { - callback(frameDeadlineObject); - } -} - -// RN has a poor polyfill for requestIdleCallback so we aren't using it. -// This implementation is only intended for short-term use anyway. -// We also don't implement cancel functionality b'c Fiber doesn't currently need it. -function scheduleDeferredCallback(callback) { - // We assume only one callback is scheduled at a time b'c that's how Fiber works. - scheduledCallback = callback; - return setTimeout(setTimeoutCallback, 1); -} - -function cancelDeferredCallback(callbackID) { - scheduledCallback = null; - clearTimeout(callbackID); -} - -/** - * `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$1(key) { - return key._reactInternalFiber; -} - -function set(key, value) { - key._reactInternalFiber = value; -} - -var ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; - -var ReactCurrentOwner = ReactInternals.ReactCurrentOwner; -var ReactDebugCurrentFrame = ReactInternals.ReactDebugCurrentFrame; - -function getComponentName(fiber) { - var type = fiber.type; - - if (typeof type === "function") { - return type.displayName || type.name; - } - if (typeof type === "string") { - return type; - } - switch (type) { - case REACT_FRAGMENT_TYPE: - return "ReactFragment"; - case REACT_PORTAL_TYPE: - return "ReactPortal"; - case REACT_CALL_TYPE: - return "ReactCall"; - case REACT_RETURN_TYPE: - return "ReactReturn"; - } - if (typeof type === "object" && type !== null) { - switch (type.$$typeof) { - case REACT_FORWARD_REF_TYPE: - var functionName = type.render.displayName || type.render.name || ""; - return functionName !== "" - ? "ForwardRef(" + functionName + ")" - : "ForwardRef"; - } - } - 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 ErrLog = /* */ 256; -var Snapshot = /* */ 2048; - -// Union of all host effects -var HostEffectMask = /* */ 2559; - -var Incomplete = /* */ 512; -var ShouldCapture = /* */ 1024; - -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.current; - if (owner !== null && owner.tag === ClassComponent) { - var ownerFiber = owner; - var instance = ownerFiber.stateNode; - !instance._warnedAboutRefsInRender - ? warning( - 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) || "A component" - ) - : void 0; - instance._warnedAboutRefsInRender = true; - } - } - - var fiber = get$1(component); - if (!fiber) { - return false; - } - return isFiberMountedImpl(fiber) === MOUNTED; -} - -function assertIsMounted(fiber) { - invariant( - isFiberMountedImpl(fiber) === MOUNTED, - "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); - invariant( - state !== UNMOUNTED, - "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"]; - var parentB = parentA ? parentA.alternate : null; - if (!parentA || !parentB) { - // 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. - invariant(false, "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; - } - invariant( - didFindChild, - "Child was not found in either parent set. This indicates a bug " + - "in React related to the return pointer. Please file an issue." - ); - } - } - - invariant( - a.alternate === b, - "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. - invariant( - a.tag === HostRoot, - "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; -} - -function findCurrentHostFiberWithNoPortals(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.tag !== HostPortal) { - 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; -} - -// 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; - -// TODO: Use an opaque type once ESLint et al support the syntax - -var NoWork = 0; -var Sync = 1; -var Never = MAX_SIGNED_31_BIT_INT; - -var UNIT_SIZE = 10; -var MAGIC_NUMBER_OFFSET = 2; - -// 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 ((ms / UNIT_SIZE) | 0) + MAGIC_NUMBER_OFFSET; -} - -function expirationTimeToMs(expirationTime) { - return (expirationTime - MAGIC_NUMBER_OFFSET) * UNIT_SIZE; -} - -function ceiling(num, precision) { - return (((num / precision) | 0) + 1) * precision; -} - -function computeExpirationBucket(currentTime, expirationInMs, bucketSizeMs) { - return ceiling( - currentTime + expirationInMs / UNIT_SIZE, - bucketSizeMs / UNIT_SIZE - ); -} - -var NoContext = 0; -var AsyncMode = 1; -var StrictMode = 2; - -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.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.mode = mode; - - // Effects - this.effectTag = NoEffect; - this.nextEffect = null; - - this.firstEffect = null; - this.lastEffect = null; - - this.expirationTime = NoWork; - - this.alternate = null; - - { - this._debugID = debugCounter++; - this._debugSource = null; - this._debugOwner = null; - this._debugIsCurrentlyTiming = false; - 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) { - return !!(Component.prototype && Component.prototype.isReactComponent); -} - -// 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.type = current.type; - workInProgress.stateNode = current.stateNode; - - { - // DEV-only fields - workInProgress._debugID = current._debugID; - workInProgress._debugSource = current._debugSource; - workInProgress._debugOwner = current._debugOwner; - } - - 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; - } - - workInProgress.expirationTime = expirationTime; - - workInProgress.child = current.child; - workInProgress.memoizedProps = current.memoizedProps; - workInProgress.memoizedState = current.memoizedState; - workInProgress.updateQueue = current.updateQueue; - - // These will be overridden during the parent's reconciliation - workInProgress.sibling = current.sibling; - workInProgress.index = current.index; - workInProgress.ref = current.ref; - - return workInProgress; -} - -function createHostRootFiber(isAsync) { - var mode = isAsync ? AsyncMode | StrictMode : NoContext; - return createFiber(HostRoot, null, null, mode); -} - -function createFiberFromElement(element, mode, expirationTime) { - var owner = null; - { - owner = element._owner; - } - - var fiber = void 0; - var type = element.type; - var key = element.key; - var pendingProps = element.props; - - var fiberTag = void 0; - if (typeof type === "function") { - fiberTag = shouldConstruct(type) ? ClassComponent : IndeterminateComponent; - } else if (typeof type === "string") { - fiberTag = HostComponent; - } else { - switch (type) { - case REACT_FRAGMENT_TYPE: - return createFiberFromFragment( - pendingProps.children, - mode, - expirationTime, - key - ); - case REACT_ASYNC_MODE_TYPE: - fiberTag = Mode; - mode |= AsyncMode | StrictMode; - break; - case REACT_STRICT_MODE_TYPE: - fiberTag = Mode; - mode |= StrictMode; - break; - case REACT_CALL_TYPE: - fiberTag = CallComponent; - break; - case REACT_RETURN_TYPE: - fiberTag = ReturnComponent; - break; - default: { - if (typeof type === "object" && type !== null) { - switch (type.$$typeof) { - case REACT_PROVIDER_TYPE: - fiberTag = ContextProvider; - break; - case REACT_CONTEXT_TYPE: - // This is a consumer - fiberTag = ContextConsumer; - break; - case REACT_FORWARD_REF_TYPE: - fiberTag = ForwardRef; - break; - default: - if (typeof type.tag === "number") { - // Currently assumed to be a continuation and therefore is a - // fiber already. - // TODO: The yield system is currently broken for updates in - // some cases. The reified yield stores a fiber, but we don't - // know which fiber that is; the current or a workInProgress? - // When the continuation gets rendered here we don't know if we - // can reuse that fiber or if we need to clone it. There is - // probably a clever way to restructure this. - fiber = type; - fiber.pendingProps = pendingProps; - fiber.expirationTime = expirationTime; - return fiber; - } else { - throwOnInvalidElementType(type, owner); - } - break; - } - } else { - throwOnInvalidElementType(type, owner); - } - } - } - } - - fiber = createFiber(fiberTag, pendingProps, key, mode); - fiber.type = type; - fiber.expirationTime = expirationTime; - - { - fiber._debugSource = element._source; - fiber._debugOwner = element._owner; - } - - return fiber; -} - -function throwOnInvalidElementType(type, owner) { - 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) : null; - if (ownerName) { - info += "\n\nCheck the render method of `" + ownerName + "`."; - } - } - invariant( - false, - "Element type is invalid: expected a string (for built-in " + - "components) or a class/function (for composite components) " + - "but got: %s.%s", - type == null ? type : typeof type, - info - ); -} - -function createFiberFromFragment(elements, mode, expirationTime, key) { - var fiber = createFiber(Fragment, elements, key, mode); - 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); - 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.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.mode = source.mode; - target.effectTag = source.effectTag; - target.nextEffect = source.nextEffect; - target.firstEffect = source.firstEffect; - target.lastEffect = source.lastEffect; - target.expirationTime = source.expirationTime; - target.alternate = source.alternate; - target._debugID = source._debugID; - target._debugSource = source._debugSource; - target._debugOwner = source._debugOwner; - target._debugIsCurrentlyTiming = source._debugIsCurrentlyTiming; - return target; -} - -// TODO: This should be lifted into the renderer. - -function createFiberRoot(containerInfo, isAsync, hydrate) { - // Cyclic construction. This cheats the type system right now because - // stateNode is any. - var uninitializedFiber = createHostRootFiber(isAsync); - var root = { - current: uninitializedFiber, - containerInfo: containerInfo, - pendingChildren: null, - pendingCommitExpirationTime: NoWork, - finishedWork: null, - context: null, - pendingContext: null, - hydrate: hydrate, - remainingExpirationTime: NoWork, - firstBatch: null, - nextScheduledRoot: null - }; - uninitializedFiber.stateNode = root; - return root; -} - -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; - warning(false, "React DevTools encountered an error: %s", err); - } - } - }; -} - -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) { - { - warning( - 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. - { - warning(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); - } -} - -var describeComponentFrame = function(name, source, ownerName) { - return ( - "\n in " + - (name || "Unknown") + - (source - ? " (at " + - source.fileName.replace(/^.*[\\\/]/, "") + - ":" + - source.lineNumber + - ")" - : ownerName ? " (created by " + ownerName + ")" : "") - ); -}; - -function describeFiber(fiber) { - switch (fiber.tag) { - case IndeterminateComponent: - case FunctionalComponent: - case ClassComponent: - case HostComponent: - var owner = fiber._debugOwner; - var source = fiber._debugSource; - var name = getComponentName(fiber); - var ownerName = null; - if (owner) { - ownerName = getComponentName(owner); - } - return describeComponentFrame(name, source, ownerName); - default: - return ""; - } -} - -// This function can only be called with a work-in-progress fiber and -// only during begin or complete phase. Do not call it under any other -// circumstances. -function getStackAddendumByWorkInProgressFiber(workInProgress) { - var info = ""; - var node = workInProgress; - do { - info += describeFiber(node); - // Otherwise this return pointer might point to the wrong tree: - node = node["return"]; - } while (node); - return info; -} - -/** - * 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( - "`warning(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) {} -}; - -{ - var LIFECYCLE_SUGGESTIONS = { - UNSAFE_componentWillMount: "componentDidMount", - UNSAFE_componentWillReceiveProps: "static getDerivedStateFromProps", - UNSAFE_componentWillUpdate: "componentDidUpdate" - }; - - var pendingComponentWillMountWarnings = []; - var pendingComponentWillReceivePropsWarnings = []; - var pendingComponentWillUpdateWarnings = []; - var pendingUnsafeLifecycleWarnings = new Map(); - - // Tracks components we have already warned about. - var didWarnAboutDeprecatedLifecycles = new Set(); - var didWarnAboutUnsafeLifecycles = 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(); - }; - - ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = function() { - pendingUnsafeLifecycleWarnings.forEach(function( - lifecycleWarningsMap, - strictRoot - ) { - var lifecyclesWarningMesages = []; - - 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) || "Component"); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - - var formatted = lifecycle.replace("UNSAFE_", ""); - var suggestion = LIFECYCLE_SUGGESTIONS[lifecycle]; - var sortedComponentNames = setToSortedString(componentNames); - - lifecyclesWarningMesages.push( - formatted + - ": Please update the following components to use " + - (suggestion + " instead: " + sortedComponentNames) - ); - } - }); - - if (lifecyclesWarningMesages.length > 0) { - var strictRootComponentStack = getStackAddendumByWorkInProgressFiber( - strictRoot - ); - - warning( - 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, - lifecyclesWarningMesages.join("\n\n") - ); - } - }); - - pendingUnsafeLifecycleWarnings = new Map(); - }; - - var getStrictRoot = function(fiber) { - var maybeStrictRoot = null; - - while (fiber !== null) { - if (fiber.mode & StrictMode) { - maybeStrictRoot = fiber; - } - - fiber = fiber["return"]; - } - - return maybeStrictRoot; - }; - - ReactStrictModeWarnings.flushPendingDeprecationWarnings = function() { - if (pendingComponentWillMountWarnings.length > 0) { - var uniqueNames = new Set(); - pendingComponentWillMountWarnings.forEach(function(fiber) { - uniqueNames.add(getComponentName(fiber) || "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) || "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) || "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 = getStrictRoot(fiber); - - // 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; - } - - // Don't warn about react-lifecycles-compat polyfilled components. - // Note that it is sufficient to check for the presence of a - // single lifecycle, componentWillMount, with the polyfill flag. - if ( - typeof instance.componentWillMount === "function" && - instance.componentWillMount.__suppressDeprecationWarning === true - ) { - 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" || - typeof instance.UNSAFE_componentWillMount === "function" - ) { - unsafeLifecycles.push("UNSAFE_componentWillMount"); - } - if ( - typeof instance.componentWillReceiveProps === "function" || - typeof instance.UNSAFE_componentWillReceiveProps === "function" - ) { - unsafeLifecycles.push("UNSAFE_componentWillReceiveProps"); - } - if ( - typeof instance.componentWillUpdate === "function" || - typeof instance.UNSAFE_componentWillUpdate === "function" - ) { - unsafeLifecycles.push("UNSAFE_componentWillUpdate"); - } - - if (unsafeLifecycles.length > 0) { - unsafeLifecycles.forEach(function(lifecycle) { - warningsForRoot[lifecycle].push(fiber); - }); - } - }; -} - -var debugRenderPhaseSideEffects = false; -var debugRenderPhaseSideEffectsForStrictMode = false; -var enableUserTimingAPI = true; -var enableGetDerivedStateFromCatch = false; -var warnAboutDeprecatedLifecycles = false; -var replayFailedUnitOfWorkWithInvokeGuardedCallback = true; - -// React Fabric uses persistent reconciler. -var enableMutatingReconciler = false; -var enableNoopReconciler = false; -var enablePersistentReconciler = true; - -// Only used in www builds. - -function getCurrentFiberOwnerName() { - { - var fiber = ReactDebugCurrentFiber.current; - if (fiber === null) { - return null; - } - var owner = fiber._debugOwner; - if (owner !== null && typeof owner !== "undefined") { - return getComponentName(owner); - } - } - return null; -} - -function getCurrentFiberStackAddendum() { - { - var fiber = ReactDebugCurrentFiber.current; - if (fiber === null) { - return null; - } - // Safe because if current fiber exists, we are reconciling, - // and it is guaranteed to be the work-in-progress version. - return getStackAddendumByWorkInProgressFiber(fiber); - } - return null; -} - -function resetCurrentFiber() { - ReactDebugCurrentFrame.getCurrentStack = null; - ReactDebugCurrentFiber.current = null; - ReactDebugCurrentFiber.phase = null; -} - -function setCurrentFiber(fiber) { - ReactDebugCurrentFrame.getCurrentStack = getCurrentFiberStackAddendum; - ReactDebugCurrentFiber.current = fiber; - ReactDebugCurrentFiber.phase = null; -} - -function setCurrentPhase(phase) { - ReactDebugCurrentFiber.phase = phase; -} - -var ReactDebugCurrentFiber = { - current: null, - phase: null, - resetCurrentFiber: resetCurrentFiber, - setCurrentFiber: setCurrentFiber, - setCurrentPhase: setCurrentPhase, - getCurrentFiberOwnerName: getCurrentFiberOwnerName, - getCurrentFiberStackAddendum: getCurrentFiberStackAddendum -}; - -// 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$$1) { - var prefix = warning$$1 ? warningEmoji + " " : reactEmoji + " "; - var suffix = warning$$1 ? " Warning: " + warning$$1 : ""; - 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$$1) { - var formattedMarkName = formatMarkName(markName); - var formattedLabel = formatLabel(label, warning$$1); - 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) || "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) || "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$$1) { - var componentName = getComponentName(fiber) || "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$$1); -}; - -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 CallComponent: - case ReturnComponent: - 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, expirationTime) { - if (enableUserTimingAPI) { - if (supportsUserTiming) { - isWaitingForCallback = false; - var warning$$1 = didExpire ? "React was blocked by main thread" : null; - endMark( - "(Waiting for async callback... will force flush in " + - expirationTime + - " ms)", - "(Waiting for async callback...)", - warning$$1 - ); - } - } -} - -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$$1 = "An error was thrown inside this error boundary"; - endFiberMark(fiber, null, warning$$1); - } -} - -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$$1 = hasScheduledUpdateInCurrentPhase - ? "Scheduled a cascading update" - : null; - endFiberMark(currentPhaseFiber, currentPhase, warning$$1); - } - 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$$1 = null; - if (interruptedBy !== null) { - if (interruptedBy.tag === HostRoot) { - warning$$1 = "A top-level update interrupted the previous render"; - } else { - var componentName = getComponentName(interruptedBy) || "Unknown"; - warning$$1 = - "An update to " + componentName + " interrupted the previous render"; - } - } else if (commitCountInCurrentWorkLoop > 1) { - warning$$1 = "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$$1); - } -} - -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$$1 = null; - if (hasScheduledUpdateInCurrentCommit) { - warning$$1 = "Lifecycle hook scheduled a cascading update"; - } else if (commitCountInCurrentWorkLoop > 0) { - warning$$1 = "Caused by a cascading update in earlier commit"; - } - hasScheduledUpdateInCurrentCommit = false; - commitCountInCurrentWorkLoop++; - isCommitting = false; - labelsInCurrentCommit.clear(); - - endMark("(Committing Changes)", "(Committing Changes)", warning$$1); - } -} - -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 didWarnUpdateInsideUpdate = void 0; - -{ - didWarnUpdateInsideUpdate = false; -} - -// Callbacks are not validated until invocation - -// Singly linked-list of updates. When an update is scheduled, it is added to -// the queue of the current fiber and the work-in-progress fiber. The two queues -// are separate but they share a persistent structure. -// -// During reconciliation, updates are removed from the work-in-progress fiber, -// but they remain on the current fiber. That ensures that if a work-in-progress -// is aborted, the aborted updates are recovered by cloning from current. -// -// The work-in-progress queue is always a subset of the current queue. -// -// When the tree is committed, the work-in-progress becomes the current. - -function createUpdateQueue(baseState) { - var queue = { - baseState: baseState, - expirationTime: NoWork, - first: null, - last: null, - callbackList: null, - hasForceUpdate: false, - isInitialized: false, - capturedValues: null - }; - { - queue.isProcessing = false; - } - return queue; -} - -function insertUpdateIntoQueue(queue, update) { - // Append the update to the end of the list. - if (queue.last === null) { - // Queue is empty - queue.first = queue.last = update; - } else { - queue.last.next = update; - queue.last = update; - } - if ( - queue.expirationTime === NoWork || - queue.expirationTime > update.expirationTime - ) { - queue.expirationTime = update.expirationTime; - } -} - -var q1 = void 0; -var q2 = void 0; -function ensureUpdateQueues(fiber) { - q1 = q2 = null; - // We'll have at least one and at most two distinct update queues. - var alternateFiber = fiber.alternate; - var queue1 = fiber.updateQueue; - if (queue1 === null) { - // TODO: We don't know what the base state will be until we begin work. - // It depends on which fiber is the next current. Initialize with an empty - // base state, then set to the memoizedState when rendering. Not super - // happy with this approach. - queue1 = fiber.updateQueue = createUpdateQueue(null); - } - - var queue2 = void 0; - if (alternateFiber !== null) { - queue2 = alternateFiber.updateQueue; - if (queue2 === null) { - queue2 = alternateFiber.updateQueue = createUpdateQueue(null); - } - } else { - queue2 = null; - } - queue2 = queue2 !== queue1 ? queue2 : null; - - // Use module variables instead of returning a tuple - q1 = queue1; - q2 = queue2; -} - -function insertUpdateIntoFiber(fiber, update) { - ensureUpdateQueues(fiber); - var queue1 = q1; - var queue2 = q2; - - // Warn if an update is scheduled from inside an updater function. - { - if ( - (queue1.isProcessing || (queue2 !== null && queue2.isProcessing)) && - !didWarnUpdateInsideUpdate - ) { - warning( - 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; - } - } - - // If there's only one queue, add the update to that queue and exit. - if (queue2 === null) { - insertUpdateIntoQueue(queue1, update); - return; - } - - // If either queue is empty, we need to add to both queues. - if (queue1.last === null || queue2.last === null) { - insertUpdateIntoQueue(queue1, update); - insertUpdateIntoQueue(queue2, update); - return; - } - - // If both lists are not empty, the last update is the same for both lists - // because of structural sharing. So, we should only append to one of - // the lists. - insertUpdateIntoQueue(queue1, update); - // But we still need to update the `last` pointer of queue2. - queue2.last = update; -} - -function getUpdateExpirationTime(fiber) { - switch (fiber.tag) { - case HostRoot: - case ClassComponent: - var updateQueue = fiber.updateQueue; - if (updateQueue === null) { - return NoWork; - } - return updateQueue.expirationTime; - default: - return NoWork; - } -} - -function getStateFromUpdate(update, instance, prevState, props) { - var partialState = update.partialState; - if (typeof partialState === "function") { - return partialState.call(instance, prevState, props); - } else { - return partialState; - } -} - -function processUpdateQueue( - current, - workInProgress, - queue, - instance, - props, - renderExpirationTime -) { - if (current !== null && current.updateQueue === queue) { - // We need to create a work-in-progress queue, by cloning the current queue. - var currentQueue = queue; - queue = workInProgress.updateQueue = { - baseState: currentQueue.baseState, - expirationTime: currentQueue.expirationTime, - first: currentQueue.first, - last: currentQueue.last, - isInitialized: currentQueue.isInitialized, - capturedValues: currentQueue.capturedValues, - // These fields are no longer valid because they were already committed. - // Reset them. - callbackList: null, - hasForceUpdate: false - }; - } - - { - // Set this flag so we can warn if setState is called inside the update - // function of another setState. - queue.isProcessing = true; - } - - // Reset the remaining expiration time. If we skip over any updates, we'll - // increase this accordingly. - queue.expirationTime = NoWork; - - // TODO: We don't know what the base state will be until we begin work. - // It depends on which fiber is the next current. Initialize with an empty - // base state, then set to the memoizedState when rendering. Not super - // happy with this approach. - var state = void 0; - if (queue.isInitialized) { - state = queue.baseState; - } else { - state = queue.baseState = workInProgress.memoizedState; - queue.isInitialized = true; - } - var dontMutatePrevState = true; - var update = queue.first; - var didSkip = false; - while (update !== null) { - var updateExpirationTime = update.expirationTime; - if (updateExpirationTime > renderExpirationTime) { - // This update does not have sufficient priority. Skip it. - var remainingExpirationTime = queue.expirationTime; - if ( - remainingExpirationTime === NoWork || - remainingExpirationTime > updateExpirationTime - ) { - // Update the remaining expiration time. - queue.expirationTime = updateExpirationTime; - } - if (!didSkip) { - didSkip = true; - queue.baseState = state; - } - // Continue to the next update. - update = update.next; - continue; - } - - // This update does have sufficient priority. - - // If no previous updates were skipped, drop this update from the queue by - // advancing the head of the list. - if (!didSkip) { - queue.first = update.next; - if (queue.first === null) { - queue.last = null; - } - } - - // Invoke setState callback an extra time to help detect side-effects. - // Ignore the return value in this case. - if ( - debugRenderPhaseSideEffects || - (debugRenderPhaseSideEffectsForStrictMode && - workInProgress.mode & StrictMode) - ) { - getStateFromUpdate(update, instance, state, props); - } - - // Process the update - var _partialState = void 0; - if (update.isReplace) { - state = getStateFromUpdate(update, instance, state, props); - dontMutatePrevState = true; - } else { - _partialState = getStateFromUpdate(update, instance, state, props); - if (_partialState) { - if (dontMutatePrevState) { - // $FlowFixMe: Idk how to type this properly. - state = Object.assign({}, state, _partialState); - } else { - state = Object.assign(state, _partialState); - } - dontMutatePrevState = false; - } - } - if (update.isForced) { - queue.hasForceUpdate = true; - } - if (update.callback !== null) { - // Append to list of callbacks. - var _callbackList = queue.callbackList; - if (_callbackList === null) { - _callbackList = queue.callbackList = []; - } - _callbackList.push(update); - } - if (update.capturedValue !== null) { - var _capturedValues = queue.capturedValues; - if (_capturedValues === null) { - queue.capturedValues = [update.capturedValue]; - } else { - _capturedValues.push(update.capturedValue); - } - } - update = update.next; - } - - if (queue.callbackList !== null) { - workInProgress.effectTag |= Callback; - } else if ( - queue.first === null && - !queue.hasForceUpdate && - queue.capturedValues === null - ) { - // The queue is empty. We can reset it. - workInProgress.updateQueue = null; - } - - if (!didSkip) { - didSkip = true; - queue.baseState = state; - } - - { - // No longer processing. - queue.isProcessing = false; - } - - return state; -} - -function commitCallbacks(queue, context) { - var callbackList = queue.callbackList; - if (callbackList === null) { - return; - } - // Set the list to null to make sure they don't get called more than once. - queue.callbackList = null; - for (var i = 0; i < callbackList.length; i++) { - var update = callbackList[i]; - var _callback = update.callback; - // This update might be processed again. Clear the callback so it's only - // called once. - update.callback = null; - invariant( - typeof _callback === "function", - "Invalid argument passed as callback. Expected a function. Instead " + - "received: %s", - _callback - ); - _callback.call(context); - } -} - -var fakeInternalInstance = {}; -var isArray = Array.isArray; - -var didWarnAboutStateAssignmentForComponent = void 0; -var didWarnAboutUndefinedDerivedState = void 0; -var didWarnAboutUninitializedState = void 0; -var didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = void 0; -var didWarnAboutLegacyLifecyclesAndDerivedState = void 0; -var warnOnInvalidCallback = void 0; - -{ - didWarnAboutStateAssignmentForComponent = new Set(); - didWarnAboutUndefinedDerivedState = new Set(); - didWarnAboutUninitializedState = new Set(); - didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = new Set(); - didWarnAboutLegacyLifecyclesAndDerivedState = 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); - warning( - false, - "%s(...): Expected the last optional `callback` argument to be a " + - "function. Instead received: %s.", - callerName, - callback - ); - } - }; - - // 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() { - invariant( - false, - "_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 callGetDerivedStateFromCatch(ctor, capturedValues) { - var resultState = {}; - for (var i = 0; i < capturedValues.length; i++) { - var capturedValue = capturedValues[i]; - var error = capturedValue.value; - var partialState = ctor.getDerivedStateFromCatch.call(null, error); - if (partialState !== null && partialState !== undefined) { - Object.assign(resultState, partialState); - } - } - return resultState; -} - -var ReactFiberClassComponent = function( - legacyContext, - scheduleWork, - computeExpirationForFiber, - memoizeProps, - memoizeState -) { - var cacheContext = legacyContext.cacheContext, - getMaskedContext = legacyContext.getMaskedContext, - getUnmaskedContext = legacyContext.getUnmaskedContext, - isContextConsumer = legacyContext.isContextConsumer, - hasContextChanged = legacyContext.hasContextChanged; - - // Class component state updater - - var updater = { - isMounted: isMounted, - enqueueSetState: function(instance, partialState, callback) { - var fiber = get$1(instance); - callback = callback === undefined ? null : callback; - { - warnOnInvalidCallback(callback, "setState"); - } - var expirationTime = computeExpirationForFiber(fiber); - var update = { - expirationTime: expirationTime, - partialState: partialState, - callback: callback, - isReplace: false, - isForced: false, - capturedValue: null, - next: null - }; - insertUpdateIntoFiber(fiber, update); - scheduleWork(fiber, expirationTime); - }, - enqueueReplaceState: function(instance, state, callback) { - var fiber = get$1(instance); - callback = callback === undefined ? null : callback; - { - warnOnInvalidCallback(callback, "replaceState"); - } - var expirationTime = computeExpirationForFiber(fiber); - var update = { - expirationTime: expirationTime, - partialState: state, - callback: callback, - isReplace: true, - isForced: false, - capturedValue: null, - next: null - }; - insertUpdateIntoFiber(fiber, update); - scheduleWork(fiber, expirationTime); - }, - enqueueForceUpdate: function(instance, callback) { - var fiber = get$1(instance); - callback = callback === undefined ? null : callback; - { - warnOnInvalidCallback(callback, "forceUpdate"); - } - var expirationTime = computeExpirationForFiber(fiber); - var update = { - expirationTime: expirationTime, - partialState: null, - callback: callback, - isReplace: false, - isForced: true, - capturedValue: null, - next: null - }; - insertUpdateIntoFiber(fiber, update); - scheduleWork(fiber, expirationTime); - } - }; - - function checkShouldComponentUpdate( - workInProgress, - oldProps, - newProps, - oldState, - newState, - newContext - ) { - if ( - oldProps === null || - (workInProgress.updateQueue !== null && - workInProgress.updateQueue.hasForceUpdate) - ) { - // If the workInProgress already has an Update effect, return true - return true; - } - - var instance = workInProgress.stateNode; - var ctor = workInProgress.type; - if (typeof instance.shouldComponentUpdate === "function") { - startPhaseTimer(workInProgress, "shouldComponentUpdate"); - var shouldUpdate = instance.shouldComponentUpdate( - newProps, - newState, - newContext - ); - stopPhaseTimer(); - - { - !(shouldUpdate !== undefined) - ? warning( - false, - "%s.shouldComponentUpdate(): Returned undefined instead of a " + - "boolean value. Make sure to return true or false.", - getComponentName(workInProgress) || "Component" - ) - : void 0; - } - - return shouldUpdate; - } - - if (ctor.prototype && ctor.prototype.isPureReactComponent) { - return ( - !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) - ); - } - - return true; - } - - function checkClassInstance(workInProgress) { - var instance = workInProgress.stateNode; - var type = workInProgress.type; - { - var name = getComponentName(workInProgress) || "Component"; - var renderPresent = instance.render; - - if (!renderPresent) { - if (type.prototype && typeof type.prototype.render === "function") { - warning( - false, - "%s(...): No `render` method found on the returned component " + - "instance: did you accidentally return an object from the constructor?", - name - ); - } else { - warning( - 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 - ? warning( - 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 - ? warning( - 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 - ? warning( - false, - "propTypes was defined as an instance property on %s. Use a static " + - "property to define propTypes instead.", - name - ) - : void 0; - var noInstanceContextTypes = !instance.contextTypes; - !noInstanceContextTypes - ? warning( - false, - "contextTypes was defined as an instance property on %s. Use a static " + - "property to define contextTypes instead.", - name - ) - : void 0; - var noComponentShouldUpdate = - typeof instance.componentShouldUpdate !== "function"; - !noComponentShouldUpdate - ? warning( - 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 ( - type.prototype && - type.prototype.isPureReactComponent && - typeof instance.shouldComponentUpdate !== "undefined" - ) { - warning( - 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(workInProgress) || "A pure component" - ); - } - var noComponentDidUnmount = - typeof instance.componentDidUnmount !== "function"; - !noComponentDidUnmount - ? warning( - 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 - ? warning( - 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 - ? warning( - false, - "%s has a method called " + - "componentWillRecieveProps(). Did you mean componentWillReceiveProps()?", - name - ) - : void 0; - var noUnsafeComponentWillRecieveProps = - typeof instance.UNSAFE_componentWillRecieveProps !== "function"; - !noUnsafeComponentWillRecieveProps - ? warning( - false, - "%s has a method called " + - "UNSAFE_componentWillRecieveProps(). Did you mean UNSAFE_componentWillReceiveProps()?", - name - ) - : void 0; - var hasMutatedProps = instance.props !== workInProgress.pendingProps; - !(instance.props === undefined || !hasMutatedProps) - ? warning( - 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 - ? warning( - 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(type) - ) { - didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.add(type); - warning( - false, - "%s: getSnapshotBeforeUpdate() should be used with componentDidUpdate(). " + - "This component defines getSnapshotBeforeUpdate() only.", - getComponentName(workInProgress) - ); - } - - var noInstanceGetDerivedStateFromProps = - typeof instance.getDerivedStateFromProps !== "function"; - !noInstanceGetDerivedStateFromProps - ? warning( - 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.getDerivedStateFromCatch !== "function"; - !noInstanceGetDerivedStateFromCatch - ? warning( - false, - "%s: getDerivedStateFromCatch() is defined as an instance method " + - "and will be ignored. Instead, declare it as a static method.", - name - ) - : void 0; - var noStaticGetSnapshotBeforeUpdate = - typeof type.getSnapshotBeforeUpdate !== "function"; - !noStaticGetSnapshotBeforeUpdate - ? warning( - 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(_state))) { - warning(false, "%s.state: must be set to an object or null", name); - } - if (typeof instance.getChildContext === "function") { - !(typeof type.childContextTypes === "object") - ? warning( - false, - "%s.getChildContext(): childContextTypes must be defined in order to " + - "use getChildContext().", - name - ) - : void 0; - } - } - } - - function resetInputPointers(workInProgress, instance) { - instance.props = workInProgress.memoizedProps; - instance.state = workInProgress.memoizedState; - } - - function adoptClassInstance(workInProgress, instance) { - instance.updater = updater; - 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, props) { - var ctor = workInProgress.type; - var unmaskedContext = getUnmaskedContext(workInProgress); - var needsContext = isContextConsumer(workInProgress); - var context = needsContext - ? getMaskedContext(workInProgress, unmaskedContext) - : emptyObject; - - // 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 = - instance.state !== null && instance.state !== undefined - ? instance.state - : null; - adoptClassInstance(workInProgress, instance); - - { - if ( - typeof ctor.getDerivedStateFromProps === "function" && - state === null - ) { - var componentName = getComponentName(workInProgress) || "Component"; - if (!didWarnAboutUninitializedState.has(componentName)) { - didWarnAboutUninitializedState.add(componentName); - warning( - false, - "%s: Did not properly initialize state during construction. " + - "Expected state to be an object, but it was %s.", - componentName, - instance.state === null ? "null" : "undefined" - ); - } - } - - // 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(workInProgress) || "Component"; - var newApiName = - typeof ctor.getDerivedStateFromProps === "function" - ? "getDerivedStateFromProps()" - : "getSnapshotBeforeUpdate()"; - if ( - !didWarnAboutLegacyLifecyclesAndDerivedState.has(_componentName) - ) { - didWarnAboutLegacyLifecyclesAndDerivedState.add(_componentName); - warning( - 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 : "" - ); - } - } - } - } - - workInProgress.memoizedState = state; - - var partialState = callGetDerivedStateFromProps( - workInProgress, - instance, - props, - state - ); - - if (partialState !== null && partialState !== undefined) { - // Render-phase updates (like this) should not be added to the update queue, - // So that multiple render passes do not enqueue multiple updates. - // Instead, just synchronously merge the returned state into the instance. - workInProgress.memoizedState = Object.assign( - {}, - workInProgress.memoizedState, - partialState - ); - } - - // 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 (needsContext) { - 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) { - { - warning( - false, - "%s.componentWillMount(): Assigning directly to this.state is " + - "deprecated (except inside a component's " + - "constructor). Use setState instead.", - getComponentName(workInProgress) || "Component" - ); - } - updater.enqueueReplaceState(instance, instance.state, null); - } - } - - function callComponentWillReceiveProps( - workInProgress, - instance, - newProps, - newContext - ) { - var oldState = instance.state; - startPhaseTimer(workInProgress, "componentWillReceiveProps"); - if (typeof instance.componentWillReceiveProps === "function") { - instance.componentWillReceiveProps(newProps, newContext); - } - if (typeof instance.UNSAFE_componentWillReceiveProps === "function") { - instance.UNSAFE_componentWillReceiveProps(newProps, newContext); - } - stopPhaseTimer(); - - if (instance.state !== oldState) { - { - var componentName = getComponentName(workInProgress) || "Component"; - if (!didWarnAboutStateAssignmentForComponent.has(componentName)) { - didWarnAboutStateAssignmentForComponent.add(componentName); - warning( - false, - "%s.componentWillReceiveProps(): Assigning directly to " + - "this.state is deprecated (except inside a component's " + - "constructor). Use setState instead.", - componentName - ); - } - } - updater.enqueueReplaceState(instance, instance.state, null); - } - } - - function callGetDerivedStateFromProps( - workInProgress, - instance, - nextProps, - prevState - ) { - var type = workInProgress.type; - - if (typeof type.getDerivedStateFromProps === "function") { - if ( - debugRenderPhaseSideEffects || - (debugRenderPhaseSideEffectsForStrictMode && - workInProgress.mode & StrictMode) - ) { - // Invoke method an extra time to help detect side-effects. - type.getDerivedStateFromProps.call(null, nextProps, prevState); - } - - var partialState = type.getDerivedStateFromProps.call( - null, - nextProps, - prevState - ); - - { - if (partialState === undefined) { - var componentName = getComponentName(workInProgress) || "Component"; - if (!didWarnAboutUndefinedDerivedState.has(componentName)) { - didWarnAboutUndefinedDerivedState.add(componentName); - warning( - false, - "%s.getDerivedStateFromProps(): A valid state object (or null) must be returned. " + - "You have returned undefined.", - componentName - ); - } - } - } - - return partialState; - } - } - - // Invokes the mount life-cycles on a previously never rendered instance. - function mountClassInstance(workInProgress, renderExpirationTime) { - var ctor = workInProgress.type; - var current = workInProgress.alternate; - - { - checkClassInstance(workInProgress); - } - - var instance = workInProgress.stateNode; - var props = workInProgress.pendingProps; - var unmaskedContext = getUnmaskedContext(workInProgress); - - instance.props = props; - instance.state = workInProgress.memoizedState; - instance.refs = emptyObject; - instance.context = getMaskedContext(workInProgress, unmaskedContext); - - { - if (workInProgress.mode & StrictMode) { - ReactStrictModeWarnings.recordUnsafeLifecycleWarnings( - workInProgress, - instance - ); - } - - if (warnAboutDeprecatedLifecycles) { - ReactStrictModeWarnings.recordDeprecationWarnings( - workInProgress, - instance - ); - } - } - - // 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. - var updateQueue = workInProgress.updateQueue; - if (updateQueue !== null) { - instance.state = processUpdateQueue( - current, - workInProgress, - updateQueue, - instance, - props, - renderExpirationTime - ); - } - } - if (typeof instance.componentDidMount === "function") { - workInProgress.effectTag |= Update; - } - } - - function resumeMountClassInstance(workInProgress, renderExpirationTime) { - var ctor = workInProgress.type; - var instance = workInProgress.stateNode; - resetInputPointers(workInProgress, instance); - - var oldProps = workInProgress.memoizedProps; - var newProps = workInProgress.pendingProps; - var oldContext = instance.context; - var newUnmaskedContext = getUnmaskedContext(workInProgress); - var newContext = getMaskedContext(workInProgress, newUnmaskedContext); - - var hasNewLifecycles = - typeof ctor.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 !== newContext) { - callComponentWillReceiveProps( - workInProgress, - instance, - newProps, - newContext - ); - } - } - - // Compute the next state using the memoized state and the update queue. - var oldState = workInProgress.memoizedState; - // TODO: Previous state can be null. - var newState = void 0; - var derivedStateFromCatch = void 0; - if (workInProgress.updateQueue !== null) { - newState = processUpdateQueue( - null, - workInProgress, - workInProgress.updateQueue, - instance, - newProps, - renderExpirationTime - ); - - var updateQueue = workInProgress.updateQueue; - if ( - updateQueue !== null && - updateQueue.capturedValues !== null && - enableGetDerivedStateFromCatch && - typeof ctor.getDerivedStateFromCatch === "function" - ) { - var capturedValues = updateQueue.capturedValues; - // Don't remove these from the update queue yet. We need them in - // finishClassComponent. Do the reset there. - // TODO: This is awkward. Refactor class components. - // updateQueue.capturedValues = null; - derivedStateFromCatch = callGetDerivedStateFromCatch( - ctor, - capturedValues - ); - } - } else { - newState = oldState; - } - - var derivedStateFromProps = void 0; - if (oldProps !== newProps) { - // The prevState parameter should be the partially updated state. - // Otherwise, spreading state in return values could override updates. - derivedStateFromProps = callGetDerivedStateFromProps( - workInProgress, - instance, - newProps, - newState - ); - } - - if (derivedStateFromProps !== null && derivedStateFromProps !== undefined) { - // Render-phase updates (like this) should not be added to the update queue, - // So that multiple render passes do not enqueue multiple updates. - // Instead, just synchronously merge the returned state into the instance. - newState = - newState === null || newState === undefined - ? derivedStateFromProps - : Object.assign({}, newState, derivedStateFromProps); - - // Update the base state of the update queue. - // FIXME: This is getting ridiculous. Refactor plz! - var _updateQueue = workInProgress.updateQueue; - if (_updateQueue !== null) { - _updateQueue.baseState = Object.assign( - {}, - _updateQueue.baseState, - derivedStateFromProps - ); - } - } - if (derivedStateFromCatch !== null && derivedStateFromCatch !== undefined) { - // Render-phase updates (like this) should not be added to the update queue, - // So that multiple render passes do not enqueue multiple updates. - // Instead, just synchronously merge the returned state into the instance. - newState = - newState === null || newState === undefined - ? derivedStateFromCatch - : Object.assign({}, newState, derivedStateFromCatch); - - // Update the base state of the update queue. - // FIXME: This is getting ridiculous. Refactor plz! - var _updateQueue2 = workInProgress.updateQueue; - if (_updateQueue2 !== null) { - _updateQueue2.baseState = Object.assign( - {}, - _updateQueue2.baseState, - derivedStateFromCatch - ); - } - } - - if ( - oldProps === newProps && - oldState === newState && - !hasContextChanged() && - !( - workInProgress.updateQueue !== null && - workInProgress.updateQueue.hasForceUpdate - ) - ) { - // 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; - } - - var shouldUpdate = checkShouldComponentUpdate( - workInProgress, - oldProps, - newProps, - oldState, - newState, - newContext - ); - - 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 props/state to indicate that this work can be reused. - memoizeProps(workInProgress, newProps); - memoizeState(workInProgress, newState); - } - - // Update the existing instance's state, props, and context pointers even - // if shouldComponentUpdate returns false. - instance.props = newProps; - instance.state = newState; - instance.context = newContext; - - return shouldUpdate; - } - - // Invokes the update life-cycles and returns false if it shouldn't rerender. - function updateClassInstance(current, workInProgress, renderExpirationTime) { - var ctor = workInProgress.type; - var instance = workInProgress.stateNode; - resetInputPointers(workInProgress, instance); - - var oldProps = workInProgress.memoizedProps; - var newProps = workInProgress.pendingProps; - var oldContext = instance.context; - var newUnmaskedContext = getUnmaskedContext(workInProgress); - var newContext = getMaskedContext(workInProgress, newUnmaskedContext); - - var hasNewLifecycles = - typeof ctor.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 !== newContext) { - callComponentWillReceiveProps( - workInProgress, - instance, - newProps, - newContext - ); - } - } - - // Compute the next state using the memoized state and the update queue. - var oldState = workInProgress.memoizedState; - // TODO: Previous state can be null. - var newState = void 0; - var derivedStateFromCatch = void 0; - - if (workInProgress.updateQueue !== null) { - newState = processUpdateQueue( - current, - workInProgress, - workInProgress.updateQueue, - instance, - newProps, - renderExpirationTime - ); - - var updateQueue = workInProgress.updateQueue; - if ( - updateQueue !== null && - updateQueue.capturedValues !== null && - enableGetDerivedStateFromCatch && - typeof ctor.getDerivedStateFromCatch === "function" - ) { - var capturedValues = updateQueue.capturedValues; - // Don't remove these from the update queue yet. We need them in - // finishClassComponent. Do the reset there. - // TODO: This is awkward. Refactor class components. - // updateQueue.capturedValues = null; - derivedStateFromCatch = callGetDerivedStateFromCatch( - ctor, - capturedValues - ); - } - } else { - newState = oldState; - } - - var derivedStateFromProps = void 0; - if (oldProps !== newProps) { - // The prevState parameter should be the partially updated state. - // Otherwise, spreading state in return values could override updates. - derivedStateFromProps = callGetDerivedStateFromProps( - workInProgress, - instance, - newProps, - newState - ); - } - - if (derivedStateFromProps !== null && derivedStateFromProps !== undefined) { - // Render-phase updates (like this) should not be added to the update queue, - // So that multiple render passes do not enqueue multiple updates. - // Instead, just synchronously merge the returned state into the instance. - newState = - newState === null || newState === undefined - ? derivedStateFromProps - : Object.assign({}, newState, derivedStateFromProps); - - // Update the base state of the update queue. - // FIXME: This is getting ridiculous. Refactor plz! - var _updateQueue3 = workInProgress.updateQueue; - if (_updateQueue3 !== null) { - _updateQueue3.baseState = Object.assign( - {}, - _updateQueue3.baseState, - derivedStateFromProps - ); - } - } - if (derivedStateFromCatch !== null && derivedStateFromCatch !== undefined) { - // Render-phase updates (like this) should not be added to the update queue, - // So that multiple render passes do not enqueue multiple updates. - // Instead, just synchronously merge the returned state into the instance. - newState = - newState === null || newState === undefined - ? derivedStateFromCatch - : Object.assign({}, newState, derivedStateFromCatch); - - // Update the base state of the update queue. - // FIXME: This is getting ridiculous. Refactor plz! - var _updateQueue4 = workInProgress.updateQueue; - if (_updateQueue4 !== null) { - _updateQueue4.baseState = Object.assign( - {}, - _updateQueue4.baseState, - derivedStateFromCatch - ); - } - } - - if ( - oldProps === newProps && - oldState === newState && - !hasContextChanged() && - !( - workInProgress.updateQueue !== null && - workInProgress.updateQueue.hasForceUpdate - ) - ) { - // 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; - } - - var shouldUpdate = checkShouldComponentUpdate( - workInProgress, - oldProps, - newProps, - oldState, - newState, - newContext - ); - - 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, newContext); - } - if (typeof instance.UNSAFE_componentWillUpdate === "function") { - instance.UNSAFE_componentWillUpdate(newProps, newState, newContext); - } - 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. - memoizeProps(workInProgress, newProps); - memoizeState(workInProgress, newState); - } - - // Update the existing instance's state, props, and context pointers even - // if shouldComponentUpdate returns false. - instance.props = newProps; - instance.state = newState; - instance.context = newContext; - - return shouldUpdate; - } - - return { - adoptClassInstance: adoptClassInstance, - callGetDerivedStateFromProps: callGetDerivedStateFromProps, - constructClassInstance: constructClassInstance, - mountClassInstance: mountClassInstance, - resumeMountClassInstance: resumeMountClassInstance, - updateClassInstance: updateClassInstance - }; -}; - -var getCurrentFiberStackAddendum$1 = - ReactDebugCurrentFiber.getCurrentFiberStackAddendum; - -var didWarnAboutMaps = void 0; -var didWarnAboutStringRefInStrictMode = void 0; -var ownerHasKeyUseWarning = void 0; -var ownerHasFunctionTypeWarning = void 0; -var warnForMissingKey = function(child) {}; - -{ - didWarnAboutMaps = 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; - } - invariant( - typeof child._store === "object", - "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 an array or iterator should have a unique " + - '"key" prop. See https://fb.me/react-warning-keys for ' + - "more information." + - (getCurrentFiberStackAddendum$1() || ""); - if (ownerHasKeyUseWarning[currentComponentErrorInfo]) { - return; - } - ownerHasKeyUseWarning[currentComponentErrorInfo] = true; - - warning( - false, - "Each child in an array or iterator should have a unique " + - '"key" prop. See https://fb.me/react-warning-keys for ' + - "more information.%s", - getCurrentFiberStackAddendum$1() - ); - }; -} - -var isArray$1 = Array.isArray; - -function coerceRef(returnFiber, current, element) { - var mixedRef = element.ref; - if ( - mixedRef !== null && - typeof mixedRef !== "function" && - typeof mixedRef !== "object" - ) { - { - if (returnFiber.mode & StrictMode) { - var componentName = getComponentName(returnFiber) || "Component"; - if (!didWarnAboutStringRefInStrictMode[componentName]) { - warning( - 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, - getStackAddendumByWorkInProgressFiber(returnFiber) - ); - didWarnAboutStringRefInStrictMode[componentName] = true; - } - } - } - - if (element._owner) { - var owner = element._owner; - var inst = void 0; - if (owner) { - var ownerFiber = owner; - invariant( - ownerFiber.tag === ClassComponent, - "Stateless function components cannot have refs." - ); - inst = ownerFiber.stateNode; - } - invariant( - inst, - "Missing owner for string ref %s. This error is likely caused by a " + - "bug in React. Please file an issue.", - mixedRef - ); - var stringRef = "" + mixedRef; - // Check if previous string ref matches new string ref - if ( - current !== null && - current.ref !== null && - current.ref._stringRef === stringRef - ) { - return current.ref; - } - var ref = function(value) { - var refs = inst.refs === emptyObject ? (inst.refs = {}) : inst.refs; - if (value === null) { - delete refs[stringRef]; - } else { - refs[stringRef] = value; - } - }; - ref._stringRef = stringRef; - return ref; - } else { - invariant( - typeof mixedRef === "string", - "Expected ref to be a function or a string." - ); - invariant( - element._owner, - "Element ref was specified as a string (%s) but no owner was set. This could happen for one of" + - " the following reasons:\n" + - "1. You may be adding a ref to a functional component\n" + - "2. You may be adding a ref to a component that was not created inside a component's render method\n" + - "3. You have multiple copies of React loaded\n" + - "See https://fb.me/react-refs-must-have-owner for more information.", - mixedRef - ); - } - } - 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." + - (getCurrentFiberStackAddendum$1() || ""); - } - invariant( - false, - "Objects are not valid as a React child (found: %s).%s", - 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." + - (getCurrentFiberStackAddendum$1() || ""); - - if (ownerHasFunctionTypeWarning[currentComponentErrorInfo]) { - return; - } - ownerHasFunctionTypeWarning[currentComponentErrorInfo] = true; - - warning( - 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.%s", - getCurrentFiberStackAddendum$1() || "" - ); -} - -// 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 = newFiber.alternate; - if (current !== null) { - var oldIndex = current.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, textContent, expirationTime) { - if (current === null || current.tag !== HostText) { - // Insert - var created = createFiberFromText( - textContent, - returnFiber.mode, - expirationTime - ); - created["return"] = returnFiber; - return created; - } else { - // Update - var existing = useFiber(current, textContent, expirationTime); - existing["return"] = returnFiber; - return existing; - } - } - - function updateElement(returnFiber, current, element, expirationTime) { - if (current !== null && current.type === element.type) { - // Move based on index - var existing = useFiber(current, element.props, expirationTime); - existing.ref = coerceRef(returnFiber, current, 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, element); - created["return"] = returnFiber; - return created; - } - } - - function updatePortal(returnFiber, current, portal, expirationTime) { - if ( - current === null || - current.tag !== HostPortal || - current.stateNode.containerInfo !== portal.containerInfo || - current.stateNode.implementation !== portal.implementation - ) { - // Insert - var created = createFiberFromPortal( - portal, - returnFiber.mode, - expirationTime - ); - created["return"] = returnFiber; - return created; - } else { - // Update - var existing = useFiber(current, portal.children || [], expirationTime); - existing["return"] = returnFiber; - return existing; - } - } - - function updateFragment(returnFiber, current, fragment, expirationTime, key) { - if (current === null || current.tag !== Fragment) { - // Insert - var created = createFiberFromFragment( - fragment, - returnFiber.mode, - expirationTime, - key - ); - created["return"] = returnFiber; - return created; - } else { - // Update - var existing = useFiber(current, 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$1(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$1(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$1(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( - 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.%s", - key, - getCurrentFiberStackAddendum$1() - ); - break; - default: - break; - } - } - return knownKeys; - } - - function reconcileChildrenArray( - returnFiber, - currentFirstChild, - newChildren, - expirationTime - ) { - // This algorithm can't optimize by searching from boths 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) { - 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) { - 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); - invariant( - typeof iteratorFn === "function", - "An object is not an iterable. This error is likely caused by a bug in " + - "React. Please file an issue." - ); - - { - // Warn about using Maps as children - if (typeof newChildrenIterable.entries === "function") { - var possibleMap = newChildrenIterable; - if (possibleMap.entries === iteratorFn) { - !didWarnAboutMaps - ? warning( - false, - "Using Maps as children is unsupported and will likely yield " + - "unexpected results. Convert it to a sequence/iterable of keyed " + - "ReactElements instead.%s", - getCurrentFiberStackAddendum$1() - ) - : 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); - invariant(newChildren != null, "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) { - 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.type === 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. - if ( - typeof newChild === "object" && - newChild !== null && - newChild.type === REACT_FRAGMENT_TYPE && - newChild.key === null - ) { - 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$1(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") { - // 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 FunctionalComponent: { - var Component = returnFiber.type; - invariant( - false, - "%s(...): Nothing was returned from render. This usually means a " + - "return statement is missing. Or, to render nothing, " + - "return null.", - Component.displayName || Component.name || "Component" - ); - } - } - } - - // Remaining cases are all treated as empty. - return deleteRemainingChildren(returnFiber, currentFirstChild); - } - - return reconcileChildFibers; -} - -var reconcileChildFibers = ChildReconciler(true); -var mountChildFibers = ChildReconciler(false); - -function cloneChildFibers(current, workInProgress) { - invariant( - current === null || workInProgress.child === current.child, - "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 didWarnAboutBadClass = void 0; -var didWarnAboutGetDerivedStateOnFunctionalComponent = void 0; -var didWarnAboutStatelessRefs = void 0; - -{ - didWarnAboutBadClass = {}; - didWarnAboutGetDerivedStateOnFunctionalComponent = {}; - didWarnAboutStatelessRefs = {}; -} - -var ReactFiberBeginWork = function( - config, - hostContext, - legacyContext, - newContext, - hydrationContext, - scheduleWork, - computeExpirationForFiber -) { - var shouldSetTextContent = config.shouldSetTextContent, - shouldDeprioritizeSubtree = config.shouldDeprioritizeSubtree; - var pushHostContext = hostContext.pushHostContext, - pushHostContainer = hostContext.pushHostContainer; - var pushProvider = newContext.pushProvider; - var getMaskedContext = legacyContext.getMaskedContext, - getUnmaskedContext = legacyContext.getUnmaskedContext, - hasLegacyContextChanged = legacyContext.hasContextChanged, - pushLegacyContextProvider = legacyContext.pushContextProvider, - pushTopLevelContextObject = legacyContext.pushTopLevelContextObject, - invalidateContextProvider = legacyContext.invalidateContextProvider; - var enterHydrationState = hydrationContext.enterHydrationState, - resetHydrationState = hydrationContext.resetHydrationState, - tryToClaimNextHydratableInstance = - hydrationContext.tryToClaimNextHydratableInstance; - - var _ReactFiberClassCompo = ReactFiberClassComponent( - legacyContext, - scheduleWork, - computeExpirationForFiber, - memoizeProps, - memoizeState - ), - adoptClassInstance = _ReactFiberClassCompo.adoptClassInstance, - callGetDerivedStateFromProps = - _ReactFiberClassCompo.callGetDerivedStateFromProps, - constructClassInstance = _ReactFiberClassCompo.constructClassInstance, - mountClassInstance = _ReactFiberClassCompo.mountClassInstance, - resumeMountClassInstance = _ReactFiberClassCompo.resumeMountClassInstance, - updateClassInstance = _ReactFiberClassCompo.updateClassInstance; - - // TODO: Remove this and use reconcileChildrenAtExpirationTime directly. - - function reconcileChildren(current, workInProgress, nextChildren) { - reconcileChildrenAtExpirationTime( - current, - workInProgress, - nextChildren, - workInProgress.expirationTime - ); - } - - function reconcileChildrenAtExpirationTime( - current, - workInProgress, - nextChildren, - renderExpirationTime - ) { - if (current === 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.child, - nextChildren, - renderExpirationTime - ); - } - } - - function updateForwardRef(current, workInProgress) { - var render = workInProgress.type.render; - var nextChildren = render(workInProgress.pendingProps, workInProgress.ref); - reconcileChildren(current, workInProgress, nextChildren); - memoizeProps(workInProgress, nextChildren); - return workInProgress.child; - } - - function updateFragment(current, workInProgress) { - var nextChildren = workInProgress.pendingProps; - if (hasLegacyContextChanged()) { - // Normally we can bail out on props equality but if context has changed - // we don't do the bailout and we have to reuse existing props instead. - } else if (workInProgress.memoizedProps === nextChildren) { - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - reconcileChildren(current, workInProgress, nextChildren); - memoizeProps(workInProgress, nextChildren); - return workInProgress.child; - } - - function updateMode(current, workInProgress) { - var nextChildren = workInProgress.pendingProps.children; - if (hasLegacyContextChanged()) { - // Normally we can bail out on props equality but if context has changed - // we don't do the bailout and we have to reuse existing props instead. - } else if ( - nextChildren === null || - workInProgress.memoizedProps === nextChildren - ) { - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - reconcileChildren(current, workInProgress, nextChildren); - memoizeProps(workInProgress, nextChildren); - return workInProgress.child; - } - - function markRef(current, workInProgress) { - var ref = workInProgress.ref; - if ( - (current === null && ref !== null) || - (current !== null && current.ref !== ref) - ) { - // Schedule a Ref effect - workInProgress.effectTag |= Ref; - } - } - - function updateFunctionalComponent(current, workInProgress) { - var fn = workInProgress.type; - var nextProps = workInProgress.pendingProps; - - if (hasLegacyContextChanged()) { - // Normally we can bail out on props equality but if context has changed - // we don't do the bailout and we have to reuse existing props instead. - } else { - if (workInProgress.memoizedProps === nextProps) { - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - // TODO: consider bringing fn.shouldComponentUpdate() back. - // It used to be here. - } - - var unmaskedContext = getUnmaskedContext(workInProgress); - var context = getMaskedContext(workInProgress, unmaskedContext); - - var nextChildren = void 0; - - { - ReactCurrentOwner.current = workInProgress; - ReactDebugCurrentFiber.setCurrentPhase("render"); - nextChildren = fn(nextProps, context); - ReactDebugCurrentFiber.setCurrentPhase(null); - } - // React DevTools reads this flag. - workInProgress.effectTag |= PerformedWork; - reconcileChildren(current, workInProgress, nextChildren); - memoizeProps(workInProgress, nextProps); - return workInProgress.child; - } - - function updateClassComponent(current, workInProgress, renderExpirationTime) { - // 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 = pushLegacyContextProvider(workInProgress); - var shouldUpdate = void 0; - if (current === null) { - if (workInProgress.stateNode === null) { - // In the initial pass we might need to construct the instance. - constructClassInstance(workInProgress, workInProgress.pendingProps); - mountClassInstance(workInProgress, renderExpirationTime); - - shouldUpdate = true; - } else { - // In a resume, we'll already have an instance we can reuse. - shouldUpdate = resumeMountClassInstance( - workInProgress, - renderExpirationTime - ); - } - } else { - shouldUpdate = updateClassInstance( - current, - workInProgress, - renderExpirationTime - ); - } - - // We processed the update queue inside updateClassInstance. It may have - // included some errors that were dispatched during the commit phase. - // TODO: Refactor class components so this is less awkward. - var didCaptureError = false; - var updateQueue = workInProgress.updateQueue; - if (updateQueue !== null && updateQueue.capturedValues !== null) { - shouldUpdate = true; - didCaptureError = true; - } - return finishClassComponent( - current, - workInProgress, - shouldUpdate, - hasContext, - didCaptureError, - renderExpirationTime - ); - } - - function finishClassComponent( - current, - workInProgress, - shouldUpdate, - hasContext, - didCaptureError, - renderExpirationTime - ) { - // Refs should update even if shouldComponentUpdate returns false - markRef(current, workInProgress); - - if (!shouldUpdate && !didCaptureError) { - // Context providers should defer to sCU for rendering - if (hasContext) { - invalidateContextProvider(workInProgress, false); - } - - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - - var ctor = workInProgress.type; - var instance = workInProgress.stateNode; - - // Rerender - ReactCurrentOwner.current = workInProgress; - var nextChildren = void 0; - if ( - didCaptureError && - (!enableGetDerivedStateFromCatch || - typeof ctor.getDerivedStateFromCatch !== "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; - } else { - { - ReactDebugCurrentFiber.setCurrentPhase("render"); - nextChildren = instance.render(); - if ( - debugRenderPhaseSideEffects || - (debugRenderPhaseSideEffectsForStrictMode && - workInProgress.mode & StrictMode) - ) { - instance.render(); - } - ReactDebugCurrentFiber.setCurrentPhase(null); - } - } - - // React DevTools reads this flag. - workInProgress.effectTag |= PerformedWork; - if (didCaptureError) { - // If we're recovering from an error, reconcile twice: first to delete - // all the existing children. - reconcileChildrenAtExpirationTime( - current, - workInProgress, - null, - renderExpirationTime - ); - workInProgress.child = null; - // Now we can continue reconciling like normal. This has the effect of - // remounting all children regardless of whether their their - // identity matches. - } - reconcileChildrenAtExpirationTime( - current, - workInProgress, - nextChildren, - renderExpirationTime - ); - // Memoize props and state using the values we just used to render. - // TODO: Restructure so we never read values from the instance. - memoizeState(workInProgress, instance.state); - memoizeProps(workInProgress, instance.props); - - // The context might have changed so we need to recalculate it. - if (hasContext) { - invalidateContextProvider(workInProgress, 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, workInProgress, renderExpirationTime) { - pushHostRootContext(workInProgress); - var updateQueue = workInProgress.updateQueue; - if (updateQueue !== null) { - var prevState = workInProgress.memoizedState; - var state = processUpdateQueue( - current, - workInProgress, - updateQueue, - null, - null, - renderExpirationTime - ); - memoizeState(workInProgress, state); - updateQueue = workInProgress.updateQueue; - - var element = void 0; - if (updateQueue !== null && updateQueue.capturedValues !== null) { - // There's an uncaught error. Unmount the whole root. - element = null; - } else if (prevState === state) { - // 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, workInProgress); - } else { - element = state.element; - } - var root = workInProgress.stateNode; - if ( - (current === null || current.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, - element, - renderExpirationTime - ); - } else { - // Otherwise reset hydration state in case we aborted and resumed another - // root. - resetHydrationState(); - reconcileChildren(current, workInProgress, element); - } - memoizeState(workInProgress, state); - return workInProgress.child; - } - resetHydrationState(); - // If there is no update queue, that's a bailout because the root has no props. - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - - function updateHostComponent(current, workInProgress, renderExpirationTime) { - pushHostContext(workInProgress); - - if (current === null) { - tryToClaimNextHydratableInstance(workInProgress); - } - - var type = workInProgress.type; - var memoizedProps = workInProgress.memoizedProps; - var nextProps = workInProgress.pendingProps; - var prevProps = current !== null ? current.memoizedProps : null; - - if (hasLegacyContextChanged()) { - // Normally we can bail out on props equality but if context has changed - // we don't do the bailout and we have to reuse existing props instead. - } else if (memoizedProps === nextProps) { - var isHidden = - workInProgress.mode & AsyncMode && - shouldDeprioritizeSubtree(type, nextProps); - if (isHidden) { - // Before bailing out, make sure we've deprioritized a hidden component. - workInProgress.expirationTime = Never; - } - if (!isHidden || renderExpirationTime !== Never) { - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - // If we're rendering a hidden node at hidden priority, don't bailout. The - // parent is complete, but the children may not be. - } - - 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 && 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, workInProgress); - - // Check the host config to see if the children are offscreen/hidden. - if ( - renderExpirationTime !== Never && - workInProgress.mode & AsyncMode && - shouldDeprioritizeSubtree(type, nextProps) - ) { - // Down-prioritize the children. - workInProgress.expirationTime = Never; - // Bailout and come back to this fiber later. - workInProgress.memoizedProps = nextProps; - return null; - } - - reconcileChildren(current, workInProgress, nextChildren); - memoizeProps(workInProgress, nextProps); - return workInProgress.child; - } - - function updateHostText(current, workInProgress) { - if (current === null) { - tryToClaimNextHydratableInstance(workInProgress); - } - var nextProps = workInProgress.pendingProps; - memoizeProps(workInProgress, nextProps); - // Nothing to do here. This is terminal. We'll do the completion step - // immediately after. - return null; - } - - function mountIndeterminateComponent( - current, - workInProgress, - renderExpirationTime - ) { - invariant( - current === null, - "An indeterminate component should never have mounted. This error is " + - "likely caused by a bug in React. Please file an issue." - ); - var fn = workInProgress.type; - var props = workInProgress.pendingProps; - var unmaskedContext = getUnmaskedContext(workInProgress); - var context = getMaskedContext(workInProgress, unmaskedContext); - - var value = void 0; - - { - if (fn.prototype && typeof fn.prototype.render === "function") { - var componentName = getComponentName(workInProgress) || "Unknown"; - - if (!didWarnAboutBadClass[componentName]) { - warning( - 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; - } - } - ReactCurrentOwner.current = workInProgress; - value = fn(props, context); - } - // React DevTools reads this flag. - workInProgress.effectTag |= PerformedWork; - - if ( - typeof value === "object" && - value !== null && - typeof value.render === "function" && - value.$$typeof === undefined - ) { - var Component = workInProgress.type; - - // Proceed under the assumption that this is a class instance - workInProgress.tag = ClassComponent; - - workInProgress.memoizedState = - value.state !== null && value.state !== undefined ? value.state : null; - - if (typeof Component.getDerivedStateFromProps === "function") { - var partialState = callGetDerivedStateFromProps( - workInProgress, - value, - props, - workInProgress.memoizedState - ); - - if (partialState !== null && partialState !== undefined) { - workInProgress.memoizedState = Object.assign( - {}, - workInProgress.memoizedState, - partialState - ); - } - } - - // 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 = pushLegacyContextProvider(workInProgress); - adoptClassInstance(workInProgress, value); - mountClassInstance(workInProgress, renderExpirationTime); - return finishClassComponent( - current, - workInProgress, - true, - hasContext, - false, - renderExpirationTime - ); - } else { - // Proceed under the assumption that this is a functional component - workInProgress.tag = FunctionalComponent; - { - var _Component = workInProgress.type; - - if (_Component) { - !!_Component.childContextTypes - ? warning( - false, - "%s(...): childContextTypes cannot be defined on a functional component.", - _Component.displayName || _Component.name || "Component" - ) - : void 0; - } - if (workInProgress.ref !== null) { - var info = ""; - var ownerName = ReactDebugCurrentFiber.getCurrentFiberOwnerName(); - 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 (!didWarnAboutStatelessRefs[warningKey]) { - didWarnAboutStatelessRefs[warningKey] = true; - warning( - false, - "Stateless function components cannot be given refs. " + - "Attempts to access this ref will fail.%s%s", - info, - ReactDebugCurrentFiber.getCurrentFiberStackAddendum() - ); - } - } - - if (typeof fn.getDerivedStateFromProps === "function") { - var _componentName = getComponentName(workInProgress) || "Unknown"; - - if ( - !didWarnAboutGetDerivedStateOnFunctionalComponent[_componentName] - ) { - warning( - false, - "%s: Stateless functional components do not support getDerivedStateFromProps.", - _componentName - ); - didWarnAboutGetDerivedStateOnFunctionalComponent[ - _componentName - ] = true; - } - } - } - reconcileChildren(current, workInProgress, value); - memoizeProps(workInProgress, props); - return workInProgress.child; - } - } - - function updateCallComponent(current, workInProgress, renderExpirationTime) { - var nextProps = workInProgress.pendingProps; - if (hasLegacyContextChanged()) { - // Normally we can bail out on props equality but if context has changed - // we don't do the bailout and we have to reuse existing props instead. - } else if (workInProgress.memoizedProps === nextProps) { - nextProps = workInProgress.memoizedProps; - // TODO: When bailing out, we might need to return the stateNode instead - // of the child. To check it for work. - // return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - - var nextChildren = nextProps.children; - - // The following is a fork of reconcileChildrenAtExpirationTime but using - // stateNode to store the child. - if (current === null) { - workInProgress.stateNode = mountChildFibers( - workInProgress, - workInProgress.stateNode, - nextChildren, - renderExpirationTime - ); - } else { - workInProgress.stateNode = reconcileChildFibers( - workInProgress, - current.stateNode, - nextChildren, - renderExpirationTime - ); - } - - memoizeProps(workInProgress, nextProps); - // This doesn't take arbitrary time so we could synchronously just begin - // eagerly do the work of workInProgress.child as an optimization. - return workInProgress.stateNode; - } - - function updatePortalComponent( - current, - workInProgress, - renderExpirationTime - ) { - pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); - var nextChildren = workInProgress.pendingProps; - if (hasLegacyContextChanged()) { - // Normally we can bail out on props equality but if context has changed - // we don't do the bailout and we have to reuse existing props instead. - } else if (workInProgress.memoizedProps === nextChildren) { - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - - if (current === 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 - ); - memoizeProps(workInProgress, nextChildren); - } else { - reconcileChildren(current, workInProgress, nextChildren); - memoizeProps(workInProgress, nextChildren); - } - return workInProgress.child; - } - - 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. - switch (fiber.tag) { - case ContextConsumer: - // Check if the context matches. - var observedBits = fiber.stateNode | 0; - if (fiber.type === context && (observedBits & changedBits) !== 0) { - // Update the expiration time of all the ancestors, including - // the alternates. - var node = fiber; - while (node !== null) { - var alternate = node.alternate; - if ( - node.expirationTime === NoWork || - node.expirationTime > renderExpirationTime - ) { - node.expirationTime = renderExpirationTime; - if ( - alternate !== null && - (alternate.expirationTime === NoWork || - alternate.expirationTime > renderExpirationTime) - ) { - alternate.expirationTime = renderExpirationTime; - } - } else if ( - alternate !== null && - (alternate.expirationTime === NoWork || - alternate.expirationTime > renderExpirationTime) - ) { - alternate.expirationTime = renderExpirationTime; - } else { - // Neither alternate was updated, which means the rest of the - // ancestor path already has sufficient priority. - break; - } - node = node["return"]; - } - // Don't scan deeper than a matching consumer. When we render the - // consumer, we'll continue scanning from that point. This way the - // scanning work is time-sliced. - nextFiber = null; - } else { - // Traverse down. - nextFiber = fiber.child; - } - break; - case ContextProvider: - // Don't scan deeper if this is a matching provider - nextFiber = fiber.type === workInProgress.type ? null : fiber.child; - break; - default: - // Traverse down. - nextFiber = fiber.child; - break; - } - 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) { - nextFiber = sibling; - break; - } - // No more siblings. Traverse up. - nextFiber = nextFiber["return"]; - } - } - fiber = nextFiber; - } - } - - function updateContextProvider( - current, - workInProgress, - renderExpirationTime - ) { - var providerType = workInProgress.type; - var context = providerType._context; - - var newProps = workInProgress.pendingProps; - var oldProps = workInProgress.memoizedProps; - - if (hasLegacyContextChanged()) { - // Normally we can bail out on props equality but if context has changed - // we don't do the bailout and we have to reuse existing props instead. - } else if (oldProps === newProps) { - workInProgress.stateNode = 0; - pushProvider(workInProgress); - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - - var newValue = newProps.value; - workInProgress.memoizedProps = newProps; - - var changedBits = void 0; - if (oldProps === null) { - // Initial render - changedBits = MAX_SIGNED_31_BIT_INT; - } else { - if (oldProps.value === newProps.value) { - // No change. Bailout early if children are the same. - if (oldProps.children === newProps.children) { - workInProgress.stateNode = 0; - pushProvider(workInProgress); - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - changedBits = 0; - } else { - var oldValue = oldProps.value; - // Use Object.is to compare the new context value to the old value. - // Inlined Object.is polyfill. - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is - if ( - (oldValue === newValue && - (oldValue !== 0 || 1 / oldValue === 1 / newValue)) || - (oldValue !== oldValue && newValue !== newValue) // eslint-disable-line no-self-compare - ) { - // No change. Bailout early if children are the same. - if (oldProps.children === newProps.children) { - workInProgress.stateNode = 0; - pushProvider(workInProgress); - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - changedBits = 0; - } else { - changedBits = - typeof context._calculateChangedBits === "function" - ? context._calculateChangedBits(oldValue, newValue) - : MAX_SIGNED_31_BIT_INT; - { - !((changedBits & MAX_SIGNED_31_BIT_INT) === changedBits) - ? warning( - false, - "calculateChangedBits: Expected the return value to be a " + - "31-bit integer. Instead received: %s", - changedBits - ) - : void 0; - } - changedBits |= 0; - - if (changedBits === 0) { - // No change. Bailout early if children are the same. - if (oldProps.children === newProps.children) { - workInProgress.stateNode = 0; - pushProvider(workInProgress); - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - } else { - propagateContextChange( - workInProgress, - context, - changedBits, - renderExpirationTime - ); - } - } - } - } - - workInProgress.stateNode = changedBits; - pushProvider(workInProgress); - - var newChildren = newProps.children; - reconcileChildren(current, workInProgress, newChildren); - return workInProgress.child; - } - - function updateContextConsumer( - current, - workInProgress, - renderExpirationTime - ) { - var context = workInProgress.type; - var newProps = workInProgress.pendingProps; - var oldProps = workInProgress.memoizedProps; - - var newValue = context._currentValue; - var changedBits = context._changedBits; - - if (hasLegacyContextChanged()) { - // Normally we can bail out on props equality but if context has changed - // we don't do the bailout and we have to reuse existing props instead. - } else if (changedBits === 0 && oldProps === newProps) { - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - workInProgress.memoizedProps = newProps; - - var observedBits = newProps.unstable_observedBits; - if (observedBits === undefined || observedBits === null) { - // Subscribe to all changes by default - observedBits = MAX_SIGNED_31_BIT_INT; - } - // Store the observedBits on the fiber's stateNode for quick access. - workInProgress.stateNode = observedBits; - - if ((changedBits & observedBits) !== 0) { - // Context change propagation stops at matching consumers, for time- - // slicing. Continue the propagation here. - propagateContextChange( - workInProgress, - context, - changedBits, - renderExpirationTime - ); - } else if (oldProps === newProps) { - // Skip over a memoized parent with a bitmask bailout even - // if we began working on it because of a deeper matching child. - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - // There is no bailout on `children` equality because we expect people - // to often pass a bound method as a child, but it may reference - // `this.state` or `this.props` (and thus needs to re-render on `setState`). - - var render = newProps.children; - - { - !(typeof render === "function") - ? warning( - 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; - } - - var newChildren = render(newValue); - reconcileChildren(current, workInProgress, newChildren); - return workInProgress.child; - } - - /* - function reuseChildrenEffects(returnFiber : Fiber, firstChild : Fiber) { - let child = firstChild; - do { - // Ensure that the first and last effect of the parent corresponds - // to the children's first and last effect. - if (!returnFiber.firstEffect) { - returnFiber.firstEffect = child.firstEffect; - } - if (child.lastEffect) { - if (returnFiber.lastEffect) { - returnFiber.lastEffect.nextEffect = child.firstEffect; - } - returnFiber.lastEffect = child.lastEffect; - } - } while (child = child.sibling); - } - */ - - function bailoutOnAlreadyFinishedWork(current, workInProgress) { - cancelWorkTimer(workInProgress); - - // TODO: We should ideally be able to bail out early if the children have no - // more work to do. However, since we don't have a separation of this - // Fiber's priority and its children yet - we don't know without doing lots - // of the same work we do anyway. Once we have that separation we can just - // bail out here if the children has no more work at this priority level. - // if (workInProgress.priorityOfChildren <= priorityLevel) { - // // If there are side-effects in these children that have not yet been - // // committed we need to ensure that they get properly transferred up. - // if (current && current.child !== workInProgress.child) { - // reuseChildrenEffects(workInProgress, child); - // } - // return null; - // } - - cloneChildFibers(current, workInProgress); - return workInProgress.child; - } - - function bailoutOnLowPriority(current, workInProgress) { - cancelWorkTimer(workInProgress); - - // TODO: Handle HostComponent tags here as well and call pushHostContext()? - // See PR 8590 discussion for context - switch (workInProgress.tag) { - case HostRoot: - pushHostRootContext(workInProgress); - break; - case ClassComponent: - pushLegacyContextProvider(workInProgress); - break; - case HostPortal: - pushHostContainer( - workInProgress, - workInProgress.stateNode.containerInfo - ); - break; - case ContextProvider: - pushProvider(workInProgress); - break; - } - // TODO: What if this is currently in progress? - // How can that happen? How is this not being cloned? - return null; - } - - // TODO: Delete memoizeProps/State and move to reconcile/bailout instead - function memoizeProps(workInProgress, nextProps) { - workInProgress.memoizedProps = nextProps; - } - - function memoizeState(workInProgress, nextState) { - workInProgress.memoizedState = nextState; - // Don't reset the updateQueue, in case there are pending updates. Resetting - // is handled by processUpdateQueue. - } - - function beginWork(current, workInProgress, renderExpirationTime) { - if ( - workInProgress.expirationTime === NoWork || - workInProgress.expirationTime > renderExpirationTime - ) { - return bailoutOnLowPriority(current, workInProgress); - } - - switch (workInProgress.tag) { - case IndeterminateComponent: - return mountIndeterminateComponent( - current, - workInProgress, - renderExpirationTime - ); - case FunctionalComponent: - return updateFunctionalComponent(current, workInProgress); - case ClassComponent: - return updateClassComponent( - current, - workInProgress, - renderExpirationTime - ); - case HostRoot: - return updateHostRoot(current, workInProgress, renderExpirationTime); - case HostComponent: - return updateHostComponent( - current, - workInProgress, - renderExpirationTime - ); - case HostText: - return updateHostText(current, workInProgress); - case CallHandlerPhase: - // This is a restart. Reset the tag to the initial phase. - workInProgress.tag = CallComponent; - // Intentionally fall through since this is now the same. - case CallComponent: - return updateCallComponent( - current, - workInProgress, - renderExpirationTime - ); - case ReturnComponent: - // A return component is just a placeholder, we can just run through the - // next one immediately. - return null; - case HostPortal: - return updatePortalComponent( - current, - workInProgress, - renderExpirationTime - ); - case ForwardRef: - return updateForwardRef(current, workInProgress); - case Fragment: - return updateFragment(current, workInProgress); - case Mode: - return updateMode(current, workInProgress); - case ContextProvider: - return updateContextProvider( - current, - workInProgress, - renderExpirationTime - ); - case ContextConsumer: - return updateContextConsumer( - current, - workInProgress, - renderExpirationTime - ); - default: - invariant( - false, - "Unknown unit of work tag. This error is likely caused by a bug in " + - "React. Please file an issue." - ); - } - } - - return { - beginWork: beginWork - }; -}; - -var ReactFiberCompleteWork = function( - config, - hostContext, - legacyContext, - newContext, - hydrationContext -) { - var createInstance = config.createInstance, - createTextInstance = config.createTextInstance, - appendInitialChild = config.appendInitialChild, - finalizeInitialChildren = config.finalizeInitialChildren, - prepareUpdate = config.prepareUpdate, - mutation = config.mutation, - persistence = config.persistence; - var getRootHostContainer = hostContext.getRootHostContainer, - popHostContext = hostContext.popHostContext, - getHostContext = hostContext.getHostContext, - popHostContainer = hostContext.popHostContainer; - var popLegacyContextProvider = legacyContext.popContextProvider, - popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject; - var popProvider = newContext.popProvider; - var prepareToHydrateHostInstance = - hydrationContext.prepareToHydrateHostInstance, - prepareToHydrateHostTextInstance = - hydrationContext.prepareToHydrateHostTextInstance, - popHydrationState = hydrationContext.popHydrationState; - - function markUpdate(workInProgress) { - // Tag the fiber with an update effect. This turns a Placement into - // a PlacementAndUpdate. - workInProgress.effectTag |= Update; - } - - function markRef(workInProgress) { - workInProgress.effectTag |= Ref; - } - - function appendAllReturns(returns, workInProgress) { - var node = workInProgress.stateNode; - if (node) { - node["return"] = workInProgress; - } - while (node !== null) { - if ( - node.tag === HostComponent || - node.tag === HostText || - node.tag === HostPortal - ) { - invariant(false, "A call cannot have host component children."); - } else if (node.tag === ReturnComponent) { - returns.push(node.pendingProps.value); - } else if (node.child !== null) { - node.child["return"] = node; - node = node.child; - continue; - } - while (node.sibling === null) { - if (node["return"] === null || node["return"] === workInProgress) { - return; - } - node = node["return"]; - } - node.sibling["return"] = node["return"]; - node = node.sibling; - } - } - - function moveCallToHandlerPhase( - current, - workInProgress, - renderExpirationTime - ) { - var props = workInProgress.memoizedProps; - invariant( - props, - "Should be resolved by now. This error is likely caused by a bug in " + - "React. Please file an issue." - ); - - // First step of the call has completed. Now we need to do the second. - // TODO: It would be nice to have a multi stage call represented by a - // single component, or at least tail call optimize nested ones. Currently - // that requires additional fields that we don't want to add to the fiber. - // So this requires nested handlers. - // Note: This doesn't mutate the alternate node. I don't think it needs to - // since this stage is reset for every pass. - workInProgress.tag = CallHandlerPhase; - - // Build up the returns. - // TODO: Compare this to a generator or opaque helpers like Children. - var returns = []; - appendAllReturns(returns, workInProgress); - var fn = props.handler; - var childProps = props.props; - var nextChildren = fn(childProps, returns); - - var currentFirstChild = current !== null ? current.child : null; - workInProgress.child = reconcileChildFibers( - workInProgress, - currentFirstChild, - nextChildren, - renderExpirationTime - ); - return workInProgress.child; - } - - function appendAllChildren(parent, workInProgress) { - // 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; - } - } - - var updateHostContainer = void 0; - var updateHostComponent = void 0; - var updateHostText = void 0; - if (mutation) { - if (enableMutatingReconciler) { - // Mutation mode - updateHostContainer = function(workInProgress) { - // Noop - }; - updateHostComponent = function( - current, - workInProgress, - updatePayload, - 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 = 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 { - invariant(false, "Mutating reconciler is disabled."); - } - } else if (persistence) { - if (enablePersistentReconciler) { - // Persistent host tree mode - var cloneInstance = persistence.cloneInstance, - createContainerChildSet = persistence.createContainerChildSet, - appendChildToContainerChildSet = - persistence.appendChildToContainerChildSet, - finalizeContainerChildren = persistence.finalizeContainerChildren; - - // An unfortunate fork of appendAllChildren because we have two different parent types. - - var appendAllChildrenToContainer = function( - containerChildSet, - workInProgress - ) { - // 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) { - appendChildToContainerChildSet(containerChildSet, 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) { - 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); - portalOrRoot.pendingChildren = newChildSet; - // Schedule an update on the container to swap out the container. - markUpdate(workInProgress); - finalizeContainerChildren(container, newChildSet); - } - }; - updateHostComponent = function( - current, - workInProgress, - updatePayload, - type, - oldProps, - newProps, - rootContainerInstance, - currentHostContext - ) { - // 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; - var currentInstance = current.stateNode; - if (childrenUnchanged && updatePayload === null) { - // No changes, just reuse the existing instance. - // Note that this might release a previous clone. - workInProgress.stateNode = currentInstance; - } else { - var recyclableInstance = workInProgress.stateNode; - 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); - } - } - }; - updateHostText = 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 { - invariant(false, "Persistent reconciler is disabled."); - } - } else { - if (enableNoopReconciler) { - // No host operations - updateHostContainer = function(workInProgress) { - // Noop - }; - updateHostComponent = function( - current, - workInProgress, - updatePayload, - type, - oldProps, - newProps, - rootContainerInstance, - currentHostContext - ) { - // Noop - }; - updateHostText = function(current, workInProgress, oldText, newText) { - // Noop - }; - } else { - invariant(false, "Noop reconciler is disabled."); - } - } - - function completeWork(current, workInProgress, renderExpirationTime) { - var newProps = workInProgress.pendingProps; - switch (workInProgress.tag) { - case FunctionalComponent: - return null; - case ClassComponent: { - // We are leaving this subtree, so pop context if any. - popLegacyContextProvider(workInProgress); - - // If this component caught an error, schedule an error log effect. - var instance = workInProgress.stateNode; - var updateQueue = workInProgress.updateQueue; - if (updateQueue !== null && updateQueue.capturedValues !== null) { - workInProgress.effectTag &= ~DidCapture; - if (typeof instance.componentDidCatch === "function") { - workInProgress.effectTag |= ErrLog; - } else { - // Normally we clear this in the commit phase, but since we did not - // schedule an effect, we need to reset it here. - updateQueue.capturedValues = null; - } - } - return null; - } - case HostRoot: { - popHostContainer(workInProgress); - popTopLevelLegacyContextObject(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); - - var _updateQueue = workInProgress.updateQueue; - if (_updateQueue !== null && _updateQueue.capturedValues !== null) { - workInProgress.effectTag |= ErrLog; - } - return null; - } - case HostComponent: { - popHostContext(workInProgress); - var rootContainerInstance = getRootHostContainer(); - var type = workInProgress.type; - if (current !== null && workInProgress.stateNode != null) { - // 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 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 - ); - - updateHostComponent( - current, - workInProgress, - updatePayload, - type, - oldProps, - newProps, - rootContainerInstance, - currentHostContext - ); - - if (current.ref !== workInProgress.ref) { - markRef(workInProgress); - } - } else { - if (!newProps) { - invariant( - workInProgress.stateNode !== null, - "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. - return null; - } - - 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 _instance2 = createInstance( - type, - newProps, - rootContainerInstance, - _currentHostContext, - workInProgress - ); - - appendAllChildren(_instance2, workInProgress); - - // 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( - _instance2, - type, - newProps, - rootContainerInstance, - _currentHostContext - ) - ) { - markUpdate(workInProgress); - } - workInProgress.stateNode = _instance2; - } - - if (workInProgress.ref !== null) { - // If there is a ref on a host node we need to schedule a callback - markRef(workInProgress); - } - } - return null; - } - 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(current, workInProgress, oldText, newText); - } else { - if (typeof newText !== "string") { - invariant( - workInProgress.stateNode !== null, - "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. - return null; - } - var _rootContainerInstance = getRootHostContainer(); - var _currentHostContext2 = getHostContext(); - var _wasHydrated = popHydrationState(workInProgress); - if (_wasHydrated) { - if (prepareToHydrateHostTextInstance(workInProgress)) { - markUpdate(workInProgress); - } - } else { - workInProgress.stateNode = createTextInstance( - newText, - _rootContainerInstance, - _currentHostContext2, - workInProgress - ); - } - } - return null; - } - case CallComponent: - return moveCallToHandlerPhase( - current, - workInProgress, - renderExpirationTime - ); - case CallHandlerPhase: - // Reset the tag to now be a first phase call. - workInProgress.tag = CallComponent; - return null; - case ReturnComponent: - // Does nothing. - return null; - case ForwardRef: - return null; - case Fragment: - return null; - case Mode: - return null; - case HostPortal: - popHostContainer(workInProgress); - updateHostContainer(workInProgress); - return null; - case ContextProvider: - // Pop provider fiber - popProvider(workInProgress); - return null; - case ContextConsumer: - return null; - // Error cases - case IndeterminateComponent: - invariant( - false, - "An indeterminate component should have become determinate before " + - "completing. This error is likely caused by a bug in React. Please " + - "file an issue." - ); - // eslint-disable-next-line no-fallthrough - default: - invariant( - false, - "Unknown unit of work tag. This error is likely caused by a bug in " + - "React. Please file an issue." - ); - } - } - - return { - completeWork: completeWork - }; -}; - -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: getStackAddendumByWorkInProgressFiber(source) - }; -} - -var ReactFiberUnwindWork = function( - hostContext, - legacyContext, - newContext, - scheduleWork, - isAlreadyFailedLegacyErrorBoundary -) { - var popHostContainer = hostContext.popHostContainer, - popHostContext = hostContext.popHostContext; - var popLegacyContextProvider = legacyContext.popContextProvider, - popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject; - var popProvider = newContext.popProvider; - - function throwException(returnFiber, sourceFiber, rawValue) { - // The source fiber did not complete. - sourceFiber.effectTag |= Incomplete; - // Its effect list is no longer valid. - sourceFiber.firstEffect = sourceFiber.lastEffect = null; - - var value = createCapturedValue(rawValue, sourceFiber); - - var workInProgress = returnFiber; - do { - switch (workInProgress.tag) { - case HostRoot: { - // Uncaught error - var errorInfo = value; - ensureUpdateQueues(workInProgress); - var updateQueue = workInProgress.updateQueue; - updateQueue.capturedValues = [errorInfo]; - workInProgress.effectTag |= ShouldCapture; - return; - } - case ClassComponent: - // Capture and retry - var ctor = workInProgress.type; - var _instance = workInProgress.stateNode; - if ( - (workInProgress.effectTag & DidCapture) === NoEffect && - ((typeof ctor.getDerivedStateFromCatch === "function" && - enableGetDerivedStateFromCatch) || - (_instance !== null && - typeof _instance.componentDidCatch === "function" && - !isAlreadyFailedLegacyErrorBoundary(_instance))) - ) { - ensureUpdateQueues(workInProgress); - var _updateQueue = workInProgress.updateQueue; - var capturedValues = _updateQueue.capturedValues; - if (capturedValues === null) { - _updateQueue.capturedValues = [value]; - } else { - capturedValues.push(value); - } - workInProgress.effectTag |= ShouldCapture; - return; - } - break; - default: - break; - } - workInProgress = workInProgress["return"]; - } while (workInProgress !== null); - } - - function unwindWork(workInProgress) { - switch (workInProgress.tag) { - case ClassComponent: { - popLegacyContextProvider(workInProgress); - var effectTag = workInProgress.effectTag; - if (effectTag & ShouldCapture) { - workInProgress.effectTag = (effectTag & ~ShouldCapture) | DidCapture; - return workInProgress; - } - return null; - } - case HostRoot: { - popHostContainer(workInProgress); - popTopLevelLegacyContextObject(workInProgress); - var _effectTag = workInProgress.effectTag; - if (_effectTag & ShouldCapture) { - workInProgress.effectTag = (_effectTag & ~ShouldCapture) | DidCapture; - return workInProgress; - } - return null; - } - case HostComponent: { - popHostContext(workInProgress); - return null; - } - case HostPortal: - popHostContainer(workInProgress); - return null; - case ContextProvider: - popProvider(workInProgress); - return null; - default: - return null; - } - } - - function unwindInterruptedWork(interruptedWork) { - switch (interruptedWork.tag) { - case ClassComponent: { - popLegacyContextProvider(interruptedWork); - break; - } - case HostRoot: { - popHostContainer(interruptedWork); - popTopLevelLegacyContextObject(interruptedWork); - break; - } - case HostComponent: { - popHostContext(interruptedWork); - break; - } - case HostPortal: - popHostContainer(interruptedWork); - break; - case ContextProvider: - popProvider(interruptedWork); - break; - default: - break; - } - } - - return { - throwException: throwException, - unwindWork: unwindWork, - unwindInterruptedWork: unwindInterruptedWork - }; -}; - -// This module is forked in different environments. -// By default, return `true` to log errors to the console. -// Forks can return `false` if this isn't desirable. -function showErrorDialog(capturedError) { - return true; -} - -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 suppressLogging = error && error.suppressReactErrorLogging; - if (suppressLogging) { - return; - } - - { - var componentName = capturedError.componentName, - componentStack = capturedError.componentStack, - errorBoundaryName = capturedError.errorBoundaryName, - errorBoundaryFound = capturedError.errorBoundaryFound, - willRetry = capturedError.willRetry; - - 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 invokeGuardedCallback$3 = ReactErrorUtils.invokeGuardedCallback; -var hasCaughtError$1 = ReactErrorUtils.hasCaughtError; -var clearCaughtError$1 = ReactErrorUtils.clearCaughtError; - -var didWarnAboutUndefinedSnapshotBeforeUpdate = null; -{ - didWarnAboutUndefinedSnapshotBeforeUpdate = new Set(); -} - -function logError(boundary, errorInfo) { - var source = errorInfo.source; - var stack = errorInfo.stack; - if (stack === null) { - stack = getStackAddendumByWorkInProgressFiber(source); - } - - var capturedError = { - componentName: source !== null ? getComponentName(source) : 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); - capturedError.errorBoundaryFound = true; - capturedError.willRetry = true; - } - - try { - logCapturedError(capturedError); - } catch (e) { - // Prevent cycle if logCapturedError() throws. - // A cycle may still occur if logCapturedError renders a component that throws. - var suppressLogging = e && e.suppressReactErrorLogging; - if (!suppressLogging) { - console.error(e); - } - } -} - -var ReactFiberCommitWork = function( - config, - captureError, - scheduleWork, - computeExpirationForFiber, - markLegacyErrorBoundaryAsFailed, - recalculateCurrentTime -) { - var getPublicInstance = config.getPublicInstance, - mutation = config.mutation, - persistence = config.persistence; - - var callComponentWillUnmountWithTimer = function(current, instance) { - startPhaseTimer(current, "componentWillUnmount"); - instance.props = current.memoizedProps; - instance.state = current.memoizedState; - instance.componentWillUnmount(); - stopPhaseTimer(); - }; - - // Capture errors so they don't interrupt unmounting. - function safelyCallComponentWillUnmount(current, instance) { - { - invokeGuardedCallback$3( - null, - callComponentWillUnmountWithTimer, - null, - current, - instance - ); - if (hasCaughtError$1()) { - var unmountError = clearCaughtError$1(); - captureError(current, unmountError); - } - } - } - - function safelyDetachRef(current) { - var ref = current.ref; - if (ref !== null) { - if (typeof ref === "function") { - { - invokeGuardedCallback$3(null, ref, null, null); - if (hasCaughtError$1()) { - var refError = clearCaughtError$1(); - captureError(current, refError); - } - } - } else { - ref.current = null; - } - } - } - - function commitBeforeMutationLifeCycles(current, finishedWork) { - switch (finishedWork.tag) { - case ClassComponent: { - if (finishedWork.effectTag & Snapshot) { - if (current !== null) { - var prevProps = current.memoizedProps; - var prevState = current.memoizedState; - startPhaseTimer(finishedWork, "getSnapshotBeforeUpdate"); - var _instance = finishedWork.stateNode; - _instance.props = finishedWork.memoizedProps; - _instance.state = finishedWork.memoizedState; - var snapshot = _instance.getSnapshotBeforeUpdate( - prevProps, - prevState - ); - { - var didWarnSet = didWarnAboutUndefinedSnapshotBeforeUpdate; - if ( - snapshot === undefined && - !didWarnSet.has(finishedWork.type) - ) { - didWarnSet.add(finishedWork.type); - warning( - false, - "%s.getSnapshotBeforeUpdate(): A snapshot value (or null) " + - "must be returned. You have returned undefined.", - getComponentName(finishedWork) - ); - } - } - _instance.__reactInternalSnapshotBeforeUpdate = snapshot; - stopPhaseTimer(); - } - } - return; - } - case HostRoot: - case HostComponent: - case HostText: - case HostPortal: - // Nothing to do for these component types - return; - default: { - invariant( - false, - "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 commitLifeCycles( - finishedRoot, - current, - finishedWork, - currentTime, - committedExpirationTime - ) { - switch (finishedWork.tag) { - case ClassComponent: { - var _instance2 = finishedWork.stateNode; - if (finishedWork.effectTag & Update) { - if (current === null) { - startPhaseTimer(finishedWork, "componentDidMount"); - _instance2.props = finishedWork.memoizedProps; - _instance2.state = finishedWork.memoizedState; - _instance2.componentDidMount(); - stopPhaseTimer(); - } else { - var prevProps = current.memoizedProps; - var prevState = current.memoizedState; - startPhaseTimer(finishedWork, "componentDidUpdate"); - _instance2.props = finishedWork.memoizedProps; - _instance2.state = finishedWork.memoizedState; - _instance2.componentDidUpdate( - prevProps, - prevState, - _instance2.__reactInternalSnapshotBeforeUpdate - ); - stopPhaseTimer(); - } - } - var updateQueue = finishedWork.updateQueue; - if (updateQueue !== null) { - commitCallbacks(updateQueue, _instance2); - } - return; - } - case HostRoot: { - var _updateQueue = finishedWork.updateQueue; - if (_updateQueue !== null) { - var _instance3 = null; - if (finishedWork.child !== null) { - switch (finishedWork.child.tag) { - case HostComponent: - _instance3 = getPublicInstance(finishedWork.child.stateNode); - break; - case ClassComponent: - _instance3 = finishedWork.child.stateNode; - break; - } - } - commitCallbacks(_updateQueue, _instance3); - } - return; - } - case HostComponent: { - var _instance4 = 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 === null && finishedWork.effectTag & Update) { - var type = finishedWork.type; - var props = finishedWork.memoizedProps; - commitMount(_instance4, 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; - } - default: { - invariant( - false, - "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 commitErrorLogging(finishedWork, onUncaughtError) { - switch (finishedWork.tag) { - case ClassComponent: - { - var ctor = finishedWork.type; - var _instance5 = finishedWork.stateNode; - var updateQueue = finishedWork.updateQueue; - invariant( - updateQueue !== null && updateQueue.capturedValues !== null, - "An error logging effect should not have been scheduled if no errors " + - "were captured. This error is likely caused by a bug in React. " + - "Please file an issue." - ); - var capturedErrors = updateQueue.capturedValues; - updateQueue.capturedValues = null; - - if (typeof ctor.getDerivedStateFromCatch !== "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 getDerivedStateFromCatch is - // not defined. - markLegacyErrorBoundaryAsFailed(_instance5); - } - - _instance5.props = finishedWork.memoizedProps; - _instance5.state = finishedWork.memoizedState; - for (var i = 0; i < capturedErrors.length; i++) { - var errorInfo = capturedErrors[i]; - var _error = errorInfo.value; - var stack = errorInfo.stack; - logError(finishedWork, errorInfo); - _instance5.componentDidCatch(_error, { - componentStack: stack !== null ? stack : "" - }); - } - } - break; - case HostRoot: { - var _updateQueue2 = finishedWork.updateQueue; - invariant( - _updateQueue2 !== null && _updateQueue2.capturedValues !== null, - "An error logging effect should not have been scheduled if no errors " + - "were captured. This error is likely caused by a bug in React. " + - "Please file an issue." - ); - var _capturedErrors = _updateQueue2.capturedValues; - _updateQueue2.capturedValues = null; - for (var _i = 0; _i < _capturedErrors.length; _i++) { - var _errorInfo = _capturedErrors[_i]; - logError(finishedWork, _errorInfo); - onUncaughtError(_errorInfo.value); - } - break; - } - default: - invariant( - false, - "This unit of work tag cannot capture errors. This error is " + - "likely caused by a bug in React. Please file an issue." - ); - } - } - - function commitAttachRef(finishedWork) { - var ref = finishedWork.ref; - if (ref !== null) { - var _instance6 = finishedWork.stateNode; - var instanceToUse = void 0; - switch (finishedWork.tag) { - case HostComponent: - instanceToUse = getPublicInstance(_instance6); - break; - default: - instanceToUse = _instance6; - } - if (typeof ref === "function") { - ref(instanceToUse); - } else { - { - if (!ref.hasOwnProperty("current")) { - warning( - false, - "Unexpected ref object provided for %s. " + - "Use either a ref-setter function or React.createRef().%s", - getComponentName(finishedWork), - getStackAddendumByWorkInProgressFiber(finishedWork) - ); - } - } - - ref.current = instanceToUse; - } - } - } - - function commitDetachRef(current) { - var currentRef = current.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) { - if (typeof onCommitUnmount === "function") { - onCommitUnmount(current); - } - - switch (current.tag) { - case ClassComponent: { - safelyDetachRef(current); - var _instance7 = current.stateNode; - if (typeof _instance7.componentWillUnmount === "function") { - safelyCallComponentWillUnmount(current, _instance7); - } - return; - } - case HostComponent: { - safelyDetachRef(current); - return; - } - case CallComponent: { - commitNestedUnmounts(current.stateNode); - return; - } - case HostPortal: { - // TODO: this is recursive. - // We are also not using this parent because - // the portal will get pushed immediately. - if (enableMutatingReconciler && mutation) { - unmountHostComponents(current); - } else if (enablePersistentReconciler && persistence) { - emptyPortalContainer(current); - } - return; - } - } - } - - 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. - (!mutation || 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) { - // 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["return"] = null; - current.child = null; - if (current.alternate) { - current.alternate.child = null; - current.alternate["return"] = null; - } - } - - var emptyPortalContainer = void 0; - - if (!mutation) { - var commitContainer = void 0; - if (persistence) { - var replaceContainerChildren = persistence.replaceContainerChildren, - createContainerChildSet = persistence.createContainerChildSet; - - emptyPortalContainer = function(current) { - var portal = current.stateNode; - var containerInfo = portal.containerInfo; - - var emptyChildSet = createContainerChildSet(containerInfo); - replaceContainerChildren(containerInfo, emptyChildSet); - }; - commitContainer = function(finishedWork) { - switch (finishedWork.tag) { - case ClassComponent: { - return; - } - case HostComponent: { - return; - } - case HostText: { - return; - } - case HostRoot: - case HostPortal: { - var portalOrRoot = finishedWork.stateNode; - var containerInfo = portalOrRoot.containerInfo, - _pendingChildren = portalOrRoot.pendingChildren; - - replaceContainerChildren(containerInfo, _pendingChildren); - return; - } - default: { - invariant( - false, - "This unit of work tag should not have side-effects. This error is " + - "likely caused by a bug in React. Please file an issue." - ); - } - } - }; - } else { - commitContainer = function(finishedWork) { - // Noop - }; - } - if (enablePersistentReconciler || enableNoopReconciler) { - return { - commitResetTextContent: function(finishedWork) {}, - commitPlacement: function(finishedWork) {}, - commitDeletion: function(current) { - // Detach refs and call componentWillUnmount() on the whole subtree. - commitNestedUnmounts(current); - detachFiber(current); - }, - commitWork: function(current, finishedWork) { - commitContainer(finishedWork); - }, - - commitLifeCycles: commitLifeCycles, - commitBeforeMutationLifeCycles: commitBeforeMutationLifeCycles, - commitErrorLogging: commitErrorLogging, - commitAttachRef: commitAttachRef, - commitDetachRef: commitDetachRef - }; - } else if (persistence) { - invariant(false, "Persistent reconciler is disabled."); - } else { - invariant(false, "Noop reconciler is disabled."); - } - } - var commitMount = mutation.commitMount, - commitUpdate = mutation.commitUpdate, - resetTextContent = mutation.resetTextContent, - commitTextUpdate = mutation.commitTextUpdate, - appendChild = mutation.appendChild, - appendChildToContainer = mutation.appendChildToContainer, - insertBefore = mutation.insertBefore, - insertInContainerBefore = mutation.insertInContainerBefore, - removeChild = mutation.removeChild, - removeChildFromContainer = mutation.removeChildFromContainer; - - function getHostParentFiber(fiber) { - var parent = fiber["return"]; - while (parent !== null) { - if (isHostParent(parent)) { - return parent; - } - parent = parent["return"]; - } - invariant( - false, - "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) { - // 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) { - // Recursively insert all host nodes into the parent. - var parentFiber = getHostParentFiber(finishedWork); - 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: - invariant( - false, - "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 recurse down its - // children to find all the terminal nodes. - var node = finishedWork; - while (true) { - if (node.tag === HostComponent || node.tag === HostText) { - if (before) { - if (isContainer) { - insertInContainerBefore(parent, node.stateNode, before); - } else { - insertBefore(parent, node.stateNode, before); - } - } else { - if (isContainer) { - appendChildToContainer(parent, node.stateNode); - } else { - appendChild(parent, node.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) { - // We only have the top Fiber that was inserted but we need recurse down its - var node = current; - - // Each iteration, currentParent is populated with node's host parent if not - // currentParentIsValid. - var currentParentIsValid = false; - var currentParent = void 0; - var currentParentIsContainer = void 0; - - while (true) { - if (!currentParentIsValid) { - var parent = node["return"]; - findParent: while (true) { - invariant( - parent !== null, - "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 (node.tag === HostPortal) { - // 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; - // Visit children because portals might contain host components. - if (node.child !== null) { - 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) { - return; - } - while (node.sibling === null) { - if (node["return"] === null || node["return"] === current) { - 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) { - // Recursively delete all host nodes from the parent. - // Detach refs and call componentWillUnmount() on the whole subtree. - unmountHostComponents(current); - detachFiber(current); - } - - function commitWork(current, finishedWork) { - switch (finishedWork.tag) { - case ClassComponent: { - return; - } - case HostComponent: { - var _instance8 = finishedWork.stateNode; - if (_instance8 != 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 !== null ? current.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( - _instance8, - updatePayload, - type, - oldProps, - newProps, - finishedWork - ); - } - } - return; - } - case HostText: { - invariant( - finishedWork.stateNode !== null, - "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 !== null ? current.memoizedProps : newText; - commitTextUpdate(textInstance, oldText, newText); - return; - } - case HostRoot: { - return; - } - default: { - invariant( - false, - "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 commitResetTextContent(current) { - resetTextContent(current.stateNode); - } - - if (enableMutatingReconciler) { - return { - commitBeforeMutationLifeCycles: commitBeforeMutationLifeCycles, - commitResetTextContent: commitResetTextContent, - commitPlacement: commitPlacement, - commitDeletion: commitDeletion, - commitWork: commitWork, - commitLifeCycles: commitLifeCycles, - commitErrorLogging: commitErrorLogging, - commitAttachRef: commitAttachRef, - commitDetachRef: commitDetachRef - }; - } else { - invariant(false, "Mutating reconciler is disabled."); - } -}; - -var NO_CONTEXT = {}; - -var ReactFiberHostContext = function(config, stack) { - var getChildHostContext = config.getChildHostContext, - getRootHostContext = config.getRootHostContext; - var createCursor = stack.createCursor, - push = stack.push, - pop = stack.pop; - - var contextStackCursor = createCursor(NO_CONTEXT); - var contextFiberStackCursor = createCursor(NO_CONTEXT); - var rootInstanceStackCursor = createCursor(NO_CONTEXT); - - function requiredContext(c) { - invariant( - c !== NO_CONTEXT, - "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, NO_CONTEXT, fiber); - var nextRootContext = getRootHostContext(nextRootInstance); - // Now that we know this function doesn't throw, replace it. - pop(contextStackCursor, fiber); - push(contextStackCursor, nextRootContext, fiber); - } - - function popHostContainer(fiber) { - pop(contextStackCursor, fiber); - pop(contextFiberStackCursor, fiber); - pop(rootInstanceStackCursor, fiber); - } - - function getHostContext() { - var context = requiredContext(contextStackCursor.current); - return context; - } - - function pushHostContext(fiber) { - var rootInstance = requiredContext(rootInstanceStackCursor.current); - var context = requiredContext(contextStackCursor.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, 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, fiber); - pop(contextFiberStackCursor, fiber); - } - - return { - getHostContext: getHostContext, - getRootHostContainer: getRootHostContainer, - popHostContainer: popHostContainer, - popHostContext: popHostContext, - pushHostContainer: pushHostContainer, - pushHostContext: pushHostContext - }; -}; - -var ReactFiberHydrationContext = function(config) { - var shouldSetTextContent = config.shouldSetTextContent, - hydration = config.hydration; - - // If this doesn't have hydration mode. - - if (!hydration) { - return { - enterHydrationState: function() { - return false; - }, - resetHydrationState: function() {}, - tryToClaimNextHydratableInstance: function() {}, - prepareToHydrateHostInstance: function() { - invariant( - false, - "Expected prepareToHydrateHostInstance() to never be called. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - }, - prepareToHydrateHostTextInstance: function() { - invariant( - false, - "Expected prepareToHydrateHostTextInstance() to never be called. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - }, - popHydrationState: function(fiber) { - return false; - } - }; - } - - var canHydrateInstance = hydration.canHydrateInstance, - canHydrateTextInstance = hydration.canHydrateTextInstance, - getNextHydratableSibling = hydration.getNextHydratableSibling, - getFirstHydratableChild = hydration.getFirstHydratableChild, - hydrateInstance = hydration.hydrateInstance, - hydrateTextInstance = hydration.hydrateTextInstance, - didNotMatchHydratedContainerTextInstance = - hydration.didNotMatchHydratedContainerTextInstance, - didNotMatchHydratedTextInstance = hydration.didNotMatchHydratedTextInstance, - didNotHydrateContainerInstance = hydration.didNotHydrateContainerInstance, - didNotHydrateInstance = hydration.didNotHydrateInstance, - didNotFindHydratableContainerInstance = - hydration.didNotFindHydratableContainerInstance, - didNotFindHydratableContainerTextInstance = - hydration.didNotFindHydratableContainerTextInstance, - didNotFindHydratableInstance = hydration.didNotFindHydratableInstance, - didNotFindHydratableTextInstance = - hydration.didNotFindHydratableTextInstance; - - // 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) { - var parentInstance = fiber.stateNode.containerInfo; - nextHydratableInstance = getFirstHydratableChild(parentInstance); - hydrationParentFiber = 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; - } - 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; - } - 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; - } - 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; - } - 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(nextInstance); - 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, nextHydratableInstance); - } - hydrationParentFiber = fiber; - nextHydratableInstance = getFirstHydratableChild(nextInstance); - } - - function prepareToHydrateHostInstance( - fiber, - rootContainerInstance, - hostContext - ) { - 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) { - 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 popToNextHostParent(fiber) { - var parent = fiber["return"]; - while ( - parent !== null && - parent.tag !== HostComponent && - parent.tag !== HostRoot - ) { - parent = parent["return"]; - } - hydrationParentFiber = parent; - } - - function popHydrationState(fiber) { - 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() { - hydrationParentFiber = null; - nextHydratableInstance = null; - isHydrating = false; - } - - return { - enterHydrationState: enterHydrationState, - resetHydrationState: resetHydrationState, - tryToClaimNextHydratableInstance: tryToClaimNextHydratableInstance, - prepareToHydrateHostInstance: prepareToHydrateHostInstance, - prepareToHydrateHostTextInstance: prepareToHydrateHostTextInstance, - popHydrationState: popHydrationState - }; -}; - -// 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; - -var warnedAboutMissingGetChildContext = void 0; - -{ - warnedAboutMissingGetChildContext = {}; -} - -var ReactFiberLegacyContext = function(stack) { - var createCursor = stack.createCursor, - push = stack.push, - pop = stack.pop; - - // A cursor to the current merged context object on the stack. - - var contextStackCursor = createCursor(emptyObject); - // 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 = emptyObject; - - function getUnmaskedContext(workInProgress) { - var hasOwnContext = isContextProvider(workInProgress); - if (hasOwnContext) { - // If the fiber is a context provider itself, when we read its context - // we 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 emptyObject; - } - - // 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(workInProgress) || "Unknown"; - checkPropTypes( - contextTypes, - context, - "context", - name, - ReactDebugCurrentFiber.getCurrentFiberStackAddendum - ); - } - - // 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 isContextConsumer(fiber) { - return fiber.tag === ClassComponent && fiber.type.contextTypes != null; - } - - function isContextProvider(fiber) { - return fiber.tag === ClassComponent && fiber.type.childContextTypes != null; - } - - function popContextProvider(fiber) { - if (!isContextProvider(fiber)) { - return; - } - - pop(didPerformWorkStackCursor, fiber); - pop(contextStackCursor, fiber); - } - - function popTopLevelContextObject(fiber) { - pop(didPerformWorkStackCursor, fiber); - pop(contextStackCursor, fiber); - } - - function pushTopLevelContextObject(fiber, context, didChange) { - invariant( - contextStackCursor.cursor == null, - "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, parentContext) { - var instance = fiber.stateNode; - var childContextTypes = fiber.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(fiber) || "Unknown"; - - if (!warnedAboutMissingGetChildContext[componentName]) { - warnedAboutMissingGetChildContext[componentName] = true; - warning( - 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; - { - ReactDebugCurrentFiber.setCurrentPhase("getChildContext"); - } - startPhaseTimer(fiber, "getChildContext"); - childContext = instance.getChildContext(); - stopPhaseTimer(); - { - ReactDebugCurrentFiber.setCurrentPhase(null); - } - for (var contextKey in childContext) { - invariant( - contextKey in childContextTypes, - '%s.getChildContext(): key "%s" is not defined in childContextTypes.', - getComponentName(fiber) || "Unknown", - contextKey - ); - } - { - var name = getComponentName(fiber) || "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. - ReactDebugCurrentFiber.getCurrentFiberStackAddendum - ); - } - - return Object.assign({}, parentContext, childContext); - } - - function pushContextProvider(workInProgress) { - if (!isContextProvider(workInProgress)) { - return false; - } - - 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) || - emptyObject; - - // 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, didChange) { - var instance = workInProgress.stateNode; - invariant( - instance, - "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, 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 - invariant( - isFiberMounted(fiber) && fiber.tag === ClassComponent, - "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; - while (node.tag !== HostRoot) { - if (isContextProvider(node)) { - return node.stateNode.__reactInternalMemoizedMergedChildContext; - } - var parent = node["return"]; - invariant( - parent, - "Found unexpected detached subtree parent. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - node = parent; - } - return node.stateNode.context; - } - - return { - getUnmaskedContext: getUnmaskedContext, - cacheContext: cacheContext, - getMaskedContext: getMaskedContext, - hasContextChanged: hasContextChanged, - isContextConsumer: isContextConsumer, - isContextProvider: isContextProvider, - popContextProvider: popContextProvider, - popTopLevelContextObject: popTopLevelContextObject, - pushTopLevelContextObject: pushTopLevelContextObject, - processChildContext: processChildContext, - pushContextProvider: pushContextProvider, - invalidateContextProvider: invalidateContextProvider, - findCurrentUnmaskedContext: findCurrentUnmaskedContext - }; -}; - -var ReactFiberNewContext = function(stack) { - var createCursor = stack.createCursor, - push = stack.push, - pop = stack.pop; - - var providerCursor = createCursor(null); - var valueCursor = createCursor(null); - var changedBitsCursor = createCursor(0); - - var rendererSigil = void 0; - { - // Use this to detect multiple renderers using the same context - rendererSigil = {}; - } - - function pushProvider(providerFiber) { - var context = providerFiber.type._context; - - push(changedBitsCursor, context._changedBits, providerFiber); - push(valueCursor, context._currentValue, providerFiber); - push(providerCursor, providerFiber, providerFiber); - - context._currentValue = providerFiber.pendingProps.value; - context._changedBits = providerFiber.stateNode; - - { - !( - context._currentRenderer === null || - context._currentRenderer === rendererSigil - ) - ? warning( - false, - "Detected multiple renderers concurrently rendering the " + - "same context provider. This is currently unsupported." - ) - : void 0; - context._currentRenderer = rendererSigil; - } - } - - function popProvider(providerFiber) { - var changedBits = changedBitsCursor.current; - var currentValue = valueCursor.current; - - pop(providerCursor, providerFiber); - pop(valueCursor, providerFiber); - pop(changedBitsCursor, providerFiber); - - var context = providerFiber.type._context; - context._currentValue = currentValue; - context._changedBits = changedBits; - } - - return { - pushProvider: pushProvider, - popProvider: popProvider - }; -}; - -var ReactFiberStack = function() { - var valueStack = []; - - var fiberStack = void 0; - - { - fiberStack = []; - } - - var index = -1; - - function createCursor(defaultValue) { - return { - current: defaultValue - }; - } - - function isEmpty() { - return index === -1; - } - - function pop(cursor, fiber) { - if (index < 0) { - { - warning(false, "Unexpected pop."); - } - return; - } - - { - if (fiber !== fiberStack[index]) { - warning(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; - } - - function checkThatStackIsEmpty() { - { - if (index !== -1) { - warning( - false, - "Expected an empty stack. Something was not reset properly." - ); - } - } - } - - function resetStackAfterFatalErrorInDev() { - { - index = -1; - valueStack.length = 0; - fiberStack.length = 0; - } - } - - return { - createCursor: createCursor, - isEmpty: isEmpty, - pop: pop, - push: push, - checkThatStackIsEmpty: checkThatStackIsEmpty, - resetStackAfterFatalErrorInDev: resetStackAfterFatalErrorInDev - }; -}; - -var invokeGuardedCallback$2 = ReactErrorUtils.invokeGuardedCallback; -var hasCaughtError = ReactErrorUtils.hasCaughtError; -var clearCaughtError = ReactErrorUtils.clearCaughtError; - -var didWarnAboutStateTransition = void 0; -var didWarnSetStateChildContext = void 0; -var warnAboutUpdateOnUnmounted = void 0; -var warnAboutInvalidUpdates = void 0; - -{ - didWarnAboutStateTransition = false; - didWarnSetStateChildContext = false; - var didWarnStateUpdateForUnmountedComponent = {}; - - warnAboutUpdateOnUnmounted = function(fiber) { - // 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) || "ReactClass"; - if (didWarnStateUpdateForUnmountedComponent[componentName]) { - return; - } - warning( - false, - "Can't call setState (or forceUpdate) 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 the " + - "componentWillUnmount method.%s", - getStackAddendumByWorkInProgressFiber(fiber) - ); - didWarnStateUpdateForUnmountedComponent[componentName] = true; - }; - - warnAboutInvalidUpdates = function(instance) { - switch (ReactDebugCurrentFiber.phase) { - case "getChildContext": - if (didWarnSetStateChildContext) { - return; - } - warning( - false, - "setState(...): Cannot call setState() inside getChildContext()" - ); - didWarnSetStateChildContext = true; - break; - case "render": - if (didWarnAboutStateTransition) { - return; - } - warning( - false, - "Cannot update during an existing state transition (such as within " + - "`render` or another component's constructor). Render methods should " + - "be a pure function of props and state; constructor side-effects are " + - "an anti-pattern, but can be moved to `componentWillMount`." - ); - didWarnAboutStateTransition = true; - break; - } - }; -} - -var ReactFiberScheduler = function(config) { - var stack = ReactFiberStack(); - var hostContext = ReactFiberHostContext(config, stack); - var legacyContext = ReactFiberLegacyContext(stack); - var newContext = ReactFiberNewContext(stack); - var popHostContext = hostContext.popHostContext, - popHostContainer = hostContext.popHostContainer; - var popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject, - popLegacyContextProvider = legacyContext.popContextProvider; - var popProvider = newContext.popProvider; - - var hydrationContext = ReactFiberHydrationContext(config); - - var _ReactFiberBeginWork = ReactFiberBeginWork( - config, - hostContext, - legacyContext, - newContext, - hydrationContext, - scheduleWork, - computeExpirationForFiber - ), - beginWork = _ReactFiberBeginWork.beginWork; - - var _ReactFiberCompleteWo = ReactFiberCompleteWork( - config, - hostContext, - legacyContext, - newContext, - hydrationContext - ), - completeWork = _ReactFiberCompleteWo.completeWork; - - var _ReactFiberUnwindWork = ReactFiberUnwindWork( - hostContext, - legacyContext, - newContext, - scheduleWork, - isAlreadyFailedLegacyErrorBoundary - ), - throwException = _ReactFiberUnwindWork.throwException, - unwindWork = _ReactFiberUnwindWork.unwindWork, - unwindInterruptedWork = _ReactFiberUnwindWork.unwindInterruptedWork; - - var _ReactFiberCommitWork = ReactFiberCommitWork( - config, - onCommitPhaseError, - scheduleWork, - computeExpirationForFiber, - markLegacyErrorBoundaryAsFailed, - recalculateCurrentTime - ), - commitBeforeMutationLifeCycles = - _ReactFiberCommitWork.commitBeforeMutationLifeCycles, - commitResetTextContent = _ReactFiberCommitWork.commitResetTextContent, - commitPlacement = _ReactFiberCommitWork.commitPlacement, - commitDeletion = _ReactFiberCommitWork.commitDeletion, - commitWork = _ReactFiberCommitWork.commitWork, - commitLifeCycles = _ReactFiberCommitWork.commitLifeCycles, - commitErrorLogging = _ReactFiberCommitWork.commitErrorLogging, - commitAttachRef = _ReactFiberCommitWork.commitAttachRef, - commitDetachRef = _ReactFiberCommitWork.commitDetachRef; - - var now = config.now, - scheduleDeferredCallback = config.scheduleDeferredCallback, - cancelDeferredCallback = config.cancelDeferredCallback, - prepareForCommit = config.prepareForCommit, - resetAfterCommit = config.resetAfterCommit; - - // Represents the current time in ms. - - var originalStartTimeMs = now(); - var mostRecentCurrentTime = msToExpirationTime(0); - var mostRecentCurrentTimeMs = originalStartTimeMs; - - // Used to ensure computeUniqueAsyncExpiration is monotonically increases. - var lastUniqueAsyncExpiration = 0; - - // Represents the expiration time that incoming updates should use. (If this - // is NoWork, use the default strategy: async updates in async mode, sync - // updates in sync mode.) - var expirationContext = NoWork; - - var isWorking = false; - - // The next work in progress fiber that we're currently working on. - var nextUnitOfWork = null; - var nextRoot = null; - // The time at which we're currently rendering work. - var nextRenderExpirationTime = NoWork; - - // The next fiber with an effect that we're currently committing. - var nextEffect = null; - - var isCommitting = false; - - var isRootReadyForCommit = false; - - var legacyErrorBoundariesThatAlreadyFailed = null; - - // Used for performance tracking. - var interruptedBy = null; - - var stashedWorkInProgressProperties = void 0; - var replayUnitOfWork = void 0; - var isReplayingFailedUnitOfWork = void 0; - var originalReplayError = void 0; - var rethrowOriginalError = void 0; - if (true && replayFailedUnitOfWorkWithInvokeGuardedCallback) { - stashedWorkInProgressProperties = null; - isReplayingFailedUnitOfWork = false; - originalReplayError = null; - replayUnitOfWork = function(failedUnitOfWork, error, isAsync) { - // Restore the original state of the work-in-progress - assignFiberPropertiesInDEV( - failedUnitOfWork, - stashedWorkInProgressProperties - ); - switch (failedUnitOfWork.tag) { - case HostRoot: - popHostContainer(failedUnitOfWork); - popTopLevelLegacyContextObject(failedUnitOfWork); - break; - case HostComponent: - popHostContext(failedUnitOfWork); - break; - case ClassComponent: - popLegacyContextProvider(failedUnitOfWork); - break; - case HostPortal: - popHostContainer(failedUnitOfWork); - break; - case ContextProvider: - popProvider(failedUnitOfWork); - break; - } - // Replay the begin phase. - isReplayingFailedUnitOfWork = true; - originalReplayError = error; - invokeGuardedCallback$2(null, workLoop, null, isAsync); - isReplayingFailedUnitOfWork = false; - originalReplayError = null; - if (hasCaughtError()) { - clearCaughtError(); - } else { - // If the begin phase did not fail the second time, set this pointer - // back to the original value. - nextUnitOfWork = failedUnitOfWork; - } - }; - rethrowOriginalError = function() { - throw originalReplayError; - }; - } - - function resetStack() { - if (nextUnitOfWork !== null) { - var interruptedWork = nextUnitOfWork["return"]; - while (interruptedWork !== null) { - unwindInterruptedWork(interruptedWork); - interruptedWork = interruptedWork["return"]; - } - } - - { - ReactStrictModeWarnings.discardPendingWarnings(); - stack.checkThatStackIsEmpty(); - } - - nextRoot = null; - nextRenderExpirationTime = NoWork; - nextUnitOfWork = null; - - isRootReadyForCommit = false; - } - - function commitAllHostEffects() { - while (nextEffect !== null) { - { - ReactDebugCurrentFiber.setCurrentFiber(nextEffect); - } - recordEffect(); - - var effectTag = nextEffect.effectTag; - - if (effectTag & ContentReset) { - commitResetTextContent(nextEffect); - } - - if (effectTag & Ref) { - var current = nextEffect.alternate; - if (current !== null) { - commitDetachRef(current); - } - } - - // 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; - } - } - nextEffect = nextEffect.nextEffect; - } - - { - ReactDebugCurrentFiber.resetCurrentFiber(); - } - } - - function commitBeforeMutationLifecycles() { - while (nextEffect !== null) { - var effectTag = nextEffect.effectTag; - - if (effectTag & Snapshot) { - recordEffect(); - var current = nextEffect.alternate; - commitBeforeMutationLifeCycles(current, nextEffect); - } - - // Don't cleanup effects yet; - // This will be done by commitAllLifeCycles() - nextEffect = nextEffect.nextEffect; - } - } - - function commitAllLifeCycles( - finishedRoot, - currentTime, - committedExpirationTime - ) { - { - ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings(); - - if (warnAboutDeprecatedLifecycles) { - ReactStrictModeWarnings.flushPendingDeprecationWarnings(); - } - } - while (nextEffect !== null) { - var effectTag = nextEffect.effectTag; - - if (effectTag & (Update | Callback)) { - recordEffect(); - var current = nextEffect.alternate; - commitLifeCycles( - finishedRoot, - current, - nextEffect, - currentTime, - committedExpirationTime - ); - } - - if (effectTag & ErrLog) { - commitErrorLogging(nextEffect, onUncaughtError); - } - - if (effectTag & Ref) { - recordEffect(); - commitAttachRef(nextEffect); - } - - var next = nextEffect.nextEffect; - // Ensure that we clean these up so that we don't accidentally keep them. - // I'm not actually sure this matters because we can't reset firstEffect - // and lastEffect since they're on every node, not just the effectful - // ones. So we have to clean everything as we reuse nodes anyway. - nextEffect.nextEffect = null; - // Ensure that we reset the effectTag here so that we can rely on effect - // tags to reason about the current life-cycle. - nextEffect = next; - } - } - - function isAlreadyFailedLegacyErrorBoundary(instance) { - return ( - legacyErrorBoundariesThatAlreadyFailed !== null && - legacyErrorBoundariesThatAlreadyFailed.has(instance) - ); - } - - function markLegacyErrorBoundaryAsFailed(instance) { - if (legacyErrorBoundariesThatAlreadyFailed === null) { - legacyErrorBoundariesThatAlreadyFailed = new Set([instance]); - } else { - legacyErrorBoundariesThatAlreadyFailed.add(instance); - } - } - - function commitRoot(finishedWork) { - isWorking = true; - isCommitting = true; - startCommitTimer(); - - var root = finishedWork.stateNode; - invariant( - root.current !== finishedWork, - "Cannot commit the same tree as before. This is probably a bug " + - "related to the return field. This error is likely caused by a bug " + - "in React. Please file an issue." - ); - var committedExpirationTime = root.pendingCommitExpirationTime; - invariant( - committedExpirationTime !== NoWork, - "Cannot commit an incomplete root. This error is likely caused by a " + - "bug in React. Please file an issue." - ); - root.pendingCommitExpirationTime = NoWork; - - var currentTime = recalculateCurrentTime(); - - // Reset this to null before calling lifecycles - ReactCurrentOwner.current = null; - - 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; - } - - prepareForCommit(root.containerInfo); - - // Invoke instances of getSnapshotBeforeUpdate before mutation. - nextEffect = firstEffect; - startCommitSnapshotEffectsTimer(); - while (nextEffect !== null) { - var didError = false; - var error = void 0; - { - invokeGuardedCallback$2(null, commitBeforeMutationLifecycles, null); - if (hasCaughtError()) { - didError = true; - error = clearCaughtError(); - } - } - if (didError) { - invariant( - nextEffect !== null, - "Should have next effect. This error is likely caused by a bug " + - "in React. Please file an issue." - ); - onCommitPhaseError(nextEffect, error); - // Clean-up - if (nextEffect !== null) { - nextEffect = nextEffect.nextEffect; - } - } - } - stopCommitSnapshotEffectsTimer(); - - // Commit all the side-effects within a tree. We'll do this in two passes. - // The first pass performs all the host insertions, updates, deletions and - // ref unmounts. - nextEffect = firstEffect; - startCommitHostEffectsTimer(); - while (nextEffect !== null) { - var _didError = false; - var _error = void 0; - { - invokeGuardedCallback$2(null, commitAllHostEffects, null); - if (hasCaughtError()) { - _didError = true; - _error = clearCaughtError(); - } - } - if (_didError) { - invariant( - nextEffect !== null, - "Should have next effect. This error is likely caused by a bug " + - "in React. Please file an issue." - ); - onCommitPhaseError(nextEffect, _error); - // Clean-up - if (nextEffect !== null) { - nextEffect = nextEffect.nextEffect; - } - } - } - stopCommitHostEffectsTimer(); - - resetAfterCommit(root.containerInfo); - - // The work-in-progress tree is now the current tree. This must come after - // the first pass of the commit phase, so that the previous tree is still - // current during componentWillUnmount, but before the second pass, so that - // the finished work is current during componentDidMount/Update. - root.current = finishedWork; - - // In the second pass we'll perform all life-cycles and ref callbacks. - // Life-cycles happen as a separate pass so that all placements, updates, - // and deletions in the entire tree have already been invoked. - // This pass also triggers any renderer-specific initial effects. - nextEffect = firstEffect; - startCommitLifeCyclesTimer(); - while (nextEffect !== null) { - var _didError2 = false; - var _error2 = void 0; - { - invokeGuardedCallback$2( - null, - commitAllLifeCycles, - null, - root, - currentTime, - committedExpirationTime - ); - if (hasCaughtError()) { - _didError2 = true; - _error2 = clearCaughtError(); - } - } - if (_didError2) { - invariant( - nextEffect !== null, - "Should have next effect. This error is likely caused by a bug " + - "in React. Please file an issue." - ); - onCommitPhaseError(nextEffect, _error2); - if (nextEffect !== null) { - nextEffect = nextEffect.nextEffect; - } - } - } - - isCommitting = false; - isWorking = false; - stopCommitLifeCyclesTimer(); - stopCommitTimer(); - if (typeof onCommitRoot === "function") { - onCommitRoot(finishedWork.stateNode); - } - if (true && ReactFiberInstrumentation_1.debugTool) { - ReactFiberInstrumentation_1.debugTool.onCommitWork(finishedWork); - } - - var remainingTime = root.current.expirationTime; - if (remainingTime === NoWork) { - // If there's no remaining work, we can clear the set of already failed - // error boundaries. - legacyErrorBoundariesThatAlreadyFailed = null; - } - return remainingTime; - } - - function resetExpirationTime(workInProgress, renderTime) { - if (renderTime !== Never && workInProgress.expirationTime === Never) { - // The children of this component are hidden. Don't bubble their - // expiration times. - return; - } - - // Check for pending updates. - var newExpirationTime = getUpdateExpirationTime(workInProgress); - - // TODO: Calls need to visit stateNode - - // Bubble up the earliest expiration time. - var child = workInProgress.child; - while (child !== null) { - if ( - child.expirationTime !== NoWork && - (newExpirationTime === NoWork || - newExpirationTime > child.expirationTime) - ) { - newExpirationTime = child.expirationTime; - } - child = child.sibling; - } - workInProgress.expirationTime = newExpirationTime; - } - - function completeUnitOfWork(workInProgress) { - // 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. - while (true) { - // 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 = workInProgress.alternate; - { - ReactDebugCurrentFiber.setCurrentFiber(workInProgress); - } - - var returnFiber = workInProgress["return"]; - var siblingFiber = workInProgress.sibling; - - if ((workInProgress.effectTag & Incomplete) === NoEffect) { - // This fiber completed. - var next = completeWork( - current, - workInProgress, - nextRenderExpirationTime - ); - stopWorkTimer(workInProgress); - resetExpirationTime(workInProgress, nextRenderExpirationTime); - { - ReactDebugCurrentFiber.resetCurrentFiber(); - } - - if (next !== null) { - stopWorkTimer(workInProgress); - if (true && ReactFiberInstrumentation_1.debugTool) { - ReactFiberInstrumentation_1.debugTool.onCompleteWork( - workInProgress - ); - } - // If completing this work spawned new work, do that next. We'll come - // back here again. - 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; - } - } - - if (true && ReactFiberInstrumentation_1.debugTool) { - ReactFiberInstrumentation_1.debugTool.onCompleteWork(workInProgress); - } - - if (siblingFiber !== null) { - // If there is more work to do in this returnFiber, do that next. - return siblingFiber; - } else if (returnFiber !== null) { - // If there's no more work in this returnFiber. Complete the returnFiber. - workInProgress = returnFiber; - continue; - } else { - // We've reached the root. - isRootReadyForCommit = true; - return null; - } - } 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); - // Because this fiber did not complete, don't reset its expiration time. - if (workInProgress.effectTag & DidCapture) { - // Restarting an error boundary - stopFailedWorkTimer(workInProgress); - } else { - stopWorkTimer(workInProgress); - } - - { - ReactDebugCurrentFiber.resetCurrentFiber(); - } - - if (_next !== null) { - stopWorkTimer(workInProgress); - if (true && ReactFiberInstrumentation_1.debugTool) { - ReactFiberInstrumentation_1.debugTool.onCompleteWork( - workInProgress - ); - } - // 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. - _next.effectTag &= HostEffectMask; - return _next; - } - - if (returnFiber !== null) { - // Mark the parent fiber as incomplete and clear its effect list. - returnFiber.firstEffect = returnFiber.lastEffect = null; - returnFiber.effectTag |= Incomplete; - } - - if (true && ReactFiberInstrumentation_1.debugTool) { - ReactFiberInstrumentation_1.debugTool.onCompleteWork(workInProgress); - } - - if (siblingFiber !== null) { - // If there is more work to do in this returnFiber, do that next. - return siblingFiber; - } else if (returnFiber !== null) { - // If there's no more work in this returnFiber. Complete the returnFiber. - workInProgress = returnFiber; - continue; - } else { - return null; - } - } - } - - // Without this explicit null return Flow complains of invalid return type - // TODO Remove the above while(true) loop - // eslint-disable-next-line no-unreachable - return null; - } - - function performUnitOfWork(workInProgress) { - // 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 = workInProgress.alternate; - - // See if beginning this work spawns more work. - startWorkTimer(workInProgress); - { - ReactDebugCurrentFiber.setCurrentFiber(workInProgress); - } - - if (true && replayFailedUnitOfWorkWithInvokeGuardedCallback) { - stashedWorkInProgressProperties = assignFiberPropertiesInDEV( - stashedWorkInProgressProperties, - workInProgress - ); - } - var next = beginWork(current, workInProgress, nextRenderExpirationTime); - { - ReactDebugCurrentFiber.resetCurrentFiber(); - if (isReplayingFailedUnitOfWork) { - // Currently replaying a failed unit of work. This should be unreachable, - // because the render phase is meant to be idempotent, and it should - // have thrown again. Since it didn't, rethrow the original error, so - // React's internal stack is not misaligned. - rethrowOriginalError(); - } - } - if (true && ReactFiberInstrumentation_1.debugTool) { - ReactFiberInstrumentation_1.debugTool.onBeginWork(workInProgress); - } - - if (next === null) { - // If this doesn't spawn new work, complete the current work. - next = completeUnitOfWork(workInProgress); - } - - ReactCurrentOwner.current = null; - - return next; - } - - function workLoop(isAsync) { - if (!isAsync) { - // Flush all expired work. - while (nextUnitOfWork !== null) { - nextUnitOfWork = performUnitOfWork(nextUnitOfWork); - } - } else { - // Flush asynchronous work until the deadline runs out of time. - while (nextUnitOfWork !== null && !shouldYield()) { - nextUnitOfWork = performUnitOfWork(nextUnitOfWork); - } - } - } - - function renderRoot(root, expirationTime, isAsync) { - invariant( - !isWorking, - "renderRoot was called recursively. This error is likely caused " + - "by a bug in React. Please file an issue." - ); - isWorking = true; - - // Check if we're starting from a fresh stack, or if we're resuming from - // previously yielded work. - if ( - expirationTime !== nextRenderExpirationTime || - root !== nextRoot || - nextUnitOfWork === null - ) { - // Reset the stack and start working from the root. - resetStack(); - nextRoot = root; - nextRenderExpirationTime = expirationTime; - nextUnitOfWork = createWorkInProgress( - nextRoot.current, - null, - nextRenderExpirationTime - ); - root.pendingCommitExpirationTime = NoWork; - } - - var didFatal = false; - - startWorkLoopTimer(nextUnitOfWork); - - do { - try { - workLoop(isAsync); - } catch (thrownValue) { - if (nextUnitOfWork === null) { - // This is a fatal error. - didFatal = true; - onUncaughtError(thrownValue); - break; - } - - if (true && replayFailedUnitOfWorkWithInvokeGuardedCallback) { - var failedUnitOfWork = nextUnitOfWork; - replayUnitOfWork(failedUnitOfWork, thrownValue, isAsync); - } - - var sourceFiber = nextUnitOfWork; - var returnFiber = sourceFiber["return"]; - if (returnFiber === null) { - // This is the root. The root could capture its own errors. However, - // we don't know if it errors before or after we pushed the host - // context. This information is needed to avoid a stack mismatch. - // Because we're not sure, treat this as a fatal error. We could track - // which phase it fails in, but doesn't seem worth it. At least - // for now. - didFatal = true; - onUncaughtError(thrownValue); - break; - } - throwException(returnFiber, sourceFiber, thrownValue); - nextUnitOfWork = completeUnitOfWork(sourceFiber); - } - break; - } while (true); - - // We're done performing work. Time to clean up. - var didCompleteRoot = false; - isWorking = false; - - // Yield back to main thread. - if (didFatal) { - stopWorkLoopTimer(interruptedBy, didCompleteRoot); - interruptedBy = null; - // There was a fatal error. - { - stack.resetStackAfterFatalErrorInDev(); - } - return null; - } else if (nextUnitOfWork === null) { - // We reached the root. - if (isRootReadyForCommit) { - didCompleteRoot = true; - stopWorkLoopTimer(interruptedBy, didCompleteRoot); - interruptedBy = null; - // The root successfully completed. It's ready for commit. - root.pendingCommitExpirationTime = expirationTime; - var finishedWork = root.current.alternate; - return finishedWork; - } else { - // The root did not complete. - stopWorkLoopTimer(interruptedBy, didCompleteRoot); - interruptedBy = null; - invariant( - false, - "Expired work should have completed. This error is likely caused " + - "by a bug in React. Please file an issue." - ); - } - } else { - stopWorkLoopTimer(interruptedBy, didCompleteRoot); - interruptedBy = null; - // There's more work to do, but we ran out of time. Yield back to - // the renderer. - return null; - } - } - - function scheduleCapture(sourceFiber, boundaryFiber, value, expirationTime) { - // TODO: We only support dispatching errors. - var capturedValue = createCapturedValue(value, sourceFiber); - var update = { - expirationTime: expirationTime, - partialState: null, - callback: null, - isReplace: false, - isForced: false, - capturedValue: capturedValue, - next: null - }; - insertUpdateIntoFiber(boundaryFiber, update); - scheduleWork(boundaryFiber, expirationTime); - } - - function dispatch(sourceFiber, value, expirationTime) { - invariant( - !isWorking || isCommitting, - "dispatch: Cannot dispatch during the render phase." - ); - - // TODO: Handle arrays - - var fiber = sourceFiber["return"]; - while (fiber !== null) { - switch (fiber.tag) { - case ClassComponent: - var ctor = fiber.type; - var instance = fiber.stateNode; - if ( - typeof ctor.getDerivedStateFromCatch === "function" || - (typeof instance.componentDidCatch === "function" && - !isAlreadyFailedLegacyErrorBoundary(instance)) - ) { - scheduleCapture(sourceFiber, fiber, value, expirationTime); - return; - } - break; - // TODO: Handle async boundaries - case HostRoot: - scheduleCapture(sourceFiber, fiber, value, expirationTime); - return; - } - fiber = fiber["return"]; - } - - if (sourceFiber.tag === HostRoot) { - // Error was thrown at the root. There is no parent, so the root - // itself should capture it. - scheduleCapture(sourceFiber, sourceFiber, value, expirationTime); - } - } - - function onCommitPhaseError(fiber, error) { - return dispatch(fiber, error, Sync); - } - - function computeAsyncExpiration(currentTime) { - // Given the current clock time, returns an expiration time. We use rounding - // to batch like updates together. - // Should complete within ~1000ms. 1200ms max. - var expirationMs = 5000; - var bucketSizeMs = 250; - return computeExpirationBucket(currentTime, expirationMs, bucketSizeMs); - } - - function computeInteractiveExpiration(currentTime) { - var expirationMs = void 0; - // 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. - { - // Should complete within ~500ms. 600ms max. - expirationMs = 500; - } - var bucketSizeMs = 100; - return computeExpirationBucket(currentTime, expirationMs, bucketSizeMs); - } - - // Creates a unique async expiration time. - function computeUniqueAsyncExpiration() { - var currentTime = recalculateCurrentTime(); - var result = computeAsyncExpiration(currentTime); - if (result <= lastUniqueAsyncExpiration) { - // Since we assume the current time monotonically increases, we only hit - // this branch when computeUniqueAsyncExpiration is fired multiple times - // within a 200ms window (or whatever the async bucket size is). - result = lastUniqueAsyncExpiration + 1; - } - lastUniqueAsyncExpiration = result; - return lastUniqueAsyncExpiration; - } - - function computeExpirationForFiber(fiber) { - var expirationTime = void 0; - if (expirationContext !== NoWork) { - // An explicit expiration context was set; - expirationTime = expirationContext; - } else if (isWorking) { - if (isCommitting) { - // Updates that occur during the commit phase should have sync priority - // by default. - expirationTime = Sync; - } else { - // Updates during the render phase should expire at the same time as - // the work that is being rendered. - expirationTime = nextRenderExpirationTime; - } - } else { - // No explicit expiration context was set, and we're not currently - // performing work. Calculate a new expiration time. - if (fiber.mode & AsyncMode) { - if (isBatchingInteractiveUpdates) { - // This is an interactive update - var currentTime = recalculateCurrentTime(); - expirationTime = computeInteractiveExpiration(currentTime); - } else { - // This is an async update - var _currentTime = recalculateCurrentTime(); - expirationTime = computeAsyncExpiration(_currentTime); - } - } else { - // This is a sync update - expirationTime = Sync; - } - } - if (isBatchingInteractiveUpdates) { - // This is an interactive update. Keep track of the lowest pending - // interactive expiration time. This allows us to synchronously flush - // all interactive updates when needed. - if ( - lowestPendingInteractiveExpirationTime === NoWork || - expirationTime > lowestPendingInteractiveExpirationTime - ) { - lowestPendingInteractiveExpirationTime = expirationTime; - } - } - return expirationTime; - } - - function scheduleWork(fiber, expirationTime) { - return scheduleWorkImpl(fiber, expirationTime, false); - } - - function scheduleWorkImpl(fiber, expirationTime, isErrorRecovery) { - recordScheduleUpdate(); - - { - if (!isErrorRecovery && fiber.tag === ClassComponent) { - var instance = fiber.stateNode; - warnAboutInvalidUpdates(instance); - } - } - - var node = fiber; - while (node !== null) { - // Walk the parent path to the root and update each node's - // expiration time. - if ( - node.expirationTime === NoWork || - node.expirationTime > expirationTime - ) { - node.expirationTime = expirationTime; - } - if (node.alternate !== null) { - if ( - node.alternate.expirationTime === NoWork || - node.alternate.expirationTime > expirationTime - ) { - node.alternate.expirationTime = expirationTime; - } - } - if (node["return"] === null) { - if (node.tag === HostRoot) { - var root = node.stateNode; - if ( - !isWorking && - nextRenderExpirationTime !== NoWork && - expirationTime < nextRenderExpirationTime - ) { - // This is an interruption. (Used for performance tracking.) - interruptedBy = fiber; - resetStack(); - } - if ( - // If we're in the render phase, we don't need to schedule this root - // for an update, because we'll do it before we exit... - !isWorking || - isCommitting || - // ...unless this is a different root than the one we're rendering. - nextRoot !== root - ) { - // Add this root to the root schedule. - requestWork(root, expirationTime); - } - if (nestedUpdateCount > NESTED_UPDATE_LIMIT) { - invariant( - false, - "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." - ); - } - } else { - { - if (!isErrorRecovery && fiber.tag === ClassComponent) { - warnAboutUpdateOnUnmounted(fiber); - } - } - return; - } - } - node = node["return"]; - } - } - - function recalculateCurrentTime() { - // Subtract initial time so it fits inside 32bits - mostRecentCurrentTimeMs = now() - originalStartTimeMs; - mostRecentCurrentTime = msToExpirationTime(mostRecentCurrentTimeMs); - return mostRecentCurrentTime; - } - - function deferredUpdates(fn) { - var previousExpirationContext = expirationContext; - var currentTime = recalculateCurrentTime(); - expirationContext = computeAsyncExpiration(currentTime); - try { - return fn(); - } finally { - expirationContext = previousExpirationContext; - } - } - function syncUpdates(fn, a, b, c, d) { - var previousExpirationContext = expirationContext; - expirationContext = Sync; - try { - return fn(a, b, c, d); - } finally { - expirationContext = previousExpirationContext; - } - } - - // TODO: Everything below this is written as if it has been lifted to the - // renderers. I'll do this in a follow-up. - - // Linked-list of roots - var firstScheduledRoot = null; - var lastScheduledRoot = null; - - var callbackExpirationTime = NoWork; - var callbackID = -1; - var isRendering = false; - var nextFlushedRoot = null; - var nextFlushedExpirationTime = NoWork; - var lowestPendingInteractiveExpirationTime = NoWork; - var deadlineDidExpire = false; - var hasUnhandledError = false; - var unhandledError = null; - var deadline = null; - - var isBatchingUpdates = false; - var isUnbatchingUpdates = false; - var isBatchingInteractiveUpdates = false; - - var completedBatches = null; - - // Use these to prevent an infinite loop of nested updates - var NESTED_UPDATE_LIMIT = 1000; - var nestedUpdateCount = 0; - - var timeHeuristicForUnitOfWork = 1; - - function scheduleCallbackWithExpiration(expirationTime) { - if (callbackExpirationTime !== NoWork) { - // A callback is already scheduled. Check its expiration time (timeout). - if (expirationTime > callbackExpirationTime) { - // Existing callback has sufficient timeout. Exit. - return; - } else { - // Existing callback has insufficient timeout. Cancel and schedule a - // new one. - cancelDeferredCallback(callbackID); - } - // The request callback timer is already running. Don't start a new one. - } else { - startRequestCallbackTimer(); - } - - // Compute a timeout for the given expiration time. - var currentMs = now() - originalStartTimeMs; - var expirationMs = expirationTimeToMs(expirationTime); - var timeout = expirationMs - currentMs; - - callbackExpirationTime = expirationTime; - callbackID = scheduleDeferredCallback(performAsyncWork, { - timeout: timeout - }); - } - - // requestWork is called by the scheduler whenever a root receives an update. - // It's up to the renderer to call renderRoot at some point in the future. - function requestWork(root, expirationTime) { - addRootToSchedule(root, expirationTime); - - if (isRendering) { - // Prevent reentrancy. Remaining work will be scheduled at the end of - // the currently rendering batch. - return; - } - - if (isBatchingUpdates) { - // Flush work at the end of the batch. - if (isUnbatchingUpdates) { - // ...unless we're inside unbatchedUpdates, in which case we should - // flush it now. - nextFlushedRoot = root; - nextFlushedExpirationTime = Sync; - performWorkOnRoot(root, Sync, false); - } - return; - } - - // TODO: Get rid of Sync and use current time? - if (expirationTime === Sync) { - performSyncWork(); - } else { - scheduleCallbackWithExpiration(expirationTime); - } - } - - function addRootToSchedule(root, expirationTime) { - // Add the root to the schedule. - // Check if this root is already part of the schedule. - if (root.nextScheduledRoot === null) { - // This root is not already scheduled. Add it. - root.remainingExpirationTime = expirationTime; - if (lastScheduledRoot === null) { - firstScheduledRoot = lastScheduledRoot = root; - root.nextScheduledRoot = root; - } else { - lastScheduledRoot.nextScheduledRoot = root; - lastScheduledRoot = root; - lastScheduledRoot.nextScheduledRoot = firstScheduledRoot; - } - } else { - // This root is already scheduled, but its priority may have increased. - var remainingExpirationTime = root.remainingExpirationTime; - if ( - remainingExpirationTime === NoWork || - expirationTime < remainingExpirationTime - ) { - // Update the priority. - root.remainingExpirationTime = expirationTime; - } - } - } - - function findHighestPriorityRoot() { - var highestPriorityWork = NoWork; - var highestPriorityRoot = null; - if (lastScheduledRoot !== null) { - var previousScheduledRoot = lastScheduledRoot; - var root = firstScheduledRoot; - while (root !== null) { - var remainingExpirationTime = root.remainingExpirationTime; - if (remainingExpirationTime === NoWork) { - // This root no longer has work. Remove it from the scheduler. - - // TODO: This check is redudant, but Flow is confused by the branch - // below where we set lastScheduledRoot to null, even though we break - // from the loop right after. - invariant( - previousScheduledRoot !== null && lastScheduledRoot !== null, - "Should have a previous and last root. This error is likely " + - "caused by a bug in React. Please file an issue." - ); - if (root === root.nextScheduledRoot) { - // This is the only root in the list. - root.nextScheduledRoot = null; - firstScheduledRoot = lastScheduledRoot = null; - break; - } else if (root === firstScheduledRoot) { - // This is the first root in the list. - var next = root.nextScheduledRoot; - firstScheduledRoot = next; - lastScheduledRoot.nextScheduledRoot = next; - root.nextScheduledRoot = null; - } else if (root === lastScheduledRoot) { - // This is the last root in the list. - lastScheduledRoot = previousScheduledRoot; - lastScheduledRoot.nextScheduledRoot = firstScheduledRoot; - root.nextScheduledRoot = null; - break; - } else { - previousScheduledRoot.nextScheduledRoot = root.nextScheduledRoot; - root.nextScheduledRoot = null; - } - root = previousScheduledRoot.nextScheduledRoot; - } else { - if ( - highestPriorityWork === NoWork || - remainingExpirationTime < highestPriorityWork - ) { - // Update the priority, if it's higher - highestPriorityWork = remainingExpirationTime; - highestPriorityRoot = root; - } - if (root === lastScheduledRoot) { - break; - } - previousScheduledRoot = root; - root = root.nextScheduledRoot; - } - } - } - - // If the next root is the same as the previous root, this is a nested - // update. To prevent an infinite loop, increment the nested update count. - var previousFlushedRoot = nextFlushedRoot; - if ( - previousFlushedRoot !== null && - previousFlushedRoot === highestPriorityRoot && - highestPriorityWork === Sync - ) { - nestedUpdateCount++; - } else { - // Reset whenever we switch roots. - nestedUpdateCount = 0; - } - nextFlushedRoot = highestPriorityRoot; - nextFlushedExpirationTime = highestPriorityWork; - } - - function performAsyncWork(dl) { - performWork(NoWork, true, dl); - } - - function performSyncWork() { - performWork(Sync, false, null); - } - - function performWork(minExpirationTime, isAsync, dl) { - deadline = dl; - - // Keep working on roots until there's no more work, or until the we reach - // the deadline. - findHighestPriorityRoot(); - - if (enableUserTimingAPI && deadline !== null) { - var didExpire = nextFlushedExpirationTime < recalculateCurrentTime(); - var timeout = expirationTimeToMs(nextFlushedExpirationTime); - stopRequestCallbackTimer(didExpire, timeout); - } - - if (isAsync) { - while ( - nextFlushedRoot !== null && - nextFlushedExpirationTime !== NoWork && - (minExpirationTime === NoWork || - minExpirationTime >= nextFlushedExpirationTime) && - (!deadlineDidExpire || - recalculateCurrentTime() >= nextFlushedExpirationTime) - ) { - performWorkOnRoot( - nextFlushedRoot, - nextFlushedExpirationTime, - !deadlineDidExpire - ); - findHighestPriorityRoot(); - } - } else { - while ( - nextFlushedRoot !== null && - nextFlushedExpirationTime !== NoWork && - (minExpirationTime === NoWork || - minExpirationTime >= nextFlushedExpirationTime) - ) { - performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime, false); - findHighestPriorityRoot(); - } - } - - // We're done flushing work. Either we ran out of time in this callback, - // or there's no more work left with sufficient priority. - - // If we're inside a callback, set this to false since we just completed it. - if (deadline !== null) { - callbackExpirationTime = NoWork; - callbackID = -1; - } - // If there's work left over, schedule a new callback. - if (nextFlushedExpirationTime !== NoWork) { - scheduleCallbackWithExpiration(nextFlushedExpirationTime); - } - - // Clean-up. - deadline = null; - deadlineDidExpire = false; - - finishRendering(); - } - - function flushRoot(root, expirationTime) { - invariant( - !isRendering, - "work.commit(): Cannot commit while already rendering. This likely " + - "means you attempted to commit from inside a lifecycle method." - ); - // Perform work on root as if the given expiration time is the current time. - // This has the effect of synchronously flushing all work up to and - // including the given time. - nextFlushedRoot = root; - nextFlushedExpirationTime = expirationTime; - performWorkOnRoot(root, expirationTime, false); - // Flush any sync work that was scheduled by lifecycles - performSyncWork(); - finishRendering(); - } - - function finishRendering() { - nestedUpdateCount = 0; - - if (completedBatches !== null) { - var batches = completedBatches; - completedBatches = null; - for (var i = 0; i < batches.length; i++) { - var batch = batches[i]; - try { - batch._onComplete(); - } catch (error) { - if (!hasUnhandledError) { - hasUnhandledError = true; - unhandledError = error; - } - } - } - } - - if (hasUnhandledError) { - var error = unhandledError; - unhandledError = null; - hasUnhandledError = false; - throw error; - } - } - - function performWorkOnRoot(root, expirationTime, isAsync) { - invariant( - !isRendering, - "performWorkOnRoot was called recursively. This error is likely caused " + - "by a bug in React. Please file an issue." - ); - - isRendering = true; - - // Check if this is async work or sync/expired work. - if (!isAsync) { - // Flush sync work. - var finishedWork = root.finishedWork; - if (finishedWork !== null) { - // This root is already complete. We can commit it. - completeRoot(root, finishedWork, expirationTime); - } else { - root.finishedWork = null; - finishedWork = renderRoot(root, expirationTime, false); - if (finishedWork !== null) { - // We've completed the root. Commit it. - completeRoot(root, finishedWork, expirationTime); - } - } - } else { - // Flush async work. - var _finishedWork = root.finishedWork; - if (_finishedWork !== null) { - // This root is already complete. We can commit it. - completeRoot(root, _finishedWork, expirationTime); - } else { - root.finishedWork = null; - _finishedWork = renderRoot(root, expirationTime, true); - if (_finishedWork !== null) { - // We've completed the root. Check the deadline one more time - // before committing. - if (!shouldYield()) { - // Still time left. Commit the root. - completeRoot(root, _finishedWork, expirationTime); - } else { - // There's no time left. Mark this root as complete. We'll come - // back and commit it later. - root.finishedWork = _finishedWork; - } - } - } - } - - isRendering = false; - } - - function completeRoot(root, finishedWork, expirationTime) { - // Check if there's a batch that matches this expiration time. - var firstBatch = root.firstBatch; - if (firstBatch !== null && firstBatch._expirationTime <= expirationTime) { - if (completedBatches === null) { - completedBatches = [firstBatch]; - } else { - completedBatches.push(firstBatch); - } - if (firstBatch._defer) { - // This root is blocked from committing by a batch. Unschedule it until - // we receive another update. - root.finishedWork = finishedWork; - root.remainingExpirationTime = NoWork; - return; - } - } - - // Commit the root. - root.finishedWork = null; - root.remainingExpirationTime = commitRoot(finishedWork); - } - - // When working on async work, the reconciler asks the renderer if it should - // yield execution. For DOM, we implement this with requestIdleCallback. - function shouldYield() { - if (deadline === null) { - return false; - } - if (deadline.timeRemaining() > timeHeuristicForUnitOfWork) { - // Disregard deadline.didTimeout. Only expired work should be flushed - // during a timeout. This path is only hit for non-expired work. - return false; - } - deadlineDidExpire = true; - return true; - } - - function onUncaughtError(error) { - invariant( - nextFlushedRoot !== null, - "Should be working on a root. This error is likely caused by a bug in " + - "React. Please file an issue." - ); - // Unschedule this root so we don't work on it again until there's - // another update. - nextFlushedRoot.remainingExpirationTime = NoWork; - if (!hasUnhandledError) { - hasUnhandledError = true; - unhandledError = error; - } - } - - // TODO: Batching should be implemented at the renderer level, not inside - // the reconciler. - function batchedUpdates(fn, a) { - var previousIsBatchingUpdates = isBatchingUpdates; - isBatchingUpdates = true; - try { - return fn(a); - } finally { - isBatchingUpdates = previousIsBatchingUpdates; - if (!isBatchingUpdates && !isRendering) { - performSyncWork(); - } - } - } - - // TODO: Batching should be implemented at the renderer level, not inside - // the reconciler. - function unbatchedUpdates(fn, a) { - if (isBatchingUpdates && !isUnbatchingUpdates) { - isUnbatchingUpdates = true; - try { - return fn(a); - } finally { - isUnbatchingUpdates = false; - } - } - return fn(a); - } - - // TODO: Batching should be implemented at the renderer level, not within - // the reconciler. - function flushSync(fn, a) { - invariant( - !isRendering, - "flushSync was called from inside a lifecycle method. It cannot be " + - "called when React is already rendering." - ); - var previousIsBatchingUpdates = isBatchingUpdates; - isBatchingUpdates = true; - try { - return syncUpdates(fn, a); - } finally { - isBatchingUpdates = previousIsBatchingUpdates; - performSyncWork(); - } - } - - function interactiveUpdates(fn, a, b) { - if (isBatchingInteractiveUpdates) { - return fn(a, b); - } - // If there are any pending interactive updates, synchronously flush them. - // This needs to happen before we read any handlers, because the effect of - // the previous event may influence which handlers are called during - // this event. - if ( - !isBatchingUpdates && - !isRendering && - lowestPendingInteractiveExpirationTime !== NoWork - ) { - // Synchronously flush pending interactive updates. - performWork(lowestPendingInteractiveExpirationTime, false, null); - lowestPendingInteractiveExpirationTime = NoWork; - } - var previousIsBatchingInteractiveUpdates = isBatchingInteractiveUpdates; - var previousIsBatchingUpdates = isBatchingUpdates; - isBatchingInteractiveUpdates = true; - isBatchingUpdates = true; - try { - return fn(a, b); - } finally { - isBatchingInteractiveUpdates = previousIsBatchingInteractiveUpdates; - isBatchingUpdates = previousIsBatchingUpdates; - if (!isBatchingUpdates && !isRendering) { - performSyncWork(); - } - } - } - - function flushInteractiveUpdates() { - if (!isRendering && lowestPendingInteractiveExpirationTime !== NoWork) { - // Synchronously flush pending interactive updates. - performWork(lowestPendingInteractiveExpirationTime, false, null); - lowestPendingInteractiveExpirationTime = NoWork; - } - } - - function flushControlled(fn) { - var previousIsBatchingUpdates = isBatchingUpdates; - isBatchingUpdates = true; - try { - syncUpdates(fn); - } finally { - isBatchingUpdates = previousIsBatchingUpdates; - if (!isBatchingUpdates && !isRendering) { - performWork(Sync, false, null); - } - } - } - - return { - recalculateCurrentTime: recalculateCurrentTime, - computeExpirationForFiber: computeExpirationForFiber, - scheduleWork: scheduleWork, - requestWork: requestWork, - flushRoot: flushRoot, - batchedUpdates: batchedUpdates, - unbatchedUpdates: unbatchedUpdates, - flushSync: flushSync, - flushControlled: flushControlled, - deferredUpdates: deferredUpdates, - syncUpdates: syncUpdates, - interactiveUpdates: interactiveUpdates, - flushInteractiveUpdates: flushInteractiveUpdates, - computeUniqueAsyncExpiration: computeUniqueAsyncExpiration, - legacyContext: legacyContext - }; -}; - -var didWarnAboutNestedUpdates = void 0; - -{ - didWarnAboutNestedUpdates = false; -} - -// 0 is PROD, 1 is DEV. -// Might add PROFILE later. - -var ReactFiberReconciler$1 = function(config) { - var getPublicInstance = config.getPublicInstance; - - var _ReactFiberScheduler = ReactFiberScheduler(config), - computeUniqueAsyncExpiration = - _ReactFiberScheduler.computeUniqueAsyncExpiration, - recalculateCurrentTime = _ReactFiberScheduler.recalculateCurrentTime, - computeExpirationForFiber = _ReactFiberScheduler.computeExpirationForFiber, - scheduleWork = _ReactFiberScheduler.scheduleWork, - requestWork = _ReactFiberScheduler.requestWork, - flushRoot = _ReactFiberScheduler.flushRoot, - batchedUpdates = _ReactFiberScheduler.batchedUpdates, - unbatchedUpdates = _ReactFiberScheduler.unbatchedUpdates, - flushSync = _ReactFiberScheduler.flushSync, - flushControlled = _ReactFiberScheduler.flushControlled, - deferredUpdates = _ReactFiberScheduler.deferredUpdates, - syncUpdates = _ReactFiberScheduler.syncUpdates, - interactiveUpdates = _ReactFiberScheduler.interactiveUpdates, - flushInteractiveUpdates = _ReactFiberScheduler.flushInteractiveUpdates, - legacyContext = _ReactFiberScheduler.legacyContext; - - var findCurrentUnmaskedContext = legacyContext.findCurrentUnmaskedContext, - isContextProvider = legacyContext.isContextProvider, - processChildContext = legacyContext.processChildContext; - - function getContextForSubtree(parentComponent) { - if (!parentComponent) { - return emptyObject; - } - - var fiber = get$1(parentComponent); - var parentContext = findCurrentUnmaskedContext(fiber); - return isContextProvider(fiber) - ? processChildContext(fiber, parentContext) - : parentContext; - } - - function scheduleRootUpdate( - current, - element, - currentTime, - expirationTime, - callback - ) { - { - if ( - ReactDebugCurrentFiber.phase === "render" && - ReactDebugCurrentFiber.current !== null && - !didWarnAboutNestedUpdates - ) { - didWarnAboutNestedUpdates = true; - warning( - 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(ReactDebugCurrentFiber.current) || "Unknown" - ); - } - } - - callback = callback === undefined ? null : callback; - { - !(callback === null || typeof callback === "function") - ? warning( - false, - "render(...): Expected the last optional `callback` argument to be a " + - "function. Instead received: %s.", - callback - ) - : void 0; - } - - var update = { - expirationTime: expirationTime, - partialState: { element: element }, - callback: callback, - isReplace: false, - isForced: false, - capturedValue: null, - next: null - }; - insertUpdateIntoFiber(current, update); - scheduleWork(current, expirationTime); - - return expirationTime; - } - - function updateContainerAtExpirationTime( - element, - container, - parentComponent, - currentTime, - expirationTime, - callback - ) { - // TODO: If this is a nested container, this won't be the root. - var current = container.current; - - { - if (ReactFiberInstrumentation_1.debugTool) { - if (current.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, - element, - currentTime, - expirationTime, - callback - ); - } - - function findHostInstance(component) { - var fiber = get$1(component); - if (fiber === undefined) { - if (typeof component.render === "function") { - invariant(false, "Unable to find node on an unmounted component."); - } else { - invariant( - false, - "Argument appears to not be a ReactComponent. Keys: %s", - Object.keys(component) - ); - } - } - var hostFiber = findCurrentHostFiber(fiber); - if (hostFiber === null) { - return null; - } - return hostFiber.stateNode; - } - - return { - createContainer: function(containerInfo, isAsync, hydrate) { - return createFiberRoot(containerInfo, isAsync, hydrate); - }, - updateContainer: function(element, container, parentComponent, callback) { - var current = container.current; - var currentTime = recalculateCurrentTime(); - var expirationTime = computeExpirationForFiber(current); - return updateContainerAtExpirationTime( - element, - container, - parentComponent, - currentTime, - expirationTime, - callback - ); - }, - updateContainerAtExpirationTime: function( - element, - container, - parentComponent, - expirationTime, - callback - ) { - var currentTime = recalculateCurrentTime(); - return updateContainerAtExpirationTime( - element, - container, - parentComponent, - currentTime, - expirationTime, - callback - ); - }, - - flushRoot: flushRoot, - - requestWork: requestWork, - - computeUniqueAsyncExpiration: computeUniqueAsyncExpiration, - - batchedUpdates: batchedUpdates, - - unbatchedUpdates: unbatchedUpdates, - - deferredUpdates: deferredUpdates, - - syncUpdates: syncUpdates, - - interactiveUpdates: interactiveUpdates, - - flushInteractiveUpdates: flushInteractiveUpdates, - - flushControlled: flushControlled, - - flushSync: flushSync, - - getPublicRootInstance: function(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; - } - }, - - findHostInstance: findHostInstance, - - findHostInstanceWithNoPortals: function(fiber) { - var hostFiber = findCurrentHostFiberWithNoPortals(fiber); - if (hostFiber === null) { - return null; - } - return hostFiber.stateNode; - }, - injectIntoDevTools: function(devToolsConfig) { - var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; - - return injectInternals( - Object.assign({}, devToolsConfig, { - 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); - } - }) - ); - } - }; -}; - -var ReactFiberReconciler$2 = Object.freeze({ - default: ReactFiberReconciler$1 -}); - -var ReactFiberReconciler$3 = - (ReactFiberReconciler$2 && ReactFiberReconciler$1) || ReactFiberReconciler$2; - -// TODO: bundle Flow types with the package. - -// TODO: decide on the top-level export form. -// This is hacky but makes it work with both Rollup and Jest. -var reactReconciler = ReactFiberReconciler$3["default"] - ? ReactFiberReconciler$3["default"] - : ReactFiberReconciler$3; - -function _classCallCheck$1(instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); - } -} - -// Modules provided by RN: -// 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; - -/** - * This is used for refs on host components. - */ - -var ReactFabricHostComponent = (function() { - function ReactFabricHostComponent(tag, viewConfig, props) { - _classCallCheck$1(this, ReactFabricHostComponent); - - this._nativeTag = tag; - this.viewConfig = viewConfig; - this.currentProps = props; - } - - ReactFabricHostComponent.prototype.blur = function blur() { - TextInputState.blurTextInput(this._nativeTag); - }; - - ReactFabricHostComponent.prototype.focus = function focus() { - TextInputState.focusTextInput(this._nativeTag); - }; - - ReactFabricHostComponent.prototype.measure = function measure(callback) { - UIManager.measure(this._nativeTag, mountSafeCallback(this, callback)); - }; - - ReactFabricHostComponent.prototype.measureInWindow = function measureInWindow( - callback - ) { - UIManager.measureInWindow( - this._nativeTag, - mountSafeCallback(this, callback) - ); - }; - - ReactFabricHostComponent.prototype.measureLayout = function measureLayout( - relativeToNativeNode, - onSuccess, - onFail /* currently unused */ - ) { - UIManager.measureLayout( - this._nativeTag, - relativeToNativeNode, - mountSafeCallback(this, onFail), - mountSafeCallback(this, onSuccess) - ); - }; - - ReactFabricHostComponent.prototype.setNativeProps = function setNativeProps( - nativeProps - ) { - { - 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) { - UIManager.updateView( - this._nativeTag, - this.viewConfig.uiViewClassName, - updatePayload - ); - } - }; - - return ReactFabricHostComponent; -})(); - -var ReactFabricRenderer = reactReconciler({ - appendInitialChild: function(parentInstance, child) { - FabricUIManager.appendChild(parentInstance.node, child.node); - }, - createInstance: function( - type, - props, - rootContainerInstance, - hostContext, - internalInstanceHandle - ) { - var tag = nextReactTag; - nextReactTag += 2; - - var viewConfig = ReactNativeViewConfigRegistry.get(type); - - { - for (var key in viewConfig.validAttributes) { - if (props.hasOwnProperty(key)) { - deepFreezeAndThrowOnMutationInDev(props[key]); - } - } - } - - var updatePayload = create(props, viewConfig.validAttributes); - - var node = FabricUIManager.createNode( - tag, // reactTag - viewConfig.uiViewClassName, // viewName - rootContainerInstance, // rootTag - updatePayload, // props - internalInstanceHandle - ); - - var component = new ReactFabricHostComponent(tag, viewConfig, props); - - return { - node: node, - canonical: component - }; - }, - createTextInstance: function( - text, - rootContainerInstance, - hostContext, - internalInstanceHandle - ) { - var tag = nextReactTag; - nextReactTag += 2; - - var node = FabricUIManager.createNode( - tag, // reactTag - "RCTRawText", // viewName - rootContainerInstance, // rootTag - { text: text }, // props - internalInstanceHandle - ); - - return { - node: node - }; - }, - finalizeInitialChildren: function( - parentInstance, - type, - props, - rootContainerInstance - ) { - return false; - }, - getRootHostContext: function() { - return emptyObject; - }, - getChildHostContext: function() { - return emptyObject; - }, - getPublicInstance: function(instance) { - return instance.canonical; - }, - - now: now, - - prepareForCommit: function() { - // Noop - }, - prepareUpdate: function( - 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. - return updatePayload; - }, - resetAfterCommit: function() { - // Noop - }, - - scheduleDeferredCallback: scheduleDeferredCallback, - cancelDeferredCallback: cancelDeferredCallback, - - shouldDeprioritizeSubtree: function(type, props) { - return false; - }, - shouldSetTextContent: function(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; - }, - - persistence: { - cloneInstance: function( - instance, - updatePayload, - type, - oldProps, - newProps, - internalInstanceHandle, - keepChildren, - recyclableInstance - ) { - var node = instance.node; - var clone = void 0; - if (keepChildren) { - if (updatePayload !== null) { - clone = FabricUIManager.cloneNodeWithNewProps(node, updatePayload); - } else { - clone = FabricUIManager.cloneNode(node); - } - } else { - if (updatePayload !== null) { - clone = FabricUIManager.cloneNodeWithNewChildrenAndProps( - node, - updatePayload - ); - } else { - clone = FabricUIManager.cloneNodeWithNewChildren(node); - } - } - return { - node: clone, - canonical: instance.canonical - }; - }, - createContainerChildSet: function(container) { - return FabricUIManager.createChildSet(container); - }, - appendChildToContainerChildSet: function(childSet, child) { - FabricUIManager.appendChildToSet(childSet, child.node); - }, - finalizeContainerChildren: function(container, newChildren) { - FabricUIManager.completeRoot(container, newChildren); - }, - replaceContainerChildren: function(container, newChildren) {} - } -}); - -// Module provided by RN: -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; - } - return emptyObject; - }; - - 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), - getInspectorData: function(findNodeHandle) { - return { - measure: function(callback) { - return 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, - 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 findHostInstance = ReactFabricRenderer.findHostInstance; - -function findNodeHandle(componentOrHandle) { - { - var owner = ReactCurrentOwner.current; - if (owner !== null && owner.stateNode !== null) { - !owner.stateNode._warnedAboutRefsInRender - ? warning( - 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) || "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 = findHostInstance(componentOrHandle); - if (hostInstance == null) { - return hostInstance; - } - if (hostInstance.canonical) { - // Fabric - return hostInstance.canonical._nativeTag; - } - return hostInstance._nativeTag; -} - -injection$2.injectRenderer(ReactFabricRenderer); - -var roots = new Map(); - -var ReactFabric = { - NativeComponent: ReactNativeComponent(findNodeHandle, findHostInstance), - - findNodeHandle: findNodeHandle, - - 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 = ReactFabricRenderer.createContainer(containerTag, false, false); - roots.set(containerTag, root); - } - ReactFabricRenderer.updateContainer(element, root, null, callback); - - return ReactFabricRenderer.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? - ReactFabricRenderer.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), - // Used by react-native-github/Libraries/ components - ReactNativeComponentTree: ReactNativeComponentTree - } -}; - -{ - // $FlowFixMe - Object.assign( - ReactFabric.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, - { - // TODO: none of these work since Fiber. Remove these dependencies. - // Used by RCTRenderingPerf, Systrace: - ReactDebugTool: { - addHook: function() {}, - removeHook: function() {} - }, - // Used by ReactPerfStallHandler, RCTRenderingPerf: - ReactPerf: { - start: function() {}, - stop: function() {}, - printInclusive: function() {}, - printWasted: function() {} - } - } - ); -} - -ReactFabricRenderer.injectIntoDevTools({ - findFiberByHostInstance: getInstanceFromTag, - 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["default"] - : ReactFabric$3; - -module.exports = fabric; - - })(); -} diff --git a/Libraries/Renderer/fb/ReactFabric-prod.js b/Libraries/Renderer/fb/ReactFabric-prod.js deleted file mode 100644 index 19ca0dde9e33cf..00000000000000 --- a/Libraries/Renderer/fb/ReactFabric-prod.js +++ /dev/null @@ -1,5875 +0,0 @@ -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @noflow - * @preventMunge - */ - -"use strict"; -require("InitializeCore"); -var invariant = require("fbjs/lib/invariant"), - emptyFunction = require("fbjs/lib/emptyFunction"), - ReactNativeViewConfigRegistry = require("ReactNativeViewConfigRegistry"), - UIManager = require("UIManager"), - TextInputState = require("TextInputState"), - deepDiffer = require("deepDiffer"), - flattenStyle = require("flattenStyle"), - React = require("react"), - emptyObject = require("fbjs/lib/emptyObject"), - shallowEqual = require("fbjs/lib/shallowEqual"), - FabricUIManager = require("FabricUIManager"), - eventPluginOrder = null, - namesToPlugins = {}; -function recomputePluginOrdering() { - if (eventPluginOrder) - for (var pluginName in namesToPlugins) { - var pluginModule = namesToPlugins[pluginName], - pluginIndex = eventPluginOrder.indexOf(pluginName); - invariant( - -1 < pluginIndex, - "EventPluginRegistry: Cannot inject event plugins that do not exist in the plugin ordering, `%s`.", - pluginName - ); - if (!plugins[pluginIndex]) { - invariant( - pluginModule.extractEvents, - "EventPluginRegistry: Event plugins must implement an `extractEvents` method, but `%s` does not.", - pluginName - ); - 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; - invariant( - !eventNameDispatchConfigs.hasOwnProperty(eventName$jscomp$0), - "EventPluginHub: More than one plugin attempted to publish the same event name, `%s`.", - 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); - invariant( - JSCompiler_inline_result, - "EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.", - eventName, - pluginName - ); - } - } - } -} -function publishRegistrationName(registrationName, pluginModule) { - invariant( - !registrationNameModules[registrationName], - "EventPluginHub: More than one plugin attempted to publish the same registration name, `%s`.", - registrationName - ); - registrationNameModules[registrationName] = pluginModule; -} -var plugins = [], - eventNameDispatchConfigs = {}, - registrationNameModules = {}, - getFiberCurrentPropsFromNode = null, - getInstanceFromNode = null, - getNodeFromInstance = null; -function isEndish(topLevelType) { - return ( - "topMouseUp" === topLevelType || - "topTouchEnd" === topLevelType || - "topTouchCancel" === topLevelType - ); -} -function isMoveish(topLevelType) { - return "topMouseMove" === topLevelType || "topTouchMove" === topLevelType; -} -function isStartish(topLevelType) { - return "topMouseDown" === topLevelType || "topTouchStart" === topLevelType; -} -function executeDirectDispatch(event) { - var dispatchListener = event._dispatchListeners, - dispatchInstance = event._dispatchInstances; - invariant( - !Array.isArray(dispatchListener), - "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) { - invariant( - null != next, - "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 injection = { - injectEventPluginOrder: function(injectedEventPluginOrder) { - invariant( - !eventPluginOrder, - "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]; - (namesToPlugins.hasOwnProperty(pluginName) && - namesToPlugins[pluginName] === pluginModule) || - (invariant( - !namesToPlugins[pluginName], - "EventPluginRegistry: Cannot inject two different event plugins using the same name, `%s`.", - 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; - invariant( - !listener || "function" === typeof listener, - "Expected `%s` listener to be a function, instead got a value of `%s` type.", - registrationName, - typeof listener - ); - 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 - ))); - } - } -} -var shouldBeReleasedProperties = "dispatchConfig _targetInst nativeEvent isDefaultPrevented isPropagationStopped _dispatchListeners _dispatchInstances".split( - " " - ), - EventInterface = { - type: null, - target: null, - currentTarget: emptyFunction.thatReturnsNull, - eventPhase: null, - bubbles: null, - cancelable: null, - timeStamp: function(event) { - return event.timeStamp || Date.now(); - }, - defaultPrevented: null, - isTrusted: null - }; -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) - ? emptyFunction.thatReturnsTrue - : emptyFunction.thatReturnsFalse; - this.isPropagationStopped = emptyFunction.thatReturnsFalse; - 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 = emptyFunction.thatReturnsTrue)); - }, - stopPropagation: function() { - var event = this.nativeEvent; - event && - (event.stopPropagation - ? event.stopPropagation() - : "unknown" !== typeof event.cancelBubble && (event.cancelBubble = !0), - (this.isPropagationStopped = emptyFunction.thatReturnsTrue)); - }, - persist: function() { - this.isPersistent = emptyFunction.thatReturnsTrue; - }, - isPersistent: emptyFunction.thatReturnsFalse, - destructor: function() { - var Interface = this.constructor.Interface, - propName; - for (propName in Interface) this[propName] = null; - for ( - Interface = 0; - Interface < shouldBeReleasedProperties.length; - Interface++ - ) - this[shouldBeReleasedProperties[Interface]] = null; - } -}); -SyntheticEvent.Interface = EventInterface; -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) { - invariant( - event instanceof this, - "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; - } - }), - touchBank = [], - touchHistory = { - touchBank: touchBank, - numberActiveTouches: 0, - indexOfSingleActiveTouch: -1, - mostRecentTimeStamp: 0 - }; -function timestampForTouch(touch) { - return touch.timeStamp || touch.timestamp; -} -function getTouchIdentifier(_ref) { - _ref = _ref.identifier; - invariant(null != _ref, "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 ( - isEndish(topLevelType) && - (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) { - invariant( - null != next, - "accumulate(...): Accumulated items must be 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, - previousActiveTouches = 0; -function changeResponder(nextResponderInst, blockHostResponder) { - var oldResponderInst = responderInst; - responderInst = nextResponderInst; - if (null !== ResponderEventPlugin.GlobalResponderHandler) - ResponderEventPlugin.GlobalResponderHandler.onChange( - oldResponderInst, - nextResponderInst, - blockHostResponder - ); -} -var eventTypes$1 = { - startShouldSetResponder: { - phasedRegistrationNames: { - bubbled: "onStartShouldSetResponder", - captured: "onStartShouldSetResponderCapture" - } - }, - scrollShouldSetResponder: { - phasedRegistrationNames: { - bubbled: "onScrollShouldSetResponder", - captured: "onScrollShouldSetResponderCapture" - } - }, - selectionChangeShouldSetResponder: { - phasedRegistrationNames: { - bubbled: "onSelectionChangeShouldSetResponder", - captured: "onSelectionChangeShouldSetResponderCapture" - } - }, - moveShouldSetResponder: { - phasedRegistrationNames: { - bubbled: "onMoveShouldSetResponder", - captured: "onMoveShouldSetResponderCapture" - } - }, - responderStart: { registrationName: "onResponderStart" }, - responderMove: { registrationName: "onResponderMove" }, - responderEnd: { registrationName: "onResponderEnd" }, - responderRelease: { registrationName: "onResponderRelease" }, - responderTerminationRequest: { - registrationName: "onResponderTerminationRequest" - }, - responderGrant: { registrationName: "onResponderGrant" }, - responderReject: { registrationName: "onResponderReject" }, - responderTerminate: { registrationName: "onResponderTerminate" } - }, - ResponderEventPlugin = { - _getResponder: function() { - return responderInst; - }, - eventTypes: eventTypes$1, - extractEvents: function( - topLevelType, - targetInst, - nativeEvent, - nativeEventTarget - ) { - if (isStartish(topLevelType)) trackedTouchCount += 1; - else if (isEndish(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$1.startShouldSetResponder - : isMoveish(topLevelType) - ? eventTypes$1.moveShouldSetResponder - : "topSelectionChange" === topLevelType - ? eventTypes$1.selectionChangeShouldSetResponder - : eventTypes$1.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$1.responderGrant, - JSCompiler_temp, - nativeEvent, - nativeEventTarget - )), - (targetInst.touchHistory = ResponderTouchHistoryStore.touchHistory), - forEachAccumulated(targetInst, accumulateDirectDispatchesSingle), - (depthA = !0 === executeDirectDispatch(targetInst)), - responderInst - ? ((tempA = ResponderSyntheticEvent.getPooled( - eventTypes$1.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$1.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$1.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 && isEndish(topLevelType); - if ( - (JSCompiler_temp$jscomp$0 = JSCompiler_temp$jscomp$0 - ? eventTypes$1.responderStart - : targetInst - ? eventTypes$1.responderMove - : depthA ? eventTypes$1.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 && isEndish(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$1.responderTerminate - : topLevelType ? eventTypes$1.responderRelease : null) - ) - (nativeEvent = ResponderSyntheticEvent.getPooled( - topLevelType, - responderInst, - nativeEvent, - nativeEventTarget - )), - (nativeEvent.touchHistory = ResponderTouchHistoryStore.touchHistory), - forEachAccumulated(nativeEvent, accumulateDirectDispatchesSingle), - (JSCompiler_temp = accumulate(JSCompiler_temp, nativeEvent)), - changeResponder(null); - nativeEvent = ResponderTouchHistoryStore.touchHistory.numberActiveTouches; - if ( - ResponderEventPlugin.GlobalInteractionHandler && - nativeEvent !== previousActiveTouches - ) - ResponderEventPlugin.GlobalInteractionHandler.onChange(nativeEvent); - previousActiveTouches = nativeEvent; - return JSCompiler_temp; - }, - GlobalResponderHandler: null, - GlobalInteractionHandler: null, - injection: { - injectGlobalResponderHandler: function(GlobalResponderHandler) { - ResponderEventPlugin.GlobalResponderHandler = GlobalResponderHandler; - }, - injectGlobalInteractionHandler: function(GlobalInteractionHandler) { - ResponderEventPlugin.GlobalInteractionHandler = GlobalInteractionHandler; - } - } - }, - customBubblingEventTypes$1 = - ReactNativeViewConfigRegistry.customBubblingEventTypes, - customDirectEventTypes$1 = - ReactNativeViewConfigRegistry.customDirectEventTypes, - ReactNativeBridgeEventPlugin = { - eventTypes: ReactNativeViewConfigRegistry.eventTypes, - extractEvents: function( - topLevelType, - targetInst, - nativeEvent, - nativeEventTarget - ) { - if (null == targetInst) return null; - var bubbleDispatchConfig = customBubblingEventTypes$1[topLevelType], - directDispatchConfig = customDirectEventTypes$1[topLevelType]; - invariant( - bubbleDispatchConfig || directDispatchConfig, - 'Unsupported top level event type "%s" dispatched', - topLevelType - ); - topLevelType = SyntheticEvent.getPooled( - bubbleDispatchConfig || directDispatchConfig, - targetInst, - nativeEvent, - nativeEventTarget - ); - if (bubbleDispatchConfig) - forEachAccumulated(topLevelType, accumulateTwoPhaseDispatchesSingle); - else if (directDispatchConfig) - forEachAccumulated(topLevelType, accumulateDirectDispatchesSingle); - else return null; - return topLevelType; - } - }, - instanceCache = {}, - instanceProps = {}; -function getInstanceFromTag(tag) { - return "number" === typeof tag ? instanceCache[tag] || null : tag; -} -var ReactNativeComponentTree = Object.freeze({ - precacheFiberNode: function(hostInst, tag) { - instanceCache[tag] = hostInst; - }, - uncacheFiberNode: function(tag) { - delete instanceCache[tag]; - delete instanceProps[tag]; - }, - getClosestInstanceFromNode: getInstanceFromTag, - getInstanceFromNode: getInstanceFromTag, - getNodeFromInstance: function(inst) { - var tag = inst.stateNode._nativeTag; - void 0 === tag && (tag = inst.stateNode.canonical._nativeTag); - invariant(tag, "All native instances should have a tag."); - return tag; - }, - getFiberCurrentPropsFromNode: function(stateNode) { - return instanceProps[stateNode._nativeTag] || null; - }, - updateFiberProps: function(tag, props) { - instanceProps[tag] = props; - } -}); -injection.injectEventPluginOrder([ - "ResponderEventPlugin", - "ReactNativeBridgeEventPlugin" -]); -getFiberCurrentPropsFromNode = - ReactNativeComponentTree.getFiberCurrentPropsFromNode; -getInstanceFromNode = ReactNativeComponentTree.getInstanceFromNode; -getNodeFromInstance = ReactNativeComponentTree.getNodeFromInstance; -ResponderEventPlugin.injection.injectGlobalResponderHandler({ - onChange: function(from, to, blockNativeResponder) { - null !== to - ? UIManager.setJSResponder(to.stateNode._nativeTag, blockNativeResponder) - : UIManager.clearJSResponder(); - } -}); -injection.injectEventPluginsByName({ - ResponderEventPlugin: ResponderEventPlugin, - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin -}); -var hasSymbol = "function" === typeof Symbol && Symbol["for"], - REACT_ELEMENT_TYPE = hasSymbol ? Symbol["for"]("react.element") : 60103, - REACT_CALL_TYPE = hasSymbol ? Symbol["for"]("react.call") : 60104, - REACT_RETURN_TYPE = hasSymbol ? Symbol["for"]("react.return") : 60105, - 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_PROVIDER_TYPE = hasSymbol ? Symbol["for"]("react.provider") : 60109, - REACT_CONTEXT_TYPE = hasSymbol ? Symbol["for"]("react.context") : 60110, - REACT_ASYNC_MODE_TYPE = hasSymbol ? Symbol["for"]("react.async_mode") : 60111, - REACT_FORWARD_REF_TYPE = hasSymbol - ? Symbol["for"]("react.forward_ref") - : 60112, - MAYBE_ITERATOR_SYMBOL = "function" === typeof Symbol && Symbol.iterator; -function getIteratorFn(maybeIterable) { - if (null === maybeIterable || "undefined" === typeof maybeIterable) - return null; - maybeIterable = - (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || - maybeIterable["@@iterator"]; - return "function" === typeof maybeIterable ? maybeIterable : null; -} -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 - }; -} -var emptyObject$1 = {}, - 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, - flattenStyle(prevProp), - nextProp, - validAttributes - ) - : diffProperties( - updatePayload, - prevProp, - flattenStyle(nextProp), - validAttributes - ); -} -function addNestedProperty(updatePayload, nextProp, validAttributes) { - if (!nextProp) return updatePayload; - if (!Array.isArray(nextProp)) - return diffProperties( - updatePayload, - emptyObject$1, - 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$1, - 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 || - 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 || - 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(context, callback) { - return function() { - if (callback) { - if ("boolean" === typeof context.__isMounted) { - if (!context.__isMounted) return; - } else if ( - "function" === typeof context.isMounted && - !context.isMounted() - ) - return; - return callback.apply(context, arguments); - } - }; -} -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 now = - "object" === typeof performance && "function" === typeof performance.now - ? function() { - return performance.now(); - } - : function() { - return Date.now(); - }, - scheduledCallback = null, - frameDeadline = 0, - frameDeadlineObject = { - timeRemaining: function() { - return frameDeadline - now(); - }, - didTimeout: !1 - }; -function setTimeoutCallback() { - frameDeadline = now() + 5; - var callback = scheduledCallback; - scheduledCallback = null; - null !== callback && callback(frameDeadlineObject); -} -var ReactCurrentOwner = - React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner; -function getComponentName(fiber) { - fiber = fiber.type; - if ("function" === typeof fiber) return fiber.displayName || fiber.name; - if ("string" === typeof fiber) return fiber; - switch (fiber) { - case REACT_FRAGMENT_TYPE: - return "ReactFragment"; - case REACT_PORTAL_TYPE: - return "ReactPortal"; - case REACT_CALL_TYPE: - return "ReactCall"; - case REACT_RETURN_TYPE: - return "ReactReturn"; - } - if ("object" === typeof fiber && null !== fiber) - switch (fiber.$$typeof) { - case REACT_FORWARD_REF_TYPE: - return ( - (fiber = fiber.render.displayName || fiber.render.name || ""), - "" !== fiber ? "ForwardRef(" + fiber + ")" : "ForwardRef" - ); - } - 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 isMounted(component) { - return (component = component._reactInternalFiber) - ? 2 === isFiberMountedImpl(component) - : !1; -} -function assertIsMounted(fiber) { - invariant( - 2 === isFiberMountedImpl(fiber), - "Unable to find node on an unmounted component." - ); -} -function findCurrentFiberUsingSlowPath(fiber) { - var alternate = fiber.alternate; - if (!alternate) - return ( - (alternate = isFiberMountedImpl(fiber)), - invariant( - 3 !== alternate, - "Unable to find node on an unmounted component." - ), - 1 === alternate ? null : fiber - ); - for (var a = fiber, b = alternate; ; ) { - var parentA = a["return"], - parentB = parentA ? parentA.alternate : null; - if (!parentA || !parentB) break; - if (parentA.child === parentB.child) { - for (var child = parentA.child; child; ) { - if (child === a) return assertIsMounted(parentA), fiber; - if (child === b) return assertIsMounted(parentA), alternate; - child = child.sibling; - } - invariant(!1, "Unable to find node on an unmounted component."); - } - if (a["return"] !== b["return"]) (a = parentA), (b = parentB); - else { - child = !1; - for (var _child = parentA.child; _child; ) { - if (_child === a) { - child = !0; - a = parentA; - b = parentB; - break; - } - if (_child === b) { - child = !0; - b = parentA; - a = parentB; - break; - } - _child = _child.sibling; - } - if (!child) { - for (_child = parentB.child; _child; ) { - if (_child === a) { - child = !0; - a = parentB; - b = parentA; - break; - } - if (_child === b) { - child = !0; - b = parentB; - a = parentA; - break; - } - _child = _child.sibling; - } - invariant( - child, - "Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue." - ); - } - } - invariant( - a.alternate === b, - "Return fibers should always be each others' alternates. This error is likely caused by a bug in React. Please file an issue." - ); - } - invariant(3 === a.tag, "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 findCurrentHostFiberWithNoPortals(parent) { - parent = findCurrentFiberUsingSlowPath(parent); - if (!parent) return null; - for (var node = parent; ; ) { - if (5 === node.tag || 6 === node.tag) return node; - if (node.child && 4 !== node.tag) - (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 FiberNode(tag, pendingProps, key, mode) { - this.tag = tag; - this.key = key; - this.stateNode = this.type = null; - this.sibling = this.child = this["return"] = null; - this.index = 0; - this.ref = null; - this.pendingProps = pendingProps; - this.memoizedState = this.updateQueue = this.memoizedProps = null; - this.mode = mode; - this.effectTag = 0; - this.lastEffect = this.firstEffect = this.nextEffect = null; - this.expirationTime = 0; - this.alternate = null; -} -function createWorkInProgress(current, pendingProps, expirationTime) { - var workInProgress = current.alternate; - null === workInProgress - ? ((workInProgress = new FiberNode( - current.tag, - pendingProps, - current.key, - current.mode - )), - (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.expirationTime = expirationTime; - workInProgress.child = current.child; - workInProgress.memoizedProps = current.memoizedProps; - workInProgress.memoizedState = current.memoizedState; - workInProgress.updateQueue = current.updateQueue; - workInProgress.sibling = current.sibling; - workInProgress.index = current.index; - workInProgress.ref = current.ref; - return workInProgress; -} -function createFiberFromElement(element, mode, expirationTime) { - var type = element.type, - key = element.key; - element = element.props; - var fiberTag = void 0; - if ("function" === typeof type) - fiberTag = type.prototype && type.prototype.isReactComponent ? 2 : 0; - else if ("string" === typeof type) fiberTag = 5; - else - switch (type) { - case REACT_FRAGMENT_TYPE: - return createFiberFromFragment( - element.children, - mode, - expirationTime, - key - ); - case REACT_ASYNC_MODE_TYPE: - fiberTag = 11; - mode |= 3; - break; - case REACT_STRICT_MODE_TYPE: - fiberTag = 11; - mode |= 2; - break; - case REACT_CALL_TYPE: - fiberTag = 7; - break; - case REACT_RETURN_TYPE: - fiberTag = 9; - break; - default: - if ("object" === typeof type && null !== type) - switch (type.$$typeof) { - case REACT_PROVIDER_TYPE: - fiberTag = 13; - break; - case REACT_CONTEXT_TYPE: - fiberTag = 12; - break; - case REACT_FORWARD_REF_TYPE: - fiberTag = 14; - break; - default: - if ("number" === typeof type.tag) - return ( - (mode = type), - (mode.pendingProps = element), - (mode.expirationTime = expirationTime), - mode - ); - throwOnInvalidElementType(type, null); - } - else throwOnInvalidElementType(type, null); - } - mode = new FiberNode(fiberTag, element, key, mode); - mode.type = type; - mode.expirationTime = expirationTime; - return mode; -} -function throwOnInvalidElementType(type) { - invariant( - !1, - "Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: %s.%s", - null == type ? type : typeof type, - "" - ); -} -function createFiberFromFragment(elements, mode, expirationTime, key) { - elements = new FiberNode(10, elements, key, mode); - elements.expirationTime = expirationTime; - return elements; -} -function createFiberFromText(content, mode, expirationTime) { - content = new FiberNode(6, content, null, mode); - content.expirationTime = expirationTime; - return content; -} -function createFiberFromPortal(portal, mode, expirationTime) { - mode = new FiberNode( - 4, - null !== portal.children ? portal.children : [], - portal.key, - mode - ); - mode.expirationTime = expirationTime; - mode.stateNode = { - containerInfo: portal.containerInfo, - pendingChildren: null, - implementation: portal.implementation - }; - return mode; -} -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; -} -function onCommitRoot(root) { - "function" === typeof onCommitFiberRoot && onCommitFiberRoot(root); -} -function onCommitUnmount(fiber) { - "function" === typeof onCommitFiberUnmount && onCommitFiberUnmount(fiber); -} -function getStackAddendumByWorkInProgressFiber(workInProgress) { - var info = ""; - do { - a: switch (workInProgress.tag) { - case 0: - case 1: - case 2: - case 5: - var owner = workInProgress._debugOwner, - source = workInProgress._debugSource; - var JSCompiler_inline_result = getComponentName(workInProgress); - var ownerName = null; - owner && (ownerName = getComponentName(owner)); - owner = source; - JSCompiler_inline_result = - "\n in " + - (JSCompiler_inline_result || "Unknown") + - (owner - ? " (at " + - owner.fileName.replace(/^.*[\\\/]/, "") + - ":" + - owner.lineNumber + - ")" - : ownerName ? " (created by " + ownerName + ")" : ""); - break a; - default: - JSCompiler_inline_result = ""; - } - info += JSCompiler_inline_result; - workInProgress = workInProgress["return"]; - } while (workInProgress); - return info; -} -new Set(); -function createUpdateQueue(baseState) { - return { - baseState: baseState, - expirationTime: 0, - first: null, - last: null, - callbackList: null, - hasForceUpdate: !1, - isInitialized: !1, - capturedValues: null - }; -} -function insertUpdateIntoQueue(queue, update) { - null === queue.last - ? (queue.first = queue.last = update) - : ((queue.last.next = update), (queue.last = update)); - if ( - 0 === queue.expirationTime || - queue.expirationTime > update.expirationTime - ) - queue.expirationTime = update.expirationTime; -} -var q1 = void 0, - q2 = void 0; -function ensureUpdateQueues(fiber) { - q1 = q2 = null; - var alternateFiber = fiber.alternate, - queue1 = fiber.updateQueue; - null === queue1 && (queue1 = fiber.updateQueue = createUpdateQueue(null)); - null !== alternateFiber - ? ((fiber = alternateFiber.updateQueue), - null === fiber && - (fiber = alternateFiber.updateQueue = createUpdateQueue(null))) - : (fiber = null); - q1 = queue1; - q2 = fiber !== queue1 ? fiber : null; -} -function insertUpdateIntoFiber(fiber, update) { - ensureUpdateQueues(fiber); - fiber = q1; - var queue2 = q2; - null === queue2 - ? insertUpdateIntoQueue(fiber, update) - : null === fiber.last || null === queue2.last - ? (insertUpdateIntoQueue(fiber, update), - insertUpdateIntoQueue(queue2, update)) - : (insertUpdateIntoQueue(fiber, update), (queue2.last = update)); -} -function getStateFromUpdate(update, instance, prevState, props) { - update = update.partialState; - return "function" === typeof update - ? update.call(instance, prevState, props) - : update; -} -function processUpdateQueue( - current, - workInProgress, - queue, - instance, - props, - renderExpirationTime -) { - null !== current && - current.updateQueue === queue && - (queue = workInProgress.updateQueue = { - baseState: queue.baseState, - expirationTime: queue.expirationTime, - first: queue.first, - last: queue.last, - isInitialized: queue.isInitialized, - capturedValues: queue.capturedValues, - callbackList: null, - hasForceUpdate: !1 - }); - queue.expirationTime = 0; - queue.isInitialized - ? (current = queue.baseState) - : ((current = queue.baseState = workInProgress.memoizedState), - (queue.isInitialized = !0)); - for ( - var dontMutatePrevState = !0, update = queue.first, didSkip = !1; - null !== update; - - ) { - var updateExpirationTime = update.expirationTime; - if (updateExpirationTime > renderExpirationTime) { - var remainingExpirationTime = queue.expirationTime; - if ( - 0 === remainingExpirationTime || - remainingExpirationTime > updateExpirationTime - ) - queue.expirationTime = updateExpirationTime; - didSkip || ((didSkip = !0), (queue.baseState = current)); - } else { - didSkip || - ((queue.first = update.next), - null === queue.first && (queue.last = null)); - if (update.isReplace) - (current = getStateFromUpdate(update, instance, current, props)), - (dontMutatePrevState = !0); - else if ( - (updateExpirationTime = getStateFromUpdate( - update, - instance, - current, - props - )) - ) - (current = dontMutatePrevState - ? Object.assign({}, current, updateExpirationTime) - : Object.assign(current, updateExpirationTime)), - (dontMutatePrevState = !1); - update.isForced && (queue.hasForceUpdate = !0); - null !== update.callback && - ((updateExpirationTime = queue.callbackList), - null === updateExpirationTime && - (updateExpirationTime = queue.callbackList = []), - updateExpirationTime.push(update)); - null !== update.capturedValue && - ((updateExpirationTime = queue.capturedValues), - null === updateExpirationTime - ? (queue.capturedValues = [update.capturedValue]) - : updateExpirationTime.push(update.capturedValue)); - } - update = update.next; - } - null !== queue.callbackList - ? (workInProgress.effectTag |= 32) - : null !== queue.first || - queue.hasForceUpdate || - null !== queue.capturedValues || - (workInProgress.updateQueue = null); - didSkip || (queue.baseState = current); - return current; -} -function commitCallbacks(queue, context) { - var callbackList = queue.callbackList; - if (null !== callbackList) - for ( - queue.callbackList = null, queue = 0; - queue < callbackList.length; - queue++ - ) { - var update = callbackList[queue], - _callback = update.callback; - update.callback = null; - invariant( - "function" === typeof _callback, - "Invalid argument passed as callback. Expected a function. Instead received: %s", - _callback - ); - _callback.call(context); - } -} -function ReactFiberClassComponent( - legacyContext, - scheduleWork, - computeExpirationForFiber, - memoizeProps, - memoizeState -) { - function checkShouldComponentUpdate( - workInProgress, - oldProps, - newProps, - oldState, - newState, - newContext - ) { - if ( - null === oldProps || - (null !== workInProgress.updateQueue && - workInProgress.updateQueue.hasForceUpdate) - ) - return !0; - var instance = workInProgress.stateNode; - workInProgress = workInProgress.type; - return "function" === typeof instance.shouldComponentUpdate - ? instance.shouldComponentUpdate(newProps, newState, newContext) - : workInProgress.prototype && - workInProgress.prototype.isPureReactComponent - ? !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) - : !0; - } - function adoptClassInstance(workInProgress, instance) { - instance.updater = updater; - workInProgress.stateNode = instance; - instance._reactInternalFiber = workInProgress; - } - function callComponentWillReceiveProps( - workInProgress, - instance, - newProps, - newContext - ) { - workInProgress = instance.state; - "function" === typeof instance.componentWillReceiveProps && - instance.componentWillReceiveProps(newProps, newContext); - "function" === typeof instance.UNSAFE_componentWillReceiveProps && - instance.UNSAFE_componentWillReceiveProps(newProps, newContext); - instance.state !== workInProgress && - updater.enqueueReplaceState(instance, instance.state, null); - } - function callGetDerivedStateFromProps( - workInProgress, - instance, - nextProps, - prevState - ) { - workInProgress = workInProgress.type; - if ("function" === typeof workInProgress.getDerivedStateFromProps) - return workInProgress.getDerivedStateFromProps.call( - null, - nextProps, - prevState - ); - } - var cacheContext = legacyContext.cacheContext, - getMaskedContext = legacyContext.getMaskedContext, - getUnmaskedContext = legacyContext.getUnmaskedContext, - isContextConsumer = legacyContext.isContextConsumer, - hasContextChanged = legacyContext.hasContextChanged, - updater = { - isMounted: isMounted, - enqueueSetState: function(instance, partialState, callback) { - instance = instance._reactInternalFiber; - callback = void 0 === callback ? null : callback; - var expirationTime = computeExpirationForFiber(instance); - insertUpdateIntoFiber(instance, { - expirationTime: expirationTime, - partialState: partialState, - callback: callback, - isReplace: !1, - isForced: !1, - capturedValue: null, - next: null - }); - scheduleWork(instance, expirationTime); - }, - enqueueReplaceState: function(instance, state, callback) { - instance = instance._reactInternalFiber; - callback = void 0 === callback ? null : callback; - var expirationTime = computeExpirationForFiber(instance); - insertUpdateIntoFiber(instance, { - expirationTime: expirationTime, - partialState: state, - callback: callback, - isReplace: !0, - isForced: !1, - capturedValue: null, - next: null - }); - scheduleWork(instance, expirationTime); - }, - enqueueForceUpdate: function(instance, callback) { - instance = instance._reactInternalFiber; - callback = void 0 === callback ? null : callback; - var expirationTime = computeExpirationForFiber(instance); - insertUpdateIntoFiber(instance, { - expirationTime: expirationTime, - partialState: null, - callback: callback, - isReplace: !1, - isForced: !0, - capturedValue: null, - next: null - }); - scheduleWork(instance, expirationTime); - } - }; - return { - adoptClassInstance: adoptClassInstance, - callGetDerivedStateFromProps: callGetDerivedStateFromProps, - constructClassInstance: function(workInProgress, props) { - var ctor = workInProgress.type, - unmaskedContext = getUnmaskedContext(workInProgress), - needsContext = isContextConsumer(workInProgress), - context = needsContext - ? getMaskedContext(workInProgress, unmaskedContext) - : emptyObject; - ctor = new ctor(props, context); - var state = - null !== ctor.state && void 0 !== ctor.state ? ctor.state : null; - adoptClassInstance(workInProgress, ctor); - workInProgress.memoizedState = state; - props = callGetDerivedStateFromProps(workInProgress, ctor, props, state); - null !== props && - void 0 !== props && - (workInProgress.memoizedState = Object.assign( - {}, - workInProgress.memoizedState, - props - )); - needsContext && cacheContext(workInProgress, unmaskedContext, context); - return ctor; - }, - mountClassInstance: function(workInProgress, renderExpirationTime) { - var ctor = workInProgress.type, - current = workInProgress.alternate, - instance = workInProgress.stateNode, - props = workInProgress.pendingProps, - unmaskedContext = getUnmaskedContext(workInProgress); - instance.props = props; - instance.state = workInProgress.memoizedState; - instance.refs = emptyObject; - instance.context = getMaskedContext(workInProgress, unmaskedContext); - "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 && - updater.enqueueReplaceState(instance, instance.state, null), - (ctor = workInProgress.updateQueue), - null !== ctor && - (instance.state = processUpdateQueue( - current, - workInProgress, - ctor, - instance, - props, - renderExpirationTime - ))); - "function" === typeof instance.componentDidMount && - (workInProgress.effectTag |= 4); - }, - resumeMountClassInstance: function(workInProgress, renderExpirationTime) { - var ctor = workInProgress.type, - instance = workInProgress.stateNode; - instance.props = workInProgress.memoizedProps; - instance.state = workInProgress.memoizedState; - var oldProps = workInProgress.memoizedProps, - newProps = workInProgress.pendingProps, - oldContext = instance.context, - newUnmaskedContext = getUnmaskedContext(workInProgress); - newUnmaskedContext = getMaskedContext(workInProgress, newUnmaskedContext); - (ctor = - "function" === typeof ctor.getDerivedStateFromProps || - "function" === typeof instance.getSnapshotBeforeUpdate) || - ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && - "function" !== typeof instance.componentWillReceiveProps) || - ((oldProps !== newProps || oldContext !== newUnmaskedContext) && - callComponentWillReceiveProps( - workInProgress, - instance, - newProps, - newUnmaskedContext - )); - oldContext = workInProgress.memoizedState; - renderExpirationTime = - null !== workInProgress.updateQueue - ? processUpdateQueue( - null, - workInProgress, - workInProgress.updateQueue, - instance, - newProps, - renderExpirationTime - ) - : oldContext; - var derivedStateFromProps = void 0; - oldProps !== newProps && - (derivedStateFromProps = callGetDerivedStateFromProps( - workInProgress, - instance, - newProps, - renderExpirationTime - )); - if (null !== derivedStateFromProps && void 0 !== derivedStateFromProps) { - renderExpirationTime = - null === renderExpirationTime || void 0 === renderExpirationTime - ? derivedStateFromProps - : Object.assign({}, renderExpirationTime, derivedStateFromProps); - var _updateQueue = workInProgress.updateQueue; - null !== _updateQueue && - (_updateQueue.baseState = Object.assign( - {}, - _updateQueue.baseState, - derivedStateFromProps - )); - } - if ( - !( - oldProps !== newProps || - oldContext !== renderExpirationTime || - hasContextChanged() || - (null !== workInProgress.updateQueue && - workInProgress.updateQueue.hasForceUpdate) - ) - ) - return ( - "function" === typeof instance.componentDidMount && - (workInProgress.effectTag |= 4), - !1 - ); - (oldProps = checkShouldComponentUpdate( - workInProgress, - oldProps, - newProps, - oldContext, - renderExpirationTime, - newUnmaskedContext - )) - ? (ctor || - ("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), - memoizeProps(workInProgress, newProps), - memoizeState(workInProgress, renderExpirationTime)); - instance.props = newProps; - instance.state = renderExpirationTime; - instance.context = newUnmaskedContext; - return oldProps; - }, - updateClassInstance: function( - current, - workInProgress, - renderExpirationTime - ) { - var ctor = workInProgress.type, - instance = workInProgress.stateNode; - instance.props = workInProgress.memoizedProps; - instance.state = workInProgress.memoizedState; - var oldProps = workInProgress.memoizedProps, - newProps = workInProgress.pendingProps, - oldContext = instance.context, - newUnmaskedContext = getUnmaskedContext(workInProgress); - newUnmaskedContext = getMaskedContext(workInProgress, newUnmaskedContext); - (ctor = - "function" === typeof ctor.getDerivedStateFromProps || - "function" === typeof instance.getSnapshotBeforeUpdate) || - ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && - "function" !== typeof instance.componentWillReceiveProps) || - ((oldProps !== newProps || oldContext !== newUnmaskedContext) && - callComponentWillReceiveProps( - workInProgress, - instance, - newProps, - newUnmaskedContext - )); - oldContext = workInProgress.memoizedState; - renderExpirationTime = - null !== workInProgress.updateQueue - ? processUpdateQueue( - current, - workInProgress, - workInProgress.updateQueue, - instance, - newProps, - renderExpirationTime - ) - : oldContext; - var derivedStateFromProps = void 0; - oldProps !== newProps && - (derivedStateFromProps = callGetDerivedStateFromProps( - workInProgress, - instance, - newProps, - renderExpirationTime - )); - if (null !== derivedStateFromProps && void 0 !== derivedStateFromProps) { - renderExpirationTime = - null === renderExpirationTime || void 0 === renderExpirationTime - ? derivedStateFromProps - : Object.assign({}, renderExpirationTime, derivedStateFromProps); - var _updateQueue3 = workInProgress.updateQueue; - null !== _updateQueue3 && - (_updateQueue3.baseState = Object.assign( - {}, - _updateQueue3.baseState, - derivedStateFromProps - )); - } - if ( - !( - oldProps !== newProps || - oldContext !== renderExpirationTime || - hasContextChanged() || - (null !== workInProgress.updateQueue && - workInProgress.updateQueue.hasForceUpdate) - ) - ) - return ( - "function" !== typeof instance.componentDidUpdate || - (oldProps === current.memoizedProps && - oldContext === current.memoizedState) || - (workInProgress.effectTag |= 4), - "function" !== typeof instance.getSnapshotBeforeUpdate || - (oldProps === current.memoizedProps && - oldContext === current.memoizedState) || - (workInProgress.effectTag |= 2048), - !1 - ); - (derivedStateFromProps = checkShouldComponentUpdate( - workInProgress, - oldProps, - newProps, - oldContext, - renderExpirationTime, - newUnmaskedContext - )) - ? (ctor || - ("function" !== typeof instance.UNSAFE_componentWillUpdate && - "function" !== typeof instance.componentWillUpdate) || - ("function" === typeof instance.componentWillUpdate && - instance.componentWillUpdate( - newProps, - renderExpirationTime, - newUnmaskedContext - ), - "function" === typeof instance.UNSAFE_componentWillUpdate && - instance.UNSAFE_componentWillUpdate( - newProps, - renderExpirationTime, - newUnmaskedContext - )), - "function" === typeof instance.componentDidUpdate && - (workInProgress.effectTag |= 4), - "function" === typeof instance.getSnapshotBeforeUpdate && - (workInProgress.effectTag |= 2048)) - : ("function" !== typeof instance.componentDidUpdate || - (oldProps === current.memoizedProps && - oldContext === current.memoizedState) || - (workInProgress.effectTag |= 4), - "function" !== typeof instance.getSnapshotBeforeUpdate || - (oldProps === current.memoizedProps && - oldContext === current.memoizedState) || - (workInProgress.effectTag |= 2048), - memoizeProps(workInProgress, newProps), - memoizeState(workInProgress, renderExpirationTime)); - instance.props = newProps; - instance.state = renderExpirationTime; - instance.context = newUnmaskedContext; - return derivedStateFromProps; - } - }; -} -var isArray$1 = Array.isArray; -function coerceRef(returnFiber, current, element) { - returnFiber = element.ref; - if ( - null !== returnFiber && - "function" !== typeof returnFiber && - "object" !== typeof returnFiber - ) { - if (element._owner) { - element = element._owner; - var inst = void 0; - element && - (invariant( - 2 === element.tag, - "Stateless function components cannot have refs." - ), - (inst = element.stateNode)); - invariant( - inst, - "Missing owner for string ref %s. This error is likely caused by a bug in React. Please file an issue.", - returnFiber - ); - var stringRef = "" + returnFiber; - if ( - null !== current && - null !== current.ref && - current.ref._stringRef === stringRef - ) - return current.ref; - current = function(value) { - var refs = inst.refs === emptyObject ? (inst.refs = {}) : inst.refs; - null === value ? delete refs[stringRef] : (refs[stringRef] = value); - }; - current._stringRef = stringRef; - return current; - } - invariant( - "string" === typeof returnFiber, - "Expected ref to be a function or a string." - ); - invariant( - element._owner, - "Element ref was specified as a string (%s) but no owner was set. This could happen for one of the following reasons:\n1. You may be adding a ref to a functional 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.", - returnFiber - ); - } - return returnFiber; -} -function throwOnInvalidObjectType(returnFiber, newChild) { - "textarea" !== returnFiber.type && - invariant( - !1, - "Objects are not valid as a React child (found: %s).%s", - "[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, textContent, expirationTime) { - if (null === current || 6 !== current.tag) - return ( - (current = createFiberFromText( - textContent, - returnFiber.mode, - expirationTime - )), - (current["return"] = returnFiber), - current - ); - current = useFiber(current, textContent, expirationTime); - current["return"] = returnFiber; - return current; - } - function updateElement(returnFiber, current, element, expirationTime) { - if (null !== current && current.type === element.type) - return ( - (expirationTime = useFiber(current, element.props, expirationTime)), - (expirationTime.ref = coerceRef(returnFiber, current, element)), - (expirationTime["return"] = returnFiber), - expirationTime - ); - expirationTime = createFiberFromElement( - element, - returnFiber.mode, - expirationTime - ); - expirationTime.ref = coerceRef(returnFiber, current, element); - expirationTime["return"] = returnFiber; - return expirationTime; - } - function updatePortal(returnFiber, current, portal, expirationTime) { - if ( - null === current || - 4 !== current.tag || - current.stateNode.containerInfo !== portal.containerInfo || - current.stateNode.implementation !== portal.implementation - ) - return ( - (current = createFiberFromPortal( - portal, - returnFiber.mode, - expirationTime - )), - (current["return"] = returnFiber), - current - ); - current = useFiber(current, portal.children || [], expirationTime); - current["return"] = returnFiber; - return current; - } - function updateFragment(returnFiber, current, fragment, expirationTime, key) { - if (null === current || 10 !== current.tag) - return ( - (current = createFiberFromFragment( - fragment, - returnFiber.mode, - expirationTime, - key - )), - (current["return"] = returnFiber), - current - ); - current = useFiber(current, fragment, expirationTime); - current["return"] = returnFiber; - return current; - } - 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 = createFiberFromElement( - newChild, - 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$1(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$1(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$1(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++) - if ( - (oldFiber = createChild( - returnFiber, - newChildren[newIdx], - expirationTime - )) - ) - (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++ - ) - if ( - (nextOldFiber = updateFromMap( - oldFiber, - returnFiber, - newIdx, - newChildren[newIdx], - expirationTime - )) - ) { - if (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); - invariant( - "function" === typeof iteratorFn, - "An object is not an iterable. This error is likely caused by a bug in React. Please file an issue." - ); - newChildrenIterable = iteratorFn.call(newChildrenIterable); - invariant( - null != newChildrenIterable, - "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) { - 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() - ) - if ( - ((step = updateFromMap( - oldFiber, - returnFiber, - newIdx, - step.value, - expirationTime - )), - null !== step) - ) { - if (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) { - "object" === typeof newChild && - null !== newChild && - newChild.type === REACT_FRAGMENT_TYPE && - null === newChild.key && - (newChild = newChild.props.children); - var isObject = "object" === typeof newChild && null !== newChild; - if (isObject) - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: - a: { - var key = newChild.key; - for (isObject = currentFirstChild; null !== isObject; ) { - if (isObject.key === key) - if ( - 10 === isObject.tag - ? newChild.type === REACT_FRAGMENT_TYPE - : isObject.type === newChild.type - ) { - deleteRemainingChildren(returnFiber, isObject.sibling); - currentFirstChild = useFiber( - isObject, - newChild.type === REACT_FRAGMENT_TYPE - ? newChild.props.children - : newChild.props, - expirationTime - ); - currentFirstChild.ref = coerceRef( - returnFiber, - isObject, - newChild - ); - currentFirstChild["return"] = returnFiber; - returnFiber = currentFirstChild; - break a; - } else { - deleteRemainingChildren(returnFiber, isObject); - break; - } - else deleteChild(returnFiber, isObject); - isObject = isObject.sibling; - } - newChild.type === REACT_FRAGMENT_TYPE - ? ((currentFirstChild = createFiberFromFragment( - newChild.props.children, - returnFiber.mode, - expirationTime, - newChild.key - )), - (currentFirstChild["return"] = returnFiber), - (returnFiber = currentFirstChild)) - : ((expirationTime = createFiberFromElement( - newChild, - returnFiber.mode, - expirationTime - )), - (expirationTime.ref = coerceRef( - returnFiber, - currentFirstChild, - newChild - )), - (expirationTime["return"] = returnFiber), - (returnFiber = expirationTime)); - } - return placeSingleChild(returnFiber); - case REACT_PORTAL_TYPE: - a: { - for (isObject = newChild.key; null !== currentFirstChild; ) { - if (currentFirstChild.key === isObject) - 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; - } else { - 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$1(newChild)) - return reconcileChildrenArray( - returnFiber, - currentFirstChild, - newChild, - expirationTime - ); - if (getIteratorFn(newChild)) - return reconcileChildrenIterator( - returnFiber, - currentFirstChild, - newChild, - expirationTime - ); - isObject && throwOnInvalidObjectType(returnFiber, newChild); - if ("undefined" === typeof newChild) - switch (returnFiber.tag) { - case 2: - case 1: - (expirationTime = returnFiber.type), - invariant( - !1, - "%s(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.", - expirationTime.displayName || expirationTime.name || "Component" - ); - } - return deleteRemainingChildren(returnFiber, currentFirstChild); - }; -} -var reconcileChildFibers = ChildReconciler(!0), - mountChildFibers = ChildReconciler(!1); -function ReactFiberBeginWork( - config, - hostContext, - legacyContext, - newContext, - hydrationContext, - scheduleWork, - computeExpirationForFiber -) { - function reconcileChildren(current, workInProgress, nextChildren) { - reconcileChildrenAtExpirationTime( - current, - workInProgress, - nextChildren, - workInProgress.expirationTime - ); - } - function reconcileChildrenAtExpirationTime( - current, - workInProgress, - nextChildren, - renderExpirationTime - ) { - workInProgress.child = - null === current - ? mountChildFibers( - workInProgress, - null, - nextChildren, - renderExpirationTime - ) - : reconcileChildFibers( - workInProgress, - current.child, - nextChildren, - renderExpirationTime - ); - } - function markRef(current, workInProgress) { - var ref = workInProgress.ref; - if ( - (null === current && null !== ref) || - (null !== current && current.ref !== ref) - ) - workInProgress.effectTag |= 128; - } - function finishClassComponent( - current, - workInProgress, - shouldUpdate, - hasContext, - didCaptureError, - renderExpirationTime - ) { - markRef(current, workInProgress); - if (!shouldUpdate && !didCaptureError) - return ( - hasContext && invalidateContextProvider(workInProgress, !1), - bailoutOnAlreadyFinishedWork(current, workInProgress) - ); - shouldUpdate = workInProgress.stateNode; - ReactCurrentOwner.current = workInProgress; - var nextChildren = didCaptureError ? null : shouldUpdate.render(); - workInProgress.effectTag |= 1; - didCaptureError && - (reconcileChildrenAtExpirationTime( - current, - workInProgress, - null, - renderExpirationTime - ), - (workInProgress.child = null)); - reconcileChildrenAtExpirationTime( - current, - workInProgress, - nextChildren, - renderExpirationTime - ); - workInProgress.memoizedState = shouldUpdate.state; - workInProgress.memoizedProps = shouldUpdate.props; - hasContext && invalidateContextProvider(workInProgress, !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 propagateContextChange( - workInProgress, - context, - changedBits, - renderExpirationTime - ) { - var fiber = workInProgress.child; - for ( - null !== fiber && (fiber["return"] = workInProgress); - null !== fiber; - - ) { - switch (fiber.tag) { - case 12: - var nextFiber = fiber.stateNode | 0; - if (fiber.type === context && 0 !== (nextFiber & changedBits)) { - for (nextFiber = fiber; null !== nextFiber; ) { - var alternate = nextFiber.alternate; - if ( - 0 === nextFiber.expirationTime || - nextFiber.expirationTime > renderExpirationTime - ) - (nextFiber.expirationTime = renderExpirationTime), - null !== alternate && - (0 === alternate.expirationTime || - alternate.expirationTime > renderExpirationTime) && - (alternate.expirationTime = renderExpirationTime); - else if ( - null !== alternate && - (0 === alternate.expirationTime || - alternate.expirationTime > renderExpirationTime) - ) - alternate.expirationTime = renderExpirationTime; - else break; - nextFiber = nextFiber["return"]; - } - nextFiber = null; - } else nextFiber = fiber.child; - break; - case 13: - nextFiber = fiber.type === workInProgress.type ? null : fiber.child; - break; - default: - nextFiber = fiber.child; - } - if (null !== nextFiber) nextFiber["return"] = fiber; - else - for (nextFiber = fiber; null !== nextFiber; ) { - if (nextFiber === workInProgress) { - nextFiber = null; - break; - } - fiber = nextFiber.sibling; - if (null !== fiber) { - nextFiber = fiber; - break; - } - nextFiber = nextFiber["return"]; - } - fiber = nextFiber; - } - } - function updateContextProvider( - current, - workInProgress, - renderExpirationTime - ) { - var context = workInProgress.type._context, - newProps = workInProgress.pendingProps, - oldProps = workInProgress.memoizedProps; - if (!hasLegacyContextChanged() && oldProps === newProps) - return ( - (workInProgress.stateNode = 0), - pushProvider(workInProgress), - bailoutOnAlreadyFinishedWork(current, workInProgress) - ); - var newValue = newProps.value; - workInProgress.memoizedProps = newProps; - if (null === oldProps) newValue = 1073741823; - else if (oldProps.value === newProps.value) { - if (oldProps.children === newProps.children) - return ( - (workInProgress.stateNode = 0), - pushProvider(workInProgress), - bailoutOnAlreadyFinishedWork(current, workInProgress) - ); - newValue = 0; - } else { - var oldValue = oldProps.value; - if ( - (oldValue === newValue && - (0 !== oldValue || 1 / oldValue === 1 / newValue)) || - (oldValue !== oldValue && newValue !== newValue) - ) { - if (oldProps.children === newProps.children) - return ( - (workInProgress.stateNode = 0), - pushProvider(workInProgress), - bailoutOnAlreadyFinishedWork(current, workInProgress) - ); - newValue = 0; - } else if ( - ((newValue = - "function" === typeof context._calculateChangedBits - ? context._calculateChangedBits(oldValue, newValue) - : 1073741823), - (newValue |= 0), - 0 === newValue) - ) { - if (oldProps.children === newProps.children) - return ( - (workInProgress.stateNode = 0), - pushProvider(workInProgress), - bailoutOnAlreadyFinishedWork(current, workInProgress) - ); - } else - propagateContextChange( - workInProgress, - context, - newValue, - renderExpirationTime - ); - } - workInProgress.stateNode = newValue; - pushProvider(workInProgress); - reconcileChildren(current, workInProgress, newProps.children); - return workInProgress.child; - } - function bailoutOnAlreadyFinishedWork(current, workInProgress) { - invariant( - null === current || workInProgress.child === current.child, - "Resuming work not yet implemented." - ); - if (null !== workInProgress.child) { - current = workInProgress.child; - var newChild = createWorkInProgress( - current, - current.pendingProps, - current.expirationTime - ); - workInProgress.child = newChild; - for (newChild["return"] = workInProgress; null !== current.sibling; ) - (current = current.sibling), - (newChild = newChild.sibling = createWorkInProgress( - current, - current.pendingProps, - current.expirationTime - )), - (newChild["return"] = workInProgress); - newChild.sibling = null; - } - return workInProgress.child; - } - var shouldSetTextContent = config.shouldSetTextContent, - shouldDeprioritizeSubtree = config.shouldDeprioritizeSubtree, - pushHostContext = hostContext.pushHostContext, - pushHostContainer = hostContext.pushHostContainer, - pushProvider = newContext.pushProvider, - getMaskedContext = legacyContext.getMaskedContext, - getUnmaskedContext = legacyContext.getUnmaskedContext, - hasLegacyContextChanged = legacyContext.hasContextChanged, - pushLegacyContextProvider = legacyContext.pushContextProvider, - pushTopLevelContextObject = legacyContext.pushTopLevelContextObject, - invalidateContextProvider = legacyContext.invalidateContextProvider, - enterHydrationState = hydrationContext.enterHydrationState, - resetHydrationState = hydrationContext.resetHydrationState, - tryToClaimNextHydratableInstance = - hydrationContext.tryToClaimNextHydratableInstance; - config = ReactFiberClassComponent( - legacyContext, - scheduleWork, - computeExpirationForFiber, - function(workInProgress, nextProps) { - workInProgress.memoizedProps = nextProps; - }, - function(workInProgress, nextState) { - workInProgress.memoizedState = nextState; - } - ); - var adoptClassInstance = config.adoptClassInstance, - callGetDerivedStateFromProps = config.callGetDerivedStateFromProps, - constructClassInstance = config.constructClassInstance, - mountClassInstance = config.mountClassInstance, - resumeMountClassInstance = config.resumeMountClassInstance, - updateClassInstance = config.updateClassInstance; - return { - beginWork: function(current, workInProgress, renderExpirationTime) { - if ( - 0 === workInProgress.expirationTime || - workInProgress.expirationTime > renderExpirationTime - ) { - switch (workInProgress.tag) { - case 3: - pushHostRootContext(workInProgress); - break; - case 2: - pushLegacyContextProvider(workInProgress); - break; - case 4: - pushHostContainer( - workInProgress, - workInProgress.stateNode.containerInfo - ); - break; - case 13: - pushProvider(workInProgress); - } - return null; - } - switch (workInProgress.tag) { - case 0: - invariant( - null === current, - "An indeterminate component should never have mounted. This error is likely caused by a bug in React. Please file an issue." - ); - var fn = workInProgress.type, - props = workInProgress.pendingProps, - unmaskedContext = getUnmaskedContext(workInProgress); - unmaskedContext = getMaskedContext(workInProgress, unmaskedContext); - fn = fn(props, unmaskedContext); - workInProgress.effectTag |= 1; - "object" === typeof fn && - null !== fn && - "function" === typeof fn.render && - void 0 === fn.$$typeof - ? ((unmaskedContext = workInProgress.type), - (workInProgress.tag = 2), - (workInProgress.memoizedState = - null !== fn.state && void 0 !== fn.state ? fn.state : null), - "function" === typeof unmaskedContext.getDerivedStateFromProps && - ((props = callGetDerivedStateFromProps( - workInProgress, - fn, - props, - workInProgress.memoizedState - )), - null !== props && - void 0 !== props && - (workInProgress.memoizedState = Object.assign( - {}, - workInProgress.memoizedState, - props - ))), - (props = pushLegacyContextProvider(workInProgress)), - adoptClassInstance(workInProgress, fn), - mountClassInstance(workInProgress, renderExpirationTime), - (current = finishClassComponent( - current, - workInProgress, - !0, - props, - !1, - renderExpirationTime - ))) - : ((workInProgress.tag = 1), - reconcileChildren(current, workInProgress, fn), - (workInProgress.memoizedProps = props), - (current = workInProgress.child)); - return current; - case 1: - return ( - (props = workInProgress.type), - (renderExpirationTime = workInProgress.pendingProps), - hasLegacyContextChanged() || - workInProgress.memoizedProps !== renderExpirationTime - ? ((fn = getUnmaskedContext(workInProgress)), - (fn = getMaskedContext(workInProgress, fn)), - (props = props(renderExpirationTime, fn)), - (workInProgress.effectTag |= 1), - reconcileChildren(current, workInProgress, props), - (workInProgress.memoizedProps = renderExpirationTime), - (current = workInProgress.child)) - : (current = bailoutOnAlreadyFinishedWork( - current, - workInProgress - )), - current - ); - case 2: - props = pushLegacyContextProvider(workInProgress); - null === current - ? null === workInProgress.stateNode - ? (constructClassInstance( - workInProgress, - workInProgress.pendingProps - ), - mountClassInstance(workInProgress, renderExpirationTime), - (fn = !0)) - : (fn = resumeMountClassInstance( - workInProgress, - renderExpirationTime - )) - : (fn = updateClassInstance( - current, - workInProgress, - renderExpirationTime - )); - unmaskedContext = !1; - var updateQueue = workInProgress.updateQueue; - null !== updateQueue && - null !== updateQueue.capturedValues && - (unmaskedContext = fn = !0); - return finishClassComponent( - current, - workInProgress, - fn, - props, - unmaskedContext, - renderExpirationTime - ); - case 3: - a: if ( - (pushHostRootContext(workInProgress), - (fn = workInProgress.updateQueue), - null !== fn) - ) { - unmaskedContext = workInProgress.memoizedState; - props = processUpdateQueue( - current, - workInProgress, - fn, - null, - null, - renderExpirationTime - ); - workInProgress.memoizedState = props; - fn = workInProgress.updateQueue; - if (null !== fn && null !== fn.capturedValues) fn = null; - else if (unmaskedContext === props) { - resetHydrationState(); - current = bailoutOnAlreadyFinishedWork(current, workInProgress); - break a; - } else fn = props.element; - unmaskedContext = workInProgress.stateNode; - (null === current || null === current.child) && - unmaskedContext.hydrate && - enterHydrationState(workInProgress) - ? ((workInProgress.effectTag |= 2), - (workInProgress.child = mountChildFibers( - workInProgress, - null, - fn, - renderExpirationTime - ))) - : (resetHydrationState(), - reconcileChildren(current, workInProgress, fn)); - workInProgress.memoizedState = props; - current = workInProgress.child; - } else - resetHydrationState(), - (current = bailoutOnAlreadyFinishedWork(current, workInProgress)); - return current; - case 5: - a: { - pushHostContext(workInProgress); - null === current && - tryToClaimNextHydratableInstance(workInProgress); - props = workInProgress.type; - updateQueue = workInProgress.memoizedProps; - fn = workInProgress.pendingProps; - unmaskedContext = null !== current ? current.memoizedProps : null; - if (!hasLegacyContextChanged() && updateQueue === fn) { - if ( - (updateQueue = - workInProgress.mode & 1 && - shouldDeprioritizeSubtree(props, fn)) - ) - workInProgress.expirationTime = 1073741823; - if (!updateQueue || 1073741823 !== renderExpirationTime) { - current = bailoutOnAlreadyFinishedWork(current, workInProgress); - break a; - } - } - updateQueue = fn.children; - shouldSetTextContent(props, fn) - ? (updateQueue = null) - : unmaskedContext && - shouldSetTextContent(props, unmaskedContext) && - (workInProgress.effectTag |= 16); - markRef(current, workInProgress); - 1073741823 !== renderExpirationTime && - workInProgress.mode & 1 && - shouldDeprioritizeSubtree(props, fn) - ? ((workInProgress.expirationTime = 1073741823), - (workInProgress.memoizedProps = fn), - (current = null)) - : (reconcileChildren(current, workInProgress, updateQueue), - (workInProgress.memoizedProps = fn), - (current = workInProgress.child)); - } - return current; - case 6: - return ( - null === current && - tryToClaimNextHydratableInstance(workInProgress), - (workInProgress.memoizedProps = workInProgress.pendingProps), - null - ); - case 8: - workInProgress.tag = 7; - case 7: - return ( - (props = workInProgress.pendingProps), - hasLegacyContextChanged() || - workInProgress.memoizedProps !== props || - (props = workInProgress.memoizedProps), - (fn = props.children), - (workInProgress.stateNode = - null === current - ? mountChildFibers( - workInProgress, - workInProgress.stateNode, - fn, - renderExpirationTime - ) - : reconcileChildFibers( - workInProgress, - current.stateNode, - fn, - renderExpirationTime - )), - (workInProgress.memoizedProps = props), - workInProgress.stateNode - ); - case 9: - return null; - case 4: - return ( - pushHostContainer( - workInProgress, - workInProgress.stateNode.containerInfo - ), - (props = workInProgress.pendingProps), - hasLegacyContextChanged() || workInProgress.memoizedProps !== props - ? (null === current - ? (workInProgress.child = reconcileChildFibers( - workInProgress, - null, - props, - renderExpirationTime - )) - : reconcileChildren(current, workInProgress, props), - (workInProgress.memoizedProps = props), - (current = workInProgress.child)) - : (current = bailoutOnAlreadyFinishedWork( - current, - workInProgress - )), - current - ); - case 14: - return ( - (renderExpirationTime = workInProgress.type.render), - (renderExpirationTime = renderExpirationTime( - workInProgress.pendingProps, - workInProgress.ref - )), - reconcileChildren(current, workInProgress, renderExpirationTime), - (workInProgress.memoizedProps = renderExpirationTime), - workInProgress.child - ); - case 10: - return ( - (renderExpirationTime = workInProgress.pendingProps), - hasLegacyContextChanged() || - workInProgress.memoizedProps !== renderExpirationTime - ? (reconcileChildren( - current, - workInProgress, - renderExpirationTime - ), - (workInProgress.memoizedProps = renderExpirationTime), - (current = workInProgress.child)) - : (current = bailoutOnAlreadyFinishedWork( - current, - workInProgress - )), - current - ); - case 11: - return ( - (renderExpirationTime = workInProgress.pendingProps.children), - hasLegacyContextChanged() || - (null !== renderExpirationTime && - workInProgress.memoizedProps !== renderExpirationTime) - ? (reconcileChildren( - current, - workInProgress, - renderExpirationTime - ), - (workInProgress.memoizedProps = renderExpirationTime), - (current = workInProgress.child)) - : (current = bailoutOnAlreadyFinishedWork( - current, - workInProgress - )), - current - ); - case 13: - return updateContextProvider( - current, - workInProgress, - renderExpirationTime - ); - case 12: - a: { - fn = workInProgress.type; - unmaskedContext = workInProgress.pendingProps; - updateQueue = workInProgress.memoizedProps; - props = fn._currentValue; - var changedBits = fn._changedBits; - if ( - hasLegacyContextChanged() || - 0 !== changedBits || - updateQueue !== unmaskedContext - ) { - workInProgress.memoizedProps = unmaskedContext; - var observedBits = unmaskedContext.unstable_observedBits; - if (void 0 === observedBits || null === observedBits) - observedBits = 1073741823; - workInProgress.stateNode = observedBits; - if (0 !== (changedBits & observedBits)) - propagateContextChange( - workInProgress, - fn, - changedBits, - renderExpirationTime - ); - else if (updateQueue === unmaskedContext) { - current = bailoutOnAlreadyFinishedWork(current, workInProgress); - break a; - } - renderExpirationTime = unmaskedContext.children; - renderExpirationTime = renderExpirationTime(props); - reconcileChildren(current, workInProgress, renderExpirationTime); - current = workInProgress.child; - } else - current = bailoutOnAlreadyFinishedWork(current, workInProgress); - } - return current; - default: - invariant( - !1, - "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." - ); - } - } - }; -} -function ReactFiberCompleteWork( - config, - hostContext, - legacyContext, - newContext, - hydrationContext -) { - function markUpdate(workInProgress) { - workInProgress.effectTag |= 4; - } - function appendAllChildren(parent, workInProgress) { - for (var node = workInProgress.child; null !== node; ) { - if (5 === node.tag || 6 === node.tag) - appendInitialChild(parent, 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; - } - } - var createInstance = config.createInstance, - createTextInstance = config.createTextInstance, - appendInitialChild = config.appendInitialChild, - finalizeInitialChildren = config.finalizeInitialChildren, - prepareUpdate = config.prepareUpdate, - persistence = config.persistence, - getRootHostContainer = hostContext.getRootHostContainer, - popHostContext = hostContext.popHostContext, - getHostContext = hostContext.getHostContext, - popHostContainer = hostContext.popHostContainer, - popLegacyContextProvider = legacyContext.popContextProvider, - popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject, - popProvider = newContext.popProvider, - prepareToHydrateHostInstance = - hydrationContext.prepareToHydrateHostInstance, - prepareToHydrateHostTextInstance = - hydrationContext.prepareToHydrateHostTextInstance, - popHydrationState = hydrationContext.popHydrationState, - updateHostContainer = void 0, - updateHostComponent = void 0, - updateHostText = void 0; - if (config.mutation) invariant(!1, "Mutating reconciler is disabled."); - else if (persistence) { - var cloneInstance = persistence.cloneInstance, - createContainerChildSet = persistence.createContainerChildSet, - appendChildToContainerChildSet = - persistence.appendChildToContainerChildSet, - finalizeContainerChildren = persistence.finalizeContainerChildren; - updateHostContainer = function(workInProgress) { - var portalOrRoot = workInProgress.stateNode; - if (null !== workInProgress.firstEffect) { - var container = portalOrRoot.containerInfo, - newChildSet = createContainerChildSet(container); - a: for (var node = workInProgress.child; null !== node; ) { - if (5 === node.tag || 6 === node.tag) - appendChildToContainerChildSet(newChildSet, node.stateNode); - else if (4 !== node.tag && null !== node.child) { - node.child["return"] = node; - node = node.child; - continue; - } - if (node === workInProgress) break a; - for (; null === node.sibling; ) { - if (null === node["return"] || node["return"] === workInProgress) - break a; - node = node["return"]; - } - node.sibling["return"] = node["return"]; - node = node.sibling; - } - portalOrRoot.pendingChildren = newChildSet; - markUpdate(workInProgress); - finalizeContainerChildren(container, newChildSet); - } - }; - updateHostComponent = function( - current, - workInProgress, - updatePayload, - type, - oldProps, - newProps, - rootContainerInstance, - currentHostContext - ) { - var childrenUnchanged = null === workInProgress.firstEffect; - current = current.stateNode; - childrenUnchanged && null === updatePayload - ? (workInProgress.stateNode = current) - : ((updatePayload = cloneInstance( - current, - updatePayload, - type, - oldProps, - newProps, - workInProgress, - childrenUnchanged, - workInProgress.stateNode - )), - finalizeInitialChildren( - updatePayload, - type, - newProps, - rootContainerInstance, - currentHostContext - ) && markUpdate(workInProgress), - (workInProgress.stateNode = updatePayload), - childrenUnchanged - ? markUpdate(workInProgress) - : appendAllChildren(updatePayload, workInProgress)); - }; - updateHostText = function(current, workInProgress, oldText, newText) { - oldText !== newText && - ((current = getRootHostContainer()), - (oldText = getHostContext()), - (workInProgress.stateNode = createTextInstance( - newText, - current, - oldText, - workInProgress - )), - markUpdate(workInProgress)); - }; - } else invariant(!1, "Noop reconciler is disabled."); - return { - completeWork: function(current, workInProgress, renderExpirationTime) { - var newProps = workInProgress.pendingProps; - switch (workInProgress.tag) { - case 1: - return null; - case 2: - return ( - popLegacyContextProvider(workInProgress), - (current = workInProgress.stateNode), - (newProps = workInProgress.updateQueue), - null !== newProps && - null !== newProps.capturedValues && - ((workInProgress.effectTag &= -65), - "function" === typeof current.componentDidCatch - ? (workInProgress.effectTag |= 256) - : (newProps.capturedValues = null)), - null - ); - case 3: - popHostContainer(workInProgress); - popTopLevelLegacyContextObject(workInProgress); - newProps = workInProgress.stateNode; - newProps.pendingContext && - ((newProps.context = newProps.pendingContext), - (newProps.pendingContext = null)); - if (null === current || null === current.child) - popHydrationState(workInProgress), (workInProgress.effectTag &= -3); - updateHostContainer(workInProgress); - current = workInProgress.updateQueue; - null !== current && - null !== current.capturedValues && - (workInProgress.effectTag |= 256); - return null; - case 5: - popHostContext(workInProgress); - renderExpirationTime = getRootHostContainer(); - var type = workInProgress.type; - if (null !== current && null != workInProgress.stateNode) { - var oldProps = current.memoizedProps, - _instance = workInProgress.stateNode, - currentHostContext = getHostContext(); - _instance = prepareUpdate( - _instance, - type, - oldProps, - newProps, - renderExpirationTime, - currentHostContext - ); - updateHostComponent( - current, - workInProgress, - _instance, - type, - oldProps, - newProps, - renderExpirationTime, - currentHostContext - ); - current.ref !== workInProgress.ref && - (workInProgress.effectTag |= 128); - } else { - if (!newProps) - return ( - invariant( - null !== workInProgress.stateNode, - "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." - ), - null - ); - current = getHostContext(); - popHydrationState(workInProgress) - ? prepareToHydrateHostInstance( - workInProgress, - renderExpirationTime, - current - ) && markUpdate(workInProgress) - : ((oldProps = createInstance( - type, - newProps, - renderExpirationTime, - current, - workInProgress - )), - appendAllChildren(oldProps, workInProgress), - finalizeInitialChildren( - oldProps, - type, - newProps, - renderExpirationTime, - current - ) && markUpdate(workInProgress), - (workInProgress.stateNode = oldProps)); - null !== workInProgress.ref && (workInProgress.effectTag |= 128); - } - return null; - case 6: - if (current && null != workInProgress.stateNode) - updateHostText( - current, - workInProgress, - current.memoizedProps, - newProps - ); - else { - if ("string" !== typeof newProps) - return ( - invariant( - null !== workInProgress.stateNode, - "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." - ), - null - ); - current = getRootHostContainer(); - renderExpirationTime = getHostContext(); - popHydrationState(workInProgress) - ? prepareToHydrateHostTextInstance(workInProgress) && - markUpdate(workInProgress) - : (workInProgress.stateNode = createTextInstance( - newProps, - current, - renderExpirationTime, - workInProgress - )); - } - return null; - case 7: - newProps = workInProgress.memoizedProps; - invariant( - newProps, - "Should be resolved by now. This error is likely caused by a bug in React. Please file an issue." - ); - workInProgress.tag = 8; - type = []; - a: for ( - (oldProps = workInProgress.stateNode) && - (oldProps["return"] = workInProgress); - null !== oldProps; - - ) { - if (5 === oldProps.tag || 6 === oldProps.tag || 4 === oldProps.tag) - invariant(!1, "A call cannot have host component children."); - else if (9 === oldProps.tag) type.push(oldProps.pendingProps.value); - else if (null !== oldProps.child) { - oldProps.child["return"] = oldProps; - oldProps = oldProps.child; - continue; - } - for (; null === oldProps.sibling; ) { - if ( - null === oldProps["return"] || - oldProps["return"] === workInProgress - ) - break a; - oldProps = oldProps["return"]; - } - oldProps.sibling["return"] = oldProps["return"]; - oldProps = oldProps.sibling; - } - oldProps = newProps.handler; - newProps = oldProps(newProps.props, type); - workInProgress.child = reconcileChildFibers( - workInProgress, - null !== current ? current.child : null, - newProps, - renderExpirationTime - ); - return workInProgress.child; - case 8: - return (workInProgress.tag = 7), null; - case 9: - return null; - case 14: - return null; - case 10: - return null; - case 11: - return null; - case 4: - return ( - popHostContainer(workInProgress), - updateHostContainer(workInProgress), - null - ); - case 13: - return popProvider(workInProgress), null; - case 12: - return null; - case 0: - invariant( - !1, - "An indeterminate component should have become determinate before completing. This error is likely caused by a bug in React. Please file an issue." - ); - default: - invariant( - !1, - "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." - ); - } - } - }; -} -function ReactFiberUnwindWork( - hostContext, - legacyContext, - newContext, - scheduleWork, - isAlreadyFailedLegacyErrorBoundary -) { - var popHostContainer = hostContext.popHostContainer, - popHostContext = hostContext.popHostContext, - popLegacyContextProvider = legacyContext.popContextProvider, - popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject, - popProvider = newContext.popProvider; - return { - throwException: function(returnFiber, sourceFiber, rawValue) { - sourceFiber.effectTag |= 512; - sourceFiber.firstEffect = sourceFiber.lastEffect = null; - sourceFiber = { - value: rawValue, - source: sourceFiber, - stack: getStackAddendumByWorkInProgressFiber(sourceFiber) - }; - do { - switch (returnFiber.tag) { - case 3: - ensureUpdateQueues(returnFiber); - returnFiber.updateQueue.capturedValues = [sourceFiber]; - returnFiber.effectTag |= 1024; - return; - case 2: - if ( - ((rawValue = returnFiber.stateNode), - 0 === (returnFiber.effectTag & 64) && - null !== rawValue && - "function" === typeof rawValue.componentDidCatch && - !isAlreadyFailedLegacyErrorBoundary(rawValue)) - ) { - ensureUpdateQueues(returnFiber); - rawValue = returnFiber.updateQueue; - var capturedValues = rawValue.capturedValues; - null === capturedValues - ? (rawValue.capturedValues = [sourceFiber]) - : capturedValues.push(sourceFiber); - returnFiber.effectTag |= 1024; - return; - } - } - returnFiber = returnFiber["return"]; - } while (null !== returnFiber); - }, - unwindWork: function(workInProgress) { - switch (workInProgress.tag) { - case 2: - popLegacyContextProvider(workInProgress); - var effectTag = workInProgress.effectTag; - return effectTag & 1024 - ? ((workInProgress.effectTag = (effectTag & -1025) | 64), - workInProgress) - : null; - case 3: - return ( - popHostContainer(workInProgress), - popTopLevelLegacyContextObject(workInProgress), - (effectTag = workInProgress.effectTag), - effectTag & 1024 - ? ((workInProgress.effectTag = (effectTag & -1025) | 64), - workInProgress) - : null - ); - case 5: - return popHostContext(workInProgress), null; - case 4: - return popHostContainer(workInProgress), null; - case 13: - return popProvider(workInProgress), null; - default: - return null; - } - }, - unwindInterruptedWork: function(interruptedWork) { - switch (interruptedWork.tag) { - case 2: - popLegacyContextProvider(interruptedWork); - break; - case 3: - popHostContainer(interruptedWork); - popTopLevelLegacyContextObject(interruptedWork); - break; - case 5: - popHostContext(interruptedWork); - break; - case 4: - popHostContainer(interruptedWork); - break; - case 13: - popProvider(interruptedWork); - } - } - }; -} -function logError(boundary, errorInfo) { - var source = errorInfo.source; - null === errorInfo.stack && getStackAddendumByWorkInProgressFiber(source); - null !== source && getComponentName(source); - errorInfo = errorInfo.value; - null !== boundary && 2 === boundary.tag && getComponentName(boundary); - try { - (errorInfo && errorInfo.suppressReactErrorLogging) || - console.error(errorInfo); - } catch (e) { - (e && e.suppressReactErrorLogging) || console.error(e); - } -} -function ReactFiberCommitWork( - config, - captureError, - scheduleWork, - computeExpirationForFiber, - markLegacyErrorBoundaryAsFailed -) { - function safelyDetachRef(current) { - var ref = current.ref; - if (null !== ref) - if ("function" === typeof ref) - try { - ref(null); - } catch (refError) { - captureError(current, refError); - } - else ref.current = null; - } - function commitBeforeMutationLifeCycles(current, finishedWork) { - switch (finishedWork.tag) { - case 2: - if (finishedWork.effectTag & 2048 && null !== current) { - var prevProps = current.memoizedProps, - prevState = current.memoizedState; - current = finishedWork.stateNode; - current.props = finishedWork.memoizedProps; - current.state = finishedWork.memoizedState; - finishedWork = current.getSnapshotBeforeUpdate(prevProps, prevState); - current.__reactInternalSnapshotBeforeUpdate = finishedWork; - } - break; - case 3: - case 5: - case 6: - case 4: - break; - default: - invariant( - !1, - "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 commitLifeCycles(finishedRoot, current, finishedWork) { - switch (finishedWork.tag) { - case 2: - finishedRoot = finishedWork.stateNode; - if (finishedWork.effectTag & 4) - if (null === current) - (finishedRoot.props = finishedWork.memoizedProps), - (finishedRoot.state = finishedWork.memoizedState), - finishedRoot.componentDidMount(); - else { - var prevProps = current.memoizedProps; - current = current.memoizedState; - finishedRoot.props = finishedWork.memoizedProps; - finishedRoot.state = finishedWork.memoizedState; - finishedRoot.componentDidUpdate( - prevProps, - current, - finishedRoot.__reactInternalSnapshotBeforeUpdate - ); - } - finishedWork = finishedWork.updateQueue; - null !== finishedWork && commitCallbacks(finishedWork, finishedRoot); - break; - case 3: - current = finishedWork.updateQueue; - if (null !== current) { - finishedRoot = null; - if (null !== finishedWork.child) - switch (finishedWork.child.tag) { - case 5: - finishedRoot = getPublicInstance(finishedWork.child.stateNode); - break; - case 2: - finishedRoot = finishedWork.child.stateNode; - } - commitCallbacks(current, finishedRoot); - } - break; - case 5: - finishedRoot = finishedWork.stateNode; - null === current && - finishedWork.effectTag & 4 && - commitMount( - finishedRoot, - finishedWork.type, - finishedWork.memoizedProps, - finishedWork - ); - break; - case 6: - break; - case 4: - break; - default: - invariant( - !1, - "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 commitErrorLogging(finishedWork, onUncaughtError) { - switch (finishedWork.tag) { - case 2: - var ctor = finishedWork.type; - onUncaughtError = finishedWork.stateNode; - var updateQueue = finishedWork.updateQueue; - invariant( - null !== updateQueue && null !== updateQueue.capturedValues, - "An error logging effect should not have been scheduled if no errors were captured. This error is likely caused by a bug in React. Please file an issue." - ); - var capturedErrors = updateQueue.capturedValues; - updateQueue.capturedValues = null; - "function" !== typeof ctor.getDerivedStateFromCatch && - markLegacyErrorBoundaryAsFailed(onUncaughtError); - onUncaughtError.props = finishedWork.memoizedProps; - onUncaughtError.state = finishedWork.memoizedState; - for (ctor = 0; ctor < capturedErrors.length; ctor++) { - updateQueue = capturedErrors[ctor]; - var _error = updateQueue.value, - stack = updateQueue.stack; - logError(finishedWork, updateQueue); - onUncaughtError.componentDidCatch(_error, { - componentStack: null !== stack ? stack : "" - }); - } - break; - case 3: - ctor = finishedWork.updateQueue; - invariant( - null !== ctor && null !== ctor.capturedValues, - "An error logging effect should not have been scheduled if no errors were captured. This error is likely caused by a bug in React. Please file an issue." - ); - capturedErrors = ctor.capturedValues; - ctor.capturedValues = null; - for (ctor = 0; ctor < capturedErrors.length; ctor++) - (updateQueue = capturedErrors[ctor]), - logError(finishedWork, updateQueue), - onUncaughtError(updateQueue.value); - break; - default: - invariant( - !1, - "This unit of work tag cannot capture errors. This error is likely caused by a bug in React. Please file an issue." - ); - } - } - function commitAttachRef(finishedWork) { - var ref = finishedWork.ref; - if (null !== ref) { - var _instance6 = finishedWork.stateNode; - switch (finishedWork.tag) { - case 5: - finishedWork = getPublicInstance(_instance6); - break; - default: - finishedWork = _instance6; - } - "function" === typeof ref - ? ref(finishedWork) - : (ref.current = finishedWork); - } - } - function commitDetachRef(current) { - current = current.ref; - null !== current && - ("function" === typeof current - ? current(null) - : (current.current = null)); - } - function commitNestedUnmounts(root) { - for (var node = root; ; ) { - var current = node; - "function" === typeof onCommitUnmount && onCommitUnmount(current); - switch (current.tag) { - case 2: - safelyDetachRef(current); - var _instance7 = current.stateNode; - if ("function" === typeof _instance7.componentWillUnmount) - try { - (_instance7.props = current.memoizedProps), - (_instance7.state = current.memoizedState), - _instance7.componentWillUnmount(); - } catch (unmountError) { - captureError(current, unmountError); - } - break; - case 5: - safelyDetachRef(current); - break; - case 7: - commitNestedUnmounts(current.stateNode); - break; - case 4: - persistence && emptyPortalContainer(current); - } - if (null === node.child || (mutation && 4 === node.tag)) { - if (node === root) break; - for (; null === node.sibling; ) { - if (null === node["return"] || node["return"] === root) return; - node = node["return"]; - } - node.sibling["return"] = node["return"]; - node = node.sibling; - } else (node.child["return"] = node), (node = node.child); - } - } - var getPublicInstance = config.getPublicInstance, - mutation = config.mutation, - persistence = config.persistence, - emptyPortalContainer = void 0; - if (!mutation) { - var commitContainer = void 0; - if (persistence) { - var replaceContainerChildren = persistence.replaceContainerChildren, - createContainerChildSet = persistence.createContainerChildSet; - emptyPortalContainer = function(current) { - current = current.stateNode.containerInfo; - var emptyChildSet = createContainerChildSet(current); - replaceContainerChildren(current, emptyChildSet); - }; - commitContainer = function(finishedWork) { - switch (finishedWork.tag) { - case 2: - break; - case 5: - break; - case 6: - break; - case 3: - case 4: - finishedWork = finishedWork.stateNode; - replaceContainerChildren( - finishedWork.containerInfo, - finishedWork.pendingChildren - ); - break; - default: - invariant( - !1, - "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." - ); - } - }; - } else commitContainer = function() {}; - return { - commitResetTextContent: function() {}, - commitPlacement: function() {}, - commitDeletion: function(current) { - commitNestedUnmounts(current); - current["return"] = null; - current.child = null; - current.alternate && - ((current.alternate.child = null), - (current.alternate["return"] = null)); - }, - commitWork: function(current, finishedWork) { - commitContainer(finishedWork); - }, - commitLifeCycles: commitLifeCycles, - commitBeforeMutationLifeCycles: commitBeforeMutationLifeCycles, - commitErrorLogging: commitErrorLogging, - commitAttachRef: commitAttachRef, - commitDetachRef: commitDetachRef - }; - } - var commitMount = mutation.commitMount; - invariant(!1, "Mutating reconciler is disabled."); -} -var NO_CONTEXT = {}; -function ReactFiberHostContext(config, stack) { - function requiredContext(c) { - invariant( - c !== NO_CONTEXT, - "Expected host context to exist. This error is likely caused by a bug in React. Please file an issue." - ); - return c; - } - var getChildHostContext = config.getChildHostContext, - getRootHostContext = config.getRootHostContext; - config = stack.createCursor; - var push = stack.push, - pop = stack.pop, - contextStackCursor = config(NO_CONTEXT), - contextFiberStackCursor = config(NO_CONTEXT), - rootInstanceStackCursor = config(NO_CONTEXT); - return { - getHostContext: function() { - return requiredContext(contextStackCursor.current); - }, - getRootHostContainer: function() { - return requiredContext(rootInstanceStackCursor.current); - }, - popHostContainer: function(fiber) { - pop(contextStackCursor, fiber); - pop(contextFiberStackCursor, fiber); - pop(rootInstanceStackCursor, fiber); - }, - popHostContext: function(fiber) { - contextFiberStackCursor.current === fiber && - (pop(contextStackCursor, fiber), pop(contextFiberStackCursor, fiber)); - }, - pushHostContainer: function(fiber, nextRootInstance) { - push(rootInstanceStackCursor, nextRootInstance, fiber); - push(contextFiberStackCursor, fiber, fiber); - push(contextStackCursor, NO_CONTEXT, fiber); - nextRootInstance = getRootHostContext(nextRootInstance); - pop(contextStackCursor, fiber); - push(contextStackCursor, nextRootInstance, fiber); - }, - pushHostContext: function(fiber) { - var rootInstance = requiredContext(rootInstanceStackCursor.current), - context = requiredContext(contextStackCursor.current); - rootInstance = getChildHostContext(context, fiber.type, rootInstance); - context !== rootInstance && - (push(contextFiberStackCursor, fiber, fiber), - push(contextStackCursor, rootInstance, fiber)); - } - }; -} -function ReactFiberHydrationContext(config) { - function deleteHydratableInstance(returnFiber, instance) { - var fiber = new FiberNode(5, null, null, 0); - fiber.type = "DELETED"; - fiber.stateNode = instance; - fiber["return"] = returnFiber; - fiber.effectTag = 8; - null !== returnFiber.lastEffect - ? ((returnFiber.lastEffect.nextEffect = fiber), - (returnFiber.lastEffect = fiber)) - : (returnFiber.firstEffect = returnFiber.lastEffect = fiber); - } - function tryHydrate(fiber, nextInstance) { - switch (fiber.tag) { - case 5: - return ( - (nextInstance = canHydrateInstance( - nextInstance, - fiber.type, - fiber.pendingProps - )), - null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1 - ); - case 6: - return ( - (nextInstance = canHydrateTextInstance( - nextInstance, - fiber.pendingProps - )), - null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1 - ); - default: - return !1; - } - } - function popToNextHostParent(fiber) { - for ( - fiber = fiber["return"]; - null !== fiber && 5 !== fiber.tag && 3 !== fiber.tag; - - ) - fiber = fiber["return"]; - hydrationParentFiber = fiber; - } - var shouldSetTextContent = config.shouldSetTextContent; - config = config.hydration; - if (!config) - return { - enterHydrationState: function() { - return !1; - }, - resetHydrationState: function() {}, - tryToClaimNextHydratableInstance: function() {}, - prepareToHydrateHostInstance: function() { - invariant( - !1, - "Expected prepareToHydrateHostInstance() to never be called. This error is likely caused by a bug in React. Please file an issue." - ); - }, - prepareToHydrateHostTextInstance: function() { - invariant( - !1, - "Expected prepareToHydrateHostTextInstance() to never be called. This error is likely caused by a bug in React. Please file an issue." - ); - }, - popHydrationState: function() { - return !1; - } - }; - var canHydrateInstance = config.canHydrateInstance, - canHydrateTextInstance = config.canHydrateTextInstance, - getNextHydratableSibling = config.getNextHydratableSibling, - getFirstHydratableChild = config.getFirstHydratableChild, - hydrateInstance = config.hydrateInstance, - hydrateTextInstance = config.hydrateTextInstance, - hydrationParentFiber = null, - nextHydratableInstance = null, - isHydrating = !1; - return { - enterHydrationState: function(fiber) { - nextHydratableInstance = getFirstHydratableChild( - fiber.stateNode.containerInfo - ); - hydrationParentFiber = fiber; - return (isHydrating = !0); - }, - resetHydrationState: function() { - nextHydratableInstance = hydrationParentFiber = null; - isHydrating = !1; - }, - tryToClaimNextHydratableInstance: function(fiber) { - if (isHydrating) { - var nextInstance = nextHydratableInstance; - if (nextInstance) { - if (!tryHydrate(fiber, nextInstance)) { - nextInstance = getNextHydratableSibling(nextInstance); - if (!nextInstance || !tryHydrate(fiber, nextInstance)) { - fiber.effectTag |= 2; - isHydrating = !1; - hydrationParentFiber = fiber; - return; - } - deleteHydratableInstance( - hydrationParentFiber, - nextHydratableInstance - ); - } - hydrationParentFiber = fiber; - nextHydratableInstance = getFirstHydratableChild(nextInstance); - } else - (fiber.effectTag |= 2), - (isHydrating = !1), - (hydrationParentFiber = fiber); - } - }, - prepareToHydrateHostInstance: function( - fiber, - rootContainerInstance, - hostContext - ) { - rootContainerInstance = hydrateInstance( - fiber.stateNode, - fiber.type, - fiber.memoizedProps, - rootContainerInstance, - hostContext, - fiber - ); - fiber.updateQueue = rootContainerInstance; - return null !== rootContainerInstance ? !0 : !1; - }, - prepareToHydrateHostTextInstance: function(fiber) { - return hydrateTextInstance(fiber.stateNode, fiber.memoizedProps, fiber); - }, - popHydrationState: function(fiber) { - if (fiber !== hydrationParentFiber) return !1; - if (!isHydrating) - return popToNextHostParent(fiber), (isHydrating = !0), !1; - var type = fiber.type; - if ( - 5 !== fiber.tag || - ("head" !== type && - "body" !== type && - !shouldSetTextContent(type, fiber.memoizedProps)) - ) - for (type = nextHydratableInstance; type; ) - deleteHydratableInstance(fiber, type), - (type = getNextHydratableSibling(type)); - popToNextHostParent(fiber); - nextHydratableInstance = hydrationParentFiber - ? getNextHydratableSibling(fiber.stateNode) - : null; - return !0; - } - }; -} -function ReactFiberLegacyContext(stack) { - function cacheContext(workInProgress, unmaskedContext, maskedContext) { - workInProgress = workInProgress.stateNode; - workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; - workInProgress.__reactInternalMemoizedMaskedChildContext = maskedContext; - } - function isContextProvider(fiber) { - return 2 === fiber.tag && null != fiber.type.childContextTypes; - } - function processChildContext(fiber, parentContext) { - var instance = fiber.stateNode, - childContextTypes = fiber.type.childContextTypes; - if ("function" !== typeof instance.getChildContext) return parentContext; - instance = instance.getChildContext(); - for (var contextKey in instance) - invariant( - contextKey in childContextTypes, - '%s.getChildContext(): key "%s" is not defined in childContextTypes.', - getComponentName(fiber) || "Unknown", - contextKey - ); - return Object.assign({}, parentContext, instance); - } - var createCursor = stack.createCursor, - push = stack.push, - pop = stack.pop, - contextStackCursor = createCursor(emptyObject), - didPerformWorkStackCursor = createCursor(!1), - previousContext = emptyObject; - return { - getUnmaskedContext: function(workInProgress) { - return isContextProvider(workInProgress) - ? previousContext - : contextStackCursor.current; - }, - cacheContext: cacheContext, - getMaskedContext: function(workInProgress, unmaskedContext) { - var contextTypes = workInProgress.type.contextTypes; - if (!contextTypes) return emptyObject; - var instance = workInProgress.stateNode; - if ( - instance && - instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext - ) - return instance.__reactInternalMemoizedMaskedChildContext; - var context = {}, - key; - for (key in contextTypes) context[key] = unmaskedContext[key]; - instance && cacheContext(workInProgress, unmaskedContext, context); - return context; - }, - hasContextChanged: function() { - return didPerformWorkStackCursor.current; - }, - isContextConsumer: function(fiber) { - return 2 === fiber.tag && null != fiber.type.contextTypes; - }, - isContextProvider: isContextProvider, - popContextProvider: function(fiber) { - isContextProvider(fiber) && - (pop(didPerformWorkStackCursor, fiber), pop(contextStackCursor, fiber)); - }, - popTopLevelContextObject: function(fiber) { - pop(didPerformWorkStackCursor, fiber); - pop(contextStackCursor, fiber); - }, - pushTopLevelContextObject: function(fiber, context, didChange) { - invariant( - null == contextStackCursor.cursor, - "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); - }, - processChildContext: processChildContext, - pushContextProvider: function(workInProgress) { - if (!isContextProvider(workInProgress)) return !1; - var instance = workInProgress.stateNode; - instance = - (instance && instance.__reactInternalMemoizedMergedChildContext) || - emptyObject; - previousContext = contextStackCursor.current; - push(contextStackCursor, instance, workInProgress); - push( - didPerformWorkStackCursor, - didPerformWorkStackCursor.current, - workInProgress - ); - return !0; - }, - invalidateContextProvider: function(workInProgress, didChange) { - var instance = workInProgress.stateNode; - invariant( - instance, - "Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue." - ); - if (didChange) { - var mergedContext = processChildContext( - workInProgress, - previousContext - ); - instance.__reactInternalMemoizedMergedChildContext = mergedContext; - pop(didPerformWorkStackCursor, workInProgress); - pop(contextStackCursor, workInProgress); - push(contextStackCursor, mergedContext, workInProgress); - } else pop(didPerformWorkStackCursor, workInProgress); - push(didPerformWorkStackCursor, didChange, workInProgress); - }, - findCurrentUnmaskedContext: function(fiber) { - for ( - invariant( - 2 === isFiberMountedImpl(fiber) && 2 === fiber.tag, - "Expected subtree parent to be a mounted class component. This error is likely caused by a bug in React. Please file an issue." - ); - 3 !== fiber.tag; - - ) { - if (isContextProvider(fiber)) - return fiber.stateNode.__reactInternalMemoizedMergedChildContext; - fiber = fiber["return"]; - invariant( - fiber, - "Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue." - ); - } - return fiber.stateNode.context; - } - }; -} -function ReactFiberNewContext(stack) { - var createCursor = stack.createCursor, - push = stack.push, - pop = stack.pop, - providerCursor = createCursor(null), - valueCursor = createCursor(null), - changedBitsCursor = createCursor(0); - return { - pushProvider: function(providerFiber) { - var context = providerFiber.type._context; - push(changedBitsCursor, context._changedBits, providerFiber); - push(valueCursor, context._currentValue, providerFiber); - push(providerCursor, providerFiber, providerFiber); - context._currentValue = providerFiber.pendingProps.value; - context._changedBits = providerFiber.stateNode; - }, - popProvider: function(providerFiber) { - var changedBits = changedBitsCursor.current, - currentValue = valueCursor.current; - pop(providerCursor, providerFiber); - pop(valueCursor, providerFiber); - pop(changedBitsCursor, providerFiber); - providerFiber = providerFiber.type._context; - providerFiber._currentValue = currentValue; - providerFiber._changedBits = changedBits; - } - }; -} -function ReactFiberStack() { - var valueStack = [], - index = -1; - return { - createCursor: function(defaultValue) { - return { current: defaultValue }; - }, - isEmpty: function() { - return -1 === index; - }, - pop: function(cursor) { - 0 > index || - ((cursor.current = valueStack[index]), - (valueStack[index] = null), - index--); - }, - push: function(cursor, value) { - index++; - valueStack[index] = cursor.current; - cursor.current = value; - }, - checkThatStackIsEmpty: function() {}, - resetStackAfterFatalErrorInDev: function() {} - }; -} -function ReactFiberScheduler(config) { - function resetStack() { - if (null !== nextUnitOfWork) - for ( - var interruptedWork = nextUnitOfWork["return"]; - null !== interruptedWork; - - ) - unwindInterruptedWork(interruptedWork), - (interruptedWork = interruptedWork["return"]); - nextRoot = null; - nextRenderExpirationTime = 0; - nextUnitOfWork = null; - isRootReadyForCommit = !1; - } - function isAlreadyFailedLegacyErrorBoundary(instance) { - return ( - null !== legacyErrorBoundariesThatAlreadyFailed && - legacyErrorBoundariesThatAlreadyFailed.has(instance) - ); - } - function completeUnitOfWork(workInProgress$jscomp$0) { - for (;;) { - var current = workInProgress$jscomp$0.alternate, - returnFiber = workInProgress$jscomp$0["return"], - siblingFiber = workInProgress$jscomp$0.sibling; - if (0 === (workInProgress$jscomp$0.effectTag & 512)) { - current = completeWork( - current, - workInProgress$jscomp$0, - nextRenderExpirationTime - ); - var workInProgress = workInProgress$jscomp$0; - if ( - 1073741823 === nextRenderExpirationTime || - 1073741823 !== workInProgress.expirationTime - ) { - b: switch (workInProgress.tag) { - case 3: - case 2: - var newExpirationTime = workInProgress.updateQueue; - newExpirationTime = - null === newExpirationTime - ? 0 - : newExpirationTime.expirationTime; - break b; - default: - newExpirationTime = 0; - } - for (var child = workInProgress.child; null !== child; ) - 0 !== child.expirationTime && - (0 === newExpirationTime || - newExpirationTime > child.expirationTime) && - (newExpirationTime = child.expirationTime), - (child = child.sibling); - workInProgress.expirationTime = newExpirationTime; - } - if (null !== current) return current; - null !== returnFiber && - 0 === (returnFiber.effectTag & 512) && - (null === returnFiber.firstEffect && - (returnFiber.firstEffect = workInProgress$jscomp$0.firstEffect), - null !== workInProgress$jscomp$0.lastEffect && - (null !== returnFiber.lastEffect && - (returnFiber.lastEffect.nextEffect = - workInProgress$jscomp$0.firstEffect), - (returnFiber.lastEffect = workInProgress$jscomp$0.lastEffect)), - 1 < workInProgress$jscomp$0.effectTag && - (null !== returnFiber.lastEffect - ? (returnFiber.lastEffect.nextEffect = workInProgress$jscomp$0) - : (returnFiber.firstEffect = workInProgress$jscomp$0), - (returnFiber.lastEffect = workInProgress$jscomp$0))); - if (null !== siblingFiber) return siblingFiber; - if (null !== returnFiber) workInProgress$jscomp$0 = returnFiber; - else { - isRootReadyForCommit = !0; - break; - } - } else { - workInProgress$jscomp$0 = unwindWork(workInProgress$jscomp$0); - if (null !== workInProgress$jscomp$0) - return ( - (workInProgress$jscomp$0.effectTag &= 2559), workInProgress$jscomp$0 - ); - null !== returnFiber && - ((returnFiber.firstEffect = returnFiber.lastEffect = null), - (returnFiber.effectTag |= 512)); - if (null !== siblingFiber) return siblingFiber; - if (null !== returnFiber) workInProgress$jscomp$0 = returnFiber; - else break; - } - } - return null; - } - function performUnitOfWork(workInProgress) { - var next = beginWork( - workInProgress.alternate, - workInProgress, - nextRenderExpirationTime - ); - null === next && (next = completeUnitOfWork(workInProgress)); - ReactCurrentOwner.current = null; - return next; - } - function renderRoot(root, expirationTime, isAsync) { - invariant( - !isWorking, - "renderRoot was called recursively. This error is likely caused by a bug in React. Please file an issue." - ); - isWorking = !0; - if ( - expirationTime !== nextRenderExpirationTime || - root !== nextRoot || - null === nextUnitOfWork - ) - resetStack(), - (nextRoot = root), - (nextRenderExpirationTime = expirationTime), - (nextUnitOfWork = createWorkInProgress( - nextRoot.current, - null, - nextRenderExpirationTime - )), - (root.pendingCommitExpirationTime = 0); - var didFatal = !1; - do { - try { - if (isAsync) - for (; null !== nextUnitOfWork && !shouldYield(); ) - nextUnitOfWork = performUnitOfWork(nextUnitOfWork); - else - for (; null !== nextUnitOfWork; ) - nextUnitOfWork = performUnitOfWork(nextUnitOfWork); - } catch (thrownValue) { - if (null === nextUnitOfWork) { - didFatal = !0; - onUncaughtError(thrownValue); - break; - } - isAsync = nextUnitOfWork; - var returnFiber = isAsync["return"]; - if (null === returnFiber) { - didFatal = !0; - onUncaughtError(thrownValue); - break; - } - throwException(returnFiber, isAsync, thrownValue); - nextUnitOfWork = completeUnitOfWork(isAsync); - } - break; - } while (1); - isWorking = !1; - if (didFatal || null !== nextUnitOfWork) return null; - if (isRootReadyForCommit) - return ( - (root.pendingCommitExpirationTime = expirationTime), - root.current.alternate - ); - invariant( - !1, - "Expired work should have completed. This error is likely caused by a bug in React. Please file an issue." - ); - } - function scheduleCapture(sourceFiber, boundaryFiber, value, expirationTime) { - sourceFiber = { - value: value, - source: sourceFiber, - stack: getStackAddendumByWorkInProgressFiber(sourceFiber) - }; - insertUpdateIntoFiber(boundaryFiber, { - expirationTime: expirationTime, - partialState: null, - callback: null, - isReplace: !1, - isForced: !1, - capturedValue: sourceFiber, - next: null - }); - scheduleWork(boundaryFiber, expirationTime); - } - function onCommitPhaseError(fiber$jscomp$0, error) { - a: { - invariant( - !isWorking || isCommitting, - "dispatch: Cannot dispatch during the render phase." - ); - for (var fiber = fiber$jscomp$0["return"]; null !== fiber; ) { - switch (fiber.tag) { - case 2: - var instance = fiber.stateNode; - if ( - "function" === typeof fiber.type.getDerivedStateFromCatch || - ("function" === typeof instance.componentDidCatch && - !isAlreadyFailedLegacyErrorBoundary(instance)) - ) { - scheduleCapture(fiber$jscomp$0, fiber, error, 1); - fiber$jscomp$0 = void 0; - break a; - } - break; - case 3: - scheduleCapture(fiber$jscomp$0, fiber, error, 1); - fiber$jscomp$0 = void 0; - break a; - } - fiber = fiber["return"]; - } - 3 === fiber$jscomp$0.tag && - scheduleCapture(fiber$jscomp$0, fiber$jscomp$0, error, 1); - fiber$jscomp$0 = void 0; - } - return fiber$jscomp$0; - } - function computeExpirationForFiber(fiber) { - fiber = - 0 !== expirationContext - ? expirationContext - : isWorking - ? isCommitting ? 1 : nextRenderExpirationTime - : fiber.mode & 1 - ? isBatchingInteractiveUpdates - ? 10 * ((((recalculateCurrentTime() + 15) / 10) | 0) + 1) - : 25 * ((((recalculateCurrentTime() + 500) / 25) | 0) + 1) - : 1; - isBatchingInteractiveUpdates && - (0 === lowestPendingInteractiveExpirationTime || - fiber > lowestPendingInteractiveExpirationTime) && - (lowestPendingInteractiveExpirationTime = fiber); - return fiber; - } - function scheduleWork(fiber, expirationTime) { - a: { - for (; null !== fiber; ) { - if (0 === fiber.expirationTime || fiber.expirationTime > expirationTime) - fiber.expirationTime = expirationTime; - null !== fiber.alternate && - (0 === fiber.alternate.expirationTime || - fiber.alternate.expirationTime > expirationTime) && - (fiber.alternate.expirationTime = expirationTime); - if (null === fiber["return"]) - if (3 === fiber.tag) { - var root = fiber.stateNode; - !isWorking && - 0 !== nextRenderExpirationTime && - expirationTime < nextRenderExpirationTime && - resetStack(); - (isWorking && !isCommitting && nextRoot === root) || - requestWork(root, expirationTime); - nestedUpdateCount > NESTED_UPDATE_LIMIT && - invariant( - !1, - "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." - ); - } else { - expirationTime = void 0; - break a; - } - fiber = fiber["return"]; - } - expirationTime = void 0; - } - return expirationTime; - } - function recalculateCurrentTime() { - mostRecentCurrentTimeMs = now() - originalStartTimeMs; - return (mostRecentCurrentTime = ((mostRecentCurrentTimeMs / 10) | 0) + 2); - } - function syncUpdates(fn, a, b, c, d) { - var previousExpirationContext = expirationContext; - expirationContext = 1; - try { - return fn(a, b, c, d); - } finally { - expirationContext = previousExpirationContext; - } - } - function scheduleCallbackWithExpiration(expirationTime) { - if (0 !== callbackExpirationTime) { - if (expirationTime > callbackExpirationTime) return; - cancelDeferredCallback(callbackID); - } - var currentMs = now() - originalStartTimeMs; - callbackExpirationTime = expirationTime; - callbackID = scheduleDeferredCallback(performAsyncWork, { - timeout: 10 * (expirationTime - 2) - currentMs - }); - } - function requestWork(root, expirationTime) { - if (null === root.nextScheduledRoot) - (root.remainingExpirationTime = expirationTime), - null === lastScheduledRoot - ? ((firstScheduledRoot = lastScheduledRoot = root), - (root.nextScheduledRoot = root)) - : ((lastScheduledRoot = lastScheduledRoot.nextScheduledRoot = root), - (lastScheduledRoot.nextScheduledRoot = firstScheduledRoot)); - else { - var remainingExpirationTime = root.remainingExpirationTime; - if ( - 0 === remainingExpirationTime || - expirationTime < remainingExpirationTime - ) - root.remainingExpirationTime = expirationTime; - } - isRendering || - (isBatchingUpdates - ? isUnbatchingUpdates && - ((nextFlushedRoot = root), - (nextFlushedExpirationTime = 1), - performWorkOnRoot(root, 1, !1)) - : 1 === expirationTime - ? performSyncWork() - : scheduleCallbackWithExpiration(expirationTime)); - } - function findHighestPriorityRoot() { - var highestPriorityWork = 0, - highestPriorityRoot = null; - if (null !== lastScheduledRoot) - for ( - var previousScheduledRoot = lastScheduledRoot, - root = firstScheduledRoot; - null !== root; - - ) { - var remainingExpirationTime = root.remainingExpirationTime; - if (0 === remainingExpirationTime) { - invariant( - null !== previousScheduledRoot && null !== lastScheduledRoot, - "Should have a previous and last root. This error is likely caused by a bug in React. Please file an issue." - ); - if (root === root.nextScheduledRoot) { - firstScheduledRoot = lastScheduledRoot = root.nextScheduledRoot = null; - break; - } else if (root === firstScheduledRoot) - (firstScheduledRoot = remainingExpirationTime = - root.nextScheduledRoot), - (lastScheduledRoot.nextScheduledRoot = remainingExpirationTime), - (root.nextScheduledRoot = null); - else if (root === lastScheduledRoot) { - lastScheduledRoot = previousScheduledRoot; - lastScheduledRoot.nextScheduledRoot = firstScheduledRoot; - root.nextScheduledRoot = null; - break; - } else - (previousScheduledRoot.nextScheduledRoot = root.nextScheduledRoot), - (root.nextScheduledRoot = null); - root = previousScheduledRoot.nextScheduledRoot; - } else { - if ( - 0 === highestPriorityWork || - remainingExpirationTime < highestPriorityWork - ) - (highestPriorityWork = remainingExpirationTime), - (highestPriorityRoot = root); - if (root === lastScheduledRoot) break; - previousScheduledRoot = root; - root = root.nextScheduledRoot; - } - } - previousScheduledRoot = nextFlushedRoot; - null !== previousScheduledRoot && - previousScheduledRoot === highestPriorityRoot && - 1 === highestPriorityWork - ? nestedUpdateCount++ - : (nestedUpdateCount = 0); - nextFlushedRoot = highestPriorityRoot; - nextFlushedExpirationTime = highestPriorityWork; - } - function performAsyncWork(dl) { - performWork(0, !0, dl); - } - function performSyncWork() { - performWork(1, !1, null); - } - function performWork(minExpirationTime, isAsync, dl) { - deadline = dl; - findHighestPriorityRoot(); - if (isAsync) - for ( - ; - null !== nextFlushedRoot && - 0 !== nextFlushedExpirationTime && - (0 === minExpirationTime || - minExpirationTime >= nextFlushedExpirationTime) && - (!deadlineDidExpire || - recalculateCurrentTime() >= nextFlushedExpirationTime); - - ) - performWorkOnRoot( - nextFlushedRoot, - nextFlushedExpirationTime, - !deadlineDidExpire - ), - findHighestPriorityRoot(); - else - for ( - ; - null !== nextFlushedRoot && - 0 !== nextFlushedExpirationTime && - (0 === minExpirationTime || - minExpirationTime >= nextFlushedExpirationTime); - - ) - performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime, !1), - findHighestPriorityRoot(); - null !== deadline && ((callbackExpirationTime = 0), (callbackID = -1)); - 0 !== nextFlushedExpirationTime && - scheduleCallbackWithExpiration(nextFlushedExpirationTime); - deadline = null; - deadlineDidExpire = !1; - finishRendering(); - } - function finishRendering() { - nestedUpdateCount = 0; - if (null !== completedBatches) { - var batches = completedBatches; - completedBatches = null; - for (var i = 0; i < batches.length; i++) { - var batch = batches[i]; - try { - batch._onComplete(); - } catch (error) { - hasUnhandledError || - ((hasUnhandledError = !0), (unhandledError = error)); - } - } - } - if (hasUnhandledError) - throw ((batches = unhandledError), - (unhandledError = null), - (hasUnhandledError = !1), - batches); - } - function performWorkOnRoot(root, expirationTime, isAsync) { - invariant( - !isRendering, - "performWorkOnRoot was called recursively. This error is likely caused by a bug in React. Please file an issue." - ); - isRendering = !0; - isAsync - ? ((isAsync = root.finishedWork), - null !== isAsync - ? completeRoot(root, isAsync, expirationTime) - : ((root.finishedWork = null), - (isAsync = renderRoot(root, expirationTime, !0)), - null !== isAsync && - (shouldYield() - ? (root.finishedWork = isAsync) - : completeRoot(root, isAsync, expirationTime)))) - : ((isAsync = root.finishedWork), - null !== isAsync - ? completeRoot(root, isAsync, expirationTime) - : ((root.finishedWork = null), - (isAsync = renderRoot(root, expirationTime, !1)), - null !== isAsync && completeRoot(root, isAsync, expirationTime))); - isRendering = !1; - } - function completeRoot(root, finishedWork, expirationTime) { - var firstBatch = root.firstBatch; - if ( - null !== firstBatch && - firstBatch._expirationTime <= expirationTime && - (null === completedBatches - ? (completedBatches = [firstBatch]) - : completedBatches.push(firstBatch), - firstBatch._defer) - ) { - root.finishedWork = finishedWork; - root.remainingExpirationTime = 0; - return; - } - root.finishedWork = null; - isCommitting = isWorking = !0; - expirationTime = finishedWork.stateNode; - invariant( - expirationTime.current !== finishedWork, - "Cannot commit the same tree as before. This is probably a bug related to the return field. This error is likely caused by a bug in React. Please file an issue." - ); - firstBatch = expirationTime.pendingCommitExpirationTime; - invariant( - 0 !== firstBatch, - "Cannot commit an incomplete root. This error is likely caused by a bug in React. Please file an issue." - ); - expirationTime.pendingCommitExpirationTime = 0; - var currentTime = recalculateCurrentTime(); - ReactCurrentOwner.current = null; - if (1 < finishedWork.effectTag) - if (null !== finishedWork.lastEffect) { - finishedWork.lastEffect.nextEffect = finishedWork; - var firstEffect = finishedWork.firstEffect; - } else firstEffect = finishedWork; - else firstEffect = finishedWork.firstEffect; - prepareForCommit(expirationTime.containerInfo); - for (nextEffect = firstEffect; null !== nextEffect; ) { - var didError = !1, - error = void 0; - try { - for (; null !== nextEffect; ) - nextEffect.effectTag & 2048 && - commitBeforeMutationLifeCycles(nextEffect.alternate, nextEffect), - (nextEffect = nextEffect.nextEffect); - } catch (e) { - (didError = !0), (error = e); - } - didError && - (invariant( - null !== nextEffect, - "Should have next effect. This error is likely caused by a bug in React. Please file an issue." - ), - onCommitPhaseError(nextEffect, error), - null !== nextEffect && (nextEffect = nextEffect.nextEffect)); - } - for (nextEffect = firstEffect; null !== nextEffect; ) { - didError = !1; - error = void 0; - try { - for (; null !== nextEffect; ) { - var effectTag = nextEffect.effectTag; - effectTag & 16 && commitResetTextContent(nextEffect); - if (effectTag & 128) { - var current = nextEffect.alternate; - null !== current && commitDetachRef(current); - } - 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: - commitDeletion(nextEffect); - } - nextEffect = nextEffect.nextEffect; - } - } catch (e) { - (didError = !0), (error = e); - } - didError && - (invariant( - null !== nextEffect, - "Should have next effect. This error is likely caused by a bug in React. Please file an issue." - ), - onCommitPhaseError(nextEffect, error), - null !== nextEffect && (nextEffect = nextEffect.nextEffect)); - } - resetAfterCommit(expirationTime.containerInfo); - expirationTime.current = finishedWork; - for (nextEffect = firstEffect; null !== nextEffect; ) { - effectTag = !1; - current = void 0; - try { - for ( - firstEffect = expirationTime, - didError = currentTime, - error = firstBatch; - null !== nextEffect; - - ) { - var effectTag$jscomp$0 = nextEffect.effectTag; - effectTag$jscomp$0 & 36 && - commitLifeCycles( - firstEffect, - nextEffect.alternate, - nextEffect, - didError, - error - ); - effectTag$jscomp$0 & 256 && - commitErrorLogging(nextEffect, onUncaughtError); - effectTag$jscomp$0 & 128 && commitAttachRef(nextEffect); - var next = nextEffect.nextEffect; - nextEffect.nextEffect = null; - nextEffect = next; - } - } catch (e) { - (effectTag = !0), (current = e); - } - effectTag && - (invariant( - null !== nextEffect, - "Should have next effect. This error is likely caused by a bug in React. Please file an issue." - ), - onCommitPhaseError(nextEffect, current), - null !== nextEffect && (nextEffect = nextEffect.nextEffect)); - } - isWorking = isCommitting = !1; - "function" === typeof onCommitRoot && onCommitRoot(finishedWork.stateNode); - finishedWork = expirationTime.current.expirationTime; - 0 === finishedWork && (legacyErrorBoundariesThatAlreadyFailed = null); - root.remainingExpirationTime = finishedWork; - } - function shouldYield() { - return null === deadline || - deadline.timeRemaining() > timeHeuristicForUnitOfWork - ? !1 - : (deadlineDidExpire = !0); - } - function onUncaughtError(error) { - invariant( - null !== nextFlushedRoot, - "Should be working on a root. This error is likely caused by a bug in React. Please file an issue." - ); - nextFlushedRoot.remainingExpirationTime = 0; - hasUnhandledError || ((hasUnhandledError = !0), (unhandledError = error)); - } - var stack = ReactFiberStack(), - hostContext = ReactFiberHostContext(config, stack), - legacyContext = ReactFiberLegacyContext(stack); - stack = ReactFiberNewContext(stack); - var hydrationContext = ReactFiberHydrationContext(config), - beginWork = ReactFiberBeginWork( - config, - hostContext, - legacyContext, - stack, - hydrationContext, - scheduleWork, - computeExpirationForFiber - ).beginWork, - completeWork = ReactFiberCompleteWork( - config, - hostContext, - legacyContext, - stack, - hydrationContext - ).completeWork; - hostContext = ReactFiberUnwindWork( - hostContext, - legacyContext, - stack, - scheduleWork, - isAlreadyFailedLegacyErrorBoundary - ); - var throwException = hostContext.throwException, - unwindWork = hostContext.unwindWork, - unwindInterruptedWork = hostContext.unwindInterruptedWork; - hostContext = ReactFiberCommitWork( - config, - onCommitPhaseError, - scheduleWork, - computeExpirationForFiber, - function(instance) { - null === legacyErrorBoundariesThatAlreadyFailed - ? (legacyErrorBoundariesThatAlreadyFailed = new Set([instance])) - : legacyErrorBoundariesThatAlreadyFailed.add(instance); - }, - recalculateCurrentTime - ); - var commitBeforeMutationLifeCycles = - hostContext.commitBeforeMutationLifeCycles, - commitResetTextContent = hostContext.commitResetTextContent, - commitPlacement = hostContext.commitPlacement, - commitDeletion = hostContext.commitDeletion, - commitWork = hostContext.commitWork, - commitLifeCycles = hostContext.commitLifeCycles, - commitErrorLogging = hostContext.commitErrorLogging, - commitAttachRef = hostContext.commitAttachRef, - commitDetachRef = hostContext.commitDetachRef, - now = config.now, - scheduleDeferredCallback = config.scheduleDeferredCallback, - cancelDeferredCallback = config.cancelDeferredCallback, - prepareForCommit = config.prepareForCommit, - resetAfterCommit = config.resetAfterCommit, - originalStartTimeMs = now(), - mostRecentCurrentTime = 2, - mostRecentCurrentTimeMs = originalStartTimeMs, - lastUniqueAsyncExpiration = 0, - expirationContext = 0, - isWorking = !1, - nextUnitOfWork = null, - nextRoot = null, - nextRenderExpirationTime = 0, - nextEffect = null, - isCommitting = !1, - isRootReadyForCommit = !1, - legacyErrorBoundariesThatAlreadyFailed = null, - firstScheduledRoot = null, - lastScheduledRoot = null, - callbackExpirationTime = 0, - callbackID = -1, - isRendering = !1, - nextFlushedRoot = null, - nextFlushedExpirationTime = 0, - lowestPendingInteractiveExpirationTime = 0, - deadlineDidExpire = !1, - hasUnhandledError = !1, - unhandledError = null, - deadline = null, - isBatchingUpdates = !1, - isUnbatchingUpdates = !1, - isBatchingInteractiveUpdates = !1, - completedBatches = null, - NESTED_UPDATE_LIMIT = 1e3, - nestedUpdateCount = 0, - timeHeuristicForUnitOfWork = 1; - return { - recalculateCurrentTime: recalculateCurrentTime, - computeExpirationForFiber: computeExpirationForFiber, - scheduleWork: scheduleWork, - requestWork: requestWork, - flushRoot: function(root, expirationTime) { - invariant( - !isRendering, - "work.commit(): Cannot commit while already rendering. This likely means you attempted to commit from inside a lifecycle method." - ); - nextFlushedRoot = root; - nextFlushedExpirationTime = expirationTime; - performWorkOnRoot(root, expirationTime, !1); - performSyncWork(); - finishRendering(); - }, - batchedUpdates: function(fn, a) { - var previousIsBatchingUpdates = isBatchingUpdates; - isBatchingUpdates = !0; - try { - return fn(a); - } finally { - (isBatchingUpdates = previousIsBatchingUpdates) || - isRendering || - performSyncWork(); - } - }, - unbatchedUpdates: function(fn, a) { - if (isBatchingUpdates && !isUnbatchingUpdates) { - isUnbatchingUpdates = !0; - try { - return fn(a); - } finally { - isUnbatchingUpdates = !1; - } - } - return fn(a); - }, - flushSync: function(fn, a) { - invariant( - !isRendering, - "flushSync was called from inside a lifecycle method. It cannot be called when React is already rendering." - ); - var previousIsBatchingUpdates = isBatchingUpdates; - isBatchingUpdates = !0; - try { - return syncUpdates(fn, a); - } finally { - (isBatchingUpdates = previousIsBatchingUpdates), performSyncWork(); - } - }, - flushControlled: function(fn) { - var previousIsBatchingUpdates = isBatchingUpdates; - isBatchingUpdates = !0; - try { - syncUpdates(fn); - } finally { - (isBatchingUpdates = previousIsBatchingUpdates) || - isRendering || - performWork(1, !1, null); - } - }, - deferredUpdates: function(fn) { - var previousExpirationContext = expirationContext; - expirationContext = - 25 * ((((recalculateCurrentTime() + 500) / 25) | 0) + 1); - try { - return fn(); - } finally { - expirationContext = previousExpirationContext; - } - }, - syncUpdates: syncUpdates, - interactiveUpdates: function(fn, a, b) { - if (isBatchingInteractiveUpdates) return fn(a, b); - isBatchingUpdates || - isRendering || - 0 === lowestPendingInteractiveExpirationTime || - (performWork(lowestPendingInteractiveExpirationTime, !1, null), - (lowestPendingInteractiveExpirationTime = 0)); - var previousIsBatchingInteractiveUpdates = isBatchingInteractiveUpdates, - previousIsBatchingUpdates = isBatchingUpdates; - isBatchingUpdates = isBatchingInteractiveUpdates = !0; - try { - return fn(a, b); - } finally { - (isBatchingInteractiveUpdates = previousIsBatchingInteractiveUpdates), - (isBatchingUpdates = previousIsBatchingUpdates) || - isRendering || - performSyncWork(); - } - }, - flushInteractiveUpdates: function() { - isRendering || - 0 === lowestPendingInteractiveExpirationTime || - (performWork(lowestPendingInteractiveExpirationTime, !1, null), - (lowestPendingInteractiveExpirationTime = 0)); - }, - computeUniqueAsyncExpiration: function() { - var result = 25 * ((((recalculateCurrentTime() + 500) / 25) | 0) + 1); - result <= lastUniqueAsyncExpiration && - (result = lastUniqueAsyncExpiration + 1); - return (lastUniqueAsyncExpiration = result); - }, - legacyContext: legacyContext - }; -} -function ReactFiberReconciler$1(config) { - function updateContainerAtExpirationTime( - element, - container, - parentComponent, - currentTime, - expirationTime, - callback - ) { - currentTime = container.current; - if (parentComponent) { - parentComponent = parentComponent._reactInternalFiber; - var parentContext = findCurrentUnmaskedContext(parentComponent); - parentComponent = isContextProvider(parentComponent) - ? processChildContext(parentComponent, parentContext) - : parentContext; - } else parentComponent = emptyObject; - null === container.context - ? (container.context = parentComponent) - : (container.pendingContext = parentComponent); - container = callback; - insertUpdateIntoFiber(currentTime, { - expirationTime: expirationTime, - partialState: { element: element }, - callback: void 0 === container ? null : container, - isReplace: !1, - isForced: !1, - capturedValue: null, - next: null - }); - scheduleWork(currentTime, expirationTime); - return expirationTime; - } - var getPublicInstance = config.getPublicInstance; - config = ReactFiberScheduler(config); - var recalculateCurrentTime = config.recalculateCurrentTime, - computeExpirationForFiber = config.computeExpirationForFiber, - scheduleWork = config.scheduleWork, - legacyContext = config.legacyContext, - findCurrentUnmaskedContext = legacyContext.findCurrentUnmaskedContext, - isContextProvider = legacyContext.isContextProvider, - processChildContext = legacyContext.processChildContext; - return { - createContainer: function(containerInfo, isAsync, hydrate) { - isAsync = new FiberNode(3, null, null, isAsync ? 3 : 0); - containerInfo = { - current: isAsync, - containerInfo: containerInfo, - pendingChildren: null, - pendingCommitExpirationTime: 0, - finishedWork: null, - context: null, - pendingContext: null, - hydrate: hydrate, - remainingExpirationTime: 0, - firstBatch: null, - nextScheduledRoot: null - }; - return (isAsync.stateNode = containerInfo); - }, - updateContainer: function(element, container, parentComponent, callback) { - var current = container.current, - currentTime = recalculateCurrentTime(); - current = computeExpirationForFiber(current); - return updateContainerAtExpirationTime( - element, - container, - parentComponent, - currentTime, - current, - callback - ); - }, - updateContainerAtExpirationTime: function( - element, - container, - parentComponent, - expirationTime, - callback - ) { - var currentTime = recalculateCurrentTime(); - return updateContainerAtExpirationTime( - element, - container, - parentComponent, - currentTime, - expirationTime, - callback - ); - }, - flushRoot: config.flushRoot, - requestWork: config.requestWork, - computeUniqueAsyncExpiration: config.computeUniqueAsyncExpiration, - batchedUpdates: config.batchedUpdates, - unbatchedUpdates: config.unbatchedUpdates, - deferredUpdates: config.deferredUpdates, - syncUpdates: config.syncUpdates, - interactiveUpdates: config.interactiveUpdates, - flushInteractiveUpdates: config.flushInteractiveUpdates, - flushControlled: config.flushControlled, - flushSync: config.flushSync, - getPublicRootInstance: function(container) { - container = container.current; - if (!container.child) return null; - switch (container.child.tag) { - case 5: - return getPublicInstance(container.child.stateNode); - default: - return container.child.stateNode; - } - }, - findHostInstance: function(component) { - var fiber = component._reactInternalFiber; - void 0 === fiber && - ("function" === typeof component.render - ? invariant(!1, "Unable to find node on an unmounted component.") - : invariant( - !1, - "Argument appears to not be a ReactComponent. Keys: %s", - Object.keys(component) - )); - component = findCurrentHostFiber(fiber); - return null === component ? null : component.stateNode; - }, - findHostInstanceWithNoPortals: function(fiber) { - fiber = findCurrentHostFiberWithNoPortals(fiber); - return null === fiber ? null : fiber.stateNode; - }, - injectIntoDevTools: function(devToolsConfig) { - var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; - return injectInternals( - Object.assign({}, devToolsConfig, { - findHostInstanceByFiber: function(fiber) { - fiber = findCurrentHostFiber(fiber); - return null === fiber ? null : fiber.stateNode; - }, - findFiberByHostInstance: function(instance) { - return findFiberByHostInstance - ? findFiberByHostInstance(instance) - : null; - } - }) - ); - } - }; -} -var ReactFiberReconciler$2 = Object.freeze({ default: ReactFiberReconciler$1 }), - ReactFiberReconciler$3 = - (ReactFiberReconciler$2 && ReactFiberReconciler$1) || - ReactFiberReconciler$2, - reactReconciler = ReactFiberReconciler$3["default"] - ? ReactFiberReconciler$3["default"] - : ReactFiberReconciler$3, - nextReactTag = 2, - ReactFabricHostComponent = (function() { - function ReactFabricHostComponent(tag, viewConfig, props) { - if (!(this instanceof ReactFabricHostComponent)) - throw new TypeError("Cannot call a class as a function"); - this._nativeTag = tag; - this.viewConfig = viewConfig; - this.currentProps = props; - } - ReactFabricHostComponent.prototype.blur = function() { - TextInputState.blurTextInput(this._nativeTag); - }; - ReactFabricHostComponent.prototype.focus = function() { - TextInputState.focusTextInput(this._nativeTag); - }; - ReactFabricHostComponent.prototype.measure = function(callback) { - UIManager.measure(this._nativeTag, mountSafeCallback(this, callback)); - }; - ReactFabricHostComponent.prototype.measureInWindow = function(callback) { - UIManager.measureInWindow( - this._nativeTag, - mountSafeCallback(this, callback) - ); - }; - ReactFabricHostComponent.prototype.measureLayout = function( - relativeToNativeNode, - onSuccess, - onFail - ) { - UIManager.measureLayout( - this._nativeTag, - relativeToNativeNode, - mountSafeCallback(this, onFail), - mountSafeCallback(this, onSuccess) - ); - }; - ReactFabricHostComponent.prototype.setNativeProps = function(nativeProps) { - nativeProps = diffProperties( - null, - emptyObject$1, - nativeProps, - this.viewConfig.validAttributes - ); - null != nativeProps && - UIManager.updateView( - this._nativeTag, - this.viewConfig.uiViewClassName, - nativeProps - ); - }; - return ReactFabricHostComponent; - })(), - ReactFabricRenderer = reactReconciler({ - appendInitialChild: function(parentInstance, child) { - FabricUIManager.appendChild(parentInstance.node, child.node); - }, - createInstance: function( - type, - props, - rootContainerInstance, - hostContext, - internalInstanceHandle - ) { - hostContext = nextReactTag; - nextReactTag += 2; - type = ReactNativeViewConfigRegistry.get(type); - var updatePayload = diffProperties( - null, - emptyObject$1, - props, - type.validAttributes - ); - rootContainerInstance = FabricUIManager.createNode( - hostContext, - type.uiViewClassName, - rootContainerInstance, - updatePayload, - internalInstanceHandle - ); - props = new ReactFabricHostComponent(hostContext, type, props); - return { node: rootContainerInstance, canonical: props }; - }, - createTextInstance: function( - text, - rootContainerInstance, - hostContext, - internalInstanceHandle - ) { - hostContext = nextReactTag; - nextReactTag += 2; - return { - node: FabricUIManager.createNode( - hostContext, - "RCTRawText", - rootContainerInstance, - { text: text }, - internalInstanceHandle - ) - }; - }, - finalizeInitialChildren: function() { - return !1; - }, - getRootHostContext: function() { - return emptyObject; - }, - getChildHostContext: function() { - return emptyObject; - }, - getPublicInstance: function(instance) { - return instance.canonical; - }, - now: now, - prepareForCommit: function() {}, - prepareUpdate: function(instance, type, oldProps, newProps) { - return diffProperties( - null, - oldProps, - newProps, - instance.canonical.viewConfig.validAttributes - ); - }, - resetAfterCommit: function() {}, - scheduleDeferredCallback: function(callback) { - scheduledCallback = callback; - return setTimeout(setTimeoutCallback, 1); - }, - cancelDeferredCallback: function(callbackID) { - scheduledCallback = null; - clearTimeout(callbackID); - }, - shouldDeprioritizeSubtree: function() { - return !1; - }, - shouldSetTextContent: function() { - return !1; - }, - persistence: { - cloneInstance: function( - instance, - updatePayload, - type, - oldProps, - newProps, - internalInstanceHandle, - keepChildren - ) { - type = instance.node; - return { - node: keepChildren - ? null !== updatePayload - ? FabricUIManager.cloneNodeWithNewProps(type, updatePayload) - : FabricUIManager.cloneNode(type) - : null !== updatePayload - ? FabricUIManager.cloneNodeWithNewChildrenAndProps( - type, - updatePayload - ) - : FabricUIManager.cloneNodeWithNewChildren(type), - canonical: instance.canonical - }; - }, - createContainerChildSet: function(container) { - return FabricUIManager.createChildSet(container); - }, - appendChildToContainerChildSet: function(childSet, child) { - FabricUIManager.appendChildToSet(childSet, child.node); - }, - finalizeContainerChildren: function(container, newChildren) { - FabricUIManager.completeRoot(container, newChildren); - }, - replaceContainerChildren: function() {} - } - }), - getInspectorDataForViewTag = void 0; -getInspectorDataForViewTag = function() { - invariant(!1, "getInspectorDataForViewTag() is not available in production"); -}; -var findHostInstance = ReactFabricRenderer.findHostInstance; -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; -} -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() { - TextInputState.blurTextInput(findNodeHandle(this)); - }; - ReactNativeComponent.prototype.focus = function() { - TextInputState.focusTextInput(findNodeHandle(this)); - }; - ReactNativeComponent.prototype.measure = function(callback) { - UIManager.measure( - findNodeHandle(this), - mountSafeCallback(this, callback) - ); - }; - ReactNativeComponent.prototype.measureInWindow = function(callback) { - UIManager.measureInWindow( - findNodeHandle(this), - mountSafeCallback(this, callback) - ); - }; - ReactNativeComponent.prototype.measureLayout = function( - relativeToNativeNode, - onSuccess, - onFail - ) { - UIManager.measureLayout( - findNodeHandle(this), - relativeToNativeNode, - mountSafeCallback(this, onFail), - mountSafeCallback(this, onSuccess) - ); - }; - ReactNativeComponent.prototype.setNativeProps = function(nativeProps) { - var maybeInstance = void 0; - try { - maybeInstance = findHostInstance(this); - } catch (error) {} - if (null != maybeInstance) { - var viewConfig = - maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; - nativeProps = diffProperties( - null, - emptyObject$1, - nativeProps, - viewConfig.validAttributes - ); - null != nativeProps && - UIManager.updateView( - maybeInstance._nativeTag, - viewConfig.uiViewClassName, - nativeProps - ); - } - }; - return ReactNativeComponent; - })(React.Component); - })(findNodeHandle, findHostInstance), - findNodeHandle: findNodeHandle, - render: function(element, containerTag, callback) { - var root = roots.get(containerTag); - root || - ((root = ReactFabricRenderer.createContainer(containerTag, !1, !1)), - roots.set(containerTag, root)); - ReactFabricRenderer.updateContainer(element, root, null, callback); - return ReactFabricRenderer.getPublicRootInstance(root); - }, - unmountComponentAtNode: function(containerTag) { - var root = roots.get(containerTag); - root && - ReactFabricRenderer.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) { - UIManager.measure( - findNodeHandle(this), - mountSafeCallback(this, callback) - ); - }, - measureInWindow: function(callback) { - UIManager.measureInWindow( - findNodeHandle(this), - mountSafeCallback(this, callback) - ); - }, - measureLayout: function(relativeToNativeNode, onSuccess, onFail) { - UIManager.measureLayout( - findNodeHandle(this), - relativeToNativeNode, - mountSafeCallback(this, onFail), - mountSafeCallback(this, onSuccess) - ); - }, - setNativeProps: function(nativeProps) { - var maybeInstance = void 0; - try { - maybeInstance = findHostInstance(this); - } catch (error) {} - if (null != maybeInstance) { - var viewConfig = maybeInstance.viewConfig; - nativeProps = diffProperties( - null, - emptyObject$1, - nativeProps, - viewConfig.validAttributes - ); - null != nativeProps && - UIManager.updateView( - maybeInstance._nativeTag, - viewConfig.uiViewClassName, - nativeProps - ); - } - }, - focus: function() { - TextInputState.focusTextInput(findNodeHandle(this)); - }, - blur: function() { - TextInputState.blurTextInput(findNodeHandle(this)); - } - }; - })(findNodeHandle, findHostInstance), - ReactNativeComponentTree: ReactNativeComponentTree - } - }; -ReactFabricRenderer.injectIntoDevTools({ - findFiberByHostInstance: getInstanceFromTag, - getInspectorDataForViewTag: getInspectorDataForViewTag, - bundleType: 0, - version: "16.3.2", - rendererPackageName: "react-native-renderer" -}); -var ReactFabric$2 = Object.freeze({ default: ReactFabric }), - ReactFabric$3 = (ReactFabric$2 && ReactFabric) || ReactFabric$2; -module.exports = ReactFabric$3["default"] - ? ReactFabric$3["default"] - : ReactFabric$3; diff --git a/Libraries/Renderer/fb/ReactFeatureFlags.js b/Libraries/Renderer/fb/ReactFeatureFlags.js deleted file mode 100644 index 44add71fc5c5e2..00000000000000 --- a/Libraries/Renderer/fb/ReactFeatureFlags.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @providesModule ReactFeatureFlags - */ - -'use strict'; - -const ReactFeatureFlags = { - debugRenderPhaseSideEffects: false, - debugRenderPhaseSideEffectsForStrictMode: false, - warnAboutDeprecatedLifecycles: true, -}; - -module.exports = ReactFeatureFlags; diff --git a/Libraries/Renderer/fb/ReactNativeRenderer-dev.js b/Libraries/Renderer/fb/ReactNativeRenderer-dev.js deleted file mode 100644 index bcdfa4c607aaa2..00000000000000 --- a/Libraries/Renderer/fb/ReactNativeRenderer-dev.js +++ /dev/null @@ -1,14437 +0,0 @@ -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @noflow - * @preventMunge - */ - -'use strict'; - -if (__DEV__) { - (function() { -"use strict"; - -require("InitializeCore"); -var invariant = require("fbjs/lib/invariant"); -var warning = require("fbjs/lib/warning"); -var emptyFunction = require("fbjs/lib/emptyFunction"); -var ReactNativeViewConfigRegistry = require("ReactNativeViewConfigRegistry"); -var UIManager = require("UIManager"); -var RCTEventEmitter = require("RCTEventEmitter"); -var TextInputState = require("TextInputState"); -var deepDiffer = require("deepDiffer"); -var flattenStyle = require("flattenStyle"); -var React = require("react"); -var emptyObject = require("fbjs/lib/emptyObject"); -var shallowEqual = require("fbjs/lib/shallowEqual"); -var ExceptionsManager = require("ExceptionsManager"); -var checkPropTypes = require("prop-types/checkPropTypes"); -var deepFreezeAndThrowOnMutationInDev = require("deepFreezeAndThrowOnMutationInDev"); - -var invokeGuardedCallback = function(name, func, context, a, b, c, d, e, f) { - this._hasCaughtError = false; - this._caughtError = null; - var funcArgs = Array.prototype.slice.call(arguments, 3); - try { - func.apply(context, funcArgs); - } catch (error) { - this._caughtError = error; - this._hasCaughtError = true; - } -}; - -{ - // 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 - // untintuitive, 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. - invariant( - typeof document !== "undefined", - "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; - - // 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); - 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 onError(event) { - error = event.error; - didSetError = true; - if (error === null && event.colno === 0 && event.lineno === 0) { - isCrossOriginError = true; - } - } - - // Create a fake event type. - var evtType = "react-" + (name ? name : "invokeguardedcallback"); - - // Attach our event handlers - window.addEventListener("error", onError); - 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 (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._hasCaughtError = true; - this._caughtError = error; - } else { - this._hasCaughtError = false; - this._caughtError = null; - } - - // Remove our event listeners - window.removeEventListener("error", onError); - }; - - invokeGuardedCallback = invokeGuardedCallbackDev; - } -} - -var invokeGuardedCallback$1 = invokeGuardedCallback; - -var ReactErrorUtils = { - // Used by Fiber to simulate a try-catch. - _caughtError: null, - _hasCaughtError: false, - - // Used by event system to capture/rethrow the first error. - _rethrowError: null, - _hasRethrowError: false, - - /** - * 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 - */ - invokeGuardedCallback: function(name, func, context, a, b, c, d, e, f) { - invokeGuardedCallback$1.apply(ReactErrorUtils, 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 - */ - invokeGuardedCallbackAndCatchFirstError: function( - name, - func, - context, - a, - b, - c, - d, - e, - f - ) { - ReactErrorUtils.invokeGuardedCallback.apply(this, arguments); - if (ReactErrorUtils.hasCaughtError()) { - var error = ReactErrorUtils.clearCaughtError(); - if (!ReactErrorUtils._hasRethrowError) { - ReactErrorUtils._hasRethrowError = true; - ReactErrorUtils._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. - */ - rethrowCaughtError: function() { - return rethrowCaughtError.apply(ReactErrorUtils, arguments); - }, - - hasCaughtError: function() { - return ReactErrorUtils._hasCaughtError; - }, - - clearCaughtError: function() { - if (ReactErrorUtils._hasCaughtError) { - var error = ReactErrorUtils._caughtError; - ReactErrorUtils._caughtError = null; - ReactErrorUtils._hasCaughtError = false; - return error; - } else { - invariant( - false, - "clearCaughtError was called but no error was captured. This error " + - "is likely caused by a bug in React. Please file an issue." - ); - } - } -}; - -var rethrowCaughtError = function() { - if (ReactErrorUtils._hasRethrowError) { - var error = ReactErrorUtils._rethrowError; - ReactErrorUtils._rethrowError = null; - ReactErrorUtils._hasRethrowError = false; - throw error; - } -}; - -/** - * 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); - invariant( - pluginIndex > -1, - "EventPluginRegistry: Cannot inject event plugins that do not exist in " + - "the plugin ordering, `%s`.", - pluginName - ); - if (plugins[pluginIndex]) { - continue; - } - invariant( - pluginModule.extractEvents, - "EventPluginRegistry: Event plugins must implement an `extractEvents` " + - "method, but `%s` does not.", - pluginName - ); - plugins[pluginIndex] = pluginModule; - var publishedEvents = pluginModule.eventTypes; - for (var eventName in publishedEvents) { - invariant( - publishEventForPlugin( - publishedEvents[eventName], - pluginModule, - eventName - ), - "EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.", - eventName, - 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) { - invariant( - !eventNameDispatchConfigs.hasOwnProperty(eventName), - "EventPluginHub: More than one plugin attempted to publish the same " + - "event name, `%s`.", - 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) { - invariant( - !registrationNameModules[registrationName], - "EventPluginHub: More than one plugin attempted to publish the same " + - "registration name, `%s`.", - 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) { - invariant( - !eventPluginOrder, - "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 - ) { - invariant( - !namesToPlugins[pluginName], - "EventPluginRegistry: Cannot inject two different event plugins " + - "using the same name, `%s`.", - pluginName - ); - namesToPlugins[pluginName] = pluginModule; - isOrderingDirty = true; - } - } - if (isOrderingDirty) { - recomputePluginOrdering(); - } -} - -var getFiberCurrentPropsFromNode = null; -var getInstanceFromNode = null; -var getNodeFromInstance = null; - -var injection$1 = { - injectComponentTree: function(Injected) { - getFiberCurrentPropsFromNode = Injected.getFiberCurrentPropsFromNode; - getInstanceFromNode = Injected.getInstanceFromNode; - getNodeFromInstance = Injected.getNodeFromInstance; - - { - !(getNodeFromInstance && getInstanceFromNode) - ? warning( - false, - "EventPluginUtils.injection.injectComponentTree(...): Injected " + - "module is missing getNodeFromInstance or getInstanceFromNode." - ) - : void 0; - } - } -}; - -function isEndish(topLevelType) { - return ( - topLevelType === "topMouseUp" || - topLevelType === "topTouchEnd" || - topLevelType === "topTouchCancel" - ); -} - -function isMoveish(topLevelType) { - return topLevelType === "topMouseMove" || topLevelType === "topTouchMove"; -} -function isStartish(topLevelType) { - return topLevelType === "topMouseDown" || topLevelType === "topTouchStart"; -} - -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) - ? warning(false, "EventPluginUtils: Invalid `event`.") - : void 0; - }; -} - -/** - * Dispatch the event to the listener. - * @param {SyntheticEvent} event SyntheticEvent to handle - * @param {boolean} simulated If the event is simulated (changes exn behavior) - * @param {function} listener Application-level callback - * @param {*} inst Internal component instance - */ -function executeDispatch(event, simulated, listener, inst) { - var type = event.type || "unknown-event"; - event.currentTarget = getNodeFromInstance(inst); - ReactErrorUtils.invokeGuardedCallbackAndCatchFirstError( - type, - listener, - undefined, - event - ); - event.currentTarget = null; -} - -/** - * Standard/simple iteration through an event's collected dispatches. - */ -function executeDispatchesInOrder(event, simulated) { - 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, - simulated, - dispatchListeners[i], - dispatchInstances[i] - ); - } - } else if (dispatchListeners) { - executeDispatch(event, simulated, 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; - invariant( - !Array.isArray(dispatchListener), - "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) { - invariant( - next != null, - "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. - * @param {boolean} simulated If the event is simulated (changes exn behavior) - * @private - */ -var executeDispatchesAndRelease = function(event, simulated) { - if (event) { - executeDispatchesInOrder(event, simulated); - - if (!event.isPersistent()) { - event.constructor.release(event); - } - } -}; -var executeDispatchesAndReleaseSimulated = function(e) { - return executeDispatchesAndRelease(e, true); -}; -var executeDispatchesAndReleaseTopLevel = function(e) { - return executeDispatchesAndRelease(e, false); -}; - -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; - } - invariant( - !listener || typeof listener === "function", - "Expected `%s` listener to be a function, instead got a value of `%s` type.", - registrationName, - typeof listener - ); - return listener; -} - -/** - * Allows registered plugins an opportunity to extract events from top-level - * native browser events. - * - * @return {*} An accumulation of synthetic events. - * @internal - */ -function extractEvents( - 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 runEventsInBatch(events, simulated) { - 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; - } - - if (simulated) { - forEachAccumulated( - processingEventQueue, - executeDispatchesAndReleaseSimulated - ); - } else { - forEachAccumulated( - processingEventQueue, - executeDispatchesAndReleaseTopLevel - ); - } - invariant( - !eventQueue, - "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. - ReactErrorUtils.rethrowCaughtError(); -} - -function runExtractedEventsInBatch( - topLevelType, - targetInst, - nativeEvent, - nativeEventTarget -) { - var events = extractEvents( - topLevelType, - targetInst, - nativeEvent, - nativeEventTarget - ); - runEventsInBatch(events, false); -} - -var IndeterminateComponent = 0; // Before we know whether it is functional or class -var FunctionalComponent = 1; -var ClassComponent = 2; -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 CallComponent = 7; -var CallHandlerPhase = 8; -var ReturnComponent = 9; -var Fragment = 10; -var Mode = 11; -var ContextConsumer = 12; -var ContextProvider = 13; -var ForwardRef = 14; - -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 ? warning(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 didWarnForAddedNewProperty = false; -var EVENT_POOL_SIZE = 10; - -var shouldBeReleasedProperties = [ - "dispatchConfig", - "_targetInst", - "nativeEvent", - "isDefaultPrevented", - "isPropagationStopped", - "_dispatchListeners", - "_dispatchInstances" -]; - -/** - * @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: emptyFunction.thatReturnsNull, - eventPhase: null, - bubbles: null, - cancelable: null, - timeStamp: function(event) { - return event.timeStamp || Date.now(); - }, - defaultPrevented: null, - isTrusted: null -}; - -/** - * 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; - } - - 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 = emptyFunction.thatReturnsTrue; - } else { - this.isDefaultPrevented = emptyFunction.thatReturnsFalse; - } - this.isPropagationStopped = emptyFunction.thatReturnsFalse; - 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 = emptyFunction.thatReturnsTrue; - }, - - 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 = emptyFunction.thatReturnsTrue; - }, - - /** - * 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 = emptyFunction.thatReturnsTrue; - }, - - /** - * Checks if this event should be released back into the pool. - * - * @return {boolean} True if this should not be released, false otherwise. - */ - isPersistent: emptyFunction.thatReturnsFalse, - - /** - * `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]) - ); - } - } - for (var i = 0; i < shouldBeReleasedProperties.length; i++) { - this[shouldBeReleasedProperties[i]] = null; - } - { - Object.defineProperty( - this, - "nativeEvent", - getPooledWarningPropertyDefinition("nativeEvent", null) - ); - Object.defineProperty( - this, - "preventDefault", - getPooledWarningPropertyDefinition("preventDefault", emptyFunction) - ); - Object.defineProperty( - this, - "stopPropagation", - getPooledWarningPropertyDefinition("stopPropagation", emptyFunction) - ); - } - } -}); - -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; -}; - -/** Proxying after everything set on SyntheticEvent - * to resolve Proxy issue on some WebKit browsers - * in which some Event properties are set to undefined (GH#10010) - */ -{ - var isProxySupported = - typeof Proxy === "function" && - // https://github.com/facebook/react/issues/12011 - !Object.isSealed(new Proxy({}, {})); - - if (isProxySupported) { - /*eslint-disable no-func-assign */ - SyntheticEvent = new Proxy(SyntheticEvent, { - construct: function(target, args) { - return this.apply(target, Object.create(target.prototype), args); - }, - apply: function(constructor, that, args) { - return new Proxy(constructor.apply(that, args), { - set: function(target, prop, value) { - if ( - prop !== "isPersistent" && - !target.constructor.Interface.hasOwnProperty(prop) && - shouldBeReleasedProperties.indexOf(prop) === -1 - ) { - !(didWarnForAddedNewProperty || target.isPersistent()) - ? warning( - false, - "This synthetic event is reused for performance reasons. If you're " + - "seeing this, you're adding a new property in the synthetic event object. " + - "The property is never released. See " + - "https://fb.me/react-event-pooling for more information." - ) - : void 0; - didWarnForAddedNewProperty = true; - } - target[prop] = value; - return true; - } - }); - } - }); - /*eslint-enable no-func-assign */ - } -} - -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$$1 - }; - - function set(val) { - var action = isFunction ? "setting the method" : "setting the property"; - warn(action, "This is effectively a no-op"); - return val; - } - - function get$$1() { - 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 - ? warning( - 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; - invariant( - event instanceof EventConstructor, - "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; -} - -var SyntheticEvent$1 = SyntheticEvent; - -/** - * `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$1.extend({ - touchHistory: function(nativeEvent) { - return null; // Actually doesn't even look at the native event. - } -}); - -/** - * 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; - - invariant(identifier != null, "Touch object is missing identifier."); - { - !(identifier <= MAX_TOUCH_BANK) - ? warning( - 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) - ? warning(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) { - invariant( - next != null, - "accumulate(...): Accumulated items must be 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; - -/** - * Last reported number of active touches. - */ -var previousActiveTouches = 0; - -var changeResponder = function(nextResponderInst, blockHostResponder) { - var oldResponderInst = responderInst; - responderInst = nextResponderInst; - if (ResponderEventPlugin.GlobalResponderHandler !== null) { - ResponderEventPlugin.GlobalResponderHandler.onChange( - oldResponderInst, - nextResponderInst, - blockHostResponder - ); - } -}; - -var eventTypes$1 = { - /** - * On a `touchStart`/`mouseDown`, is it desired that this element become the - * responder? - */ - startShouldSetResponder: { - phasedRegistrationNames: { - bubbled: "onStartShouldSetResponder", - captured: "onStartShouldSetResponderCapture" - } - }, - - /** - * 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" - } - }, - - /** - * 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" - } - }, - - /** - * On a `touchMove`/`mouseMove`, is it desired that this element become the - * responder? - */ - moveShouldSetResponder: { - phasedRegistrationNames: { - bubbled: "onMoveShouldSetResponder", - captured: "onMoveShouldSetResponderCapture" - } - }, - - /** - * Direct responder events dispatched directly to responder. Do not bubble. - */ - responderStart: { registrationName: "onResponderStart" }, - responderMove: { registrationName: "onResponderMove" }, - responderEnd: { registrationName: "onResponderEnd" }, - responderRelease: { registrationName: "onResponderRelease" }, - responderTerminationRequest: { - registrationName: "onResponderTerminationRequest" - }, - responderGrant: { registrationName: "onResponderGrant" }, - responderReject: { registrationName: "onResponderReject" }, - responderTerminate: { registrationName: "onResponderTerminate" } -}; - -/** - * - * 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$1.startShouldSetResponder - : isMoveish(topLevelType) - ? eventTypes$1.moveShouldSetResponder - : topLevelType === "topSelectionChange" - ? eventTypes$1.selectionChangeShouldSetResponder - : eventTypes$1.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$1.responderGrant, - wantsResponderInst, - nativeEvent, - nativeEventTarget - ); - grantEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; - - accumulateDirectDispatches(grantEvent); - var blockHostResponder = executeDirectDispatch(grantEvent) === true; - if (responderInst) { - var terminationRequestEvent = ResponderSyntheticEvent.getPooled( - eventTypes$1.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$1.responderTerminate, - responderInst, - nativeEvent, - nativeEventTarget - ); - terminateEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; - accumulateDirectDispatches(terminateEvent); - extracted = accumulate(extracted, [grantEvent, terminateEvent]); - changeResponder(wantsResponderInst, blockHostResponder); - } else { - var rejectEvent = ResponderSyntheticEvent.getPooled( - eventTypes$1.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 === "topScroll" && !nativeEvent.responderIgnoreScroll) || - (trackedTouchCount > 0 && topLevelType === "topSelectionChange") || - 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$1, - - /** - * 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$1.responderStart - : isResponderTouchMove - ? eventTypes$1.responderMove - : isResponderTouchEnd ? eventTypes$1.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 === "topTouchCancel"; - var isResponderRelease = - responderInst && - !isResponderTerminate && - isEndish(topLevelType) && - noResponderTouches(nativeEvent); - var finalTouch = isResponderTerminate - ? eventTypes$1.responderTerminate - : isResponderRelease ? eventTypes$1.responderRelease : null; - if (finalTouch) { - var finalEvent = ResponderSyntheticEvent.getPooled( - finalTouch, - responderInst, - nativeEvent, - nativeEventTarget - ); - finalEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; - accumulateDirectDispatches(finalEvent); - extracted = accumulate(extracted, finalEvent); - changeResponder(null); - } - - var numberActiveTouches = - ResponderTouchHistoryStore.touchHistory.numberActiveTouches; - if ( - ResponderEventPlugin.GlobalInteractionHandler && - numberActiveTouches !== previousActiveTouches - ) { - ResponderEventPlugin.GlobalInteractionHandler.onChange( - numberActiveTouches - ); - } - previousActiveTouches = numberActiveTouches; - - return extracted; - }, - - GlobalResponderHandler: null, - GlobalInteractionHandler: 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; - }, - - /** - * @param {{onChange: (numberActiveTouches) => void} GlobalInteractionHandler - * Object that handles any change in the number of active touches. - */ - injectGlobalInteractionHandler: function(GlobalInteractionHandler) { - ResponderEventPlugin.GlobalInteractionHandler = GlobalInteractionHandler; - } - } -}; - -var customBubblingEventTypes$1 = - ReactNativeViewConfigRegistry.customBubblingEventTypes; -var customDirectEventTypes$1 = - ReactNativeViewConfigRegistry.customDirectEventTypes; -var eventTypes$2 = ReactNativeViewConfigRegistry.eventTypes; - -var ReactNativeBridgeEventPlugin = { - eventTypes: eventTypes$2, - - /** - * @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$1[topLevelType]; - var directDispatchConfig = customDirectEventTypes$1[topLevelType]; - invariant( - bubbleDispatchConfig || directDispatchConfig, - 'Unsupported top level event type "%s" dispatched', - topLevelType - ); - var event = SyntheticEvent$1.getPooled( - bubbleDispatchConfig || directDispatchConfig, - targetInst, - nativeEvent, - nativeEventTarget - ); - if (bubbleDispatchConfig) { - accumulateTwoPhaseDispatches(event); - } else if (directDispatchConfig) { - accumulateDirectDispatches(event); - } else { - return null; - } - return event; - } -}; - -var instanceCache = {}; -var instanceProps = {}; - -function precacheFiberNode(hostInst, tag) { - instanceCache[tag] = hostInst; -} - -function uncacheFiberNode(tag) { - delete instanceCache[tag]; - delete instanceProps[tag]; -} - -function getInstanceFromTag(tag) { - if (typeof tag === "number") { - return instanceCache[tag] || null; - } else { - // Fabric will invoke event emitters on a direct fiber reference - return tag; - } -} - -function getTagFromInstance(inst) { - var tag = inst.stateNode._nativeTag; - if (tag === undefined) { - tag = inst.stateNode.canonical._nativeTag; - } - invariant(tag, "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; -} - -var ReactNativeComponentTree = Object.freeze({ - precacheFiberNode: precacheFiberNode, - uncacheFiberNode: uncacheFiberNode, - getClosestInstanceFromNode: getInstanceFromTag, - getInstanceFromNode: getInstanceFromTag, - getNodeFromInstance: getTagFromInstance, - getFiberCurrentPropsFromNode: getFiberCurrentPropsFromNode$1, - updateFiberProps: updateFiberProps -}); - -var ReactNativeEventPluginOrder = [ - "ResponderEventPlugin", - "ReactNativeBridgeEventPlugin" -]; - -// Module provided by RN: -var ReactNativeGlobalResponderHandler = { - onChange: function(from, to, blockNativeResponder) { - if (to !== null) { - var tag = to.stateNode._nativeTag; - UIManager.setJSResponder(tag, blockNativeResponder); - } else { - UIManager.clearJSResponder(); - } - } -}; - -/** - * 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); -injection$1.injectComponentTree(ReactNativeComponentTree); - -ResponderEventPlugin.injection.injectGlobalResponderHandler( - ReactNativeGlobalResponderHandler -); - -/** - * Some important event plugins included by default (without having to require - * them). - */ -injection.injectEventPluginsByName({ - ResponderEventPlugin: ResponderEventPlugin, - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin -}); - -// Use to restore controlled state after a change event has fired. - -var fiberHostComponent = 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; - } - invariant( - fiberHostComponent && - typeof fiberHostComponent.restoreControlledState === "function", - "Fiber needs to be injected to handle a fiber target for controlled " + - "events. This error is likely caused by a bug in React. Please file an issue." - ); - var props = getFiberCurrentPropsFromNode(internalInstance.stateNode); - fiberHostComponent.restoreControlledState( - 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 _batchedUpdates = function(fn, bookkeeping) { - return fn(bookkeeping); -}; -var _interactiveUpdates = function(fn, a, b) { - return fn(a, b); -}; -var _flushInteractiveUpdates = 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 _batchedUpdates(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. - _flushInteractiveUpdates(); - restoreStateIfNeeded(); - } - } -} - -var injection$2 = { - injectRenderer: function(renderer) { - _batchedUpdates = renderer.batchedUpdates; - _interactiveUpdates = renderer.interactiveUpdates; - _flushInteractiveUpdates = renderer.flushInteractiveUpdates; - } -}; - -/** - * 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() { - runExtractedEventsInBatch( - 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) { - { - warning( - 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); - } -} - -var ReactNativeEventEmitter = Object.freeze({ - getListener: getListener, - registrationNames: registrationNameModules, - _receiveRootNodeIDEvent: _receiveRootNodeIDEvent, - receiveEvent: receiveEvent, - receiveTouches: receiveTouches -}); - -// Module provided by RN: -/** - * Register the event emitter with the native bridge - */ -RCTEventEmitter.register(ReactNativeEventEmitter); - -// 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_CALL_TYPE = hasSymbol ? Symbol["for"]("react.call") : 0xeac8; -var REACT_RETURN_TYPE = hasSymbol ? Symbol["for"]("react.return") : 0xeac9; -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_PROVIDER_TYPE = hasSymbol ? Symbol["for"]("react.provider") : 0xeacd; -var REACT_CONTEXT_TYPE = hasSymbol ? Symbol["for"]("react.context") : 0xeace; -var REACT_ASYNC_MODE_TYPE = hasSymbol - ? Symbol["for"]("react.async_mode") - : 0xeacf; -var REACT_FORWARD_REF_TYPE = hasSymbol - ? Symbol["for"]("react.forward_ref") - : 0xead0; - -var MAYBE_ITERATOR_SYMBOL = typeof Symbol === "function" && Symbol.iterator; -var FAUX_ITERATOR_SYMBOL = "@@iterator"; - -function getIteratorFn(maybeIterable) { - if (maybeIterable === null || typeof maybeIterable === "undefined") { - return null; - } - var maybeIterator = - (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || - maybeIterable[FAUX_ITERATOR_SYMBOL]; - if (typeof maybeIterator === "function") { - return maybeIterator; - } - return null; -} - -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.3.2"; - -var describeComponentFrame = function(name, source, ownerName) { - return ( - "\n in " + - (name || "Unknown") + - (source - ? " (at " + - source.fileName.replace(/^.*[\\\/]/, "") + - ":" + - source.lineNumber + - ")" - : ownerName ? " (created by " + ownerName + ")" : "") - ); -}; - -function getComponentName(fiber) { - var type = fiber.type; - - if (typeof type === "function") { - return type.displayName || type.name; - } - if (typeof type === "string") { - return type; - } - switch (type) { - case REACT_FRAGMENT_TYPE: - return "ReactFragment"; - case REACT_PORTAL_TYPE: - return "ReactPortal"; - case REACT_CALL_TYPE: - return "ReactCall"; - case REACT_RETURN_TYPE: - return "ReactReturn"; - } - if (typeof type === "object" && type !== null) { - switch (type.$$typeof) { - case REACT_FORWARD_REF_TYPE: - var functionName = type.render.displayName || type.render.name || ""; - return functionName !== "" - ? "ForwardRef(" + functionName + ")" - : "ForwardRef"; - } - } - return null; -} - -function describeFiber(fiber) { - switch (fiber.tag) { - case IndeterminateComponent: - case FunctionalComponent: - case ClassComponent: - case HostComponent: - var owner = fiber._debugOwner; - var source = fiber._debugSource; - var name = getComponentName(fiber); - var ownerName = null; - if (owner) { - ownerName = getComponentName(owner); - } - return describeComponentFrame(name, source, ownerName); - default: - return ""; - } -} - -// This function can only be called with a work-in-progress fiber and -// only during begin or complete phase. Do not call it under any other -// circumstances. -function getStackAddendumByWorkInProgressFiber(workInProgress) { - var info = ""; - var node = workInProgress; - do { - info += describeFiber(node); - // Otherwise this return pointer might point to the wrong tree: - node = node["return"]; - } while (node); - return info; -} - -// Modules provided by RN: -var emptyObject$1 = {}; - -/** - * 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 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. - 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. - 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$1, 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$1, - 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(context, callback) { - return function() { - if (!callback) { - return undefined; - } - if (typeof context.__isMounted === "boolean") { - // TODO(gaearon): this is gross and should be removed. - // It is currently necessary because View uses createClass, - // and so any measure() calls on View (which are done by React - // DevTools) trigger the isMounted() deprecation warning. - if (!context.__isMounted) { - return undefined; - } - // The else branch is important so that we don't - // trigger the deprecation warning by calling isMounted. - } else if (typeof context.isMounted === "function") { - if (!context.isMounted()) { - return undefined; - } - } - 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 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) { - UIManager.measure( - findNodeHandle(this), - mountSafeCallback(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) { - UIManager.measureInWindow( - findNodeHandle(this), - mountSafeCallback(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 */ - ) { - UIManager.measureLayout( - findNodeHandle(this), - relativeToNativeNode, - mountSafeCallback(this, onFail), - mountSafeCallback(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; - } - - var viewConfig = maybeInstance.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) { - UIManager.updateView( - maybeInstance._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() { - TextInputState.focusTextInput(findNodeHandle(this)); - }, - - /** - * Removes focus from an input or view. This is the opposite of `focus()`. - */ - blur: function() { - 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; - invariant( - !NativeMethodsMixin_DEV.componentWillMount && - !NativeMethodsMixin_DEV.componentWillReceiveProps && - !NativeMethodsMixin_DEV.UNSAFE_componentWillMount && - !NativeMethodsMixin_DEV.UNSAFE_componentWillReceiveProps, - "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(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(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() { - TextInputState.blurTextInput(findNodeHandle(this)); - }; - - /** - * Requests focus. The exact behavior depends on the platform and view. - */ - - ReactNativeComponent.prototype.focus = function focus() { - 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) { - UIManager.measure( - findNodeHandle(this), - mountSafeCallback(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 - ) { - UIManager.measureInWindow( - findNodeHandle(this), - mountSafeCallback(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 */ - ) { - UIManager.measureLayout( - findNodeHandle(this), - relativeToNativeNode, - mountSafeCallback(this, onFail), - mountSafeCallback(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; - } - - 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) { - UIManager.updateView( - maybeInstance._nativeTag, - viewConfig.uiViewClassName, - updatePayload - ); - } - }; - - return ReactNativeComponent; - })(React.Component); - - // eslint-disable-next-line no-unused-expressions - - return ReactNativeComponent; -}; - -/** - * `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$1(key) { - return key._reactInternalFiber; -} - -function set(key, value) { - key._reactInternalFiber = value; -} - -var ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; - -var ReactCurrentOwner = ReactInternals.ReactCurrentOwner; -var ReactDebugCurrentFrame = ReactInternals.ReactDebugCurrentFrame; - -// 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 ErrLog = /* */ 256; -var Snapshot = /* */ 2048; - -// Union of all host effects -var HostEffectMask = /* */ 2559; - -var Incomplete = /* */ 512; -var ShouldCapture = /* */ 1024; - -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.current; - if (owner !== null && owner.tag === ClassComponent) { - var ownerFiber = owner; - var instance = ownerFiber.stateNode; - !instance._warnedAboutRefsInRender - ? warning( - 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) || "A component" - ) - : void 0; - instance._warnedAboutRefsInRender = true; - } - } - - var fiber = get$1(component); - if (!fiber) { - return false; - } - return isFiberMountedImpl(fiber) === MOUNTED; -} - -function assertIsMounted(fiber) { - invariant( - isFiberMountedImpl(fiber) === MOUNTED, - "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); - invariant( - state !== UNMOUNTED, - "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"]; - var parentB = parentA ? parentA.alternate : null; - if (!parentA || !parentB) { - // 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. - invariant(false, "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; - } - invariant( - didFindChild, - "Child was not found in either parent set. This indicates a bug " + - "in React related to the return pointer. Please file an issue." - ); - } - } - - invariant( - a.alternate === b, - "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. - invariant( - a.tag === HostRoot, - "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; -} - -function findCurrentHostFiberWithNoPortals(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.tag !== HostPortal) { - 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; -} - -// 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; - -// TODO: Use an opaque type once ESLint et al support the syntax - -var NoWork = 0; -var Sync = 1; -var Never = MAX_SIGNED_31_BIT_INT; - -var UNIT_SIZE = 10; -var MAGIC_NUMBER_OFFSET = 2; - -// 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 ((ms / UNIT_SIZE) | 0) + MAGIC_NUMBER_OFFSET; -} - -function expirationTimeToMs(expirationTime) { - return (expirationTime - MAGIC_NUMBER_OFFSET) * UNIT_SIZE; -} - -function ceiling(num, precision) { - return (((num / precision) | 0) + 1) * precision; -} - -function computeExpirationBucket(currentTime, expirationInMs, bucketSizeMs) { - return ceiling( - currentTime + expirationInMs / UNIT_SIZE, - bucketSizeMs / UNIT_SIZE - ); -} - -var NoContext = 0; -var AsyncMode = 1; -var StrictMode = 2; - -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.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.mode = mode; - - // Effects - this.effectTag = NoEffect; - this.nextEffect = null; - - this.firstEffect = null; - this.lastEffect = null; - - this.expirationTime = NoWork; - - this.alternate = null; - - { - this._debugID = debugCounter++; - this._debugSource = null; - this._debugOwner = null; - this._debugIsCurrentlyTiming = false; - 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) { - return !!(Component.prototype && Component.prototype.isReactComponent); -} - -// 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.type = current.type; - workInProgress.stateNode = current.stateNode; - - { - // DEV-only fields - workInProgress._debugID = current._debugID; - workInProgress._debugSource = current._debugSource; - workInProgress._debugOwner = current._debugOwner; - } - - 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; - } - - workInProgress.expirationTime = expirationTime; - - workInProgress.child = current.child; - workInProgress.memoizedProps = current.memoizedProps; - workInProgress.memoizedState = current.memoizedState; - workInProgress.updateQueue = current.updateQueue; - - // These will be overridden during the parent's reconciliation - workInProgress.sibling = current.sibling; - workInProgress.index = current.index; - workInProgress.ref = current.ref; - - return workInProgress; -} - -function createHostRootFiber(isAsync) { - var mode = isAsync ? AsyncMode | StrictMode : NoContext; - return createFiber(HostRoot, null, null, mode); -} - -function createFiberFromElement(element, mode, expirationTime) { - var owner = null; - { - owner = element._owner; - } - - var fiber = void 0; - var type = element.type; - var key = element.key; - var pendingProps = element.props; - - var fiberTag = void 0; - if (typeof type === "function") { - fiberTag = shouldConstruct(type) ? ClassComponent : IndeterminateComponent; - } else if (typeof type === "string") { - fiberTag = HostComponent; - } else { - switch (type) { - case REACT_FRAGMENT_TYPE: - return createFiberFromFragment( - pendingProps.children, - mode, - expirationTime, - key - ); - case REACT_ASYNC_MODE_TYPE: - fiberTag = Mode; - mode |= AsyncMode | StrictMode; - break; - case REACT_STRICT_MODE_TYPE: - fiberTag = Mode; - mode |= StrictMode; - break; - case REACT_CALL_TYPE: - fiberTag = CallComponent; - break; - case REACT_RETURN_TYPE: - fiberTag = ReturnComponent; - break; - default: { - if (typeof type === "object" && type !== null) { - switch (type.$$typeof) { - case REACT_PROVIDER_TYPE: - fiberTag = ContextProvider; - break; - case REACT_CONTEXT_TYPE: - // This is a consumer - fiberTag = ContextConsumer; - break; - case REACT_FORWARD_REF_TYPE: - fiberTag = ForwardRef; - break; - default: - if (typeof type.tag === "number") { - // Currently assumed to be a continuation and therefore is a - // fiber already. - // TODO: The yield system is currently broken for updates in - // some cases. The reified yield stores a fiber, but we don't - // know which fiber that is; the current or a workInProgress? - // When the continuation gets rendered here we don't know if we - // can reuse that fiber or if we need to clone it. There is - // probably a clever way to restructure this. - fiber = type; - fiber.pendingProps = pendingProps; - fiber.expirationTime = expirationTime; - return fiber; - } else { - throwOnInvalidElementType(type, owner); - } - break; - } - } else { - throwOnInvalidElementType(type, owner); - } - } - } - } - - fiber = createFiber(fiberTag, pendingProps, key, mode); - fiber.type = type; - fiber.expirationTime = expirationTime; - - { - fiber._debugSource = element._source; - fiber._debugOwner = element._owner; - } - - return fiber; -} - -function throwOnInvalidElementType(type, owner) { - 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) : null; - if (ownerName) { - info += "\n\nCheck the render method of `" + ownerName + "`."; - } - } - invariant( - false, - "Element type is invalid: expected a string (for built-in " + - "components) or a class/function (for composite components) " + - "but got: %s.%s", - type == null ? type : typeof type, - info - ); -} - -function createFiberFromFragment(elements, mode, expirationTime, key) { - var fiber = createFiber(Fragment, elements, key, mode); - 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); - 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.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.mode = source.mode; - target.effectTag = source.effectTag; - target.nextEffect = source.nextEffect; - target.firstEffect = source.firstEffect; - target.lastEffect = source.lastEffect; - target.expirationTime = source.expirationTime; - target.alternate = source.alternate; - target._debugID = source._debugID; - target._debugSource = source._debugSource; - target._debugOwner = source._debugOwner; - target._debugIsCurrentlyTiming = source._debugIsCurrentlyTiming; - return target; -} - -// TODO: This should be lifted into the renderer. - -function createFiberRoot(containerInfo, isAsync, hydrate) { - // Cyclic construction. This cheats the type system right now because - // stateNode is any. - var uninitializedFiber = createHostRootFiber(isAsync); - var root = { - current: uninitializedFiber, - containerInfo: containerInfo, - pendingChildren: null, - pendingCommitExpirationTime: NoWork, - finishedWork: null, - context: null, - pendingContext: null, - hydrate: hydrate, - remainingExpirationTime: NoWork, - firstBatch: null, - nextScheduledRoot: null - }; - uninitializedFiber.stateNode = root; - return root; -} - -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; - warning(false, "React DevTools encountered an error: %s", err); - } - } - }; -} - -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) { - { - warning( - 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. - { - warning(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); - } -} - -/** - * 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( - "`warning(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) {} -}; - -{ - var LIFECYCLE_SUGGESTIONS = { - UNSAFE_componentWillMount: "componentDidMount", - UNSAFE_componentWillReceiveProps: "static getDerivedStateFromProps", - UNSAFE_componentWillUpdate: "componentDidUpdate" - }; - - var pendingComponentWillMountWarnings = []; - var pendingComponentWillReceivePropsWarnings = []; - var pendingComponentWillUpdateWarnings = []; - var pendingUnsafeLifecycleWarnings = new Map(); - - // Tracks components we have already warned about. - var didWarnAboutDeprecatedLifecycles = new Set(); - var didWarnAboutUnsafeLifecycles = 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(); - }; - - ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = function() { - pendingUnsafeLifecycleWarnings.forEach(function( - lifecycleWarningsMap, - strictRoot - ) { - var lifecyclesWarningMesages = []; - - 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) || "Component"); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - - var formatted = lifecycle.replace("UNSAFE_", ""); - var suggestion = LIFECYCLE_SUGGESTIONS[lifecycle]; - var sortedComponentNames = setToSortedString(componentNames); - - lifecyclesWarningMesages.push( - formatted + - ": Please update the following components to use " + - (suggestion + " instead: " + sortedComponentNames) - ); - } - }); - - if (lifecyclesWarningMesages.length > 0) { - var strictRootComponentStack = getStackAddendumByWorkInProgressFiber( - strictRoot - ); - - warning( - 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, - lifecyclesWarningMesages.join("\n\n") - ); - } - }); - - pendingUnsafeLifecycleWarnings = new Map(); - }; - - var getStrictRoot = function(fiber) { - var maybeStrictRoot = null; - - while (fiber !== null) { - if (fiber.mode & StrictMode) { - maybeStrictRoot = fiber; - } - - fiber = fiber["return"]; - } - - return maybeStrictRoot; - }; - - ReactStrictModeWarnings.flushPendingDeprecationWarnings = function() { - if (pendingComponentWillMountWarnings.length > 0) { - var uniqueNames = new Set(); - pendingComponentWillMountWarnings.forEach(function(fiber) { - uniqueNames.add(getComponentName(fiber) || "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) || "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) || "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 = getStrictRoot(fiber); - - // 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; - } - - // Don't warn about react-lifecycles-compat polyfilled components. - // Note that it is sufficient to check for the presence of a - // single lifecycle, componentWillMount, with the polyfill flag. - if ( - typeof instance.componentWillMount === "function" && - instance.componentWillMount.__suppressDeprecationWarning === true - ) { - 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" || - typeof instance.UNSAFE_componentWillMount === "function" - ) { - unsafeLifecycles.push("UNSAFE_componentWillMount"); - } - if ( - typeof instance.componentWillReceiveProps === "function" || - typeof instance.UNSAFE_componentWillReceiveProps === "function" - ) { - unsafeLifecycles.push("UNSAFE_componentWillReceiveProps"); - } - if ( - typeof instance.componentWillUpdate === "function" || - typeof instance.UNSAFE_componentWillUpdate === "function" - ) { - unsafeLifecycles.push("UNSAFE_componentWillUpdate"); - } - - if (unsafeLifecycles.length > 0) { - unsafeLifecycles.forEach(function(lifecycle) { - warningsForRoot[lifecycle].push(fiber); - }); - } - }; -} - -// Re-export dynamic flags from the fbsource version. -var _require = require("ReactFeatureFlags"); - -var enableGetDerivedStateFromCatch = _require.enableGetDerivedStateFromCatch; -var debugRenderPhaseSideEffects = _require.debugRenderPhaseSideEffects; -var debugRenderPhaseSideEffectsForStrictMode = - _require.debugRenderPhaseSideEffectsForStrictMode; -var warnAboutDeprecatedLifecycles = _require.warnAboutDeprecatedLifecycles; -var replayFailedUnitOfWorkWithInvokeGuardedCallback = - _require.replayFailedUnitOfWorkWithInvokeGuardedCallback; - -var enableUserTimingAPI = true; -var enableMutatingReconciler = true; -var enableNoopReconciler = false; -var enablePersistentReconciler = false; - -// Only used in www builds. - -function getCurrentFiberOwnerName() { - { - var fiber = ReactDebugCurrentFiber.current; - if (fiber === null) { - return null; - } - var owner = fiber._debugOwner; - if (owner !== null && typeof owner !== "undefined") { - return getComponentName(owner); - } - } - return null; -} - -function getCurrentFiberStackAddendum() { - { - var fiber = ReactDebugCurrentFiber.current; - if (fiber === null) { - return null; - } - // Safe because if current fiber exists, we are reconciling, - // and it is guaranteed to be the work-in-progress version. - return getStackAddendumByWorkInProgressFiber(fiber); - } - return null; -} - -function resetCurrentFiber() { - ReactDebugCurrentFrame.getCurrentStack = null; - ReactDebugCurrentFiber.current = null; - ReactDebugCurrentFiber.phase = null; -} - -function setCurrentFiber(fiber) { - ReactDebugCurrentFrame.getCurrentStack = getCurrentFiberStackAddendum; - ReactDebugCurrentFiber.current = fiber; - ReactDebugCurrentFiber.phase = null; -} - -function setCurrentPhase(phase) { - ReactDebugCurrentFiber.phase = phase; -} - -var ReactDebugCurrentFiber = { - current: null, - phase: null, - resetCurrentFiber: resetCurrentFiber, - setCurrentFiber: setCurrentFiber, - setCurrentPhase: setCurrentPhase, - getCurrentFiberOwnerName: getCurrentFiberOwnerName, - getCurrentFiberStackAddendum: getCurrentFiberStackAddendum -}; - -// 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$$1) { - var prefix = warning$$1 ? warningEmoji + " " : reactEmoji + " "; - var suffix = warning$$1 ? " Warning: " + warning$$1 : ""; - 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$$1) { - var formattedMarkName = formatMarkName(markName); - var formattedLabel = formatLabel(label, warning$$1); - 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) || "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) || "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$$1) { - var componentName = getComponentName(fiber) || "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$$1); -}; - -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 CallComponent: - case ReturnComponent: - 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, expirationTime) { - if (enableUserTimingAPI) { - if (supportsUserTiming) { - isWaitingForCallback = false; - var warning$$1 = didExpire ? "React was blocked by main thread" : null; - endMark( - "(Waiting for async callback... will force flush in " + - expirationTime + - " ms)", - "(Waiting for async callback...)", - warning$$1 - ); - } - } -} - -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$$1 = "An error was thrown inside this error boundary"; - endFiberMark(fiber, null, warning$$1); - } -} - -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$$1 = hasScheduledUpdateInCurrentPhase - ? "Scheduled a cascading update" - : null; - endFiberMark(currentPhaseFiber, currentPhase, warning$$1); - } - 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$$1 = null; - if (interruptedBy !== null) { - if (interruptedBy.tag === HostRoot) { - warning$$1 = "A top-level update interrupted the previous render"; - } else { - var componentName = getComponentName(interruptedBy) || "Unknown"; - warning$$1 = - "An update to " + componentName + " interrupted the previous render"; - } - } else if (commitCountInCurrentWorkLoop > 1) { - warning$$1 = "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$$1); - } -} - -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$$1 = null; - if (hasScheduledUpdateInCurrentCommit) { - warning$$1 = "Lifecycle hook scheduled a cascading update"; - } else if (commitCountInCurrentWorkLoop > 0) { - warning$$1 = "Caused by a cascading update in earlier commit"; - } - hasScheduledUpdateInCurrentCommit = false; - commitCountInCurrentWorkLoop++; - isCommitting = false; - labelsInCurrentCommit.clear(); - - endMark("(Committing Changes)", "(Committing Changes)", warning$$1); - } -} - -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 didWarnUpdateInsideUpdate = void 0; - -{ - didWarnUpdateInsideUpdate = false; -} - -// Callbacks are not validated until invocation - -// Singly linked-list of updates. When an update is scheduled, it is added to -// the queue of the current fiber and the work-in-progress fiber. The two queues -// are separate but they share a persistent structure. -// -// During reconciliation, updates are removed from the work-in-progress fiber, -// but they remain on the current fiber. That ensures that if a work-in-progress -// is aborted, the aborted updates are recovered by cloning from current. -// -// The work-in-progress queue is always a subset of the current queue. -// -// When the tree is committed, the work-in-progress becomes the current. - -function createUpdateQueue(baseState) { - var queue = { - baseState: baseState, - expirationTime: NoWork, - first: null, - last: null, - callbackList: null, - hasForceUpdate: false, - isInitialized: false, - capturedValues: null - }; - { - queue.isProcessing = false; - } - return queue; -} - -function insertUpdateIntoQueue(queue, update) { - // Append the update to the end of the list. - if (queue.last === null) { - // Queue is empty - queue.first = queue.last = update; - } else { - queue.last.next = update; - queue.last = update; - } - if ( - queue.expirationTime === NoWork || - queue.expirationTime > update.expirationTime - ) { - queue.expirationTime = update.expirationTime; - } -} - -var q1 = void 0; -var q2 = void 0; -function ensureUpdateQueues(fiber) { - q1 = q2 = null; - // We'll have at least one and at most two distinct update queues. - var alternateFiber = fiber.alternate; - var queue1 = fiber.updateQueue; - if (queue1 === null) { - // TODO: We don't know what the base state will be until we begin work. - // It depends on which fiber is the next current. Initialize with an empty - // base state, then set to the memoizedState when rendering. Not super - // happy with this approach. - queue1 = fiber.updateQueue = createUpdateQueue(null); - } - - var queue2 = void 0; - if (alternateFiber !== null) { - queue2 = alternateFiber.updateQueue; - if (queue2 === null) { - queue2 = alternateFiber.updateQueue = createUpdateQueue(null); - } - } else { - queue2 = null; - } - queue2 = queue2 !== queue1 ? queue2 : null; - - // Use module variables instead of returning a tuple - q1 = queue1; - q2 = queue2; -} - -function insertUpdateIntoFiber(fiber, update) { - ensureUpdateQueues(fiber); - var queue1 = q1; - var queue2 = q2; - - // Warn if an update is scheduled from inside an updater function. - { - if ( - (queue1.isProcessing || (queue2 !== null && queue2.isProcessing)) && - !didWarnUpdateInsideUpdate - ) { - warning( - 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; - } - } - - // If there's only one queue, add the update to that queue and exit. - if (queue2 === null) { - insertUpdateIntoQueue(queue1, update); - return; - } - - // If either queue is empty, we need to add to both queues. - if (queue1.last === null || queue2.last === null) { - insertUpdateIntoQueue(queue1, update); - insertUpdateIntoQueue(queue2, update); - return; - } - - // If both lists are not empty, the last update is the same for both lists - // because of structural sharing. So, we should only append to one of - // the lists. - insertUpdateIntoQueue(queue1, update); - // But we still need to update the `last` pointer of queue2. - queue2.last = update; -} - -function getUpdateExpirationTime(fiber) { - switch (fiber.tag) { - case HostRoot: - case ClassComponent: - var updateQueue = fiber.updateQueue; - if (updateQueue === null) { - return NoWork; - } - return updateQueue.expirationTime; - default: - return NoWork; - } -} - -function getStateFromUpdate(update, instance, prevState, props) { - var partialState = update.partialState; - if (typeof partialState === "function") { - return partialState.call(instance, prevState, props); - } else { - return partialState; - } -} - -function processUpdateQueue( - current, - workInProgress, - queue, - instance, - props, - renderExpirationTime -) { - if (current !== null && current.updateQueue === queue) { - // We need to create a work-in-progress queue, by cloning the current queue. - var currentQueue = queue; - queue = workInProgress.updateQueue = { - baseState: currentQueue.baseState, - expirationTime: currentQueue.expirationTime, - first: currentQueue.first, - last: currentQueue.last, - isInitialized: currentQueue.isInitialized, - capturedValues: currentQueue.capturedValues, - // These fields are no longer valid because they were already committed. - // Reset them. - callbackList: null, - hasForceUpdate: false - }; - } - - { - // Set this flag so we can warn if setState is called inside the update - // function of another setState. - queue.isProcessing = true; - } - - // Reset the remaining expiration time. If we skip over any updates, we'll - // increase this accordingly. - queue.expirationTime = NoWork; - - // TODO: We don't know what the base state will be until we begin work. - // It depends on which fiber is the next current. Initialize with an empty - // base state, then set to the memoizedState when rendering. Not super - // happy with this approach. - var state = void 0; - if (queue.isInitialized) { - state = queue.baseState; - } else { - state = queue.baseState = workInProgress.memoizedState; - queue.isInitialized = true; - } - var dontMutatePrevState = true; - var update = queue.first; - var didSkip = false; - while (update !== null) { - var updateExpirationTime = update.expirationTime; - if (updateExpirationTime > renderExpirationTime) { - // This update does not have sufficient priority. Skip it. - var remainingExpirationTime = queue.expirationTime; - if ( - remainingExpirationTime === NoWork || - remainingExpirationTime > updateExpirationTime - ) { - // Update the remaining expiration time. - queue.expirationTime = updateExpirationTime; - } - if (!didSkip) { - didSkip = true; - queue.baseState = state; - } - // Continue to the next update. - update = update.next; - continue; - } - - // This update does have sufficient priority. - - // If no previous updates were skipped, drop this update from the queue by - // advancing the head of the list. - if (!didSkip) { - queue.first = update.next; - if (queue.first === null) { - queue.last = null; - } - } - - // Invoke setState callback an extra time to help detect side-effects. - // Ignore the return value in this case. - if ( - debugRenderPhaseSideEffects || - (debugRenderPhaseSideEffectsForStrictMode && - workInProgress.mode & StrictMode) - ) { - getStateFromUpdate(update, instance, state, props); - } - - // Process the update - var _partialState = void 0; - if (update.isReplace) { - state = getStateFromUpdate(update, instance, state, props); - dontMutatePrevState = true; - } else { - _partialState = getStateFromUpdate(update, instance, state, props); - if (_partialState) { - if (dontMutatePrevState) { - // $FlowFixMe: Idk how to type this properly. - state = Object.assign({}, state, _partialState); - } else { - state = Object.assign(state, _partialState); - } - dontMutatePrevState = false; - } - } - if (update.isForced) { - queue.hasForceUpdate = true; - } - if (update.callback !== null) { - // Append to list of callbacks. - var _callbackList = queue.callbackList; - if (_callbackList === null) { - _callbackList = queue.callbackList = []; - } - _callbackList.push(update); - } - if (update.capturedValue !== null) { - var _capturedValues = queue.capturedValues; - if (_capturedValues === null) { - queue.capturedValues = [update.capturedValue]; - } else { - _capturedValues.push(update.capturedValue); - } - } - update = update.next; - } - - if (queue.callbackList !== null) { - workInProgress.effectTag |= Callback; - } else if ( - queue.first === null && - !queue.hasForceUpdate && - queue.capturedValues === null - ) { - // The queue is empty. We can reset it. - workInProgress.updateQueue = null; - } - - if (!didSkip) { - didSkip = true; - queue.baseState = state; - } - - { - // No longer processing. - queue.isProcessing = false; - } - - return state; -} - -function commitCallbacks(queue, context) { - var callbackList = queue.callbackList; - if (callbackList === null) { - return; - } - // Set the list to null to make sure they don't get called more than once. - queue.callbackList = null; - for (var i = 0; i < callbackList.length; i++) { - var update = callbackList[i]; - var _callback = update.callback; - // This update might be processed again. Clear the callback so it's only - // called once. - update.callback = null; - invariant( - typeof _callback === "function", - "Invalid argument passed as callback. Expected a function. Instead " + - "received: %s", - _callback - ); - _callback.call(context); - } -} - -var fakeInternalInstance = {}; -var isArray = Array.isArray; - -var didWarnAboutStateAssignmentForComponent = void 0; -var didWarnAboutUndefinedDerivedState = void 0; -var didWarnAboutUninitializedState = void 0; -var didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = void 0; -var didWarnAboutLegacyLifecyclesAndDerivedState = void 0; -var warnOnInvalidCallback = void 0; - -{ - didWarnAboutStateAssignmentForComponent = new Set(); - didWarnAboutUndefinedDerivedState = new Set(); - didWarnAboutUninitializedState = new Set(); - didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = new Set(); - didWarnAboutLegacyLifecyclesAndDerivedState = 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); - warning( - false, - "%s(...): Expected the last optional `callback` argument to be a " + - "function. Instead received: %s.", - callerName, - callback - ); - } - }; - - // 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() { - invariant( - false, - "_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 callGetDerivedStateFromCatch(ctor, capturedValues) { - var resultState = {}; - for (var i = 0; i < capturedValues.length; i++) { - var capturedValue = capturedValues[i]; - var error = capturedValue.value; - var partialState = ctor.getDerivedStateFromCatch.call(null, error); - if (partialState !== null && partialState !== undefined) { - Object.assign(resultState, partialState); - } - } - return resultState; -} - -var ReactFiberClassComponent = function( - legacyContext, - scheduleWork, - computeExpirationForFiber, - memoizeProps, - memoizeState -) { - var cacheContext = legacyContext.cacheContext, - getMaskedContext = legacyContext.getMaskedContext, - getUnmaskedContext = legacyContext.getUnmaskedContext, - isContextConsumer = legacyContext.isContextConsumer, - hasContextChanged = legacyContext.hasContextChanged; - - // Class component state updater - - var updater = { - isMounted: isMounted, - enqueueSetState: function(instance, partialState, callback) { - var fiber = get$1(instance); - callback = callback === undefined ? null : callback; - { - warnOnInvalidCallback(callback, "setState"); - } - var expirationTime = computeExpirationForFiber(fiber); - var update = { - expirationTime: expirationTime, - partialState: partialState, - callback: callback, - isReplace: false, - isForced: false, - capturedValue: null, - next: null - }; - insertUpdateIntoFiber(fiber, update); - scheduleWork(fiber, expirationTime); - }, - enqueueReplaceState: function(instance, state, callback) { - var fiber = get$1(instance); - callback = callback === undefined ? null : callback; - { - warnOnInvalidCallback(callback, "replaceState"); - } - var expirationTime = computeExpirationForFiber(fiber); - var update = { - expirationTime: expirationTime, - partialState: state, - callback: callback, - isReplace: true, - isForced: false, - capturedValue: null, - next: null - }; - insertUpdateIntoFiber(fiber, update); - scheduleWork(fiber, expirationTime); - }, - enqueueForceUpdate: function(instance, callback) { - var fiber = get$1(instance); - callback = callback === undefined ? null : callback; - { - warnOnInvalidCallback(callback, "forceUpdate"); - } - var expirationTime = computeExpirationForFiber(fiber); - var update = { - expirationTime: expirationTime, - partialState: null, - callback: callback, - isReplace: false, - isForced: true, - capturedValue: null, - next: null - }; - insertUpdateIntoFiber(fiber, update); - scheduleWork(fiber, expirationTime); - } - }; - - function checkShouldComponentUpdate( - workInProgress, - oldProps, - newProps, - oldState, - newState, - newContext - ) { - if ( - oldProps === null || - (workInProgress.updateQueue !== null && - workInProgress.updateQueue.hasForceUpdate) - ) { - // If the workInProgress already has an Update effect, return true - return true; - } - - var instance = workInProgress.stateNode; - var ctor = workInProgress.type; - if (typeof instance.shouldComponentUpdate === "function") { - startPhaseTimer(workInProgress, "shouldComponentUpdate"); - var shouldUpdate = instance.shouldComponentUpdate( - newProps, - newState, - newContext - ); - stopPhaseTimer(); - - { - !(shouldUpdate !== undefined) - ? warning( - false, - "%s.shouldComponentUpdate(): Returned undefined instead of a " + - "boolean value. Make sure to return true or false.", - getComponentName(workInProgress) || "Component" - ) - : void 0; - } - - return shouldUpdate; - } - - if (ctor.prototype && ctor.prototype.isPureReactComponent) { - return ( - !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) - ); - } - - return true; - } - - function checkClassInstance(workInProgress) { - var instance = workInProgress.stateNode; - var type = workInProgress.type; - { - var name = getComponentName(workInProgress) || "Component"; - var renderPresent = instance.render; - - if (!renderPresent) { - if (type.prototype && typeof type.prototype.render === "function") { - warning( - false, - "%s(...): No `render` method found on the returned component " + - "instance: did you accidentally return an object from the constructor?", - name - ); - } else { - warning( - 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 - ? warning( - 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 - ? warning( - 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 - ? warning( - false, - "propTypes was defined as an instance property on %s. Use a static " + - "property to define propTypes instead.", - name - ) - : void 0; - var noInstanceContextTypes = !instance.contextTypes; - !noInstanceContextTypes - ? warning( - false, - "contextTypes was defined as an instance property on %s. Use a static " + - "property to define contextTypes instead.", - name - ) - : void 0; - var noComponentShouldUpdate = - typeof instance.componentShouldUpdate !== "function"; - !noComponentShouldUpdate - ? warning( - 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 ( - type.prototype && - type.prototype.isPureReactComponent && - typeof instance.shouldComponentUpdate !== "undefined" - ) { - warning( - 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(workInProgress) || "A pure component" - ); - } - var noComponentDidUnmount = - typeof instance.componentDidUnmount !== "function"; - !noComponentDidUnmount - ? warning( - 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 - ? warning( - 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 - ? warning( - false, - "%s has a method called " + - "componentWillRecieveProps(). Did you mean componentWillReceiveProps()?", - name - ) - : void 0; - var noUnsafeComponentWillRecieveProps = - typeof instance.UNSAFE_componentWillRecieveProps !== "function"; - !noUnsafeComponentWillRecieveProps - ? warning( - false, - "%s has a method called " + - "UNSAFE_componentWillRecieveProps(). Did you mean UNSAFE_componentWillReceiveProps()?", - name - ) - : void 0; - var hasMutatedProps = instance.props !== workInProgress.pendingProps; - !(instance.props === undefined || !hasMutatedProps) - ? warning( - 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 - ? warning( - 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(type) - ) { - didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.add(type); - warning( - false, - "%s: getSnapshotBeforeUpdate() should be used with componentDidUpdate(). " + - "This component defines getSnapshotBeforeUpdate() only.", - getComponentName(workInProgress) - ); - } - - var noInstanceGetDerivedStateFromProps = - typeof instance.getDerivedStateFromProps !== "function"; - !noInstanceGetDerivedStateFromProps - ? warning( - 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.getDerivedStateFromCatch !== "function"; - !noInstanceGetDerivedStateFromCatch - ? warning( - false, - "%s: getDerivedStateFromCatch() is defined as an instance method " + - "and will be ignored. Instead, declare it as a static method.", - name - ) - : void 0; - var noStaticGetSnapshotBeforeUpdate = - typeof type.getSnapshotBeforeUpdate !== "function"; - !noStaticGetSnapshotBeforeUpdate - ? warning( - 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(_state))) { - warning(false, "%s.state: must be set to an object or null", name); - } - if (typeof instance.getChildContext === "function") { - !(typeof type.childContextTypes === "object") - ? warning( - false, - "%s.getChildContext(): childContextTypes must be defined in order to " + - "use getChildContext().", - name - ) - : void 0; - } - } - } - - function resetInputPointers(workInProgress, instance) { - instance.props = workInProgress.memoizedProps; - instance.state = workInProgress.memoizedState; - } - - function adoptClassInstance(workInProgress, instance) { - instance.updater = updater; - 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, props) { - var ctor = workInProgress.type; - var unmaskedContext = getUnmaskedContext(workInProgress); - var needsContext = isContextConsumer(workInProgress); - var context = needsContext - ? getMaskedContext(workInProgress, unmaskedContext) - : emptyObject; - - // 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 = - instance.state !== null && instance.state !== undefined - ? instance.state - : null; - adoptClassInstance(workInProgress, instance); - - { - if ( - typeof ctor.getDerivedStateFromProps === "function" && - state === null - ) { - var componentName = getComponentName(workInProgress) || "Component"; - if (!didWarnAboutUninitializedState.has(componentName)) { - didWarnAboutUninitializedState.add(componentName); - warning( - false, - "%s: Did not properly initialize state during construction. " + - "Expected state to be an object, but it was %s.", - componentName, - instance.state === null ? "null" : "undefined" - ); - } - } - - // 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(workInProgress) || "Component"; - var newApiName = - typeof ctor.getDerivedStateFromProps === "function" - ? "getDerivedStateFromProps()" - : "getSnapshotBeforeUpdate()"; - if ( - !didWarnAboutLegacyLifecyclesAndDerivedState.has(_componentName) - ) { - didWarnAboutLegacyLifecyclesAndDerivedState.add(_componentName); - warning( - 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 : "" - ); - } - } - } - } - - workInProgress.memoizedState = state; - - var partialState = callGetDerivedStateFromProps( - workInProgress, - instance, - props, - state - ); - - if (partialState !== null && partialState !== undefined) { - // Render-phase updates (like this) should not be added to the update queue, - // So that multiple render passes do not enqueue multiple updates. - // Instead, just synchronously merge the returned state into the instance. - workInProgress.memoizedState = Object.assign( - {}, - workInProgress.memoizedState, - partialState - ); - } - - // 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 (needsContext) { - 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) { - { - warning( - false, - "%s.componentWillMount(): Assigning directly to this.state is " + - "deprecated (except inside a component's " + - "constructor). Use setState instead.", - getComponentName(workInProgress) || "Component" - ); - } - updater.enqueueReplaceState(instance, instance.state, null); - } - } - - function callComponentWillReceiveProps( - workInProgress, - instance, - newProps, - newContext - ) { - var oldState = instance.state; - startPhaseTimer(workInProgress, "componentWillReceiveProps"); - if (typeof instance.componentWillReceiveProps === "function") { - instance.componentWillReceiveProps(newProps, newContext); - } - if (typeof instance.UNSAFE_componentWillReceiveProps === "function") { - instance.UNSAFE_componentWillReceiveProps(newProps, newContext); - } - stopPhaseTimer(); - - if (instance.state !== oldState) { - { - var componentName = getComponentName(workInProgress) || "Component"; - if (!didWarnAboutStateAssignmentForComponent.has(componentName)) { - didWarnAboutStateAssignmentForComponent.add(componentName); - warning( - false, - "%s.componentWillReceiveProps(): Assigning directly to " + - "this.state is deprecated (except inside a component's " + - "constructor). Use setState instead.", - componentName - ); - } - } - updater.enqueueReplaceState(instance, instance.state, null); - } - } - - function callGetDerivedStateFromProps( - workInProgress, - instance, - nextProps, - prevState - ) { - var type = workInProgress.type; - - if (typeof type.getDerivedStateFromProps === "function") { - if ( - debugRenderPhaseSideEffects || - (debugRenderPhaseSideEffectsForStrictMode && - workInProgress.mode & StrictMode) - ) { - // Invoke method an extra time to help detect side-effects. - type.getDerivedStateFromProps.call(null, nextProps, prevState); - } - - var partialState = type.getDerivedStateFromProps.call( - null, - nextProps, - prevState - ); - - { - if (partialState === undefined) { - var componentName = getComponentName(workInProgress) || "Component"; - if (!didWarnAboutUndefinedDerivedState.has(componentName)) { - didWarnAboutUndefinedDerivedState.add(componentName); - warning( - false, - "%s.getDerivedStateFromProps(): A valid state object (or null) must be returned. " + - "You have returned undefined.", - componentName - ); - } - } - } - - return partialState; - } - } - - // Invokes the mount life-cycles on a previously never rendered instance. - function mountClassInstance(workInProgress, renderExpirationTime) { - var ctor = workInProgress.type; - var current = workInProgress.alternate; - - { - checkClassInstance(workInProgress); - } - - var instance = workInProgress.stateNode; - var props = workInProgress.pendingProps; - var unmaskedContext = getUnmaskedContext(workInProgress); - - instance.props = props; - instance.state = workInProgress.memoizedState; - instance.refs = emptyObject; - instance.context = getMaskedContext(workInProgress, unmaskedContext); - - { - if (workInProgress.mode & StrictMode) { - ReactStrictModeWarnings.recordUnsafeLifecycleWarnings( - workInProgress, - instance - ); - } - - if (warnAboutDeprecatedLifecycles) { - ReactStrictModeWarnings.recordDeprecationWarnings( - workInProgress, - instance - ); - } - } - - // 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. - var updateQueue = workInProgress.updateQueue; - if (updateQueue !== null) { - instance.state = processUpdateQueue( - current, - workInProgress, - updateQueue, - instance, - props, - renderExpirationTime - ); - } - } - if (typeof instance.componentDidMount === "function") { - workInProgress.effectTag |= Update; - } - } - - function resumeMountClassInstance(workInProgress, renderExpirationTime) { - var ctor = workInProgress.type; - var instance = workInProgress.stateNode; - resetInputPointers(workInProgress, instance); - - var oldProps = workInProgress.memoizedProps; - var newProps = workInProgress.pendingProps; - var oldContext = instance.context; - var newUnmaskedContext = getUnmaskedContext(workInProgress); - var newContext = getMaskedContext(workInProgress, newUnmaskedContext); - - var hasNewLifecycles = - typeof ctor.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 !== newContext) { - callComponentWillReceiveProps( - workInProgress, - instance, - newProps, - newContext - ); - } - } - - // Compute the next state using the memoized state and the update queue. - var oldState = workInProgress.memoizedState; - // TODO: Previous state can be null. - var newState = void 0; - var derivedStateFromCatch = void 0; - if (workInProgress.updateQueue !== null) { - newState = processUpdateQueue( - null, - workInProgress, - workInProgress.updateQueue, - instance, - newProps, - renderExpirationTime - ); - - var updateQueue = workInProgress.updateQueue; - if ( - updateQueue !== null && - updateQueue.capturedValues !== null && - enableGetDerivedStateFromCatch && - typeof ctor.getDerivedStateFromCatch === "function" - ) { - var capturedValues = updateQueue.capturedValues; - // Don't remove these from the update queue yet. We need them in - // finishClassComponent. Do the reset there. - // TODO: This is awkward. Refactor class components. - // updateQueue.capturedValues = null; - derivedStateFromCatch = callGetDerivedStateFromCatch( - ctor, - capturedValues - ); - } - } else { - newState = oldState; - } - - var derivedStateFromProps = void 0; - if (oldProps !== newProps) { - // The prevState parameter should be the partially updated state. - // Otherwise, spreading state in return values could override updates. - derivedStateFromProps = callGetDerivedStateFromProps( - workInProgress, - instance, - newProps, - newState - ); - } - - if (derivedStateFromProps !== null && derivedStateFromProps !== undefined) { - // Render-phase updates (like this) should not be added to the update queue, - // So that multiple render passes do not enqueue multiple updates. - // Instead, just synchronously merge the returned state into the instance. - newState = - newState === null || newState === undefined - ? derivedStateFromProps - : Object.assign({}, newState, derivedStateFromProps); - - // Update the base state of the update queue. - // FIXME: This is getting ridiculous. Refactor plz! - var _updateQueue = workInProgress.updateQueue; - if (_updateQueue !== null) { - _updateQueue.baseState = Object.assign( - {}, - _updateQueue.baseState, - derivedStateFromProps - ); - } - } - if (derivedStateFromCatch !== null && derivedStateFromCatch !== undefined) { - // Render-phase updates (like this) should not be added to the update queue, - // So that multiple render passes do not enqueue multiple updates. - // Instead, just synchronously merge the returned state into the instance. - newState = - newState === null || newState === undefined - ? derivedStateFromCatch - : Object.assign({}, newState, derivedStateFromCatch); - - // Update the base state of the update queue. - // FIXME: This is getting ridiculous. Refactor plz! - var _updateQueue2 = workInProgress.updateQueue; - if (_updateQueue2 !== null) { - _updateQueue2.baseState = Object.assign( - {}, - _updateQueue2.baseState, - derivedStateFromCatch - ); - } - } - - if ( - oldProps === newProps && - oldState === newState && - !hasContextChanged() && - !( - workInProgress.updateQueue !== null && - workInProgress.updateQueue.hasForceUpdate - ) - ) { - // 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; - } - - var shouldUpdate = checkShouldComponentUpdate( - workInProgress, - oldProps, - newProps, - oldState, - newState, - newContext - ); - - 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 props/state to indicate that this work can be reused. - memoizeProps(workInProgress, newProps); - memoizeState(workInProgress, newState); - } - - // Update the existing instance's state, props, and context pointers even - // if shouldComponentUpdate returns false. - instance.props = newProps; - instance.state = newState; - instance.context = newContext; - - return shouldUpdate; - } - - // Invokes the update life-cycles and returns false if it shouldn't rerender. - function updateClassInstance(current, workInProgress, renderExpirationTime) { - var ctor = workInProgress.type; - var instance = workInProgress.stateNode; - resetInputPointers(workInProgress, instance); - - var oldProps = workInProgress.memoizedProps; - var newProps = workInProgress.pendingProps; - var oldContext = instance.context; - var newUnmaskedContext = getUnmaskedContext(workInProgress); - var newContext = getMaskedContext(workInProgress, newUnmaskedContext); - - var hasNewLifecycles = - typeof ctor.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 !== newContext) { - callComponentWillReceiveProps( - workInProgress, - instance, - newProps, - newContext - ); - } - } - - // Compute the next state using the memoized state and the update queue. - var oldState = workInProgress.memoizedState; - // TODO: Previous state can be null. - var newState = void 0; - var derivedStateFromCatch = void 0; - - if (workInProgress.updateQueue !== null) { - newState = processUpdateQueue( - current, - workInProgress, - workInProgress.updateQueue, - instance, - newProps, - renderExpirationTime - ); - - var updateQueue = workInProgress.updateQueue; - if ( - updateQueue !== null && - updateQueue.capturedValues !== null && - enableGetDerivedStateFromCatch && - typeof ctor.getDerivedStateFromCatch === "function" - ) { - var capturedValues = updateQueue.capturedValues; - // Don't remove these from the update queue yet. We need them in - // finishClassComponent. Do the reset there. - // TODO: This is awkward. Refactor class components. - // updateQueue.capturedValues = null; - derivedStateFromCatch = callGetDerivedStateFromCatch( - ctor, - capturedValues - ); - } - } else { - newState = oldState; - } - - var derivedStateFromProps = void 0; - if (oldProps !== newProps) { - // The prevState parameter should be the partially updated state. - // Otherwise, spreading state in return values could override updates. - derivedStateFromProps = callGetDerivedStateFromProps( - workInProgress, - instance, - newProps, - newState - ); - } - - if (derivedStateFromProps !== null && derivedStateFromProps !== undefined) { - // Render-phase updates (like this) should not be added to the update queue, - // So that multiple render passes do not enqueue multiple updates. - // Instead, just synchronously merge the returned state into the instance. - newState = - newState === null || newState === undefined - ? derivedStateFromProps - : Object.assign({}, newState, derivedStateFromProps); - - // Update the base state of the update queue. - // FIXME: This is getting ridiculous. Refactor plz! - var _updateQueue3 = workInProgress.updateQueue; - if (_updateQueue3 !== null) { - _updateQueue3.baseState = Object.assign( - {}, - _updateQueue3.baseState, - derivedStateFromProps - ); - } - } - if (derivedStateFromCatch !== null && derivedStateFromCatch !== undefined) { - // Render-phase updates (like this) should not be added to the update queue, - // So that multiple render passes do not enqueue multiple updates. - // Instead, just synchronously merge the returned state into the instance. - newState = - newState === null || newState === undefined - ? derivedStateFromCatch - : Object.assign({}, newState, derivedStateFromCatch); - - // Update the base state of the update queue. - // FIXME: This is getting ridiculous. Refactor plz! - var _updateQueue4 = workInProgress.updateQueue; - if (_updateQueue4 !== null) { - _updateQueue4.baseState = Object.assign( - {}, - _updateQueue4.baseState, - derivedStateFromCatch - ); - } - } - - if ( - oldProps === newProps && - oldState === newState && - !hasContextChanged() && - !( - workInProgress.updateQueue !== null && - workInProgress.updateQueue.hasForceUpdate - ) - ) { - // 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; - } - - var shouldUpdate = checkShouldComponentUpdate( - workInProgress, - oldProps, - newProps, - oldState, - newState, - newContext - ); - - 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, newContext); - } - if (typeof instance.UNSAFE_componentWillUpdate === "function") { - instance.UNSAFE_componentWillUpdate(newProps, newState, newContext); - } - 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. - memoizeProps(workInProgress, newProps); - memoizeState(workInProgress, newState); - } - - // Update the existing instance's state, props, and context pointers even - // if shouldComponentUpdate returns false. - instance.props = newProps; - instance.state = newState; - instance.context = newContext; - - return shouldUpdate; - } - - return { - adoptClassInstance: adoptClassInstance, - callGetDerivedStateFromProps: callGetDerivedStateFromProps, - constructClassInstance: constructClassInstance, - mountClassInstance: mountClassInstance, - resumeMountClassInstance: resumeMountClassInstance, - updateClassInstance: updateClassInstance - }; -}; - -var getCurrentFiberStackAddendum$1 = - ReactDebugCurrentFiber.getCurrentFiberStackAddendum; - -var didWarnAboutMaps = void 0; -var didWarnAboutStringRefInStrictMode = void 0; -var ownerHasKeyUseWarning = void 0; -var ownerHasFunctionTypeWarning = void 0; -var warnForMissingKey = function(child) {}; - -{ - didWarnAboutMaps = 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; - } - invariant( - typeof child._store === "object", - "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 an array or iterator should have a unique " + - '"key" prop. See https://fb.me/react-warning-keys for ' + - "more information." + - (getCurrentFiberStackAddendum$1() || ""); - if (ownerHasKeyUseWarning[currentComponentErrorInfo]) { - return; - } - ownerHasKeyUseWarning[currentComponentErrorInfo] = true; - - warning( - false, - "Each child in an array or iterator should have a unique " + - '"key" prop. See https://fb.me/react-warning-keys for ' + - "more information.%s", - getCurrentFiberStackAddendum$1() - ); - }; -} - -var isArray$1 = Array.isArray; - -function coerceRef(returnFiber, current, element) { - var mixedRef = element.ref; - if ( - mixedRef !== null && - typeof mixedRef !== "function" && - typeof mixedRef !== "object" - ) { - { - if (returnFiber.mode & StrictMode) { - var componentName = getComponentName(returnFiber) || "Component"; - if (!didWarnAboutStringRefInStrictMode[componentName]) { - warning( - 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, - getStackAddendumByWorkInProgressFiber(returnFiber) - ); - didWarnAboutStringRefInStrictMode[componentName] = true; - } - } - } - - if (element._owner) { - var owner = element._owner; - var inst = void 0; - if (owner) { - var ownerFiber = owner; - invariant( - ownerFiber.tag === ClassComponent, - "Stateless function components cannot have refs." - ); - inst = ownerFiber.stateNode; - } - invariant( - inst, - "Missing owner for string ref %s. This error is likely caused by a " + - "bug in React. Please file an issue.", - mixedRef - ); - var stringRef = "" + mixedRef; - // Check if previous string ref matches new string ref - if ( - current !== null && - current.ref !== null && - current.ref._stringRef === stringRef - ) { - return current.ref; - } - var ref = function(value) { - var refs = inst.refs === emptyObject ? (inst.refs = {}) : inst.refs; - if (value === null) { - delete refs[stringRef]; - } else { - refs[stringRef] = value; - } - }; - ref._stringRef = stringRef; - return ref; - } else { - invariant( - typeof mixedRef === "string", - "Expected ref to be a function or a string." - ); - invariant( - element._owner, - "Element ref was specified as a string (%s) but no owner was set. This could happen for one of" + - " the following reasons:\n" + - "1. You may be adding a ref to a functional component\n" + - "2. You may be adding a ref to a component that was not created inside a component's render method\n" + - "3. You have multiple copies of React loaded\n" + - "See https://fb.me/react-refs-must-have-owner for more information.", - mixedRef - ); - } - } - 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." + - (getCurrentFiberStackAddendum$1() || ""); - } - invariant( - false, - "Objects are not valid as a React child (found: %s).%s", - 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." + - (getCurrentFiberStackAddendum$1() || ""); - - if (ownerHasFunctionTypeWarning[currentComponentErrorInfo]) { - return; - } - ownerHasFunctionTypeWarning[currentComponentErrorInfo] = true; - - warning( - 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.%s", - getCurrentFiberStackAddendum$1() || "" - ); -} - -// 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 = newFiber.alternate; - if (current !== null) { - var oldIndex = current.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, textContent, expirationTime) { - if (current === null || current.tag !== HostText) { - // Insert - var created = createFiberFromText( - textContent, - returnFiber.mode, - expirationTime - ); - created["return"] = returnFiber; - return created; - } else { - // Update - var existing = useFiber(current, textContent, expirationTime); - existing["return"] = returnFiber; - return existing; - } - } - - function updateElement(returnFiber, current, element, expirationTime) { - if (current !== null && current.type === element.type) { - // Move based on index - var existing = useFiber(current, element.props, expirationTime); - existing.ref = coerceRef(returnFiber, current, 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, element); - created["return"] = returnFiber; - return created; - } - } - - function updatePortal(returnFiber, current, portal, expirationTime) { - if ( - current === null || - current.tag !== HostPortal || - current.stateNode.containerInfo !== portal.containerInfo || - current.stateNode.implementation !== portal.implementation - ) { - // Insert - var created = createFiberFromPortal( - portal, - returnFiber.mode, - expirationTime - ); - created["return"] = returnFiber; - return created; - } else { - // Update - var existing = useFiber(current, portal.children || [], expirationTime); - existing["return"] = returnFiber; - return existing; - } - } - - function updateFragment(returnFiber, current, fragment, expirationTime, key) { - if (current === null || current.tag !== Fragment) { - // Insert - var created = createFiberFromFragment( - fragment, - returnFiber.mode, - expirationTime, - key - ); - created["return"] = returnFiber; - return created; - } else { - // Update - var existing = useFiber(current, 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$1(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$1(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$1(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( - 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.%s", - key, - getCurrentFiberStackAddendum$1() - ); - break; - default: - break; - } - } - return knownKeys; - } - - function reconcileChildrenArray( - returnFiber, - currentFirstChild, - newChildren, - expirationTime - ) { - // This algorithm can't optimize by searching from boths 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) { - 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) { - 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); - invariant( - typeof iteratorFn === "function", - "An object is not an iterable. This error is likely caused by a bug in " + - "React. Please file an issue." - ); - - { - // Warn about using Maps as children - if (typeof newChildrenIterable.entries === "function") { - var possibleMap = newChildrenIterable; - if (possibleMap.entries === iteratorFn) { - !didWarnAboutMaps - ? warning( - false, - "Using Maps as children is unsupported and will likely yield " + - "unexpected results. Convert it to a sequence/iterable of keyed " + - "ReactElements instead.%s", - getCurrentFiberStackAddendum$1() - ) - : 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); - invariant(newChildren != null, "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) { - 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.type === 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. - if ( - typeof newChild === "object" && - newChild !== null && - newChild.type === REACT_FRAGMENT_TYPE && - newChild.key === null - ) { - 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$1(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") { - // 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 FunctionalComponent: { - var Component = returnFiber.type; - invariant( - false, - "%s(...): Nothing was returned from render. This usually means a " + - "return statement is missing. Or, to render nothing, " + - "return null.", - Component.displayName || Component.name || "Component" - ); - } - } - } - - // Remaining cases are all treated as empty. - return deleteRemainingChildren(returnFiber, currentFirstChild); - } - - return reconcileChildFibers; -} - -var reconcileChildFibers = ChildReconciler(true); -var mountChildFibers = ChildReconciler(false); - -function cloneChildFibers(current, workInProgress) { - invariant( - current === null || workInProgress.child === current.child, - "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 didWarnAboutBadClass = void 0; -var didWarnAboutGetDerivedStateOnFunctionalComponent = void 0; -var didWarnAboutStatelessRefs = void 0; - -{ - didWarnAboutBadClass = {}; - didWarnAboutGetDerivedStateOnFunctionalComponent = {}; - didWarnAboutStatelessRefs = {}; -} - -var ReactFiberBeginWork = function( - config, - hostContext, - legacyContext, - newContext, - hydrationContext, - scheduleWork, - computeExpirationForFiber -) { - var shouldSetTextContent = config.shouldSetTextContent, - shouldDeprioritizeSubtree = config.shouldDeprioritizeSubtree; - var pushHostContext = hostContext.pushHostContext, - pushHostContainer = hostContext.pushHostContainer; - var pushProvider = newContext.pushProvider; - var getMaskedContext = legacyContext.getMaskedContext, - getUnmaskedContext = legacyContext.getUnmaskedContext, - hasLegacyContextChanged = legacyContext.hasContextChanged, - pushLegacyContextProvider = legacyContext.pushContextProvider, - pushTopLevelContextObject = legacyContext.pushTopLevelContextObject, - invalidateContextProvider = legacyContext.invalidateContextProvider; - var enterHydrationState = hydrationContext.enterHydrationState, - resetHydrationState = hydrationContext.resetHydrationState, - tryToClaimNextHydratableInstance = - hydrationContext.tryToClaimNextHydratableInstance; - - var _ReactFiberClassCompo = ReactFiberClassComponent( - legacyContext, - scheduleWork, - computeExpirationForFiber, - memoizeProps, - memoizeState - ), - adoptClassInstance = _ReactFiberClassCompo.adoptClassInstance, - callGetDerivedStateFromProps = - _ReactFiberClassCompo.callGetDerivedStateFromProps, - constructClassInstance = _ReactFiberClassCompo.constructClassInstance, - mountClassInstance = _ReactFiberClassCompo.mountClassInstance, - resumeMountClassInstance = _ReactFiberClassCompo.resumeMountClassInstance, - updateClassInstance = _ReactFiberClassCompo.updateClassInstance; - - // TODO: Remove this and use reconcileChildrenAtExpirationTime directly. - - function reconcileChildren(current, workInProgress, nextChildren) { - reconcileChildrenAtExpirationTime( - current, - workInProgress, - nextChildren, - workInProgress.expirationTime - ); - } - - function reconcileChildrenAtExpirationTime( - current, - workInProgress, - nextChildren, - renderExpirationTime - ) { - if (current === 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.child, - nextChildren, - renderExpirationTime - ); - } - } - - function updateForwardRef(current, workInProgress) { - var render = workInProgress.type.render; - var nextChildren = render(workInProgress.pendingProps, workInProgress.ref); - reconcileChildren(current, workInProgress, nextChildren); - memoizeProps(workInProgress, nextChildren); - return workInProgress.child; - } - - function updateFragment(current, workInProgress) { - var nextChildren = workInProgress.pendingProps; - if (hasLegacyContextChanged()) { - // Normally we can bail out on props equality but if context has changed - // we don't do the bailout and we have to reuse existing props instead. - } else if (workInProgress.memoizedProps === nextChildren) { - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - reconcileChildren(current, workInProgress, nextChildren); - memoizeProps(workInProgress, nextChildren); - return workInProgress.child; - } - - function updateMode(current, workInProgress) { - var nextChildren = workInProgress.pendingProps.children; - if (hasLegacyContextChanged()) { - // Normally we can bail out on props equality but if context has changed - // we don't do the bailout and we have to reuse existing props instead. - } else if ( - nextChildren === null || - workInProgress.memoizedProps === nextChildren - ) { - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - reconcileChildren(current, workInProgress, nextChildren); - memoizeProps(workInProgress, nextChildren); - return workInProgress.child; - } - - function markRef(current, workInProgress) { - var ref = workInProgress.ref; - if ( - (current === null && ref !== null) || - (current !== null && current.ref !== ref) - ) { - // Schedule a Ref effect - workInProgress.effectTag |= Ref; - } - } - - function updateFunctionalComponent(current, workInProgress) { - var fn = workInProgress.type; - var nextProps = workInProgress.pendingProps; - - if (hasLegacyContextChanged()) { - // Normally we can bail out on props equality but if context has changed - // we don't do the bailout and we have to reuse existing props instead. - } else { - if (workInProgress.memoizedProps === nextProps) { - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - // TODO: consider bringing fn.shouldComponentUpdate() back. - // It used to be here. - } - - var unmaskedContext = getUnmaskedContext(workInProgress); - var context = getMaskedContext(workInProgress, unmaskedContext); - - var nextChildren = void 0; - - { - ReactCurrentOwner.current = workInProgress; - ReactDebugCurrentFiber.setCurrentPhase("render"); - nextChildren = fn(nextProps, context); - ReactDebugCurrentFiber.setCurrentPhase(null); - } - // React DevTools reads this flag. - workInProgress.effectTag |= PerformedWork; - reconcileChildren(current, workInProgress, nextChildren); - memoizeProps(workInProgress, nextProps); - return workInProgress.child; - } - - function updateClassComponent(current, workInProgress, renderExpirationTime) { - // 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 = pushLegacyContextProvider(workInProgress); - var shouldUpdate = void 0; - if (current === null) { - if (workInProgress.stateNode === null) { - // In the initial pass we might need to construct the instance. - constructClassInstance(workInProgress, workInProgress.pendingProps); - mountClassInstance(workInProgress, renderExpirationTime); - - shouldUpdate = true; - } else { - // In a resume, we'll already have an instance we can reuse. - shouldUpdate = resumeMountClassInstance( - workInProgress, - renderExpirationTime - ); - } - } else { - shouldUpdate = updateClassInstance( - current, - workInProgress, - renderExpirationTime - ); - } - - // We processed the update queue inside updateClassInstance. It may have - // included some errors that were dispatched during the commit phase. - // TODO: Refactor class components so this is less awkward. - var didCaptureError = false; - var updateQueue = workInProgress.updateQueue; - if (updateQueue !== null && updateQueue.capturedValues !== null) { - shouldUpdate = true; - didCaptureError = true; - } - return finishClassComponent( - current, - workInProgress, - shouldUpdate, - hasContext, - didCaptureError, - renderExpirationTime - ); - } - - function finishClassComponent( - current, - workInProgress, - shouldUpdate, - hasContext, - didCaptureError, - renderExpirationTime - ) { - // Refs should update even if shouldComponentUpdate returns false - markRef(current, workInProgress); - - if (!shouldUpdate && !didCaptureError) { - // Context providers should defer to sCU for rendering - if (hasContext) { - invalidateContextProvider(workInProgress, false); - } - - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - - var ctor = workInProgress.type; - var instance = workInProgress.stateNode; - - // Rerender - ReactCurrentOwner.current = workInProgress; - var nextChildren = void 0; - if ( - didCaptureError && - (!enableGetDerivedStateFromCatch || - typeof ctor.getDerivedStateFromCatch !== "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; - } else { - { - ReactDebugCurrentFiber.setCurrentPhase("render"); - nextChildren = instance.render(); - if ( - debugRenderPhaseSideEffects || - (debugRenderPhaseSideEffectsForStrictMode && - workInProgress.mode & StrictMode) - ) { - instance.render(); - } - ReactDebugCurrentFiber.setCurrentPhase(null); - } - } - - // React DevTools reads this flag. - workInProgress.effectTag |= PerformedWork; - if (didCaptureError) { - // If we're recovering from an error, reconcile twice: first to delete - // all the existing children. - reconcileChildrenAtExpirationTime( - current, - workInProgress, - null, - renderExpirationTime - ); - workInProgress.child = null; - // Now we can continue reconciling like normal. This has the effect of - // remounting all children regardless of whether their their - // identity matches. - } - reconcileChildrenAtExpirationTime( - current, - workInProgress, - nextChildren, - renderExpirationTime - ); - // Memoize props and state using the values we just used to render. - // TODO: Restructure so we never read values from the instance. - memoizeState(workInProgress, instance.state); - memoizeProps(workInProgress, instance.props); - - // The context might have changed so we need to recalculate it. - if (hasContext) { - invalidateContextProvider(workInProgress, 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, workInProgress, renderExpirationTime) { - pushHostRootContext(workInProgress); - var updateQueue = workInProgress.updateQueue; - if (updateQueue !== null) { - var prevState = workInProgress.memoizedState; - var state = processUpdateQueue( - current, - workInProgress, - updateQueue, - null, - null, - renderExpirationTime - ); - memoizeState(workInProgress, state); - updateQueue = workInProgress.updateQueue; - - var element = void 0; - if (updateQueue !== null && updateQueue.capturedValues !== null) { - // There's an uncaught error. Unmount the whole root. - element = null; - } else if (prevState === state) { - // 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, workInProgress); - } else { - element = state.element; - } - var root = workInProgress.stateNode; - if ( - (current === null || current.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, - element, - renderExpirationTime - ); - } else { - // Otherwise reset hydration state in case we aborted and resumed another - // root. - resetHydrationState(); - reconcileChildren(current, workInProgress, element); - } - memoizeState(workInProgress, state); - return workInProgress.child; - } - resetHydrationState(); - // If there is no update queue, that's a bailout because the root has no props. - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - - function updateHostComponent(current, workInProgress, renderExpirationTime) { - pushHostContext(workInProgress); - - if (current === null) { - tryToClaimNextHydratableInstance(workInProgress); - } - - var type = workInProgress.type; - var memoizedProps = workInProgress.memoizedProps; - var nextProps = workInProgress.pendingProps; - var prevProps = current !== null ? current.memoizedProps : null; - - if (hasLegacyContextChanged()) { - // Normally we can bail out on props equality but if context has changed - // we don't do the bailout and we have to reuse existing props instead. - } else if (memoizedProps === nextProps) { - var isHidden = - workInProgress.mode & AsyncMode && - shouldDeprioritizeSubtree(type, nextProps); - if (isHidden) { - // Before bailing out, make sure we've deprioritized a hidden component. - workInProgress.expirationTime = Never; - } - if (!isHidden || renderExpirationTime !== Never) { - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - // If we're rendering a hidden node at hidden priority, don't bailout. The - // parent is complete, but the children may not be. - } - - 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 && 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, workInProgress); - - // Check the host config to see if the children are offscreen/hidden. - if ( - renderExpirationTime !== Never && - workInProgress.mode & AsyncMode && - shouldDeprioritizeSubtree(type, nextProps) - ) { - // Down-prioritize the children. - workInProgress.expirationTime = Never; - // Bailout and come back to this fiber later. - workInProgress.memoizedProps = nextProps; - return null; - } - - reconcileChildren(current, workInProgress, nextChildren); - memoizeProps(workInProgress, nextProps); - return workInProgress.child; - } - - function updateHostText(current, workInProgress) { - if (current === null) { - tryToClaimNextHydratableInstance(workInProgress); - } - var nextProps = workInProgress.pendingProps; - memoizeProps(workInProgress, nextProps); - // Nothing to do here. This is terminal. We'll do the completion step - // immediately after. - return null; - } - - function mountIndeterminateComponent( - current, - workInProgress, - renderExpirationTime - ) { - invariant( - current === null, - "An indeterminate component should never have mounted. This error is " + - "likely caused by a bug in React. Please file an issue." - ); - var fn = workInProgress.type; - var props = workInProgress.pendingProps; - var unmaskedContext = getUnmaskedContext(workInProgress); - var context = getMaskedContext(workInProgress, unmaskedContext); - - var value = void 0; - - { - if (fn.prototype && typeof fn.prototype.render === "function") { - var componentName = getComponentName(workInProgress) || "Unknown"; - - if (!didWarnAboutBadClass[componentName]) { - warning( - 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; - } - } - ReactCurrentOwner.current = workInProgress; - value = fn(props, context); - } - // React DevTools reads this flag. - workInProgress.effectTag |= PerformedWork; - - if ( - typeof value === "object" && - value !== null && - typeof value.render === "function" && - value.$$typeof === undefined - ) { - var Component = workInProgress.type; - - // Proceed under the assumption that this is a class instance - workInProgress.tag = ClassComponent; - - workInProgress.memoizedState = - value.state !== null && value.state !== undefined ? value.state : null; - - if (typeof Component.getDerivedStateFromProps === "function") { - var partialState = callGetDerivedStateFromProps( - workInProgress, - value, - props, - workInProgress.memoizedState - ); - - if (partialState !== null && partialState !== undefined) { - workInProgress.memoizedState = Object.assign( - {}, - workInProgress.memoizedState, - partialState - ); - } - } - - // 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 = pushLegacyContextProvider(workInProgress); - adoptClassInstance(workInProgress, value); - mountClassInstance(workInProgress, renderExpirationTime); - return finishClassComponent( - current, - workInProgress, - true, - hasContext, - false, - renderExpirationTime - ); - } else { - // Proceed under the assumption that this is a functional component - workInProgress.tag = FunctionalComponent; - { - var _Component = workInProgress.type; - - if (_Component) { - !!_Component.childContextTypes - ? warning( - false, - "%s(...): childContextTypes cannot be defined on a functional component.", - _Component.displayName || _Component.name || "Component" - ) - : void 0; - } - if (workInProgress.ref !== null) { - var info = ""; - var ownerName = ReactDebugCurrentFiber.getCurrentFiberOwnerName(); - 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 (!didWarnAboutStatelessRefs[warningKey]) { - didWarnAboutStatelessRefs[warningKey] = true; - warning( - false, - "Stateless function components cannot be given refs. " + - "Attempts to access this ref will fail.%s%s", - info, - ReactDebugCurrentFiber.getCurrentFiberStackAddendum() - ); - } - } - - if (typeof fn.getDerivedStateFromProps === "function") { - var _componentName = getComponentName(workInProgress) || "Unknown"; - - if ( - !didWarnAboutGetDerivedStateOnFunctionalComponent[_componentName] - ) { - warning( - false, - "%s: Stateless functional components do not support getDerivedStateFromProps.", - _componentName - ); - didWarnAboutGetDerivedStateOnFunctionalComponent[ - _componentName - ] = true; - } - } - } - reconcileChildren(current, workInProgress, value); - memoizeProps(workInProgress, props); - return workInProgress.child; - } - } - - function updateCallComponent(current, workInProgress, renderExpirationTime) { - var nextProps = workInProgress.pendingProps; - if (hasLegacyContextChanged()) { - // Normally we can bail out on props equality but if context has changed - // we don't do the bailout and we have to reuse existing props instead. - } else if (workInProgress.memoizedProps === nextProps) { - nextProps = workInProgress.memoizedProps; - // TODO: When bailing out, we might need to return the stateNode instead - // of the child. To check it for work. - // return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - - var nextChildren = nextProps.children; - - // The following is a fork of reconcileChildrenAtExpirationTime but using - // stateNode to store the child. - if (current === null) { - workInProgress.stateNode = mountChildFibers( - workInProgress, - workInProgress.stateNode, - nextChildren, - renderExpirationTime - ); - } else { - workInProgress.stateNode = reconcileChildFibers( - workInProgress, - current.stateNode, - nextChildren, - renderExpirationTime - ); - } - - memoizeProps(workInProgress, nextProps); - // This doesn't take arbitrary time so we could synchronously just begin - // eagerly do the work of workInProgress.child as an optimization. - return workInProgress.stateNode; - } - - function updatePortalComponent( - current, - workInProgress, - renderExpirationTime - ) { - pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); - var nextChildren = workInProgress.pendingProps; - if (hasLegacyContextChanged()) { - // Normally we can bail out on props equality but if context has changed - // we don't do the bailout and we have to reuse existing props instead. - } else if (workInProgress.memoizedProps === nextChildren) { - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - - if (current === 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 - ); - memoizeProps(workInProgress, nextChildren); - } else { - reconcileChildren(current, workInProgress, nextChildren); - memoizeProps(workInProgress, nextChildren); - } - return workInProgress.child; - } - - 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. - switch (fiber.tag) { - case ContextConsumer: - // Check if the context matches. - var observedBits = fiber.stateNode | 0; - if (fiber.type === context && (observedBits & changedBits) !== 0) { - // Update the expiration time of all the ancestors, including - // the alternates. - var node = fiber; - while (node !== null) { - var alternate = node.alternate; - if ( - node.expirationTime === NoWork || - node.expirationTime > renderExpirationTime - ) { - node.expirationTime = renderExpirationTime; - if ( - alternate !== null && - (alternate.expirationTime === NoWork || - alternate.expirationTime > renderExpirationTime) - ) { - alternate.expirationTime = renderExpirationTime; - } - } else if ( - alternate !== null && - (alternate.expirationTime === NoWork || - alternate.expirationTime > renderExpirationTime) - ) { - alternate.expirationTime = renderExpirationTime; - } else { - // Neither alternate was updated, which means the rest of the - // ancestor path already has sufficient priority. - break; - } - node = node["return"]; - } - // Don't scan deeper than a matching consumer. When we render the - // consumer, we'll continue scanning from that point. This way the - // scanning work is time-sliced. - nextFiber = null; - } else { - // Traverse down. - nextFiber = fiber.child; - } - break; - case ContextProvider: - // Don't scan deeper if this is a matching provider - nextFiber = fiber.type === workInProgress.type ? null : fiber.child; - break; - default: - // Traverse down. - nextFiber = fiber.child; - break; - } - 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) { - nextFiber = sibling; - break; - } - // No more siblings. Traverse up. - nextFiber = nextFiber["return"]; - } - } - fiber = nextFiber; - } - } - - function updateContextProvider( - current, - workInProgress, - renderExpirationTime - ) { - var providerType = workInProgress.type; - var context = providerType._context; - - var newProps = workInProgress.pendingProps; - var oldProps = workInProgress.memoizedProps; - - if (hasLegacyContextChanged()) { - // Normally we can bail out on props equality but if context has changed - // we don't do the bailout and we have to reuse existing props instead. - } else if (oldProps === newProps) { - workInProgress.stateNode = 0; - pushProvider(workInProgress); - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - - var newValue = newProps.value; - workInProgress.memoizedProps = newProps; - - var changedBits = void 0; - if (oldProps === null) { - // Initial render - changedBits = MAX_SIGNED_31_BIT_INT; - } else { - if (oldProps.value === newProps.value) { - // No change. Bailout early if children are the same. - if (oldProps.children === newProps.children) { - workInProgress.stateNode = 0; - pushProvider(workInProgress); - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - changedBits = 0; - } else { - var oldValue = oldProps.value; - // Use Object.is to compare the new context value to the old value. - // Inlined Object.is polyfill. - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is - if ( - (oldValue === newValue && - (oldValue !== 0 || 1 / oldValue === 1 / newValue)) || - (oldValue !== oldValue && newValue !== newValue) // eslint-disable-line no-self-compare - ) { - // No change. Bailout early if children are the same. - if (oldProps.children === newProps.children) { - workInProgress.stateNode = 0; - pushProvider(workInProgress); - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - changedBits = 0; - } else { - changedBits = - typeof context._calculateChangedBits === "function" - ? context._calculateChangedBits(oldValue, newValue) - : MAX_SIGNED_31_BIT_INT; - { - !((changedBits & MAX_SIGNED_31_BIT_INT) === changedBits) - ? warning( - false, - "calculateChangedBits: Expected the return value to be a " + - "31-bit integer. Instead received: %s", - changedBits - ) - : void 0; - } - changedBits |= 0; - - if (changedBits === 0) { - // No change. Bailout early if children are the same. - if (oldProps.children === newProps.children) { - workInProgress.stateNode = 0; - pushProvider(workInProgress); - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - } else { - propagateContextChange( - workInProgress, - context, - changedBits, - renderExpirationTime - ); - } - } - } - } - - workInProgress.stateNode = changedBits; - pushProvider(workInProgress); - - var newChildren = newProps.children; - reconcileChildren(current, workInProgress, newChildren); - return workInProgress.child; - } - - function updateContextConsumer( - current, - workInProgress, - renderExpirationTime - ) { - var context = workInProgress.type; - var newProps = workInProgress.pendingProps; - var oldProps = workInProgress.memoizedProps; - - var newValue = context._currentValue; - var changedBits = context._changedBits; - - if (hasLegacyContextChanged()) { - // Normally we can bail out on props equality but if context has changed - // we don't do the bailout and we have to reuse existing props instead. - } else if (changedBits === 0 && oldProps === newProps) { - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - workInProgress.memoizedProps = newProps; - - var observedBits = newProps.unstable_observedBits; - if (observedBits === undefined || observedBits === null) { - // Subscribe to all changes by default - observedBits = MAX_SIGNED_31_BIT_INT; - } - // Store the observedBits on the fiber's stateNode for quick access. - workInProgress.stateNode = observedBits; - - if ((changedBits & observedBits) !== 0) { - // Context change propagation stops at matching consumers, for time- - // slicing. Continue the propagation here. - propagateContextChange( - workInProgress, - context, - changedBits, - renderExpirationTime - ); - } else if (oldProps === newProps) { - // Skip over a memoized parent with a bitmask bailout even - // if we began working on it because of a deeper matching child. - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - // There is no bailout on `children` equality because we expect people - // to often pass a bound method as a child, but it may reference - // `this.state` or `this.props` (and thus needs to re-render on `setState`). - - var render = newProps.children; - - { - !(typeof render === "function") - ? warning( - 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; - } - - var newChildren = render(newValue); - reconcileChildren(current, workInProgress, newChildren); - return workInProgress.child; - } - - /* - function reuseChildrenEffects(returnFiber : Fiber, firstChild : Fiber) { - let child = firstChild; - do { - // Ensure that the first and last effect of the parent corresponds - // to the children's first and last effect. - if (!returnFiber.firstEffect) { - returnFiber.firstEffect = child.firstEffect; - } - if (child.lastEffect) { - if (returnFiber.lastEffect) { - returnFiber.lastEffect.nextEffect = child.firstEffect; - } - returnFiber.lastEffect = child.lastEffect; - } - } while (child = child.sibling); - } - */ - - function bailoutOnAlreadyFinishedWork(current, workInProgress) { - cancelWorkTimer(workInProgress); - - // TODO: We should ideally be able to bail out early if the children have no - // more work to do. However, since we don't have a separation of this - // Fiber's priority and its children yet - we don't know without doing lots - // of the same work we do anyway. Once we have that separation we can just - // bail out here if the children has no more work at this priority level. - // if (workInProgress.priorityOfChildren <= priorityLevel) { - // // If there are side-effects in these children that have not yet been - // // committed we need to ensure that they get properly transferred up. - // if (current && current.child !== workInProgress.child) { - // reuseChildrenEffects(workInProgress, child); - // } - // return null; - // } - - cloneChildFibers(current, workInProgress); - return workInProgress.child; - } - - function bailoutOnLowPriority(current, workInProgress) { - cancelWorkTimer(workInProgress); - - // TODO: Handle HostComponent tags here as well and call pushHostContext()? - // See PR 8590 discussion for context - switch (workInProgress.tag) { - case HostRoot: - pushHostRootContext(workInProgress); - break; - case ClassComponent: - pushLegacyContextProvider(workInProgress); - break; - case HostPortal: - pushHostContainer( - workInProgress, - workInProgress.stateNode.containerInfo - ); - break; - case ContextProvider: - pushProvider(workInProgress); - break; - } - // TODO: What if this is currently in progress? - // How can that happen? How is this not being cloned? - return null; - } - - // TODO: Delete memoizeProps/State and move to reconcile/bailout instead - function memoizeProps(workInProgress, nextProps) { - workInProgress.memoizedProps = nextProps; - } - - function memoizeState(workInProgress, nextState) { - workInProgress.memoizedState = nextState; - // Don't reset the updateQueue, in case there are pending updates. Resetting - // is handled by processUpdateQueue. - } - - function beginWork(current, workInProgress, renderExpirationTime) { - if ( - workInProgress.expirationTime === NoWork || - workInProgress.expirationTime > renderExpirationTime - ) { - return bailoutOnLowPriority(current, workInProgress); - } - - switch (workInProgress.tag) { - case IndeterminateComponent: - return mountIndeterminateComponent( - current, - workInProgress, - renderExpirationTime - ); - case FunctionalComponent: - return updateFunctionalComponent(current, workInProgress); - case ClassComponent: - return updateClassComponent( - current, - workInProgress, - renderExpirationTime - ); - case HostRoot: - return updateHostRoot(current, workInProgress, renderExpirationTime); - case HostComponent: - return updateHostComponent( - current, - workInProgress, - renderExpirationTime - ); - case HostText: - return updateHostText(current, workInProgress); - case CallHandlerPhase: - // This is a restart. Reset the tag to the initial phase. - workInProgress.tag = CallComponent; - // Intentionally fall through since this is now the same. - case CallComponent: - return updateCallComponent( - current, - workInProgress, - renderExpirationTime - ); - case ReturnComponent: - // A return component is just a placeholder, we can just run through the - // next one immediately. - return null; - case HostPortal: - return updatePortalComponent( - current, - workInProgress, - renderExpirationTime - ); - case ForwardRef: - return updateForwardRef(current, workInProgress); - case Fragment: - return updateFragment(current, workInProgress); - case Mode: - return updateMode(current, workInProgress); - case ContextProvider: - return updateContextProvider( - current, - workInProgress, - renderExpirationTime - ); - case ContextConsumer: - return updateContextConsumer( - current, - workInProgress, - renderExpirationTime - ); - default: - invariant( - false, - "Unknown unit of work tag. This error is likely caused by a bug in " + - "React. Please file an issue." - ); - } - } - - return { - beginWork: beginWork - }; -}; - -var ReactFiberCompleteWork = function( - config, - hostContext, - legacyContext, - newContext, - hydrationContext -) { - var createInstance = config.createInstance, - createTextInstance = config.createTextInstance, - appendInitialChild = config.appendInitialChild, - finalizeInitialChildren = config.finalizeInitialChildren, - prepareUpdate = config.prepareUpdate, - mutation = config.mutation, - persistence = config.persistence; - var getRootHostContainer = hostContext.getRootHostContainer, - popHostContext = hostContext.popHostContext, - getHostContext = hostContext.getHostContext, - popHostContainer = hostContext.popHostContainer; - var popLegacyContextProvider = legacyContext.popContextProvider, - popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject; - var popProvider = newContext.popProvider; - var prepareToHydrateHostInstance = - hydrationContext.prepareToHydrateHostInstance, - prepareToHydrateHostTextInstance = - hydrationContext.prepareToHydrateHostTextInstance, - popHydrationState = hydrationContext.popHydrationState; - - function markUpdate(workInProgress) { - // Tag the fiber with an update effect. This turns a Placement into - // a PlacementAndUpdate. - workInProgress.effectTag |= Update; - } - - function markRef(workInProgress) { - workInProgress.effectTag |= Ref; - } - - function appendAllReturns(returns, workInProgress) { - var node = workInProgress.stateNode; - if (node) { - node["return"] = workInProgress; - } - while (node !== null) { - if ( - node.tag === HostComponent || - node.tag === HostText || - node.tag === HostPortal - ) { - invariant(false, "A call cannot have host component children."); - } else if (node.tag === ReturnComponent) { - returns.push(node.pendingProps.value); - } else if (node.child !== null) { - node.child["return"] = node; - node = node.child; - continue; - } - while (node.sibling === null) { - if (node["return"] === null || node["return"] === workInProgress) { - return; - } - node = node["return"]; - } - node.sibling["return"] = node["return"]; - node = node.sibling; - } - } - - function moveCallToHandlerPhase( - current, - workInProgress, - renderExpirationTime - ) { - var props = workInProgress.memoizedProps; - invariant( - props, - "Should be resolved by now. This error is likely caused by a bug in " + - "React. Please file an issue." - ); - - // First step of the call has completed. Now we need to do the second. - // TODO: It would be nice to have a multi stage call represented by a - // single component, or at least tail call optimize nested ones. Currently - // that requires additional fields that we don't want to add to the fiber. - // So this requires nested handlers. - // Note: This doesn't mutate the alternate node. I don't think it needs to - // since this stage is reset for every pass. - workInProgress.tag = CallHandlerPhase; - - // Build up the returns. - // TODO: Compare this to a generator or opaque helpers like Children. - var returns = []; - appendAllReturns(returns, workInProgress); - var fn = props.handler; - var childProps = props.props; - var nextChildren = fn(childProps, returns); - - var currentFirstChild = current !== null ? current.child : null; - workInProgress.child = reconcileChildFibers( - workInProgress, - currentFirstChild, - nextChildren, - renderExpirationTime - ); - return workInProgress.child; - } - - function appendAllChildren(parent, workInProgress) { - // 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; - } - } - - var updateHostContainer = void 0; - var updateHostComponent = void 0; - var updateHostText = void 0; - if (mutation) { - if (enableMutatingReconciler) { - // Mutation mode - updateHostContainer = function(workInProgress) { - // Noop - }; - updateHostComponent = function( - current, - workInProgress, - updatePayload, - 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 = 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 { - invariant(false, "Mutating reconciler is disabled."); - } - } else if (persistence) { - if (enablePersistentReconciler) { - // Persistent host tree mode - var cloneInstance = persistence.cloneInstance, - createContainerChildSet = persistence.createContainerChildSet, - appendChildToContainerChildSet = - persistence.appendChildToContainerChildSet, - finalizeContainerChildren = persistence.finalizeContainerChildren; - - // An unfortunate fork of appendAllChildren because we have two different parent types. - - var appendAllChildrenToContainer = function( - containerChildSet, - workInProgress - ) { - // 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) { - appendChildToContainerChildSet(containerChildSet, 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) { - 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); - portalOrRoot.pendingChildren = newChildSet; - // Schedule an update on the container to swap out the container. - markUpdate(workInProgress); - finalizeContainerChildren(container, newChildSet); - } - }; - updateHostComponent = function( - current, - workInProgress, - updatePayload, - type, - oldProps, - newProps, - rootContainerInstance, - currentHostContext - ) { - // 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; - var currentInstance = current.stateNode; - if (childrenUnchanged && updatePayload === null) { - // No changes, just reuse the existing instance. - // Note that this might release a previous clone. - workInProgress.stateNode = currentInstance; - } else { - var recyclableInstance = workInProgress.stateNode; - 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); - } - } - }; - updateHostText = 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 { - invariant(false, "Persistent reconciler is disabled."); - } - } else { - if (enableNoopReconciler) { - // No host operations - updateHostContainer = function(workInProgress) { - // Noop - }; - updateHostComponent = function( - current, - workInProgress, - updatePayload, - type, - oldProps, - newProps, - rootContainerInstance, - currentHostContext - ) { - // Noop - }; - updateHostText = function(current, workInProgress, oldText, newText) { - // Noop - }; - } else { - invariant(false, "Noop reconciler is disabled."); - } - } - - function completeWork(current, workInProgress, renderExpirationTime) { - var newProps = workInProgress.pendingProps; - switch (workInProgress.tag) { - case FunctionalComponent: - return null; - case ClassComponent: { - // We are leaving this subtree, so pop context if any. - popLegacyContextProvider(workInProgress); - - // If this component caught an error, schedule an error log effect. - var instance = workInProgress.stateNode; - var updateQueue = workInProgress.updateQueue; - if (updateQueue !== null && updateQueue.capturedValues !== null) { - workInProgress.effectTag &= ~DidCapture; - if (typeof instance.componentDidCatch === "function") { - workInProgress.effectTag |= ErrLog; - } else { - // Normally we clear this in the commit phase, but since we did not - // schedule an effect, we need to reset it here. - updateQueue.capturedValues = null; - } - } - return null; - } - case HostRoot: { - popHostContainer(workInProgress); - popTopLevelLegacyContextObject(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); - - var _updateQueue = workInProgress.updateQueue; - if (_updateQueue !== null && _updateQueue.capturedValues !== null) { - workInProgress.effectTag |= ErrLog; - } - return null; - } - case HostComponent: { - popHostContext(workInProgress); - var rootContainerInstance = getRootHostContainer(); - var type = workInProgress.type; - if (current !== null && workInProgress.stateNode != null) { - // 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 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 - ); - - updateHostComponent( - current, - workInProgress, - updatePayload, - type, - oldProps, - newProps, - rootContainerInstance, - currentHostContext - ); - - if (current.ref !== workInProgress.ref) { - markRef(workInProgress); - } - } else { - if (!newProps) { - invariant( - workInProgress.stateNode !== null, - "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. - return null; - } - - 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 _instance2 = createInstance( - type, - newProps, - rootContainerInstance, - _currentHostContext, - workInProgress - ); - - appendAllChildren(_instance2, workInProgress); - - // 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( - _instance2, - type, - newProps, - rootContainerInstance, - _currentHostContext - ) - ) { - markUpdate(workInProgress); - } - workInProgress.stateNode = _instance2; - } - - if (workInProgress.ref !== null) { - // If there is a ref on a host node we need to schedule a callback - markRef(workInProgress); - } - } - return null; - } - 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(current, workInProgress, oldText, newText); - } else { - if (typeof newText !== "string") { - invariant( - workInProgress.stateNode !== null, - "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. - return null; - } - var _rootContainerInstance = getRootHostContainer(); - var _currentHostContext2 = getHostContext(); - var _wasHydrated = popHydrationState(workInProgress); - if (_wasHydrated) { - if (prepareToHydrateHostTextInstance(workInProgress)) { - markUpdate(workInProgress); - } - } else { - workInProgress.stateNode = createTextInstance( - newText, - _rootContainerInstance, - _currentHostContext2, - workInProgress - ); - } - } - return null; - } - case CallComponent: - return moveCallToHandlerPhase( - current, - workInProgress, - renderExpirationTime - ); - case CallHandlerPhase: - // Reset the tag to now be a first phase call. - workInProgress.tag = CallComponent; - return null; - case ReturnComponent: - // Does nothing. - return null; - case ForwardRef: - return null; - case Fragment: - return null; - case Mode: - return null; - case HostPortal: - popHostContainer(workInProgress); - updateHostContainer(workInProgress); - return null; - case ContextProvider: - // Pop provider fiber - popProvider(workInProgress); - return null; - case ContextConsumer: - return null; - // Error cases - case IndeterminateComponent: - invariant( - false, - "An indeterminate component should have become determinate before " + - "completing. This error is likely caused by a bug in React. Please " + - "file an issue." - ); - // eslint-disable-next-line no-fallthrough - default: - invariant( - false, - "Unknown unit of work tag. This error is likely caused by a bug in " + - "React. Please file an issue." - ); - } - } - - return { - completeWork: completeWork - }; -}; - -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: getStackAddendumByWorkInProgressFiber(source) - }; -} - -var ReactFiberUnwindWork = function( - hostContext, - legacyContext, - newContext, - scheduleWork, - isAlreadyFailedLegacyErrorBoundary -) { - var popHostContainer = hostContext.popHostContainer, - popHostContext = hostContext.popHostContext; - var popLegacyContextProvider = legacyContext.popContextProvider, - popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject; - var popProvider = newContext.popProvider; - - function throwException(returnFiber, sourceFiber, rawValue) { - // The source fiber did not complete. - sourceFiber.effectTag |= Incomplete; - // Its effect list is no longer valid. - sourceFiber.firstEffect = sourceFiber.lastEffect = null; - - var value = createCapturedValue(rawValue, sourceFiber); - - var workInProgress = returnFiber; - do { - switch (workInProgress.tag) { - case HostRoot: { - // Uncaught error - var errorInfo = value; - ensureUpdateQueues(workInProgress); - var updateQueue = workInProgress.updateQueue; - updateQueue.capturedValues = [errorInfo]; - workInProgress.effectTag |= ShouldCapture; - return; - } - case ClassComponent: - // Capture and retry - var ctor = workInProgress.type; - var _instance = workInProgress.stateNode; - if ( - (workInProgress.effectTag & DidCapture) === NoEffect && - ((typeof ctor.getDerivedStateFromCatch === "function" && - enableGetDerivedStateFromCatch) || - (_instance !== null && - typeof _instance.componentDidCatch === "function" && - !isAlreadyFailedLegacyErrorBoundary(_instance))) - ) { - ensureUpdateQueues(workInProgress); - var _updateQueue = workInProgress.updateQueue; - var capturedValues = _updateQueue.capturedValues; - if (capturedValues === null) { - _updateQueue.capturedValues = [value]; - } else { - capturedValues.push(value); - } - workInProgress.effectTag |= ShouldCapture; - return; - } - break; - default: - break; - } - workInProgress = workInProgress["return"]; - } while (workInProgress !== null); - } - - function unwindWork(workInProgress) { - switch (workInProgress.tag) { - case ClassComponent: { - popLegacyContextProvider(workInProgress); - var effectTag = workInProgress.effectTag; - if (effectTag & ShouldCapture) { - workInProgress.effectTag = (effectTag & ~ShouldCapture) | DidCapture; - return workInProgress; - } - return null; - } - case HostRoot: { - popHostContainer(workInProgress); - popTopLevelLegacyContextObject(workInProgress); - var _effectTag = workInProgress.effectTag; - if (_effectTag & ShouldCapture) { - workInProgress.effectTag = (_effectTag & ~ShouldCapture) | DidCapture; - return workInProgress; - } - return null; - } - case HostComponent: { - popHostContext(workInProgress); - return null; - } - case HostPortal: - popHostContainer(workInProgress); - return null; - case ContextProvider: - popProvider(workInProgress); - return null; - default: - return null; - } - } - - function unwindInterruptedWork(interruptedWork) { - switch (interruptedWork.tag) { - case ClassComponent: { - popLegacyContextProvider(interruptedWork); - break; - } - case HostRoot: { - popHostContainer(interruptedWork); - popTopLevelLegacyContextObject(interruptedWork); - break; - } - case HostComponent: { - popHostContext(interruptedWork); - break; - } - case HostPortal: - popHostContainer(interruptedWork); - break; - case ContextProvider: - popProvider(interruptedWork); - break; - default: - break; - } - } - - return { - throwException: throwException, - unwindWork: unwindWork, - unwindInterruptedWork: unwindInterruptedWork - }; -}; - -// 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); - } - - 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 suppressLogging = error && error.suppressReactErrorLogging; - if (suppressLogging) { - return; - } - - { - var componentName = capturedError.componentName, - componentStack = capturedError.componentStack, - errorBoundaryName = capturedError.errorBoundaryName, - errorBoundaryFound = capturedError.errorBoundaryFound, - willRetry = capturedError.willRetry; - - 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 invokeGuardedCallback$3 = ReactErrorUtils.invokeGuardedCallback; -var hasCaughtError$1 = ReactErrorUtils.hasCaughtError; -var clearCaughtError$1 = ReactErrorUtils.clearCaughtError; - -var didWarnAboutUndefinedSnapshotBeforeUpdate = null; -{ - didWarnAboutUndefinedSnapshotBeforeUpdate = new Set(); -} - -function logError(boundary, errorInfo) { - var source = errorInfo.source; - var stack = errorInfo.stack; - if (stack === null) { - stack = getStackAddendumByWorkInProgressFiber(source); - } - - var capturedError = { - componentName: source !== null ? getComponentName(source) : 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); - capturedError.errorBoundaryFound = true; - capturedError.willRetry = true; - } - - try { - logCapturedError(capturedError); - } catch (e) { - // Prevent cycle if logCapturedError() throws. - // A cycle may still occur if logCapturedError renders a component that throws. - var suppressLogging = e && e.suppressReactErrorLogging; - if (!suppressLogging) { - console.error(e); - } - } -} - -var ReactFiberCommitWork = function( - config, - captureError, - scheduleWork, - computeExpirationForFiber, - markLegacyErrorBoundaryAsFailed, - recalculateCurrentTime -) { - var getPublicInstance = config.getPublicInstance, - mutation = config.mutation, - persistence = config.persistence; - - var callComponentWillUnmountWithTimer = function(current, instance) { - startPhaseTimer(current, "componentWillUnmount"); - instance.props = current.memoizedProps; - instance.state = current.memoizedState; - instance.componentWillUnmount(); - stopPhaseTimer(); - }; - - // Capture errors so they don't interrupt unmounting. - function safelyCallComponentWillUnmount(current, instance) { - { - invokeGuardedCallback$3( - null, - callComponentWillUnmountWithTimer, - null, - current, - instance - ); - if (hasCaughtError$1()) { - var unmountError = clearCaughtError$1(); - captureError(current, unmountError); - } - } - } - - function safelyDetachRef(current) { - var ref = current.ref; - if (ref !== null) { - if (typeof ref === "function") { - { - invokeGuardedCallback$3(null, ref, null, null); - if (hasCaughtError$1()) { - var refError = clearCaughtError$1(); - captureError(current, refError); - } - } - } else { - ref.current = null; - } - } - } - - function commitBeforeMutationLifeCycles(current, finishedWork) { - switch (finishedWork.tag) { - case ClassComponent: { - if (finishedWork.effectTag & Snapshot) { - if (current !== null) { - var prevProps = current.memoizedProps; - var prevState = current.memoizedState; - startPhaseTimer(finishedWork, "getSnapshotBeforeUpdate"); - var _instance = finishedWork.stateNode; - _instance.props = finishedWork.memoizedProps; - _instance.state = finishedWork.memoizedState; - var snapshot = _instance.getSnapshotBeforeUpdate( - prevProps, - prevState - ); - { - var didWarnSet = didWarnAboutUndefinedSnapshotBeforeUpdate; - if ( - snapshot === undefined && - !didWarnSet.has(finishedWork.type) - ) { - didWarnSet.add(finishedWork.type); - warning( - false, - "%s.getSnapshotBeforeUpdate(): A snapshot value (or null) " + - "must be returned. You have returned undefined.", - getComponentName(finishedWork) - ); - } - } - _instance.__reactInternalSnapshotBeforeUpdate = snapshot; - stopPhaseTimer(); - } - } - return; - } - case HostRoot: - case HostComponent: - case HostText: - case HostPortal: - // Nothing to do for these component types - return; - default: { - invariant( - false, - "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 commitLifeCycles( - finishedRoot, - current, - finishedWork, - currentTime, - committedExpirationTime - ) { - switch (finishedWork.tag) { - case ClassComponent: { - var _instance2 = finishedWork.stateNode; - if (finishedWork.effectTag & Update) { - if (current === null) { - startPhaseTimer(finishedWork, "componentDidMount"); - _instance2.props = finishedWork.memoizedProps; - _instance2.state = finishedWork.memoizedState; - _instance2.componentDidMount(); - stopPhaseTimer(); - } else { - var prevProps = current.memoizedProps; - var prevState = current.memoizedState; - startPhaseTimer(finishedWork, "componentDidUpdate"); - _instance2.props = finishedWork.memoizedProps; - _instance2.state = finishedWork.memoizedState; - _instance2.componentDidUpdate( - prevProps, - prevState, - _instance2.__reactInternalSnapshotBeforeUpdate - ); - stopPhaseTimer(); - } - } - var updateQueue = finishedWork.updateQueue; - if (updateQueue !== null) { - commitCallbacks(updateQueue, _instance2); - } - return; - } - case HostRoot: { - var _updateQueue = finishedWork.updateQueue; - if (_updateQueue !== null) { - var _instance3 = null; - if (finishedWork.child !== null) { - switch (finishedWork.child.tag) { - case HostComponent: - _instance3 = getPublicInstance(finishedWork.child.stateNode); - break; - case ClassComponent: - _instance3 = finishedWork.child.stateNode; - break; - } - } - commitCallbacks(_updateQueue, _instance3); - } - return; - } - case HostComponent: { - var _instance4 = 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 === null && finishedWork.effectTag & Update) { - var type = finishedWork.type; - var props = finishedWork.memoizedProps; - commitMount(_instance4, 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; - } - default: { - invariant( - false, - "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 commitErrorLogging(finishedWork, onUncaughtError) { - switch (finishedWork.tag) { - case ClassComponent: - { - var ctor = finishedWork.type; - var _instance5 = finishedWork.stateNode; - var updateQueue = finishedWork.updateQueue; - invariant( - updateQueue !== null && updateQueue.capturedValues !== null, - "An error logging effect should not have been scheduled if no errors " + - "were captured. This error is likely caused by a bug in React. " + - "Please file an issue." - ); - var capturedErrors = updateQueue.capturedValues; - updateQueue.capturedValues = null; - - if (typeof ctor.getDerivedStateFromCatch !== "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 getDerivedStateFromCatch is - // not defined. - markLegacyErrorBoundaryAsFailed(_instance5); - } - - _instance5.props = finishedWork.memoizedProps; - _instance5.state = finishedWork.memoizedState; - for (var i = 0; i < capturedErrors.length; i++) { - var errorInfo = capturedErrors[i]; - var _error = errorInfo.value; - var stack = errorInfo.stack; - logError(finishedWork, errorInfo); - _instance5.componentDidCatch(_error, { - componentStack: stack !== null ? stack : "" - }); - } - } - break; - case HostRoot: { - var _updateQueue2 = finishedWork.updateQueue; - invariant( - _updateQueue2 !== null && _updateQueue2.capturedValues !== null, - "An error logging effect should not have been scheduled if no errors " + - "were captured. This error is likely caused by a bug in React. " + - "Please file an issue." - ); - var _capturedErrors = _updateQueue2.capturedValues; - _updateQueue2.capturedValues = null; - for (var _i = 0; _i < _capturedErrors.length; _i++) { - var _errorInfo = _capturedErrors[_i]; - logError(finishedWork, _errorInfo); - onUncaughtError(_errorInfo.value); - } - break; - } - default: - invariant( - false, - "This unit of work tag cannot capture errors. This error is " + - "likely caused by a bug in React. Please file an issue." - ); - } - } - - function commitAttachRef(finishedWork) { - var ref = finishedWork.ref; - if (ref !== null) { - var _instance6 = finishedWork.stateNode; - var instanceToUse = void 0; - switch (finishedWork.tag) { - case HostComponent: - instanceToUse = getPublicInstance(_instance6); - break; - default: - instanceToUse = _instance6; - } - if (typeof ref === "function") { - ref(instanceToUse); - } else { - { - if (!ref.hasOwnProperty("current")) { - warning( - false, - "Unexpected ref object provided for %s. " + - "Use either a ref-setter function or React.createRef().%s", - getComponentName(finishedWork), - getStackAddendumByWorkInProgressFiber(finishedWork) - ); - } - } - - ref.current = instanceToUse; - } - } - } - - function commitDetachRef(current) { - var currentRef = current.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) { - if (typeof onCommitUnmount === "function") { - onCommitUnmount(current); - } - - switch (current.tag) { - case ClassComponent: { - safelyDetachRef(current); - var _instance7 = current.stateNode; - if (typeof _instance7.componentWillUnmount === "function") { - safelyCallComponentWillUnmount(current, _instance7); - } - return; - } - case HostComponent: { - safelyDetachRef(current); - return; - } - case CallComponent: { - commitNestedUnmounts(current.stateNode); - return; - } - case HostPortal: { - // TODO: this is recursive. - // We are also not using this parent because - // the portal will get pushed immediately. - if (enableMutatingReconciler && mutation) { - unmountHostComponents(current); - } else if (enablePersistentReconciler && persistence) { - emptyPortalContainer(current); - } - return; - } - } - } - - 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. - (!mutation || 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) { - // 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["return"] = null; - current.child = null; - if (current.alternate) { - current.alternate.child = null; - current.alternate["return"] = null; - } - } - - var emptyPortalContainer = void 0; - - if (!mutation) { - var commitContainer = void 0; - if (persistence) { - var replaceContainerChildren = persistence.replaceContainerChildren, - createContainerChildSet = persistence.createContainerChildSet; - - emptyPortalContainer = function(current) { - var portal = current.stateNode; - var containerInfo = portal.containerInfo; - - var emptyChildSet = createContainerChildSet(containerInfo); - replaceContainerChildren(containerInfo, emptyChildSet); - }; - commitContainer = function(finishedWork) { - switch (finishedWork.tag) { - case ClassComponent: { - return; - } - case HostComponent: { - return; - } - case HostText: { - return; - } - case HostRoot: - case HostPortal: { - var portalOrRoot = finishedWork.stateNode; - var containerInfo = portalOrRoot.containerInfo, - _pendingChildren = portalOrRoot.pendingChildren; - - replaceContainerChildren(containerInfo, _pendingChildren); - return; - } - default: { - invariant( - false, - "This unit of work tag should not have side-effects. This error is " + - "likely caused by a bug in React. Please file an issue." - ); - } - } - }; - } else { - commitContainer = function(finishedWork) { - // Noop - }; - } - if (enablePersistentReconciler || enableNoopReconciler) { - return { - commitResetTextContent: function(finishedWork) {}, - commitPlacement: function(finishedWork) {}, - commitDeletion: function(current) { - // Detach refs and call componentWillUnmount() on the whole subtree. - commitNestedUnmounts(current); - detachFiber(current); - }, - commitWork: function(current, finishedWork) { - commitContainer(finishedWork); - }, - - commitLifeCycles: commitLifeCycles, - commitBeforeMutationLifeCycles: commitBeforeMutationLifeCycles, - commitErrorLogging: commitErrorLogging, - commitAttachRef: commitAttachRef, - commitDetachRef: commitDetachRef - }; - } else if (persistence) { - invariant(false, "Persistent reconciler is disabled."); - } else { - invariant(false, "Noop reconciler is disabled."); - } - } - var commitMount = mutation.commitMount, - commitUpdate = mutation.commitUpdate, - resetTextContent = mutation.resetTextContent, - commitTextUpdate = mutation.commitTextUpdate, - appendChild = mutation.appendChild, - appendChildToContainer = mutation.appendChildToContainer, - insertBefore = mutation.insertBefore, - insertInContainerBefore = mutation.insertInContainerBefore, - removeChild = mutation.removeChild, - removeChildFromContainer = mutation.removeChildFromContainer; - - function getHostParentFiber(fiber) { - var parent = fiber["return"]; - while (parent !== null) { - if (isHostParent(parent)) { - return parent; - } - parent = parent["return"]; - } - invariant( - false, - "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) { - // 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) { - // Recursively insert all host nodes into the parent. - var parentFiber = getHostParentFiber(finishedWork); - 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: - invariant( - false, - "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 recurse down its - // children to find all the terminal nodes. - var node = finishedWork; - while (true) { - if (node.tag === HostComponent || node.tag === HostText) { - if (before) { - if (isContainer) { - insertInContainerBefore(parent, node.stateNode, before); - } else { - insertBefore(parent, node.stateNode, before); - } - } else { - if (isContainer) { - appendChildToContainer(parent, node.stateNode); - } else { - appendChild(parent, node.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) { - // We only have the top Fiber that was inserted but we need recurse down its - var node = current; - - // Each iteration, currentParent is populated with node's host parent if not - // currentParentIsValid. - var currentParentIsValid = false; - var currentParent = void 0; - var currentParentIsContainer = void 0; - - while (true) { - if (!currentParentIsValid) { - var parent = node["return"]; - findParent: while (true) { - invariant( - parent !== null, - "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 (node.tag === HostPortal) { - // 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; - // Visit children because portals might contain host components. - if (node.child !== null) { - 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) { - return; - } - while (node.sibling === null) { - if (node["return"] === null || node["return"] === current) { - 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) { - // Recursively delete all host nodes from the parent. - // Detach refs and call componentWillUnmount() on the whole subtree. - unmountHostComponents(current); - detachFiber(current); - } - - function commitWork(current, finishedWork) { - switch (finishedWork.tag) { - case ClassComponent: { - return; - } - case HostComponent: { - var _instance8 = finishedWork.stateNode; - if (_instance8 != 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 !== null ? current.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( - _instance8, - updatePayload, - type, - oldProps, - newProps, - finishedWork - ); - } - } - return; - } - case HostText: { - invariant( - finishedWork.stateNode !== null, - "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 !== null ? current.memoizedProps : newText; - commitTextUpdate(textInstance, oldText, newText); - return; - } - case HostRoot: { - return; - } - default: { - invariant( - false, - "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 commitResetTextContent(current) { - resetTextContent(current.stateNode); - } - - if (enableMutatingReconciler) { - return { - commitBeforeMutationLifeCycles: commitBeforeMutationLifeCycles, - commitResetTextContent: commitResetTextContent, - commitPlacement: commitPlacement, - commitDeletion: commitDeletion, - commitWork: commitWork, - commitLifeCycles: commitLifeCycles, - commitErrorLogging: commitErrorLogging, - commitAttachRef: commitAttachRef, - commitDetachRef: commitDetachRef - }; - } else { - invariant(false, "Mutating reconciler is disabled."); - } -}; - -var NO_CONTEXT = {}; - -var ReactFiberHostContext = function(config, stack) { - var getChildHostContext = config.getChildHostContext, - getRootHostContext = config.getRootHostContext; - var createCursor = stack.createCursor, - push = stack.push, - pop = stack.pop; - - var contextStackCursor = createCursor(NO_CONTEXT); - var contextFiberStackCursor = createCursor(NO_CONTEXT); - var rootInstanceStackCursor = createCursor(NO_CONTEXT); - - function requiredContext(c) { - invariant( - c !== NO_CONTEXT, - "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, NO_CONTEXT, fiber); - var nextRootContext = getRootHostContext(nextRootInstance); - // Now that we know this function doesn't throw, replace it. - pop(contextStackCursor, fiber); - push(contextStackCursor, nextRootContext, fiber); - } - - function popHostContainer(fiber) { - pop(contextStackCursor, fiber); - pop(contextFiberStackCursor, fiber); - pop(rootInstanceStackCursor, fiber); - } - - function getHostContext() { - var context = requiredContext(contextStackCursor.current); - return context; - } - - function pushHostContext(fiber) { - var rootInstance = requiredContext(rootInstanceStackCursor.current); - var context = requiredContext(contextStackCursor.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, 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, fiber); - pop(contextFiberStackCursor, fiber); - } - - return { - getHostContext: getHostContext, - getRootHostContainer: getRootHostContainer, - popHostContainer: popHostContainer, - popHostContext: popHostContext, - pushHostContainer: pushHostContainer, - pushHostContext: pushHostContext - }; -}; - -var ReactFiberHydrationContext = function(config) { - var shouldSetTextContent = config.shouldSetTextContent, - hydration = config.hydration; - - // If this doesn't have hydration mode. - - if (!hydration) { - return { - enterHydrationState: function() { - return false; - }, - resetHydrationState: function() {}, - tryToClaimNextHydratableInstance: function() {}, - prepareToHydrateHostInstance: function() { - invariant( - false, - "Expected prepareToHydrateHostInstance() to never be called. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - }, - prepareToHydrateHostTextInstance: function() { - invariant( - false, - "Expected prepareToHydrateHostTextInstance() to never be called. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - }, - popHydrationState: function(fiber) { - return false; - } - }; - } - - var canHydrateInstance = hydration.canHydrateInstance, - canHydrateTextInstance = hydration.canHydrateTextInstance, - getNextHydratableSibling = hydration.getNextHydratableSibling, - getFirstHydratableChild = hydration.getFirstHydratableChild, - hydrateInstance = hydration.hydrateInstance, - hydrateTextInstance = hydration.hydrateTextInstance, - didNotMatchHydratedContainerTextInstance = - hydration.didNotMatchHydratedContainerTextInstance, - didNotMatchHydratedTextInstance = hydration.didNotMatchHydratedTextInstance, - didNotHydrateContainerInstance = hydration.didNotHydrateContainerInstance, - didNotHydrateInstance = hydration.didNotHydrateInstance, - didNotFindHydratableContainerInstance = - hydration.didNotFindHydratableContainerInstance, - didNotFindHydratableContainerTextInstance = - hydration.didNotFindHydratableContainerTextInstance, - didNotFindHydratableInstance = hydration.didNotFindHydratableInstance, - didNotFindHydratableTextInstance = - hydration.didNotFindHydratableTextInstance; - - // 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) { - var parentInstance = fiber.stateNode.containerInfo; - nextHydratableInstance = getFirstHydratableChild(parentInstance); - hydrationParentFiber = 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; - } - 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; - } - 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; - } - 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; - } - 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(nextInstance); - 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, nextHydratableInstance); - } - hydrationParentFiber = fiber; - nextHydratableInstance = getFirstHydratableChild(nextInstance); - } - - function prepareToHydrateHostInstance( - fiber, - rootContainerInstance, - hostContext - ) { - 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) { - 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 popToNextHostParent(fiber) { - var parent = fiber["return"]; - while ( - parent !== null && - parent.tag !== HostComponent && - parent.tag !== HostRoot - ) { - parent = parent["return"]; - } - hydrationParentFiber = parent; - } - - function popHydrationState(fiber) { - 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() { - hydrationParentFiber = null; - nextHydratableInstance = null; - isHydrating = false; - } - - return { - enterHydrationState: enterHydrationState, - resetHydrationState: resetHydrationState, - tryToClaimNextHydratableInstance: tryToClaimNextHydratableInstance, - prepareToHydrateHostInstance: prepareToHydrateHostInstance, - prepareToHydrateHostTextInstance: prepareToHydrateHostTextInstance, - popHydrationState: popHydrationState - }; -}; - -// 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; - -var warnedAboutMissingGetChildContext = void 0; - -{ - warnedAboutMissingGetChildContext = {}; -} - -var ReactFiberLegacyContext = function(stack) { - var createCursor = stack.createCursor, - push = stack.push, - pop = stack.pop; - - // A cursor to the current merged context object on the stack. - - var contextStackCursor = createCursor(emptyObject); - // 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 = emptyObject; - - function getUnmaskedContext(workInProgress) { - var hasOwnContext = isContextProvider(workInProgress); - if (hasOwnContext) { - // If the fiber is a context provider itself, when we read its context - // we 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 emptyObject; - } - - // 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(workInProgress) || "Unknown"; - checkPropTypes( - contextTypes, - context, - "context", - name, - ReactDebugCurrentFiber.getCurrentFiberStackAddendum - ); - } - - // 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 isContextConsumer(fiber) { - return fiber.tag === ClassComponent && fiber.type.contextTypes != null; - } - - function isContextProvider(fiber) { - return fiber.tag === ClassComponent && fiber.type.childContextTypes != null; - } - - function popContextProvider(fiber) { - if (!isContextProvider(fiber)) { - return; - } - - pop(didPerformWorkStackCursor, fiber); - pop(contextStackCursor, fiber); - } - - function popTopLevelContextObject(fiber) { - pop(didPerformWorkStackCursor, fiber); - pop(contextStackCursor, fiber); - } - - function pushTopLevelContextObject(fiber, context, didChange) { - invariant( - contextStackCursor.cursor == null, - "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, parentContext) { - var instance = fiber.stateNode; - var childContextTypes = fiber.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(fiber) || "Unknown"; - - if (!warnedAboutMissingGetChildContext[componentName]) { - warnedAboutMissingGetChildContext[componentName] = true; - warning( - 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; - { - ReactDebugCurrentFiber.setCurrentPhase("getChildContext"); - } - startPhaseTimer(fiber, "getChildContext"); - childContext = instance.getChildContext(); - stopPhaseTimer(); - { - ReactDebugCurrentFiber.setCurrentPhase(null); - } - for (var contextKey in childContext) { - invariant( - contextKey in childContextTypes, - '%s.getChildContext(): key "%s" is not defined in childContextTypes.', - getComponentName(fiber) || "Unknown", - contextKey - ); - } - { - var name = getComponentName(fiber) || "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. - ReactDebugCurrentFiber.getCurrentFiberStackAddendum - ); - } - - return Object.assign({}, parentContext, childContext); - } - - function pushContextProvider(workInProgress) { - if (!isContextProvider(workInProgress)) { - return false; - } - - 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) || - emptyObject; - - // 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, didChange) { - var instance = workInProgress.stateNode; - invariant( - instance, - "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, 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 - invariant( - isFiberMounted(fiber) && fiber.tag === ClassComponent, - "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; - while (node.tag !== HostRoot) { - if (isContextProvider(node)) { - return node.stateNode.__reactInternalMemoizedMergedChildContext; - } - var parent = node["return"]; - invariant( - parent, - "Found unexpected detached subtree parent. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - node = parent; - } - return node.stateNode.context; - } - - return { - getUnmaskedContext: getUnmaskedContext, - cacheContext: cacheContext, - getMaskedContext: getMaskedContext, - hasContextChanged: hasContextChanged, - isContextConsumer: isContextConsumer, - isContextProvider: isContextProvider, - popContextProvider: popContextProvider, - popTopLevelContextObject: popTopLevelContextObject, - pushTopLevelContextObject: pushTopLevelContextObject, - processChildContext: processChildContext, - pushContextProvider: pushContextProvider, - invalidateContextProvider: invalidateContextProvider, - findCurrentUnmaskedContext: findCurrentUnmaskedContext - }; -}; - -var ReactFiberNewContext = function(stack) { - var createCursor = stack.createCursor, - push = stack.push, - pop = stack.pop; - - var providerCursor = createCursor(null); - var valueCursor = createCursor(null); - var changedBitsCursor = createCursor(0); - - var rendererSigil = void 0; - { - // Use this to detect multiple renderers using the same context - rendererSigil = {}; - } - - function pushProvider(providerFiber) { - var context = providerFiber.type._context; - - push(changedBitsCursor, context._changedBits, providerFiber); - push(valueCursor, context._currentValue, providerFiber); - push(providerCursor, providerFiber, providerFiber); - - context._currentValue = providerFiber.pendingProps.value; - context._changedBits = providerFiber.stateNode; - - { - !( - context._currentRenderer === null || - context._currentRenderer === rendererSigil - ) - ? warning( - false, - "Detected multiple renderers concurrently rendering the " + - "same context provider. This is currently unsupported." - ) - : void 0; - context._currentRenderer = rendererSigil; - } - } - - function popProvider(providerFiber) { - var changedBits = changedBitsCursor.current; - var currentValue = valueCursor.current; - - pop(providerCursor, providerFiber); - pop(valueCursor, providerFiber); - pop(changedBitsCursor, providerFiber); - - var context = providerFiber.type._context; - context._currentValue = currentValue; - context._changedBits = changedBits; - } - - return { - pushProvider: pushProvider, - popProvider: popProvider - }; -}; - -var ReactFiberStack = function() { - var valueStack = []; - - var fiberStack = void 0; - - { - fiberStack = []; - } - - var index = -1; - - function createCursor(defaultValue) { - return { - current: defaultValue - }; - } - - function isEmpty() { - return index === -1; - } - - function pop(cursor, fiber) { - if (index < 0) { - { - warning(false, "Unexpected pop."); - } - return; - } - - { - if (fiber !== fiberStack[index]) { - warning(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; - } - - function checkThatStackIsEmpty() { - { - if (index !== -1) { - warning( - false, - "Expected an empty stack. Something was not reset properly." - ); - } - } - } - - function resetStackAfterFatalErrorInDev() { - { - index = -1; - valueStack.length = 0; - fiberStack.length = 0; - } - } - - return { - createCursor: createCursor, - isEmpty: isEmpty, - pop: pop, - push: push, - checkThatStackIsEmpty: checkThatStackIsEmpty, - resetStackAfterFatalErrorInDev: resetStackAfterFatalErrorInDev - }; -}; - -var invokeGuardedCallback$2 = ReactErrorUtils.invokeGuardedCallback; -var hasCaughtError = ReactErrorUtils.hasCaughtError; -var clearCaughtError = ReactErrorUtils.clearCaughtError; - -var didWarnAboutStateTransition = void 0; -var didWarnSetStateChildContext = void 0; -var warnAboutUpdateOnUnmounted = void 0; -var warnAboutInvalidUpdates = void 0; - -{ - didWarnAboutStateTransition = false; - didWarnSetStateChildContext = false; - var didWarnStateUpdateForUnmountedComponent = {}; - - warnAboutUpdateOnUnmounted = function(fiber) { - // 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) || "ReactClass"; - if (didWarnStateUpdateForUnmountedComponent[componentName]) { - return; - } - warning( - false, - "Can't call setState (or forceUpdate) 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 the " + - "componentWillUnmount method.%s", - getStackAddendumByWorkInProgressFiber(fiber) - ); - didWarnStateUpdateForUnmountedComponent[componentName] = true; - }; - - warnAboutInvalidUpdates = function(instance) { - switch (ReactDebugCurrentFiber.phase) { - case "getChildContext": - if (didWarnSetStateChildContext) { - return; - } - warning( - false, - "setState(...): Cannot call setState() inside getChildContext()" - ); - didWarnSetStateChildContext = true; - break; - case "render": - if (didWarnAboutStateTransition) { - return; - } - warning( - false, - "Cannot update during an existing state transition (such as within " + - "`render` or another component's constructor). Render methods should " + - "be a pure function of props and state; constructor side-effects are " + - "an anti-pattern, but can be moved to `componentWillMount`." - ); - didWarnAboutStateTransition = true; - break; - } - }; -} - -var ReactFiberScheduler = function(config) { - var stack = ReactFiberStack(); - var hostContext = ReactFiberHostContext(config, stack); - var legacyContext = ReactFiberLegacyContext(stack); - var newContext = ReactFiberNewContext(stack); - var popHostContext = hostContext.popHostContext, - popHostContainer = hostContext.popHostContainer; - var popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject, - popLegacyContextProvider = legacyContext.popContextProvider; - var popProvider = newContext.popProvider; - - var hydrationContext = ReactFiberHydrationContext(config); - - var _ReactFiberBeginWork = ReactFiberBeginWork( - config, - hostContext, - legacyContext, - newContext, - hydrationContext, - scheduleWork, - computeExpirationForFiber - ), - beginWork = _ReactFiberBeginWork.beginWork; - - var _ReactFiberCompleteWo = ReactFiberCompleteWork( - config, - hostContext, - legacyContext, - newContext, - hydrationContext - ), - completeWork = _ReactFiberCompleteWo.completeWork; - - var _ReactFiberUnwindWork = ReactFiberUnwindWork( - hostContext, - legacyContext, - newContext, - scheduleWork, - isAlreadyFailedLegacyErrorBoundary - ), - throwException = _ReactFiberUnwindWork.throwException, - unwindWork = _ReactFiberUnwindWork.unwindWork, - unwindInterruptedWork = _ReactFiberUnwindWork.unwindInterruptedWork; - - var _ReactFiberCommitWork = ReactFiberCommitWork( - config, - onCommitPhaseError, - scheduleWork, - computeExpirationForFiber, - markLegacyErrorBoundaryAsFailed, - recalculateCurrentTime - ), - commitBeforeMutationLifeCycles = - _ReactFiberCommitWork.commitBeforeMutationLifeCycles, - commitResetTextContent = _ReactFiberCommitWork.commitResetTextContent, - commitPlacement = _ReactFiberCommitWork.commitPlacement, - commitDeletion = _ReactFiberCommitWork.commitDeletion, - commitWork = _ReactFiberCommitWork.commitWork, - commitLifeCycles = _ReactFiberCommitWork.commitLifeCycles, - commitErrorLogging = _ReactFiberCommitWork.commitErrorLogging, - commitAttachRef = _ReactFiberCommitWork.commitAttachRef, - commitDetachRef = _ReactFiberCommitWork.commitDetachRef; - - var now = config.now, - scheduleDeferredCallback = config.scheduleDeferredCallback, - cancelDeferredCallback = config.cancelDeferredCallback, - prepareForCommit = config.prepareForCommit, - resetAfterCommit = config.resetAfterCommit; - - // Represents the current time in ms. - - var originalStartTimeMs = now(); - var mostRecentCurrentTime = msToExpirationTime(0); - var mostRecentCurrentTimeMs = originalStartTimeMs; - - // Used to ensure computeUniqueAsyncExpiration is monotonically increases. - var lastUniqueAsyncExpiration = 0; - - // Represents the expiration time that incoming updates should use. (If this - // is NoWork, use the default strategy: async updates in async mode, sync - // updates in sync mode.) - var expirationContext = NoWork; - - var isWorking = false; - - // The next work in progress fiber that we're currently working on. - var nextUnitOfWork = null; - var nextRoot = null; - // The time at which we're currently rendering work. - var nextRenderExpirationTime = NoWork; - - // The next fiber with an effect that we're currently committing. - var nextEffect = null; - - var isCommitting = false; - - var isRootReadyForCommit = false; - - var legacyErrorBoundariesThatAlreadyFailed = null; - - // Used for performance tracking. - var interruptedBy = null; - - var stashedWorkInProgressProperties = void 0; - var replayUnitOfWork = void 0; - var isReplayingFailedUnitOfWork = void 0; - var originalReplayError = void 0; - var rethrowOriginalError = void 0; - if (true && replayFailedUnitOfWorkWithInvokeGuardedCallback) { - stashedWorkInProgressProperties = null; - isReplayingFailedUnitOfWork = false; - originalReplayError = null; - replayUnitOfWork = function(failedUnitOfWork, error, isAsync) { - // Restore the original state of the work-in-progress - assignFiberPropertiesInDEV( - failedUnitOfWork, - stashedWorkInProgressProperties - ); - switch (failedUnitOfWork.tag) { - case HostRoot: - popHostContainer(failedUnitOfWork); - popTopLevelLegacyContextObject(failedUnitOfWork); - break; - case HostComponent: - popHostContext(failedUnitOfWork); - break; - case ClassComponent: - popLegacyContextProvider(failedUnitOfWork); - break; - case HostPortal: - popHostContainer(failedUnitOfWork); - break; - case ContextProvider: - popProvider(failedUnitOfWork); - break; - } - // Replay the begin phase. - isReplayingFailedUnitOfWork = true; - originalReplayError = error; - invokeGuardedCallback$2(null, workLoop, null, isAsync); - isReplayingFailedUnitOfWork = false; - originalReplayError = null; - if (hasCaughtError()) { - clearCaughtError(); - } else { - // If the begin phase did not fail the second time, set this pointer - // back to the original value. - nextUnitOfWork = failedUnitOfWork; - } - }; - rethrowOriginalError = function() { - throw originalReplayError; - }; - } - - function resetStack() { - if (nextUnitOfWork !== null) { - var interruptedWork = nextUnitOfWork["return"]; - while (interruptedWork !== null) { - unwindInterruptedWork(interruptedWork); - interruptedWork = interruptedWork["return"]; - } - } - - { - ReactStrictModeWarnings.discardPendingWarnings(); - stack.checkThatStackIsEmpty(); - } - - nextRoot = null; - nextRenderExpirationTime = NoWork; - nextUnitOfWork = null; - - isRootReadyForCommit = false; - } - - function commitAllHostEffects() { - while (nextEffect !== null) { - { - ReactDebugCurrentFiber.setCurrentFiber(nextEffect); - } - recordEffect(); - - var effectTag = nextEffect.effectTag; - - if (effectTag & ContentReset) { - commitResetTextContent(nextEffect); - } - - if (effectTag & Ref) { - var current = nextEffect.alternate; - if (current !== null) { - commitDetachRef(current); - } - } - - // 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; - } - } - nextEffect = nextEffect.nextEffect; - } - - { - ReactDebugCurrentFiber.resetCurrentFiber(); - } - } - - function commitBeforeMutationLifecycles() { - while (nextEffect !== null) { - var effectTag = nextEffect.effectTag; - - if (effectTag & Snapshot) { - recordEffect(); - var current = nextEffect.alternate; - commitBeforeMutationLifeCycles(current, nextEffect); - } - - // Don't cleanup effects yet; - // This will be done by commitAllLifeCycles() - nextEffect = nextEffect.nextEffect; - } - } - - function commitAllLifeCycles( - finishedRoot, - currentTime, - committedExpirationTime - ) { - { - ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings(); - - if (warnAboutDeprecatedLifecycles) { - ReactStrictModeWarnings.flushPendingDeprecationWarnings(); - } - } - while (nextEffect !== null) { - var effectTag = nextEffect.effectTag; - - if (effectTag & (Update | Callback)) { - recordEffect(); - var current = nextEffect.alternate; - commitLifeCycles( - finishedRoot, - current, - nextEffect, - currentTime, - committedExpirationTime - ); - } - - if (effectTag & ErrLog) { - commitErrorLogging(nextEffect, onUncaughtError); - } - - if (effectTag & Ref) { - recordEffect(); - commitAttachRef(nextEffect); - } - - var next = nextEffect.nextEffect; - // Ensure that we clean these up so that we don't accidentally keep them. - // I'm not actually sure this matters because we can't reset firstEffect - // and lastEffect since they're on every node, not just the effectful - // ones. So we have to clean everything as we reuse nodes anyway. - nextEffect.nextEffect = null; - // Ensure that we reset the effectTag here so that we can rely on effect - // tags to reason about the current life-cycle. - nextEffect = next; - } - } - - function isAlreadyFailedLegacyErrorBoundary(instance) { - return ( - legacyErrorBoundariesThatAlreadyFailed !== null && - legacyErrorBoundariesThatAlreadyFailed.has(instance) - ); - } - - function markLegacyErrorBoundaryAsFailed(instance) { - if (legacyErrorBoundariesThatAlreadyFailed === null) { - legacyErrorBoundariesThatAlreadyFailed = new Set([instance]); - } else { - legacyErrorBoundariesThatAlreadyFailed.add(instance); - } - } - - function commitRoot(finishedWork) { - isWorking = true; - isCommitting = true; - startCommitTimer(); - - var root = finishedWork.stateNode; - invariant( - root.current !== finishedWork, - "Cannot commit the same tree as before. This is probably a bug " + - "related to the return field. This error is likely caused by a bug " + - "in React. Please file an issue." - ); - var committedExpirationTime = root.pendingCommitExpirationTime; - invariant( - committedExpirationTime !== NoWork, - "Cannot commit an incomplete root. This error is likely caused by a " + - "bug in React. Please file an issue." - ); - root.pendingCommitExpirationTime = NoWork; - - var currentTime = recalculateCurrentTime(); - - // Reset this to null before calling lifecycles - ReactCurrentOwner.current = null; - - 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; - } - - prepareForCommit(root.containerInfo); - - // Invoke instances of getSnapshotBeforeUpdate before mutation. - nextEffect = firstEffect; - startCommitSnapshotEffectsTimer(); - while (nextEffect !== null) { - var didError = false; - var error = void 0; - { - invokeGuardedCallback$2(null, commitBeforeMutationLifecycles, null); - if (hasCaughtError()) { - didError = true; - error = clearCaughtError(); - } - } - if (didError) { - invariant( - nextEffect !== null, - "Should have next effect. This error is likely caused by a bug " + - "in React. Please file an issue." - ); - onCommitPhaseError(nextEffect, error); - // Clean-up - if (nextEffect !== null) { - nextEffect = nextEffect.nextEffect; - } - } - } - stopCommitSnapshotEffectsTimer(); - - // Commit all the side-effects within a tree. We'll do this in two passes. - // The first pass performs all the host insertions, updates, deletions and - // ref unmounts. - nextEffect = firstEffect; - startCommitHostEffectsTimer(); - while (nextEffect !== null) { - var _didError = false; - var _error = void 0; - { - invokeGuardedCallback$2(null, commitAllHostEffects, null); - if (hasCaughtError()) { - _didError = true; - _error = clearCaughtError(); - } - } - if (_didError) { - invariant( - nextEffect !== null, - "Should have next effect. This error is likely caused by a bug " + - "in React. Please file an issue." - ); - onCommitPhaseError(nextEffect, _error); - // Clean-up - if (nextEffect !== null) { - nextEffect = nextEffect.nextEffect; - } - } - } - stopCommitHostEffectsTimer(); - - resetAfterCommit(root.containerInfo); - - // The work-in-progress tree is now the current tree. This must come after - // the first pass of the commit phase, so that the previous tree is still - // current during componentWillUnmount, but before the second pass, so that - // the finished work is current during componentDidMount/Update. - root.current = finishedWork; - - // In the second pass we'll perform all life-cycles and ref callbacks. - // Life-cycles happen as a separate pass so that all placements, updates, - // and deletions in the entire tree have already been invoked. - // This pass also triggers any renderer-specific initial effects. - nextEffect = firstEffect; - startCommitLifeCyclesTimer(); - while (nextEffect !== null) { - var _didError2 = false; - var _error2 = void 0; - { - invokeGuardedCallback$2( - null, - commitAllLifeCycles, - null, - root, - currentTime, - committedExpirationTime - ); - if (hasCaughtError()) { - _didError2 = true; - _error2 = clearCaughtError(); - } - } - if (_didError2) { - invariant( - nextEffect !== null, - "Should have next effect. This error is likely caused by a bug " + - "in React. Please file an issue." - ); - onCommitPhaseError(nextEffect, _error2); - if (nextEffect !== null) { - nextEffect = nextEffect.nextEffect; - } - } - } - - isCommitting = false; - isWorking = false; - stopCommitLifeCyclesTimer(); - stopCommitTimer(); - if (typeof onCommitRoot === "function") { - onCommitRoot(finishedWork.stateNode); - } - if (true && ReactFiberInstrumentation_1.debugTool) { - ReactFiberInstrumentation_1.debugTool.onCommitWork(finishedWork); - } - - var remainingTime = root.current.expirationTime; - if (remainingTime === NoWork) { - // If there's no remaining work, we can clear the set of already failed - // error boundaries. - legacyErrorBoundariesThatAlreadyFailed = null; - } - return remainingTime; - } - - function resetExpirationTime(workInProgress, renderTime) { - if (renderTime !== Never && workInProgress.expirationTime === Never) { - // The children of this component are hidden. Don't bubble their - // expiration times. - return; - } - - // Check for pending updates. - var newExpirationTime = getUpdateExpirationTime(workInProgress); - - // TODO: Calls need to visit stateNode - - // Bubble up the earliest expiration time. - var child = workInProgress.child; - while (child !== null) { - if ( - child.expirationTime !== NoWork && - (newExpirationTime === NoWork || - newExpirationTime > child.expirationTime) - ) { - newExpirationTime = child.expirationTime; - } - child = child.sibling; - } - workInProgress.expirationTime = newExpirationTime; - } - - function completeUnitOfWork(workInProgress) { - // 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. - while (true) { - // 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 = workInProgress.alternate; - { - ReactDebugCurrentFiber.setCurrentFiber(workInProgress); - } - - var returnFiber = workInProgress["return"]; - var siblingFiber = workInProgress.sibling; - - if ((workInProgress.effectTag & Incomplete) === NoEffect) { - // This fiber completed. - var next = completeWork( - current, - workInProgress, - nextRenderExpirationTime - ); - stopWorkTimer(workInProgress); - resetExpirationTime(workInProgress, nextRenderExpirationTime); - { - ReactDebugCurrentFiber.resetCurrentFiber(); - } - - if (next !== null) { - stopWorkTimer(workInProgress); - if (true && ReactFiberInstrumentation_1.debugTool) { - ReactFiberInstrumentation_1.debugTool.onCompleteWork( - workInProgress - ); - } - // If completing this work spawned new work, do that next. We'll come - // back here again. - 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; - } - } - - if (true && ReactFiberInstrumentation_1.debugTool) { - ReactFiberInstrumentation_1.debugTool.onCompleteWork(workInProgress); - } - - if (siblingFiber !== null) { - // If there is more work to do in this returnFiber, do that next. - return siblingFiber; - } else if (returnFiber !== null) { - // If there's no more work in this returnFiber. Complete the returnFiber. - workInProgress = returnFiber; - continue; - } else { - // We've reached the root. - isRootReadyForCommit = true; - return null; - } - } 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); - // Because this fiber did not complete, don't reset its expiration time. - if (workInProgress.effectTag & DidCapture) { - // Restarting an error boundary - stopFailedWorkTimer(workInProgress); - } else { - stopWorkTimer(workInProgress); - } - - { - ReactDebugCurrentFiber.resetCurrentFiber(); - } - - if (_next !== null) { - stopWorkTimer(workInProgress); - if (true && ReactFiberInstrumentation_1.debugTool) { - ReactFiberInstrumentation_1.debugTool.onCompleteWork( - workInProgress - ); - } - // 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. - _next.effectTag &= HostEffectMask; - return _next; - } - - if (returnFiber !== null) { - // Mark the parent fiber as incomplete and clear its effect list. - returnFiber.firstEffect = returnFiber.lastEffect = null; - returnFiber.effectTag |= Incomplete; - } - - if (true && ReactFiberInstrumentation_1.debugTool) { - ReactFiberInstrumentation_1.debugTool.onCompleteWork(workInProgress); - } - - if (siblingFiber !== null) { - // If there is more work to do in this returnFiber, do that next. - return siblingFiber; - } else if (returnFiber !== null) { - // If there's no more work in this returnFiber. Complete the returnFiber. - workInProgress = returnFiber; - continue; - } else { - return null; - } - } - } - - // Without this explicit null return Flow complains of invalid return type - // TODO Remove the above while(true) loop - // eslint-disable-next-line no-unreachable - return null; - } - - function performUnitOfWork(workInProgress) { - // 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 = workInProgress.alternate; - - // See if beginning this work spawns more work. - startWorkTimer(workInProgress); - { - ReactDebugCurrentFiber.setCurrentFiber(workInProgress); - } - - if (true && replayFailedUnitOfWorkWithInvokeGuardedCallback) { - stashedWorkInProgressProperties = assignFiberPropertiesInDEV( - stashedWorkInProgressProperties, - workInProgress - ); - } - var next = beginWork(current, workInProgress, nextRenderExpirationTime); - { - ReactDebugCurrentFiber.resetCurrentFiber(); - if (isReplayingFailedUnitOfWork) { - // Currently replaying a failed unit of work. This should be unreachable, - // because the render phase is meant to be idempotent, and it should - // have thrown again. Since it didn't, rethrow the original error, so - // React's internal stack is not misaligned. - rethrowOriginalError(); - } - } - if (true && ReactFiberInstrumentation_1.debugTool) { - ReactFiberInstrumentation_1.debugTool.onBeginWork(workInProgress); - } - - if (next === null) { - // If this doesn't spawn new work, complete the current work. - next = completeUnitOfWork(workInProgress); - } - - ReactCurrentOwner.current = null; - - return next; - } - - function workLoop(isAsync) { - if (!isAsync) { - // Flush all expired work. - while (nextUnitOfWork !== null) { - nextUnitOfWork = performUnitOfWork(nextUnitOfWork); - } - } else { - // Flush asynchronous work until the deadline runs out of time. - while (nextUnitOfWork !== null && !shouldYield()) { - nextUnitOfWork = performUnitOfWork(nextUnitOfWork); - } - } - } - - function renderRoot(root, expirationTime, isAsync) { - invariant( - !isWorking, - "renderRoot was called recursively. This error is likely caused " + - "by a bug in React. Please file an issue." - ); - isWorking = true; - - // Check if we're starting from a fresh stack, or if we're resuming from - // previously yielded work. - if ( - expirationTime !== nextRenderExpirationTime || - root !== nextRoot || - nextUnitOfWork === null - ) { - // Reset the stack and start working from the root. - resetStack(); - nextRoot = root; - nextRenderExpirationTime = expirationTime; - nextUnitOfWork = createWorkInProgress( - nextRoot.current, - null, - nextRenderExpirationTime - ); - root.pendingCommitExpirationTime = NoWork; - } - - var didFatal = false; - - startWorkLoopTimer(nextUnitOfWork); - - do { - try { - workLoop(isAsync); - } catch (thrownValue) { - if (nextUnitOfWork === null) { - // This is a fatal error. - didFatal = true; - onUncaughtError(thrownValue); - break; - } - - if (true && replayFailedUnitOfWorkWithInvokeGuardedCallback) { - var failedUnitOfWork = nextUnitOfWork; - replayUnitOfWork(failedUnitOfWork, thrownValue, isAsync); - } - - var sourceFiber = nextUnitOfWork; - var returnFiber = sourceFiber["return"]; - if (returnFiber === null) { - // This is the root. The root could capture its own errors. However, - // we don't know if it errors before or after we pushed the host - // context. This information is needed to avoid a stack mismatch. - // Because we're not sure, treat this as a fatal error. We could track - // which phase it fails in, but doesn't seem worth it. At least - // for now. - didFatal = true; - onUncaughtError(thrownValue); - break; - } - throwException(returnFiber, sourceFiber, thrownValue); - nextUnitOfWork = completeUnitOfWork(sourceFiber); - } - break; - } while (true); - - // We're done performing work. Time to clean up. - var didCompleteRoot = false; - isWorking = false; - - // Yield back to main thread. - if (didFatal) { - stopWorkLoopTimer(interruptedBy, didCompleteRoot); - interruptedBy = null; - // There was a fatal error. - { - stack.resetStackAfterFatalErrorInDev(); - } - return null; - } else if (nextUnitOfWork === null) { - // We reached the root. - if (isRootReadyForCommit) { - didCompleteRoot = true; - stopWorkLoopTimer(interruptedBy, didCompleteRoot); - interruptedBy = null; - // The root successfully completed. It's ready for commit. - root.pendingCommitExpirationTime = expirationTime; - var finishedWork = root.current.alternate; - return finishedWork; - } else { - // The root did not complete. - stopWorkLoopTimer(interruptedBy, didCompleteRoot); - interruptedBy = null; - invariant( - false, - "Expired work should have completed. This error is likely caused " + - "by a bug in React. Please file an issue." - ); - } - } else { - stopWorkLoopTimer(interruptedBy, didCompleteRoot); - interruptedBy = null; - // There's more work to do, but we ran out of time. Yield back to - // the renderer. - return null; - } - } - - function scheduleCapture(sourceFiber, boundaryFiber, value, expirationTime) { - // TODO: We only support dispatching errors. - var capturedValue = createCapturedValue(value, sourceFiber); - var update = { - expirationTime: expirationTime, - partialState: null, - callback: null, - isReplace: false, - isForced: false, - capturedValue: capturedValue, - next: null - }; - insertUpdateIntoFiber(boundaryFiber, update); - scheduleWork(boundaryFiber, expirationTime); - } - - function dispatch(sourceFiber, value, expirationTime) { - invariant( - !isWorking || isCommitting, - "dispatch: Cannot dispatch during the render phase." - ); - - // TODO: Handle arrays - - var fiber = sourceFiber["return"]; - while (fiber !== null) { - switch (fiber.tag) { - case ClassComponent: - var ctor = fiber.type; - var instance = fiber.stateNode; - if ( - typeof ctor.getDerivedStateFromCatch === "function" || - (typeof instance.componentDidCatch === "function" && - !isAlreadyFailedLegacyErrorBoundary(instance)) - ) { - scheduleCapture(sourceFiber, fiber, value, expirationTime); - return; - } - break; - // TODO: Handle async boundaries - case HostRoot: - scheduleCapture(sourceFiber, fiber, value, expirationTime); - return; - } - fiber = fiber["return"]; - } - - if (sourceFiber.tag === HostRoot) { - // Error was thrown at the root. There is no parent, so the root - // itself should capture it. - scheduleCapture(sourceFiber, sourceFiber, value, expirationTime); - } - } - - function onCommitPhaseError(fiber, error) { - return dispatch(fiber, error, Sync); - } - - function computeAsyncExpiration(currentTime) { - // Given the current clock time, returns an expiration time. We use rounding - // to batch like updates together. - // Should complete within ~1000ms. 1200ms max. - var expirationMs = 5000; - var bucketSizeMs = 250; - return computeExpirationBucket(currentTime, expirationMs, bucketSizeMs); - } - - function computeInteractiveExpiration(currentTime) { - var expirationMs = void 0; - // 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. - { - // Should complete within ~500ms. 600ms max. - expirationMs = 500; - } - var bucketSizeMs = 100; - return computeExpirationBucket(currentTime, expirationMs, bucketSizeMs); - } - - // Creates a unique async expiration time. - function computeUniqueAsyncExpiration() { - var currentTime = recalculateCurrentTime(); - var result = computeAsyncExpiration(currentTime); - if (result <= lastUniqueAsyncExpiration) { - // Since we assume the current time monotonically increases, we only hit - // this branch when computeUniqueAsyncExpiration is fired multiple times - // within a 200ms window (or whatever the async bucket size is). - result = lastUniqueAsyncExpiration + 1; - } - lastUniqueAsyncExpiration = result; - return lastUniqueAsyncExpiration; - } - - function computeExpirationForFiber(fiber) { - var expirationTime = void 0; - if (expirationContext !== NoWork) { - // An explicit expiration context was set; - expirationTime = expirationContext; - } else if (isWorking) { - if (isCommitting) { - // Updates that occur during the commit phase should have sync priority - // by default. - expirationTime = Sync; - } else { - // Updates during the render phase should expire at the same time as - // the work that is being rendered. - expirationTime = nextRenderExpirationTime; - } - } else { - // No explicit expiration context was set, and we're not currently - // performing work. Calculate a new expiration time. - if (fiber.mode & AsyncMode) { - if (isBatchingInteractiveUpdates) { - // This is an interactive update - var currentTime = recalculateCurrentTime(); - expirationTime = computeInteractiveExpiration(currentTime); - } else { - // This is an async update - var _currentTime = recalculateCurrentTime(); - expirationTime = computeAsyncExpiration(_currentTime); - } - } else { - // This is a sync update - expirationTime = Sync; - } - } - if (isBatchingInteractiveUpdates) { - // This is an interactive update. Keep track of the lowest pending - // interactive expiration time. This allows us to synchronously flush - // all interactive updates when needed. - if ( - lowestPendingInteractiveExpirationTime === NoWork || - expirationTime > lowestPendingInteractiveExpirationTime - ) { - lowestPendingInteractiveExpirationTime = expirationTime; - } - } - return expirationTime; - } - - function scheduleWork(fiber, expirationTime) { - return scheduleWorkImpl(fiber, expirationTime, false); - } - - function scheduleWorkImpl(fiber, expirationTime, isErrorRecovery) { - recordScheduleUpdate(); - - { - if (!isErrorRecovery && fiber.tag === ClassComponent) { - var instance = fiber.stateNode; - warnAboutInvalidUpdates(instance); - } - } - - var node = fiber; - while (node !== null) { - // Walk the parent path to the root and update each node's - // expiration time. - if ( - node.expirationTime === NoWork || - node.expirationTime > expirationTime - ) { - node.expirationTime = expirationTime; - } - if (node.alternate !== null) { - if ( - node.alternate.expirationTime === NoWork || - node.alternate.expirationTime > expirationTime - ) { - node.alternate.expirationTime = expirationTime; - } - } - if (node["return"] === null) { - if (node.tag === HostRoot) { - var root = node.stateNode; - if ( - !isWorking && - nextRenderExpirationTime !== NoWork && - expirationTime < nextRenderExpirationTime - ) { - // This is an interruption. (Used for performance tracking.) - interruptedBy = fiber; - resetStack(); - } - if ( - // If we're in the render phase, we don't need to schedule this root - // for an update, because we'll do it before we exit... - !isWorking || - isCommitting || - // ...unless this is a different root than the one we're rendering. - nextRoot !== root - ) { - // Add this root to the root schedule. - requestWork(root, expirationTime); - } - if (nestedUpdateCount > NESTED_UPDATE_LIMIT) { - invariant( - false, - "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." - ); - } - } else { - { - if (!isErrorRecovery && fiber.tag === ClassComponent) { - warnAboutUpdateOnUnmounted(fiber); - } - } - return; - } - } - node = node["return"]; - } - } - - function recalculateCurrentTime() { - // Subtract initial time so it fits inside 32bits - mostRecentCurrentTimeMs = now() - originalStartTimeMs; - mostRecentCurrentTime = msToExpirationTime(mostRecentCurrentTimeMs); - return mostRecentCurrentTime; - } - - function deferredUpdates(fn) { - var previousExpirationContext = expirationContext; - var currentTime = recalculateCurrentTime(); - expirationContext = computeAsyncExpiration(currentTime); - try { - return fn(); - } finally { - expirationContext = previousExpirationContext; - } - } - function syncUpdates(fn, a, b, c, d) { - var previousExpirationContext = expirationContext; - expirationContext = Sync; - try { - return fn(a, b, c, d); - } finally { - expirationContext = previousExpirationContext; - } - } - - // TODO: Everything below this is written as if it has been lifted to the - // renderers. I'll do this in a follow-up. - - // Linked-list of roots - var firstScheduledRoot = null; - var lastScheduledRoot = null; - - var callbackExpirationTime = NoWork; - var callbackID = -1; - var isRendering = false; - var nextFlushedRoot = null; - var nextFlushedExpirationTime = NoWork; - var lowestPendingInteractiveExpirationTime = NoWork; - var deadlineDidExpire = false; - var hasUnhandledError = false; - var unhandledError = null; - var deadline = null; - - var isBatchingUpdates = false; - var isUnbatchingUpdates = false; - var isBatchingInteractiveUpdates = false; - - var completedBatches = null; - - // Use these to prevent an infinite loop of nested updates - var NESTED_UPDATE_LIMIT = 1000; - var nestedUpdateCount = 0; - - var timeHeuristicForUnitOfWork = 1; - - function scheduleCallbackWithExpiration(expirationTime) { - if (callbackExpirationTime !== NoWork) { - // A callback is already scheduled. Check its expiration time (timeout). - if (expirationTime > callbackExpirationTime) { - // Existing callback has sufficient timeout. Exit. - return; - } else { - // Existing callback has insufficient timeout. Cancel and schedule a - // new one. - cancelDeferredCallback(callbackID); - } - // The request callback timer is already running. Don't start a new one. - } else { - startRequestCallbackTimer(); - } - - // Compute a timeout for the given expiration time. - var currentMs = now() - originalStartTimeMs; - var expirationMs = expirationTimeToMs(expirationTime); - var timeout = expirationMs - currentMs; - - callbackExpirationTime = expirationTime; - callbackID = scheduleDeferredCallback(performAsyncWork, { - timeout: timeout - }); - } - - // requestWork is called by the scheduler whenever a root receives an update. - // It's up to the renderer to call renderRoot at some point in the future. - function requestWork(root, expirationTime) { - addRootToSchedule(root, expirationTime); - - if (isRendering) { - // Prevent reentrancy. Remaining work will be scheduled at the end of - // the currently rendering batch. - return; - } - - if (isBatchingUpdates) { - // Flush work at the end of the batch. - if (isUnbatchingUpdates) { - // ...unless we're inside unbatchedUpdates, in which case we should - // flush it now. - nextFlushedRoot = root; - nextFlushedExpirationTime = Sync; - performWorkOnRoot(root, Sync, false); - } - return; - } - - // TODO: Get rid of Sync and use current time? - if (expirationTime === Sync) { - performSyncWork(); - } else { - scheduleCallbackWithExpiration(expirationTime); - } - } - - function addRootToSchedule(root, expirationTime) { - // Add the root to the schedule. - // Check if this root is already part of the schedule. - if (root.nextScheduledRoot === null) { - // This root is not already scheduled. Add it. - root.remainingExpirationTime = expirationTime; - if (lastScheduledRoot === null) { - firstScheduledRoot = lastScheduledRoot = root; - root.nextScheduledRoot = root; - } else { - lastScheduledRoot.nextScheduledRoot = root; - lastScheduledRoot = root; - lastScheduledRoot.nextScheduledRoot = firstScheduledRoot; - } - } else { - // This root is already scheduled, but its priority may have increased. - var remainingExpirationTime = root.remainingExpirationTime; - if ( - remainingExpirationTime === NoWork || - expirationTime < remainingExpirationTime - ) { - // Update the priority. - root.remainingExpirationTime = expirationTime; - } - } - } - - function findHighestPriorityRoot() { - var highestPriorityWork = NoWork; - var highestPriorityRoot = null; - if (lastScheduledRoot !== null) { - var previousScheduledRoot = lastScheduledRoot; - var root = firstScheduledRoot; - while (root !== null) { - var remainingExpirationTime = root.remainingExpirationTime; - if (remainingExpirationTime === NoWork) { - // This root no longer has work. Remove it from the scheduler. - - // TODO: This check is redudant, but Flow is confused by the branch - // below where we set lastScheduledRoot to null, even though we break - // from the loop right after. - invariant( - previousScheduledRoot !== null && lastScheduledRoot !== null, - "Should have a previous and last root. This error is likely " + - "caused by a bug in React. Please file an issue." - ); - if (root === root.nextScheduledRoot) { - // This is the only root in the list. - root.nextScheduledRoot = null; - firstScheduledRoot = lastScheduledRoot = null; - break; - } else if (root === firstScheduledRoot) { - // This is the first root in the list. - var next = root.nextScheduledRoot; - firstScheduledRoot = next; - lastScheduledRoot.nextScheduledRoot = next; - root.nextScheduledRoot = null; - } else if (root === lastScheduledRoot) { - // This is the last root in the list. - lastScheduledRoot = previousScheduledRoot; - lastScheduledRoot.nextScheduledRoot = firstScheduledRoot; - root.nextScheduledRoot = null; - break; - } else { - previousScheduledRoot.nextScheduledRoot = root.nextScheduledRoot; - root.nextScheduledRoot = null; - } - root = previousScheduledRoot.nextScheduledRoot; - } else { - if ( - highestPriorityWork === NoWork || - remainingExpirationTime < highestPriorityWork - ) { - // Update the priority, if it's higher - highestPriorityWork = remainingExpirationTime; - highestPriorityRoot = root; - } - if (root === lastScheduledRoot) { - break; - } - previousScheduledRoot = root; - root = root.nextScheduledRoot; - } - } - } - - // If the next root is the same as the previous root, this is a nested - // update. To prevent an infinite loop, increment the nested update count. - var previousFlushedRoot = nextFlushedRoot; - if ( - previousFlushedRoot !== null && - previousFlushedRoot === highestPriorityRoot && - highestPriorityWork === Sync - ) { - nestedUpdateCount++; - } else { - // Reset whenever we switch roots. - nestedUpdateCount = 0; - } - nextFlushedRoot = highestPriorityRoot; - nextFlushedExpirationTime = highestPriorityWork; - } - - function performAsyncWork(dl) { - performWork(NoWork, true, dl); - } - - function performSyncWork() { - performWork(Sync, false, null); - } - - function performWork(minExpirationTime, isAsync, dl) { - deadline = dl; - - // Keep working on roots until there's no more work, or until the we reach - // the deadline. - findHighestPriorityRoot(); - - if (enableUserTimingAPI && deadline !== null) { - var didExpire = nextFlushedExpirationTime < recalculateCurrentTime(); - var timeout = expirationTimeToMs(nextFlushedExpirationTime); - stopRequestCallbackTimer(didExpire, timeout); - } - - if (isAsync) { - while ( - nextFlushedRoot !== null && - nextFlushedExpirationTime !== NoWork && - (minExpirationTime === NoWork || - minExpirationTime >= nextFlushedExpirationTime) && - (!deadlineDidExpire || - recalculateCurrentTime() >= nextFlushedExpirationTime) - ) { - performWorkOnRoot( - nextFlushedRoot, - nextFlushedExpirationTime, - !deadlineDidExpire - ); - findHighestPriorityRoot(); - } - } else { - while ( - nextFlushedRoot !== null && - nextFlushedExpirationTime !== NoWork && - (minExpirationTime === NoWork || - minExpirationTime >= nextFlushedExpirationTime) - ) { - performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime, false); - findHighestPriorityRoot(); - } - } - - // We're done flushing work. Either we ran out of time in this callback, - // or there's no more work left with sufficient priority. - - // If we're inside a callback, set this to false since we just completed it. - if (deadline !== null) { - callbackExpirationTime = NoWork; - callbackID = -1; - } - // If there's work left over, schedule a new callback. - if (nextFlushedExpirationTime !== NoWork) { - scheduleCallbackWithExpiration(nextFlushedExpirationTime); - } - - // Clean-up. - deadline = null; - deadlineDidExpire = false; - - finishRendering(); - } - - function flushRoot(root, expirationTime) { - invariant( - !isRendering, - "work.commit(): Cannot commit while already rendering. This likely " + - "means you attempted to commit from inside a lifecycle method." - ); - // Perform work on root as if the given expiration time is the current time. - // This has the effect of synchronously flushing all work up to and - // including the given time. - nextFlushedRoot = root; - nextFlushedExpirationTime = expirationTime; - performWorkOnRoot(root, expirationTime, false); - // Flush any sync work that was scheduled by lifecycles - performSyncWork(); - finishRendering(); - } - - function finishRendering() { - nestedUpdateCount = 0; - - if (completedBatches !== null) { - var batches = completedBatches; - completedBatches = null; - for (var i = 0; i < batches.length; i++) { - var batch = batches[i]; - try { - batch._onComplete(); - } catch (error) { - if (!hasUnhandledError) { - hasUnhandledError = true; - unhandledError = error; - } - } - } - } - - if (hasUnhandledError) { - var error = unhandledError; - unhandledError = null; - hasUnhandledError = false; - throw error; - } - } - - function performWorkOnRoot(root, expirationTime, isAsync) { - invariant( - !isRendering, - "performWorkOnRoot was called recursively. This error is likely caused " + - "by a bug in React. Please file an issue." - ); - - isRendering = true; - - // Check if this is async work or sync/expired work. - if (!isAsync) { - // Flush sync work. - var finishedWork = root.finishedWork; - if (finishedWork !== null) { - // This root is already complete. We can commit it. - completeRoot(root, finishedWork, expirationTime); - } else { - root.finishedWork = null; - finishedWork = renderRoot(root, expirationTime, false); - if (finishedWork !== null) { - // We've completed the root. Commit it. - completeRoot(root, finishedWork, expirationTime); - } - } - } else { - // Flush async work. - var _finishedWork = root.finishedWork; - if (_finishedWork !== null) { - // This root is already complete. We can commit it. - completeRoot(root, _finishedWork, expirationTime); - } else { - root.finishedWork = null; - _finishedWork = renderRoot(root, expirationTime, true); - if (_finishedWork !== null) { - // We've completed the root. Check the deadline one more time - // before committing. - if (!shouldYield()) { - // Still time left. Commit the root. - completeRoot(root, _finishedWork, expirationTime); - } else { - // There's no time left. Mark this root as complete. We'll come - // back and commit it later. - root.finishedWork = _finishedWork; - } - } - } - } - - isRendering = false; - } - - function completeRoot(root, finishedWork, expirationTime) { - // Check if there's a batch that matches this expiration time. - var firstBatch = root.firstBatch; - if (firstBatch !== null && firstBatch._expirationTime <= expirationTime) { - if (completedBatches === null) { - completedBatches = [firstBatch]; - } else { - completedBatches.push(firstBatch); - } - if (firstBatch._defer) { - // This root is blocked from committing by a batch. Unschedule it until - // we receive another update. - root.finishedWork = finishedWork; - root.remainingExpirationTime = NoWork; - return; - } - } - - // Commit the root. - root.finishedWork = null; - root.remainingExpirationTime = commitRoot(finishedWork); - } - - // When working on async work, the reconciler asks the renderer if it should - // yield execution. For DOM, we implement this with requestIdleCallback. - function shouldYield() { - if (deadline === null) { - return false; - } - if (deadline.timeRemaining() > timeHeuristicForUnitOfWork) { - // Disregard deadline.didTimeout. Only expired work should be flushed - // during a timeout. This path is only hit for non-expired work. - return false; - } - deadlineDidExpire = true; - return true; - } - - function onUncaughtError(error) { - invariant( - nextFlushedRoot !== null, - "Should be working on a root. This error is likely caused by a bug in " + - "React. Please file an issue." - ); - // Unschedule this root so we don't work on it again until there's - // another update. - nextFlushedRoot.remainingExpirationTime = NoWork; - if (!hasUnhandledError) { - hasUnhandledError = true; - unhandledError = error; - } - } - - // TODO: Batching should be implemented at the renderer level, not inside - // the reconciler. - function batchedUpdates(fn, a) { - var previousIsBatchingUpdates = isBatchingUpdates; - isBatchingUpdates = true; - try { - return fn(a); - } finally { - isBatchingUpdates = previousIsBatchingUpdates; - if (!isBatchingUpdates && !isRendering) { - performSyncWork(); - } - } - } - - // TODO: Batching should be implemented at the renderer level, not inside - // the reconciler. - function unbatchedUpdates(fn, a) { - if (isBatchingUpdates && !isUnbatchingUpdates) { - isUnbatchingUpdates = true; - try { - return fn(a); - } finally { - isUnbatchingUpdates = false; - } - } - return fn(a); - } - - // TODO: Batching should be implemented at the renderer level, not within - // the reconciler. - function flushSync(fn, a) { - invariant( - !isRendering, - "flushSync was called from inside a lifecycle method. It cannot be " + - "called when React is already rendering." - ); - var previousIsBatchingUpdates = isBatchingUpdates; - isBatchingUpdates = true; - try { - return syncUpdates(fn, a); - } finally { - isBatchingUpdates = previousIsBatchingUpdates; - performSyncWork(); - } - } - - function interactiveUpdates(fn, a, b) { - if (isBatchingInteractiveUpdates) { - return fn(a, b); - } - // If there are any pending interactive updates, synchronously flush them. - // This needs to happen before we read any handlers, because the effect of - // the previous event may influence which handlers are called during - // this event. - if ( - !isBatchingUpdates && - !isRendering && - lowestPendingInteractiveExpirationTime !== NoWork - ) { - // Synchronously flush pending interactive updates. - performWork(lowestPendingInteractiveExpirationTime, false, null); - lowestPendingInteractiveExpirationTime = NoWork; - } - var previousIsBatchingInteractiveUpdates = isBatchingInteractiveUpdates; - var previousIsBatchingUpdates = isBatchingUpdates; - isBatchingInteractiveUpdates = true; - isBatchingUpdates = true; - try { - return fn(a, b); - } finally { - isBatchingInteractiveUpdates = previousIsBatchingInteractiveUpdates; - isBatchingUpdates = previousIsBatchingUpdates; - if (!isBatchingUpdates && !isRendering) { - performSyncWork(); - } - } - } - - function flushInteractiveUpdates() { - if (!isRendering && lowestPendingInteractiveExpirationTime !== NoWork) { - // Synchronously flush pending interactive updates. - performWork(lowestPendingInteractiveExpirationTime, false, null); - lowestPendingInteractiveExpirationTime = NoWork; - } - } - - function flushControlled(fn) { - var previousIsBatchingUpdates = isBatchingUpdates; - isBatchingUpdates = true; - try { - syncUpdates(fn); - } finally { - isBatchingUpdates = previousIsBatchingUpdates; - if (!isBatchingUpdates && !isRendering) { - performWork(Sync, false, null); - } - } - } - - return { - recalculateCurrentTime: recalculateCurrentTime, - computeExpirationForFiber: computeExpirationForFiber, - scheduleWork: scheduleWork, - requestWork: requestWork, - flushRoot: flushRoot, - batchedUpdates: batchedUpdates, - unbatchedUpdates: unbatchedUpdates, - flushSync: flushSync, - flushControlled: flushControlled, - deferredUpdates: deferredUpdates, - syncUpdates: syncUpdates, - interactiveUpdates: interactiveUpdates, - flushInteractiveUpdates: flushInteractiveUpdates, - computeUniqueAsyncExpiration: computeUniqueAsyncExpiration, - legacyContext: legacyContext - }; -}; - -var didWarnAboutNestedUpdates = void 0; - -{ - didWarnAboutNestedUpdates = false; -} - -// 0 is PROD, 1 is DEV. -// Might add PROFILE later. - -var ReactFiberReconciler$1 = function(config) { - var getPublicInstance = config.getPublicInstance; - - var _ReactFiberScheduler = ReactFiberScheduler(config), - computeUniqueAsyncExpiration = - _ReactFiberScheduler.computeUniqueAsyncExpiration, - recalculateCurrentTime = _ReactFiberScheduler.recalculateCurrentTime, - computeExpirationForFiber = _ReactFiberScheduler.computeExpirationForFiber, - scheduleWork = _ReactFiberScheduler.scheduleWork, - requestWork = _ReactFiberScheduler.requestWork, - flushRoot = _ReactFiberScheduler.flushRoot, - batchedUpdates = _ReactFiberScheduler.batchedUpdates, - unbatchedUpdates = _ReactFiberScheduler.unbatchedUpdates, - flushSync = _ReactFiberScheduler.flushSync, - flushControlled = _ReactFiberScheduler.flushControlled, - deferredUpdates = _ReactFiberScheduler.deferredUpdates, - syncUpdates = _ReactFiberScheduler.syncUpdates, - interactiveUpdates = _ReactFiberScheduler.interactiveUpdates, - flushInteractiveUpdates = _ReactFiberScheduler.flushInteractiveUpdates, - legacyContext = _ReactFiberScheduler.legacyContext; - - var findCurrentUnmaskedContext = legacyContext.findCurrentUnmaskedContext, - isContextProvider = legacyContext.isContextProvider, - processChildContext = legacyContext.processChildContext; - - function getContextForSubtree(parentComponent) { - if (!parentComponent) { - return emptyObject; - } - - var fiber = get$1(parentComponent); - var parentContext = findCurrentUnmaskedContext(fiber); - return isContextProvider(fiber) - ? processChildContext(fiber, parentContext) - : parentContext; - } - - function scheduleRootUpdate( - current, - element, - currentTime, - expirationTime, - callback - ) { - { - if ( - ReactDebugCurrentFiber.phase === "render" && - ReactDebugCurrentFiber.current !== null && - !didWarnAboutNestedUpdates - ) { - didWarnAboutNestedUpdates = true; - warning( - 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(ReactDebugCurrentFiber.current) || "Unknown" - ); - } - } - - callback = callback === undefined ? null : callback; - { - !(callback === null || typeof callback === "function") - ? warning( - false, - "render(...): Expected the last optional `callback` argument to be a " + - "function. Instead received: %s.", - callback - ) - : void 0; - } - - var update = { - expirationTime: expirationTime, - partialState: { element: element }, - callback: callback, - isReplace: false, - isForced: false, - capturedValue: null, - next: null - }; - insertUpdateIntoFiber(current, update); - scheduleWork(current, expirationTime); - - return expirationTime; - } - - function updateContainerAtExpirationTime( - element, - container, - parentComponent, - currentTime, - expirationTime, - callback - ) { - // TODO: If this is a nested container, this won't be the root. - var current = container.current; - - { - if (ReactFiberInstrumentation_1.debugTool) { - if (current.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, - element, - currentTime, - expirationTime, - callback - ); - } - - function findHostInstance(component) { - var fiber = get$1(component); - if (fiber === undefined) { - if (typeof component.render === "function") { - invariant(false, "Unable to find node on an unmounted component."); - } else { - invariant( - false, - "Argument appears to not be a ReactComponent. Keys: %s", - Object.keys(component) - ); - } - } - var hostFiber = findCurrentHostFiber(fiber); - if (hostFiber === null) { - return null; - } - return hostFiber.stateNode; - } - - return { - createContainer: function(containerInfo, isAsync, hydrate) { - return createFiberRoot(containerInfo, isAsync, hydrate); - }, - updateContainer: function(element, container, parentComponent, callback) { - var current = container.current; - var currentTime = recalculateCurrentTime(); - var expirationTime = computeExpirationForFiber(current); - return updateContainerAtExpirationTime( - element, - container, - parentComponent, - currentTime, - expirationTime, - callback - ); - }, - updateContainerAtExpirationTime: function( - element, - container, - parentComponent, - expirationTime, - callback - ) { - var currentTime = recalculateCurrentTime(); - return updateContainerAtExpirationTime( - element, - container, - parentComponent, - currentTime, - expirationTime, - callback - ); - }, - - flushRoot: flushRoot, - - requestWork: requestWork, - - computeUniqueAsyncExpiration: computeUniqueAsyncExpiration, - - batchedUpdates: batchedUpdates, - - unbatchedUpdates: unbatchedUpdates, - - deferredUpdates: deferredUpdates, - - syncUpdates: syncUpdates, - - interactiveUpdates: interactiveUpdates, - - flushInteractiveUpdates: flushInteractiveUpdates, - - flushControlled: flushControlled, - - flushSync: flushSync, - - getPublicRootInstance: function(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; - } - }, - - findHostInstance: findHostInstance, - - findHostInstanceWithNoPortals: function(fiber) { - var hostFiber = findCurrentHostFiberWithNoPortals(fiber); - if (hostFiber === null) { - return null; - } - return hostFiber.stateNode; - }, - injectIntoDevTools: function(devToolsConfig) { - var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; - - return injectInternals( - Object.assign({}, devToolsConfig, { - 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); - } - }) - ); - } - }; -}; - -var ReactFiberReconciler$2 = Object.freeze({ - default: ReactFiberReconciler$1 -}); - -var ReactFiberReconciler$3 = - (ReactFiberReconciler$2 && ReactFiberReconciler$1) || ReactFiberReconciler$2; - -// TODO: bundle Flow types with the package. - -// TODO: decide on the top-level export form. -// This is hacky but makes it work with both Rollup and Jest. -var reactReconciler = ReactFiberReconciler$3["default"] - ? ReactFiberReconciler$3["default"] - : ReactFiberReconciler$3; - -function _classCallCheck$1(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$1(this, ReactNativeFiberHostComponent); - - this._nativeTag = tag; - this._children = []; - this.viewConfig = viewConfig; - } - - ReactNativeFiberHostComponent.prototype.blur = function blur() { - TextInputState.blurTextInput(this._nativeTag); - }; - - ReactNativeFiberHostComponent.prototype.focus = function focus() { - TextInputState.focusTextInput(this._nativeTag); - }; - - ReactNativeFiberHostComponent.prototype.measure = function measure(callback) { - UIManager.measure(this._nativeTag, mountSafeCallback(this, callback)); - }; - - ReactNativeFiberHostComponent.prototype.measureInWindow = function measureInWindow( - callback - ) { - UIManager.measureInWindow( - this._nativeTag, - mountSafeCallback(this, callback) - ); - }; - - ReactNativeFiberHostComponent.prototype.measureLayout = function measureLayout( - relativeToNativeNode, - onSuccess, - onFail /* currently unused */ - ) { - UIManager.measureLayout( - this._nativeTag, - relativeToNativeNode, - mountSafeCallback(this, onFail), - mountSafeCallback(this, onSuccess) - ); - }; - - ReactNativeFiberHostComponent.prototype.setNativeProps = function setNativeProps( - nativeProps - ) { - { - 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) { - UIManager.updateView( - this._nativeTag, - this.viewConfig.uiViewClassName, - updatePayload - ); - } - }; - - return ReactNativeFiberHostComponent; -})(); - -var hasNativePerformanceNow = - typeof performance === "object" && typeof performance.now === "function"; - -var now = hasNativePerformanceNow - ? function() { - return performance.now(); - } - : function() { - return Date.now(); - }; - -var scheduledCallback = null; -var frameDeadline = 0; - -var frameDeadlineObject = { - timeRemaining: function() { - return frameDeadline - now(); - }, - didTimeout: false -}; - -function setTimeoutCallback() { - // TODO (bvaughn) Hard-coded 5ms unblocks initial async testing. - // React API probably changing to boolean rather than time remaining. - // Longer-term plan is to rewrite this using shared memory, - // And just return the value of the bit as the boolean. - frameDeadline = now() + 5; - - var callback = scheduledCallback; - scheduledCallback = null; - if (callback !== null) { - callback(frameDeadlineObject); - } -} - -// RN has a poor polyfill for requestIdleCallback so we aren't using it. -// This implementation is only intended for short-term use anyway. -// We also don't implement cancel functionality b'c Fiber doesn't currently need it. -function scheduleDeferredCallback(callback) { - // We assume only one callback is scheduled at a time b'c that's how Fiber works. - scheduledCallback = callback; - return setTimeout(setTimeoutCallback, 1); -} - -function cancelDeferredCallback(callbackID) { - scheduledCallback = null; - clearTimeout(callbackID); -} - -// Modules provided by RN: -// 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); - } -} - -var NativeRenderer = reactReconciler({ - appendInitialChild: function(parentInstance, child) { - parentInstance._children.push(child); - }, - createInstance: function( - type, - props, - rootContainerInstance, - hostContext, - internalInstanceHandle - ) { - var tag = allocateTag(); - var viewConfig = ReactNativeViewConfigRegistry.get(type); - - { - for (var key in viewConfig.validAttributes) { - if (props.hasOwnProperty(key)) { - deepFreezeAndThrowOnMutationInDev(props[key]); - } - } - } - - var updatePayload = create(props, viewConfig.validAttributes); - - UIManager.createView( - tag, // reactTag - viewConfig.uiViewClassName, // viewName - rootContainerInstance, // rootTag - updatePayload - ); - - 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; - }, - createTextInstance: function( - text, - rootContainerInstance, - hostContext, - internalInstanceHandle - ) { - var tag = allocateTag(); - - UIManager.createView( - tag, // reactTag - "RCTRawText", // viewName - rootContainerInstance, // rootTag - { text: text } - ); - - precacheFiberNode(internalInstanceHandle, tag); - - return tag; - }, - finalizeInitialChildren: function( - parentInstance, - type, - props, - rootContainerInstance - ) { - // 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; - }); - - UIManager.setChildren( - parentInstance._nativeTag, // containerTag - nativeTags - ); - - return false; - }, - getRootHostContext: function() { - return emptyObject; - }, - getChildHostContext: function() { - return emptyObject; - }, - getPublicInstance: function(instance) { - return instance; - }, - - now: now, - - prepareForCommit: function() { - // Noop - }, - prepareUpdate: function( - instance, - type, - oldProps, - newProps, - rootContainerInstance, - hostContext - ) { - return emptyObject; - }, - resetAfterCommit: function() { - // Noop - }, - - scheduleDeferredCallback: scheduleDeferredCallback, - cancelDeferredCallback: cancelDeferredCallback, - - shouldDeprioritizeSubtree: function(type, props) { - return false; - }, - shouldSetTextContent: function(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: { - appendChild: function(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); - - UIManager.manageChildren( - parentInstance._nativeTag, // containerTag - [index], // moveFromIndices - [children.length - 1], // moveToIndices - [], // addChildReactTags - [], // addAtIndices - [] - ); - } else { - children.push(child); - - UIManager.manageChildren( - parentInstance._nativeTag, // containerTag - [], // moveFromIndices - [], // moveToIndices - [childTag], // addChildReactTags - [children.length - 1], // addAtIndices - [] - ); - } - }, - appendChildToContainer: function(parentInstance, child) { - var childTag = typeof child === "number" ? child : child._nativeTag; - UIManager.setChildren( - parentInstance, // containerTag - [childTag] - ); - }, - commitTextUpdate: function(textInstance, oldText, newText) { - UIManager.updateView( - textInstance, // reactTag - "RCTRawText", // viewName - { text: newText } - ); - }, - commitMount: function(instance, type, newProps, internalInstanceHandle) { - // Noop - }, - commitUpdate: function( - 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) { - UIManager.updateView( - instance._nativeTag, // reactTag - viewConfig.uiViewClassName, // viewName - updatePayload - ); - } - }, - insertBefore: function(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); - - UIManager.manageChildren( - parentInstance._nativeTag, // containerID - [index], // moveFromIndices - [beforeChildIndex], // moveToIndices - [], // addChildReactTags - [], // addAtIndices - [] - ); - } else { - var _beforeChildIndex = children.indexOf(beforeChild); - children.splice(_beforeChildIndex, 0, child); - - var childTag = typeof child === "number" ? child : child._nativeTag; - - UIManager.manageChildren( - parentInstance._nativeTag, // containerID - [], // moveFromIndices - [], // moveToIndices - [childTag], // addChildReactTags - [_beforeChildIndex], // addAtIndices - [] - ); - } - }, - insertInContainerBefore: function(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. - invariant( - typeof parentInstance !== "number", - "Container does not support insertBefore operation" - ); - }, - removeChild: function(parentInstance, child) { - recursivelyUncacheFiberNode(child); - var children = parentInstance._children; - var index = children.indexOf(child); - - children.splice(index, 1); - - UIManager.manageChildren( - parentInstance._nativeTag, // containerID - [], // moveFromIndices - [], // moveToIndices - [], // addChildReactTags - [], // addAtIndices - [index] - ); - }, - removeChildFromContainer: function(parentInstance, child) { - recursivelyUncacheFiberNode(child); - UIManager.manageChildren( - parentInstance, // containerID - [], // moveFromIndices - [], // moveToIndices - [], // addChildReactTags - [], // addAtIndices - [0] - ); - }, - resetTextContent: function(instance) { - // Noop - } - } -}); - -// Module provided by RN: -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; - } - return emptyObject; - }; - - 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), - getInspectorData: function(findNodeHandle) { - return { - measure: function(callback) { - return 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, - 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: -var findHostInstance = NativeRenderer.findHostInstance; - -function findNodeHandle(componentOrHandle) { - { - var owner = ReactCurrentOwner.current; - if (owner !== null && owner.stateNode !== null) { - !owner.stateNode._warnedAboutRefsInRender - ? warning( - 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) || "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 = findHostInstance(componentOrHandle); - if (hostInstance == null) { - return hostInstance; - } - if (hostInstance.canonical) { - // Fabric - return hostInstance.canonical._nativeTag; - } - return hostInstance._nativeTag; -} - -injection$2.injectRenderer(NativeRenderer); - -function computeComponentStackForErrorReporting(reactTag) { - var fiber = getInstanceFromTag(reactTag); - if (!fiber) { - return ""; - } - return getStackAddendumByWorkInProgressFiber(fiber); -} - -var roots = new Map(); - -var ReactNativeRenderer = { - NativeComponent: ReactNativeComponent(findNodeHandle, findHostInstance), - - findNodeHandle: findNodeHandle, - - 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 = NativeRenderer.createContainer(containerTag, false, false); - roots.set(containerTag, root); - } - NativeRenderer.updateContainer(element, root, null, callback); - - return NativeRenderer.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? - NativeRenderer.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 - 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), - // Used by react-native-github/Libraries/ components - ReactNativeComponentTree: ReactNativeComponentTree, // ScrollResponder - computeComponentStackForErrorReporting: computeComponentStackForErrorReporting - } -}; - -{ - // $FlowFixMe - Object.assign( - ReactNativeRenderer.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, - { - // TODO: none of these work since Fiber. Remove these dependencies. - // Used by RCTRenderingPerf, Systrace: - ReactDebugTool: { - addHook: function() {}, - removeHook: function() {} - }, - // Used by ReactPerfStallHandler, RCTRenderingPerf: - ReactPerf: { - start: function() {}, - stop: function() {}, - printInclusive: function() {}, - printWasted: function() {} - } - } - ); -} - -NativeRenderer.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["default"] - : ReactNativeRenderer$3; - -module.exports = reactNativeRenderer; - - })(); -} diff --git a/Libraries/Renderer/fb/ReactNativeRenderer-prod.js b/Libraries/Renderer/fb/ReactNativeRenderer-prod.js deleted file mode 100644 index 08b70c789b54dd..00000000000000 --- a/Libraries/Renderer/fb/ReactNativeRenderer-prod.js +++ /dev/null @@ -1,6395 +0,0 @@ -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @noflow - * @preventMunge - */ - -"use strict"; -require("InitializeCore"); -var invariant = require("fbjs/lib/invariant"), - emptyFunction = require("fbjs/lib/emptyFunction"), - ReactNativeViewConfigRegistry = require("ReactNativeViewConfigRegistry"), - UIManager = require("UIManager"), - RCTEventEmitter = require("RCTEventEmitter"), - TextInputState = require("TextInputState"), - deepDiffer = require("deepDiffer"), - flattenStyle = require("flattenStyle"), - React = require("react"), - emptyObject = require("fbjs/lib/emptyObject"), - shallowEqual = require("fbjs/lib/shallowEqual"), - ExceptionsManager = require("ExceptionsManager"); -function invokeGuardedCallback(name, func, context, a, b, c, d, e, f) { - this._hasCaughtError = !1; - this._caughtError = null; - var funcArgs = Array.prototype.slice.call(arguments, 3); - try { - func.apply(context, funcArgs); - } catch (error) { - (this._caughtError = error), (this._hasCaughtError = !0); - } -} -var ReactErrorUtils = { - _caughtError: null, - _hasCaughtError: !1, - _rethrowError: null, - _hasRethrowError: !1, - invokeGuardedCallback: function(name, func, context, a, b, c, d, e, f) { - invokeGuardedCallback.apply(ReactErrorUtils, arguments); - }, - invokeGuardedCallbackAndCatchFirstError: function( - name, - func, - context, - a, - b, - c, - d, - e, - f - ) { - ReactErrorUtils.invokeGuardedCallback.apply(this, arguments); - if (ReactErrorUtils.hasCaughtError()) { - var error = ReactErrorUtils.clearCaughtError(); - ReactErrorUtils._hasRethrowError || - ((ReactErrorUtils._hasRethrowError = !0), - (ReactErrorUtils._rethrowError = error)); - } - }, - rethrowCaughtError: function() { - return rethrowCaughtError.apply(ReactErrorUtils, arguments); - }, - hasCaughtError: function() { - return ReactErrorUtils._hasCaughtError; - }, - clearCaughtError: function() { - if (ReactErrorUtils._hasCaughtError) { - var error = ReactErrorUtils._caughtError; - ReactErrorUtils._caughtError = null; - ReactErrorUtils._hasCaughtError = !1; - return error; - } - invariant( - !1, - "clearCaughtError was called but no error was captured. This error is likely caused by a bug in React. Please file an issue." - ); - } -}; -function rethrowCaughtError() { - if (ReactErrorUtils._hasRethrowError) { - var error = ReactErrorUtils._rethrowError; - ReactErrorUtils._rethrowError = null; - ReactErrorUtils._hasRethrowError = !1; - throw error; - } -} -var eventPluginOrder = null, - namesToPlugins = {}; -function recomputePluginOrdering() { - if (eventPluginOrder) - for (var pluginName in namesToPlugins) { - var pluginModule = namesToPlugins[pluginName], - pluginIndex = eventPluginOrder.indexOf(pluginName); - invariant( - -1 < pluginIndex, - "EventPluginRegistry: Cannot inject event plugins that do not exist in the plugin ordering, `%s`.", - pluginName - ); - if (!plugins[pluginIndex]) { - invariant( - pluginModule.extractEvents, - "EventPluginRegistry: Event plugins must implement an `extractEvents` method, but `%s` does not.", - pluginName - ); - 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; - invariant( - !eventNameDispatchConfigs.hasOwnProperty(eventName$jscomp$0), - "EventPluginHub: More than one plugin attempted to publish the same event name, `%s`.", - 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); - invariant( - JSCompiler_inline_result, - "EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.", - eventName, - pluginName - ); - } - } - } -} -function publishRegistrationName(registrationName, pluginModule) { - invariant( - !registrationNameModules[registrationName], - "EventPluginHub: More than one plugin attempted to publish the same registration name, `%s`.", - registrationName - ); - registrationNameModules[registrationName] = pluginModule; -} -var plugins = [], - eventNameDispatchConfigs = {}, - registrationNameModules = {}, - getFiberCurrentPropsFromNode = null, - getInstanceFromNode = null, - getNodeFromInstance = null; -function isEndish(topLevelType) { - return ( - "topMouseUp" === topLevelType || - "topTouchEnd" === topLevelType || - "topTouchCancel" === topLevelType - ); -} -function isMoveish(topLevelType) { - return "topMouseMove" === topLevelType || "topTouchMove" === topLevelType; -} -function isStartish(topLevelType) { - return "topMouseDown" === topLevelType || "topTouchStart" === topLevelType; -} -function executeDispatch(event, simulated, listener, inst) { - simulated = event.type || "unknown-event"; - event.currentTarget = getNodeFromInstance(inst); - ReactErrorUtils.invokeGuardedCallbackAndCatchFirstError( - simulated, - listener, - void 0, - event - ); - event.currentTarget = null; -} -function executeDirectDispatch(event) { - var dispatchListener = event._dispatchListeners, - dispatchInstance = event._dispatchInstances; - invariant( - !Array.isArray(dispatchListener), - "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) { - invariant( - null != next, - "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, !1, dispatchListeners[i], dispatchInstances[i]); - else - dispatchListeners && - executeDispatch(e, !1, dispatchListeners, dispatchInstances); - e._dispatchListeners = null; - e._dispatchInstances = null; - e.isPersistent() || e.constructor.release(e); - } -} -var injection = { - injectEventPluginOrder: function(injectedEventPluginOrder) { - invariant( - !eventPluginOrder, - "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]; - (namesToPlugins.hasOwnProperty(pluginName) && - namesToPlugins[pluginName] === pluginModule) || - (invariant( - !namesToPlugins[pluginName], - "EventPluginRegistry: Cannot inject two different event plugins using the same name, `%s`.", - 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; - invariant( - !listener || "function" === typeof listener, - "Expected `%s` listener to be a function, instead got a value of `%s` type.", - registrationName, - typeof listener - ); - 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 - ))); - } - } -} -var shouldBeReleasedProperties = "dispatchConfig _targetInst nativeEvent isDefaultPrevented isPropagationStopped _dispatchListeners _dispatchInstances".split( - " " - ), - EventInterface = { - type: null, - target: null, - currentTarget: emptyFunction.thatReturnsNull, - eventPhase: null, - bubbles: null, - cancelable: null, - timeStamp: function(event) { - return event.timeStamp || Date.now(); - }, - defaultPrevented: null, - isTrusted: null - }; -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) - ? emptyFunction.thatReturnsTrue - : emptyFunction.thatReturnsFalse; - this.isPropagationStopped = emptyFunction.thatReturnsFalse; - 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 = emptyFunction.thatReturnsTrue)); - }, - stopPropagation: function() { - var event = this.nativeEvent; - event && - (event.stopPropagation - ? event.stopPropagation() - : "unknown" !== typeof event.cancelBubble && (event.cancelBubble = !0), - (this.isPropagationStopped = emptyFunction.thatReturnsTrue)); - }, - persist: function() { - this.isPersistent = emptyFunction.thatReturnsTrue; - }, - isPersistent: emptyFunction.thatReturnsFalse, - destructor: function() { - var Interface = this.constructor.Interface, - propName; - for (propName in Interface) this[propName] = null; - for ( - Interface = 0; - Interface < shouldBeReleasedProperties.length; - Interface++ - ) - this[shouldBeReleasedProperties[Interface]] = null; - } -}); -SyntheticEvent.Interface = EventInterface; -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) { - invariant( - event instanceof this, - "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; - } - }), - touchBank = [], - touchHistory = { - touchBank: touchBank, - numberActiveTouches: 0, - indexOfSingleActiveTouch: -1, - mostRecentTimeStamp: 0 - }; -function timestampForTouch(touch) { - return touch.timeStamp || touch.timestamp; -} -function getTouchIdentifier(_ref) { - _ref = _ref.identifier; - invariant(null != _ref, "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 ( - isEndish(topLevelType) && - (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) { - invariant( - null != next, - "accumulate(...): Accumulated items must be 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, - previousActiveTouches = 0; -function changeResponder(nextResponderInst, blockHostResponder) { - var oldResponderInst = responderInst; - responderInst = nextResponderInst; - if (null !== ResponderEventPlugin.GlobalResponderHandler) - ResponderEventPlugin.GlobalResponderHandler.onChange( - oldResponderInst, - nextResponderInst, - blockHostResponder - ); -} -var eventTypes$1 = { - startShouldSetResponder: { - phasedRegistrationNames: { - bubbled: "onStartShouldSetResponder", - captured: "onStartShouldSetResponderCapture" - } - }, - scrollShouldSetResponder: { - phasedRegistrationNames: { - bubbled: "onScrollShouldSetResponder", - captured: "onScrollShouldSetResponderCapture" - } - }, - selectionChangeShouldSetResponder: { - phasedRegistrationNames: { - bubbled: "onSelectionChangeShouldSetResponder", - captured: "onSelectionChangeShouldSetResponderCapture" - } - }, - moveShouldSetResponder: { - phasedRegistrationNames: { - bubbled: "onMoveShouldSetResponder", - captured: "onMoveShouldSetResponderCapture" - } - }, - responderStart: { registrationName: "onResponderStart" }, - responderMove: { registrationName: "onResponderMove" }, - responderEnd: { registrationName: "onResponderEnd" }, - responderRelease: { registrationName: "onResponderRelease" }, - responderTerminationRequest: { - registrationName: "onResponderTerminationRequest" - }, - responderGrant: { registrationName: "onResponderGrant" }, - responderReject: { registrationName: "onResponderReject" }, - responderTerminate: { registrationName: "onResponderTerminate" } - }, - ResponderEventPlugin = { - _getResponder: function() { - return responderInst; - }, - eventTypes: eventTypes$1, - extractEvents: function( - topLevelType, - targetInst, - nativeEvent, - nativeEventTarget - ) { - if (isStartish(topLevelType)) trackedTouchCount += 1; - else if (isEndish(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$1.startShouldSetResponder - : isMoveish(topLevelType) - ? eventTypes$1.moveShouldSetResponder - : "topSelectionChange" === topLevelType - ? eventTypes$1.selectionChangeShouldSetResponder - : eventTypes$1.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$1.responderGrant, - JSCompiler_temp, - nativeEvent, - nativeEventTarget - )), - (targetInst.touchHistory = ResponderTouchHistoryStore.touchHistory), - forEachAccumulated(targetInst, accumulateDirectDispatchesSingle), - (depthA = !0 === executeDirectDispatch(targetInst)), - responderInst - ? ((tempA = ResponderSyntheticEvent.getPooled( - eventTypes$1.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$1.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$1.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 && isEndish(topLevelType); - if ( - (JSCompiler_temp$jscomp$0 = JSCompiler_temp$jscomp$0 - ? eventTypes$1.responderStart - : targetInst - ? eventTypes$1.responderMove - : depthA ? eventTypes$1.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 && isEndish(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$1.responderTerminate - : topLevelType ? eventTypes$1.responderRelease : null) - ) - (nativeEvent = ResponderSyntheticEvent.getPooled( - topLevelType, - responderInst, - nativeEvent, - nativeEventTarget - )), - (nativeEvent.touchHistory = ResponderTouchHistoryStore.touchHistory), - forEachAccumulated(nativeEvent, accumulateDirectDispatchesSingle), - (JSCompiler_temp = accumulate(JSCompiler_temp, nativeEvent)), - changeResponder(null); - nativeEvent = ResponderTouchHistoryStore.touchHistory.numberActiveTouches; - if ( - ResponderEventPlugin.GlobalInteractionHandler && - nativeEvent !== previousActiveTouches - ) - ResponderEventPlugin.GlobalInteractionHandler.onChange(nativeEvent); - previousActiveTouches = nativeEvent; - return JSCompiler_temp; - }, - GlobalResponderHandler: null, - GlobalInteractionHandler: null, - injection: { - injectGlobalResponderHandler: function(GlobalResponderHandler) { - ResponderEventPlugin.GlobalResponderHandler = GlobalResponderHandler; - }, - injectGlobalInteractionHandler: function(GlobalInteractionHandler) { - ResponderEventPlugin.GlobalInteractionHandler = GlobalInteractionHandler; - } - } - }, - customBubblingEventTypes$1 = - ReactNativeViewConfigRegistry.customBubblingEventTypes, - customDirectEventTypes$1 = - ReactNativeViewConfigRegistry.customDirectEventTypes, - ReactNativeBridgeEventPlugin = { - eventTypes: ReactNativeViewConfigRegistry.eventTypes, - extractEvents: function( - topLevelType, - targetInst, - nativeEvent, - nativeEventTarget - ) { - if (null == targetInst) return null; - var bubbleDispatchConfig = customBubblingEventTypes$1[topLevelType], - directDispatchConfig = customDirectEventTypes$1[topLevelType]; - invariant( - bubbleDispatchConfig || directDispatchConfig, - 'Unsupported top level event type "%s" dispatched', - topLevelType - ); - topLevelType = SyntheticEvent.getPooled( - bubbleDispatchConfig || directDispatchConfig, - targetInst, - nativeEvent, - nativeEventTarget - ); - if (bubbleDispatchConfig) - forEachAccumulated(topLevelType, accumulateTwoPhaseDispatchesSingle); - else if (directDispatchConfig) - forEachAccumulated(topLevelType, accumulateDirectDispatchesSingle); - else return null; - return topLevelType; - } - }, - instanceCache = {}, - instanceProps = {}; -function uncacheFiberNode(tag) { - delete instanceCache[tag]; - delete instanceProps[tag]; -} -function getInstanceFromTag(tag) { - return "number" === typeof tag ? instanceCache[tag] || null : tag; -} -var ReactNativeComponentTree = Object.freeze({ - precacheFiberNode: function(hostInst, tag) { - instanceCache[tag] = hostInst; - }, - uncacheFiberNode: uncacheFiberNode, - getClosestInstanceFromNode: getInstanceFromTag, - getInstanceFromNode: getInstanceFromTag, - getNodeFromInstance: function(inst) { - var tag = inst.stateNode._nativeTag; - void 0 === tag && (tag = inst.stateNode.canonical._nativeTag); - invariant(tag, "All native instances should have a tag."); - return tag; - }, - getFiberCurrentPropsFromNode: function(stateNode) { - return instanceProps[stateNode._nativeTag] || null; - }, - updateFiberProps: function(tag, props) { - instanceProps[tag] = props; - } -}); -injection.injectEventPluginOrder([ - "ResponderEventPlugin", - "ReactNativeBridgeEventPlugin" -]); -getFiberCurrentPropsFromNode = - ReactNativeComponentTree.getFiberCurrentPropsFromNode; -getInstanceFromNode = ReactNativeComponentTree.getInstanceFromNode; -getNodeFromInstance = ReactNativeComponentTree.getNodeFromInstance; -ResponderEventPlugin.injection.injectGlobalResponderHandler({ - onChange: function(from, to, blockNativeResponder) { - null !== to - ? UIManager.setJSResponder(to.stateNode._nativeTag, blockNativeResponder) - : UIManager.clearJSResponder(); - } -}); -injection.injectEventPluginsByName({ - ResponderEventPlugin: ResponderEventPlugin, - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin -}); -var restoreTarget = null, - restoreQueue = null; -function restoreStateOfTarget(target) { - if ((target = getInstanceFromNode(target))) { - invariant( - null, - "Fiber needs to be injected to handle a fiber target for controlled events. This error is likely caused by a bug in React. Please file an issue." - ); - var props = getFiberCurrentPropsFromNode(target.stateNode); - null.restoreControlledState(target.stateNode, target.type, props); - } -} -function _batchedUpdates(fn, bookkeeping) { - return fn(bookkeeping); -} -function _flushInteractiveUpdates() {} -var isBatching = !1; -function batchedUpdates(fn, bookkeeping) { - if (isBatching) return fn(bookkeeping); - isBatching = !0; - try { - return _batchedUpdates(fn, bookkeeping); - } finally { - if (((isBatching = !1), null !== restoreTarget || null !== restoreQueue)) - if ( - (_flushInteractiveUpdates(), - 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; - events && - (forEachAccumulated(events, executeDispatchesAndReleaseTopLevel), - invariant( - !eventQueue, - "processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented." - ), - ReactErrorUtils.rethrowCaughtError()); - }); -} -var ReactNativeEventEmitter = Object.freeze({ - getListener: getListener, - registrationNames: registrationNameModules, - _receiveRootNodeIDEvent: _receiveRootNodeIDEvent, - 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); - } - } -}); -RCTEventEmitter.register(ReactNativeEventEmitter); -var hasSymbol = "function" === typeof Symbol && Symbol["for"], - REACT_ELEMENT_TYPE = hasSymbol ? Symbol["for"]("react.element") : 60103, - REACT_CALL_TYPE = hasSymbol ? Symbol["for"]("react.call") : 60104, - REACT_RETURN_TYPE = hasSymbol ? Symbol["for"]("react.return") : 60105, - 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_PROVIDER_TYPE = hasSymbol ? Symbol["for"]("react.provider") : 60109, - REACT_CONTEXT_TYPE = hasSymbol ? Symbol["for"]("react.context") : 60110, - REACT_ASYNC_MODE_TYPE = hasSymbol ? Symbol["for"]("react.async_mode") : 60111, - REACT_FORWARD_REF_TYPE = hasSymbol - ? Symbol["for"]("react.forward_ref") - : 60112, - MAYBE_ITERATOR_SYMBOL = "function" === typeof Symbol && Symbol.iterator; -function getIteratorFn(maybeIterable) { - if (null === maybeIterable || "undefined" === typeof maybeIterable) - return null; - maybeIterable = - (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || - maybeIterable["@@iterator"]; - return "function" === typeof maybeIterable ? maybeIterable : null; -} -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 getComponentName(fiber) { - fiber = fiber.type; - if ("function" === typeof fiber) return fiber.displayName || fiber.name; - if ("string" === typeof fiber) return fiber; - switch (fiber) { - case REACT_FRAGMENT_TYPE: - return "ReactFragment"; - case REACT_PORTAL_TYPE: - return "ReactPortal"; - case REACT_CALL_TYPE: - return "ReactCall"; - case REACT_RETURN_TYPE: - return "ReactReturn"; - } - if ("object" === typeof fiber && null !== fiber) - switch (fiber.$$typeof) { - case REACT_FORWARD_REF_TYPE: - return ( - (fiber = fiber.render.displayName || fiber.render.name || ""), - "" !== fiber ? "ForwardRef(" + fiber + ")" : "ForwardRef" - ); - } - return null; -} -function getStackAddendumByWorkInProgressFiber(workInProgress) { - var info = ""; - do { - a: switch (workInProgress.tag) { - case 0: - case 1: - case 2: - case 5: - var owner = workInProgress._debugOwner, - source = workInProgress._debugSource; - var JSCompiler_inline_result = getComponentName(workInProgress); - var ownerName = null; - owner && (ownerName = getComponentName(owner)); - owner = source; - JSCompiler_inline_result = - "\n in " + - (JSCompiler_inline_result || "Unknown") + - (owner - ? " (at " + - owner.fileName.replace(/^.*[\\\/]/, "") + - ":" + - owner.lineNumber + - ")" - : ownerName ? " (created by " + ownerName + ")" : ""); - break a; - default: - JSCompiler_inline_result = ""; - } - info += JSCompiler_inline_result; - workInProgress = workInProgress["return"]; - } while (workInProgress); - return info; -} -var emptyObject$1 = {}, - 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, - flattenStyle(prevProp), - nextProp, - validAttributes - ) - : diffProperties( - updatePayload, - prevProp, - flattenStyle(nextProp), - validAttributes - ); -} -function addNestedProperty(updatePayload, nextProp, validAttributes) { - if (!nextProp) return updatePayload; - if (!Array.isArray(nextProp)) - return diffProperties( - updatePayload, - emptyObject$1, - 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$1, - 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 || - 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 || - 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(context, callback) { - return function() { - if (callback) { - if ("boolean" === typeof context.__isMounted) { - if (!context.__isMounted) return; - } else if ( - "function" === typeof context.isMounted && - !context.isMounted() - ) - return; - return callback.apply(context, arguments); - } - }; -} -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 ReactCurrentOwner = - React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner; -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 isMounted(component) { - return (component = component._reactInternalFiber) - ? 2 === isFiberMountedImpl(component) - : !1; -} -function assertIsMounted(fiber) { - invariant( - 2 === isFiberMountedImpl(fiber), - "Unable to find node on an unmounted component." - ); -} -function findCurrentFiberUsingSlowPath(fiber) { - var alternate = fiber.alternate; - if (!alternate) - return ( - (alternate = isFiberMountedImpl(fiber)), - invariant( - 3 !== alternate, - "Unable to find node on an unmounted component." - ), - 1 === alternate ? null : fiber - ); - for (var a = fiber, b = alternate; ; ) { - var parentA = a["return"], - parentB = parentA ? parentA.alternate : null; - if (!parentA || !parentB) break; - if (parentA.child === parentB.child) { - for (var child = parentA.child; child; ) { - if (child === a) return assertIsMounted(parentA), fiber; - if (child === b) return assertIsMounted(parentA), alternate; - child = child.sibling; - } - invariant(!1, "Unable to find node on an unmounted component."); - } - if (a["return"] !== b["return"]) (a = parentA), (b = parentB); - else { - child = !1; - for (var _child = parentA.child; _child; ) { - if (_child === a) { - child = !0; - a = parentA; - b = parentB; - break; - } - if (_child === b) { - child = !0; - b = parentA; - a = parentB; - break; - } - _child = _child.sibling; - } - if (!child) { - for (_child = parentB.child; _child; ) { - if (_child === a) { - child = !0; - a = parentB; - b = parentA; - break; - } - if (_child === b) { - child = !0; - b = parentB; - a = parentA; - break; - } - _child = _child.sibling; - } - invariant( - child, - "Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue." - ); - } - } - invariant( - a.alternate === b, - "Return fibers should always be each others' alternates. This error is likely caused by a bug in React. Please file an issue." - ); - } - invariant(3 === a.tag, "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 findCurrentHostFiberWithNoPortals(parent) { - parent = findCurrentFiberUsingSlowPath(parent); - if (!parent) return null; - for (var node = parent; ; ) { - if (5 === node.tag || 6 === node.tag) return node; - if (node.child && 4 !== node.tag) - (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 FiberNode(tag, pendingProps, key, mode) { - this.tag = tag; - this.key = key; - this.stateNode = this.type = null; - this.sibling = this.child = this["return"] = null; - this.index = 0; - this.ref = null; - this.pendingProps = pendingProps; - this.memoizedState = this.updateQueue = this.memoizedProps = null; - this.mode = mode; - this.effectTag = 0; - this.lastEffect = this.firstEffect = this.nextEffect = null; - this.expirationTime = 0; - this.alternate = null; -} -function createWorkInProgress(current, pendingProps, expirationTime) { - var workInProgress = current.alternate; - null === workInProgress - ? ((workInProgress = new FiberNode( - current.tag, - pendingProps, - current.key, - current.mode - )), - (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.expirationTime = expirationTime; - workInProgress.child = current.child; - workInProgress.memoizedProps = current.memoizedProps; - workInProgress.memoizedState = current.memoizedState; - workInProgress.updateQueue = current.updateQueue; - workInProgress.sibling = current.sibling; - workInProgress.index = current.index; - workInProgress.ref = current.ref; - return workInProgress; -} -function createFiberFromElement(element, mode, expirationTime) { - var type = element.type, - key = element.key; - element = element.props; - var fiberTag = void 0; - if ("function" === typeof type) - fiberTag = type.prototype && type.prototype.isReactComponent ? 2 : 0; - else if ("string" === typeof type) fiberTag = 5; - else - switch (type) { - case REACT_FRAGMENT_TYPE: - return createFiberFromFragment( - element.children, - mode, - expirationTime, - key - ); - case REACT_ASYNC_MODE_TYPE: - fiberTag = 11; - mode |= 3; - break; - case REACT_STRICT_MODE_TYPE: - fiberTag = 11; - mode |= 2; - break; - case REACT_CALL_TYPE: - fiberTag = 7; - break; - case REACT_RETURN_TYPE: - fiberTag = 9; - break; - default: - if ("object" === typeof type && null !== type) - switch (type.$$typeof) { - case REACT_PROVIDER_TYPE: - fiberTag = 13; - break; - case REACT_CONTEXT_TYPE: - fiberTag = 12; - break; - case REACT_FORWARD_REF_TYPE: - fiberTag = 14; - break; - default: - if ("number" === typeof type.tag) - return ( - (mode = type), - (mode.pendingProps = element), - (mode.expirationTime = expirationTime), - mode - ); - throwOnInvalidElementType(type, null); - } - else throwOnInvalidElementType(type, null); - } - mode = new FiberNode(fiberTag, element, key, mode); - mode.type = type; - mode.expirationTime = expirationTime; - return mode; -} -function throwOnInvalidElementType(type) { - invariant( - !1, - "Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: %s.%s", - null == type ? type : typeof type, - "" - ); -} -function createFiberFromFragment(elements, mode, expirationTime, key) { - elements = new FiberNode(10, elements, key, mode); - elements.expirationTime = expirationTime; - return elements; -} -function createFiberFromText(content, mode, expirationTime) { - content = new FiberNode(6, content, null, mode); - content.expirationTime = expirationTime; - return content; -} -function createFiberFromPortal(portal, mode, expirationTime) { - mode = new FiberNode( - 4, - null !== portal.children ? portal.children : [], - portal.key, - mode - ); - mode.expirationTime = expirationTime; - mode.stateNode = { - containerInfo: portal.containerInfo, - pendingChildren: null, - implementation: portal.implementation - }; - return mode; -} -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; -} -function onCommitRoot(root) { - "function" === typeof onCommitFiberRoot && onCommitFiberRoot(root); -} -function onCommitUnmount(fiber) { - "function" === typeof onCommitFiberUnmount && onCommitFiberUnmount(fiber); -} -var _require = require("ReactFeatureFlags"), - enableGetDerivedStateFromCatch = _require.enableGetDerivedStateFromCatch, - debugRenderPhaseSideEffects = _require.debugRenderPhaseSideEffects, - debugRenderPhaseSideEffectsForStrictMode = - _require.debugRenderPhaseSideEffectsForStrictMode; -new Set(); -function createUpdateQueue(baseState) { - return { - baseState: baseState, - expirationTime: 0, - first: null, - last: null, - callbackList: null, - hasForceUpdate: !1, - isInitialized: !1, - capturedValues: null - }; -} -function insertUpdateIntoQueue(queue, update) { - null === queue.last - ? (queue.first = queue.last = update) - : ((queue.last.next = update), (queue.last = update)); - if ( - 0 === queue.expirationTime || - queue.expirationTime > update.expirationTime - ) - queue.expirationTime = update.expirationTime; -} -var q1 = void 0, - q2 = void 0; -function ensureUpdateQueues(fiber) { - q1 = q2 = null; - var alternateFiber = fiber.alternate, - queue1 = fiber.updateQueue; - null === queue1 && (queue1 = fiber.updateQueue = createUpdateQueue(null)); - null !== alternateFiber - ? ((fiber = alternateFiber.updateQueue), - null === fiber && - (fiber = alternateFiber.updateQueue = createUpdateQueue(null))) - : (fiber = null); - q1 = queue1; - q2 = fiber !== queue1 ? fiber : null; -} -function insertUpdateIntoFiber(fiber, update) { - ensureUpdateQueues(fiber); - fiber = q1; - var queue2 = q2; - null === queue2 - ? insertUpdateIntoQueue(fiber, update) - : null === fiber.last || null === queue2.last - ? (insertUpdateIntoQueue(fiber, update), - insertUpdateIntoQueue(queue2, update)) - : (insertUpdateIntoQueue(fiber, update), (queue2.last = update)); -} -function getStateFromUpdate(update, instance, prevState, props) { - update = update.partialState; - return "function" === typeof update - ? update.call(instance, prevState, props) - : update; -} -function processUpdateQueue( - current, - workInProgress, - queue, - instance, - props, - renderExpirationTime -) { - null !== current && - current.updateQueue === queue && - (queue = workInProgress.updateQueue = { - baseState: queue.baseState, - expirationTime: queue.expirationTime, - first: queue.first, - last: queue.last, - isInitialized: queue.isInitialized, - capturedValues: queue.capturedValues, - callbackList: null, - hasForceUpdate: !1 - }); - queue.expirationTime = 0; - queue.isInitialized - ? (current = queue.baseState) - : ((current = queue.baseState = workInProgress.memoizedState), - (queue.isInitialized = !0)); - for ( - var dontMutatePrevState = !0, update = queue.first, didSkip = !1; - null !== update; - - ) { - var updateExpirationTime = update.expirationTime; - if (updateExpirationTime > renderExpirationTime) { - var remainingExpirationTime = queue.expirationTime; - if ( - 0 === remainingExpirationTime || - remainingExpirationTime > updateExpirationTime - ) - queue.expirationTime = updateExpirationTime; - didSkip || ((didSkip = !0), (queue.baseState = current)); - } else { - didSkip || - ((queue.first = update.next), - null === queue.first && (queue.last = null)); - (debugRenderPhaseSideEffects || - (debugRenderPhaseSideEffectsForStrictMode && - workInProgress.mode & 2)) && - getStateFromUpdate(update, instance, current, props); - if (update.isReplace) - (current = getStateFromUpdate(update, instance, current, props)), - (dontMutatePrevState = !0); - else if ( - (updateExpirationTime = getStateFromUpdate( - update, - instance, - current, - props - )) - ) - (current = dontMutatePrevState - ? Object.assign({}, current, updateExpirationTime) - : Object.assign(current, updateExpirationTime)), - (dontMutatePrevState = !1); - update.isForced && (queue.hasForceUpdate = !0); - null !== update.callback && - ((updateExpirationTime = queue.callbackList), - null === updateExpirationTime && - (updateExpirationTime = queue.callbackList = []), - updateExpirationTime.push(update)); - null !== update.capturedValue && - ((updateExpirationTime = queue.capturedValues), - null === updateExpirationTime - ? (queue.capturedValues = [update.capturedValue]) - : updateExpirationTime.push(update.capturedValue)); - } - update = update.next; - } - null !== queue.callbackList - ? (workInProgress.effectTag |= 32) - : null !== queue.first || - queue.hasForceUpdate || - null !== queue.capturedValues || - (workInProgress.updateQueue = null); - didSkip || (queue.baseState = current); - return current; -} -function commitCallbacks(queue, context) { - var callbackList = queue.callbackList; - if (null !== callbackList) - for ( - queue.callbackList = null, queue = 0; - queue < callbackList.length; - queue++ - ) { - var update = callbackList[queue], - _callback = update.callback; - update.callback = null; - invariant( - "function" === typeof _callback, - "Invalid argument passed as callback. Expected a function. Instead received: %s", - _callback - ); - _callback.call(context); - } -} -function callGetDerivedStateFromCatch(ctor, capturedValues) { - for (var resultState = {}, i = 0; i < capturedValues.length; i++) { - var partialState = ctor.getDerivedStateFromCatch.call( - null, - capturedValues[i].value - ); - null !== partialState && - void 0 !== partialState && - Object.assign(resultState, partialState); - } - return resultState; -} -function ReactFiberClassComponent( - legacyContext, - scheduleWork, - computeExpirationForFiber, - memoizeProps, - memoizeState -) { - function checkShouldComponentUpdate( - workInProgress, - oldProps, - newProps, - oldState, - newState, - newContext - ) { - if ( - null === oldProps || - (null !== workInProgress.updateQueue && - workInProgress.updateQueue.hasForceUpdate) - ) - return !0; - var instance = workInProgress.stateNode; - workInProgress = workInProgress.type; - return "function" === typeof instance.shouldComponentUpdate - ? instance.shouldComponentUpdate(newProps, newState, newContext) - : workInProgress.prototype && - workInProgress.prototype.isPureReactComponent - ? !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) - : !0; - } - function adoptClassInstance(workInProgress, instance) { - instance.updater = updater; - workInProgress.stateNode = instance; - instance._reactInternalFiber = workInProgress; - } - function callComponentWillReceiveProps( - workInProgress, - instance, - newProps, - newContext - ) { - workInProgress = instance.state; - "function" === typeof instance.componentWillReceiveProps && - instance.componentWillReceiveProps(newProps, newContext); - "function" === typeof instance.UNSAFE_componentWillReceiveProps && - instance.UNSAFE_componentWillReceiveProps(newProps, newContext); - instance.state !== workInProgress && - updater.enqueueReplaceState(instance, instance.state, null); - } - function callGetDerivedStateFromProps( - workInProgress, - instance, - nextProps, - prevState - ) { - instance = workInProgress.type; - if ("function" === typeof instance.getDerivedStateFromProps) - return ( - (debugRenderPhaseSideEffects || - (debugRenderPhaseSideEffectsForStrictMode && - workInProgress.mode & 2)) && - instance.getDerivedStateFromProps.call(null, nextProps, prevState), - instance.getDerivedStateFromProps.call(null, nextProps, prevState) - ); - } - var cacheContext = legacyContext.cacheContext, - getMaskedContext = legacyContext.getMaskedContext, - getUnmaskedContext = legacyContext.getUnmaskedContext, - isContextConsumer = legacyContext.isContextConsumer, - hasContextChanged = legacyContext.hasContextChanged, - updater = { - isMounted: isMounted, - enqueueSetState: function(instance, partialState, callback) { - instance = instance._reactInternalFiber; - callback = void 0 === callback ? null : callback; - var expirationTime = computeExpirationForFiber(instance); - insertUpdateIntoFiber(instance, { - expirationTime: expirationTime, - partialState: partialState, - callback: callback, - isReplace: !1, - isForced: !1, - capturedValue: null, - next: null - }); - scheduleWork(instance, expirationTime); - }, - enqueueReplaceState: function(instance, state, callback) { - instance = instance._reactInternalFiber; - callback = void 0 === callback ? null : callback; - var expirationTime = computeExpirationForFiber(instance); - insertUpdateIntoFiber(instance, { - expirationTime: expirationTime, - partialState: state, - callback: callback, - isReplace: !0, - isForced: !1, - capturedValue: null, - next: null - }); - scheduleWork(instance, expirationTime); - }, - enqueueForceUpdate: function(instance, callback) { - instance = instance._reactInternalFiber; - callback = void 0 === callback ? null : callback; - var expirationTime = computeExpirationForFiber(instance); - insertUpdateIntoFiber(instance, { - expirationTime: expirationTime, - partialState: null, - callback: callback, - isReplace: !1, - isForced: !0, - capturedValue: null, - next: null - }); - scheduleWork(instance, expirationTime); - } - }; - return { - adoptClassInstance: adoptClassInstance, - callGetDerivedStateFromProps: callGetDerivedStateFromProps, - constructClassInstance: function(workInProgress, props) { - var ctor = workInProgress.type, - unmaskedContext = getUnmaskedContext(workInProgress), - needsContext = isContextConsumer(workInProgress), - context = needsContext - ? getMaskedContext(workInProgress, unmaskedContext) - : emptyObject; - (debugRenderPhaseSideEffects || - (debugRenderPhaseSideEffectsForStrictMode && - workInProgress.mode & 2)) && - new ctor(props, context); - ctor = new ctor(props, context); - var state = - null !== ctor.state && void 0 !== ctor.state ? ctor.state : null; - adoptClassInstance(workInProgress, ctor); - workInProgress.memoizedState = state; - props = callGetDerivedStateFromProps(workInProgress, ctor, props, state); - null !== props && - void 0 !== props && - (workInProgress.memoizedState = Object.assign( - {}, - workInProgress.memoizedState, - props - )); - needsContext && cacheContext(workInProgress, unmaskedContext, context); - return ctor; - }, - mountClassInstance: function(workInProgress, renderExpirationTime) { - var ctor = workInProgress.type, - current = workInProgress.alternate, - instance = workInProgress.stateNode, - props = workInProgress.pendingProps, - unmaskedContext = getUnmaskedContext(workInProgress); - instance.props = props; - instance.state = workInProgress.memoizedState; - instance.refs = emptyObject; - instance.context = getMaskedContext(workInProgress, unmaskedContext); - "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 && - updater.enqueueReplaceState(instance, instance.state, null), - (ctor = workInProgress.updateQueue), - null !== ctor && - (instance.state = processUpdateQueue( - current, - workInProgress, - ctor, - instance, - props, - renderExpirationTime - ))); - "function" === typeof instance.componentDidMount && - (workInProgress.effectTag |= 4); - }, - resumeMountClassInstance: function(workInProgress, renderExpirationTime) { - var ctor = workInProgress.type, - instance = workInProgress.stateNode; - instance.props = workInProgress.memoizedProps; - instance.state = workInProgress.memoizedState; - var oldProps = workInProgress.memoizedProps, - newProps = workInProgress.pendingProps, - oldContext = instance.context, - newUnmaskedContext = getUnmaskedContext(workInProgress); - newUnmaskedContext = getMaskedContext(workInProgress, newUnmaskedContext); - var hasNewLifecycles = - "function" === typeof ctor.getDerivedStateFromProps || - "function" === typeof instance.getSnapshotBeforeUpdate; - hasNewLifecycles || - ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && - "function" !== typeof instance.componentWillReceiveProps) || - ((oldProps !== newProps || oldContext !== newUnmaskedContext) && - callComponentWillReceiveProps( - workInProgress, - instance, - newProps, - newUnmaskedContext - )); - oldContext = workInProgress.memoizedState; - var derivedStateFromCatch = void 0; - if (null !== workInProgress.updateQueue) { - renderExpirationTime = processUpdateQueue( - null, - workInProgress, - workInProgress.updateQueue, - instance, - newProps, - renderExpirationTime - ); - var updateQueue = workInProgress.updateQueue; - null !== updateQueue && - null !== updateQueue.capturedValues && - enableGetDerivedStateFromCatch && - "function" === typeof ctor.getDerivedStateFromCatch && - (derivedStateFromCatch = callGetDerivedStateFromCatch( - ctor, - updateQueue.capturedValues - )); - } else renderExpirationTime = oldContext; - ctor = void 0; - oldProps !== newProps && - (ctor = callGetDerivedStateFromProps( - workInProgress, - instance, - newProps, - renderExpirationTime - )); - null !== ctor && - void 0 !== ctor && - ((renderExpirationTime = - null === renderExpirationTime || void 0 === renderExpirationTime - ? ctor - : Object.assign({}, renderExpirationTime, ctor)), - (updateQueue = workInProgress.updateQueue), - null !== updateQueue && - (updateQueue.baseState = Object.assign( - {}, - updateQueue.baseState, - ctor - ))); - null !== derivedStateFromCatch && - void 0 !== derivedStateFromCatch && - ((renderExpirationTime = - null === renderExpirationTime || void 0 === renderExpirationTime - ? derivedStateFromCatch - : Object.assign({}, renderExpirationTime, derivedStateFromCatch)), - (ctor = workInProgress.updateQueue), - null !== ctor && - (ctor.baseState = Object.assign( - {}, - ctor.baseState, - derivedStateFromCatch - ))); - if ( - !( - oldProps !== newProps || - oldContext !== renderExpirationTime || - hasContextChanged() || - (null !== workInProgress.updateQueue && - workInProgress.updateQueue.hasForceUpdate) - ) - ) - return ( - "function" === typeof instance.componentDidMount && - (workInProgress.effectTag |= 4), - !1 - ); - (oldProps = checkShouldComponentUpdate( - workInProgress, - oldProps, - newProps, - oldContext, - renderExpirationTime, - newUnmaskedContext - )) - ? (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), - memoizeProps(workInProgress, newProps), - memoizeState(workInProgress, renderExpirationTime)); - instance.props = newProps; - instance.state = renderExpirationTime; - instance.context = newUnmaskedContext; - return oldProps; - }, - updateClassInstance: function( - current, - workInProgress, - renderExpirationTime - ) { - var ctor = workInProgress.type, - instance = workInProgress.stateNode; - instance.props = workInProgress.memoizedProps; - instance.state = workInProgress.memoizedState; - var oldProps = workInProgress.memoizedProps, - newProps = workInProgress.pendingProps, - oldContext = instance.context, - newUnmaskedContext = getUnmaskedContext(workInProgress); - newUnmaskedContext = getMaskedContext(workInProgress, newUnmaskedContext); - var hasNewLifecycles = - "function" === typeof ctor.getDerivedStateFromProps || - "function" === typeof instance.getSnapshotBeforeUpdate; - hasNewLifecycles || - ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && - "function" !== typeof instance.componentWillReceiveProps) || - ((oldProps !== newProps || oldContext !== newUnmaskedContext) && - callComponentWillReceiveProps( - workInProgress, - instance, - newProps, - newUnmaskedContext - )); - oldContext = workInProgress.memoizedState; - var derivedStateFromCatch = void 0; - if (null !== workInProgress.updateQueue) { - renderExpirationTime = processUpdateQueue( - current, - workInProgress, - workInProgress.updateQueue, - instance, - newProps, - renderExpirationTime - ); - var updateQueue = workInProgress.updateQueue; - null !== updateQueue && - null !== updateQueue.capturedValues && - enableGetDerivedStateFromCatch && - "function" === typeof ctor.getDerivedStateFromCatch && - (derivedStateFromCatch = callGetDerivedStateFromCatch( - ctor, - updateQueue.capturedValues - )); - } else renderExpirationTime = oldContext; - ctor = void 0; - oldProps !== newProps && - (ctor = callGetDerivedStateFromProps( - workInProgress, - instance, - newProps, - renderExpirationTime - )); - null !== ctor && - void 0 !== ctor && - ((renderExpirationTime = - null === renderExpirationTime || void 0 === renderExpirationTime - ? ctor - : Object.assign({}, renderExpirationTime, ctor)), - (updateQueue = workInProgress.updateQueue), - null !== updateQueue && - (updateQueue.baseState = Object.assign( - {}, - updateQueue.baseState, - ctor - ))); - null !== derivedStateFromCatch && - void 0 !== derivedStateFromCatch && - ((renderExpirationTime = - null === renderExpirationTime || void 0 === renderExpirationTime - ? derivedStateFromCatch - : Object.assign({}, renderExpirationTime, derivedStateFromCatch)), - (ctor = workInProgress.updateQueue), - null !== ctor && - (ctor.baseState = Object.assign( - {}, - ctor.baseState, - derivedStateFromCatch - ))); - if ( - !( - oldProps !== newProps || - oldContext !== renderExpirationTime || - hasContextChanged() || - (null !== workInProgress.updateQueue && - workInProgress.updateQueue.hasForceUpdate) - ) - ) - return ( - "function" !== typeof instance.componentDidUpdate || - (oldProps === current.memoizedProps && - oldContext === current.memoizedState) || - (workInProgress.effectTag |= 4), - "function" !== typeof instance.getSnapshotBeforeUpdate || - (oldProps === current.memoizedProps && - oldContext === current.memoizedState) || - (workInProgress.effectTag |= 2048), - !1 - ); - (derivedStateFromCatch = checkShouldComponentUpdate( - workInProgress, - oldProps, - newProps, - oldContext, - renderExpirationTime, - newUnmaskedContext - )) - ? (hasNewLifecycles || - ("function" !== typeof instance.UNSAFE_componentWillUpdate && - "function" !== typeof instance.componentWillUpdate) || - ("function" === typeof instance.componentWillUpdate && - instance.componentWillUpdate( - newProps, - renderExpirationTime, - newUnmaskedContext - ), - "function" === typeof instance.UNSAFE_componentWillUpdate && - instance.UNSAFE_componentWillUpdate( - newProps, - renderExpirationTime, - newUnmaskedContext - )), - "function" === typeof instance.componentDidUpdate && - (workInProgress.effectTag |= 4), - "function" === typeof instance.getSnapshotBeforeUpdate && - (workInProgress.effectTag |= 2048)) - : ("function" !== typeof instance.componentDidUpdate || - (oldProps === current.memoizedProps && - oldContext === current.memoizedState) || - (workInProgress.effectTag |= 4), - "function" !== typeof instance.getSnapshotBeforeUpdate || - (oldProps === current.memoizedProps && - oldContext === current.memoizedState) || - (workInProgress.effectTag |= 2048), - memoizeProps(workInProgress, newProps), - memoizeState(workInProgress, renderExpirationTime)); - instance.props = newProps; - instance.state = renderExpirationTime; - instance.context = newUnmaskedContext; - return derivedStateFromCatch; - } - }; -} -var isArray$1 = Array.isArray; -function coerceRef(returnFiber, current, element) { - returnFiber = element.ref; - if ( - null !== returnFiber && - "function" !== typeof returnFiber && - "object" !== typeof returnFiber - ) { - if (element._owner) { - element = element._owner; - var inst = void 0; - element && - (invariant( - 2 === element.tag, - "Stateless function components cannot have refs." - ), - (inst = element.stateNode)); - invariant( - inst, - "Missing owner for string ref %s. This error is likely caused by a bug in React. Please file an issue.", - returnFiber - ); - var stringRef = "" + returnFiber; - if ( - null !== current && - null !== current.ref && - current.ref._stringRef === stringRef - ) - return current.ref; - current = function(value) { - var refs = inst.refs === emptyObject ? (inst.refs = {}) : inst.refs; - null === value ? delete refs[stringRef] : (refs[stringRef] = value); - }; - current._stringRef = stringRef; - return current; - } - invariant( - "string" === typeof returnFiber, - "Expected ref to be a function or a string." - ); - invariant( - element._owner, - "Element ref was specified as a string (%s) but no owner was set. This could happen for one of the following reasons:\n1. You may be adding a ref to a functional 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.", - returnFiber - ); - } - return returnFiber; -} -function throwOnInvalidObjectType(returnFiber, newChild) { - "textarea" !== returnFiber.type && - invariant( - !1, - "Objects are not valid as a React child (found: %s).%s", - "[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, textContent, expirationTime) { - if (null === current || 6 !== current.tag) - return ( - (current = createFiberFromText( - textContent, - returnFiber.mode, - expirationTime - )), - (current["return"] = returnFiber), - current - ); - current = useFiber(current, textContent, expirationTime); - current["return"] = returnFiber; - return current; - } - function updateElement(returnFiber, current, element, expirationTime) { - if (null !== current && current.type === element.type) - return ( - (expirationTime = useFiber(current, element.props, expirationTime)), - (expirationTime.ref = coerceRef(returnFiber, current, element)), - (expirationTime["return"] = returnFiber), - expirationTime - ); - expirationTime = createFiberFromElement( - element, - returnFiber.mode, - expirationTime - ); - expirationTime.ref = coerceRef(returnFiber, current, element); - expirationTime["return"] = returnFiber; - return expirationTime; - } - function updatePortal(returnFiber, current, portal, expirationTime) { - if ( - null === current || - 4 !== current.tag || - current.stateNode.containerInfo !== portal.containerInfo || - current.stateNode.implementation !== portal.implementation - ) - return ( - (current = createFiberFromPortal( - portal, - returnFiber.mode, - expirationTime - )), - (current["return"] = returnFiber), - current - ); - current = useFiber(current, portal.children || [], expirationTime); - current["return"] = returnFiber; - return current; - } - function updateFragment(returnFiber, current, fragment, expirationTime, key) { - if (null === current || 10 !== current.tag) - return ( - (current = createFiberFromFragment( - fragment, - returnFiber.mode, - expirationTime, - key - )), - (current["return"] = returnFiber), - current - ); - current = useFiber(current, fragment, expirationTime); - current["return"] = returnFiber; - return current; - } - 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 = createFiberFromElement( - newChild, - 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$1(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$1(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$1(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++) - if ( - (oldFiber = createChild( - returnFiber, - newChildren[newIdx], - expirationTime - )) - ) - (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++ - ) - if ( - (nextOldFiber = updateFromMap( - oldFiber, - returnFiber, - newIdx, - newChildren[newIdx], - expirationTime - )) - ) { - if (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); - invariant( - "function" === typeof iteratorFn, - "An object is not an iterable. This error is likely caused by a bug in React. Please file an issue." - ); - newChildrenIterable = iteratorFn.call(newChildrenIterable); - invariant( - null != newChildrenIterable, - "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) { - 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() - ) - if ( - ((step = updateFromMap( - oldFiber, - returnFiber, - newIdx, - step.value, - expirationTime - )), - null !== step) - ) { - if (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) { - "object" === typeof newChild && - null !== newChild && - newChild.type === REACT_FRAGMENT_TYPE && - null === newChild.key && - (newChild = newChild.props.children); - var isObject = "object" === typeof newChild && null !== newChild; - if (isObject) - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: - a: { - var key = newChild.key; - for (isObject = currentFirstChild; null !== isObject; ) { - if (isObject.key === key) - if ( - 10 === isObject.tag - ? newChild.type === REACT_FRAGMENT_TYPE - : isObject.type === newChild.type - ) { - deleteRemainingChildren(returnFiber, isObject.sibling); - currentFirstChild = useFiber( - isObject, - newChild.type === REACT_FRAGMENT_TYPE - ? newChild.props.children - : newChild.props, - expirationTime - ); - currentFirstChild.ref = coerceRef( - returnFiber, - isObject, - newChild - ); - currentFirstChild["return"] = returnFiber; - returnFiber = currentFirstChild; - break a; - } else { - deleteRemainingChildren(returnFiber, isObject); - break; - } - else deleteChild(returnFiber, isObject); - isObject = isObject.sibling; - } - newChild.type === REACT_FRAGMENT_TYPE - ? ((currentFirstChild = createFiberFromFragment( - newChild.props.children, - returnFiber.mode, - expirationTime, - newChild.key - )), - (currentFirstChild["return"] = returnFiber), - (returnFiber = currentFirstChild)) - : ((expirationTime = createFiberFromElement( - newChild, - returnFiber.mode, - expirationTime - )), - (expirationTime.ref = coerceRef( - returnFiber, - currentFirstChild, - newChild - )), - (expirationTime["return"] = returnFiber), - (returnFiber = expirationTime)); - } - return placeSingleChild(returnFiber); - case REACT_PORTAL_TYPE: - a: { - for (isObject = newChild.key; null !== currentFirstChild; ) { - if (currentFirstChild.key === isObject) - 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; - } else { - 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$1(newChild)) - return reconcileChildrenArray( - returnFiber, - currentFirstChild, - newChild, - expirationTime - ); - if (getIteratorFn(newChild)) - return reconcileChildrenIterator( - returnFiber, - currentFirstChild, - newChild, - expirationTime - ); - isObject && throwOnInvalidObjectType(returnFiber, newChild); - if ("undefined" === typeof newChild) - switch (returnFiber.tag) { - case 2: - case 1: - (expirationTime = returnFiber.type), - invariant( - !1, - "%s(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.", - expirationTime.displayName || expirationTime.name || "Component" - ); - } - return deleteRemainingChildren(returnFiber, currentFirstChild); - }; -} -var reconcileChildFibers = ChildReconciler(!0), - mountChildFibers = ChildReconciler(!1); -function ReactFiberBeginWork( - config, - hostContext, - legacyContext, - newContext, - hydrationContext, - scheduleWork, - computeExpirationForFiber -) { - function reconcileChildren(current, workInProgress, nextChildren) { - reconcileChildrenAtExpirationTime( - current, - workInProgress, - nextChildren, - workInProgress.expirationTime - ); - } - function reconcileChildrenAtExpirationTime( - current, - workInProgress, - nextChildren, - renderExpirationTime - ) { - workInProgress.child = - null === current - ? mountChildFibers( - workInProgress, - null, - nextChildren, - renderExpirationTime - ) - : reconcileChildFibers( - workInProgress, - current.child, - nextChildren, - renderExpirationTime - ); - } - function markRef(current, workInProgress) { - var ref = workInProgress.ref; - if ( - (null === current && null !== ref) || - (null !== current && current.ref !== ref) - ) - workInProgress.effectTag |= 128; - } - function finishClassComponent( - current, - workInProgress, - shouldUpdate, - hasContext, - didCaptureError, - renderExpirationTime - ) { - markRef(current, workInProgress); - if (!shouldUpdate && !didCaptureError) - return ( - hasContext && invalidateContextProvider(workInProgress, !1), - bailoutOnAlreadyFinishedWork(current, workInProgress) - ); - var ctor = workInProgress.type; - shouldUpdate = workInProgress.stateNode; - ReactCurrentOwner.current = workInProgress; - !didCaptureError || - (enableGetDerivedStateFromCatch && - "function" === typeof ctor.getDerivedStateFromCatch) - ? ((debugRenderPhaseSideEffects || - (debugRenderPhaseSideEffectsForStrictMode && - workInProgress.mode & 2)) && - shouldUpdate.render(), - (ctor = shouldUpdate.render())) - : (ctor = null); - workInProgress.effectTag |= 1; - didCaptureError && - (reconcileChildrenAtExpirationTime( - current, - workInProgress, - null, - renderExpirationTime - ), - (workInProgress.child = null)); - reconcileChildrenAtExpirationTime( - current, - workInProgress, - ctor, - renderExpirationTime - ); - workInProgress.memoizedState = shouldUpdate.state; - workInProgress.memoizedProps = shouldUpdate.props; - hasContext && invalidateContextProvider(workInProgress, !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 propagateContextChange( - workInProgress, - context, - changedBits, - renderExpirationTime - ) { - var fiber = workInProgress.child; - for ( - null !== fiber && (fiber["return"] = workInProgress); - null !== fiber; - - ) { - switch (fiber.tag) { - case 12: - var nextFiber = fiber.stateNode | 0; - if (fiber.type === context && 0 !== (nextFiber & changedBits)) { - for (nextFiber = fiber; null !== nextFiber; ) { - var alternate = nextFiber.alternate; - if ( - 0 === nextFiber.expirationTime || - nextFiber.expirationTime > renderExpirationTime - ) - (nextFiber.expirationTime = renderExpirationTime), - null !== alternate && - (0 === alternate.expirationTime || - alternate.expirationTime > renderExpirationTime) && - (alternate.expirationTime = renderExpirationTime); - else if ( - null !== alternate && - (0 === alternate.expirationTime || - alternate.expirationTime > renderExpirationTime) - ) - alternate.expirationTime = renderExpirationTime; - else break; - nextFiber = nextFiber["return"]; - } - nextFiber = null; - } else nextFiber = fiber.child; - break; - case 13: - nextFiber = fiber.type === workInProgress.type ? null : fiber.child; - break; - default: - nextFiber = fiber.child; - } - if (null !== nextFiber) nextFiber["return"] = fiber; - else - for (nextFiber = fiber; null !== nextFiber; ) { - if (nextFiber === workInProgress) { - nextFiber = null; - break; - } - fiber = nextFiber.sibling; - if (null !== fiber) { - nextFiber = fiber; - break; - } - nextFiber = nextFiber["return"]; - } - fiber = nextFiber; - } - } - function updateContextProvider( - current, - workInProgress, - renderExpirationTime - ) { - var context = workInProgress.type._context, - newProps = workInProgress.pendingProps, - oldProps = workInProgress.memoizedProps; - if (!hasLegacyContextChanged() && oldProps === newProps) - return ( - (workInProgress.stateNode = 0), - pushProvider(workInProgress), - bailoutOnAlreadyFinishedWork(current, workInProgress) - ); - var newValue = newProps.value; - workInProgress.memoizedProps = newProps; - if (null === oldProps) newValue = 1073741823; - else if (oldProps.value === newProps.value) { - if (oldProps.children === newProps.children) - return ( - (workInProgress.stateNode = 0), - pushProvider(workInProgress), - bailoutOnAlreadyFinishedWork(current, workInProgress) - ); - newValue = 0; - } else { - var oldValue = oldProps.value; - if ( - (oldValue === newValue && - (0 !== oldValue || 1 / oldValue === 1 / newValue)) || - (oldValue !== oldValue && newValue !== newValue) - ) { - if (oldProps.children === newProps.children) - return ( - (workInProgress.stateNode = 0), - pushProvider(workInProgress), - bailoutOnAlreadyFinishedWork(current, workInProgress) - ); - newValue = 0; - } else if ( - ((newValue = - "function" === typeof context._calculateChangedBits - ? context._calculateChangedBits(oldValue, newValue) - : 1073741823), - (newValue |= 0), - 0 === newValue) - ) { - if (oldProps.children === newProps.children) - return ( - (workInProgress.stateNode = 0), - pushProvider(workInProgress), - bailoutOnAlreadyFinishedWork(current, workInProgress) - ); - } else - propagateContextChange( - workInProgress, - context, - newValue, - renderExpirationTime - ); - } - workInProgress.stateNode = newValue; - pushProvider(workInProgress); - reconcileChildren(current, workInProgress, newProps.children); - return workInProgress.child; - } - function bailoutOnAlreadyFinishedWork(current, workInProgress) { - invariant( - null === current || workInProgress.child === current.child, - "Resuming work not yet implemented." - ); - if (null !== workInProgress.child) { - current = workInProgress.child; - var newChild = createWorkInProgress( - current, - current.pendingProps, - current.expirationTime - ); - workInProgress.child = newChild; - for (newChild["return"] = workInProgress; null !== current.sibling; ) - (current = current.sibling), - (newChild = newChild.sibling = createWorkInProgress( - current, - current.pendingProps, - current.expirationTime - )), - (newChild["return"] = workInProgress); - newChild.sibling = null; - } - return workInProgress.child; - } - var shouldSetTextContent = config.shouldSetTextContent, - shouldDeprioritizeSubtree = config.shouldDeprioritizeSubtree, - pushHostContext = hostContext.pushHostContext, - pushHostContainer = hostContext.pushHostContainer, - pushProvider = newContext.pushProvider, - getMaskedContext = legacyContext.getMaskedContext, - getUnmaskedContext = legacyContext.getUnmaskedContext, - hasLegacyContextChanged = legacyContext.hasContextChanged, - pushLegacyContextProvider = legacyContext.pushContextProvider, - pushTopLevelContextObject = legacyContext.pushTopLevelContextObject, - invalidateContextProvider = legacyContext.invalidateContextProvider, - enterHydrationState = hydrationContext.enterHydrationState, - resetHydrationState = hydrationContext.resetHydrationState, - tryToClaimNextHydratableInstance = - hydrationContext.tryToClaimNextHydratableInstance; - config = ReactFiberClassComponent( - legacyContext, - scheduleWork, - computeExpirationForFiber, - function(workInProgress, nextProps) { - workInProgress.memoizedProps = nextProps; - }, - function(workInProgress, nextState) { - workInProgress.memoizedState = nextState; - } - ); - var adoptClassInstance = config.adoptClassInstance, - callGetDerivedStateFromProps = config.callGetDerivedStateFromProps, - constructClassInstance = config.constructClassInstance, - mountClassInstance = config.mountClassInstance, - resumeMountClassInstance = config.resumeMountClassInstance, - updateClassInstance = config.updateClassInstance; - return { - beginWork: function(current, workInProgress, renderExpirationTime) { - if ( - 0 === workInProgress.expirationTime || - workInProgress.expirationTime > renderExpirationTime - ) { - switch (workInProgress.tag) { - case 3: - pushHostRootContext(workInProgress); - break; - case 2: - pushLegacyContextProvider(workInProgress); - break; - case 4: - pushHostContainer( - workInProgress, - workInProgress.stateNode.containerInfo - ); - break; - case 13: - pushProvider(workInProgress); - } - return null; - } - switch (workInProgress.tag) { - case 0: - invariant( - null === current, - "An indeterminate component should never have mounted. This error is likely caused by a bug in React. Please file an issue." - ); - var fn = workInProgress.type, - props = workInProgress.pendingProps, - unmaskedContext = getUnmaskedContext(workInProgress); - unmaskedContext = getMaskedContext(workInProgress, unmaskedContext); - fn = fn(props, unmaskedContext); - workInProgress.effectTag |= 1; - "object" === typeof fn && - null !== fn && - "function" === typeof fn.render && - void 0 === fn.$$typeof - ? ((unmaskedContext = workInProgress.type), - (workInProgress.tag = 2), - (workInProgress.memoizedState = - null !== fn.state && void 0 !== fn.state ? fn.state : null), - "function" === typeof unmaskedContext.getDerivedStateFromProps && - ((props = callGetDerivedStateFromProps( - workInProgress, - fn, - props, - workInProgress.memoizedState - )), - null !== props && - void 0 !== props && - (workInProgress.memoizedState = Object.assign( - {}, - workInProgress.memoizedState, - props - ))), - (props = pushLegacyContextProvider(workInProgress)), - adoptClassInstance(workInProgress, fn), - mountClassInstance(workInProgress, renderExpirationTime), - (current = finishClassComponent( - current, - workInProgress, - !0, - props, - !1, - renderExpirationTime - ))) - : ((workInProgress.tag = 1), - reconcileChildren(current, workInProgress, fn), - (workInProgress.memoizedProps = props), - (current = workInProgress.child)); - return current; - case 1: - return ( - (props = workInProgress.type), - (renderExpirationTime = workInProgress.pendingProps), - hasLegacyContextChanged() || - workInProgress.memoizedProps !== renderExpirationTime - ? ((fn = getUnmaskedContext(workInProgress)), - (fn = getMaskedContext(workInProgress, fn)), - (props = props(renderExpirationTime, fn)), - (workInProgress.effectTag |= 1), - reconcileChildren(current, workInProgress, props), - (workInProgress.memoizedProps = renderExpirationTime), - (current = workInProgress.child)) - : (current = bailoutOnAlreadyFinishedWork( - current, - workInProgress - )), - current - ); - case 2: - props = pushLegacyContextProvider(workInProgress); - null === current - ? null === workInProgress.stateNode - ? (constructClassInstance( - workInProgress, - workInProgress.pendingProps - ), - mountClassInstance(workInProgress, renderExpirationTime), - (fn = !0)) - : (fn = resumeMountClassInstance( - workInProgress, - renderExpirationTime - )) - : (fn = updateClassInstance( - current, - workInProgress, - renderExpirationTime - )); - unmaskedContext = !1; - var updateQueue = workInProgress.updateQueue; - null !== updateQueue && - null !== updateQueue.capturedValues && - (unmaskedContext = fn = !0); - return finishClassComponent( - current, - workInProgress, - fn, - props, - unmaskedContext, - renderExpirationTime - ); - case 3: - a: if ( - (pushHostRootContext(workInProgress), - (fn = workInProgress.updateQueue), - null !== fn) - ) { - unmaskedContext = workInProgress.memoizedState; - props = processUpdateQueue( - current, - workInProgress, - fn, - null, - null, - renderExpirationTime - ); - workInProgress.memoizedState = props; - fn = workInProgress.updateQueue; - if (null !== fn && null !== fn.capturedValues) fn = null; - else if (unmaskedContext === props) { - resetHydrationState(); - current = bailoutOnAlreadyFinishedWork(current, workInProgress); - break a; - } else fn = props.element; - unmaskedContext = workInProgress.stateNode; - (null === current || null === current.child) && - unmaskedContext.hydrate && - enterHydrationState(workInProgress) - ? ((workInProgress.effectTag |= 2), - (workInProgress.child = mountChildFibers( - workInProgress, - null, - fn, - renderExpirationTime - ))) - : (resetHydrationState(), - reconcileChildren(current, workInProgress, fn)); - workInProgress.memoizedState = props; - current = workInProgress.child; - } else - resetHydrationState(), - (current = bailoutOnAlreadyFinishedWork(current, workInProgress)); - return current; - case 5: - a: { - pushHostContext(workInProgress); - null === current && - tryToClaimNextHydratableInstance(workInProgress); - props = workInProgress.type; - updateQueue = workInProgress.memoizedProps; - fn = workInProgress.pendingProps; - unmaskedContext = null !== current ? current.memoizedProps : null; - if (!hasLegacyContextChanged() && updateQueue === fn) { - if ( - (updateQueue = - workInProgress.mode & 1 && - shouldDeprioritizeSubtree(props, fn)) - ) - workInProgress.expirationTime = 1073741823; - if (!updateQueue || 1073741823 !== renderExpirationTime) { - current = bailoutOnAlreadyFinishedWork(current, workInProgress); - break a; - } - } - updateQueue = fn.children; - shouldSetTextContent(props, fn) - ? (updateQueue = null) - : unmaskedContext && - shouldSetTextContent(props, unmaskedContext) && - (workInProgress.effectTag |= 16); - markRef(current, workInProgress); - 1073741823 !== renderExpirationTime && - workInProgress.mode & 1 && - shouldDeprioritizeSubtree(props, fn) - ? ((workInProgress.expirationTime = 1073741823), - (workInProgress.memoizedProps = fn), - (current = null)) - : (reconcileChildren(current, workInProgress, updateQueue), - (workInProgress.memoizedProps = fn), - (current = workInProgress.child)); - } - return current; - case 6: - return ( - null === current && - tryToClaimNextHydratableInstance(workInProgress), - (workInProgress.memoizedProps = workInProgress.pendingProps), - null - ); - case 8: - workInProgress.tag = 7; - case 7: - return ( - (props = workInProgress.pendingProps), - hasLegacyContextChanged() || - workInProgress.memoizedProps !== props || - (props = workInProgress.memoizedProps), - (fn = props.children), - (workInProgress.stateNode = - null === current - ? mountChildFibers( - workInProgress, - workInProgress.stateNode, - fn, - renderExpirationTime - ) - : reconcileChildFibers( - workInProgress, - current.stateNode, - fn, - renderExpirationTime - )), - (workInProgress.memoizedProps = props), - workInProgress.stateNode - ); - case 9: - return null; - case 4: - return ( - pushHostContainer( - workInProgress, - workInProgress.stateNode.containerInfo - ), - (props = workInProgress.pendingProps), - hasLegacyContextChanged() || workInProgress.memoizedProps !== props - ? (null === current - ? (workInProgress.child = reconcileChildFibers( - workInProgress, - null, - props, - renderExpirationTime - )) - : reconcileChildren(current, workInProgress, props), - (workInProgress.memoizedProps = props), - (current = workInProgress.child)) - : (current = bailoutOnAlreadyFinishedWork( - current, - workInProgress - )), - current - ); - case 14: - return ( - (renderExpirationTime = workInProgress.type.render), - (renderExpirationTime = renderExpirationTime( - workInProgress.pendingProps, - workInProgress.ref - )), - reconcileChildren(current, workInProgress, renderExpirationTime), - (workInProgress.memoizedProps = renderExpirationTime), - workInProgress.child - ); - case 10: - return ( - (renderExpirationTime = workInProgress.pendingProps), - hasLegacyContextChanged() || - workInProgress.memoizedProps !== renderExpirationTime - ? (reconcileChildren( - current, - workInProgress, - renderExpirationTime - ), - (workInProgress.memoizedProps = renderExpirationTime), - (current = workInProgress.child)) - : (current = bailoutOnAlreadyFinishedWork( - current, - workInProgress - )), - current - ); - case 11: - return ( - (renderExpirationTime = workInProgress.pendingProps.children), - hasLegacyContextChanged() || - (null !== renderExpirationTime && - workInProgress.memoizedProps !== renderExpirationTime) - ? (reconcileChildren( - current, - workInProgress, - renderExpirationTime - ), - (workInProgress.memoizedProps = renderExpirationTime), - (current = workInProgress.child)) - : (current = bailoutOnAlreadyFinishedWork( - current, - workInProgress - )), - current - ); - case 13: - return updateContextProvider( - current, - workInProgress, - renderExpirationTime - ); - case 12: - a: { - fn = workInProgress.type; - unmaskedContext = workInProgress.pendingProps; - updateQueue = workInProgress.memoizedProps; - props = fn._currentValue; - var changedBits = fn._changedBits; - if ( - hasLegacyContextChanged() || - 0 !== changedBits || - updateQueue !== unmaskedContext - ) { - workInProgress.memoizedProps = unmaskedContext; - var observedBits = unmaskedContext.unstable_observedBits; - if (void 0 === observedBits || null === observedBits) - observedBits = 1073741823; - workInProgress.stateNode = observedBits; - if (0 !== (changedBits & observedBits)) - propagateContextChange( - workInProgress, - fn, - changedBits, - renderExpirationTime - ); - else if (updateQueue === unmaskedContext) { - current = bailoutOnAlreadyFinishedWork(current, workInProgress); - break a; - } - renderExpirationTime = unmaskedContext.children; - renderExpirationTime = renderExpirationTime(props); - reconcileChildren(current, workInProgress, renderExpirationTime); - current = workInProgress.child; - } else - current = bailoutOnAlreadyFinishedWork(current, workInProgress); - } - return current; - default: - invariant( - !1, - "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." - ); - } - } - }; -} -function ReactFiberCompleteWork( - config, - hostContext, - legacyContext, - newContext, - hydrationContext -) { - function markUpdate(workInProgress) { - workInProgress.effectTag |= 4; - } - var createInstance = config.createInstance, - createTextInstance = config.createTextInstance, - appendInitialChild = config.appendInitialChild, - finalizeInitialChildren = config.finalizeInitialChildren, - prepareUpdate = config.prepareUpdate, - persistence = config.persistence, - getRootHostContainer = hostContext.getRootHostContainer, - popHostContext = hostContext.popHostContext, - getHostContext = hostContext.getHostContext, - popHostContainer = hostContext.popHostContainer, - popLegacyContextProvider = legacyContext.popContextProvider, - popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject, - popProvider = newContext.popProvider, - prepareToHydrateHostInstance = - hydrationContext.prepareToHydrateHostInstance, - prepareToHydrateHostTextInstance = - hydrationContext.prepareToHydrateHostTextInstance, - popHydrationState = hydrationContext.popHydrationState, - updateHostContainer = void 0, - updateHostComponent = void 0, - updateHostText = void 0; - config.mutation - ? ((updateHostContainer = function() {}), - (updateHostComponent = function(current, workInProgress, updatePayload) { - (workInProgress.updateQueue = updatePayload) && - markUpdate(workInProgress); - }), - (updateHostText = function(current, workInProgress, oldText, newText) { - oldText !== newText && markUpdate(workInProgress); - })) - : persistence - ? invariant(!1, "Persistent reconciler is disabled.") - : invariant(!1, "Noop reconciler is disabled."); - return { - completeWork: function(current, workInProgress, renderExpirationTime) { - var newProps = workInProgress.pendingProps; - switch (workInProgress.tag) { - case 1: - return null; - case 2: - return ( - popLegacyContextProvider(workInProgress), - (current = workInProgress.stateNode), - (newProps = workInProgress.updateQueue), - null !== newProps && - null !== newProps.capturedValues && - ((workInProgress.effectTag &= -65), - "function" === typeof current.componentDidCatch - ? (workInProgress.effectTag |= 256) - : (newProps.capturedValues = null)), - null - ); - case 3: - popHostContainer(workInProgress); - popTopLevelLegacyContextObject(workInProgress); - newProps = workInProgress.stateNode; - newProps.pendingContext && - ((newProps.context = newProps.pendingContext), - (newProps.pendingContext = null)); - if (null === current || null === current.child) - popHydrationState(workInProgress), (workInProgress.effectTag &= -3); - updateHostContainer(workInProgress); - current = workInProgress.updateQueue; - null !== current && - null !== current.capturedValues && - (workInProgress.effectTag |= 256); - return null; - case 5: - popHostContext(workInProgress); - renderExpirationTime = getRootHostContainer(); - var type = workInProgress.type; - if (null !== current && null != workInProgress.stateNode) { - var oldProps = current.memoizedProps, - _instance = workInProgress.stateNode, - currentHostContext = getHostContext(); - _instance = prepareUpdate( - _instance, - type, - oldProps, - newProps, - renderExpirationTime, - currentHostContext - ); - updateHostComponent( - current, - workInProgress, - _instance, - type, - oldProps, - newProps, - renderExpirationTime, - currentHostContext - ); - current.ref !== workInProgress.ref && - (workInProgress.effectTag |= 128); - } else { - if (!newProps) - return ( - invariant( - null !== workInProgress.stateNode, - "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." - ), - null - ); - current = getHostContext(); - if (popHydrationState(workInProgress)) - prepareToHydrateHostInstance( - workInProgress, - renderExpirationTime, - current - ) && markUpdate(workInProgress); - else { - oldProps = createInstance( - type, - newProps, - renderExpirationTime, - current, - workInProgress - ); - a: for ( - currentHostContext = workInProgress.child; - null !== currentHostContext; - - ) { - if ( - 5 === currentHostContext.tag || - 6 === currentHostContext.tag - ) - appendInitialChild(oldProps, currentHostContext.stateNode); - else if ( - 4 !== currentHostContext.tag && - null !== currentHostContext.child - ) { - currentHostContext.child["return"] = currentHostContext; - currentHostContext = currentHostContext.child; - continue; - } - if (currentHostContext === workInProgress) break; - for (; null === currentHostContext.sibling; ) { - if ( - null === currentHostContext["return"] || - currentHostContext["return"] === workInProgress - ) - break a; - currentHostContext = currentHostContext["return"]; - } - currentHostContext.sibling["return"] = - currentHostContext["return"]; - currentHostContext = currentHostContext.sibling; - } - finalizeInitialChildren( - oldProps, - type, - newProps, - renderExpirationTime, - current - ) && markUpdate(workInProgress); - workInProgress.stateNode = oldProps; - } - null !== workInProgress.ref && (workInProgress.effectTag |= 128); - } - return null; - case 6: - if (current && null != workInProgress.stateNode) - updateHostText( - current, - workInProgress, - current.memoizedProps, - newProps - ); - else { - if ("string" !== typeof newProps) - return ( - invariant( - null !== workInProgress.stateNode, - "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." - ), - null - ); - current = getRootHostContainer(); - renderExpirationTime = getHostContext(); - popHydrationState(workInProgress) - ? prepareToHydrateHostTextInstance(workInProgress) && - markUpdate(workInProgress) - : (workInProgress.stateNode = createTextInstance( - newProps, - current, - renderExpirationTime, - workInProgress - )); - } - return null; - case 7: - newProps = workInProgress.memoizedProps; - invariant( - newProps, - "Should be resolved by now. This error is likely caused by a bug in React. Please file an issue." - ); - workInProgress.tag = 8; - type = []; - a: for ( - (oldProps = workInProgress.stateNode) && - (oldProps["return"] = workInProgress); - null !== oldProps; - - ) { - if (5 === oldProps.tag || 6 === oldProps.tag || 4 === oldProps.tag) - invariant(!1, "A call cannot have host component children."); - else if (9 === oldProps.tag) type.push(oldProps.pendingProps.value); - else if (null !== oldProps.child) { - oldProps.child["return"] = oldProps; - oldProps = oldProps.child; - continue; - } - for (; null === oldProps.sibling; ) { - if ( - null === oldProps["return"] || - oldProps["return"] === workInProgress - ) - break a; - oldProps = oldProps["return"]; - } - oldProps.sibling["return"] = oldProps["return"]; - oldProps = oldProps.sibling; - } - oldProps = newProps.handler; - newProps = oldProps(newProps.props, type); - workInProgress.child = reconcileChildFibers( - workInProgress, - null !== current ? current.child : null, - newProps, - renderExpirationTime - ); - return workInProgress.child; - case 8: - return (workInProgress.tag = 7), null; - case 9: - return null; - case 14: - return null; - case 10: - return null; - case 11: - return null; - case 4: - return ( - popHostContainer(workInProgress), - updateHostContainer(workInProgress), - null - ); - case 13: - return popProvider(workInProgress), null; - case 12: - return null; - case 0: - invariant( - !1, - "An indeterminate component should have become determinate before completing. This error is likely caused by a bug in React. Please file an issue." - ); - default: - invariant( - !1, - "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." - ); - } - } - }; -} -function ReactFiberUnwindWork( - hostContext, - legacyContext, - newContext, - scheduleWork, - isAlreadyFailedLegacyErrorBoundary -) { - var popHostContainer = hostContext.popHostContainer, - popHostContext = hostContext.popHostContext, - popLegacyContextProvider = legacyContext.popContextProvider, - popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject, - popProvider = newContext.popProvider; - return { - throwException: function(returnFiber, sourceFiber, rawValue) { - sourceFiber.effectTag |= 512; - sourceFiber.firstEffect = sourceFiber.lastEffect = null; - sourceFiber = { - value: rawValue, - source: sourceFiber, - stack: getStackAddendumByWorkInProgressFiber(sourceFiber) - }; - do { - switch (returnFiber.tag) { - case 3: - ensureUpdateQueues(returnFiber); - returnFiber.updateQueue.capturedValues = [sourceFiber]; - returnFiber.effectTag |= 1024; - return; - case 2: - rawValue = returnFiber.type; - var _instance = returnFiber.stateNode; - if ( - 0 === (returnFiber.effectTag & 64) && - (("function" === typeof rawValue.getDerivedStateFromCatch && - enableGetDerivedStateFromCatch) || - (null !== _instance && - "function" === typeof _instance.componentDidCatch && - !isAlreadyFailedLegacyErrorBoundary(_instance))) - ) { - ensureUpdateQueues(returnFiber); - rawValue = returnFiber.updateQueue; - _instance = rawValue.capturedValues; - null === _instance - ? (rawValue.capturedValues = [sourceFiber]) - : _instance.push(sourceFiber); - returnFiber.effectTag |= 1024; - return; - } - } - returnFiber = returnFiber["return"]; - } while (null !== returnFiber); - }, - unwindWork: function(workInProgress) { - switch (workInProgress.tag) { - case 2: - popLegacyContextProvider(workInProgress); - var effectTag = workInProgress.effectTag; - return effectTag & 1024 - ? ((workInProgress.effectTag = (effectTag & -1025) | 64), - workInProgress) - : null; - case 3: - return ( - popHostContainer(workInProgress), - popTopLevelLegacyContextObject(workInProgress), - (effectTag = workInProgress.effectTag), - effectTag & 1024 - ? ((workInProgress.effectTag = (effectTag & -1025) | 64), - workInProgress) - : null - ); - case 5: - return popHostContext(workInProgress), null; - case 4: - return popHostContainer(workInProgress), null; - case 13: - return popProvider(workInProgress), null; - default: - return null; - } - }, - unwindInterruptedWork: function(interruptedWork) { - switch (interruptedWork.tag) { - case 2: - popLegacyContextProvider(interruptedWork); - break; - case 3: - popHostContainer(interruptedWork); - popTopLevelLegacyContextObject(interruptedWork); - break; - case 5: - popHostContext(interruptedWork); - break; - case 4: - popHostContainer(interruptedWork); - break; - case 13: - popProvider(interruptedWork); - } - } - }; -} -function logError(boundary, errorInfo) { - var source = errorInfo.source, - stack = errorInfo.stack; - null === stack && (stack = getStackAddendumByWorkInProgressFiber(source)); - null !== source && getComponentName(source); - source = null !== stack ? stack : ""; - errorInfo = errorInfo.value; - null !== boundary && 2 === boundary.tag && getComponentName(boundary); - try { - if (errorInfo instanceof Error) { - var message = errorInfo.message, - name = errorInfo.name; - var errorToHandle = errorInfo; - try { - errorToHandle.message = - (message ? name + ": " + message : name) + - "\n\nThis error is located at:" + - source; - } catch (e) {} - } else - errorToHandle = - "string" === typeof errorInfo - ? Error(errorInfo + "\n\nThis error is located at:" + source) - : Error("Unspecified error at:" + source); - ExceptionsManager.handleException(errorToHandle, !1); - } catch (e) { - (e && e.suppressReactErrorLogging) || console.error(e); - } -} -function ReactFiberCommitWork( - config, - captureError, - scheduleWork, - computeExpirationForFiber, - markLegacyErrorBoundaryAsFailed -) { - function safelyDetachRef(current) { - var ref = current.ref; - if (null !== ref) - if ("function" === typeof ref) - try { - ref(null); - } catch (refError) { - captureError(current, refError); - } - else ref.current = null; - } - function commitUnmount(current) { - "function" === typeof onCommitUnmount && onCommitUnmount(current); - switch (current.tag) { - case 2: - safelyDetachRef(current); - var _instance7 = current.stateNode; - if ("function" === typeof _instance7.componentWillUnmount) - try { - (_instance7.props = current.memoizedProps), - (_instance7.state = current.memoizedState), - _instance7.componentWillUnmount(); - } catch (unmountError) { - captureError(current, unmountError); - } - break; - case 5: - safelyDetachRef(current); - break; - case 7: - commitNestedUnmounts(current.stateNode); - break; - case 4: - mutation && unmountHostComponents(current); - } - } - function commitNestedUnmounts(root) { - for (var node = root; ; ) - if ( - (commitUnmount(node), - null === node.child || (mutation && 4 === node.tag)) - ) { - if (node === root) break; - for (; null === node.sibling; ) { - if (null === node["return"] || node["return"] === root) return; - node = node["return"]; - } - node.sibling["return"] = node["return"]; - node = node.sibling; - } else (node.child["return"] = node), (node = node.child); - } - function isHostParent(fiber) { - return 5 === fiber.tag || 3 === fiber.tag || 4 === fiber.tag; - } - function unmountHostComponents(current) { - for ( - var node = current, - currentParentIsValid = !1, - currentParent = void 0, - currentParentIsContainer = void 0; - ; - - ) { - if (!currentParentIsValid) { - currentParentIsValid = node["return"]; - a: for (;;) { - invariant( - null !== currentParentIsValid, - "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) - commitNestedUnmounts(node), - currentParentIsContainer - ? removeChildFromContainer(currentParent, node.stateNode) - : removeChild(currentParent, node.stateNode); - else if ( - (4 === node.tag - ? (currentParent = node.stateNode.containerInfo) - : commitUnmount(node), - null !== node.child) - ) { - node.child["return"] = node; - node = node.child; - continue; - } - if (node === current) break; - for (; null === node.sibling; ) { - if (null === node["return"] || node["return"] === current) return; - node = node["return"]; - 4 === node.tag && (currentParentIsValid = !1); - } - node.sibling["return"] = node["return"]; - node = node.sibling; - } - } - var getPublicInstance = config.getPublicInstance, - mutation = config.mutation; - config = config.persistence; - mutation || - (config - ? invariant(!1, "Persistent reconciler is disabled.") - : invariant(!1, "Noop reconciler is disabled.")); - var commitMount = mutation.commitMount, - commitUpdate = mutation.commitUpdate, - resetTextContent = mutation.resetTextContent, - commitTextUpdate = mutation.commitTextUpdate, - appendChild = mutation.appendChild, - appendChildToContainer = mutation.appendChildToContainer, - insertBefore = mutation.insertBefore, - insertInContainerBefore = mutation.insertInContainerBefore, - removeChild = mutation.removeChild, - removeChildFromContainer = mutation.removeChildFromContainer; - return { - commitBeforeMutationLifeCycles: function(current, finishedWork) { - switch (finishedWork.tag) { - case 2: - if (finishedWork.effectTag & 2048 && null !== current) { - var prevProps = current.memoizedProps, - prevState = current.memoizedState; - current = finishedWork.stateNode; - current.props = finishedWork.memoizedProps; - current.state = finishedWork.memoizedState; - finishedWork = current.getSnapshotBeforeUpdate( - prevProps, - prevState - ); - current.__reactInternalSnapshotBeforeUpdate = finishedWork; - } - break; - case 3: - case 5: - case 6: - case 4: - break; - default: - invariant( - !1, - "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." - ); - } - }, - commitResetTextContent: function(current) { - resetTextContent(current.stateNode); - }, - commitPlacement: function(finishedWork) { - a: { - for (var parent = finishedWork["return"]; null !== parent; ) { - if (isHostParent(parent)) { - var parentFiber = parent; - break a; - } - parent = parent["return"]; - } - invariant( - !1, - "Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue." - ); - parentFiber = void 0; - } - var isContainer = (parent = void 0); - switch (parentFiber.tag) { - case 5: - parent = parentFiber.stateNode; - isContainer = !1; - break; - case 3: - parent = parentFiber.stateNode.containerInfo; - isContainer = !0; - break; - case 4: - parent = parentFiber.stateNode.containerInfo; - isContainer = !0; - break; - default: - invariant( - !1, - "Invalid host parent fiber. This error is likely caused by a bug in React. Please file an issue." - ); - } - parentFiber.effectTag & 16 && - (resetTextContent(parent), (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; - - ) { - 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) - parentFiber - ? isContainer - ? insertInContainerBefore(parent, node.stateNode, parentFiber) - : insertBefore(parent, node.stateNode, parentFiber) - : isContainer - ? appendChildToContainer(parent, node.stateNode) - : appendChild(parent, node.stateNode); - 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; - } - }, - commitDeletion: function(current) { - unmountHostComponents(current); - current["return"] = null; - current.child = null; - current.alternate && - ((current.alternate.child = null), - (current.alternate["return"] = null)); - }, - commitWork: function(current, finishedWork) { - switch (finishedWork.tag) { - case 2: - break; - case 5: - var _instance8 = finishedWork.stateNode; - if (null != _instance8) { - var newProps = finishedWork.memoizedProps; - current = null !== current ? current.memoizedProps : newProps; - var type = finishedWork.type, - updatePayload = finishedWork.updateQueue; - finishedWork.updateQueue = null; - null !== updatePayload && - commitUpdate( - _instance8, - updatePayload, - type, - current, - newProps, - finishedWork - ); - } - break; - case 6: - invariant( - null !== finishedWork.stateNode, - "This should have a text node initialized. This error is likely caused by a bug in React. Please file an issue." - ); - _instance8 = finishedWork.memoizedProps; - commitTextUpdate( - finishedWork.stateNode, - null !== current ? current.memoizedProps : _instance8, - _instance8 - ); - break; - case 3: - break; - default: - invariant( - !1, - "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." - ); - } - }, - commitLifeCycles: function(finishedRoot, current, finishedWork) { - switch (finishedWork.tag) { - case 2: - finishedRoot = finishedWork.stateNode; - if (finishedWork.effectTag & 4) - if (null === current) - (finishedRoot.props = finishedWork.memoizedProps), - (finishedRoot.state = finishedWork.memoizedState), - finishedRoot.componentDidMount(); - else { - var prevProps = current.memoizedProps; - current = current.memoizedState; - finishedRoot.props = finishedWork.memoizedProps; - finishedRoot.state = finishedWork.memoizedState; - finishedRoot.componentDidUpdate( - prevProps, - current, - finishedRoot.__reactInternalSnapshotBeforeUpdate - ); - } - finishedWork = finishedWork.updateQueue; - null !== finishedWork && commitCallbacks(finishedWork, finishedRoot); - break; - case 3: - current = finishedWork.updateQueue; - if (null !== current) { - finishedRoot = null; - if (null !== finishedWork.child) - switch (finishedWork.child.tag) { - case 5: - finishedRoot = getPublicInstance( - finishedWork.child.stateNode - ); - break; - case 2: - finishedRoot = finishedWork.child.stateNode; - } - commitCallbacks(current, finishedRoot); - } - break; - case 5: - finishedRoot = finishedWork.stateNode; - null === current && - finishedWork.effectTag & 4 && - commitMount( - finishedRoot, - finishedWork.type, - finishedWork.memoizedProps, - finishedWork - ); - break; - case 6: - break; - case 4: - break; - default: - invariant( - !1, - "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." - ); - } - }, - commitErrorLogging: function(finishedWork, onUncaughtError) { - switch (finishedWork.tag) { - case 2: - var ctor = finishedWork.type; - onUncaughtError = finishedWork.stateNode; - var updateQueue = finishedWork.updateQueue; - invariant( - null !== updateQueue && null !== updateQueue.capturedValues, - "An error logging effect should not have been scheduled if no errors were captured. This error is likely caused by a bug in React. Please file an issue." - ); - var capturedErrors = updateQueue.capturedValues; - updateQueue.capturedValues = null; - "function" !== typeof ctor.getDerivedStateFromCatch && - markLegacyErrorBoundaryAsFailed(onUncaughtError); - onUncaughtError.props = finishedWork.memoizedProps; - onUncaughtError.state = finishedWork.memoizedState; - for (ctor = 0; ctor < capturedErrors.length; ctor++) { - updateQueue = capturedErrors[ctor]; - var _error = updateQueue.value, - stack = updateQueue.stack; - logError(finishedWork, updateQueue); - onUncaughtError.componentDidCatch(_error, { - componentStack: null !== stack ? stack : "" - }); - } - break; - case 3: - ctor = finishedWork.updateQueue; - invariant( - null !== ctor && null !== ctor.capturedValues, - "An error logging effect should not have been scheduled if no errors were captured. This error is likely caused by a bug in React. Please file an issue." - ); - capturedErrors = ctor.capturedValues; - ctor.capturedValues = null; - for (ctor = 0; ctor < capturedErrors.length; ctor++) - (updateQueue = capturedErrors[ctor]), - logError(finishedWork, updateQueue), - onUncaughtError(updateQueue.value); - break; - default: - invariant( - !1, - "This unit of work tag cannot capture errors. This error is likely caused by a bug in React. Please file an issue." - ); - } - }, - commitAttachRef: function(finishedWork) { - var ref = finishedWork.ref; - if (null !== ref) { - var _instance6 = finishedWork.stateNode; - switch (finishedWork.tag) { - case 5: - finishedWork = getPublicInstance(_instance6); - break; - default: - finishedWork = _instance6; - } - "function" === typeof ref - ? ref(finishedWork) - : (ref.current = finishedWork); - } - }, - commitDetachRef: function(current) { - current = current.ref; - null !== current && - ("function" === typeof current - ? current(null) - : (current.current = null)); - } - }; -} -var NO_CONTEXT = {}; -function ReactFiberHostContext(config, stack) { - function requiredContext(c) { - invariant( - c !== NO_CONTEXT, - "Expected host context to exist. This error is likely caused by a bug in React. Please file an issue." - ); - return c; - } - var getChildHostContext = config.getChildHostContext, - getRootHostContext = config.getRootHostContext; - config = stack.createCursor; - var push = stack.push, - pop = stack.pop, - contextStackCursor = config(NO_CONTEXT), - contextFiberStackCursor = config(NO_CONTEXT), - rootInstanceStackCursor = config(NO_CONTEXT); - return { - getHostContext: function() { - return requiredContext(contextStackCursor.current); - }, - getRootHostContainer: function() { - return requiredContext(rootInstanceStackCursor.current); - }, - popHostContainer: function(fiber) { - pop(contextStackCursor, fiber); - pop(contextFiberStackCursor, fiber); - pop(rootInstanceStackCursor, fiber); - }, - popHostContext: function(fiber) { - contextFiberStackCursor.current === fiber && - (pop(contextStackCursor, fiber), pop(contextFiberStackCursor, fiber)); - }, - pushHostContainer: function(fiber, nextRootInstance) { - push(rootInstanceStackCursor, nextRootInstance, fiber); - push(contextFiberStackCursor, fiber, fiber); - push(contextStackCursor, NO_CONTEXT, fiber); - nextRootInstance = getRootHostContext(nextRootInstance); - pop(contextStackCursor, fiber); - push(contextStackCursor, nextRootInstance, fiber); - }, - pushHostContext: function(fiber) { - var rootInstance = requiredContext(rootInstanceStackCursor.current), - context = requiredContext(contextStackCursor.current); - rootInstance = getChildHostContext(context, fiber.type, rootInstance); - context !== rootInstance && - (push(contextFiberStackCursor, fiber, fiber), - push(contextStackCursor, rootInstance, fiber)); - } - }; -} -function ReactFiberHydrationContext(config) { - function deleteHydratableInstance(returnFiber, instance) { - var fiber = new FiberNode(5, null, null, 0); - fiber.type = "DELETED"; - fiber.stateNode = instance; - fiber["return"] = returnFiber; - fiber.effectTag = 8; - null !== returnFiber.lastEffect - ? ((returnFiber.lastEffect.nextEffect = fiber), - (returnFiber.lastEffect = fiber)) - : (returnFiber.firstEffect = returnFiber.lastEffect = fiber); - } - function tryHydrate(fiber, nextInstance) { - switch (fiber.tag) { - case 5: - return ( - (nextInstance = canHydrateInstance( - nextInstance, - fiber.type, - fiber.pendingProps - )), - null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1 - ); - case 6: - return ( - (nextInstance = canHydrateTextInstance( - nextInstance, - fiber.pendingProps - )), - null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1 - ); - default: - return !1; - } - } - function popToNextHostParent(fiber) { - for ( - fiber = fiber["return"]; - null !== fiber && 5 !== fiber.tag && 3 !== fiber.tag; - - ) - fiber = fiber["return"]; - hydrationParentFiber = fiber; - } - var shouldSetTextContent = config.shouldSetTextContent; - config = config.hydration; - if (!config) - return { - enterHydrationState: function() { - return !1; - }, - resetHydrationState: function() {}, - tryToClaimNextHydratableInstance: function() {}, - prepareToHydrateHostInstance: function() { - invariant( - !1, - "Expected prepareToHydrateHostInstance() to never be called. This error is likely caused by a bug in React. Please file an issue." - ); - }, - prepareToHydrateHostTextInstance: function() { - invariant( - !1, - "Expected prepareToHydrateHostTextInstance() to never be called. This error is likely caused by a bug in React. Please file an issue." - ); - }, - popHydrationState: function() { - return !1; - } - }; - var canHydrateInstance = config.canHydrateInstance, - canHydrateTextInstance = config.canHydrateTextInstance, - getNextHydratableSibling = config.getNextHydratableSibling, - getFirstHydratableChild = config.getFirstHydratableChild, - hydrateInstance = config.hydrateInstance, - hydrateTextInstance = config.hydrateTextInstance, - hydrationParentFiber = null, - nextHydratableInstance = null, - isHydrating = !1; - return { - enterHydrationState: function(fiber) { - nextHydratableInstance = getFirstHydratableChild( - fiber.stateNode.containerInfo - ); - hydrationParentFiber = fiber; - return (isHydrating = !0); - }, - resetHydrationState: function() { - nextHydratableInstance = hydrationParentFiber = null; - isHydrating = !1; - }, - tryToClaimNextHydratableInstance: function(fiber) { - if (isHydrating) { - var nextInstance = nextHydratableInstance; - if (nextInstance) { - if (!tryHydrate(fiber, nextInstance)) { - nextInstance = getNextHydratableSibling(nextInstance); - if (!nextInstance || !tryHydrate(fiber, nextInstance)) { - fiber.effectTag |= 2; - isHydrating = !1; - hydrationParentFiber = fiber; - return; - } - deleteHydratableInstance( - hydrationParentFiber, - nextHydratableInstance - ); - } - hydrationParentFiber = fiber; - nextHydratableInstance = getFirstHydratableChild(nextInstance); - } else - (fiber.effectTag |= 2), - (isHydrating = !1), - (hydrationParentFiber = fiber); - } - }, - prepareToHydrateHostInstance: function( - fiber, - rootContainerInstance, - hostContext - ) { - rootContainerInstance = hydrateInstance( - fiber.stateNode, - fiber.type, - fiber.memoizedProps, - rootContainerInstance, - hostContext, - fiber - ); - fiber.updateQueue = rootContainerInstance; - return null !== rootContainerInstance ? !0 : !1; - }, - prepareToHydrateHostTextInstance: function(fiber) { - return hydrateTextInstance(fiber.stateNode, fiber.memoizedProps, fiber); - }, - popHydrationState: function(fiber) { - if (fiber !== hydrationParentFiber) return !1; - if (!isHydrating) - return popToNextHostParent(fiber), (isHydrating = !0), !1; - var type = fiber.type; - if ( - 5 !== fiber.tag || - ("head" !== type && - "body" !== type && - !shouldSetTextContent(type, fiber.memoizedProps)) - ) - for (type = nextHydratableInstance; type; ) - deleteHydratableInstance(fiber, type), - (type = getNextHydratableSibling(type)); - popToNextHostParent(fiber); - nextHydratableInstance = hydrationParentFiber - ? getNextHydratableSibling(fiber.stateNode) - : null; - return !0; - } - }; -} -function ReactFiberLegacyContext(stack) { - function cacheContext(workInProgress, unmaskedContext, maskedContext) { - workInProgress = workInProgress.stateNode; - workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; - workInProgress.__reactInternalMemoizedMaskedChildContext = maskedContext; - } - function isContextProvider(fiber) { - return 2 === fiber.tag && null != fiber.type.childContextTypes; - } - function processChildContext(fiber, parentContext) { - var instance = fiber.stateNode, - childContextTypes = fiber.type.childContextTypes; - if ("function" !== typeof instance.getChildContext) return parentContext; - instance = instance.getChildContext(); - for (var contextKey in instance) - invariant( - contextKey in childContextTypes, - '%s.getChildContext(): key "%s" is not defined in childContextTypes.', - getComponentName(fiber) || "Unknown", - contextKey - ); - return Object.assign({}, parentContext, instance); - } - var createCursor = stack.createCursor, - push = stack.push, - pop = stack.pop, - contextStackCursor = createCursor(emptyObject), - didPerformWorkStackCursor = createCursor(!1), - previousContext = emptyObject; - return { - getUnmaskedContext: function(workInProgress) { - return isContextProvider(workInProgress) - ? previousContext - : contextStackCursor.current; - }, - cacheContext: cacheContext, - getMaskedContext: function(workInProgress, unmaskedContext) { - var contextTypes = workInProgress.type.contextTypes; - if (!contextTypes) return emptyObject; - var instance = workInProgress.stateNode; - if ( - instance && - instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext - ) - return instance.__reactInternalMemoizedMaskedChildContext; - var context = {}, - key; - for (key in contextTypes) context[key] = unmaskedContext[key]; - instance && cacheContext(workInProgress, unmaskedContext, context); - return context; - }, - hasContextChanged: function() { - return didPerformWorkStackCursor.current; - }, - isContextConsumer: function(fiber) { - return 2 === fiber.tag && null != fiber.type.contextTypes; - }, - isContextProvider: isContextProvider, - popContextProvider: function(fiber) { - isContextProvider(fiber) && - (pop(didPerformWorkStackCursor, fiber), pop(contextStackCursor, fiber)); - }, - popTopLevelContextObject: function(fiber) { - pop(didPerformWorkStackCursor, fiber); - pop(contextStackCursor, fiber); - }, - pushTopLevelContextObject: function(fiber, context, didChange) { - invariant( - null == contextStackCursor.cursor, - "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); - }, - processChildContext: processChildContext, - pushContextProvider: function(workInProgress) { - if (!isContextProvider(workInProgress)) return !1; - var instance = workInProgress.stateNode; - instance = - (instance && instance.__reactInternalMemoizedMergedChildContext) || - emptyObject; - previousContext = contextStackCursor.current; - push(contextStackCursor, instance, workInProgress); - push( - didPerformWorkStackCursor, - didPerformWorkStackCursor.current, - workInProgress - ); - return !0; - }, - invalidateContextProvider: function(workInProgress, didChange) { - var instance = workInProgress.stateNode; - invariant( - instance, - "Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue." - ); - if (didChange) { - var mergedContext = processChildContext( - workInProgress, - previousContext - ); - instance.__reactInternalMemoizedMergedChildContext = mergedContext; - pop(didPerformWorkStackCursor, workInProgress); - pop(contextStackCursor, workInProgress); - push(contextStackCursor, mergedContext, workInProgress); - } else pop(didPerformWorkStackCursor, workInProgress); - push(didPerformWorkStackCursor, didChange, workInProgress); - }, - findCurrentUnmaskedContext: function(fiber) { - for ( - invariant( - 2 === isFiberMountedImpl(fiber) && 2 === fiber.tag, - "Expected subtree parent to be a mounted class component. This error is likely caused by a bug in React. Please file an issue." - ); - 3 !== fiber.tag; - - ) { - if (isContextProvider(fiber)) - return fiber.stateNode.__reactInternalMemoizedMergedChildContext; - fiber = fiber["return"]; - invariant( - fiber, - "Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue." - ); - } - return fiber.stateNode.context; - } - }; -} -function ReactFiberNewContext(stack) { - var createCursor = stack.createCursor, - push = stack.push, - pop = stack.pop, - providerCursor = createCursor(null), - valueCursor = createCursor(null), - changedBitsCursor = createCursor(0); - return { - pushProvider: function(providerFiber) { - var context = providerFiber.type._context; - push(changedBitsCursor, context._changedBits, providerFiber); - push(valueCursor, context._currentValue, providerFiber); - push(providerCursor, providerFiber, providerFiber); - context._currentValue = providerFiber.pendingProps.value; - context._changedBits = providerFiber.stateNode; - }, - popProvider: function(providerFiber) { - var changedBits = changedBitsCursor.current, - currentValue = valueCursor.current; - pop(providerCursor, providerFiber); - pop(valueCursor, providerFiber); - pop(changedBitsCursor, providerFiber); - providerFiber = providerFiber.type._context; - providerFiber._currentValue = currentValue; - providerFiber._changedBits = changedBits; - } - }; -} -function ReactFiberStack() { - var valueStack = [], - index = -1; - return { - createCursor: function(defaultValue) { - return { current: defaultValue }; - }, - isEmpty: function() { - return -1 === index; - }, - pop: function(cursor) { - 0 > index || - ((cursor.current = valueStack[index]), - (valueStack[index] = null), - index--); - }, - push: function(cursor, value) { - index++; - valueStack[index] = cursor.current; - cursor.current = value; - }, - checkThatStackIsEmpty: function() {}, - resetStackAfterFatalErrorInDev: function() {} - }; -} -function ReactFiberScheduler(config) { - function resetStack() { - if (null !== nextUnitOfWork) - for ( - var interruptedWork = nextUnitOfWork["return"]; - null !== interruptedWork; - - ) - unwindInterruptedWork(interruptedWork), - (interruptedWork = interruptedWork["return"]); - nextRoot = null; - nextRenderExpirationTime = 0; - nextUnitOfWork = null; - isRootReadyForCommit = !1; - } - function isAlreadyFailedLegacyErrorBoundary(instance) { - return ( - null !== legacyErrorBoundariesThatAlreadyFailed && - legacyErrorBoundariesThatAlreadyFailed.has(instance) - ); - } - function completeUnitOfWork(workInProgress$jscomp$0) { - for (;;) { - var current = workInProgress$jscomp$0.alternate, - returnFiber = workInProgress$jscomp$0["return"], - siblingFiber = workInProgress$jscomp$0.sibling; - if (0 === (workInProgress$jscomp$0.effectTag & 512)) { - current = completeWork( - current, - workInProgress$jscomp$0, - nextRenderExpirationTime - ); - var workInProgress = workInProgress$jscomp$0; - if ( - 1073741823 === nextRenderExpirationTime || - 1073741823 !== workInProgress.expirationTime - ) { - b: switch (workInProgress.tag) { - case 3: - case 2: - var newExpirationTime = workInProgress.updateQueue; - newExpirationTime = - null === newExpirationTime - ? 0 - : newExpirationTime.expirationTime; - break b; - default: - newExpirationTime = 0; - } - for (var child = workInProgress.child; null !== child; ) - 0 !== child.expirationTime && - (0 === newExpirationTime || - newExpirationTime > child.expirationTime) && - (newExpirationTime = child.expirationTime), - (child = child.sibling); - workInProgress.expirationTime = newExpirationTime; - } - if (null !== current) return current; - null !== returnFiber && - 0 === (returnFiber.effectTag & 512) && - (null === returnFiber.firstEffect && - (returnFiber.firstEffect = workInProgress$jscomp$0.firstEffect), - null !== workInProgress$jscomp$0.lastEffect && - (null !== returnFiber.lastEffect && - (returnFiber.lastEffect.nextEffect = - workInProgress$jscomp$0.firstEffect), - (returnFiber.lastEffect = workInProgress$jscomp$0.lastEffect)), - 1 < workInProgress$jscomp$0.effectTag && - (null !== returnFiber.lastEffect - ? (returnFiber.lastEffect.nextEffect = workInProgress$jscomp$0) - : (returnFiber.firstEffect = workInProgress$jscomp$0), - (returnFiber.lastEffect = workInProgress$jscomp$0))); - if (null !== siblingFiber) return siblingFiber; - if (null !== returnFiber) workInProgress$jscomp$0 = returnFiber; - else { - isRootReadyForCommit = !0; - break; - } - } else { - workInProgress$jscomp$0 = unwindWork(workInProgress$jscomp$0); - if (null !== workInProgress$jscomp$0) - return ( - (workInProgress$jscomp$0.effectTag &= 2559), workInProgress$jscomp$0 - ); - null !== returnFiber && - ((returnFiber.firstEffect = returnFiber.lastEffect = null), - (returnFiber.effectTag |= 512)); - if (null !== siblingFiber) return siblingFiber; - if (null !== returnFiber) workInProgress$jscomp$0 = returnFiber; - else break; - } - } - return null; - } - function performUnitOfWork(workInProgress) { - var next = beginWork( - workInProgress.alternate, - workInProgress, - nextRenderExpirationTime - ); - null === next && (next = completeUnitOfWork(workInProgress)); - ReactCurrentOwner.current = null; - return next; - } - function renderRoot(root, expirationTime, isAsync) { - invariant( - !isWorking, - "renderRoot was called recursively. This error is likely caused by a bug in React. Please file an issue." - ); - isWorking = !0; - if ( - expirationTime !== nextRenderExpirationTime || - root !== nextRoot || - null === nextUnitOfWork - ) - resetStack(), - (nextRoot = root), - (nextRenderExpirationTime = expirationTime), - (nextUnitOfWork = createWorkInProgress( - nextRoot.current, - null, - nextRenderExpirationTime - )), - (root.pendingCommitExpirationTime = 0); - var didFatal = !1; - do { - try { - if (isAsync) - for (; null !== nextUnitOfWork && !shouldYield(); ) - nextUnitOfWork = performUnitOfWork(nextUnitOfWork); - else - for (; null !== nextUnitOfWork; ) - nextUnitOfWork = performUnitOfWork(nextUnitOfWork); - } catch (thrownValue) { - if (null === nextUnitOfWork) { - didFatal = !0; - onUncaughtError(thrownValue); - break; - } - isAsync = nextUnitOfWork; - var returnFiber = isAsync["return"]; - if (null === returnFiber) { - didFatal = !0; - onUncaughtError(thrownValue); - break; - } - throwException(returnFiber, isAsync, thrownValue); - nextUnitOfWork = completeUnitOfWork(isAsync); - } - break; - } while (1); - isWorking = !1; - if (didFatal || null !== nextUnitOfWork) return null; - if (isRootReadyForCommit) - return ( - (root.pendingCommitExpirationTime = expirationTime), - root.current.alternate - ); - invariant( - !1, - "Expired work should have completed. This error is likely caused by a bug in React. Please file an issue." - ); - } - function scheduleCapture(sourceFiber, boundaryFiber, value, expirationTime) { - sourceFiber = { - value: value, - source: sourceFiber, - stack: getStackAddendumByWorkInProgressFiber(sourceFiber) - }; - insertUpdateIntoFiber(boundaryFiber, { - expirationTime: expirationTime, - partialState: null, - callback: null, - isReplace: !1, - isForced: !1, - capturedValue: sourceFiber, - next: null - }); - scheduleWork(boundaryFiber, expirationTime); - } - function onCommitPhaseError(fiber$jscomp$0, error) { - a: { - invariant( - !isWorking || isCommitting, - "dispatch: Cannot dispatch during the render phase." - ); - for (var fiber = fiber$jscomp$0["return"]; null !== fiber; ) { - switch (fiber.tag) { - case 2: - var instance = fiber.stateNode; - if ( - "function" === typeof fiber.type.getDerivedStateFromCatch || - ("function" === typeof instance.componentDidCatch && - !isAlreadyFailedLegacyErrorBoundary(instance)) - ) { - scheduleCapture(fiber$jscomp$0, fiber, error, 1); - fiber$jscomp$0 = void 0; - break a; - } - break; - case 3: - scheduleCapture(fiber$jscomp$0, fiber, error, 1); - fiber$jscomp$0 = void 0; - break a; - } - fiber = fiber["return"]; - } - 3 === fiber$jscomp$0.tag && - scheduleCapture(fiber$jscomp$0, fiber$jscomp$0, error, 1); - fiber$jscomp$0 = void 0; - } - return fiber$jscomp$0; - } - function computeExpirationForFiber(fiber) { - fiber = - 0 !== expirationContext - ? expirationContext - : isWorking - ? isCommitting ? 1 : nextRenderExpirationTime - : fiber.mode & 1 - ? isBatchingInteractiveUpdates - ? 10 * ((((recalculateCurrentTime() + 15) / 10) | 0) + 1) - : 25 * ((((recalculateCurrentTime() + 500) / 25) | 0) + 1) - : 1; - isBatchingInteractiveUpdates && - (0 === lowestPendingInteractiveExpirationTime || - fiber > lowestPendingInteractiveExpirationTime) && - (lowestPendingInteractiveExpirationTime = fiber); - return fiber; - } - function scheduleWork(fiber, expirationTime) { - a: { - for (; null !== fiber; ) { - if (0 === fiber.expirationTime || fiber.expirationTime > expirationTime) - fiber.expirationTime = expirationTime; - null !== fiber.alternate && - (0 === fiber.alternate.expirationTime || - fiber.alternate.expirationTime > expirationTime) && - (fiber.alternate.expirationTime = expirationTime); - if (null === fiber["return"]) - if (3 === fiber.tag) { - var root = fiber.stateNode; - !isWorking && - 0 !== nextRenderExpirationTime && - expirationTime < nextRenderExpirationTime && - resetStack(); - (isWorking && !isCommitting && nextRoot === root) || - requestWork(root, expirationTime); - nestedUpdateCount > NESTED_UPDATE_LIMIT && - invariant( - !1, - "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." - ); - } else { - expirationTime = void 0; - break a; - } - fiber = fiber["return"]; - } - expirationTime = void 0; - } - return expirationTime; - } - function recalculateCurrentTime() { - mostRecentCurrentTimeMs = now() - originalStartTimeMs; - return (mostRecentCurrentTime = ((mostRecentCurrentTimeMs / 10) | 0) + 2); - } - function syncUpdates(fn, a, b, c, d) { - var previousExpirationContext = expirationContext; - expirationContext = 1; - try { - return fn(a, b, c, d); - } finally { - expirationContext = previousExpirationContext; - } - } - function scheduleCallbackWithExpiration(expirationTime) { - if (0 !== callbackExpirationTime) { - if (expirationTime > callbackExpirationTime) return; - cancelDeferredCallback(callbackID); - } - var currentMs = now() - originalStartTimeMs; - callbackExpirationTime = expirationTime; - callbackID = scheduleDeferredCallback(performAsyncWork, { - timeout: 10 * (expirationTime - 2) - currentMs - }); - } - function requestWork(root, expirationTime) { - if (null === root.nextScheduledRoot) - (root.remainingExpirationTime = expirationTime), - null === lastScheduledRoot - ? ((firstScheduledRoot = lastScheduledRoot = root), - (root.nextScheduledRoot = root)) - : ((lastScheduledRoot = lastScheduledRoot.nextScheduledRoot = root), - (lastScheduledRoot.nextScheduledRoot = firstScheduledRoot)); - else { - var remainingExpirationTime = root.remainingExpirationTime; - if ( - 0 === remainingExpirationTime || - expirationTime < remainingExpirationTime - ) - root.remainingExpirationTime = expirationTime; - } - isRendering || - (isBatchingUpdates - ? isUnbatchingUpdates && - ((nextFlushedRoot = root), - (nextFlushedExpirationTime = 1), - performWorkOnRoot(root, 1, !1)) - : 1 === expirationTime - ? performSyncWork() - : scheduleCallbackWithExpiration(expirationTime)); - } - function findHighestPriorityRoot() { - var highestPriorityWork = 0, - highestPriorityRoot = null; - if (null !== lastScheduledRoot) - for ( - var previousScheduledRoot = lastScheduledRoot, - root = firstScheduledRoot; - null !== root; - - ) { - var remainingExpirationTime = root.remainingExpirationTime; - if (0 === remainingExpirationTime) { - invariant( - null !== previousScheduledRoot && null !== lastScheduledRoot, - "Should have a previous and last root. This error is likely caused by a bug in React. Please file an issue." - ); - if (root === root.nextScheduledRoot) { - firstScheduledRoot = lastScheduledRoot = root.nextScheduledRoot = null; - break; - } else if (root === firstScheduledRoot) - (firstScheduledRoot = remainingExpirationTime = - root.nextScheduledRoot), - (lastScheduledRoot.nextScheduledRoot = remainingExpirationTime), - (root.nextScheduledRoot = null); - else if (root === lastScheduledRoot) { - lastScheduledRoot = previousScheduledRoot; - lastScheduledRoot.nextScheduledRoot = firstScheduledRoot; - root.nextScheduledRoot = null; - break; - } else - (previousScheduledRoot.nextScheduledRoot = root.nextScheduledRoot), - (root.nextScheduledRoot = null); - root = previousScheduledRoot.nextScheduledRoot; - } else { - if ( - 0 === highestPriorityWork || - remainingExpirationTime < highestPriorityWork - ) - (highestPriorityWork = remainingExpirationTime), - (highestPriorityRoot = root); - if (root === lastScheduledRoot) break; - previousScheduledRoot = root; - root = root.nextScheduledRoot; - } - } - previousScheduledRoot = nextFlushedRoot; - null !== previousScheduledRoot && - previousScheduledRoot === highestPriorityRoot && - 1 === highestPriorityWork - ? nestedUpdateCount++ - : (nestedUpdateCount = 0); - nextFlushedRoot = highestPriorityRoot; - nextFlushedExpirationTime = highestPriorityWork; - } - function performAsyncWork(dl) { - performWork(0, !0, dl); - } - function performSyncWork() { - performWork(1, !1, null); - } - function performWork(minExpirationTime, isAsync, dl) { - deadline = dl; - findHighestPriorityRoot(); - if (isAsync) - for ( - ; - null !== nextFlushedRoot && - 0 !== nextFlushedExpirationTime && - (0 === minExpirationTime || - minExpirationTime >= nextFlushedExpirationTime) && - (!deadlineDidExpire || - recalculateCurrentTime() >= nextFlushedExpirationTime); - - ) - performWorkOnRoot( - nextFlushedRoot, - nextFlushedExpirationTime, - !deadlineDidExpire - ), - findHighestPriorityRoot(); - else - for ( - ; - null !== nextFlushedRoot && - 0 !== nextFlushedExpirationTime && - (0 === minExpirationTime || - minExpirationTime >= nextFlushedExpirationTime); - - ) - performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime, !1), - findHighestPriorityRoot(); - null !== deadline && ((callbackExpirationTime = 0), (callbackID = -1)); - 0 !== nextFlushedExpirationTime && - scheduleCallbackWithExpiration(nextFlushedExpirationTime); - deadline = null; - deadlineDidExpire = !1; - finishRendering(); - } - function finishRendering() { - nestedUpdateCount = 0; - if (null !== completedBatches) { - var batches = completedBatches; - completedBatches = null; - for (var i = 0; i < batches.length; i++) { - var batch = batches[i]; - try { - batch._onComplete(); - } catch (error) { - hasUnhandledError || - ((hasUnhandledError = !0), (unhandledError = error)); - } - } - } - if (hasUnhandledError) - throw ((batches = unhandledError), - (unhandledError = null), - (hasUnhandledError = !1), - batches); - } - function performWorkOnRoot(root, expirationTime, isAsync) { - invariant( - !isRendering, - "performWorkOnRoot was called recursively. This error is likely caused by a bug in React. Please file an issue." - ); - isRendering = !0; - isAsync - ? ((isAsync = root.finishedWork), - null !== isAsync - ? completeRoot(root, isAsync, expirationTime) - : ((root.finishedWork = null), - (isAsync = renderRoot(root, expirationTime, !0)), - null !== isAsync && - (shouldYield() - ? (root.finishedWork = isAsync) - : completeRoot(root, isAsync, expirationTime)))) - : ((isAsync = root.finishedWork), - null !== isAsync - ? completeRoot(root, isAsync, expirationTime) - : ((root.finishedWork = null), - (isAsync = renderRoot(root, expirationTime, !1)), - null !== isAsync && completeRoot(root, isAsync, expirationTime))); - isRendering = !1; - } - function completeRoot(root, finishedWork, expirationTime) { - var firstBatch = root.firstBatch; - if ( - null !== firstBatch && - firstBatch._expirationTime <= expirationTime && - (null === completedBatches - ? (completedBatches = [firstBatch]) - : completedBatches.push(firstBatch), - firstBatch._defer) - ) { - root.finishedWork = finishedWork; - root.remainingExpirationTime = 0; - return; - } - root.finishedWork = null; - isCommitting = isWorking = !0; - expirationTime = finishedWork.stateNode; - invariant( - expirationTime.current !== finishedWork, - "Cannot commit the same tree as before. This is probably a bug related to the return field. This error is likely caused by a bug in React. Please file an issue." - ); - firstBatch = expirationTime.pendingCommitExpirationTime; - invariant( - 0 !== firstBatch, - "Cannot commit an incomplete root. This error is likely caused by a bug in React. Please file an issue." - ); - expirationTime.pendingCommitExpirationTime = 0; - var currentTime = recalculateCurrentTime(); - ReactCurrentOwner.current = null; - if (1 < finishedWork.effectTag) - if (null !== finishedWork.lastEffect) { - finishedWork.lastEffect.nextEffect = finishedWork; - var firstEffect = finishedWork.firstEffect; - } else firstEffect = finishedWork; - else firstEffect = finishedWork.firstEffect; - prepareForCommit(expirationTime.containerInfo); - for (nextEffect = firstEffect; null !== nextEffect; ) { - var didError = !1, - error = void 0; - try { - for (; null !== nextEffect; ) - nextEffect.effectTag & 2048 && - commitBeforeMutationLifeCycles(nextEffect.alternate, nextEffect), - (nextEffect = nextEffect.nextEffect); - } catch (e) { - (didError = !0), (error = e); - } - didError && - (invariant( - null !== nextEffect, - "Should have next effect. This error is likely caused by a bug in React. Please file an issue." - ), - onCommitPhaseError(nextEffect, error), - null !== nextEffect && (nextEffect = nextEffect.nextEffect)); - } - for (nextEffect = firstEffect; null !== nextEffect; ) { - didError = !1; - error = void 0; - try { - for (; null !== nextEffect; ) { - var effectTag = nextEffect.effectTag; - effectTag & 16 && commitResetTextContent(nextEffect); - if (effectTag & 128) { - var current = nextEffect.alternate; - null !== current && commitDetachRef(current); - } - 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: - commitDeletion(nextEffect); - } - nextEffect = nextEffect.nextEffect; - } - } catch (e) { - (didError = !0), (error = e); - } - didError && - (invariant( - null !== nextEffect, - "Should have next effect. This error is likely caused by a bug in React. Please file an issue." - ), - onCommitPhaseError(nextEffect, error), - null !== nextEffect && (nextEffect = nextEffect.nextEffect)); - } - resetAfterCommit(expirationTime.containerInfo); - expirationTime.current = finishedWork; - for (nextEffect = firstEffect; null !== nextEffect; ) { - effectTag = !1; - current = void 0; - try { - for ( - firstEffect = expirationTime, - didError = currentTime, - error = firstBatch; - null !== nextEffect; - - ) { - var effectTag$jscomp$0 = nextEffect.effectTag; - effectTag$jscomp$0 & 36 && - commitLifeCycles( - firstEffect, - nextEffect.alternate, - nextEffect, - didError, - error - ); - effectTag$jscomp$0 & 256 && - commitErrorLogging(nextEffect, onUncaughtError); - effectTag$jscomp$0 & 128 && commitAttachRef(nextEffect); - var next = nextEffect.nextEffect; - nextEffect.nextEffect = null; - nextEffect = next; - } - } catch (e) { - (effectTag = !0), (current = e); - } - effectTag && - (invariant( - null !== nextEffect, - "Should have next effect. This error is likely caused by a bug in React. Please file an issue." - ), - onCommitPhaseError(nextEffect, current), - null !== nextEffect && (nextEffect = nextEffect.nextEffect)); - } - isWorking = isCommitting = !1; - "function" === typeof onCommitRoot && onCommitRoot(finishedWork.stateNode); - finishedWork = expirationTime.current.expirationTime; - 0 === finishedWork && (legacyErrorBoundariesThatAlreadyFailed = null); - root.remainingExpirationTime = finishedWork; - } - function shouldYield() { - return null === deadline || - deadline.timeRemaining() > timeHeuristicForUnitOfWork - ? !1 - : (deadlineDidExpire = !0); - } - function onUncaughtError(error) { - invariant( - null !== nextFlushedRoot, - "Should be working on a root. This error is likely caused by a bug in React. Please file an issue." - ); - nextFlushedRoot.remainingExpirationTime = 0; - hasUnhandledError || ((hasUnhandledError = !0), (unhandledError = error)); - } - var stack = ReactFiberStack(), - hostContext = ReactFiberHostContext(config, stack), - legacyContext = ReactFiberLegacyContext(stack); - stack = ReactFiberNewContext(stack); - var hydrationContext = ReactFiberHydrationContext(config), - beginWork = ReactFiberBeginWork( - config, - hostContext, - legacyContext, - stack, - hydrationContext, - scheduleWork, - computeExpirationForFiber - ).beginWork, - completeWork = ReactFiberCompleteWork( - config, - hostContext, - legacyContext, - stack, - hydrationContext - ).completeWork; - hostContext = ReactFiberUnwindWork( - hostContext, - legacyContext, - stack, - scheduleWork, - isAlreadyFailedLegacyErrorBoundary - ); - var throwException = hostContext.throwException, - unwindWork = hostContext.unwindWork, - unwindInterruptedWork = hostContext.unwindInterruptedWork; - hostContext = ReactFiberCommitWork( - config, - onCommitPhaseError, - scheduleWork, - computeExpirationForFiber, - function(instance) { - null === legacyErrorBoundariesThatAlreadyFailed - ? (legacyErrorBoundariesThatAlreadyFailed = new Set([instance])) - : legacyErrorBoundariesThatAlreadyFailed.add(instance); - }, - recalculateCurrentTime - ); - var commitBeforeMutationLifeCycles = - hostContext.commitBeforeMutationLifeCycles, - commitResetTextContent = hostContext.commitResetTextContent, - commitPlacement = hostContext.commitPlacement, - commitDeletion = hostContext.commitDeletion, - commitWork = hostContext.commitWork, - commitLifeCycles = hostContext.commitLifeCycles, - commitErrorLogging = hostContext.commitErrorLogging, - commitAttachRef = hostContext.commitAttachRef, - commitDetachRef = hostContext.commitDetachRef, - now = config.now, - scheduleDeferredCallback = config.scheduleDeferredCallback, - cancelDeferredCallback = config.cancelDeferredCallback, - prepareForCommit = config.prepareForCommit, - resetAfterCommit = config.resetAfterCommit, - originalStartTimeMs = now(), - mostRecentCurrentTime = 2, - mostRecentCurrentTimeMs = originalStartTimeMs, - lastUniqueAsyncExpiration = 0, - expirationContext = 0, - isWorking = !1, - nextUnitOfWork = null, - nextRoot = null, - nextRenderExpirationTime = 0, - nextEffect = null, - isCommitting = !1, - isRootReadyForCommit = !1, - legacyErrorBoundariesThatAlreadyFailed = null, - firstScheduledRoot = null, - lastScheduledRoot = null, - callbackExpirationTime = 0, - callbackID = -1, - isRendering = !1, - nextFlushedRoot = null, - nextFlushedExpirationTime = 0, - lowestPendingInteractiveExpirationTime = 0, - deadlineDidExpire = !1, - hasUnhandledError = !1, - unhandledError = null, - deadline = null, - isBatchingUpdates = !1, - isUnbatchingUpdates = !1, - isBatchingInteractiveUpdates = !1, - completedBatches = null, - NESTED_UPDATE_LIMIT = 1e3, - nestedUpdateCount = 0, - timeHeuristicForUnitOfWork = 1; - return { - recalculateCurrentTime: recalculateCurrentTime, - computeExpirationForFiber: computeExpirationForFiber, - scheduleWork: scheduleWork, - requestWork: requestWork, - flushRoot: function(root, expirationTime) { - invariant( - !isRendering, - "work.commit(): Cannot commit while already rendering. This likely means you attempted to commit from inside a lifecycle method." - ); - nextFlushedRoot = root; - nextFlushedExpirationTime = expirationTime; - performWorkOnRoot(root, expirationTime, !1); - performSyncWork(); - finishRendering(); - }, - batchedUpdates: function(fn, a) { - var previousIsBatchingUpdates = isBatchingUpdates; - isBatchingUpdates = !0; - try { - return fn(a); - } finally { - (isBatchingUpdates = previousIsBatchingUpdates) || - isRendering || - performSyncWork(); - } - }, - unbatchedUpdates: function(fn, a) { - if (isBatchingUpdates && !isUnbatchingUpdates) { - isUnbatchingUpdates = !0; - try { - return fn(a); - } finally { - isUnbatchingUpdates = !1; - } - } - return fn(a); - }, - flushSync: function(fn, a) { - invariant( - !isRendering, - "flushSync was called from inside a lifecycle method. It cannot be called when React is already rendering." - ); - var previousIsBatchingUpdates = isBatchingUpdates; - isBatchingUpdates = !0; - try { - return syncUpdates(fn, a); - } finally { - (isBatchingUpdates = previousIsBatchingUpdates), performSyncWork(); - } - }, - flushControlled: function(fn) { - var previousIsBatchingUpdates = isBatchingUpdates; - isBatchingUpdates = !0; - try { - syncUpdates(fn); - } finally { - (isBatchingUpdates = previousIsBatchingUpdates) || - isRendering || - performWork(1, !1, null); - } - }, - deferredUpdates: function(fn) { - var previousExpirationContext = expirationContext; - expirationContext = - 25 * ((((recalculateCurrentTime() + 500) / 25) | 0) + 1); - try { - return fn(); - } finally { - expirationContext = previousExpirationContext; - } - }, - syncUpdates: syncUpdates, - interactiveUpdates: function(fn, a, b) { - if (isBatchingInteractiveUpdates) return fn(a, b); - isBatchingUpdates || - isRendering || - 0 === lowestPendingInteractiveExpirationTime || - (performWork(lowestPendingInteractiveExpirationTime, !1, null), - (lowestPendingInteractiveExpirationTime = 0)); - var previousIsBatchingInteractiveUpdates = isBatchingInteractiveUpdates, - previousIsBatchingUpdates = isBatchingUpdates; - isBatchingUpdates = isBatchingInteractiveUpdates = !0; - try { - return fn(a, b); - } finally { - (isBatchingInteractiveUpdates = previousIsBatchingInteractiveUpdates), - (isBatchingUpdates = previousIsBatchingUpdates) || - isRendering || - performSyncWork(); - } - }, - flushInteractiveUpdates: function() { - isRendering || - 0 === lowestPendingInteractiveExpirationTime || - (performWork(lowestPendingInteractiveExpirationTime, !1, null), - (lowestPendingInteractiveExpirationTime = 0)); - }, - computeUniqueAsyncExpiration: function() { - var result = 25 * ((((recalculateCurrentTime() + 500) / 25) | 0) + 1); - result <= lastUniqueAsyncExpiration && - (result = lastUniqueAsyncExpiration + 1); - return (lastUniqueAsyncExpiration = result); - }, - legacyContext: legacyContext - }; -} -function ReactFiberReconciler$1(config) { - function updateContainerAtExpirationTime( - element, - container, - parentComponent, - currentTime, - expirationTime, - callback - ) { - currentTime = container.current; - if (parentComponent) { - parentComponent = parentComponent._reactInternalFiber; - var parentContext = findCurrentUnmaskedContext(parentComponent); - parentComponent = isContextProvider(parentComponent) - ? processChildContext(parentComponent, parentContext) - : parentContext; - } else parentComponent = emptyObject; - null === container.context - ? (container.context = parentComponent) - : (container.pendingContext = parentComponent); - container = callback; - insertUpdateIntoFiber(currentTime, { - expirationTime: expirationTime, - partialState: { element: element }, - callback: void 0 === container ? null : container, - isReplace: !1, - isForced: !1, - capturedValue: null, - next: null - }); - scheduleWork(currentTime, expirationTime); - return expirationTime; - } - var getPublicInstance = config.getPublicInstance; - config = ReactFiberScheduler(config); - var recalculateCurrentTime = config.recalculateCurrentTime, - computeExpirationForFiber = config.computeExpirationForFiber, - scheduleWork = config.scheduleWork, - legacyContext = config.legacyContext, - findCurrentUnmaskedContext = legacyContext.findCurrentUnmaskedContext, - isContextProvider = legacyContext.isContextProvider, - processChildContext = legacyContext.processChildContext; - return { - createContainer: function(containerInfo, isAsync, hydrate) { - isAsync = new FiberNode(3, null, null, isAsync ? 3 : 0); - containerInfo = { - current: isAsync, - containerInfo: containerInfo, - pendingChildren: null, - pendingCommitExpirationTime: 0, - finishedWork: null, - context: null, - pendingContext: null, - hydrate: hydrate, - remainingExpirationTime: 0, - firstBatch: null, - nextScheduledRoot: null - }; - return (isAsync.stateNode = containerInfo); - }, - updateContainer: function(element, container, parentComponent, callback) { - var current = container.current, - currentTime = recalculateCurrentTime(); - current = computeExpirationForFiber(current); - return updateContainerAtExpirationTime( - element, - container, - parentComponent, - currentTime, - current, - callback - ); - }, - updateContainerAtExpirationTime: function( - element, - container, - parentComponent, - expirationTime, - callback - ) { - var currentTime = recalculateCurrentTime(); - return updateContainerAtExpirationTime( - element, - container, - parentComponent, - currentTime, - expirationTime, - callback - ); - }, - flushRoot: config.flushRoot, - requestWork: config.requestWork, - computeUniqueAsyncExpiration: config.computeUniqueAsyncExpiration, - batchedUpdates: config.batchedUpdates, - unbatchedUpdates: config.unbatchedUpdates, - deferredUpdates: config.deferredUpdates, - syncUpdates: config.syncUpdates, - interactiveUpdates: config.interactiveUpdates, - flushInteractiveUpdates: config.flushInteractiveUpdates, - flushControlled: config.flushControlled, - flushSync: config.flushSync, - getPublicRootInstance: function(container) { - container = container.current; - if (!container.child) return null; - switch (container.child.tag) { - case 5: - return getPublicInstance(container.child.stateNode); - default: - return container.child.stateNode; - } - }, - findHostInstance: function(component) { - var fiber = component._reactInternalFiber; - void 0 === fiber && - ("function" === typeof component.render - ? invariant(!1, "Unable to find node on an unmounted component.") - : invariant( - !1, - "Argument appears to not be a ReactComponent. Keys: %s", - Object.keys(component) - )); - component = findCurrentHostFiber(fiber); - return null === component ? null : component.stateNode; - }, - findHostInstanceWithNoPortals: function(fiber) { - fiber = findCurrentHostFiberWithNoPortals(fiber); - return null === fiber ? null : fiber.stateNode; - }, - injectIntoDevTools: function(devToolsConfig) { - var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; - return injectInternals( - Object.assign({}, devToolsConfig, { - findHostInstanceByFiber: function(fiber) { - fiber = findCurrentHostFiber(fiber); - return null === fiber ? null : fiber.stateNode; - }, - findFiberByHostInstance: function(instance) { - return findFiberByHostInstance - ? findFiberByHostInstance(instance) - : null; - } - }) - ); - } - }; -} -var ReactFiberReconciler$2 = Object.freeze({ default: ReactFiberReconciler$1 }), - ReactFiberReconciler$3 = - (ReactFiberReconciler$2 && ReactFiberReconciler$1) || - ReactFiberReconciler$2, - reactReconciler = ReactFiberReconciler$3["default"] - ? ReactFiberReconciler$3["default"] - : ReactFiberReconciler$3, - 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() { - TextInputState.blurTextInput(this._nativeTag); - }; - ReactNativeFiberHostComponent.prototype.focus = function() { - TextInputState.focusTextInput(this._nativeTag); - }; - ReactNativeFiberHostComponent.prototype.measure = function(callback) { - UIManager.measure(this._nativeTag, mountSafeCallback(this, callback)); - }; - ReactNativeFiberHostComponent.prototype.measureInWindow = function( - callback - ) { - UIManager.measureInWindow( - this._nativeTag, - mountSafeCallback(this, callback) - ); - }; - ReactNativeFiberHostComponent.prototype.measureLayout = function( - relativeToNativeNode, - onSuccess, - onFail - ) { - UIManager.measureLayout( - this._nativeTag, - relativeToNativeNode, - mountSafeCallback(this, onFail), - mountSafeCallback(this, onSuccess) - ); - }; - ReactNativeFiberHostComponent.prototype.setNativeProps = function( - nativeProps - ) { - nativeProps = diffProperties( - null, - emptyObject$1, - nativeProps, - this.viewConfig.validAttributes - ); - null != nativeProps && - UIManager.updateView( - this._nativeTag, - this.viewConfig.uiViewClassName, - nativeProps - ); - }; - return ReactNativeFiberHostComponent; - })(), - now = - "object" === typeof performance && "function" === typeof performance.now - ? function() { - return performance.now(); - } - : function() { - return Date.now(); - }, - scheduledCallback = null, - frameDeadline = 0, - frameDeadlineObject = { - timeRemaining: function() { - return frameDeadline - now(); - }, - didTimeout: !1 - }; -function setTimeoutCallback() { - frameDeadline = now() + 5; - var callback = scheduledCallback; - scheduledCallback = null; - null !== callback && callback(frameDeadlineObject); -} -var nextReactTag = 3; -function allocateTag() { - var tag = nextReactTag; - 1 === tag % 10 && (tag += 2); - nextReactTag = tag + 2; - return tag; -} -function recursivelyUncacheFiberNode(node) { - "number" === typeof node - ? uncacheFiberNode(node) - : (uncacheFiberNode(node._nativeTag), - node._children.forEach(recursivelyUncacheFiberNode)); -} -var NativeRenderer = reactReconciler({ - appendInitialChild: function(parentInstance, child) { - parentInstance._children.push(child); - }, - createInstance: function( - type, - props, - rootContainerInstance, - hostContext, - internalInstanceHandle - ) { - hostContext = allocateTag(); - type = ReactNativeViewConfigRegistry.get(type); - var updatePayload = diffProperties( - null, - emptyObject$1, - props, - type.validAttributes - ); - UIManager.createView( - hostContext, - type.uiViewClassName, - rootContainerInstance, - updatePayload - ); - rootContainerInstance = new ReactNativeFiberHostComponent( - hostContext, - type - ); - instanceCache[hostContext] = internalInstanceHandle; - instanceProps[hostContext] = props; - return rootContainerInstance; - }, - createTextInstance: function( - text, - rootContainerInstance, - hostContext, - internalInstanceHandle - ) { - hostContext = allocateTag(); - UIManager.createView(hostContext, "RCTRawText", rootContainerInstance, { - text: text - }); - instanceCache[hostContext] = internalInstanceHandle; - return hostContext; - }, - finalizeInitialChildren: function(parentInstance) { - if (0 === parentInstance._children.length) return !1; - var nativeTags = parentInstance._children.map(function(child) { - return "number" === typeof child ? child : child._nativeTag; - }); - UIManager.setChildren(parentInstance._nativeTag, nativeTags); - return !1; - }, - getRootHostContext: function() { - return emptyObject; - }, - getChildHostContext: function() { - return emptyObject; - }, - getPublicInstance: function(instance) { - return instance; - }, - now: now, - prepareForCommit: function() {}, - prepareUpdate: function() { - return emptyObject; - }, - resetAfterCommit: function() {}, - scheduleDeferredCallback: function(callback) { - scheduledCallback = callback; - return setTimeout(setTimeoutCallback, 1); - }, - cancelDeferredCallback: function(callbackID) { - scheduledCallback = null; - clearTimeout(callbackID); - }, - shouldDeprioritizeSubtree: function() { - return !1; - }, - shouldSetTextContent: function() { - return !1; - }, - mutation: { - appendChild: function(parentInstance, child) { - var childTag = "number" === typeof child ? child : child._nativeTag, - children = parentInstance._children, - index = children.indexOf(child); - 0 <= index - ? (children.splice(index, 1), - children.push(child), - UIManager.manageChildren( - parentInstance._nativeTag, - [index], - [children.length - 1], - [], - [], - [] - )) - : (children.push(child), - UIManager.manageChildren( - parentInstance._nativeTag, - [], - [], - [childTag], - [children.length - 1], - [] - )); - }, - appendChildToContainer: function(parentInstance, child) { - UIManager.setChildren(parentInstance, [ - "number" === typeof child ? child : child._nativeTag - ]); - }, - commitTextUpdate: function(textInstance, oldText, newText) { - UIManager.updateView(textInstance, "RCTRawText", { text: newText }); - }, - commitMount: function() {}, - commitUpdate: function( - instance, - updatePayloadTODO, - type, - oldProps, - newProps - ) { - updatePayloadTODO = instance.viewConfig; - instanceProps[instance._nativeTag] = newProps; - oldProps = diffProperties( - null, - oldProps, - newProps, - updatePayloadTODO.validAttributes - ); - null != oldProps && - UIManager.updateView( - instance._nativeTag, - updatePayloadTODO.uiViewClassName, - oldProps - ); - }, - insertBefore: function(parentInstance, child, beforeChild) { - var children = parentInstance._children, - index = children.indexOf(child); - 0 <= index - ? (children.splice(index, 1), - (beforeChild = children.indexOf(beforeChild)), - children.splice(beforeChild, 0, child), - UIManager.manageChildren( - parentInstance._nativeTag, - [index], - [beforeChild], - [], - [], - [] - )) - : ((index = children.indexOf(beforeChild)), - children.splice(index, 0, child), - UIManager.manageChildren( - parentInstance._nativeTag, - [], - [], - ["number" === typeof child ? child : child._nativeTag], - [index], - [] - )); - }, - insertInContainerBefore: function(parentInstance) { - invariant( - "number" !== typeof parentInstance, - "Container does not support insertBefore operation" - ); - }, - removeChild: function(parentInstance, child) { - recursivelyUncacheFiberNode(child); - var children = parentInstance._children; - child = children.indexOf(child); - children.splice(child, 1); - UIManager.manageChildren( - parentInstance._nativeTag, - [], - [], - [], - [], - [child] - ); - }, - removeChildFromContainer: function(parentInstance, child) { - recursivelyUncacheFiberNode(child); - UIManager.manageChildren(parentInstance, [], [], [], [], [0]); - }, - resetTextContent: function() {} - } - }), - getInspectorDataForViewTag = void 0; -getInspectorDataForViewTag = function() { - invariant(!1, "getInspectorDataForViewTag() is not available in production"); -}; -var findHostInstance = NativeRenderer.findHostInstance; -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; -} -_batchedUpdates = NativeRenderer.batchedUpdates; -_flushInteractiveUpdates = NativeRenderer.flushInteractiveUpdates; -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() { - TextInputState.blurTextInput(findNodeHandle(this)); - }; - ReactNativeComponent.prototype.focus = function() { - TextInputState.focusTextInput(findNodeHandle(this)); - }; - ReactNativeComponent.prototype.measure = function(callback) { - UIManager.measure( - findNodeHandle(this), - mountSafeCallback(this, callback) - ); - }; - ReactNativeComponent.prototype.measureInWindow = function(callback) { - UIManager.measureInWindow( - findNodeHandle(this), - mountSafeCallback(this, callback) - ); - }; - ReactNativeComponent.prototype.measureLayout = function( - relativeToNativeNode, - onSuccess, - onFail - ) { - UIManager.measureLayout( - findNodeHandle(this), - relativeToNativeNode, - mountSafeCallback(this, onFail), - mountSafeCallback(this, onSuccess) - ); - }; - ReactNativeComponent.prototype.setNativeProps = function(nativeProps) { - var maybeInstance = void 0; - try { - maybeInstance = findHostInstance(this); - } catch (error) {} - if (null != maybeInstance) { - var viewConfig = - maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; - nativeProps = diffProperties( - null, - emptyObject$1, - nativeProps, - viewConfig.validAttributes - ); - null != nativeProps && - UIManager.updateView( - maybeInstance._nativeTag, - viewConfig.uiViewClassName, - nativeProps - ); - } - }; - return ReactNativeComponent; - })(React.Component); - })(findNodeHandle, findHostInstance), - findNodeHandle: findNodeHandle, - render: function(element, containerTag, callback) { - var root = roots.get(containerTag); - root || - ((root = NativeRenderer.createContainer(containerTag, !1, !1)), - roots.set(containerTag, root)); - NativeRenderer.updateContainer(element, root, null, callback); - return NativeRenderer.getPublicRootInstance(root); - }, - unmountComponentAtNode: function(containerTag) { - var root = roots.get(containerTag); - root && - NativeRenderer.updateContainer(null, root, null, function() { - roots["delete"](containerTag); - }); - }, - unmountComponentAtNodeAndRemoveContainer: function(containerTag) { - ReactNativeRenderer.unmountComponentAtNode(containerTag); - 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) { - UIManager.measure( - findNodeHandle(this), - mountSafeCallback(this, callback) - ); - }, - measureInWindow: function(callback) { - UIManager.measureInWindow( - findNodeHandle(this), - mountSafeCallback(this, callback) - ); - }, - measureLayout: function(relativeToNativeNode, onSuccess, onFail) { - UIManager.measureLayout( - findNodeHandle(this), - relativeToNativeNode, - mountSafeCallback(this, onFail), - mountSafeCallback(this, onSuccess) - ); - }, - setNativeProps: function(nativeProps) { - var maybeInstance = void 0; - try { - maybeInstance = findHostInstance(this); - } catch (error) {} - if (null != maybeInstance) { - var viewConfig = maybeInstance.viewConfig; - nativeProps = diffProperties( - null, - emptyObject$1, - nativeProps, - viewConfig.validAttributes - ); - null != nativeProps && - UIManager.updateView( - maybeInstance._nativeTag, - viewConfig.uiViewClassName, - nativeProps - ); - } - }, - focus: function() { - TextInputState.focusTextInput(findNodeHandle(this)); - }, - blur: function() { - TextInputState.blurTextInput(findNodeHandle(this)); - } - }; - })(findNodeHandle, findHostInstance), - ReactNativeComponentTree: ReactNativeComponentTree, - computeComponentStackForErrorReporting: function(reactTag) { - return (reactTag = getInstanceFromTag(reactTag)) - ? getStackAddendumByWorkInProgressFiber(reactTag) - : ""; - } - } - }; -NativeRenderer.injectIntoDevTools({ - findFiberByHostInstance: getInstanceFromTag, - getInspectorDataForViewTag: getInspectorDataForViewTag, - bundleType: 0, - version: "16.3.2", - rendererPackageName: "react-native-renderer" -}); -var ReactNativeRenderer$2 = Object.freeze({ default: ReactNativeRenderer }), - ReactNativeRenderer$3 = - (ReactNativeRenderer$2 && ReactNativeRenderer) || ReactNativeRenderer$2; -module.exports = ReactNativeRenderer$3["default"] - ? ReactNativeRenderer$3["default"] - : ReactNativeRenderer$3; From 931930ae63d8866cd0d5bfa001a6c872f751df0c Mon Sep 17 00:00:00 2001 From: Nat Mote Date: Fri, 20 Apr 2018 10:40:28 -0700 Subject: [PATCH 0357/1109] Remove non-top-level export from JSTimers Reviewed By: davidaurelio Differential Revision: D7705416 fbshipit-source-id: 1252789c2cd59b8666b57edcf17948c102e63888 --- Libraries/Core/Timers/JSTimers.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Libraries/Core/Timers/JSTimers.js b/Libraries/Core/Timers/JSTimers.js index 5fae3408aa5158..e0b4fbbd8866ac 100644 --- a/Libraries/Core/Timers/JSTimers.js +++ b/Libraries/Core/Timers/JSTimers.js @@ -483,13 +483,16 @@ const JSTimers = { }, }; +let ExportedJSTimers; if (!Timing) { console.warn("Timing native module is not available, can't set timers."); // $FlowFixMe: we can assume timers are generally available - module.exports = ({ + ExportedJSTimers = ({ callImmediates: JSTimers.callImmediates, setImmediate: JSTimers.setImmediate, }: typeof JSTimers); } else { - module.exports = JSTimers; + ExportedJSTimers = JSTimers; } + +module.exports = ExportedJSTimers; From 06ec0f0fd1b85c07dd76f9cd37a1c36264196b08 Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Fri, 20 Apr 2018 14:03:33 -0700 Subject: [PATCH 0358/1109] Expose the asyncRequireModulePath param Reviewed By: mjesun Differential Revision: D7709569 fbshipit-source-id: 871dd9c178b1e5c81163558201ef983315561211 --- local-cli/bundle/buildBundle.js | 1 + local-cli/server/runServer.js | 1 + 2 files changed, 2 insertions(+) diff --git a/local-cli/bundle/buildBundle.js b/local-cli/bundle/buildBundle.js index 99c45ddc08db5c..c5d2314805290b 100644 --- a/local-cli/bundle/buildBundle.js +++ b/local-cli/bundle/buildBundle.js @@ -78,6 +78,7 @@ async function buildBundle( const terminal = new Terminal(process.stdout); const server = new Server({ + asyncRequireModulePath: config.getAsyncRequireModulePath(), assetExts: defaultAssetExts.concat(assetExts), assetRegistryPath: ASSET_REGISTRY_PATH, blacklistRE: config.getBlacklistRE(), diff --git a/local-cli/server/runServer.js b/local-cli/server/runServer.js index 47c11535bdf4b5..e9b5f3e35bba75 100644 --- a/local-cli/server/runServer.js +++ b/local-cli/server/runServer.js @@ -176,6 +176,7 @@ function getPackagerServer(args, config, reporter) { args.providesModuleNodeModules || defaultProvidesModuleNodeModules; return Metro.createServer({ + asyncRequireModulePath: config.getAsyncRequireModulePath(), assetExts: defaultAssetExts.concat(args.assetExts), assetRegistryPath: ASSET_REGISTRY_PATH, blacklistRE: config.getBlacklistRE(), From 57919a3edd3d09f595224e0d92f95da1df75e884 Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Fri, 20 Apr 2018 14:03:35 -0700 Subject: [PATCH 0359/1109] Bump metro@0.34.0 Differential Revision: D7708906 fbshipit-source-id: 3d8cdfd2745baf73c92f90e0960f7cd73a289f77 --- babel-preset/package.json | 2 +- package.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/babel-preset/package.json b/babel-preset/package.json index ce1c169a82f960..691941cf378b7f 100644 --- a/babel-preset/package.json +++ b/babel-preset/package.json @@ -40,6 +40,6 @@ "@babel/plugin-transform-template-literals": "7.0.0-beta.40", "@babel/plugin-transform-unicode-regex": "7.0.0-beta.40", "@babel/template": "7.0.0-beta.40", - "metro-babel7-plugin-react-transform": "0.32.0" + "metro-babel7-plugin-react-transform": "0.34.0" } } diff --git a/package.json b/package.json index 8cadfda93457f0..5974c35feebfee 100644 --- a/package.json +++ b/package.json @@ -166,8 +166,8 @@ "graceful-fs": "^4.1.3", "inquirer": "^3.0.6", "lodash": "^4.17.5", - "metro": "^0.33.0", - "metro-core": "^0.33.0", + "metro": "^0.34.0", + "metro-core": "^0.34.0", "mime": "^1.3.4", "minimist": "^1.2.0", "mkdirp": "^0.5.1", From 5c8596dabe8bc63bc10ab6820ba8d5db70433663 Mon Sep 17 00:00:00 2001 From: Miguel Jimenez Esun Date: Sat, 21 Apr 2018 11:20:59 -0700 Subject: [PATCH 0360/1109] Upgrade Jest to 23.0.0-beta.1 Reviewed By: cpojer Differential Revision: D7722547 fbshipit-source-id: 711617c5c88fced5a38067a66fda86d2b281c0a2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5974c35feebfee..6f013d4aa1e8b7 100644 --- a/package.json +++ b/package.json @@ -207,7 +207,7 @@ "eslint-plugin-prettier": "2.6.0", "eslint-plugin-react": "7.6.1", "flow-bin": "^0.70.0", - "jest": "23.0.0-alpha.4", + "jest": "23.0.0-beta.1", "jest-junit": "3.6.0", "prettier": "1.12.1", "react": "16.3.2", From 2690ba5e591fb67aea1d528e96b3999c6ddd272f Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Mon, 23 Apr 2018 03:52:15 -0700 Subject: [PATCH 0361/1109] Move worker protocol and babelRegisterOnly into their own packages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Moves the implementation of Buck’s worker protocol into its own package and babelRegisterOnly for better reusability. Reviewed By: rafeca Differential Revision: D7666896 fbshipit-source-id: ae297494ced3b8dd1f9d90983a640643d6ce7896 --- jest/preprocessor.js | 2 +- package.json | 1 + setupBabel.js | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/jest/preprocessor.js b/jest/preprocessor.js index 170f7091c30824..6d9e60de675f2f 100644 --- a/jest/preprocessor.js +++ b/jest/preprocessor.js @@ -15,7 +15,7 @@ const {transformSync: babelTransformSync} = require('@babel/core'); /* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error * found when Flow v0.54 was deployed. To see the error delete this comment and * run Flow. */ -const babelRegisterOnly = require('metro/src/babelRegisterOnly'); +const babelRegisterOnly = require('metro-babel-register'); /* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error * found when Flow v0.54 was deployed. To see the error delete this comment and * run Flow. */ diff --git a/package.json b/package.json index 6f013d4aa1e8b7..a2ee96304c1e6d 100644 --- a/package.json +++ b/package.json @@ -167,6 +167,7 @@ "inquirer": "^3.0.6", "lodash": "^4.17.5", "metro": "^0.34.0", + "metro-babel-register": "^0.34.1", "metro-core": "^0.34.0", "mime": "^1.3.4", "minimist": "^1.2.0", diff --git a/setupBabel.js b/setupBabel.js index 6bac7dde43aead..28b208e05a9950 100644 --- a/setupBabel.js +++ b/setupBabel.js @@ -7,7 +7,7 @@ 'use strict'; -const babelRegisterOnly = require('metro/src/babelRegisterOnly'); +const babelRegisterOnly = require('metro-babel-register'); const escapeRegExp = require('lodash/escapeRegExp'); const path = require('path'); From e85799faed7ccfad34d1e7d9ec827f6e70d8f330 Mon Sep 17 00:00:00 2001 From: Peter van der Zee Date: Mon, 23 Apr 2018 05:48:20 -0700 Subject: [PATCH 0362/1109] Add @babel/core to RN dev deps for testing Summary: This adds a locked down version of Babel 7 (beta.40) to the dev dependencies for RN because it's used in testing. See also; https://github.com/facebook/react-native/commit/f8d6b97140cffe8d18b2558f94570c8d1b410d5c#r28569573 Reviewed By: davidaurelio Differential Revision: D7685590 fbshipit-source-id: eae8379b586d82527788e9812a573ab321dfc8e3 --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index a2ee96304c1e6d..3ecb3625c2cbba 100644 --- a/package.json +++ b/package.json @@ -198,6 +198,7 @@ "yargs": "^9.0.0" }, "devDependencies": { + "@babel/core": "7.0.0-beta.40", "babel-eslint": "8.2.1", "eslint": "4.17.0", "eslint-config-fb-strict": "22.1.0", From fc42f9cca24a9f8023db0ad908807e003a583a73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 23 Apr 2018 10:26:28 -0700 Subject: [PATCH 0363/1109] Adds async & babel-generator to the devDependencies Reviewed By: mjesun Differential Revision: D7707199 fbshipit-source-id: 30635f44b24c156ef1947652ef78850b4d9d68b6 --- package.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/package.json b/package.json index 3ecb3625c2cbba..603b8808007d3c 100644 --- a/package.json +++ b/package.json @@ -199,7 +199,9 @@ }, "devDependencies": { "@babel/core": "7.0.0-beta.40", + "async": "^2.4.0", "babel-eslint": "8.2.1", + "babel-generator": "^6.26.0", "eslint": "4.17.0", "eslint-config-fb-strict": "22.1.0", "eslint-config-fbjs": "2.0.1", From 05b75b9ebfa3ce6d67b2a3aee446ff0cd515311b Mon Sep 17 00:00:00 2001 From: David Vacca Date: Mon, 23 Apr 2018 11:13:07 -0700 Subject: [PATCH 0364/1109] Revert D7612904: [react-native][PR] Fix view indices with Android LayoutAnimation Differential Revision: D7612904 Original commit changeset: a04cf47ab80e fbshipit-source-id: fd22a1243f770aab486f6c6d09726547c92841c0 --- .../react/uimanager/NativeViewHierarchyManager.java | 13 +++++-------- .../facebook/react/uimanager/ViewGroupManager.java | 8 -------- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java index 2b72a0a3333088..a57205b861ebe2 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java @@ -373,13 +373,12 @@ public synchronized void manageChildren( if (mLayoutAnimationEnabled && mLayoutAnimator.shouldAnimateLayout(viewToRemove) && arrayContains(tagsToDelete, viewToRemove.getId())) { - // Display the view in the parent after removal for the duration of the layout animation, - // but pretend that it doesn't exist when calling other ViewGroup methods. - viewManager.startViewTransition(viewToManage, viewToRemove); + // The view will be removed and dropped by the 'delete' layout animation + // instead, so do nothing + } else { + viewManager.removeViewAt(viewToManage, indexToRemove); } - viewManager.removeViewAt(viewToManage, indexToRemove); - lastIndexToRemove = indexToRemove; } } @@ -424,9 +423,7 @@ public synchronized void manageChildren( mLayoutAnimator.deleteView(viewToDestroy, new LayoutAnimationListener() { @Override public void onAnimationEnd() { - // Already removed from the ViewGroup, we can just end the transition here to - // release the child. - viewManager.endViewTransition(viewToManage, viewToDestroy); + viewManager.removeView(viewToManage, viewToDestroy); dropView(viewToDestroy); } }); diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewGroupManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewGroupManager.java index c4d5eed429dde7..017fb5764e7237 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewGroupManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewGroupManager.java @@ -93,14 +93,6 @@ public void removeAllViews(T parent) { } } - public void startViewTransition(T parent, View view) { - parent.startViewTransition(view); - } - - public void endViewTransition(T parent, View view) { - parent.endViewTransition(view); - } - /** * Returns whether this View type needs to handle laying out its own children instead of * deferring to the standard css-layout algorithm. From f80000b9e72596392567a3deda59441e43f6327d Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Mon, 23 Apr 2018 13:37:19 -0700 Subject: [PATCH 0365/1109] Move `buildRegExps` from `react-native` to `metro-babel-register` Summary: Moves the `buildRegExps` function from `react-native` to `metro-babel-register`. This way, it is easier to reuse, and we can remove FB-specific logic from React Native. Reviewed By: jeanlauliac, mjesun Differential Revision: D7727483 fbshipit-source-id: 0f7773ff044033c465f0712c523a0aef61bf8444 --- package.json | 2 +- setupBabel.js | 41 ++--------------------------------------- 2 files changed, 3 insertions(+), 40 deletions(-) diff --git a/package.json b/package.json index 603b8808007d3c..ced5fcabbd6381 100644 --- a/package.json +++ b/package.json @@ -167,7 +167,7 @@ "inquirer": "^3.0.6", "lodash": "^4.17.5", "metro": "^0.34.0", - "metro-babel-register": "^0.34.1", + "metro-babel-register": "^0.34.2", "metro-core": "^0.34.0", "mime": "^1.3.4", "minimist": "^1.2.0", diff --git a/setupBabel.js b/setupBabel.js index 28b208e05a9950..96b54429d7cf67 100644 --- a/setupBabel.js +++ b/setupBabel.js @@ -8,43 +8,8 @@ 'use strict'; const babelRegisterOnly = require('metro-babel-register'); -const escapeRegExp = require('lodash/escapeRegExp'); -const path = require('path'); -const BABEL_ENABLED_PATHS = ['local-cli', 'metro']; - -/** - * We use absolute paths for matching only the top-level folders reliably. For - * example, we would not want to match some deeply nested forder that happens to - * have the same name as one of `BABEL_ENABLED_PATHS`. - */ -function buildRegExps(basePath, dirPaths) { - return dirPaths.map( - folderPath => - folderPath === 'metro' - // metro uses flow (for example) which needs to be stripped out w/babel. - // it'll resolve to .../metro/src/index.js we want root - ? path.resolve(require.resolve('metro'), '..') - // Babel `only` option works with forward slashes in the RegExp so replace - // backslashes for Windows. - : folderPath instanceof RegExp - ? new RegExp( - `^${escapeRegExp( - path.resolve(basePath, '.').replace(/\\/g, '/') - )}/${folderPath.source}`, - folderPath.flags - ) - : new RegExp( - `^${escapeRegExp( - path.resolve(basePath, folderPath).replace(/\\/g, '/') - )}` - ) - ); -} - -function getOnlyList() { - return buildRegExps(__dirname, BABEL_ENABLED_PATHS); -} +const BABEL_ENABLED_PATHS = ['local-cli']; /** * Centralized place to register all the directories that need a Babel @@ -52,9 +17,7 @@ function getOnlyList() { * support Flow type annotations. */ function setupBabel() { - babelRegisterOnly(getOnlyList()); + babelRegisterOnly(babelRegisterOnly.buildRegExps(__dirname, BABEL_ENABLED_PATHS)); } -setupBabel.buildRegExps = buildRegExps; -setupBabel.getOnlyList = getOnlyList; module.exports = setupBabel; From 37d28be2d97df0310d1918b258b40815c8346209 Mon Sep 17 00:00:00 2001 From: Max Sherman Date: Mon, 23 Apr 2018 22:05:32 -0700 Subject: [PATCH 0366/1109] Fix stacktrace parsing for JS Reviewed By: adamjernst, indragiek Differential Revision: D7734756 fbshipit-source-id: 7111932386bb5fede83b5f55a946549b1dc6c402 --- .../react/devsupport/StackTraceHelper.java | 24 ++++++++++++------- .../devsupport/StackTraceHelperTest.java | 10 ++++++++ 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/StackTraceHelper.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/StackTraceHelper.java index 75ca90d532911f..3e66d52e61acac 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/StackTraceHelper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/StackTraceHelper.java @@ -28,8 +28,10 @@ public class StackTraceHelper { public static final java.lang.String COLUMN_KEY = "column"; public static final java.lang.String LINE_NUMBER_KEY = "lineNumber"; - private static final Pattern STACK_FRAME_PATTERN = Pattern.compile( + private static final Pattern STACK_FRAME_PATTERN1 = Pattern.compile( "^(?:(.*?)@)?(.*?)\\:([0-9]+)\\:([0-9]+)$"); + private static final Pattern STACK_FRAME_PATTERN2 = Pattern.compile( + "\\s*(?:at)\\s*(.+?)\\s*[@(](.*):([0-9]+):([0-9]+)[)]$"); /** * Represents a generic entry in a stack trace, be it originally from JS or Java. @@ -175,16 +177,22 @@ public static StackFrame[] convertJsStackTrace(String stack) { String[] stackTrace = stack.split("\n"); StackFrame[] result = new StackFrame[stackTrace.length]; for (int i = 0; i < stackTrace.length; ++i) { - Matcher matcher = STACK_FRAME_PATTERN.matcher(stackTrace[i]); - if (matcher.find()) { - result[i] = new StackFrameImpl( - matcher.group(2), - matcher.group(1) == null ? "(unknown)" : matcher.group(1), - Integer.parseInt(matcher.group(3)), - Integer.parseInt(matcher.group(4))); + Matcher matcher1 = STACK_FRAME_PATTERN1.matcher(stackTrace[i]); + Matcher matcher2 = STACK_FRAME_PATTERN2.matcher(stackTrace[i]); + Matcher matcher; + if (matcher2.find()) { + matcher = matcher2; + } else if (matcher1.find()) { + matcher = matcher1; } else { result[i] = new StackFrameImpl(null, stackTrace[i], -1, -1); + continue; } + result[i] = new StackFrameImpl( + matcher.group(2), + matcher.group(1) == null ? "(unknown)" : matcher.group(1), + Integer.parseInt(matcher.group(3)), + Integer.parseInt(matcher.group(4))); } return result; } diff --git a/ReactAndroid/src/test/java/com/facebook/react/devsupport/StackTraceHelperTest.java b/ReactAndroid/src/test/java/com/facebook/react/devsupport/StackTraceHelperTest.java index b348bd14995dc3..70b64184bcb504 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/devsupport/StackTraceHelperTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/devsupport/StackTraceHelperTest.java @@ -17,6 +17,16 @@ @RunWith(RobolectricTestRunner.class) public class StackTraceHelperTest { + @Test + public void testParseAlternateFormatStackFrameWithMethod() { + final StackFrame frame = StackTraceHelper.convertJsStackTrace( + "at func1 (/path/to/file.js:2:18)")[0]; + assertThat(frame.getMethod()).isEqualTo("func1"); + assertThat(frame.getFileName()).isEqualTo("file.js"); + assertThat(frame.getLine()).isEqualTo(2); + assertThat(frame.getColumn()).isEqualTo(18); + } + @Test public void testParseStackFrameWithMethod() { final StackFrame frame = StackTraceHelper.convertJsStackTrace( From 9909a4243f7154c8f817489599702e8155c2beb2 Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Tue, 24 Apr 2018 02:00:09 -0700 Subject: [PATCH 0367/1109] iOS: RCTTestRunner should deallocate rootview before invalidating the bridge Summary: There are cases of race condition where the react component being mounted is calling a nativemodule from JS *right after* the test runner starts invalidating the bridge. This causes assertion failure deep in the RCTModuleData such that the bridge doesn't complete the invalidation. To avoid this, unmount and deallocate the RCTRootView before invalidating the bridge. Reviewed By: sahrens Differential Revision: D7727249 fbshipit-source-id: 8b82edc3b795ceb2e32441f16e225d723fcd9be1 --- Libraries/RCTTest/RCTTestRunner.m | 61 ++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/Libraries/RCTTest/RCTTestRunner.m b/Libraries/RCTTest/RCTTestRunner.m index 00e97137282d0b..315371f4abfbf4 100644 --- a/Libraries/RCTTest/RCTTestRunner.m +++ b/Libraries/RCTTest/RCTTestRunner.m @@ -12,6 +12,7 @@ #import #import #import +#import #import #import "FBSnapshotTestController.h" @@ -113,6 +114,7 @@ - (void)runTest:(SEL)test module:(NSString *)moduleName expectErrorBlock:(BOOL(^)(NSString *error))expectErrorBlock { __weak RCTBridge *batchedBridge; + NSNumber *rootTag; @autoreleasepool { __block NSMutableArray *errors = nil; @@ -133,35 +135,42 @@ - (void)runTest:(SEL)test module:(NSString *)moduleName [bridge.devSettings setIsDebuggingRemotely:_useJSDebugger]; batchedBridge = [bridge batchedBridge]; - RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:moduleName initialProperties:initialProps]; -#if TARGET_OS_TV - rootView.frame = CGRectMake(0, 0, 1920, 1080); // Standard screen size for tvOS -#else - rootView.frame = CGRectMake(0, 0, 320, 2000); // Constant size for testing on multiple devices -#endif + UIViewController *vc = RCTSharedApplication().delegate.window.rootViewController; + vc.view = [UIView new]; - RCTTestModule *testModule = [rootView.bridge moduleForClass:[RCTTestModule class]]; + RCTTestModule *testModule = [bridge moduleForClass:[RCTTestModule class]]; RCTAssert(_testController != nil, @"_testController should not be nil"); testModule.controller = _testController; testModule.testSelector = test; testModule.testSuffix = _testSuffix; - testModule.view = rootView; - UIViewController *vc = RCTSharedApplication().delegate.window.rootViewController; - vc.view = [UIView new]; - [vc.view addSubview:rootView]; // Add as subview so it doesn't get resized + @autoreleasepool { + // The rootView needs to be deallocated after this @autoreleasepool block exits. + RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:moduleName initialProperties:initialProps]; +#if TARGET_OS_TV + rootView.frame = CGRectMake(0, 0, 1920, 1080); // Standard screen size for tvOS +#else + rootView.frame = CGRectMake(0, 0, 320, 2000); // Constant size for testing on multiple devices +#endif - if (configurationBlock) { - configurationBlock(rootView); - } + rootTag = rootView.reactTag; + testModule.view = rootView; - NSDate *date = [NSDate dateWithTimeIntervalSinceNow:kTestTimeoutSeconds]; - while (date.timeIntervalSinceNow > 0 && testModule.status == RCTTestStatusPending && errors == nil) { - [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; - [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; - } + [vc.view addSubview:rootView]; // Add as subview so it doesn't get resized + + if (configurationBlock) { + configurationBlock(rootView); + } - [rootView removeFromSuperview]; + NSDate *date = [NSDate dateWithTimeIntervalSinceNow:kTestTimeoutSeconds]; + while (date.timeIntervalSinceNow > 0 && testModule.status == RCTTestStatusPending && errors == nil) { + [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + } + + [rootView removeFromSuperview]; + testModule.view = nil; + } RCTSetLogFunction(defaultLogFunction); @@ -181,15 +190,25 @@ - (void)runTest:(SEL)test module:(NSString *)moduleName RCTAssert(testModule.status == RCTTestStatusPassed, @"Test failed"); } + // Wait for the rootView to be deallocated completely before invalidating the bridge. + RCTUIManager *uiManager = [bridge moduleForClass:[RCTUIManager class]]; + NSDate *date = [NSDate dateWithTimeIntervalSinceNow:5]; + while (date.timeIntervalSinceNow > 0 && [uiManager viewForReactTag:rootTag]) { + [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + } + RCTAssert([uiManager viewForReactTag:rootTag] == nil, @"RootView should have been deallocated after removed."); + [bridge invalidate]; } - // Give the bridge a chance to disappear before continuing to the next test. + // Wait for the bridge to disappear before continuing to the next test. NSDate *invalidateTimeout = [NSDate dateWithTimeIntervalSinceNow:30]; while (invalidateTimeout.timeIntervalSinceNow > 0 && batchedBridge != nil) { [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; } + RCTAssert(batchedBridge == nil, @"Bridge should be deallocated after the test"); } @end From 6b07602915157f54c39adbf0f9746ac056ad2d13 Mon Sep 17 00:00:00 2001 From: liangtongchuan Date: Tue, 24 Apr 2018 09:43:16 -0700 Subject: [PATCH 0368/1109] Update fresco to v1.9.0, okhttp3 to v3.10.0 Summary: I found many crash reports of imagepipeline in our android app, this is caused by fresco webp native memory leak, they have fixed it in v1.9.0 fixed wrong pull request of [18848](https://github.com/facebook/react-native/pull/18848) Test with local build. Check CI passes. [ANDROID] [ENHANCEMENT] [Fresco/OkHttp] - Updates Fresco to 1.9.0, OkHttp to 3.10.0 Closes https://github.com/facebook/react-native/pull/18849 Differential Revision: D7651377 Pulled By: mdvacca fbshipit-source-id: 0bfe79fd3d232b11a6a9380c961b9401c9e0ced9 --- ReactAndroid/build.gradle | 8 +++---- .../libraries/fresco/fresco-react-native/BUCK | 24 +++++++++---------- .../src/main/third-party/java/okhttp/BUCK | 8 +++---- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle index eecfe6929779b0..503b814f32acb1 100644 --- a/ReactAndroid/build.gradle +++ b/ReactAndroid/build.gradle @@ -294,12 +294,12 @@ dependencies { compile 'javax.inject:javax.inject:1' compile 'com.android.support:appcompat-v7:23.0.1' compile 'com.facebook.fbui.textlayoutbuilder:textlayoutbuilder:1.0.0' - compile 'com.facebook.fresco:fresco:1.8.1' - compile 'com.facebook.fresco:imagepipeline-okhttp3:1.8.1' + compile 'com.facebook.fresco:fresco:1.9.0' + compile 'com.facebook.fresco:imagepipeline-okhttp3:1.9.0' compile 'com.facebook.soloader:soloader:0.3.0' compile 'com.google.code.findbugs:jsr305:3.0.0' - compile 'com.squareup.okhttp3:okhttp:3.8.0' - compile 'com.squareup.okhttp3:okhttp-urlconnection:3.8.0' + compile 'com.squareup.okhttp3:okhttp:3.10.0' + compile 'com.squareup.okhttp3:okhttp-urlconnection:3.10.0' compile 'com.squareup.okio:okio:1.14.0' compile 'org.webkit:android-jsc:r174650' diff --git a/ReactAndroid/src/main/libraries/fresco/fresco-react-native/BUCK b/ReactAndroid/src/main/libraries/fresco/fresco-react-native/BUCK index 33ceb77095e719..e4a46ecc3f8694 100644 --- a/ReactAndroid/src/main/libraries/fresco/fresco-react-native/BUCK +++ b/ReactAndroid/src/main/libraries/fresco/fresco-react-native/BUCK @@ -8,8 +8,8 @@ rn_android_prebuilt_aar( remote_file( name = "fresco-binary-aar", - sha1 = "c6ed3f696ed47dca3b20d4ffbd0600c94b9119b2", - url = "mvn:com.facebook.fresco:fresco:aar:1.8.1", + sha1 = "f4415e8676eef4d12fdc8ddbd784bb752cf0c5e3", + url = "mvn:com.facebook.fresco:fresco:aar:1.9.0", ) android_prebuilt_aar( @@ -20,8 +20,8 @@ android_prebuilt_aar( remote_file( name = "drawee-binary-aar", - sha1 = "6bc689901ddcac8f3df5ba4db1f8aabeb8e80107", - url = "mvn:com.facebook.fresco:drawee:aar:1.8.1", + sha1 = "e0c3b0fa64fc7525f05a852476bc8723ae6ddc90", + url = "mvn:com.facebook.fresco:drawee:aar:1.9.0", ) rn_android_library( @@ -42,8 +42,8 @@ rn_android_prebuilt_aar( remote_file( name = "imagepipeline-base-aar", - sha1 = "42fd80c46a853850dfc0d71808b982fef401c841", - url = "mvn:com.facebook.fresco:imagepipeline-base:aar:1.8.1", + sha1 = "8034e5c8a75385bd20e72ff51489b0673029fcf7", + url = "mvn:com.facebook.fresco:imagepipeline-base:aar:1.9.0", ) rn_android_prebuilt_aar( @@ -54,8 +54,8 @@ rn_android_prebuilt_aar( remote_file( name = "imagepipeline-aar", - sha1 = "06a2a4c3e1d9a7fb7d7f1ad14db63e2d32ef0b61", - url = "mvn:com.facebook.fresco:imagepipeline:aar:1.8.1", + sha1 = "8043733b1bf3713d3a3c7fc7896205c96c050fd7", + url = "mvn:com.facebook.fresco:imagepipeline:aar:1.9.0", ) rn_prebuilt_jar( @@ -78,8 +78,8 @@ android_prebuilt_aar( remote_file( name = "fbcore-aar", - sha1 = "99b7a83946e16f037149e4cd3abfd6840a09445d", - url = "mvn:com.facebook.fresco:fbcore:aar:1.8.1", + sha1 = "fc3703511dc7b135bcd0e76d8015cdaf247b1760", + url = "mvn:com.facebook.fresco:fbcore:aar:1.9.0", ) android_prebuilt_aar( @@ -90,6 +90,6 @@ android_prebuilt_aar( remote_file( name = "imagepipeline-okhttp3-binary-aar", - sha1 = "751f19412e1843b1c1e76eae46e388fb1deddbcc", - url = "mvn:com.facebook.fresco:imagepipeline-okhttp3:aar:1.8.1", + sha1 = "4ac95941c1761a1ba5647ed551f7e47a5c417c7b", + url = "mvn:com.facebook.fresco:imagepipeline-okhttp3:aar:1.9.0", ) diff --git a/ReactAndroid/src/main/third-party/java/okhttp/BUCK b/ReactAndroid/src/main/third-party/java/okhttp/BUCK index 84be571ad87c77..549c3f45786226 100644 --- a/ReactAndroid/src/main/third-party/java/okhttp/BUCK +++ b/ReactAndroid/src/main/third-party/java/okhttp/BUCK @@ -6,8 +6,8 @@ prebuilt_jar( remote_file( name = "okhttp3-binary-jar", - sha1 = "5a11f020cce2d11eb71ba916700600e18c4547e7", - url = "mvn:com.squareup.okhttp3:okhttp:jar:3.8.0", + sha1 = "7ef0f1d95bf4c0b3ba30bbae25e0e562b05cf75e", + url = "mvn:com.squareup.okhttp3:okhttp:jar:3.10.0", ) prebuilt_jar( @@ -18,6 +18,6 @@ prebuilt_jar( remote_file( name = "okhttp3-urlconnection-binary-jar", - sha1 = "265257b82f20bb0371a926cc8ceb5f7bb17c0df8", - url = "mvn:com.squareup.okhttp3:okhttp-urlconnection:jar:3.8.0", + sha1 = "ec614c05825ddd2267677a99f585d3913474b125", + url = "mvn:com.squareup.okhttp3:okhttp-urlconnection:jar:3.10.0", ) From 16a5324ca610e7841a2e06b73110ae968aaadd7c Mon Sep 17 00:00:00 2001 From: David Vacca Date: Tue, 24 Apr 2018 12:31:56 -0700 Subject: [PATCH 0369/1109] Introducing ViewType in native code Reviewed By: achen1 Differential Revision: D7729477 fbshipit-source-id: e8d1af87489522c4ae8b52b6a9e4c0a680abf4f6 --- .../com/facebook/react/uimanager/common/BUCK | 4 +++ .../react/uimanager/common/ViewType.java | 21 ++++++++++++++ .../react/uimanager/common/ViewUtil.java | 29 +++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/common/ViewType.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/common/ViewUtil.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/common/BUCK b/ReactAndroid/src/main/java/com/facebook/react/uimanager/common/BUCK index 5c4a5b26df6114..08230b0a0be115 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/common/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/common/BUCK @@ -3,6 +3,10 @@ load("//ReactNative:DEFS.bzl", "rn_android_library", "react_native_dep", "react_ rn_android_library( name = "common", srcs = glob(["*.java"]), + provided_deps = [ + react_native_dep("third-party/android/support/v4:lib-support-v4"), + react_native_dep("third-party/android/support-annotations:android-support-annotations"), + ], visibility = [ "PUBLIC", ], diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/common/ViewType.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/common/ViewType.java new file mode 100644 index 00000000000000..66e4fdbecd44d5 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/common/ViewType.java @@ -0,0 +1,21 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * + * 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.uimanager.common; + +import static com.facebook.react.uimanager.common.ViewType.FABRIC; +import static com.facebook.react.uimanager.common.ViewType.PAPER; +import static java.lang.annotation.RetentionPolicy.SOURCE; + +import java.lang.annotation.Retention; +import android.support.annotation.IntDef; + +@Retention(SOURCE) +@IntDef({PAPER, FABRIC}) +public @interface ViewType { + int PAPER = 1; + int FABRIC = 2; +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/common/ViewUtil.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/common/ViewUtil.java new file mode 100644 index 00000000000000..cc7a3ddcbd044d --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/common/ViewUtil.java @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * + * 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.uimanager.common; + +import static com.facebook.react.uimanager.common.ViewType.FABRIC; +import static com.facebook.react.uimanager.common.ViewType.PAPER; + +public class ViewUtil { + + /** + * Counter for uniquely identifying views. + * - % 10 === 1 means it is a rootTag. + * - % 2 === 0 means it is a Fabric tag. + * See https://github.com/facebook/react/pull/12587 + * + * @param reactTag {@link } + */ + @ViewType + public static int getViewType(int reactTag) { + if (reactTag % 2 == 0) return FABRIC; + return PAPER; + } + +} From f44e78df55a3b4b794c32fc6682130160ed1d6f2 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Tue, 24 Apr 2018 12:37:08 -0700 Subject: [PATCH 0370/1109] Add InstanceHandle parameter into FabricJSC/JSI Reviewed By: achen1 Differential Revision: D7644487 fbshipit-source-id: b49381a58a791043bf61b8ac5f065817caff7c95 --- .../react/fabric/FabricUIManager.java | 2 +- .../react/fabric/jsc/jni/FabricJSCBinding.cpp | 7 +++--- .../react/fabric/FabricUIManagerTest.java | 22 +++++++++++-------- 3 files changed, 17 insertions(+), 14 deletions(-) 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 191d463ab725c3..cd6045f00d88ce 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -67,7 +67,7 @@ public FabricUIManager( /** Creates a new {@link ReactShadowNode} */ @Nullable public ReactShadowNode createNode( - int reactTag, String viewName, int rootTag, ReadableNativeMap props) { + int reactTag, String viewName, int rootTag, ReadableNativeMap props, int instanceHandle) { if (DEBUG) { Log.d(TAG, "createNode \n\ttag: " + reactTag + "\n\tviewName: " + viewName + diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/FabricJSCBinding.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/FabricJSCBinding.cpp index 6ce8b9976e34bf..83023f488aa712 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/FabricJSCBinding.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/FabricJSCBinding.cpp @@ -83,17 +83,16 @@ JSValueRef createNode(JSContextRef ctx, JSObjectRef function, JSObjectRef thisOb static auto createNode = jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") - ->getMethod(jint, jstring, jint, ReadableNativeMap::javaobject)>("createNode"); + ->getMethod(jint, jstring, jint, ReadableNativeMap::javaobject, jint)>("createNode"); int reactTag = (int)JSC_JSValueToNumber(ctx, arguments[0], NULL); auto viewName = JSValueToJString(ctx, arguments[1]); int rootTag = (int)JSC_JSValueToNumber(ctx, arguments[2], NULL); auto props = JSC_JSValueIsNull(ctx, arguments[3]) ? local_ref(nullptr) : JSValueToReadableMapViaJSON(ctx, arguments[3]);; + int instanceHandle = (int)JSC_JSValueToNumber(ctx, arguments[4], NULL); - // TODO: Retain object in arguments[4] using a weak ref. - - auto node = createNode(manager, reactTag, viewName.get(), rootTag, props.get()); + auto node = createNode(manager, reactTag, viewName.get(), rootTag, props.get(), instanceHandle); return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(node.get())); } diff --git a/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java b/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java index 441003004bd119..32a0bbb40015e3 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java @@ -47,6 +47,7 @@ public class FabricUIManagerTest { private FabricUIManager mFabricUIManager; private ThemedReactContext mThemedReactContext; private int mNextReactTag; + private int mNextInstanceHandle; @Before public void setUp() throws Exception { @@ -70,8 +71,10 @@ public void testCreateNode() { new ReactRootView(RuntimeEnvironment.application.getApplicationContext()); int rootTag = mFabricUIManager.addRootView(rootView); int reactTag = mNextReactTag++; + int instanceHandle = mNextInstanceHandle++; String viewClass = ReactViewManager.REACT_CLASS; - ReactShadowNode node = mFabricUIManager.createNode(reactTag, viewClass, rootTag, null); + ReactShadowNode node = + mFabricUIManager.createNode(reactTag, viewClass, rootTag, null, instanceHandle); assertThat(reactTag).isEqualTo(node.getReactTag()); assertThat(viewClass).isEqualTo(node.getViewClass()); @@ -89,8 +92,10 @@ private int createAndRenderRootView() { new ReactRootView(RuntimeEnvironment.application.getApplicationContext()); int rootTag = mFabricUIManager.addRootView(rootView); int reactTag = mNextReactTag++; + int instanceHandle = mNextInstanceHandle++; String viewClass = ReactViewManager.REACT_CLASS; - ReactShadowNode node = mFabricUIManager.createNode(reactTag, viewClass, rootTag, null); + ReactShadowNode node = + mFabricUIManager.createNode(reactTag, viewClass, rootTag, null, instanceHandle); List childSet = mFabricUIManager.createChildSet(rootTag); mFabricUIManager.appendChildToSet(childSet, node); @@ -220,9 +225,8 @@ public void testTextMutableClone() { ReactRootView rootView = new ReactRootView(RuntimeEnvironment.application.getApplicationContext()); int rootTag = mFabricUIManager.addRootView(rootView); - ReactShadowNode text = - mFabricUIManager.createNode(0, ReactTextViewManager.REACT_CLASS, rootTag, null); + mFabricUIManager.createNode(0, ReactTextViewManager.REACT_CLASS, rootTag, null, mNextInstanceHandle++); assertThat(text.isMeasureDefined()).isTrue(); ReactShadowNode textCopy = text.mutableCopy(); @@ -248,13 +252,13 @@ public void testRemoveOriginalNodeReferences() { int rootTag = mFabricUIManager.addRootView(rootView); String viewClass = ReactViewManager.REACT_CLASS; - ReactShadowNode aa = mFabricUIManager.createNode(2, viewClass, rootTag, null); - ReactShadowNode a = mFabricUIManager.createNode(3, viewClass, rootTag, null); + ReactShadowNode aa = mFabricUIManager.createNode(2, viewClass, rootTag, null, mNextInstanceHandle++); + ReactShadowNode a = mFabricUIManager.createNode(3, viewClass, rootTag, null, mNextInstanceHandle++); mFabricUIManager.appendChild(a, aa); - ReactShadowNode bb = mFabricUIManager.createNode(4, viewClass, rootTag, null); - ReactShadowNode b = mFabricUIManager.createNode(5, viewClass, rootTag, null); + ReactShadowNode bb = mFabricUIManager.createNode(4, viewClass, rootTag, null, mNextInstanceHandle++); + ReactShadowNode b = mFabricUIManager.createNode(5, viewClass, rootTag, null, mNextInstanceHandle++); mFabricUIManager.appendChild(b, bb); - ReactShadowNode container = mFabricUIManager.createNode(6, viewClass, rootTag, null); + ReactShadowNode container = mFabricUIManager.createNode(6, viewClass, rootTag, null, mNextInstanceHandle++); mFabricUIManager.appendChild(container, a); mFabricUIManager.appendChild(container, b); List childSet = mFabricUIManager.createChildSet(rootTag); From 4a802100d16ee9f52e6e4caea6e54b9a49694351 Mon Sep 17 00:00:00 2001 From: Alex McKelvey Date: Tue, 24 Apr 2018 13:40:27 -0700 Subject: [PATCH 0371/1109] Improve VirtualizedList yellow-box warning when item is missing a key Reviewed By: sahrens Differential Revision: D7746659 fbshipit-source-id: b271dcd604d9adb85d0996dce5b8af1a6efd37d2 --- Libraries/Lists/VirtualizedList.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Libraries/Lists/VirtualizedList.js b/Libraries/Lists/VirtualizedList.js index 30e8777eaee43d..bbfc6cf3bdecd6 100644 --- a/Libraries/Lists/VirtualizedList.js +++ b/Libraries/Lists/VirtualizedList.js @@ -218,6 +218,7 @@ type OptionalProps = { export type Props = RequiredProps & OptionalProps; let _usedIndexForKey = false; +let _keylessItemComponentName: string = ''; type Frame = { offset: number, @@ -431,6 +432,9 @@ class VirtualizedList extends React.PureComponent { return item.key; } _usedIndexForKey = true; + if (item.type && item.type.displayName) { + _keylessItemComponentName = item.type.displayName; + } return String(index); }, maxToRenderPerBatch: 10, @@ -762,6 +766,7 @@ class VirtualizedList extends React.PureComponent { const itemCount = this.props.getItemCount(data); if (itemCount > 0) { _usedIndexForKey = false; + _keylessItemComponentName = ''; const spacerKey = !horizontal ? 'height' : 'width'; const lastInitialIndex = this.props.initialScrollIndex ? -1 @@ -831,6 +836,7 @@ class VirtualizedList extends React.PureComponent { console.warn( 'VirtualizedList: missing keys for items, make sure to specify a key property on each ' + 'item or provide a custom keyExtractor.', + _keylessItemComponentName, ); this._hasWarned.keys = true; } From d5e9e55fa38c574bce6c04cbcaf6b144b87fa17f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Norte?= Date: Wed, 25 Apr 2018 07:00:46 -0700 Subject: [PATCH 0372/1109] Remove @providesModule from all modules Summary: This PR removes the need for having the `providesModule` tags in all the modules in the repository. It configures Flow, Jest and Metro to get the module names from the filenames (`Libraries/Animated/src/nodes/AnimatedInterpolation.js` => `AnimatedInterpolation`) * Checked the Flow configuration by running flow on the project root (no errors): ``` yarn flow ``` * Checked the Jest configuration by running the tests with a clean cache: ``` yarn jest --clearCache && yarn test ``` * Checked the Metro configuration by starting the server with a clean cache and requesting some bundles: ``` yarn run start --reset-cache curl 'localhost:8081/IntegrationTests/AccessibilityManagerTest.bundle?platform=android' curl 'localhost:8081/Libraries/Alert/Alert.bundle?platform=ios' ``` [INTERNAL] [FEATURE] [All] - Removed providesModule from all modules and configured tools. Closes https://github.com/facebook/react-native/pull/18995 Reviewed By: mjesun Differential Revision: D7729509 Pulled By: rubennorte fbshipit-source-id: 892f760a05ce1fddb088ff0cd2e97e521fb8e825 --- .flowconfig | 17 +++++ IntegrationTests/AccessibilityManagerTest.js | 1 - IntegrationTests/AppEventsTest.js | 1 - IntegrationTests/AsyncStorageTest.js | 1 - IntegrationTests/ImageCachePolicyTest.js | 1 - IntegrationTests/ImageSnapshotTest.js | 1 - .../IntegrationTestHarnessTest.js | 1 - IntegrationTests/IntegrationTestsApp.js | 1 - IntegrationTests/LayoutEventsTest.js | 1 - IntegrationTests/LoggingTestModule.js | 1 - IntegrationTests/PromiseTest.js | 1 - IntegrationTests/PropertiesUpdateTest.js | 1 - .../RCTRootViewIntegrationTestApp.js | 1 - .../ReactContentSizeUpdateTest.js | 1 - IntegrationTests/SimpleSnapshotTest.js | 1 - IntegrationTests/SizeFlexibilityUpdateTest.js | 1 - IntegrationTests/SyncMethodTest.js | 1 - IntegrationTests/TimersTest.js | 1 - IntegrationTests/WebSocketTest.js | 1 - IntegrationTests/WebViewTest.js | 1 - .../websocket_integration_test_server.js | 1 - Libraries/ART/ARTSerializablePath.js | 1 - Libraries/ART/ReactNativeART.js | 1 - Libraries/ActionSheetIOS/ActionSheetIOS.js | 1 - Libraries/Alert/Alert.js | 1 - Libraries/Alert/AlertIOS.js | 1 - Libraries/Alert/RCTAlertManager.android.js | 1 - Libraries/Alert/RCTAlertManager.ios.js | 1 - Libraries/Animated/release/gulpfile.js | 1 - Libraries/Animated/src/Animated.js | 1 - Libraries/Animated/src/AnimatedEvent.js | 1 - .../Animated/src/AnimatedImplementation.js | 1 - Libraries/Animated/src/AnimatedWeb.js | 1 - Libraries/Animated/src/Easing.js | 1 - .../Animated/src/NativeAnimatedHelper.js | 1 - Libraries/Animated/src/SpringConfig.js | 1 - .../Animated/src/animations/Animation.js | 1 - .../Animated/src/animations/DecayAnimation.js | 1 - .../src/animations/SpringAnimation.js | 1 - .../src/animations/TimingAnimation.js | 1 - Libraries/Animated/src/bezier.js | 1 - .../Animated/src/createAnimatedComponent.js | 1 - .../Animated/src/nodes/AnimatedAddition.js | 1 - .../Animated/src/nodes/AnimatedDiffClamp.js | 1 - .../Animated/src/nodes/AnimatedDivision.js | 1 - .../src/nodes/AnimatedInterpolation.js | 1 - .../Animated/src/nodes/AnimatedModulo.js | 1 - .../src/nodes/AnimatedMultiplication.js | 1 - Libraries/Animated/src/nodes/AnimatedNode.js | 1 - Libraries/Animated/src/nodes/AnimatedProps.js | 1 - Libraries/Animated/src/nodes/AnimatedStyle.js | 1 - .../Animated/src/nodes/AnimatedSubtraction.js | 1 - .../Animated/src/nodes/AnimatedTracking.js | 1 - .../Animated/src/nodes/AnimatedTransform.js | 1 - Libraries/Animated/src/nodes/AnimatedValue.js | 1 - .../Animated/src/nodes/AnimatedValueXY.js | 1 - .../src/nodes/AnimatedWithChildren.js | 1 - Libraries/AppState/AppState.js | 1 - Libraries/BatchedBridge/BatchedBridge.js | 1 - Libraries/BatchedBridge/MessageQueue.js | 1 - Libraries/BatchedBridge/NativeModules.js | 1 - Libraries/Blob/Blob.js | 1 - Libraries/Blob/BlobManager.js | 1 - Libraries/Blob/BlobRegistry.js | 1 - Libraries/Blob/BlobTypes.js | 1 - Libraries/Blob/File.js | 1 - Libraries/Blob/FileReader.js | 1 - Libraries/Blob/URL.js | 1 - Libraries/BugReporting/BugReporting.js | 1 - Libraries/BugReporting/dumpReactTree.js | 1 - Libraries/BugReporting/getReactData.js | 1 - Libraries/CameraRoll/CameraRoll.js | 1 - Libraries/CameraRoll/ImagePickerIOS.js | 1 - Libraries/Color/normalizeColor.js | 1 - .../AccessibilityInfo.android.js | 1 - .../AccessibilityInfo.ios.js | 1 - .../ActivityIndicator/ActivityIndicator.js | 1 - .../Components/AppleTV/TVEventHandler.js | 1 - .../Components/AppleTV/TVViewPropTypes.js | 1 - Libraries/Components/Button.js | 1 - .../Components/CheckBox/CheckBox.android.js | 1 - Libraries/Components/CheckBox/CheckBox.ios.js | 1 - Libraries/Components/Clipboard/Clipboard.js | 1 - .../DatePicker/DatePickerIOS.android.js | 1 - .../DatePicker/DatePickerIOS.ios.js | 1 - .../DatePickerAndroid.android.js | 1 - .../DatePickerAndroid.ios.js | 1 - .../DrawerLayoutAndroid.android.js | 1 - .../DrawerAndroid/DrawerLayoutAndroid.ios.js | 1 - Libraries/Components/Keyboard/Keyboard.js | 1 - .../Keyboard/KeyboardAvoidingView.js | 1 - Libraries/Components/LazyRenderer.js | 1 - .../MaskedView/MaskedViewIOS.android.js | 1 - .../MaskedView/MaskedViewIOS.ios.js | 1 - .../Navigation/NavigatorIOS.android.js | 1 - .../Components/Navigation/NavigatorIOS.ios.js | 1 - Libraries/Components/Picker/Picker.js | 1 - .../Picker/PickerAndroid.android.js | 1 - .../Components/Picker/PickerAndroid.ios.js | 1 - .../Components/Picker/PickerIOS.android.js | 1 - Libraries/Components/Picker/PickerIOS.ios.js | 1 - .../ProgressBarAndroid.android.js | 1 - .../ProgressBarAndroid.ios.js | 1 - .../ProgressViewIOS.android.js | 1 - .../ProgressViewIOS/ProgressViewIOS.ios.js | 1 - .../RefreshControl/RefreshControl.js | 1 - .../SafeAreaView/SafeAreaView.android.js | 1 - .../SafeAreaView/SafeAreaView.ios.js | 1 - Libraries/Components/ScrollResponder.js | 1 - Libraries/Components/ScrollView/ScrollView.js | 1 - .../ScrollView/ScrollViewStickyHeader.js | 1 - .../ScrollView/processDecelerationRate.js | 1 - .../SegmentedControlIOS.android.js | 1 - .../SegmentedControlIOS.ios.js | 1 - Libraries/Components/Slider/Slider.js | 1 - Libraries/Components/StaticContainer.react.js | 1 - Libraries/Components/StaticRenderer.js | 1 - Libraries/Components/StatusBar/StatusBar.js | 1 - .../StatusBar/StatusBarIOS.android.js | 1 - .../Components/StatusBar/StatusBarIOS.ios.js | 1 - Libraries/Components/Subscribable.js | 1 - Libraries/Components/Switch/Switch.js | 1 - .../Components/TabBarIOS/TabBarIOS.android.js | 1 - .../Components/TabBarIOS/TabBarIOS.ios.js | 1 - .../TabBarIOS/TabBarItemIOS.android.js | 1 - .../Components/TabBarIOS/TabBarItemIOS.ios.js | 1 - .../TextInput/InputAccessoryView.js | 1 - Libraries/Components/TextInput/TextInput.js | 1 - .../Components/TextInput/TextInputState.js | 1 - .../TimePickerAndroid.android.js | 1 - .../TimePickerAndroid.ios.js | 1 - .../ToastAndroid/ToastAndroid.android.js | 1 - .../ToastAndroid/ToastAndroid.ios.js | 1 - .../ToolbarAndroid/ToolbarAndroid.android.js | 1 - .../ToolbarAndroid/ToolbarAndroid.ios.js | 1 - .../Touchable/BoundingDimensions.js | 1 - Libraries/Components/Touchable/PooledClass.js | 1 - Libraries/Components/Touchable/Position.js | 1 - Libraries/Components/Touchable/Touchable.js | 1 - .../Components/Touchable/TouchableBounce.js | 1 - .../Touchable/TouchableHighlight.js | 1 - .../TouchableNativeFeedback.android.js | 1 - .../Touchable/TouchableNativeFeedback.ios.js | 1 - .../Components/Touchable/TouchableOpacity.js | 1 - .../Touchable/TouchableWithoutFeedback.js | 1 - .../Touchable/ensureComponentIsNative.js | 1 - .../Touchable/ensurePositiveDelayProps.js | 1 - .../UnimplementedViews/UnimplementedView.js | 1 - .../Components/View/PlatformViewPropTypes.js | 1 - .../View/ReactNativeStyleAttributes.js | 1 - .../View/ReactNativeViewAttributes.js | 1 - .../Components/View/ShadowPropTypesIOS.js | 1 - Libraries/Components/View/View.js | 1 - .../Components/View/ViewAccessibility.js | 1 - Libraries/Components/View/ViewContext.js | 1 - Libraries/Components/View/ViewPropTypes.js | 1 - .../Components/View/ViewStylePropTypes.js | 1 - .../ViewPager/ViewPagerAndroid.android.js | 1 - .../ViewPager/ViewPagerAndroid.ios.js | 1 - .../Components/WebView/WebView.android.js | 1 - Libraries/Components/WebView/WebView.ios.js | 1 - Libraries/Core/Devtools/getDevServer.js | 1 - Libraries/Core/Devtools/openFileInEditor.js | 1 - Libraries/Core/Devtools/parseErrorStack.js | 1 - Libraries/Core/Devtools/setupDevtools.js | 1 - .../Core/Devtools/symbolicateStackTrace.js | 1 - Libraries/Core/ExceptionsManager.js | 1 - Libraries/Core/InitializeCore.js | 1 - Libraries/Core/ReactNativeVersion.js | 1 - Libraries/Core/ReactNativeVersionCheck.js | 1 - Libraries/Core/Timers/JSTimers.js | 1 - .../MissingNativeEventEmitterShim.js | 1 - Libraries/EventEmitter/NativeEventEmitter.js | 1 - .../EventEmitter/RCTDeviceEventEmitter.js | 1 - Libraries/EventEmitter/RCTEventEmitter.js | 1 - .../EventEmitter/RCTNativeAppEventEmitter.js | 1 - Libraries/Experimental/Incremental.js | 1 - Libraries/Experimental/IncrementalExample.js | 1 - Libraries/Experimental/IncrementalGroup.js | 1 - .../Experimental/IncrementalPresenter.js | 1 - .../SwipeableRow/SwipeableFlatList.js | 1 - .../SwipeableRow/SwipeableListView.js | 1 - .../SwipeableListViewDataSource.js | 1 - .../SwipeableQuickActionButton.js | 1 - .../SwipeableRow/SwipeableQuickActions.js | 1 - .../Experimental/SwipeableRow/SwipeableRow.js | 1 - Libraries/Experimental/WindowedListView.js | 1 - Libraries/Geolocation/Geolocation.js | 1 - Libraries/Image/AssetRegistry.js | 1 - Libraries/Image/AssetSourceResolver.js | 1 - Libraries/Image/Image.android.js | 1 - Libraries/Image/Image.ios.js | 1 - Libraries/Image/ImageBackground.js | 1 - Libraries/Image/ImageEditor.js | 1 - Libraries/Image/ImageProps.js | 1 - Libraries/Image/ImageResizeMode.js | 1 - Libraries/Image/ImageSource.js | 1 - Libraries/Image/ImageSourcePropType.js | 1 - Libraries/Image/ImageStore.js | 1 - Libraries/Image/ImageStylePropTypes.js | 1 - Libraries/Image/RelativeImageStub.js | 1 - Libraries/Image/nativeImageSource.js | 1 - Libraries/Image/resolveAssetSource.js | 1 - Libraries/Inspector/BorderBox.js | 1 - Libraries/Inspector/BoxInspector.js | 1 - Libraries/Inspector/ElementBox.js | 1 - Libraries/Inspector/ElementProperties.js | 1 - Libraries/Inspector/Inspector.js | 1 - Libraries/Inspector/InspectorOverlay.js | 1 - Libraries/Inspector/InspectorPanel.js | 1 - Libraries/Inspector/NetworkOverlay.js | 1 - Libraries/Inspector/PerformanceOverlay.js | 1 - Libraries/Inspector/StyleInspector.js | 1 - Libraries/Inspector/resolveBoxStyle.js | 1 - Libraries/Interaction/Batchinator.js | 1 - .../Interaction/BridgeSpyStallHandler.js | 1 - Libraries/Interaction/FrameRateLogger.js | 1 - Libraries/Interaction/InteractionManager.js | 1 - Libraries/Interaction/InteractionMixin.js | 1 - .../Interaction/InteractionStallDebugger.js | 1 - Libraries/Interaction/JSEventLoopWatchdog.js | 1 - Libraries/Interaction/PanResponder.js | 1 - .../Interaction/ReactPerfStallHandler.js | 1 - Libraries/Interaction/TaskQueue.js | 1 - Libraries/JSInspector/InspectorAgent.js | 1 - Libraries/JSInspector/JSInspector.js | 1 - Libraries/JSInspector/NetworkAgent.js | 1 - Libraries/LayoutAnimation/LayoutAnimation.js | 1 - Libraries/Linking/Linking.js | 1 - Libraries/Lists/FillRateHelper.js | 1 - Libraries/Lists/FlatList.js | 1 - Libraries/Lists/ListView/ListView.js | 1 - .../Lists/ListView/ListViewDataSource.js | 1 - Libraries/Lists/MetroListView.js | 1 - Libraries/Lists/SectionList.js | 1 - Libraries/Lists/ViewabilityHelper.js | 1 - Libraries/Lists/VirtualizeUtils.js | 1 - Libraries/Lists/VirtualizedList.js | 1 - Libraries/Lists/VirtualizedSectionList.js | 1 - Libraries/Modal/Modal.js | 1 - Libraries/Network/FormData.js | 1 - Libraries/Network/NetInfo.js | 1 - Libraries/Network/RCTNetworking.android.js | 1 - Libraries/Network/RCTNetworking.ios.js | 1 - Libraries/Network/XHRInterceptor.js | 1 - Libraries/Network/XMLHttpRequest.js | 1 - Libraries/Network/convertRequestBody.js | 1 - Libraries/Network/fetch.js | 1 - .../Performance/QuickPerformanceLogger.js | 1 - Libraries/Performance/SamplingProfiler.js | 1 - Libraries/Performance/Systrace.js | 1 - .../PermissionsAndroid/PermissionsAndroid.js | 1 - Libraries/Promise.js | 1 - .../PushNotificationIOS.js | 1 - Libraries/RCTTest/SnapshotViewIOS.android.js | 1 - Libraries/RCTTest/SnapshotViewIOS.ios.js | 1 - Libraries/ReactNative/AppContainer.js | 1 - Libraries/ReactNative/AppRegistry.js | 1 - Libraries/ReactNative/FabricUIManager.js | 1 - Libraries/ReactNative/I18nManager.js | 1 - Libraries/ReactNative/ReactFabricInternals.js | 1 - Libraries/ReactNative/UIManager.js | 1 - Libraries/ReactNative/UIManagerStatTracker.js | 1 - Libraries/ReactNative/YellowBox.js | 1 - Libraries/ReactNative/queryLayoutByID.js | 1 - Libraries/ReactNative/renderApplication.js | 1 - .../ReactNative/requireNativeComponent.js | 1 - Libraries/ReactNative/takeSnapshot.js | 1 - Libraries/ReactNative/verifyPropTypes.js | 1 - Libraries/Renderer/oss/ReactFabric-dev.js | 1 - Libraries/Renderer/oss/ReactFabric-prod.js | 1 - .../Renderer/oss/ReactNativeRenderer-dev.js | 1 - .../Renderer/oss/ReactNativeRenderer-prod.js | 1 - .../Renderer/shims/NativeMethodsMixin.js | 1 - Libraries/Renderer/shims/ReactDebugTool.js | 1 - Libraries/Renderer/shims/ReactFabric.js | 1 - Libraries/Renderer/shims/ReactNative.js | 1 - .../shims/ReactNativeComponentTree.js | 1 - Libraries/Renderer/shims/ReactNativeTypes.js | 1 - .../shims/ReactNativeViewConfigRegistry.js | 1 - Libraries/Renderer/shims/ReactPerf.js | 1 - Libraries/Renderer/shims/ReactTypes.js | 1 - .../shims/createReactNativeComponentClass.js | 1 - Libraries/Sample/Sample.android.js | 1 - Libraries/Sample/Sample.ios.js | 1 - Libraries/Settings/Settings.android.js | 1 - Libraries/Settings/Settings.ios.js | 1 - Libraries/Share/Share.js | 1 - Libraries/Storage/AsyncStorage.js | 1 - Libraries/StyleSheet/ColorPropType.js | 1 - Libraries/StyleSheet/EdgeInsetsPropType.js | 1 - Libraries/StyleSheet/LayoutPropTypes.js | 1 - Libraries/StyleSheet/PointPropType.js | 1 - Libraries/StyleSheet/StyleSheet.js | 1 - Libraries/StyleSheet/StyleSheetPropType.js | 1 - Libraries/StyleSheet/StyleSheetTypes.js | 1 - Libraries/StyleSheet/StyleSheetValidation.js | 1 - Libraries/StyleSheet/TransformPropTypes.js | 1 - Libraries/StyleSheet/flattenStyle.js | 1 - Libraries/StyleSheet/processColor.js | 1 - Libraries/StyleSheet/processTransform.js | 1 - .../StyleSheet/setNormalizedColorAlpha.js | 1 - Libraries/Text/Text.js | 1 - Libraries/Text/TextPropTypes.js | 1 - Libraries/Text/TextProps.js | 1 - Libraries/Text/TextStylePropTypes.js | 1 - Libraries/Text/TextUpdateTest.js | 1 - Libraries/Types/CoreEventTypes.js | 1 - Libraries/UTFSequence.js | 1 - Libraries/Utilities/BackAndroid.js | 1 - Libraries/Utilities/BackHandler.android.js | 1 - Libraries/Utilities/BackHandler.ios.js | 1 - Libraries/Utilities/DeviceInfo.js | 1 - Libraries/Utilities/Dimensions.js | 1 - Libraries/Utilities/HMRClient.js | 1 - Libraries/Utilities/HMRLoadingView.android.js | 1 - Libraries/Utilities/HMRLoadingView.ios.js | 1 - Libraries/Utilities/HeapCapture.js | 1 - Libraries/Utilities/JSDevSupportModule.js | 1 - Libraries/Utilities/MatrixMath.js | 1 - Libraries/Utilities/PerformanceLogger.js | 1 - Libraries/Utilities/PixelRatio.js | 1 - Libraries/Utilities/Platform.android.js | 1 - Libraries/Utilities/Platform.ios.js | 1 - Libraries/Utilities/PlatformOS.android.js | 1 - Libraries/Utilities/PlatformOS.ios.js | 1 - Libraries/Utilities/PolyfillFunctions.js | 1 - Libraries/Utilities/RCTLog.js | 1 - Libraries/Utilities/SceneTracker.js | 1 - Libraries/Utilities/binaryToBase64.js | 1 - Libraries/Utilities/buildStyleInterpolator.js | 1 - Libraries/Utilities/clamp.js | 1 - .../Utilities/createStrictShapeTypeChecker.js | 1 - .../deepFreezeAndThrowOnMutationInDev.js | 1 - .../Utilities/defineLazyObjectProperty.js | 1 - Libraries/Utilities/deprecatedPropType.js | 1 - Libraries/Utilities/differ/deepDiffer.js | 1 - Libraries/Utilities/differ/insetsDiffer.js | 1 - Libraries/Utilities/differ/matricesDiffer.js | 1 - Libraries/Utilities/differ/pointsDiffer.js | 1 - Libraries/Utilities/differ/sizesDiffer.js | 1 - Libraries/Utilities/dismissKeyboard.js | 1 - Libraries/Utilities/groupByEveryN.js | 1 - Libraries/Utilities/infoLog.js | 1 - Libraries/Utilities/logError.js | 1 - Libraries/Utilities/mapWithSeparator.js | 1 - Libraries/Utilities/mergeFast.js | 1 - Libraries/Utilities/mergeIntoFast.js | 1 - Libraries/Utilities/stringifySafe.js | 1 - Libraries/Utilities/truncate.js | 1 - Libraries/Vibration/Vibration.js | 1 - Libraries/Vibration/VibrationIOS.android.js | 1 - Libraries/Vibration/VibrationIOS.ios.js | 1 - Libraries/WebSocket/WebSocket.js | 1 - Libraries/WebSocket/WebSocketEvent.js | 1 - Libraries/WebSocket/WebSocketInterceptor.js | 1 - Libraries/polyfills/Array.es6.js | 1 - Libraries/polyfills/Array.prototype.es6.js | 1 - Libraries/polyfills/Number.es6.js | 1 - Libraries/polyfills/Object.es6.js | 1 - Libraries/polyfills/Object.es7.js | 1 - Libraries/polyfills/String.prototype.es6.js | 1 - Libraries/polyfills/babelHelpers.js | 1 - Libraries/polyfills/console.js | 1 - Libraries/polyfills/error-guard.js | 1 - Libraries/promiseRejectionIsError.js | 1 - Libraries/react-native/React.js | 1 - .../react-native-implementation.js | 1 - .../react-native/react-native-interface.js | 1 - Libraries/vendor/core/ErrorUtils.js | 1 - Libraries/vendor/core/Map.js | 1 - Libraries/vendor/core/Set.js | 1 - .../core/_shouldPolyfillES6Collection.js | 1 - Libraries/vendor/core/getObjectValues.js | 1 - Libraries/vendor/core/guid.js | 1 - Libraries/vendor/core/isEmpty.js | 1 - Libraries/vendor/core/merge.js | 3 +- Libraries/vendor/core/mergeHelpers.js | 1 - Libraries/vendor/core/mergeInto.js | 3 +- Libraries/vendor/core/toIterator.js | 1 - .../selection/DocumentSelectionState.js | 1 - .../vendor/emitter/EmitterSubscription.js | 1 - Libraries/vendor/emitter/EventEmitter.js | 1 - .../vendor/emitter/EventEmitterWithHolding.js | 1 - Libraries/vendor/emitter/EventHolder.js | 1 - Libraries/vendor/emitter/EventSubscription.js | 1 - .../vendor/emitter/EventSubscriptionVendor.js | 1 - Libraries/vendor/emitter/EventValidator.js | 1 - Libraries/vendor/emitter/mixInEventEmitter.js | 1 - .../RNTesterUnitTestsBundle.js | 1 - RNTester/js/ARTExample.js | 1 - .../js/AccessibilityAndroidExample.android.js | 1 - RNTester/js/AccessibilityIOSExample.js | 1 - RNTester/js/ActionSheetIOSExample.js | 1 - RNTester/js/ActivityIndicatorExample.js | 1 - RNTester/js/AlertExample.js | 1 - RNTester/js/AlertIOSExample.js | 1 - RNTester/js/AnimatedExample.js | 1 - RNTester/js/AnimatedGratuitousApp/AnExApp.js | 1 - .../js/AnimatedGratuitousApp/AnExBobble.js | 1 - .../js/AnimatedGratuitousApp/AnExChained.js | 1 - .../js/AnimatedGratuitousApp/AnExScroll.js | 1 - RNTester/js/AnimatedGratuitousApp/AnExSet.js | 1 - RNTester/js/AnimatedGratuitousApp/AnExTilt.js | 1 - RNTester/js/AppStateExample.js | 1 - RNTester/js/AssetScaledImageExample.js | 1 - RNTester/js/AsyncStorageExample.js | 1 - RNTester/js/BorderExample.js | 1 - RNTester/js/BoxShadowExample.js | 1 - RNTester/js/ButtonExample.js | 1 - RNTester/js/CameraRollExample.js | 1 - RNTester/js/CameraRollView.js | 1 - RNTester/js/CheckBoxExample.js | 1 - RNTester/js/ClipboardExample.js | 1 - RNTester/js/DatePickerAndroidExample.js | 1 - RNTester/js/DatePickerIOSExample.js | 1 - RNTester/js/DimensionsExample.js | 1 - RNTester/js/ExampleTypes.js | 1 - RNTester/js/FlatListExample.js | 1 - RNTester/js/GeolocationExample.js | 1 - RNTester/js/ImageCapInsetsExample.js | 1 - RNTester/js/ImageEditingExample.js | 1 - RNTester/js/ImageExample.js | 1 - RNTester/js/InputAccessoryViewExample.js | 1 - RNTester/js/KeyboardAvoidingViewExample.js | 1 - RNTester/js/LayoutAnimationExample.js | 1 - RNTester/js/LayoutEventsExample.js | 1 - RNTester/js/LayoutExample.js | 1 - RNTester/js/LinkingExample.js | 1 - RNTester/js/ListExampleShared.js | 1 - RNTester/js/ListViewExample.js | 1 - RNTester/js/ListViewGridLayoutExample.js | 1 - RNTester/js/ListViewPagingExample.js | 1 - RNTester/js/MaskedViewExample.js | 1 - RNTester/js/ModalExample.js | 1 - RNTester/js/MultiColumnExample.js | 1 - RNTester/js/NativeAnimationsExample.js | 1 - RNTester/js/NavigatorIOSBarStyleExample.js | 1 - RNTester/js/NavigatorIOSColorsExample.js | 1 - RNTester/js/NavigatorIOSExample.js | 1 - RNTester/js/NetInfoExample.js | 1 - RNTester/js/OrientationChangeExample.js | 1 - RNTester/js/PanResponderExample.js | 1 - .../js/PermissionsExampleAndroid.android.js | 1 - RNTester/js/PickerExample.js | 1 - RNTester/js/PickerIOSExample.js | 1 - RNTester/js/PointerEventsExample.js | 1 - .../js/ProgressBarAndroidExample.android.js | 1 - RNTester/js/ProgressViewIOSExample.js | 1 - RNTester/js/PushNotificationIOSExample.js | 1 - RNTester/js/RCTRootViewIOSExample.js | 1 - RNTester/js/RNTesterActions.js | 1 - RNTester/js/RNTesterApp.android.js | 1 - RNTester/js/RNTesterApp.ios.js | 1 - RNTester/js/RNTesterBlock.js | 1 - RNTester/js/RNTesterButton.js | 1 - RNTester/js/RNTesterExampleContainer.js | 1 - RNTester/js/RNTesterExampleList.js | 1 - RNTester/js/RNTesterList.android.js | 1 - RNTester/js/RNTesterList.ios.js | 1 - RNTester/js/RNTesterNavigationReducer.js | 1 - RNTester/js/RNTesterPage.js | 1 - RNTester/js/RNTesterSettingSwitchRow.js | 1 - RNTester/js/RNTesterStatePersister.js | 1 - RNTester/js/RNTesterTitle.js | 1 - RNTester/js/RTLExample.js | 1 - RNTester/js/RefreshControlExample.js | 1 - .../js/RootViewSizeFlexibilityExampleApp.js | 1 - RNTester/js/SafeAreaViewExample.js | 1 - RNTester/js/ScrollViewExample.js | 1 - RNTester/js/ScrollViewSimpleExample.js | 1 - RNTester/js/SectionListExample.js | 1 - RNTester/js/SegmentedControlIOSExample.js | 1 - RNTester/js/SetPropertiesExampleApp.js | 1 - RNTester/js/ShareExample.js | 1 - RNTester/js/SliderExample.js | 1 - RNTester/js/SnapshotExample.js | 1 - RNTester/js/StatusBarExample.js | 1 - RNTester/js/SwipeableFlatListExample.js | 1 - RNTester/js/SwipeableListViewExample.js | 1 - RNTester/js/SwitchExample.js | 1 - RNTester/js/TVEventHandlerExample.js | 1 - RNTester/js/TabBarIOSBarStyleExample.js | 1 - RNTester/js/TabBarIOSExample.js | 1 - RNTester/js/TextExample.android.js | 1 - RNTester/js/TextExample.ios.js | 1 - RNTester/js/TextInputExample.android.js | 1 - RNTester/js/TextInputExample.ios.js | 1 - RNTester/js/TimePickerAndroidExample.js | 1 - RNTester/js/TimerExample.js | 1 - RNTester/js/ToastAndroidExample.android.js | 1 - RNTester/js/ToolbarAndroidExample.android.js | 1 - RNTester/js/ToolbarAndroidExample.ios.js | 1 - RNTester/js/TouchableExample.js | 1 - RNTester/js/TransformExample.js | 1 - RNTester/js/TransparentHitTestExample.js | 1 - RNTester/js/URIActionMap.js | 1 - RNTester/js/VibrationExample.js | 1 - RNTester/js/VibrationIOSExample.js | 1 - RNTester/js/ViewExample.js | 1 - .../js/ViewPagerAndroidExample.android.js | 1 - RNTester/js/WebSocketExample.js | 1 - RNTester/js/WebViewExample.js | 1 - RNTester/js/XHRExample.js | 1 - RNTester/js/XHRExampleBinaryUpload.js | 1 - RNTester/js/XHRExampleCookies.js | 1 - RNTester/js/XHRExampleDownload.js | 1 - RNTester/js/XHRExampleFetch.js | 1 - RNTester/js/XHRExampleFormData.js | 1 - RNTester/js/XHRExampleHeaders.js | 1 - RNTester/js/XHRExampleOnTimeOut.js | 1 - RNTester/js/createExamplePage.js | 1 - RNTester/js/http_test_server.js | 1 - RNTester/js/websocket_test_server.js | 1 - ReactAndroid/src/androidTest/js/Asserts.js | 1 - .../js/CatalystRootViewTestModule.js | 1 - .../js/DatePickerDialogTestModule.js | 1 - .../src/androidTest/js/InitialPropsTestApp.js | 1 - .../src/androidTest/js/JSResponderTestApp.js | 1 - .../src/androidTest/js/LayoutEventsTestApp.js | 1 - .../androidTest/js/MeasureLayoutTestModule.js | 1 - .../js/MultitouchHandlingTestAppModule.js | 1 - .../src/androidTest/js/NativeIdTestModule.js | 1 - .../androidTest/js/PickerAndroidTestModule.js | 1 - .../androidTest/js/ProgressBarTestModule.js | 1 - .../androidTest/js/ScrollViewTestModule.js | 1 - .../src/androidTest/js/ShareTestModule.js | 1 - .../js/SubviewsClippingTestModule.js | 1 - .../js/SwipeRefreshLayoutTestModule.js | 1 - ReactAndroid/src/androidTest/js/TestBundle.js | 1 - .../src/androidTest/js/TestIdTestModule.js | 1 - .../src/androidTest/js/TestJSLocaleModule.js | 1 - .../js/TestJSToJavaParametersModule.js | 1 - .../js/TestJavaToJSArgumentsModule.js | 1 - .../js/TestJavaToJSReturnValuesModule.js | 1 - .../src/androidTest/js/TextInputTestModule.js | 1 - .../js/TimePickerDialogTestModule.js | 1 - .../js/TouchBubblingTestAppModule.js | 1 - .../src/androidTest/js/UIManagerTestModule.js | 1 - .../androidTest/js/ViewRenderingTestModule.js | 1 - jest/hasteImpl.js | 75 +++++++++++++++++++ local-cli/core/index.js | 2 + package.json | 1 + 543 files changed, 97 insertions(+), 541 deletions(-) create mode 100644 jest/hasteImpl.js diff --git a/.flowconfig b/.flowconfig index 386c9389a49803..cd3dd707a7223b 100644 --- a/.flowconfig +++ b/.flowconfig @@ -36,6 +36,23 @@ flow-github/ emoji=true 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.blacklist=/Libraries/Animated/src/polyfills/.* +module.system.haste.paths.whitelist=/Libraries/.* +module.system.haste.paths.whitelist=/RNTester/.* +module.system.haste.paths.whitelist=/IntegrationTests/.* +module.system.haste.paths.blacklist=/Libraries/Animated/src/polyfills/.* munge_underscores=true diff --git a/IntegrationTests/AccessibilityManagerTest.js b/IntegrationTests/AccessibilityManagerTest.js index 74dbe9ba19edab..4287094d375905 100644 --- a/IntegrationTests/AccessibilityManagerTest.js +++ b/IntegrationTests/AccessibilityManagerTest.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule AccessibilityManagerTest */ 'use strict'; diff --git a/IntegrationTests/AppEventsTest.js b/IntegrationTests/AppEventsTest.js index ae061e167b86d8..af04819b38fd67 100644 --- a/IntegrationTests/AppEventsTest.js +++ b/IntegrationTests/AppEventsTest.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AppEventsTest * @flow */ 'use strict'; diff --git a/IntegrationTests/AsyncStorageTest.js b/IntegrationTests/AsyncStorageTest.js index 3ce0265dd8ceb0..2d951dab3984c5 100644 --- a/IntegrationTests/AsyncStorageTest.js +++ b/IntegrationTests/AsyncStorageTest.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule AsyncStorageTest */ 'use strict'; diff --git a/IntegrationTests/ImageCachePolicyTest.js b/IntegrationTests/ImageCachePolicyTest.js index d6fa4f544a1bf9..a095b4ec99128a 100644 --- a/IntegrationTests/ImageCachePolicyTest.js +++ b/IntegrationTests/ImageCachePolicyTest.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule ImageCachePolicyTest */ 'use strict'; diff --git a/IntegrationTests/ImageSnapshotTest.js b/IntegrationTests/ImageSnapshotTest.js index 8ba7734286d673..3d024d569da669 100644 --- a/IntegrationTests/ImageSnapshotTest.js +++ b/IntegrationTests/ImageSnapshotTest.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule ImageSnapshotTest */ 'use strict'; diff --git a/IntegrationTests/IntegrationTestHarnessTest.js b/IntegrationTests/IntegrationTestHarnessTest.js index 6291c915d68643..9b34065b8fd6d4 100644 --- a/IntegrationTests/IntegrationTestHarnessTest.js +++ b/IntegrationTests/IntegrationTestHarnessTest.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule IntegrationTestHarnessTest */ 'use strict'; diff --git a/IntegrationTests/IntegrationTestsApp.js b/IntegrationTests/IntegrationTestsApp.js index 6b255c2befe54a..62f6fa83057b3c 100644 --- a/IntegrationTests/IntegrationTestsApp.js +++ b/IntegrationTests/IntegrationTestsApp.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule IntegrationTestsApp */ 'use strict'; diff --git a/IntegrationTests/LayoutEventsTest.js b/IntegrationTests/LayoutEventsTest.js index 769ff98f6be8b5..31dd1839c86cfc 100644 --- a/IntegrationTests/LayoutEventsTest.js +++ b/IntegrationTests/LayoutEventsTest.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule LayoutEventsTest * @flow */ 'use strict'; diff --git a/IntegrationTests/LoggingTestModule.js b/IntegrationTests/LoggingTestModule.js index 25b409353ce1d4..df2b0e59b52414 100644 --- a/IntegrationTests/LoggingTestModule.js +++ b/IntegrationTests/LoggingTestModule.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule LoggingTestModule */ 'use strict'; diff --git a/IntegrationTests/PromiseTest.js b/IntegrationTests/PromiseTest.js index f6a81e3d6d5d16..21005576d678d0 100644 --- a/IntegrationTests/PromiseTest.js +++ b/IntegrationTests/PromiseTest.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule PromiseTest */ 'use strict'; diff --git a/IntegrationTests/PropertiesUpdateTest.js b/IntegrationTests/PropertiesUpdateTest.js index 623dc82c8ee94b..3d93d9d0ac238f 100644 --- a/IntegrationTests/PropertiesUpdateTest.js +++ b/IntegrationTests/PropertiesUpdateTest.js @@ -3,7 +3,6 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * @providesModule PropertiesUpdateTest */ 'use strict'; diff --git a/IntegrationTests/RCTRootViewIntegrationTestApp.js b/IntegrationTests/RCTRootViewIntegrationTestApp.js index a97873d2c3224e..aef56f97599220 100644 --- a/IntegrationTests/RCTRootViewIntegrationTestApp.js +++ b/IntegrationTests/RCTRootViewIntegrationTestApp.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule RCTRootViewIntegrationTestApp */ 'use strict'; diff --git a/IntegrationTests/ReactContentSizeUpdateTest.js b/IntegrationTests/ReactContentSizeUpdateTest.js index c5f5ae80c246b0..dda42b4df9c875 100644 --- a/IntegrationTests/ReactContentSizeUpdateTest.js +++ b/IntegrationTests/ReactContentSizeUpdateTest.js @@ -3,7 +3,6 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * @providesModule ReactContentSizeUpdateTest */ 'use strict'; diff --git a/IntegrationTests/SimpleSnapshotTest.js b/IntegrationTests/SimpleSnapshotTest.js index 1c0be2a431d469..dd8bf9ac8731e7 100644 --- a/IntegrationTests/SimpleSnapshotTest.js +++ b/IntegrationTests/SimpleSnapshotTest.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule SimpleSnapshotTest */ 'use strict'; diff --git a/IntegrationTests/SizeFlexibilityUpdateTest.js b/IntegrationTests/SizeFlexibilityUpdateTest.js index 679694a0d631ce..ce0be9e6e2229d 100644 --- a/IntegrationTests/SizeFlexibilityUpdateTest.js +++ b/IntegrationTests/SizeFlexibilityUpdateTest.js @@ -3,7 +3,6 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * @providesModule SizeFlexibilityUpdateTest */ 'use strict'; diff --git a/IntegrationTests/SyncMethodTest.js b/IntegrationTests/SyncMethodTest.js index 6318eaa4f14282..f61f52b3610600 100644 --- a/IntegrationTests/SyncMethodTest.js +++ b/IntegrationTests/SyncMethodTest.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule SyncMethodTest */ 'use strict'; diff --git a/IntegrationTests/TimersTest.js b/IntegrationTests/TimersTest.js index 23da99dc6edbdc..f40742c9a8b008 100644 --- a/IntegrationTests/TimersTest.js +++ b/IntegrationTests/TimersTest.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule TimersTest */ 'use strict'; diff --git a/IntegrationTests/WebSocketTest.js b/IntegrationTests/WebSocketTest.js index 6e459f913babc3..de8428f79e6acb 100644 --- a/IntegrationTests/WebSocketTest.js +++ b/IntegrationTests/WebSocketTest.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule WebSocketTest */ 'use strict'; diff --git a/IntegrationTests/WebViewTest.js b/IntegrationTests/WebViewTest.js index a41e244b58be3a..499e1c095400aa 100644 --- a/IntegrationTests/WebViewTest.js +++ b/IntegrationTests/WebViewTest.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule WebViewTest */ 'use strict'; diff --git a/IntegrationTests/websocket_integration_test_server.js b/IntegrationTests/websocket_integration_test_server.js index e338d85ae3b89d..763668f3275da8 100755 --- a/IntegrationTests/websocket_integration_test_server.js +++ b/IntegrationTests/websocket_integration_test_server.js @@ -7,7 +7,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule websocket_integration_test_server */ 'use strict'; diff --git a/Libraries/ART/ARTSerializablePath.js b/Libraries/ART/ARTSerializablePath.js index 7f52bc6540eda2..08c4530222dff3 100644 --- a/Libraries/ART/ARTSerializablePath.js +++ b/Libraries/ART/ARTSerializablePath.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ARTSerializablePath */ 'use strict'; diff --git a/Libraries/ART/ReactNativeART.js b/Libraries/ART/ReactNativeART.js index 7d9f1b59063459..9b0a725cd140ec 100644 --- a/Libraries/ART/ReactNativeART.js +++ b/Libraries/ART/ReactNativeART.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ReactNativeART */ 'use strict'; diff --git a/Libraries/ActionSheetIOS/ActionSheetIOS.js b/Libraries/ActionSheetIOS/ActionSheetIOS.js index 23db7680ab34e1..b135a23e5fc998 100644 --- a/Libraries/ActionSheetIOS/ActionSheetIOS.js +++ b/Libraries/ActionSheetIOS/ActionSheetIOS.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ActionSheetIOS * @flow * @format */ diff --git a/Libraries/Alert/Alert.js b/Libraries/Alert/Alert.js index bcb51714440444..ed78335043c53e 100644 --- a/Libraries/Alert/Alert.js +++ b/Libraries/Alert/Alert.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Alert * @flow */ 'use strict'; diff --git a/Libraries/Alert/AlertIOS.js b/Libraries/Alert/AlertIOS.js index b254406462399e..eb15d1cdee0313 100644 --- a/Libraries/Alert/AlertIOS.js +++ b/Libraries/Alert/AlertIOS.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AlertIOS * @flow * @jsdoc */ diff --git a/Libraries/Alert/RCTAlertManager.android.js b/Libraries/Alert/RCTAlertManager.android.js index f819b55e1b3d1f..25297171c4ce46 100644 --- a/Libraries/Alert/RCTAlertManager.android.js +++ b/Libraries/Alert/RCTAlertManager.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule RCTAlertManager */ 'use strict'; diff --git a/Libraries/Alert/RCTAlertManager.ios.js b/Libraries/Alert/RCTAlertManager.ios.js index 3aef740abed4d5..220b72c3d91ded 100644 --- a/Libraries/Alert/RCTAlertManager.ios.js +++ b/Libraries/Alert/RCTAlertManager.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule RCTAlertManager * @flow */ 'use strict'; diff --git a/Libraries/Animated/release/gulpfile.js b/Libraries/Animated/release/gulpfile.js index b454ea790c2731..f5e87b4c998709 100644 --- a/Libraries/Animated/release/gulpfile.js +++ b/Libraries/Animated/release/gulpfile.js @@ -3,7 +3,6 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * @providesModule gulpfile */ 'use strict'; diff --git a/Libraries/Animated/src/Animated.js b/Libraries/Animated/src/Animated.js index 32ec9ff8046954..f25d2a0796a1ad 100644 --- a/Libraries/Animated/src/Animated.js +++ b/Libraries/Animated/src/Animated.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Animated * @flow * @format */ diff --git a/Libraries/Animated/src/AnimatedEvent.js b/Libraries/Animated/src/AnimatedEvent.js index f9300feb4e79ea..084632737c661d 100644 --- a/Libraries/Animated/src/AnimatedEvent.js +++ b/Libraries/Animated/src/AnimatedEvent.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AnimatedEvent * @flow * @format */ diff --git a/Libraries/Animated/src/AnimatedImplementation.js b/Libraries/Animated/src/AnimatedImplementation.js index 9291a7956531e3..2c1ce431d10686 100644 --- a/Libraries/Animated/src/AnimatedImplementation.js +++ b/Libraries/Animated/src/AnimatedImplementation.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AnimatedImplementation * @flow * @format * @preventMunge diff --git a/Libraries/Animated/src/AnimatedWeb.js b/Libraries/Animated/src/AnimatedWeb.js index f3af397b740931..a22bd075ec51ce 100644 --- a/Libraries/Animated/src/AnimatedWeb.js +++ b/Libraries/Animated/src/AnimatedWeb.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule AnimatedWeb */ 'use strict'; diff --git a/Libraries/Animated/src/Easing.js b/Libraries/Animated/src/Easing.js index f5c00fd813f7dc..5fb4478eef63f7 100644 --- a/Libraries/Animated/src/Easing.js +++ b/Libraries/Animated/src/Easing.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Easing * @flow */ 'use strict'; diff --git a/Libraries/Animated/src/NativeAnimatedHelper.js b/Libraries/Animated/src/NativeAnimatedHelper.js index 68bf4563fa9597..61b2bde64a4d75 100644 --- a/Libraries/Animated/src/NativeAnimatedHelper.js +++ b/Libraries/Animated/src/NativeAnimatedHelper.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule NativeAnimatedHelper * @flow * @format */ diff --git a/Libraries/Animated/src/SpringConfig.js b/Libraries/Animated/src/SpringConfig.js index 5b476f6723469e..6227c28301b4e3 100644 --- a/Libraries/Animated/src/SpringConfig.js +++ b/Libraries/Animated/src/SpringConfig.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule SpringConfig * @flow */ diff --git a/Libraries/Animated/src/animations/Animation.js b/Libraries/Animated/src/animations/Animation.js index 000e44d77f9bc8..b4e38016dba557 100644 --- a/Libraries/Animated/src/animations/Animation.js +++ b/Libraries/Animated/src/animations/Animation.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Animation * @flow * @format */ diff --git a/Libraries/Animated/src/animations/DecayAnimation.js b/Libraries/Animated/src/animations/DecayAnimation.js index 7df0e104b72f48..78f6e2b7cc8524 100644 --- a/Libraries/Animated/src/animations/DecayAnimation.js +++ b/Libraries/Animated/src/animations/DecayAnimation.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule DecayAnimation * @flow * @format */ diff --git a/Libraries/Animated/src/animations/SpringAnimation.js b/Libraries/Animated/src/animations/SpringAnimation.js index 8b6f96fe67bdb6..2bc610eed752b7 100644 --- a/Libraries/Animated/src/animations/SpringAnimation.js +++ b/Libraries/Animated/src/animations/SpringAnimation.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule SpringAnimation * @flow * @format */ diff --git a/Libraries/Animated/src/animations/TimingAnimation.js b/Libraries/Animated/src/animations/TimingAnimation.js index 1b6a4ae94cd9b0..694a52c0a39f7b 100644 --- a/Libraries/Animated/src/animations/TimingAnimation.js +++ b/Libraries/Animated/src/animations/TimingAnimation.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TimingAnimation * @flow * @format */ diff --git a/Libraries/Animated/src/bezier.js b/Libraries/Animated/src/bezier.js index 2bd594930064c9..9aa777a124931a 100644 --- a/Libraries/Animated/src/bezier.js +++ b/Libraries/Animated/src/bezier.js @@ -3,7 +3,6 @@ * https://github.com/gre/bezier-easing * * @copyright 2014-2015 Gaëtan Renaudeau. MIT License. - * @providesModule bezier * @noflow */ 'use strict'; diff --git a/Libraries/Animated/src/createAnimatedComponent.js b/Libraries/Animated/src/createAnimatedComponent.js index 357ee0bd59bcd1..d876af645c4e0c 100644 --- a/Libraries/Animated/src/createAnimatedComponent.js +++ b/Libraries/Animated/src/createAnimatedComponent.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule createAnimatedComponent * @flow * @format */ diff --git a/Libraries/Animated/src/nodes/AnimatedAddition.js b/Libraries/Animated/src/nodes/AnimatedAddition.js index 2e3453965565f0..60713da500213c 100644 --- a/Libraries/Animated/src/nodes/AnimatedAddition.js +++ b/Libraries/Animated/src/nodes/AnimatedAddition.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AnimatedAddition * @flow * @format */ diff --git a/Libraries/Animated/src/nodes/AnimatedDiffClamp.js b/Libraries/Animated/src/nodes/AnimatedDiffClamp.js index 0f64e75c723c06..4219eccfb377ff 100644 --- a/Libraries/Animated/src/nodes/AnimatedDiffClamp.js +++ b/Libraries/Animated/src/nodes/AnimatedDiffClamp.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AnimatedDiffClamp * @flow * @format */ diff --git a/Libraries/Animated/src/nodes/AnimatedDivision.js b/Libraries/Animated/src/nodes/AnimatedDivision.js index 606e63937b9a86..3498d322211f64 100644 --- a/Libraries/Animated/src/nodes/AnimatedDivision.js +++ b/Libraries/Animated/src/nodes/AnimatedDivision.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AnimatedDivision * @flow * @format */ diff --git a/Libraries/Animated/src/nodes/AnimatedInterpolation.js b/Libraries/Animated/src/nodes/AnimatedInterpolation.js index bc7b1365879db8..e8f9823c20e4f4 100644 --- a/Libraries/Animated/src/nodes/AnimatedInterpolation.js +++ b/Libraries/Animated/src/nodes/AnimatedInterpolation.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AnimatedInterpolation * @flow * @format */ diff --git a/Libraries/Animated/src/nodes/AnimatedModulo.js b/Libraries/Animated/src/nodes/AnimatedModulo.js index 24cd3f0b077c12..6699ded50a658a 100644 --- a/Libraries/Animated/src/nodes/AnimatedModulo.js +++ b/Libraries/Animated/src/nodes/AnimatedModulo.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AnimatedModulo * @flow * @format */ diff --git a/Libraries/Animated/src/nodes/AnimatedMultiplication.js b/Libraries/Animated/src/nodes/AnimatedMultiplication.js index dc01f7f17127f1..889f530c76baee 100644 --- a/Libraries/Animated/src/nodes/AnimatedMultiplication.js +++ b/Libraries/Animated/src/nodes/AnimatedMultiplication.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AnimatedMultiplication * @flow * @format */ diff --git a/Libraries/Animated/src/nodes/AnimatedNode.js b/Libraries/Animated/src/nodes/AnimatedNode.js index e75cfaf0e5c8fb..34e010a62f8c45 100644 --- a/Libraries/Animated/src/nodes/AnimatedNode.js +++ b/Libraries/Animated/src/nodes/AnimatedNode.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AnimatedNode * @flow * @format */ diff --git a/Libraries/Animated/src/nodes/AnimatedProps.js b/Libraries/Animated/src/nodes/AnimatedProps.js index 78cd11189edfa7..75c9c25487135a 100644 --- a/Libraries/Animated/src/nodes/AnimatedProps.js +++ b/Libraries/Animated/src/nodes/AnimatedProps.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AnimatedProps * @flow * @format */ diff --git a/Libraries/Animated/src/nodes/AnimatedStyle.js b/Libraries/Animated/src/nodes/AnimatedStyle.js index c7bb24e3b42b14..990b960a336805 100644 --- a/Libraries/Animated/src/nodes/AnimatedStyle.js +++ b/Libraries/Animated/src/nodes/AnimatedStyle.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AnimatedStyle * @flow * @format */ diff --git a/Libraries/Animated/src/nodes/AnimatedSubtraction.js b/Libraries/Animated/src/nodes/AnimatedSubtraction.js index 610fc226eb65a8..3fe8bbb6920703 100644 --- a/Libraries/Animated/src/nodes/AnimatedSubtraction.js +++ b/Libraries/Animated/src/nodes/AnimatedSubtraction.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AnimatedSubtraction * @flow * @format */ diff --git a/Libraries/Animated/src/nodes/AnimatedTracking.js b/Libraries/Animated/src/nodes/AnimatedTracking.js index cf20d6e8bbf3fc..699da167c7b2c7 100644 --- a/Libraries/Animated/src/nodes/AnimatedTracking.js +++ b/Libraries/Animated/src/nodes/AnimatedTracking.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AnimatedTracking * @flow * @format */ diff --git a/Libraries/Animated/src/nodes/AnimatedTransform.js b/Libraries/Animated/src/nodes/AnimatedTransform.js index 48f82f9fe3443d..1706923394ec96 100644 --- a/Libraries/Animated/src/nodes/AnimatedTransform.js +++ b/Libraries/Animated/src/nodes/AnimatedTransform.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AnimatedTransform * @flow * @format */ diff --git a/Libraries/Animated/src/nodes/AnimatedValue.js b/Libraries/Animated/src/nodes/AnimatedValue.js index 9d06c751cefbea..a3fb3a325b838e 100644 --- a/Libraries/Animated/src/nodes/AnimatedValue.js +++ b/Libraries/Animated/src/nodes/AnimatedValue.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AnimatedValue * @flow * @format */ diff --git a/Libraries/Animated/src/nodes/AnimatedValueXY.js b/Libraries/Animated/src/nodes/AnimatedValueXY.js index 52c207c0f42ffe..3de5bbaf9d3a04 100644 --- a/Libraries/Animated/src/nodes/AnimatedValueXY.js +++ b/Libraries/Animated/src/nodes/AnimatedValueXY.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AnimatedValueXY * @flow * @format */ diff --git a/Libraries/Animated/src/nodes/AnimatedWithChildren.js b/Libraries/Animated/src/nodes/AnimatedWithChildren.js index 1f58cd834e165e..9cd5fb49e14070 100644 --- a/Libraries/Animated/src/nodes/AnimatedWithChildren.js +++ b/Libraries/Animated/src/nodes/AnimatedWithChildren.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AnimatedWithChildren * @flow * @format */ diff --git a/Libraries/AppState/AppState.js b/Libraries/AppState/AppState.js index f2faa9480d2b57..ecb106bb24e863 100644 --- a/Libraries/AppState/AppState.js +++ b/Libraries/AppState/AppState.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AppState * @flow */ 'use strict'; diff --git a/Libraries/BatchedBridge/BatchedBridge.js b/Libraries/BatchedBridge/BatchedBridge.js index 516c2ac1e22339..bc66ae32f9f4c6 100644 --- a/Libraries/BatchedBridge/BatchedBridge.js +++ b/Libraries/BatchedBridge/BatchedBridge.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule BatchedBridge * @flow */ 'use strict'; diff --git a/Libraries/BatchedBridge/MessageQueue.js b/Libraries/BatchedBridge/MessageQueue.js index ef689333917db1..5c2338d033e833 100644 --- a/Libraries/BatchedBridge/MessageQueue.js +++ b/Libraries/BatchedBridge/MessageQueue.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule MessageQueue * @flow * @format */ diff --git a/Libraries/BatchedBridge/NativeModules.js b/Libraries/BatchedBridge/NativeModules.js index 324c4f6e995bdd..a5f9911499956e 100644 --- a/Libraries/BatchedBridge/NativeModules.js +++ b/Libraries/BatchedBridge/NativeModules.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule NativeModules * @flow */ 'use strict'; diff --git a/Libraries/Blob/Blob.js b/Libraries/Blob/Blob.js index eca13a6a309e8f..0e36b07f7f4e5a 100644 --- a/Libraries/Blob/Blob.js +++ b/Libraries/Blob/Blob.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Blob * @flow * @format */ diff --git a/Libraries/Blob/BlobManager.js b/Libraries/Blob/BlobManager.js index dd7cc00eabc652..b08082e35e1580 100644 --- a/Libraries/Blob/BlobManager.js +++ b/Libraries/Blob/BlobManager.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule BlobManager * @flow * @format */ diff --git a/Libraries/Blob/BlobRegistry.js b/Libraries/Blob/BlobRegistry.js index 330c1659ae4235..d78a9d26656e07 100644 --- a/Libraries/Blob/BlobRegistry.js +++ b/Libraries/Blob/BlobRegistry.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule BlobRegistry * @flow * @format */ diff --git a/Libraries/Blob/BlobTypes.js b/Libraries/Blob/BlobTypes.js index 8e895d9006108f..b03922f24f32c5 100644 --- a/Libraries/Blob/BlobTypes.js +++ b/Libraries/Blob/BlobTypes.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule BlobTypes * @flow * @format */ diff --git a/Libraries/Blob/File.js b/Libraries/Blob/File.js index f5b03d85f7f178..2f57183cdb3f19 100644 --- a/Libraries/Blob/File.js +++ b/Libraries/Blob/File.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule File * @flow * @format */ diff --git a/Libraries/Blob/FileReader.js b/Libraries/Blob/FileReader.js index b3ed89dc9318e6..309e4577a455f8 100644 --- a/Libraries/Blob/FileReader.js +++ b/Libraries/Blob/FileReader.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule FileReader * @flow * @format */ diff --git a/Libraries/Blob/URL.js b/Libraries/Blob/URL.js index 7349f7752f268c..de73affac2af1b 100644 --- a/Libraries/Blob/URL.js +++ b/Libraries/Blob/URL.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule URL * @format * @flow */ diff --git a/Libraries/BugReporting/BugReporting.js b/Libraries/BugReporting/BugReporting.js index 11a59e6d5222ca..f196276c36fae6 100644 --- a/Libraries/BugReporting/BugReporting.js +++ b/Libraries/BugReporting/BugReporting.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule BugReporting * @flow */ 'use strict'; diff --git a/Libraries/BugReporting/dumpReactTree.js b/Libraries/BugReporting/dumpReactTree.js index f8a137ceff7f2c..6ffe64244e50f9 100644 --- a/Libraries/BugReporting/dumpReactTree.js +++ b/Libraries/BugReporting/dumpReactTree.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule dumpReactTree * @flow */ 'use strict'; diff --git a/Libraries/BugReporting/getReactData.js b/Libraries/BugReporting/getReactData.js index 53c8fb6ccfc110..3f7a1a903d6675 100644 --- a/Libraries/BugReporting/getReactData.js +++ b/Libraries/BugReporting/getReactData.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule getReactData * @flow */ 'use strict'; diff --git a/Libraries/CameraRoll/CameraRoll.js b/Libraries/CameraRoll/CameraRoll.js index 3bc48664f35db1..f2a4f65aa80933 100644 --- a/Libraries/CameraRoll/CameraRoll.js +++ b/Libraries/CameraRoll/CameraRoll.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule CameraRoll * @flow * @format */ diff --git a/Libraries/CameraRoll/ImagePickerIOS.js b/Libraries/CameraRoll/ImagePickerIOS.js index 24d1309d2e1b91..fe50825da14222 100644 --- a/Libraries/CameraRoll/ImagePickerIOS.js +++ b/Libraries/CameraRoll/ImagePickerIOS.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ImagePickerIOS * @flow */ 'use strict'; diff --git a/Libraries/Color/normalizeColor.js b/Libraries/Color/normalizeColor.js index 09c2e1525d5473..de62e68dad0a06 100755 --- a/Libraries/Color/normalizeColor.js +++ b/Libraries/Color/normalizeColor.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule normalizeColor * @flow */ /* eslint no-bitwise: 0 */ diff --git a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js index afc4abe1533a72..232370b5cbf827 100644 --- a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js +++ b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AccessibilityInfo * @flow */ 'use strict'; diff --git a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.ios.js b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.ios.js index 6e39b5e477d5fb..d1b36494e99acb 100644 --- a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.ios.js +++ b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AccessibilityInfo * @flow */ 'use strict'; diff --git a/Libraries/Components/ActivityIndicator/ActivityIndicator.js b/Libraries/Components/ActivityIndicator/ActivityIndicator.js index a520b657904738..9692cbf8073e11 100644 --- a/Libraries/Components/ActivityIndicator/ActivityIndicator.js +++ b/Libraries/Components/ActivityIndicator/ActivityIndicator.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ActivityIndicator * @flow */ 'use strict'; diff --git a/Libraries/Components/AppleTV/TVEventHandler.js b/Libraries/Components/AppleTV/TVEventHandler.js index 363d50d903d876..303e07617f9825 100644 --- a/Libraries/Components/AppleTV/TVEventHandler.js +++ b/Libraries/Components/AppleTV/TVEventHandler.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TVEventHandler * @flow */ 'use strict'; diff --git a/Libraries/Components/AppleTV/TVViewPropTypes.js b/Libraries/Components/AppleTV/TVViewPropTypes.js index 2b6a6d4e53dcd1..831d5c3992d746 100644 --- a/Libraries/Components/AppleTV/TVViewPropTypes.js +++ b/Libraries/Components/AppleTV/TVViewPropTypes.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TVViewPropTypes * @flow */ 'use strict'; diff --git a/Libraries/Components/Button.js b/Libraries/Components/Button.js index 51ca2aa636c359..2956b1a1245b52 100644 --- a/Libraries/Components/Button.js +++ b/Libraries/Components/Button.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Button * @flow */ 'use strict'; diff --git a/Libraries/Components/CheckBox/CheckBox.android.js b/Libraries/Components/CheckBox/CheckBox.android.js index e4a14c6f73dafb..5417a0e811debe 100644 --- a/Libraries/Components/CheckBox/CheckBox.android.js +++ b/Libraries/Components/CheckBox/CheckBox.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule CheckBox * @flow * @format */ diff --git a/Libraries/Components/CheckBox/CheckBox.ios.js b/Libraries/Components/CheckBox/CheckBox.ios.js index 386255541d47ec..5fda2cd5ec2bce 100644 --- a/Libraries/Components/CheckBox/CheckBox.ios.js +++ b/Libraries/Components/CheckBox/CheckBox.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule CheckBox * @flow * @format */ diff --git a/Libraries/Components/Clipboard/Clipboard.js b/Libraries/Components/Clipboard/Clipboard.js index 80d067cce257c0..0bf3b470774c1c 100644 --- a/Libraries/Components/Clipboard/Clipboard.js +++ b/Libraries/Components/Clipboard/Clipboard.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Clipboard * @flow */ 'use strict'; diff --git a/Libraries/Components/DatePicker/DatePickerIOS.android.js b/Libraries/Components/DatePicker/DatePickerIOS.android.js index 2a0d8998bfb556..d2053808699cad 100644 --- a/Libraries/Components/DatePicker/DatePickerIOS.android.js +++ b/Libraries/Components/DatePicker/DatePickerIOS.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule DatePickerIOS */ 'use strict'; diff --git a/Libraries/Components/DatePicker/DatePickerIOS.ios.js b/Libraries/Components/DatePicker/DatePickerIOS.ios.js index b08bf8f93412bf..41b0a88969ab37 100644 --- a/Libraries/Components/DatePicker/DatePickerIOS.ios.js +++ b/Libraries/Components/DatePicker/DatePickerIOS.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule DatePickerIOS * @flow * * This is a controlled component version of RCTDatePickerIOS diff --git a/Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js b/Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js index 750ed921f0684b..23691ce10882de 100644 --- a/Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js +++ b/Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule DatePickerAndroid * @flow */ 'use strict'; diff --git a/Libraries/Components/DatePickerAndroid/DatePickerAndroid.ios.js b/Libraries/Components/DatePickerAndroid/DatePickerAndroid.ios.js index a23602128078f8..4895dfd8286d18 100644 --- a/Libraries/Components/DatePickerAndroid/DatePickerAndroid.ios.js +++ b/Libraries/Components/DatePickerAndroid/DatePickerAndroid.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule DatePickerAndroid * @flow */ 'use strict'; diff --git a/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js b/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js index 6a20d894f4f4c4..f9d84442448b80 100644 --- a/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js +++ b/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule DrawerLayoutAndroid */ 'use strict'; diff --git a/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.ios.js b/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.ios.js index d5b950c5b41ef0..ebd42dd5b18bb0 100644 --- a/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.ios.js +++ b/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule DrawerLayoutAndroid */ 'use strict'; diff --git a/Libraries/Components/Keyboard/Keyboard.js b/Libraries/Components/Keyboard/Keyboard.js index 55d9891902ea7a..d61b07a88670f7 100644 --- a/Libraries/Components/Keyboard/Keyboard.js +++ b/Libraries/Components/Keyboard/Keyboard.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Keyboard * @flow */ 'use strict'; diff --git a/Libraries/Components/Keyboard/KeyboardAvoidingView.js b/Libraries/Components/Keyboard/KeyboardAvoidingView.js index ffb6c58fe6379f..87a0172f2091c0 100644 --- a/Libraries/Components/Keyboard/KeyboardAvoidingView.js +++ b/Libraries/Components/Keyboard/KeyboardAvoidingView.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule KeyboardAvoidingView * @flow */ 'use strict'; diff --git a/Libraries/Components/LazyRenderer.js b/Libraries/Components/LazyRenderer.js index 851bf55feee032..b1217aa1f3a2a9 100644 --- a/Libraries/Components/LazyRenderer.js +++ b/Libraries/Components/LazyRenderer.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule LazyRenderer */ 'use strict'; diff --git a/Libraries/Components/MaskedView/MaskedViewIOS.android.js b/Libraries/Components/MaskedView/MaskedViewIOS.android.js index ad37017e1c201b..9684447d0fea12 100644 --- a/Libraries/Components/MaskedView/MaskedViewIOS.android.js +++ b/Libraries/Components/MaskedView/MaskedViewIOS.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule MaskedViewIOS * @flow */ 'use strict'; diff --git a/Libraries/Components/MaskedView/MaskedViewIOS.ios.js b/Libraries/Components/MaskedView/MaskedViewIOS.ios.js index 0d61728c4b29b1..0407d3be089f04 100644 --- a/Libraries/Components/MaskedView/MaskedViewIOS.ios.js +++ b/Libraries/Components/MaskedView/MaskedViewIOS.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule MaskedViewIOS * @flow */ diff --git a/Libraries/Components/Navigation/NavigatorIOS.android.js b/Libraries/Components/Navigation/NavigatorIOS.android.js index 271f7ea0143fc5..ebd42dd5b18bb0 100644 --- a/Libraries/Components/Navigation/NavigatorIOS.android.js +++ b/Libraries/Components/Navigation/NavigatorIOS.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule NavigatorIOS */ 'use strict'; diff --git a/Libraries/Components/Navigation/NavigatorIOS.ios.js b/Libraries/Components/Navigation/NavigatorIOS.ios.js index 289680bf6fc6f3..36223bfadca306 100644 --- a/Libraries/Components/Navigation/NavigatorIOS.ios.js +++ b/Libraries/Components/Navigation/NavigatorIOS.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule NavigatorIOS * @flow */ 'use strict'; diff --git a/Libraries/Components/Picker/Picker.js b/Libraries/Components/Picker/Picker.js index 1df316249d7ce7..1212993191069a 100644 --- a/Libraries/Components/Picker/Picker.js +++ b/Libraries/Components/Picker/Picker.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Picker * @flow */ diff --git a/Libraries/Components/Picker/PickerAndroid.android.js b/Libraries/Components/Picker/PickerAndroid.android.js index bd9c664a8fa5d6..6bc912bd6d33d3 100644 --- a/Libraries/Components/Picker/PickerAndroid.android.js +++ b/Libraries/Components/Picker/PickerAndroid.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule PickerAndroid * @flow */ diff --git a/Libraries/Components/Picker/PickerAndroid.ios.js b/Libraries/Components/Picker/PickerAndroid.ios.js index b84e15bad67af0..ebd42dd5b18bb0 100644 --- a/Libraries/Components/Picker/PickerAndroid.ios.js +++ b/Libraries/Components/Picker/PickerAndroid.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule PickerAndroid */ 'use strict'; diff --git a/Libraries/Components/Picker/PickerIOS.android.js b/Libraries/Components/Picker/PickerIOS.android.js index ce50c2ad4e4157..2977696844b00f 100644 --- a/Libraries/Components/Picker/PickerIOS.android.js +++ b/Libraries/Components/Picker/PickerIOS.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule PickerIOS * * This is a controlled component version of RCTPickerIOS */ diff --git a/Libraries/Components/Picker/PickerIOS.ios.js b/Libraries/Components/Picker/PickerIOS.ios.js index d1fe0761d5cc34..fcd5b12c163322 100644 --- a/Libraries/Components/Picker/PickerIOS.ios.js +++ b/Libraries/Components/Picker/PickerIOS.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule PickerIOS * * This is a controlled component version of RCTPickerIOS */ diff --git a/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js b/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js index f5dcb10cfb9508..db20d579db0a5f 100644 --- a/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js +++ b/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ProgressBarAndroid */ 'use strict'; diff --git a/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.ios.js b/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.ios.js index 92bae8066abe69..ebd42dd5b18bb0 100644 --- a/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.ios.js +++ b/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ProgressBarAndroid */ 'use strict'; diff --git a/Libraries/Components/ProgressViewIOS/ProgressViewIOS.android.js b/Libraries/Components/ProgressViewIOS/ProgressViewIOS.android.js index f467db1ff51f64..dcc8c3fc7489b7 100644 --- a/Libraries/Components/ProgressViewIOS/ProgressViewIOS.android.js +++ b/Libraries/Components/ProgressViewIOS/ProgressViewIOS.android.js @@ -5,7 +5,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ProgressViewIOS */ 'use strict'; diff --git a/Libraries/Components/ProgressViewIOS/ProgressViewIOS.ios.js b/Libraries/Components/ProgressViewIOS/ProgressViewIOS.ios.js index 55ae1b83abe13d..2c14b4cddff768 100644 --- a/Libraries/Components/ProgressViewIOS/ProgressViewIOS.ios.js +++ b/Libraries/Components/ProgressViewIOS/ProgressViewIOS.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ProgressViewIOS * @flow */ 'use strict'; diff --git a/Libraries/Components/RefreshControl/RefreshControl.js b/Libraries/Components/RefreshControl/RefreshControl.js index 8aac1ebf3e5744..07415276261ac3 100644 --- a/Libraries/Components/RefreshControl/RefreshControl.js +++ b/Libraries/Components/RefreshControl/RefreshControl.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule RefreshControl * @flow */ 'use strict'; diff --git a/Libraries/Components/SafeAreaView/SafeAreaView.android.js b/Libraries/Components/SafeAreaView/SafeAreaView.android.js index 62a81a8a284352..fbc94020538334 100644 --- a/Libraries/Components/SafeAreaView/SafeAreaView.android.js +++ b/Libraries/Components/SafeAreaView/SafeAreaView.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule SafeAreaView * @flow */ 'use strict'; diff --git a/Libraries/Components/SafeAreaView/SafeAreaView.ios.js b/Libraries/Components/SafeAreaView/SafeAreaView.ios.js index 344cbe5f301ef1..65daa32fd7542d 100644 --- a/Libraries/Components/SafeAreaView/SafeAreaView.ios.js +++ b/Libraries/Components/SafeAreaView/SafeAreaView.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule SafeAreaView * @flow * @format */ diff --git a/Libraries/Components/ScrollResponder.js b/Libraries/Components/ScrollResponder.js index 6c926b9d40e135..93431293a348ac 100644 --- a/Libraries/Components/ScrollResponder.js +++ b/Libraries/Components/ScrollResponder.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ScrollResponder * @flow */ 'use strict'; diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js index 2d9d031027ca92..0ec0f188abd88f 100644 --- a/Libraries/Components/ScrollView/ScrollView.js +++ b/Libraries/Components/ScrollView/ScrollView.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ScrollView * @flow */ 'use strict'; diff --git a/Libraries/Components/ScrollView/ScrollViewStickyHeader.js b/Libraries/Components/ScrollView/ScrollViewStickyHeader.js index af9dc9b8b63549..e17467b264cd98 100644 --- a/Libraries/Components/ScrollView/ScrollViewStickyHeader.js +++ b/Libraries/Components/ScrollView/ScrollViewStickyHeader.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ScrollViewStickyHeader * @flow * @format */ diff --git a/Libraries/Components/ScrollView/processDecelerationRate.js b/Libraries/Components/ScrollView/processDecelerationRate.js index 9cb5a52a557715..f46755fda278d3 100644 --- a/Libraries/Components/ScrollView/processDecelerationRate.js +++ b/Libraries/Components/ScrollView/processDecelerationRate.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule processDecelerationRate */ 'use strict'; diff --git a/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.android.js b/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.android.js index a5b4c0b339bf6e..a8b791e2f6ef1c 100644 --- a/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.android.js +++ b/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.android.js @@ -5,7 +5,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule SegmentedControlIOS */ 'use strict'; diff --git a/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.ios.js b/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.ios.js index 3eb4249fa2dbce..620a8a3ec5c044 100644 --- a/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.ios.js +++ b/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule SegmentedControlIOS * @flow */ 'use strict'; diff --git a/Libraries/Components/Slider/Slider.js b/Libraries/Components/Slider/Slider.js index 5a163fe176d129..c0f3d015badb16 100644 --- a/Libraries/Components/Slider/Slider.js +++ b/Libraries/Components/Slider/Slider.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Slider * @flow */ 'use strict'; diff --git a/Libraries/Components/StaticContainer.react.js b/Libraries/Components/StaticContainer.react.js index 81e06ace1fdb5f..a6a4454c8118c4 100644 --- a/Libraries/Components/StaticContainer.react.js +++ b/Libraries/Components/StaticContainer.react.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule StaticContainer.react * @flow */ 'use strict'; diff --git a/Libraries/Components/StaticRenderer.js b/Libraries/Components/StaticRenderer.js index 777fe900e120b6..5bb9cb99f48493 100644 --- a/Libraries/Components/StaticRenderer.js +++ b/Libraries/Components/StaticRenderer.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule StaticRenderer * @flow */ 'use strict'; diff --git a/Libraries/Components/StatusBar/StatusBar.js b/Libraries/Components/StatusBar/StatusBar.js index 0562a315493853..05bd9177ccd450 100644 --- a/Libraries/Components/StatusBar/StatusBar.js +++ b/Libraries/Components/StatusBar/StatusBar.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule StatusBar * @flow */ 'use strict'; diff --git a/Libraries/Components/StatusBar/StatusBarIOS.android.js b/Libraries/Components/StatusBar/StatusBarIOS.android.js index 5c69c15339addf..28ad139b8969e6 100644 --- a/Libraries/Components/StatusBar/StatusBarIOS.android.js +++ b/Libraries/Components/StatusBar/StatusBarIOS.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule StatusBarIOS * @flow */ 'use strict'; diff --git a/Libraries/Components/StatusBar/StatusBarIOS.ios.js b/Libraries/Components/StatusBar/StatusBarIOS.ios.js index f132f005696def..3ccab44da625fc 100644 --- a/Libraries/Components/StatusBar/StatusBarIOS.ios.js +++ b/Libraries/Components/StatusBar/StatusBarIOS.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule StatusBarIOS * @flow */ 'use strict'; diff --git a/Libraries/Components/Subscribable.js b/Libraries/Components/Subscribable.js index 6825acd02f70c5..a4fc660b5b9f50 100644 --- a/Libraries/Components/Subscribable.js +++ b/Libraries/Components/Subscribable.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Subscribable * @flow */ 'use strict'; diff --git a/Libraries/Components/Switch/Switch.js b/Libraries/Components/Switch/Switch.js index f259229c3538aa..ad613e2c85d48e 100644 --- a/Libraries/Components/Switch/Switch.js +++ b/Libraries/Components/Switch/Switch.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Switch * @flow */ 'use strict'; diff --git a/Libraries/Components/TabBarIOS/TabBarIOS.android.js b/Libraries/Components/TabBarIOS/TabBarIOS.android.js index c52d947ebd325e..62a6bbac8fb966 100644 --- a/Libraries/Components/TabBarIOS/TabBarIOS.android.js +++ b/Libraries/Components/TabBarIOS/TabBarIOS.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TabBarIOS * @flow */ diff --git a/Libraries/Components/TabBarIOS/TabBarIOS.ios.js b/Libraries/Components/TabBarIOS/TabBarIOS.ios.js index 9d1b63567ba826..57e32df01e5b49 100644 --- a/Libraries/Components/TabBarIOS/TabBarIOS.ios.js +++ b/Libraries/Components/TabBarIOS/TabBarIOS.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TabBarIOS * @flow */ 'use strict'; diff --git a/Libraries/Components/TabBarIOS/TabBarItemIOS.android.js b/Libraries/Components/TabBarIOS/TabBarItemIOS.android.js index ff891312c21acd..6f6ff561892399 100644 --- a/Libraries/Components/TabBarIOS/TabBarItemIOS.android.js +++ b/Libraries/Components/TabBarIOS/TabBarItemIOS.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TabBarItemIOS */ 'use strict'; diff --git a/Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js b/Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js index 6b56cf78ecb86e..3f0b85a0c501fe 100644 --- a/Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js +++ b/Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TabBarItemIOS * @noflow */ 'use strict'; diff --git a/Libraries/Components/TextInput/InputAccessoryView.js b/Libraries/Components/TextInput/InputAccessoryView.js index 73d83c03a22b60..731476bc7138b7 100644 --- a/Libraries/Components/TextInput/InputAccessoryView.js +++ b/Libraries/Components/TextInput/InputAccessoryView.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule InputAccessoryView * @flow * @format */ diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js index fd67b8ec55fc0a..e887b07438f412 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TextInput * @flow * @format */ diff --git a/Libraries/Components/TextInput/TextInputState.js b/Libraries/Components/TextInput/TextInputState.js index cb41eef0c529af..47eeddf12189d5 100644 --- a/Libraries/Components/TextInput/TextInputState.js +++ b/Libraries/Components/TextInput/TextInputState.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TextInputState * @flow * * This class is responsible for coordinating the "focused" diff --git a/Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js b/Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js index be7f4c4f9286c6..b2b8c759e59501 100644 --- a/Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js +++ b/Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TimePickerAndroid * @flow */ 'use strict'; diff --git a/Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js b/Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js index a6b630d7c394a4..3813b6522b00d9 100644 --- a/Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js +++ b/Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TimePickerAndroid * @flow */ 'use strict'; diff --git a/Libraries/Components/ToastAndroid/ToastAndroid.android.js b/Libraries/Components/ToastAndroid/ToastAndroid.android.js index 15a8a597a5b686..b0a242ed5ffec1 100644 --- a/Libraries/Components/ToastAndroid/ToastAndroid.android.js +++ b/Libraries/Components/ToastAndroid/ToastAndroid.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ToastAndroid * @flow */ diff --git a/Libraries/Components/ToastAndroid/ToastAndroid.ios.js b/Libraries/Components/ToastAndroid/ToastAndroid.ios.js index 83db0cfa82cae4..94d0487647ac85 100644 --- a/Libraries/Components/ToastAndroid/ToastAndroid.ios.js +++ b/Libraries/Components/ToastAndroid/ToastAndroid.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ToastAndroid * @noflow */ 'use strict'; diff --git a/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js b/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js index 1d845e5b65bacf..de6fd5aad12b99 100644 --- a/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js +++ b/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ToolbarAndroid */ 'use strict'; diff --git a/Libraries/Components/ToolbarAndroid/ToolbarAndroid.ios.js b/Libraries/Components/ToolbarAndroid/ToolbarAndroid.ios.js index 68ef4ef8300aba..ebd42dd5b18bb0 100644 --- a/Libraries/Components/ToolbarAndroid/ToolbarAndroid.ios.js +++ b/Libraries/Components/ToolbarAndroid/ToolbarAndroid.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ToolbarAndroid */ 'use strict'; diff --git a/Libraries/Components/Touchable/BoundingDimensions.js b/Libraries/Components/Touchable/BoundingDimensions.js index 9bc78e515d8ef3..898244979d28e8 100644 --- a/Libraries/Components/Touchable/BoundingDimensions.js +++ b/Libraries/Components/Touchable/BoundingDimensions.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule BoundingDimensions */ 'use strict'; diff --git a/Libraries/Components/Touchable/PooledClass.js b/Libraries/Components/Touchable/PooledClass.js index a3ae190aa3d22f..42cb503d07b791 100644 --- a/Libraries/Components/Touchable/PooledClass.js +++ b/Libraries/Components/Touchable/PooledClass.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule PooledClass * @flow */ diff --git a/Libraries/Components/Touchable/Position.js b/Libraries/Components/Touchable/Position.js index 572d1132f038bc..ce09d00a8e36a7 100644 --- a/Libraries/Components/Touchable/Position.js +++ b/Libraries/Components/Touchable/Position.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Position */ 'use strict'; diff --git a/Libraries/Components/Touchable/Touchable.js b/Libraries/Components/Touchable/Touchable.js index f39457b827253d..20831533271624 100644 --- a/Libraries/Components/Touchable/Touchable.js +++ b/Libraries/Components/Touchable/Touchable.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Touchable */ 'use strict'; diff --git a/Libraries/Components/Touchable/TouchableBounce.js b/Libraries/Components/Touchable/TouchableBounce.js index 2afef30637b59d..1ebb1a877415e0 100644 --- a/Libraries/Components/Touchable/TouchableBounce.js +++ b/Libraries/Components/Touchable/TouchableBounce.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TouchableBounce * @flow * @format */ diff --git a/Libraries/Components/Touchable/TouchableHighlight.js b/Libraries/Components/Touchable/TouchableHighlight.js index 19680b236528c0..4d8f63eecdd0bc 100644 --- a/Libraries/Components/Touchable/TouchableHighlight.js +++ b/Libraries/Components/Touchable/TouchableHighlight.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TouchableHighlight * @flow * @format */ diff --git a/Libraries/Components/Touchable/TouchableNativeFeedback.android.js b/Libraries/Components/Touchable/TouchableNativeFeedback.android.js index 4f3887642dce43..00f67818bf455a 100644 --- a/Libraries/Components/Touchable/TouchableNativeFeedback.android.js +++ b/Libraries/Components/Touchable/TouchableNativeFeedback.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TouchableNativeFeedback */ 'use strict'; diff --git a/Libraries/Components/Touchable/TouchableNativeFeedback.ios.js b/Libraries/Components/Touchable/TouchableNativeFeedback.ios.js index e898d20ab64a97..8c195b9549bd97 100644 --- a/Libraries/Components/Touchable/TouchableNativeFeedback.ios.js +++ b/Libraries/Components/Touchable/TouchableNativeFeedback.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TouchableNativeFeedback */ 'use strict'; diff --git a/Libraries/Components/Touchable/TouchableOpacity.js b/Libraries/Components/Touchable/TouchableOpacity.js index 8ff2ab8d0f2a34..4ae20db8fb287c 100644 --- a/Libraries/Components/Touchable/TouchableOpacity.js +++ b/Libraries/Components/Touchable/TouchableOpacity.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TouchableOpacity * @noflow */ 'use strict'; diff --git a/Libraries/Components/Touchable/TouchableWithoutFeedback.js b/Libraries/Components/Touchable/TouchableWithoutFeedback.js index 642c8593cbe023..d59d04cf4e6cf9 100755 --- a/Libraries/Components/Touchable/TouchableWithoutFeedback.js +++ b/Libraries/Components/Touchable/TouchableWithoutFeedback.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TouchableWithoutFeedback * @flow */ 'use strict'; diff --git a/Libraries/Components/Touchable/ensureComponentIsNative.js b/Libraries/Components/Touchable/ensureComponentIsNative.js index 63c1e8bf8d02d0..9b82aeb45ec6ae 100644 --- a/Libraries/Components/Touchable/ensureComponentIsNative.js +++ b/Libraries/Components/Touchable/ensureComponentIsNative.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ensureComponentIsNative * @flow */ 'use strict'; diff --git a/Libraries/Components/Touchable/ensurePositiveDelayProps.js b/Libraries/Components/Touchable/ensurePositiveDelayProps.js index 51b97f5ca42e68..9d0be5ccdc5e8d 100644 --- a/Libraries/Components/Touchable/ensurePositiveDelayProps.js +++ b/Libraries/Components/Touchable/ensurePositiveDelayProps.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ensurePositiveDelayProps * @flow */ 'use strict'; diff --git a/Libraries/Components/UnimplementedViews/UnimplementedView.js b/Libraries/Components/UnimplementedViews/UnimplementedView.js index 5da72d04f35430..7be6f1ac77f759 100644 --- a/Libraries/Components/UnimplementedViews/UnimplementedView.js +++ b/Libraries/Components/UnimplementedViews/UnimplementedView.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule UnimplementedView * @flow * @format */ diff --git a/Libraries/Components/View/PlatformViewPropTypes.js b/Libraries/Components/View/PlatformViewPropTypes.js index 891fa34572a4f7..70ab6694192fb2 100644 --- a/Libraries/Components/View/PlatformViewPropTypes.js +++ b/Libraries/Components/View/PlatformViewPropTypes.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule PlatformViewPropTypes * @flow */ diff --git a/Libraries/Components/View/ReactNativeStyleAttributes.js b/Libraries/Components/View/ReactNativeStyleAttributes.js index a9441cad97f156..7c8422413579ad 100644 --- a/Libraries/Components/View/ReactNativeStyleAttributes.js +++ b/Libraries/Components/View/ReactNativeStyleAttributes.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ReactNativeStyleAttributes * @flow */ diff --git a/Libraries/Components/View/ReactNativeViewAttributes.js b/Libraries/Components/View/ReactNativeViewAttributes.js index 26fb368aceb96f..f18b70281935bc 100644 --- a/Libraries/Components/View/ReactNativeViewAttributes.js +++ b/Libraries/Components/View/ReactNativeViewAttributes.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ReactNativeViewAttributes * @flow */ 'use strict'; diff --git a/Libraries/Components/View/ShadowPropTypesIOS.js b/Libraries/Components/View/ShadowPropTypesIOS.js index f4f2f0ab4c481a..2dfc021735ad9e 100644 --- a/Libraries/Components/View/ShadowPropTypesIOS.js +++ b/Libraries/Components/View/ShadowPropTypesIOS.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ShadowPropTypesIOS * @flow * @format */ diff --git a/Libraries/Components/View/View.js b/Libraries/Components/View/View.js index 0a77bff8a40766..558f40a5d4087c 100644 --- a/Libraries/Components/View/View.js +++ b/Libraries/Components/View/View.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule View * @flow * @format */ diff --git a/Libraries/Components/View/ViewAccessibility.js b/Libraries/Components/View/ViewAccessibility.js index b45366fd079755..edab2a5695112b 100644 --- a/Libraries/Components/View/ViewAccessibility.js +++ b/Libraries/Components/View/ViewAccessibility.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ViewAccessibility * @flow */ 'use strict'; diff --git a/Libraries/Components/View/ViewContext.js b/Libraries/Components/View/ViewContext.js index f9f98000409ddc..81879aa35ecfa1 100644 --- a/Libraries/Components/View/ViewContext.js +++ b/Libraries/Components/View/ViewContext.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ViewContext * @flow * @format */ diff --git a/Libraries/Components/View/ViewPropTypes.js b/Libraries/Components/View/ViewPropTypes.js index 574bd577cc9997..f5f03bf10efd83 100644 --- a/Libraries/Components/View/ViewPropTypes.js +++ b/Libraries/Components/View/ViewPropTypes.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ViewPropTypes * @flow */ 'use strict'; diff --git a/Libraries/Components/View/ViewStylePropTypes.js b/Libraries/Components/View/ViewStylePropTypes.js index c21ce5934ac33c..e252cf5d2c7850 100644 --- a/Libraries/Components/View/ViewStylePropTypes.js +++ b/Libraries/Components/View/ViewStylePropTypes.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ViewStylePropTypes * @flow */ 'use strict'; diff --git a/Libraries/Components/ViewPager/ViewPagerAndroid.android.js b/Libraries/Components/ViewPager/ViewPagerAndroid.android.js index 8463503bd7930b..19421ccc6436d1 100644 --- a/Libraries/Components/ViewPager/ViewPagerAndroid.android.js +++ b/Libraries/Components/ViewPager/ViewPagerAndroid.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ViewPagerAndroid * @flow */ 'use strict'; diff --git a/Libraries/Components/ViewPager/ViewPagerAndroid.ios.js b/Libraries/Components/ViewPager/ViewPagerAndroid.ios.js index ee0022ae5453fa..ebd42dd5b18bb0 100644 --- a/Libraries/Components/ViewPager/ViewPagerAndroid.ios.js +++ b/Libraries/Components/ViewPager/ViewPagerAndroid.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ViewPagerAndroid */ 'use strict'; diff --git a/Libraries/Components/WebView/WebView.android.js b/Libraries/Components/WebView/WebView.android.js index 16f2991df1e770..a457298f96f65f 100644 --- a/Libraries/Components/WebView/WebView.android.js +++ b/Libraries/Components/WebView/WebView.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule WebView */ 'use strict'; diff --git a/Libraries/Components/WebView/WebView.ios.js b/Libraries/Components/WebView/WebView.ios.js index f01cfae537dd33..56a4465fea6b97 100644 --- a/Libraries/Components/WebView/WebView.ios.js +++ b/Libraries/Components/WebView/WebView.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule WebView * @noflow */ 'use strict'; diff --git a/Libraries/Core/Devtools/getDevServer.js b/Libraries/Core/Devtools/getDevServer.js index 975a75f827b240..1087f6ead2b76f 100644 --- a/Libraries/Core/Devtools/getDevServer.js +++ b/Libraries/Core/Devtools/getDevServer.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule getDevServer * @flow */ 'use strict'; diff --git a/Libraries/Core/Devtools/openFileInEditor.js b/Libraries/Core/Devtools/openFileInEditor.js index a5f9da59e6b1ab..1f4437a5ef8c16 100644 --- a/Libraries/Core/Devtools/openFileInEditor.js +++ b/Libraries/Core/Devtools/openFileInEditor.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule openFileInEditor * @flow */ 'use strict'; diff --git a/Libraries/Core/Devtools/parseErrorStack.js b/Libraries/Core/Devtools/parseErrorStack.js index e1ae27294fee68..efcad10191d461 100644 --- a/Libraries/Core/Devtools/parseErrorStack.js +++ b/Libraries/Core/Devtools/parseErrorStack.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule parseErrorStack * @flow */ 'use strict'; diff --git a/Libraries/Core/Devtools/setupDevtools.js b/Libraries/Core/Devtools/setupDevtools.js index cbfb8df3983b59..fec7ea6160cc5d 100644 --- a/Libraries/Core/Devtools/setupDevtools.js +++ b/Libraries/Core/Devtools/setupDevtools.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule setupDevtools * @flow */ 'use strict'; diff --git a/Libraries/Core/Devtools/symbolicateStackTrace.js b/Libraries/Core/Devtools/symbolicateStackTrace.js index 5ac25fe03e98fb..8933394ba92deb 100644 --- a/Libraries/Core/Devtools/symbolicateStackTrace.js +++ b/Libraries/Core/Devtools/symbolicateStackTrace.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule symbolicateStackTrace * @flow */ 'use strict'; diff --git a/Libraries/Core/ExceptionsManager.js b/Libraries/Core/ExceptionsManager.js index 8a63ec3bff4bcc..6a0ba132dc8133 100644 --- a/Libraries/Core/ExceptionsManager.js +++ b/Libraries/Core/ExceptionsManager.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ExceptionsManager * @flow */ 'use strict'; diff --git a/Libraries/Core/InitializeCore.js b/Libraries/Core/InitializeCore.js index c97576397a94b6..d739ab78231748 100644 --- a/Libraries/Core/InitializeCore.js +++ b/Libraries/Core/InitializeCore.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule InitializeCore * @flow */ diff --git a/Libraries/Core/ReactNativeVersion.js b/Libraries/Core/ReactNativeVersion.js index 52b8f9c47b8f26..1b2b2155f55175 100644 --- a/Libraries/Core/ReactNativeVersion.js +++ b/Libraries/Core/ReactNativeVersion.js @@ -7,7 +7,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule ReactNativeVersion */ exports.version = { diff --git a/Libraries/Core/ReactNativeVersionCheck.js b/Libraries/Core/ReactNativeVersionCheck.js index acbac3337baffd..8a937c769d9979 100644 --- a/Libraries/Core/ReactNativeVersionCheck.js +++ b/Libraries/Core/ReactNativeVersionCheck.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ReactNativeVersionCheck * @flow * @format */ diff --git a/Libraries/Core/Timers/JSTimers.js b/Libraries/Core/Timers/JSTimers.js index e0b4fbbd8866ac..dbd23f807f8150 100644 --- a/Libraries/Core/Timers/JSTimers.js +++ b/Libraries/Core/Timers/JSTimers.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule JSTimers * @format * @flow */ diff --git a/Libraries/EventEmitter/MissingNativeEventEmitterShim.js b/Libraries/EventEmitter/MissingNativeEventEmitterShim.js index d4abfc228a4ba1..e9c11b925c8e98 100644 --- a/Libraries/EventEmitter/MissingNativeEventEmitterShim.js +++ b/Libraries/EventEmitter/MissingNativeEventEmitterShim.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule MissingNativeEventEmitterShim * @flow */ 'use strict'; diff --git a/Libraries/EventEmitter/NativeEventEmitter.js b/Libraries/EventEmitter/NativeEventEmitter.js index f453cbc5184e42..582cf9561f160a 100644 --- a/Libraries/EventEmitter/NativeEventEmitter.js +++ b/Libraries/EventEmitter/NativeEventEmitter.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule NativeEventEmitter * @flow */ 'use strict'; diff --git a/Libraries/EventEmitter/RCTDeviceEventEmitter.js b/Libraries/EventEmitter/RCTDeviceEventEmitter.js index 57ce4fa08990c8..9378a5f5310bc4 100644 --- a/Libraries/EventEmitter/RCTDeviceEventEmitter.js +++ b/Libraries/EventEmitter/RCTDeviceEventEmitter.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule RCTDeviceEventEmitter * @flow */ 'use strict'; diff --git a/Libraries/EventEmitter/RCTEventEmitter.js b/Libraries/EventEmitter/RCTEventEmitter.js index 581515482f1c9b..976356b7aa07e1 100644 --- a/Libraries/EventEmitter/RCTEventEmitter.js +++ b/Libraries/EventEmitter/RCTEventEmitter.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule RCTEventEmitter * @flow */ 'use strict'; diff --git a/Libraries/EventEmitter/RCTNativeAppEventEmitter.js b/Libraries/EventEmitter/RCTNativeAppEventEmitter.js index 9fe0a1573fe18f..43245aba558ec2 100644 --- a/Libraries/EventEmitter/RCTNativeAppEventEmitter.js +++ b/Libraries/EventEmitter/RCTNativeAppEventEmitter.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule RCTNativeAppEventEmitter * @flow */ 'use strict'; diff --git a/Libraries/Experimental/Incremental.js b/Libraries/Experimental/Incremental.js index 45c0a7dce5a071..237e5dbc32e72d 100644 --- a/Libraries/Experimental/Incremental.js +++ b/Libraries/Experimental/Incremental.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Incremental * @flow */ 'use strict'; diff --git a/Libraries/Experimental/IncrementalExample.js b/Libraries/Experimental/IncrementalExample.js index 280d36f198cfa0..e46510b5e4e9d4 100644 --- a/Libraries/Experimental/IncrementalExample.js +++ b/Libraries/Experimental/IncrementalExample.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule IncrementalExample * @flow */ 'use strict'; diff --git a/Libraries/Experimental/IncrementalGroup.js b/Libraries/Experimental/IncrementalGroup.js index e2aefae6836f2d..f630ba66c8c55e 100644 --- a/Libraries/Experimental/IncrementalGroup.js +++ b/Libraries/Experimental/IncrementalGroup.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule IncrementalGroup * @flow */ 'use strict'; diff --git a/Libraries/Experimental/IncrementalPresenter.js b/Libraries/Experimental/IncrementalPresenter.js index 03c69d1fcdcf71..05520a3ec4879e 100644 --- a/Libraries/Experimental/IncrementalPresenter.js +++ b/Libraries/Experimental/IncrementalPresenter.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule IncrementalPresenter * @flow */ 'use strict'; diff --git a/Libraries/Experimental/SwipeableRow/SwipeableFlatList.js b/Libraries/Experimental/SwipeableRow/SwipeableFlatList.js index f7f78b40103acf..b01fea760dd0f4 100644 --- a/Libraries/Experimental/SwipeableRow/SwipeableFlatList.js +++ b/Libraries/Experimental/SwipeableRow/SwipeableFlatList.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule SwipeableFlatList * @flow * @format */ diff --git a/Libraries/Experimental/SwipeableRow/SwipeableListView.js b/Libraries/Experimental/SwipeableRow/SwipeableListView.js index c6623be75b3ba6..4187684ddb674e 100644 --- a/Libraries/Experimental/SwipeableRow/SwipeableListView.js +++ b/Libraries/Experimental/SwipeableRow/SwipeableListView.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule SwipeableListView * @flow */ 'use strict'; diff --git a/Libraries/Experimental/SwipeableRow/SwipeableListViewDataSource.js b/Libraries/Experimental/SwipeableRow/SwipeableListViewDataSource.js index bda3bd3b530651..da4377acad8fcb 100644 --- a/Libraries/Experimental/SwipeableRow/SwipeableListViewDataSource.js +++ b/Libraries/Experimental/SwipeableRow/SwipeableListViewDataSource.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule SwipeableListViewDataSource */ 'use strict'; diff --git a/Libraries/Experimental/SwipeableRow/SwipeableQuickActionButton.js b/Libraries/Experimental/SwipeableRow/SwipeableQuickActionButton.js index 315b8a2f64c389..704f315961ceb5 100644 --- a/Libraries/Experimental/SwipeableRow/SwipeableQuickActionButton.js +++ b/Libraries/Experimental/SwipeableRow/SwipeableQuickActionButton.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule SwipeableQuickActionButton * @flow */ 'use strict'; diff --git a/Libraries/Experimental/SwipeableRow/SwipeableQuickActions.js b/Libraries/Experimental/SwipeableRow/SwipeableQuickActions.js index 96fe1d23daab47..42d2f2cc060b90 100644 --- a/Libraries/Experimental/SwipeableRow/SwipeableQuickActions.js +++ b/Libraries/Experimental/SwipeableRow/SwipeableQuickActions.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule SwipeableQuickActions * @flow */ 'use strict'; diff --git a/Libraries/Experimental/SwipeableRow/SwipeableRow.js b/Libraries/Experimental/SwipeableRow/SwipeableRow.js index 80e627376e8482..0c072611aaca44 100644 --- a/Libraries/Experimental/SwipeableRow/SwipeableRow.js +++ b/Libraries/Experimental/SwipeableRow/SwipeableRow.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule SwipeableRow * @flow */ 'use strict'; diff --git a/Libraries/Experimental/WindowedListView.js b/Libraries/Experimental/WindowedListView.js index 2a102b23f3c47c..bf7ef3324b8117 100644 --- a/Libraries/Experimental/WindowedListView.js +++ b/Libraries/Experimental/WindowedListView.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule WindowedListView * @flow */ 'use strict'; diff --git a/Libraries/Geolocation/Geolocation.js b/Libraries/Geolocation/Geolocation.js index a4efe4c0201cb5..29bb0aa13a9932 100644 --- a/Libraries/Geolocation/Geolocation.js +++ b/Libraries/Geolocation/Geolocation.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Geolocation * @flow */ 'use strict'; diff --git a/Libraries/Image/AssetRegistry.js b/Libraries/Image/AssetRegistry.js index 7dabcfb9b53561..5f5f0980f432be 100644 --- a/Libraries/Image/AssetRegistry.js +++ b/Libraries/Image/AssetRegistry.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AssetRegistry * @flow * @format */ diff --git a/Libraries/Image/AssetSourceResolver.js b/Libraries/Image/AssetSourceResolver.js index 819353e03846ea..d7b583ebcb8d63 100644 --- a/Libraries/Image/AssetSourceResolver.js +++ b/Libraries/Image/AssetSourceResolver.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AssetSourceResolver * @flow * @format */ diff --git a/Libraries/Image/Image.android.js b/Libraries/Image/Image.android.js index 4c8fa6e7fd173d..7b0ec83a8738ec 100644 --- a/Libraries/Image/Image.android.js +++ b/Libraries/Image/Image.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Image * @flow * @format */ diff --git a/Libraries/Image/Image.ios.js b/Libraries/Image/Image.ios.js index c3e9ad5359c166..eb0d0241af52eb 100644 --- a/Libraries/Image/Image.ios.js +++ b/Libraries/Image/Image.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Image * @flow * @format */ diff --git a/Libraries/Image/ImageBackground.js b/Libraries/Image/ImageBackground.js index 405bced59ce254..7b86d9c5f5298d 100644 --- a/Libraries/Image/ImageBackground.js +++ b/Libraries/Image/ImageBackground.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ImageBackground * @flow * @format */ diff --git a/Libraries/Image/ImageEditor.js b/Libraries/Image/ImageEditor.js index ddd7fd381285c5..66504b501293db 100644 --- a/Libraries/Image/ImageEditor.js +++ b/Libraries/Image/ImageEditor.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ImageEditor * @flow * @format */ diff --git a/Libraries/Image/ImageProps.js b/Libraries/Image/ImageProps.js index f075d9ccecedca..63015586296d4a 100644 --- a/Libraries/Image/ImageProps.js +++ b/Libraries/Image/ImageProps.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ImageProps * @flow * @format */ diff --git a/Libraries/Image/ImageResizeMode.js b/Libraries/Image/ImageResizeMode.js index 25d937d60efe5f..89e74bcc502ee6 100644 --- a/Libraries/Image/ImageResizeMode.js +++ b/Libraries/Image/ImageResizeMode.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ImageResizeMode * @flow * @format */ diff --git a/Libraries/Image/ImageSource.js b/Libraries/Image/ImageSource.js index 533eb513219ca2..b729863234ffe3 100644 --- a/Libraries/Image/ImageSource.js +++ b/Libraries/Image/ImageSource.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ImageSource * @flow * @format */ diff --git a/Libraries/Image/ImageSourcePropType.js b/Libraries/Image/ImageSourcePropType.js index af9dac3c479477..6f67113fe1bf18 100644 --- a/Libraries/Image/ImageSourcePropType.js +++ b/Libraries/Image/ImageSourcePropType.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ImageSourcePropType * @no-flow * @format */ diff --git a/Libraries/Image/ImageStore.js b/Libraries/Image/ImageStore.js index 215bdec246cb1e..5373020376a5f1 100644 --- a/Libraries/Image/ImageStore.js +++ b/Libraries/Image/ImageStore.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ImageStore * @flow * @format */ diff --git a/Libraries/Image/ImageStylePropTypes.js b/Libraries/Image/ImageStylePropTypes.js index 9a688ac7f9d425..c88c19ea3cec29 100644 --- a/Libraries/Image/ImageStylePropTypes.js +++ b/Libraries/Image/ImageStylePropTypes.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ImageStylePropTypes * @flow * @format */ diff --git a/Libraries/Image/RelativeImageStub.js b/Libraries/Image/RelativeImageStub.js index 4adf66b806b4f2..866488eecc83c3 100644 --- a/Libraries/Image/RelativeImageStub.js +++ b/Libraries/Image/RelativeImageStub.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule RelativeImageStub * @flow */ 'use strict'; diff --git a/Libraries/Image/nativeImageSource.js b/Libraries/Image/nativeImageSource.js index 26b194ace776be..1fdbe1caa97615 100644 --- a/Libraries/Image/nativeImageSource.js +++ b/Libraries/Image/nativeImageSource.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule nativeImageSource * @flow * @format */ diff --git a/Libraries/Image/resolveAssetSource.js b/Libraries/Image/resolveAssetSource.js index 0d160a28077deb..fefb28ff5f7b32 100644 --- a/Libraries/Image/resolveAssetSource.js +++ b/Libraries/Image/resolveAssetSource.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule resolveAssetSource * @flow * * Resolves an asset into a `source` for `Image`. diff --git a/Libraries/Inspector/BorderBox.js b/Libraries/Inspector/BorderBox.js index c121de5ea1dabb..7ed32e73ae49a0 100644 --- a/Libraries/Inspector/BorderBox.js +++ b/Libraries/Inspector/BorderBox.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule BorderBox * @flow */ 'use strict'; diff --git a/Libraries/Inspector/BoxInspector.js b/Libraries/Inspector/BoxInspector.js index 31bedeecdaa0c8..6009e78ea44186 100644 --- a/Libraries/Inspector/BoxInspector.js +++ b/Libraries/Inspector/BoxInspector.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule BoxInspector * @flow */ 'use strict'; diff --git a/Libraries/Inspector/ElementBox.js b/Libraries/Inspector/ElementBox.js index b9caef093cc340..7eebb22f337af6 100644 --- a/Libraries/Inspector/ElementBox.js +++ b/Libraries/Inspector/ElementBox.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ElementBox * @flow */ 'use strict'; diff --git a/Libraries/Inspector/ElementProperties.js b/Libraries/Inspector/ElementProperties.js index 460e1c2df81059..75beaf93e233f8 100644 --- a/Libraries/Inspector/ElementProperties.js +++ b/Libraries/Inspector/ElementProperties.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ElementProperties * @flow */ 'use strict'; diff --git a/Libraries/Inspector/Inspector.js b/Libraries/Inspector/Inspector.js index 963b616fca3bcb..73ce0719b36d03 100644 --- a/Libraries/Inspector/Inspector.js +++ b/Libraries/Inspector/Inspector.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Inspector * @flow */ diff --git a/Libraries/Inspector/InspectorOverlay.js b/Libraries/Inspector/InspectorOverlay.js index d441ba59884ea9..3ef8ae60f3501b 100644 --- a/Libraries/Inspector/InspectorOverlay.js +++ b/Libraries/Inspector/InspectorOverlay.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule InspectorOverlay * @flow */ 'use strict'; diff --git a/Libraries/Inspector/InspectorPanel.js b/Libraries/Inspector/InspectorPanel.js index c4031a355d5c45..b2dd639c4a898b 100644 --- a/Libraries/Inspector/InspectorPanel.js +++ b/Libraries/Inspector/InspectorPanel.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule InspectorPanel * @flow */ 'use strict'; diff --git a/Libraries/Inspector/NetworkOverlay.js b/Libraries/Inspector/NetworkOverlay.js index 789ac6de824c65..3651aa3511899d 100644 --- a/Libraries/Inspector/NetworkOverlay.js +++ b/Libraries/Inspector/NetworkOverlay.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule NetworkOverlay * @flow */ 'use strict'; diff --git a/Libraries/Inspector/PerformanceOverlay.js b/Libraries/Inspector/PerformanceOverlay.js index 8240a43244ac6b..d414ea2db298da 100644 --- a/Libraries/Inspector/PerformanceOverlay.js +++ b/Libraries/Inspector/PerformanceOverlay.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule PerformanceOverlay * @flow */ 'use strict'; diff --git a/Libraries/Inspector/StyleInspector.js b/Libraries/Inspector/StyleInspector.js index 7bd137bdea7de6..a65e027996521c 100644 --- a/Libraries/Inspector/StyleInspector.js +++ b/Libraries/Inspector/StyleInspector.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule StyleInspector * @flow */ 'use strict'; diff --git a/Libraries/Inspector/resolveBoxStyle.js b/Libraries/Inspector/resolveBoxStyle.js index 28f4af50525b33..43026ada8f763e 100644 --- a/Libraries/Inspector/resolveBoxStyle.js +++ b/Libraries/Inspector/resolveBoxStyle.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule resolveBoxStyle * @flow */ 'use strict'; diff --git a/Libraries/Interaction/Batchinator.js b/Libraries/Interaction/Batchinator.js index 3f3b4e069a019e..84097514ba6443 100644 --- a/Libraries/Interaction/Batchinator.js +++ b/Libraries/Interaction/Batchinator.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Batchinator * @flow */ 'use strict'; diff --git a/Libraries/Interaction/BridgeSpyStallHandler.js b/Libraries/Interaction/BridgeSpyStallHandler.js index f47f0751d8ad67..88f892442d09b0 100644 --- a/Libraries/Interaction/BridgeSpyStallHandler.js +++ b/Libraries/Interaction/BridgeSpyStallHandler.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule BridgeSpyStallHandler * @flow */ 'use strict'; diff --git a/Libraries/Interaction/FrameRateLogger.js b/Libraries/Interaction/FrameRateLogger.js index 072adeb930f8d8..252fc465a3d487 100644 --- a/Libraries/Interaction/FrameRateLogger.js +++ b/Libraries/Interaction/FrameRateLogger.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule FrameRateLogger * @flow */ 'use strict'; diff --git a/Libraries/Interaction/InteractionManager.js b/Libraries/Interaction/InteractionManager.js index 227e1b05bd3a73..7373575a0cae8d 100644 --- a/Libraries/Interaction/InteractionManager.js +++ b/Libraries/Interaction/InteractionManager.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule InteractionManager * @flow */ 'use strict'; diff --git a/Libraries/Interaction/InteractionMixin.js b/Libraries/Interaction/InteractionMixin.js index 9e81a4fddaec1e..e4310ad91d86ec 100644 --- a/Libraries/Interaction/InteractionMixin.js +++ b/Libraries/Interaction/InteractionMixin.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule InteractionMixin * @flow */ 'use strict'; diff --git a/Libraries/Interaction/InteractionStallDebugger.js b/Libraries/Interaction/InteractionStallDebugger.js index 8d2bcc82e5f9ba..f62e8d24444428 100644 --- a/Libraries/Interaction/InteractionStallDebugger.js +++ b/Libraries/Interaction/InteractionStallDebugger.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule InteractionStallDebugger * @flow */ 'use strict'; diff --git a/Libraries/Interaction/JSEventLoopWatchdog.js b/Libraries/Interaction/JSEventLoopWatchdog.js index 2d1866a0c77f2f..8e2f00eef41dc8 100644 --- a/Libraries/Interaction/JSEventLoopWatchdog.js +++ b/Libraries/Interaction/JSEventLoopWatchdog.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule JSEventLoopWatchdog * @flow */ 'use strict'; diff --git a/Libraries/Interaction/PanResponder.js b/Libraries/Interaction/PanResponder.js index d927fa5fc14d89..92438d904656d4 100644 --- a/Libraries/Interaction/PanResponder.js +++ b/Libraries/Interaction/PanResponder.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule PanResponder */ 'use strict'; diff --git a/Libraries/Interaction/ReactPerfStallHandler.js b/Libraries/Interaction/ReactPerfStallHandler.js index 394bc7533ca1c7..09c57dabc5f449 100644 --- a/Libraries/Interaction/ReactPerfStallHandler.js +++ b/Libraries/Interaction/ReactPerfStallHandler.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ReactPerfStallHandler * @flow */ 'use strict'; diff --git a/Libraries/Interaction/TaskQueue.js b/Libraries/Interaction/TaskQueue.js index 0ee5e4500af9f0..6660d84f47196c 100644 --- a/Libraries/Interaction/TaskQueue.js +++ b/Libraries/Interaction/TaskQueue.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TaskQueue * @flow */ 'use strict'; diff --git a/Libraries/JSInspector/InspectorAgent.js b/Libraries/JSInspector/InspectorAgent.js index a5b6cca0da3da3..b419a6c2aadf61 100644 --- a/Libraries/JSInspector/InspectorAgent.js +++ b/Libraries/JSInspector/InspectorAgent.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule InspectorAgent * @flow */ 'use strict'; diff --git a/Libraries/JSInspector/JSInspector.js b/Libraries/JSInspector/JSInspector.js index 9a6b13ffb7c690..e62669aee6a324 100644 --- a/Libraries/JSInspector/JSInspector.js +++ b/Libraries/JSInspector/JSInspector.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule JSInspector * @flow */ 'use strict'; diff --git a/Libraries/JSInspector/NetworkAgent.js b/Libraries/JSInspector/NetworkAgent.js index 56f6f2a37fdccf..bf1de686ae9155 100644 --- a/Libraries/JSInspector/NetworkAgent.js +++ b/Libraries/JSInspector/NetworkAgent.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule NetworkAgent * @flow */ 'use strict'; diff --git a/Libraries/LayoutAnimation/LayoutAnimation.js b/Libraries/LayoutAnimation/LayoutAnimation.js index f04feca9331afb..e739ec8595158d 100644 --- a/Libraries/LayoutAnimation/LayoutAnimation.js +++ b/Libraries/LayoutAnimation/LayoutAnimation.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule LayoutAnimation * @flow * @format */ diff --git a/Libraries/Linking/Linking.js b/Libraries/Linking/Linking.js index a621e647adccf8..a4ad9b3b593283 100644 --- a/Libraries/Linking/Linking.js +++ b/Libraries/Linking/Linking.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Linking * @flow */ 'use strict'; diff --git a/Libraries/Lists/FillRateHelper.js b/Libraries/Lists/FillRateHelper.js index f060897356b73a..82b0612cdcf8b6 100644 --- a/Libraries/Lists/FillRateHelper.js +++ b/Libraries/Lists/FillRateHelper.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule FillRateHelper * @flow * @format */ diff --git a/Libraries/Lists/FlatList.js b/Libraries/Lists/FlatList.js index 13b87ed995b756..5a0827be1df830 100644 --- a/Libraries/Lists/FlatList.js +++ b/Libraries/Lists/FlatList.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule FlatList * @flow * @format */ diff --git a/Libraries/Lists/ListView/ListView.js b/Libraries/Lists/ListView/ListView.js index 9aefd2ea9222b3..b36150510e2c62 100644 --- a/Libraries/Lists/ListView/ListView.js +++ b/Libraries/Lists/ListView/ListView.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ListView * @flow * @format */ diff --git a/Libraries/Lists/ListView/ListViewDataSource.js b/Libraries/Lists/ListView/ListViewDataSource.js index ec63c94d0f46dd..dda74b50cb8381 100644 --- a/Libraries/Lists/ListView/ListViewDataSource.js +++ b/Libraries/Lists/ListView/ListViewDataSource.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ListViewDataSource * @flow * @format */ diff --git a/Libraries/Lists/MetroListView.js b/Libraries/Lists/MetroListView.js index 5f22eb264ee85b..f2447760f9ee2b 100644 --- a/Libraries/Lists/MetroListView.js +++ b/Libraries/Lists/MetroListView.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule MetroListView * @flow * @format */ diff --git a/Libraries/Lists/SectionList.js b/Libraries/Lists/SectionList.js index 2404d26f54c72a..17a4f84711e0ab 100644 --- a/Libraries/Lists/SectionList.js +++ b/Libraries/Lists/SectionList.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule SectionList * @flow * @format */ diff --git a/Libraries/Lists/ViewabilityHelper.js b/Libraries/Lists/ViewabilityHelper.js index 0c0a8356019075..415e77895360da 100644 --- a/Libraries/Lists/ViewabilityHelper.js +++ b/Libraries/Lists/ViewabilityHelper.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ViewabilityHelper * @flow * @format */ diff --git a/Libraries/Lists/VirtualizeUtils.js b/Libraries/Lists/VirtualizeUtils.js index 663b36b8cc6e76..b47ceda1fece63 100644 --- a/Libraries/Lists/VirtualizeUtils.js +++ b/Libraries/Lists/VirtualizeUtils.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule VirtualizeUtils * @flow * @format */ diff --git a/Libraries/Lists/VirtualizedList.js b/Libraries/Lists/VirtualizedList.js index bbfc6cf3bdecd6..ca6d9fc7fe56e4 100644 --- a/Libraries/Lists/VirtualizedList.js +++ b/Libraries/Lists/VirtualizedList.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule VirtualizedList * @flow * @format */ diff --git a/Libraries/Lists/VirtualizedSectionList.js b/Libraries/Lists/VirtualizedSectionList.js index 2bb196814abf13..6da08dc1ab6659 100644 --- a/Libraries/Lists/VirtualizedSectionList.js +++ b/Libraries/Lists/VirtualizedSectionList.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule VirtualizedSectionList * @flow * @format */ diff --git a/Libraries/Modal/Modal.js b/Libraries/Modal/Modal.js index dabdbc5d92f618..b1cc4a1cb7bb80 100644 --- a/Libraries/Modal/Modal.js +++ b/Libraries/Modal/Modal.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Modal * @flow */ 'use strict'; diff --git a/Libraries/Network/FormData.js b/Libraries/Network/FormData.js index 669bf0f2a30cf7..6028a06bf87657 100644 --- a/Libraries/Network/FormData.js +++ b/Libraries/Network/FormData.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule FormData * @flow */ 'use strict'; diff --git a/Libraries/Network/NetInfo.js b/Libraries/Network/NetInfo.js index 0db9d4eab26825..474ce79144e063 100644 --- a/Libraries/Network/NetInfo.js +++ b/Libraries/Network/NetInfo.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule NetInfo * @flow */ 'use strict'; diff --git a/Libraries/Network/RCTNetworking.android.js b/Libraries/Network/RCTNetworking.android.js index 9ec01dccecb838..30162a0e88c8fe 100644 --- a/Libraries/Network/RCTNetworking.android.js +++ b/Libraries/Network/RCTNetworking.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule RCTNetworking * @flow */ 'use strict'; diff --git a/Libraries/Network/RCTNetworking.ios.js b/Libraries/Network/RCTNetworking.ios.js index 004322a080f1bc..2b834577809e43 100644 --- a/Libraries/Network/RCTNetworking.ios.js +++ b/Libraries/Network/RCTNetworking.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule RCTNetworking * @flow */ 'use strict'; diff --git a/Libraries/Network/XHRInterceptor.js b/Libraries/Network/XHRInterceptor.js index 09cc3b22038a56..22c6cf853fe0a8 100644 --- a/Libraries/Network/XHRInterceptor.js +++ b/Libraries/Network/XHRInterceptor.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule XHRInterceptor */ 'use strict'; diff --git a/Libraries/Network/XMLHttpRequest.js b/Libraries/Network/XMLHttpRequest.js index d17001d3743f34..dd43fa40c86cd2 100644 --- a/Libraries/Network/XMLHttpRequest.js +++ b/Libraries/Network/XMLHttpRequest.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule XMLHttpRequest * @flow */ 'use strict'; diff --git a/Libraries/Network/convertRequestBody.js b/Libraries/Network/convertRequestBody.js index 2d3ecc7353aa8d..84cc9c569078d2 100644 --- a/Libraries/Network/convertRequestBody.js +++ b/Libraries/Network/convertRequestBody.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule convertRequestBody * @flow * @format */ diff --git a/Libraries/Network/fetch.js b/Libraries/Network/fetch.js index 1e1c934316d6db..10be3631d26bdf 100644 --- a/Libraries/Network/fetch.js +++ b/Libraries/Network/fetch.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule fetch * */ diff --git a/Libraries/Performance/QuickPerformanceLogger.js b/Libraries/Performance/QuickPerformanceLogger.js index 4eec7220a7cc7c..bdf6d952e1e814 100644 --- a/Libraries/Performance/QuickPerformanceLogger.js +++ b/Libraries/Performance/QuickPerformanceLogger.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule QuickPerformanceLogger * @flow */ diff --git a/Libraries/Performance/SamplingProfiler.js b/Libraries/Performance/SamplingProfiler.js index 739274399bde9f..ec4323e12575f1 100644 --- a/Libraries/Performance/SamplingProfiler.js +++ b/Libraries/Performance/SamplingProfiler.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule SamplingProfiler * @flow */ 'use strict'; diff --git a/Libraries/Performance/Systrace.js b/Libraries/Performance/Systrace.js index 2e38d8298d1e39..19105ad3039719 100644 --- a/Libraries/Performance/Systrace.js +++ b/Libraries/Performance/Systrace.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Systrace * @flow * @format */ diff --git a/Libraries/PermissionsAndroid/PermissionsAndroid.js b/Libraries/PermissionsAndroid/PermissionsAndroid.js index 18858e1669dbf7..6febce80ffd131 100644 --- a/Libraries/PermissionsAndroid/PermissionsAndroid.js +++ b/Libraries/PermissionsAndroid/PermissionsAndroid.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule PermissionsAndroid * @flow */ 'use strict'; diff --git a/Libraries/Promise.js b/Libraries/Promise.js index 288ee75f6f0f72..aee5ad7e7d0c6e 100644 --- a/Libraries/Promise.js +++ b/Libraries/Promise.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Promise * @flow */ 'use strict'; diff --git a/Libraries/PushNotificationIOS/PushNotificationIOS.js b/Libraries/PushNotificationIOS/PushNotificationIOS.js index 955bdf8c1adc9d..9f013436c991ae 100644 --- a/Libraries/PushNotificationIOS/PushNotificationIOS.js +++ b/Libraries/PushNotificationIOS/PushNotificationIOS.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule PushNotificationIOS * @flow */ 'use strict'; diff --git a/Libraries/RCTTest/SnapshotViewIOS.android.js b/Libraries/RCTTest/SnapshotViewIOS.android.js index ef8eb9d7bf67f6..ebd42dd5b18bb0 100644 --- a/Libraries/RCTTest/SnapshotViewIOS.android.js +++ b/Libraries/RCTTest/SnapshotViewIOS.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule SnapshotViewIOS */ 'use strict'; diff --git a/Libraries/RCTTest/SnapshotViewIOS.ios.js b/Libraries/RCTTest/SnapshotViewIOS.ios.js index 494830cd4ff3c0..050ec5d633dd63 100644 --- a/Libraries/RCTTest/SnapshotViewIOS.ios.js +++ b/Libraries/RCTTest/SnapshotViewIOS.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule SnapshotViewIOS * @flow */ 'use strict'; diff --git a/Libraries/ReactNative/AppContainer.js b/Libraries/ReactNative/AppContainer.js index cb1ea048e4adbc..8cdbd6dec15c18 100644 --- a/Libraries/ReactNative/AppContainer.js +++ b/Libraries/ReactNative/AppContainer.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AppContainer * @format * @flow */ diff --git a/Libraries/ReactNative/AppRegistry.js b/Libraries/ReactNative/AppRegistry.js index efe8e5584f2f0a..a2fdf91e632d45 100644 --- a/Libraries/ReactNative/AppRegistry.js +++ b/Libraries/ReactNative/AppRegistry.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AppRegistry * @flow * @format */ diff --git a/Libraries/ReactNative/FabricUIManager.js b/Libraries/ReactNative/FabricUIManager.js index 602b5459101b7d..f1b06ede5c1715 100644 --- a/Libraries/ReactNative/FabricUIManager.js +++ b/Libraries/ReactNative/FabricUIManager.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule FabricUIManager * @flow * @format */ diff --git a/Libraries/ReactNative/I18nManager.js b/Libraries/ReactNative/I18nManager.js index a8a256d515f480..5212d1100dac92 100644 --- a/Libraries/ReactNative/I18nManager.js +++ b/Libraries/ReactNative/I18nManager.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule I18nManager * @flow * @format */ diff --git a/Libraries/ReactNative/ReactFabricInternals.js b/Libraries/ReactNative/ReactFabricInternals.js index 72f37a41232d73..47855a8b7c0c29 100644 --- a/Libraries/ReactNative/ReactFabricInternals.js +++ b/Libraries/ReactNative/ReactFabricInternals.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ReactFabricInternals * @flow * @format */ diff --git a/Libraries/ReactNative/UIManager.js b/Libraries/ReactNative/UIManager.js index 946d2233c5f132..9f34734a731cd5 100644 --- a/Libraries/ReactNative/UIManager.js +++ b/Libraries/ReactNative/UIManager.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule UIManager * @flow * @format */ diff --git a/Libraries/ReactNative/UIManagerStatTracker.js b/Libraries/ReactNative/UIManagerStatTracker.js index 31f0a83613ffd1..3e1a6afd073916 100644 --- a/Libraries/ReactNative/UIManagerStatTracker.js +++ b/Libraries/ReactNative/UIManagerStatTracker.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule UIManagerStatTracker * @flow * @format */ diff --git a/Libraries/ReactNative/YellowBox.js b/Libraries/ReactNative/YellowBox.js index 8c3eb1f2cb714b..aa5d9788ab9f13 100644 --- a/Libraries/ReactNative/YellowBox.js +++ b/Libraries/ReactNative/YellowBox.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule YellowBox * @flow * @format */ diff --git a/Libraries/ReactNative/queryLayoutByID.js b/Libraries/ReactNative/queryLayoutByID.js index d484405920d29a..b4d001e04d983f 100644 --- a/Libraries/ReactNative/queryLayoutByID.js +++ b/Libraries/ReactNative/queryLayoutByID.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule queryLayoutByID * @flow * @format */ diff --git a/Libraries/ReactNative/renderApplication.js b/Libraries/ReactNative/renderApplication.js index 8abfed260402b5..42e9673dbc4895 100644 --- a/Libraries/ReactNative/renderApplication.js +++ b/Libraries/ReactNative/renderApplication.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule renderApplication * @format * @flow */ diff --git a/Libraries/ReactNative/requireNativeComponent.js b/Libraries/ReactNative/requireNativeComponent.js index 77141b1c049ae1..83a071c7066f23 100644 --- a/Libraries/ReactNative/requireNativeComponent.js +++ b/Libraries/ReactNative/requireNativeComponent.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule requireNativeComponent * @flow * @format */ diff --git a/Libraries/ReactNative/takeSnapshot.js b/Libraries/ReactNative/takeSnapshot.js index 212e6338faca72..5c9e248e5e4af7 100644 --- a/Libraries/ReactNative/takeSnapshot.js +++ b/Libraries/ReactNative/takeSnapshot.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule takeSnapshot * @format * @flow */ diff --git a/Libraries/ReactNative/verifyPropTypes.js b/Libraries/ReactNative/verifyPropTypes.js index 7791899d298b2f..b7b04d013c2315 100644 --- a/Libraries/ReactNative/verifyPropTypes.js +++ b/Libraries/ReactNative/verifyPropTypes.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule verifyPropTypes * @flow * @format */ diff --git a/Libraries/Renderer/oss/ReactFabric-dev.js b/Libraries/Renderer/oss/ReactFabric-dev.js index a24f4f6a50dddb..0424315c8ed6b5 100644 --- a/Libraries/Renderer/oss/ReactFabric-dev.js +++ b/Libraries/Renderer/oss/ReactFabric-dev.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @noflow - * @providesModule ReactFabric-dev * @preventMunge */ diff --git a/Libraries/Renderer/oss/ReactFabric-prod.js b/Libraries/Renderer/oss/ReactFabric-prod.js index 48099a5351cbf3..19ca0dde9e33cf 100644 --- a/Libraries/Renderer/oss/ReactFabric-prod.js +++ b/Libraries/Renderer/oss/ReactFabric-prod.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @noflow - * @providesModule ReactFabric-prod * @preventMunge */ diff --git a/Libraries/Renderer/oss/ReactNativeRenderer-dev.js b/Libraries/Renderer/oss/ReactNativeRenderer-dev.js index 9e14a0c266e9db..21d9a6c1d54399 100644 --- a/Libraries/Renderer/oss/ReactNativeRenderer-dev.js +++ b/Libraries/Renderer/oss/ReactNativeRenderer-dev.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @noflow - * @providesModule ReactNativeRenderer-dev * @preventMunge */ diff --git a/Libraries/Renderer/oss/ReactNativeRenderer-prod.js b/Libraries/Renderer/oss/ReactNativeRenderer-prod.js index 32b4729f3c96f8..f7eb9e09f0dce6 100644 --- a/Libraries/Renderer/oss/ReactNativeRenderer-prod.js +++ b/Libraries/Renderer/oss/ReactNativeRenderer-prod.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @noflow - * @providesModule ReactNativeRenderer-prod * @preventMunge */ diff --git a/Libraries/Renderer/shims/NativeMethodsMixin.js b/Libraries/Renderer/shims/NativeMethodsMixin.js index cd0e673b3bffe1..7acdf99bbd39ae 100644 --- a/Libraries/Renderer/shims/NativeMethodsMixin.js +++ b/Libraries/Renderer/shims/NativeMethodsMixin.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule NativeMethodsMixin * @flow */ diff --git a/Libraries/Renderer/shims/ReactDebugTool.js b/Libraries/Renderer/shims/ReactDebugTool.js index e45af4fb099433..8ea7ba5c1433c8 100644 --- a/Libraries/Renderer/shims/ReactDebugTool.js +++ b/Libraries/Renderer/shims/ReactDebugTool.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ReactDebugTool */ 'use strict'; diff --git a/Libraries/Renderer/shims/ReactFabric.js b/Libraries/Renderer/shims/ReactFabric.js index 4162ca62fef73d..8dce288d28a71e 100644 --- a/Libraries/Renderer/shims/ReactFabric.js +++ b/Libraries/Renderer/shims/ReactFabric.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ReactFabric * @flow */ 'use strict'; diff --git a/Libraries/Renderer/shims/ReactNative.js b/Libraries/Renderer/shims/ReactNative.js index a648cafbc30c22..43c5002e05f58a 100644 --- a/Libraries/Renderer/shims/ReactNative.js +++ b/Libraries/Renderer/shims/ReactNative.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ReactNative * @flow */ 'use strict'; diff --git a/Libraries/Renderer/shims/ReactNativeComponentTree.js b/Libraries/Renderer/shims/ReactNativeComponentTree.js index 30ec5257f424c8..8e8ce6ae06c1a0 100644 --- a/Libraries/Renderer/shims/ReactNativeComponentTree.js +++ b/Libraries/Renderer/shims/ReactNativeComponentTree.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ReactNativeComponentTree * @flow */ diff --git a/Libraries/Renderer/shims/ReactNativeTypes.js b/Libraries/Renderer/shims/ReactNativeTypes.js index bf94119739334d..485ce162ecc6bd 100644 --- a/Libraries/Renderer/shims/ReactNativeTypes.js +++ b/Libraries/Renderer/shims/ReactNativeTypes.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule ReactNativeTypes */ export type MeasureOnSuccessCallback = ( diff --git a/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js b/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js index ffb0fa213f3b31..c8ed940a860955 100644 --- a/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js +++ b/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ReactNativeViewConfigRegistry * @flow */ 'use strict'; diff --git a/Libraries/Renderer/shims/ReactPerf.js b/Libraries/Renderer/shims/ReactPerf.js index bb6777fff0b989..e94c87501c7dc1 100644 --- a/Libraries/Renderer/shims/ReactPerf.js +++ b/Libraries/Renderer/shims/ReactPerf.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ReactPerf */ 'use strict'; diff --git a/Libraries/Renderer/shims/ReactTypes.js b/Libraries/Renderer/shims/ReactTypes.js index 689ed18bf95294..747a6c07b6f363 100644 --- a/Libraries/Renderer/shims/ReactTypes.js +++ b/Libraries/Renderer/shims/ReactTypes.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule ReactTypes */ export type ReactNode = diff --git a/Libraries/Renderer/shims/createReactNativeComponentClass.js b/Libraries/Renderer/shims/createReactNativeComponentClass.js index 1a050e8b3cf0f8..cacaedab88f2c4 100644 --- a/Libraries/Renderer/shims/createReactNativeComponentClass.js +++ b/Libraries/Renderer/shims/createReactNativeComponentClass.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule createReactNativeComponentClass * @flow */ diff --git a/Libraries/Sample/Sample.android.js b/Libraries/Sample/Sample.android.js index 1a66fb9bf57506..dbb43949f6f61c 100644 --- a/Libraries/Sample/Sample.android.js +++ b/Libraries/Sample/Sample.android.js @@ -1,7 +1,6 @@ /** * Stub of Sample for Android. * - * @providesModule Sample * @flow */ 'use strict'; diff --git a/Libraries/Sample/Sample.ios.js b/Libraries/Sample/Sample.ios.js index fd94afe0a68e02..ae51247cc63524 100644 --- a/Libraries/Sample/Sample.ios.js +++ b/Libraries/Sample/Sample.ios.js @@ -1,5 +1,4 @@ /** - * @providesModule Sample * @flow */ 'use strict'; diff --git a/Libraries/Settings/Settings.android.js b/Libraries/Settings/Settings.android.js index 946c4aa9cde219..220c04e8b15961 100644 --- a/Libraries/Settings/Settings.android.js +++ b/Libraries/Settings/Settings.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Settings * @flow */ 'use strict'; diff --git a/Libraries/Settings/Settings.ios.js b/Libraries/Settings/Settings.ios.js index 08f1be6a1c8ae1..46f0a8bebdd7c9 100644 --- a/Libraries/Settings/Settings.ios.js +++ b/Libraries/Settings/Settings.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Settings * @flow */ 'use strict'; diff --git a/Libraries/Share/Share.js b/Libraries/Share/Share.js index e41b29db8e54d8..b6066c11da54aa 100644 --- a/Libraries/Share/Share.js +++ b/Libraries/Share/Share.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Share * @flow */ 'use strict'; diff --git a/Libraries/Storage/AsyncStorage.js b/Libraries/Storage/AsyncStorage.js index 4e262e6150c36f..f953aecbce26b0 100644 --- a/Libraries/Storage/AsyncStorage.js +++ b/Libraries/Storage/AsyncStorage.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AsyncStorage * @noflow * @flow-weak * @jsdoc diff --git a/Libraries/StyleSheet/ColorPropType.js b/Libraries/StyleSheet/ColorPropType.js index 60e362275bfbc9..28bc93f45fa9ef 100644 --- a/Libraries/StyleSheet/ColorPropType.js +++ b/Libraries/StyleSheet/ColorPropType.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ColorPropType */ 'use strict'; diff --git a/Libraries/StyleSheet/EdgeInsetsPropType.js b/Libraries/StyleSheet/EdgeInsetsPropType.js index 307c6be2e5daed..0bab3a58e65aac 100644 --- a/Libraries/StyleSheet/EdgeInsetsPropType.js +++ b/Libraries/StyleSheet/EdgeInsetsPropType.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule EdgeInsetsPropType * @flow */ 'use strict'; diff --git a/Libraries/StyleSheet/LayoutPropTypes.js b/Libraries/StyleSheet/LayoutPropTypes.js index 02ec8733f6bbd8..6ff1844c7facd8 100644 --- a/Libraries/StyleSheet/LayoutPropTypes.js +++ b/Libraries/StyleSheet/LayoutPropTypes.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule LayoutPropTypes * @flow */ 'use strict'; diff --git a/Libraries/StyleSheet/PointPropType.js b/Libraries/StyleSheet/PointPropType.js index a55628adbee7d3..44efc2d5fc400c 100644 --- a/Libraries/StyleSheet/PointPropType.js +++ b/Libraries/StyleSheet/PointPropType.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule PointPropType * @flow */ 'use strict'; diff --git a/Libraries/StyleSheet/StyleSheet.js b/Libraries/StyleSheet/StyleSheet.js index 5aab99d157626a..4384ce9dbfc05d 100644 --- a/Libraries/StyleSheet/StyleSheet.js +++ b/Libraries/StyleSheet/StyleSheet.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule StyleSheet * @flow * @format */ diff --git a/Libraries/StyleSheet/StyleSheetPropType.js b/Libraries/StyleSheet/StyleSheetPropType.js index ac779f915393c8..9fed3d207a6303 100644 --- a/Libraries/StyleSheet/StyleSheetPropType.js +++ b/Libraries/StyleSheet/StyleSheetPropType.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule StyleSheetPropType * @flow */ 'use strict'; diff --git a/Libraries/StyleSheet/StyleSheetTypes.js b/Libraries/StyleSheet/StyleSheetTypes.js index 1134c252deeb81..321bdc86922dc3 100644 --- a/Libraries/StyleSheet/StyleSheetTypes.js +++ b/Libraries/StyleSheet/StyleSheetTypes.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule StyleSheetTypes * @flow * @format */ diff --git a/Libraries/StyleSheet/StyleSheetValidation.js b/Libraries/StyleSheet/StyleSheetValidation.js index 3e1af7bc1dd2f7..ae6c843de4f7ee 100644 --- a/Libraries/StyleSheet/StyleSheetValidation.js +++ b/Libraries/StyleSheet/StyleSheetValidation.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule StyleSheetValidation * @flow */ 'use strict'; diff --git a/Libraries/StyleSheet/TransformPropTypes.js b/Libraries/StyleSheet/TransformPropTypes.js index bd1f3d352e116d..13a58fdd7ff8ca 100644 --- a/Libraries/StyleSheet/TransformPropTypes.js +++ b/Libraries/StyleSheet/TransformPropTypes.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TransformPropTypes * @flow */ 'use strict'; diff --git a/Libraries/StyleSheet/flattenStyle.js b/Libraries/StyleSheet/flattenStyle.js index 176f5492a7e79e..f62e35ea70f4f4 100644 --- a/Libraries/StyleSheet/flattenStyle.js +++ b/Libraries/StyleSheet/flattenStyle.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule flattenStyle * @flow * @format */ diff --git a/Libraries/StyleSheet/processColor.js b/Libraries/StyleSheet/processColor.js index 7d3a802bbbe3c2..dba665255110c5 100644 --- a/Libraries/StyleSheet/processColor.js +++ b/Libraries/StyleSheet/processColor.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule processColor * @flow */ 'use strict'; diff --git a/Libraries/StyleSheet/processTransform.js b/Libraries/StyleSheet/processTransform.js index 09cc7ca95d18c0..3c8d30ea0e0ed6 100644 --- a/Libraries/StyleSheet/processTransform.js +++ b/Libraries/StyleSheet/processTransform.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule processTransform * @flow */ 'use strict'; diff --git a/Libraries/StyleSheet/setNormalizedColorAlpha.js b/Libraries/StyleSheet/setNormalizedColorAlpha.js index 309d86cea12e80..83a0873e577f1e 100644 --- a/Libraries/StyleSheet/setNormalizedColorAlpha.js +++ b/Libraries/StyleSheet/setNormalizedColorAlpha.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule setNormalizedColorAlpha * @flow */ /* eslint no-bitwise: 0 */ diff --git a/Libraries/Text/Text.js b/Libraries/Text/Text.js index 83b02877b88386..d6fd56fcc62e40 100644 --- a/Libraries/Text/Text.js +++ b/Libraries/Text/Text.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Text * @flow * @format */ diff --git a/Libraries/Text/TextPropTypes.js b/Libraries/Text/TextPropTypes.js index 81a7af03f6058f..5a3c99d7378531 100644 --- a/Libraries/Text/TextPropTypes.js +++ b/Libraries/Text/TextPropTypes.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TextPropTypes * @flow * @format */ diff --git a/Libraries/Text/TextProps.js b/Libraries/Text/TextProps.js index effc8b05480b92..56229632a01bac 100644 --- a/Libraries/Text/TextProps.js +++ b/Libraries/Text/TextProps.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TextProps * @flow * @format */ diff --git a/Libraries/Text/TextStylePropTypes.js b/Libraries/Text/TextStylePropTypes.js index 872497ecf2ee1f..532f2e3d3edea5 100644 --- a/Libraries/Text/TextStylePropTypes.js +++ b/Libraries/Text/TextStylePropTypes.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TextStylePropTypes * @flow */ 'use strict'; diff --git a/Libraries/Text/TextUpdateTest.js b/Libraries/Text/TextUpdateTest.js index ec81ddab1c7903..18a3ac5084b7af 100644 --- a/Libraries/Text/TextUpdateTest.js +++ b/Libraries/Text/TextUpdateTest.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TextUpdateTest * @flow */ 'use strict'; diff --git a/Libraries/Types/CoreEventTypes.js b/Libraries/Types/CoreEventTypes.js index 56d4eecf8c348b..ede607f0c706d2 100644 --- a/Libraries/Types/CoreEventTypes.js +++ b/Libraries/Types/CoreEventTypes.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule CoreEventTypes * @flow * @format */ diff --git a/Libraries/UTFSequence.js b/Libraries/UTFSequence.js index 9bff51555d5563..f1e9e28e505e34 100644 --- a/Libraries/UTFSequence.js +++ b/Libraries/UTFSequence.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule UTFSequence * @flow * @format */ diff --git a/Libraries/Utilities/BackAndroid.js b/Libraries/Utilities/BackAndroid.js index 4fc029341f4b9e..51a68a7671f8e4 100644 --- a/Libraries/Utilities/BackAndroid.js +++ b/Libraries/Utilities/BackAndroid.js @@ -7,7 +7,6 @@ * BackAndroid has been moved to BackHandler. This stub calls BackHandler methods * after generating a warning to remind users to move to the new BackHandler module. * - * @providesModule BackAndroid */ 'use strict'; diff --git a/Libraries/Utilities/BackHandler.android.js b/Libraries/Utilities/BackHandler.android.js index 8f34cfacd1c349..b2e3a74bc44864 100644 --- a/Libraries/Utilities/BackHandler.android.js +++ b/Libraries/Utilities/BackHandler.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule BackHandler */ 'use strict'; diff --git a/Libraries/Utilities/BackHandler.ios.js b/Libraries/Utilities/BackHandler.ios.js index 33c6a8c1d6aa48..0c0d7d437870df 100644 --- a/Libraries/Utilities/BackHandler.ios.js +++ b/Libraries/Utilities/BackHandler.ios.js @@ -7,7 +7,6 @@ * On Apple TV, this implements back navigation using the TV remote's menu button. * On iOS, this just implements a stub. * - * @providesModule BackHandler */ 'use strict'; diff --git a/Libraries/Utilities/DeviceInfo.js b/Libraries/Utilities/DeviceInfo.js index 8503ac75ca31f5..427ed495232dad 100644 --- a/Libraries/Utilities/DeviceInfo.js +++ b/Libraries/Utilities/DeviceInfo.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule DeviceInfo * @flow */ 'use strict'; diff --git a/Libraries/Utilities/Dimensions.js b/Libraries/Utilities/Dimensions.js index d13b14f1bd18ea..f27ecc0976b823 100644 --- a/Libraries/Utilities/Dimensions.js +++ b/Libraries/Utilities/Dimensions.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Dimensions * @flow */ 'use strict'; diff --git a/Libraries/Utilities/HMRClient.js b/Libraries/Utilities/HMRClient.js index ff897afda8bf99..77169a2efcb57b 100644 --- a/Libraries/Utilities/HMRClient.js +++ b/Libraries/Utilities/HMRClient.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule HMRClient * @format * @flow */ diff --git a/Libraries/Utilities/HMRLoadingView.android.js b/Libraries/Utilities/HMRLoadingView.android.js index ebda3ee65c81ec..f4c0c5c731222d 100644 --- a/Libraries/Utilities/HMRLoadingView.android.js +++ b/Libraries/Utilities/HMRLoadingView.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule HMRLoadingView * @flow */ diff --git a/Libraries/Utilities/HMRLoadingView.ios.js b/Libraries/Utilities/HMRLoadingView.ios.js index 7100164d4ca667..4e9ad8fbf93f1d 100644 --- a/Libraries/Utilities/HMRLoadingView.ios.js +++ b/Libraries/Utilities/HMRLoadingView.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule HMRLoadingView * @flow */ diff --git a/Libraries/Utilities/HeapCapture.js b/Libraries/Utilities/HeapCapture.js index 49e9d678e1eef2..519a2e94370b8c 100644 --- a/Libraries/Utilities/HeapCapture.js +++ b/Libraries/Utilities/HeapCapture.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule HeapCapture * @flow */ 'use strict'; diff --git a/Libraries/Utilities/JSDevSupportModule.js b/Libraries/Utilities/JSDevSupportModule.js index dc45030bf3b5bd..c2512328461393 100644 --- a/Libraries/Utilities/JSDevSupportModule.js +++ b/Libraries/Utilities/JSDevSupportModule.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule JSDevSupportModule * @flow */ 'use strict'; diff --git a/Libraries/Utilities/MatrixMath.js b/Libraries/Utilities/MatrixMath.js index b36b316833fcb7..be329c2e645d5d 100755 --- a/Libraries/Utilities/MatrixMath.js +++ b/Libraries/Utilities/MatrixMath.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule MatrixMath * @noflow */ /* eslint-disable space-infix-ops */ diff --git a/Libraries/Utilities/PerformanceLogger.js b/Libraries/Utilities/PerformanceLogger.js index 95b5f4924e89ef..aa4633fceb9c6e 100644 --- a/Libraries/Utilities/PerformanceLogger.js +++ b/Libraries/Utilities/PerformanceLogger.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule PerformanceLogger * @flow * @format */ diff --git a/Libraries/Utilities/PixelRatio.js b/Libraries/Utilities/PixelRatio.js index bd8a6a0b9571dc..5f52bdc0f5b838 100644 --- a/Libraries/Utilities/PixelRatio.js +++ b/Libraries/Utilities/PixelRatio.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule PixelRatio * @flow */ 'use strict'; diff --git a/Libraries/Utilities/Platform.android.js b/Libraries/Utilities/Platform.android.js index f0e80633f2f283..56b0d24944780d 100644 --- a/Libraries/Utilities/Platform.android.js +++ b/Libraries/Utilities/Platform.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Platform * @flow */ diff --git a/Libraries/Utilities/Platform.ios.js b/Libraries/Utilities/Platform.ios.js index 776880b7fa400d..9780ec75d2742b 100644 --- a/Libraries/Utilities/Platform.ios.js +++ b/Libraries/Utilities/Platform.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Platform * @flow */ diff --git a/Libraries/Utilities/PlatformOS.android.js b/Libraries/Utilities/PlatformOS.android.js index ff2a383759c455..d2183c41682cfd 100644 --- a/Libraries/Utilities/PlatformOS.android.js +++ b/Libraries/Utilities/PlatformOS.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule PlatformOS * @flow */ diff --git a/Libraries/Utilities/PlatformOS.ios.js b/Libraries/Utilities/PlatformOS.ios.js index 11fed5978096cb..95b275712a08e7 100644 --- a/Libraries/Utilities/PlatformOS.ios.js +++ b/Libraries/Utilities/PlatformOS.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule PlatformOS * @flow */ diff --git a/Libraries/Utilities/PolyfillFunctions.js b/Libraries/Utilities/PolyfillFunctions.js index 5bf31ee118b4d2..28cb44d5402bae 100644 --- a/Libraries/Utilities/PolyfillFunctions.js +++ b/Libraries/Utilities/PolyfillFunctions.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule PolyfillFunctions * @flow * @format */ diff --git a/Libraries/Utilities/RCTLog.js b/Libraries/Utilities/RCTLog.js index 2514d9b4039d29..7259b79761f72d 100644 --- a/Libraries/Utilities/RCTLog.js +++ b/Libraries/Utilities/RCTLog.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule RCTLog * @flow */ 'use strict'; diff --git a/Libraries/Utilities/SceneTracker.js b/Libraries/Utilities/SceneTracker.js index 9cebe76a99d5d2..ae41ec03e08b00 100644 --- a/Libraries/Utilities/SceneTracker.js +++ b/Libraries/Utilities/SceneTracker.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule SceneTracker * @flow */ diff --git a/Libraries/Utilities/binaryToBase64.js b/Libraries/Utilities/binaryToBase64.js index d17c4d403c8705..74a01a0bcad411 100644 --- a/Libraries/Utilities/binaryToBase64.js +++ b/Libraries/Utilities/binaryToBase64.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule binaryToBase64 * @flow */ 'use strict'; diff --git a/Libraries/Utilities/buildStyleInterpolator.js b/Libraries/Utilities/buildStyleInterpolator.js index ec174441173965..a22526e45cf31e 100644 --- a/Libraries/Utilities/buildStyleInterpolator.js +++ b/Libraries/Utilities/buildStyleInterpolator.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule buildStyleInterpolator */ 'use strict'; diff --git a/Libraries/Utilities/clamp.js b/Libraries/Utilities/clamp.js index 5d15d8b3b12f3f..dcfc93d855ddd4 100644 --- a/Libraries/Utilities/clamp.js +++ b/Libraries/Utilities/clamp.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule clamp * @typechecks */ 'use strict'; diff --git a/Libraries/Utilities/createStrictShapeTypeChecker.js b/Libraries/Utilities/createStrictShapeTypeChecker.js index 89347d15e0b86a..5cde7eb5315768 100644 --- a/Libraries/Utilities/createStrictShapeTypeChecker.js +++ b/Libraries/Utilities/createStrictShapeTypeChecker.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule createStrictShapeTypeChecker * @flow */ 'use strict'; diff --git a/Libraries/Utilities/deepFreezeAndThrowOnMutationInDev.js b/Libraries/Utilities/deepFreezeAndThrowOnMutationInDev.js index 19cb60a9c56d6f..041691a67f7abe 100644 --- a/Libraries/Utilities/deepFreezeAndThrowOnMutationInDev.js +++ b/Libraries/Utilities/deepFreezeAndThrowOnMutationInDev.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule deepFreezeAndThrowOnMutationInDev * @flow */ diff --git a/Libraries/Utilities/defineLazyObjectProperty.js b/Libraries/Utilities/defineLazyObjectProperty.js index 87e893037913b4..cd01de5c27096c 100644 --- a/Libraries/Utilities/defineLazyObjectProperty.js +++ b/Libraries/Utilities/defineLazyObjectProperty.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule defineLazyObjectProperty * @flow */ diff --git a/Libraries/Utilities/deprecatedPropType.js b/Libraries/Utilities/deprecatedPropType.js index 8b08854fabb043..398410545ed84d 100644 --- a/Libraries/Utilities/deprecatedPropType.js +++ b/Libraries/Utilities/deprecatedPropType.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule deprecatedPropType * @flow */ 'use strict'; diff --git a/Libraries/Utilities/differ/deepDiffer.js b/Libraries/Utilities/differ/deepDiffer.js index af0bd295694b19..700733f51f6bcf 100644 --- a/Libraries/Utilities/differ/deepDiffer.js +++ b/Libraries/Utilities/differ/deepDiffer.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule deepDiffer * @flow */ 'use strict'; diff --git a/Libraries/Utilities/differ/insetsDiffer.js b/Libraries/Utilities/differ/insetsDiffer.js index 1d497c0948e53a..7214ab6d763895 100644 --- a/Libraries/Utilities/differ/insetsDiffer.js +++ b/Libraries/Utilities/differ/insetsDiffer.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule insetsDiffer * @flow */ 'use strict'; diff --git a/Libraries/Utilities/differ/matricesDiffer.js b/Libraries/Utilities/differ/matricesDiffer.js index 25e741a4ff8283..177a7a110ac43a 100644 --- a/Libraries/Utilities/differ/matricesDiffer.js +++ b/Libraries/Utilities/differ/matricesDiffer.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule matricesDiffer */ 'use strict'; diff --git a/Libraries/Utilities/differ/pointsDiffer.js b/Libraries/Utilities/differ/pointsDiffer.js index cb41cec85494a4..e019124e76d1d8 100644 --- a/Libraries/Utilities/differ/pointsDiffer.js +++ b/Libraries/Utilities/differ/pointsDiffer.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule pointsDiffer * @flow */ 'use strict'; diff --git a/Libraries/Utilities/differ/sizesDiffer.js b/Libraries/Utilities/differ/sizesDiffer.js index 55ea66ded36ca5..c4e104a1439b79 100644 --- a/Libraries/Utilities/differ/sizesDiffer.js +++ b/Libraries/Utilities/differ/sizesDiffer.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule sizesDiffer */ 'use strict'; diff --git a/Libraries/Utilities/dismissKeyboard.js b/Libraries/Utilities/dismissKeyboard.js index febcc82bfa9a65..a5b9e2f00dd987 100644 --- a/Libraries/Utilities/dismissKeyboard.js +++ b/Libraries/Utilities/dismissKeyboard.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule dismissKeyboard * * This function dismisses the currently-open keyboard, if any */ diff --git a/Libraries/Utilities/groupByEveryN.js b/Libraries/Utilities/groupByEveryN.js index ea400392291231..2cda280be6f15f 100644 --- a/Libraries/Utilities/groupByEveryN.js +++ b/Libraries/Utilities/groupByEveryN.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule groupByEveryN * @flow */ diff --git a/Libraries/Utilities/infoLog.js b/Libraries/Utilities/infoLog.js index 66278f520e8424..9437179b163d4b 100644 --- a/Libraries/Utilities/infoLog.js +++ b/Libraries/Utilities/infoLog.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule infoLog */ 'use strict'; diff --git a/Libraries/Utilities/logError.js b/Libraries/Utilities/logError.js index 6cf212b1f14712..5482448ae20b54 100644 --- a/Libraries/Utilities/logError.js +++ b/Libraries/Utilities/logError.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule logError * @flow */ 'use strict'; diff --git a/Libraries/Utilities/mapWithSeparator.js b/Libraries/Utilities/mapWithSeparator.js index 0beceda0174c0f..09fe19cec8977d 100644 --- a/Libraries/Utilities/mapWithSeparator.js +++ b/Libraries/Utilities/mapWithSeparator.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule mapWithSeparator * @flow */ 'use strict'; diff --git a/Libraries/Utilities/mergeFast.js b/Libraries/Utilities/mergeFast.js index 60ad36c20464a8..42e357e5dbda59 100644 --- a/Libraries/Utilities/mergeFast.js +++ b/Libraries/Utilities/mergeFast.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule mergeFast * @flow */ 'use strict'; diff --git a/Libraries/Utilities/mergeIntoFast.js b/Libraries/Utilities/mergeIntoFast.js index ff048311403a87..e657de7c3d9dbb 100644 --- a/Libraries/Utilities/mergeIntoFast.js +++ b/Libraries/Utilities/mergeIntoFast.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule mergeIntoFast * @flow */ 'use strict'; diff --git a/Libraries/Utilities/stringifySafe.js b/Libraries/Utilities/stringifySafe.js index 39ada622714243..f8f7ab8f0e4013 100644 --- a/Libraries/Utilities/stringifySafe.js +++ b/Libraries/Utilities/stringifySafe.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule stringifySafe * @flow */ 'use strict'; diff --git a/Libraries/Utilities/truncate.js b/Libraries/Utilities/truncate.js index 0e0d8c643ea55e..5b89e8ff200741 100644 --- a/Libraries/Utilities/truncate.js +++ b/Libraries/Utilities/truncate.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule truncate * @flow */ 'use strict'; diff --git a/Libraries/Vibration/Vibration.js b/Libraries/Vibration/Vibration.js index 7f10cda29f8fab..c0ee75203fcd57 100644 --- a/Libraries/Vibration/Vibration.js +++ b/Libraries/Vibration/Vibration.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Vibration * @flow * @jsdoc */ diff --git a/Libraries/Vibration/VibrationIOS.android.js b/Libraries/Vibration/VibrationIOS.android.js index 0b2279b696ccb5..b57279a73844df 100644 --- a/Libraries/Vibration/VibrationIOS.android.js +++ b/Libraries/Vibration/VibrationIOS.android.js @@ -6,7 +6,6 @@ * * Stub of VibrationIOS for Android. * - * @providesModule VibrationIOS */ 'use strict'; diff --git a/Libraries/Vibration/VibrationIOS.ios.js b/Libraries/Vibration/VibrationIOS.ios.js index ec55640442f670..5ce5f4019bb5a6 100644 --- a/Libraries/Vibration/VibrationIOS.ios.js +++ b/Libraries/Vibration/VibrationIOS.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule VibrationIOS * @flow */ 'use strict'; diff --git a/Libraries/WebSocket/WebSocket.js b/Libraries/WebSocket/WebSocket.js index 1b401d236c2830..ef28c6ce464d0a 100644 --- a/Libraries/WebSocket/WebSocket.js +++ b/Libraries/WebSocket/WebSocket.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule WebSocket * @flow */ 'use strict'; diff --git a/Libraries/WebSocket/WebSocketEvent.js b/Libraries/WebSocket/WebSocketEvent.js index 93133902a94a8d..b72188d34b8c4c 100644 --- a/Libraries/WebSocket/WebSocketEvent.js +++ b/Libraries/WebSocket/WebSocketEvent.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule WebSocketEvent */ 'use strict'; diff --git a/Libraries/WebSocket/WebSocketInterceptor.js b/Libraries/WebSocket/WebSocketInterceptor.js index 10251dfa1a2045..0ab63cf662a9b2 100644 --- a/Libraries/WebSocket/WebSocketInterceptor.js +++ b/Libraries/WebSocket/WebSocketInterceptor.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule WebSocketInterceptor */ 'use strict'; diff --git a/Libraries/polyfills/Array.es6.js b/Libraries/polyfills/Array.es6.js index 0075d7ae1e070c..252d996b919fd2 100644 --- a/Libraries/polyfills/Array.es6.js +++ b/Libraries/polyfills/Array.es6.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Array.es6 * @polyfill * @nolint */ diff --git a/Libraries/polyfills/Array.prototype.es6.js b/Libraries/polyfills/Array.prototype.es6.js index 2bf044144eb7a9..a3c8da5415fa62 100644 --- a/Libraries/polyfills/Array.prototype.es6.js +++ b/Libraries/polyfills/Array.prototype.es6.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Array.prototype.es6 * @polyfill * @nolint */ diff --git a/Libraries/polyfills/Number.es6.js b/Libraries/polyfills/Number.es6.js index ef7d4ac88e4f41..b95166205be6e3 100644 --- a/Libraries/polyfills/Number.es6.js +++ b/Libraries/polyfills/Number.es6.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Number.es6 * @polyfill * @nolint */ diff --git a/Libraries/polyfills/Object.es6.js b/Libraries/polyfills/Object.es6.js index 0aa884e8be9596..3d521e0a630d57 100644 --- a/Libraries/polyfills/Object.es6.js +++ b/Libraries/polyfills/Object.es6.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Object.es6 * @polyfill * @nolint */ diff --git a/Libraries/polyfills/Object.es7.js b/Libraries/polyfills/Object.es7.js index 294756b11c3638..a891057b9e7bed 100644 --- a/Libraries/polyfills/Object.es7.js +++ b/Libraries/polyfills/Object.es7.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Object.es7 * @polyfill * @nolint */ diff --git a/Libraries/polyfills/String.prototype.es6.js b/Libraries/polyfills/String.prototype.es6.js index b3bd95be6b88bc..02b33dd1e199dd 100644 --- a/Libraries/polyfills/String.prototype.es6.js +++ b/Libraries/polyfills/String.prototype.es6.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule String.prototype.es6 * @polyfill * @nolint */ diff --git a/Libraries/polyfills/babelHelpers.js b/Libraries/polyfills/babelHelpers.js index 7d251ea347489b..11123e0f3bc002 100644 --- a/Libraries/polyfills/babelHelpers.js +++ b/Libraries/polyfills/babelHelpers.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule babelHelpers * @polyfill * @nolint */ diff --git a/Libraries/polyfills/console.js b/Libraries/polyfills/console.js index 794a89c4f49f97..47970958a066e9 100644 --- a/Libraries/polyfills/console.js +++ b/Libraries/polyfills/console.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule console * @polyfill * @nolint * @format diff --git a/Libraries/polyfills/error-guard.js b/Libraries/polyfills/error-guard.js index 632e7e0e4f02d6..17181d10219290 100644 --- a/Libraries/polyfills/error-guard.js +++ b/Libraries/polyfills/error-guard.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule error-guard * @polyfill * @nolint */ diff --git a/Libraries/promiseRejectionIsError.js b/Libraries/promiseRejectionIsError.js index ce3ee915cff47f..672949116911f7 100644 --- a/Libraries/promiseRejectionIsError.js +++ b/Libraries/promiseRejectionIsError.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule promiseRejectionIsError * @flow */ 'use strict'; diff --git a/Libraries/react-native/React.js b/Libraries/react-native/React.js index f000f1403b5d6a..ff4c2454459fe0 100644 --- a/Libraries/react-native/React.js +++ b/Libraries/react-native/React.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule React */ 'use strict'; diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index e3b19adc459c80..5a6f9759e8ced4 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule react-native-implementation * @flow */ 'use strict'; diff --git a/Libraries/react-native/react-native-interface.js b/Libraries/react-native/react-native-interface.js index fd4ad545c31b10..5f2cdf2c1cf69c 100644 --- a/Libraries/react-native/react-native-interface.js +++ b/Libraries/react-native/react-native-interface.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule react-native-interface */ 'use strict'; diff --git a/Libraries/vendor/core/ErrorUtils.js b/Libraries/vendor/core/ErrorUtils.js index 8b36c611105d0e..2fb0272d347adf 100644 --- a/Libraries/vendor/core/ErrorUtils.js +++ b/Libraries/vendor/core/ErrorUtils.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ErrorUtils * @flow */ diff --git a/Libraries/vendor/core/Map.js b/Libraries/vendor/core/Map.js index e9e687a15ce99e..115e2f855eafab 100644 --- a/Libraries/vendor/core/Map.js +++ b/Libraries/vendor/core/Map.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Map * @preventMunge * @typechecks */ diff --git a/Libraries/vendor/core/Set.js b/Libraries/vendor/core/Set.js index b43313205ef7e3..16e3cecae21fb1 100644 --- a/Libraries/vendor/core/Set.js +++ b/Libraries/vendor/core/Set.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Set * @preventMunge * @typechecks */ diff --git a/Libraries/vendor/core/_shouldPolyfillES6Collection.js b/Libraries/vendor/core/_shouldPolyfillES6Collection.js index e3f77b169dece5..84ed51ded55e18 100644 --- a/Libraries/vendor/core/_shouldPolyfillES6Collection.js +++ b/Libraries/vendor/core/_shouldPolyfillES6Collection.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule _shouldPolyfillES6Collection * @preventMunge * @flow */ diff --git a/Libraries/vendor/core/getObjectValues.js b/Libraries/vendor/core/getObjectValues.js index aac327c2eaed9d..398788c1e02f96 100644 --- a/Libraries/vendor/core/getObjectValues.js +++ b/Libraries/vendor/core/getObjectValues.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule getObjectValues * @typechecks */ 'use strict'; diff --git a/Libraries/vendor/core/guid.js b/Libraries/vendor/core/guid.js index 74c97cf383de1f..b6195ef6b6917d 100644 --- a/Libraries/vendor/core/guid.js +++ b/Libraries/vendor/core/guid.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule guid */ /* eslint-disable no-bitwise */ diff --git a/Libraries/vendor/core/isEmpty.js b/Libraries/vendor/core/isEmpty.js index 1f55d4519ff3af..6d451729c7c8e2 100644 --- a/Libraries/vendor/core/isEmpty.js +++ b/Libraries/vendor/core/isEmpty.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule isEmpty */ 'use strict'; diff --git a/Libraries/vendor/core/merge.js b/Libraries/vendor/core/merge.js index 800c08c1be263a..6963eddd5628af 100644 --- a/Libraries/vendor/core/merge.js +++ b/Libraries/vendor/core/merge.js @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<0e3063b19e14ed191102b1dffe45551f>> + * @generated SignedSource<<148d1974f94f5c9597e86f946bdf0d4e>> * * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! * !! This file is a check-in of a static_upstream project! !! @@ -26,7 +26,6 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * @providesModule merge */ "use strict"; diff --git a/Libraries/vendor/core/mergeHelpers.js b/Libraries/vendor/core/mergeHelpers.js index 4eb2d9d2aec8f1..e24559ddb50c2f 100644 --- a/Libraries/vendor/core/mergeHelpers.js +++ b/Libraries/vendor/core/mergeHelpers.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule mergeHelpers * * requiresPolyfills: Array.isArray */ diff --git a/Libraries/vendor/core/mergeInto.js b/Libraries/vendor/core/mergeInto.js index 0da86a50cdb419..d42b3dcf36ed3f 100644 --- a/Libraries/vendor/core/mergeInto.js +++ b/Libraries/vendor/core/mergeInto.js @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<> * * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! * !! This file is a check-in of a static_upstream project! !! @@ -26,7 +26,6 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * @providesModule mergeInto * @typechecks static-only */ diff --git a/Libraries/vendor/core/toIterator.js b/Libraries/vendor/core/toIterator.js index b396c469c03f3e..cabd1e2b066786 100644 --- a/Libraries/vendor/core/toIterator.js +++ b/Libraries/vendor/core/toIterator.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule toIterator */ 'use strict'; diff --git a/Libraries/vendor/document/selection/DocumentSelectionState.js b/Libraries/vendor/document/selection/DocumentSelectionState.js index a702582c6965d0..28b93e34390609 100644 --- a/Libraries/vendor/document/selection/DocumentSelectionState.js +++ b/Libraries/vendor/document/selection/DocumentSelectionState.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule DocumentSelectionState * @typechecks */ diff --git a/Libraries/vendor/emitter/EmitterSubscription.js b/Libraries/vendor/emitter/EmitterSubscription.js index e352e71675c9b9..844c28e386c8c2 100644 --- a/Libraries/vendor/emitter/EmitterSubscription.js +++ b/Libraries/vendor/emitter/EmitterSubscription.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule EmitterSubscription * @flow */ 'use strict'; diff --git a/Libraries/vendor/emitter/EventEmitter.js b/Libraries/vendor/emitter/EventEmitter.js index 4fdb10a051593a..4b9307e492925e 100644 --- a/Libraries/vendor/emitter/EventEmitter.js +++ b/Libraries/vendor/emitter/EventEmitter.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule EventEmitter * @noflow * @typecheck */ diff --git a/Libraries/vendor/emitter/EventEmitterWithHolding.js b/Libraries/vendor/emitter/EventEmitterWithHolding.js index 8c082222e8f73f..a9f232a567a8c0 100644 --- a/Libraries/vendor/emitter/EventEmitterWithHolding.js +++ b/Libraries/vendor/emitter/EventEmitterWithHolding.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule EventEmitterWithHolding * @flow */ 'use strict'; diff --git a/Libraries/vendor/emitter/EventHolder.js b/Libraries/vendor/emitter/EventHolder.js index 3bb7062e020f6a..2faa43eb19a8e3 100644 --- a/Libraries/vendor/emitter/EventHolder.js +++ b/Libraries/vendor/emitter/EventHolder.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule EventHolder * @flow */ 'use strict'; diff --git a/Libraries/vendor/emitter/EventSubscription.js b/Libraries/vendor/emitter/EventSubscription.js index 82cb06fc4fd556..1d809c371d14ab 100644 --- a/Libraries/vendor/emitter/EventSubscription.js +++ b/Libraries/vendor/emitter/EventSubscription.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule EventSubscription * @flow */ 'use strict'; diff --git a/Libraries/vendor/emitter/EventSubscriptionVendor.js b/Libraries/vendor/emitter/EventSubscriptionVendor.js index aa2a4e76b90b21..779952898c8be8 100644 --- a/Libraries/vendor/emitter/EventSubscriptionVendor.js +++ b/Libraries/vendor/emitter/EventSubscriptionVendor.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule EventSubscriptionVendor * @flow */ 'use strict'; diff --git a/Libraries/vendor/emitter/EventValidator.js b/Libraries/vendor/emitter/EventValidator.js index 9930236776b210..16b4697910377e 100644 --- a/Libraries/vendor/emitter/EventValidator.js +++ b/Libraries/vendor/emitter/EventValidator.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule EventValidator * @flow */ 'use strict'; diff --git a/Libraries/vendor/emitter/mixInEventEmitter.js b/Libraries/vendor/emitter/mixInEventEmitter.js index 6ee08d6d31acb0..5b23f891d88307 100644 --- a/Libraries/vendor/emitter/mixInEventEmitter.js +++ b/Libraries/vendor/emitter/mixInEventEmitter.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule mixInEventEmitter * @flow */ 'use strict'; diff --git a/RNTester/RNTesterUnitTests/RNTesterUnitTestsBundle.js b/RNTester/RNTesterUnitTests/RNTesterUnitTestsBundle.js index f0a455ff355294..e6ff98a10ac117 100644 --- a/RNTester/RNTesterUnitTests/RNTesterUnitTestsBundle.js +++ b/RNTester/RNTesterUnitTests/RNTesterUnitTestsBundle.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule RNTesterUnitTestsBundle */ 'use strict'; diff --git a/RNTester/js/ARTExample.js b/RNTester/js/ARTExample.js index 704a9c06bbdc3e..fb8d0378c862a6 100644 --- a/RNTester/js/ARTExample.js +++ b/RNTester/js/ARTExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule ARTExample */ 'use strict'; diff --git a/RNTester/js/AccessibilityAndroidExample.android.js b/RNTester/js/AccessibilityAndroidExample.android.js index 54b087fa207fdf..6c6a80d416c07c 100644 --- a/RNTester/js/AccessibilityAndroidExample.android.js +++ b/RNTester/js/AccessibilityAndroidExample.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AccessibilityAndroidExample */ 'use strict'; diff --git a/RNTester/js/AccessibilityIOSExample.js b/RNTester/js/AccessibilityIOSExample.js index 0deead7538d62e..dabce101ce1e17 100644 --- a/RNTester/js/AccessibilityIOSExample.js +++ b/RNTester/js/AccessibilityIOSExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule AccessibilityIOSExample */ 'use strict'; diff --git a/RNTester/js/ActionSheetIOSExample.js b/RNTester/js/ActionSheetIOSExample.js index ac9d9737863780..1b04190b253ae6 100644 --- a/RNTester/js/ActionSheetIOSExample.js +++ b/RNTester/js/ActionSheetIOSExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule ActionSheetIOSExample */ 'use strict'; diff --git a/RNTester/js/ActivityIndicatorExample.js b/RNTester/js/ActivityIndicatorExample.js index 692acd01c7d167..05c9e06d4060ac 100644 --- a/RNTester/js/ActivityIndicatorExample.js +++ b/RNTester/js/ActivityIndicatorExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule ActivityIndicatorExample */ 'use strict'; diff --git a/RNTester/js/AlertExample.js b/RNTester/js/AlertExample.js index 93c82e4069c9f3..dee922a66abfd9 100644 --- a/RNTester/js/AlertExample.js +++ b/RNTester/js/AlertExample.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AlertExample */ 'use strict'; diff --git a/RNTester/js/AlertIOSExample.js b/RNTester/js/AlertIOSExample.js index b8b1cee43f85f7..8f4a898a572685 100644 --- a/RNTester/js/AlertIOSExample.js +++ b/RNTester/js/AlertIOSExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule AlertIOSExample */ 'use strict'; diff --git a/RNTester/js/AnimatedExample.js b/RNTester/js/AnimatedExample.js index 8130a9d9f62908..9e60a81cb10588 100644 --- a/RNTester/js/AnimatedExample.js +++ b/RNTester/js/AnimatedExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule AnimatedExample */ 'use strict'; diff --git a/RNTester/js/AnimatedGratuitousApp/AnExApp.js b/RNTester/js/AnimatedGratuitousApp/AnExApp.js index 1116a84ee98254..c723f40f7e1188 100644 --- a/RNTester/js/AnimatedGratuitousApp/AnExApp.js +++ b/RNTester/js/AnimatedGratuitousApp/AnExApp.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AnExApp * @flow */ 'use strict'; diff --git a/RNTester/js/AnimatedGratuitousApp/AnExBobble.js b/RNTester/js/AnimatedGratuitousApp/AnExBobble.js index d3f8885275eb91..7f56bbe68e97ee 100644 --- a/RNTester/js/AnimatedGratuitousApp/AnExBobble.js +++ b/RNTester/js/AnimatedGratuitousApp/AnExBobble.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AnExBobble * @flow */ 'use strict'; diff --git a/RNTester/js/AnimatedGratuitousApp/AnExChained.js b/RNTester/js/AnimatedGratuitousApp/AnExChained.js index 63a83804ed34c9..00d72dafb12aa8 100644 --- a/RNTester/js/AnimatedGratuitousApp/AnExChained.js +++ b/RNTester/js/AnimatedGratuitousApp/AnExChained.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AnExChained * @flow */ 'use strict'; diff --git a/RNTester/js/AnimatedGratuitousApp/AnExScroll.js b/RNTester/js/AnimatedGratuitousApp/AnExScroll.js index b7f69425437fdf..c0f7495e4baa87 100644 --- a/RNTester/js/AnimatedGratuitousApp/AnExScroll.js +++ b/RNTester/js/AnimatedGratuitousApp/AnExScroll.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AnExScroll * @flow */ 'use strict'; diff --git a/RNTester/js/AnimatedGratuitousApp/AnExSet.js b/RNTester/js/AnimatedGratuitousApp/AnExSet.js index a89fd2008a3f04..873d5251c2eb51 100644 --- a/RNTester/js/AnimatedGratuitousApp/AnExSet.js +++ b/RNTester/js/AnimatedGratuitousApp/AnExSet.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AnExSet * @flow */ 'use strict'; diff --git a/RNTester/js/AnimatedGratuitousApp/AnExTilt.js b/RNTester/js/AnimatedGratuitousApp/AnExTilt.js index a5678b6865073c..c7540de730eb9b 100644 --- a/RNTester/js/AnimatedGratuitousApp/AnExTilt.js +++ b/RNTester/js/AnimatedGratuitousApp/AnExTilt.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AnExTilt * @flow */ 'use strict'; diff --git a/RNTester/js/AppStateExample.js b/RNTester/js/AppStateExample.js index 8088d77fc06f37..f6b4265c84c3c8 100644 --- a/RNTester/js/AppStateExample.js +++ b/RNTester/js/AppStateExample.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule AppStateExample * @flow */ 'use strict'; diff --git a/RNTester/js/AssetScaledImageExample.js b/RNTester/js/AssetScaledImageExample.js index b723d8f50ea588..51e97a8aee925f 100644 --- a/RNTester/js/AssetScaledImageExample.js +++ b/RNTester/js/AssetScaledImageExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule AssetScaledImageExample */ 'use strict'; diff --git a/RNTester/js/AsyncStorageExample.js b/RNTester/js/AsyncStorageExample.js index 5e16a6b847c42c..eb354b2db633fc 100644 --- a/RNTester/js/AsyncStorageExample.js +++ b/RNTester/js/AsyncStorageExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule AsyncStorageExample */ 'use strict'; diff --git a/RNTester/js/BorderExample.js b/RNTester/js/BorderExample.js index 8885537fb35b43..6f64581dfbda8a 100644 --- a/RNTester/js/BorderExample.js +++ b/RNTester/js/BorderExample.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule BorderExample */ 'use strict'; diff --git a/RNTester/js/BoxShadowExample.js b/RNTester/js/BoxShadowExample.js index bddce0490b3b2c..056b61aee33ab2 100644 --- a/RNTester/js/BoxShadowExample.js +++ b/RNTester/js/BoxShadowExample.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule BoxShadowExample */ 'use strict'; diff --git a/RNTester/js/ButtonExample.js b/RNTester/js/ButtonExample.js index 6c850a2121a7f6..8ba4876ed74eab 100644 --- a/RNTester/js/ButtonExample.js +++ b/RNTester/js/ButtonExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule ButtonExample */ 'use strict'; diff --git a/RNTester/js/CameraRollExample.js b/RNTester/js/CameraRollExample.js index 508980d47196ad..f289a2b610771f 100644 --- a/RNTester/js/CameraRollExample.js +++ b/RNTester/js/CameraRollExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule CameraRollExample * @format */ 'use strict'; diff --git a/RNTester/js/CameraRollView.js b/RNTester/js/CameraRollView.js index c08aeb71e833c7..29eb070223a9cc 100644 --- a/RNTester/js/CameraRollView.js +++ b/RNTester/js/CameraRollView.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule CameraRollView * @flow */ 'use strict'; diff --git a/RNTester/js/CheckBoxExample.js b/RNTester/js/CheckBoxExample.js index 98685fac4be787..1ef830cabd1248 100644 --- a/RNTester/js/CheckBoxExample.js +++ b/RNTester/js/CheckBoxExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule CheckBoxExample * @format */ 'use strict'; diff --git a/RNTester/js/ClipboardExample.js b/RNTester/js/ClipboardExample.js index 8526cea43340e4..57ee1e172e7394 100644 --- a/RNTester/js/ClipboardExample.js +++ b/RNTester/js/ClipboardExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule ClipboardExample */ 'use strict'; diff --git a/RNTester/js/DatePickerAndroidExample.js b/RNTester/js/DatePickerAndroidExample.js index 926071b66d7a4a..2b6706e06be5ac 100644 --- a/RNTester/js/DatePickerAndroidExample.js +++ b/RNTester/js/DatePickerAndroidExample.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule DatePickerAndroidExample */ 'use strict'; diff --git a/RNTester/js/DatePickerIOSExample.js b/RNTester/js/DatePickerIOSExample.js index b11e0644c20d80..a0b6234e8225b1 100644 --- a/RNTester/js/DatePickerIOSExample.js +++ b/RNTester/js/DatePickerIOSExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule DatePickerIOSExample */ 'use strict'; diff --git a/RNTester/js/DimensionsExample.js b/RNTester/js/DimensionsExample.js index 9611eedd482de1..d0274f15a185b6 100644 --- a/RNTester/js/DimensionsExample.js +++ b/RNTester/js/DimensionsExample.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule DimensionsExample * @flow */ 'use strict'; diff --git a/RNTester/js/ExampleTypes.js b/RNTester/js/ExampleTypes.js index e747e43be9f940..4e42bf4cf3da78 100644 --- a/RNTester/js/ExampleTypes.js +++ b/RNTester/js/ExampleTypes.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ExampleTypes * @flow */ 'use strict'; diff --git a/RNTester/js/FlatListExample.js b/RNTester/js/FlatListExample.js index 9ec623fc86aadb..0c47ebc69f6870 100644 --- a/RNTester/js/FlatListExample.js +++ b/RNTester/js/FlatListExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule FlatListExample */ 'use strict'; diff --git a/RNTester/js/GeolocationExample.js b/RNTester/js/GeolocationExample.js index 1282673f0acb91..2cbd091f50f536 100644 --- a/RNTester/js/GeolocationExample.js +++ b/RNTester/js/GeolocationExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule GeolocationExample */ 'use strict'; diff --git a/RNTester/js/ImageCapInsetsExample.js b/RNTester/js/ImageCapInsetsExample.js index 645d002b9be457..97b407f08e1118 100644 --- a/RNTester/js/ImageCapInsetsExample.js +++ b/RNTester/js/ImageCapInsetsExample.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ImageCapInsetsExample * @flow */ 'use strict'; diff --git a/RNTester/js/ImageEditingExample.js b/RNTester/js/ImageEditingExample.js index d9defa775f5ae3..76bf871273a4df 100644 --- a/RNTester/js/ImageEditingExample.js +++ b/RNTester/js/ImageEditingExample.js @@ -5,5 +5,4 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule ImageEditingExample */ diff --git a/RNTester/js/ImageExample.js b/RNTester/js/ImageExample.js index 37f36b697de32a..65c6380509b239 100644 --- a/RNTester/js/ImageExample.js +++ b/RNTester/js/ImageExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule ImageExample */ 'use strict'; diff --git a/RNTester/js/InputAccessoryViewExample.js b/RNTester/js/InputAccessoryViewExample.js index 9287fb7e1e6833..45b63e20d9f5da 100644 --- a/RNTester/js/InputAccessoryViewExample.js +++ b/RNTester/js/InputAccessoryViewExample.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule InputAccessoryViewExample * @flow * @format */ diff --git a/RNTester/js/KeyboardAvoidingViewExample.js b/RNTester/js/KeyboardAvoidingViewExample.js index 3b52f3accbb760..3c84590822d621 100644 --- a/RNTester/js/KeyboardAvoidingViewExample.js +++ b/RNTester/js/KeyboardAvoidingViewExample.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule KeyboardAvoidingViewExample */ 'use strict'; diff --git a/RNTester/js/LayoutAnimationExample.js b/RNTester/js/LayoutAnimationExample.js index d815712bba4f0b..a62143d2b04ad1 100644 --- a/RNTester/js/LayoutAnimationExample.js +++ b/RNTester/js/LayoutAnimationExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule LayoutAnimationExample */ 'use strict'; diff --git a/RNTester/js/LayoutEventsExample.js b/RNTester/js/LayoutEventsExample.js index 37b9811d8d4080..b90bc27fd5ca92 100644 --- a/RNTester/js/LayoutEventsExample.js +++ b/RNTester/js/LayoutEventsExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule LayoutEventsExample */ 'use strict'; diff --git a/RNTester/js/LayoutExample.js b/RNTester/js/LayoutExample.js index eec0faa433d265..b6edcaef7297a1 100644 --- a/RNTester/js/LayoutExample.js +++ b/RNTester/js/LayoutExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule LayoutExample */ 'use strict'; diff --git a/RNTester/js/LinkingExample.js b/RNTester/js/LinkingExample.js index 52297f07cf8ed6..4ee6a27421b692 100644 --- a/RNTester/js/LinkingExample.js +++ b/RNTester/js/LinkingExample.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule LinkingExample */ 'use strict'; diff --git a/RNTester/js/ListExampleShared.js b/RNTester/js/ListExampleShared.js index 75ef6bb4b65cd4..2aab9716165734 100644 --- a/RNTester/js/ListExampleShared.js +++ b/RNTester/js/ListExampleShared.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule ListExampleShared */ 'use strict'; diff --git a/RNTester/js/ListViewExample.js b/RNTester/js/ListViewExample.js index ee828423618784..ea1e07bafe5e1d 100644 --- a/RNTester/js/ListViewExample.js +++ b/RNTester/js/ListViewExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule ListViewExample */ 'use strict'; diff --git a/RNTester/js/ListViewGridLayoutExample.js b/RNTester/js/ListViewGridLayoutExample.js index 636db62fccecb7..5f389596ea86fb 100644 --- a/RNTester/js/ListViewGridLayoutExample.js +++ b/RNTester/js/ListViewGridLayoutExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule ListViewGridLayoutExample */ 'use strict'; diff --git a/RNTester/js/ListViewPagingExample.js b/RNTester/js/ListViewPagingExample.js index 3d68e7ec54683c..88548ec0b98539 100644 --- a/RNTester/js/ListViewPagingExample.js +++ b/RNTester/js/ListViewPagingExample.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ListViewPagingExample * @flow */ 'use strict'; diff --git a/RNTester/js/MaskedViewExample.js b/RNTester/js/MaskedViewExample.js index cca734b53576a1..6548b7e4957004 100644 --- a/RNTester/js/MaskedViewExample.js +++ b/RNTester/js/MaskedViewExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule MaskedViewExample */ 'use strict'; diff --git a/RNTester/js/ModalExample.js b/RNTester/js/ModalExample.js index 12093f4d8f4e07..eba8a646cfc9a5 100644 --- a/RNTester/js/ModalExample.js +++ b/RNTester/js/ModalExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule ModalExample */ 'use strict'; diff --git a/RNTester/js/MultiColumnExample.js b/RNTester/js/MultiColumnExample.js index cc323cfcdad8c0..52fdaa2721d47c 100644 --- a/RNTester/js/MultiColumnExample.js +++ b/RNTester/js/MultiColumnExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule MultiColumnExample */ 'use strict'; diff --git a/RNTester/js/NativeAnimationsExample.js b/RNTester/js/NativeAnimationsExample.js index 5a6e5df55e84e2..52cb766c8aecec 100644 --- a/RNTester/js/NativeAnimationsExample.js +++ b/RNTester/js/NativeAnimationsExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule NativeAnimationsExample */ 'use strict'; diff --git a/RNTester/js/NavigatorIOSBarStyleExample.js b/RNTester/js/NavigatorIOSBarStyleExample.js index d9d53edd3c99a2..62e331e22f5ae1 100644 --- a/RNTester/js/NavigatorIOSBarStyleExample.js +++ b/RNTester/js/NavigatorIOSBarStyleExample.js @@ -16,7 +16,6 @@ * 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. * - * @providesModule NavigatorIOSBarStyleExample */ 'use strict'; diff --git a/RNTester/js/NavigatorIOSColorsExample.js b/RNTester/js/NavigatorIOSColorsExample.js index f34c9c9d10aff3..cdcf6edb7bbd1b 100644 --- a/RNTester/js/NavigatorIOSColorsExample.js +++ b/RNTester/js/NavigatorIOSColorsExample.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule NavigatorIOSColorsExample */ 'use strict'; diff --git a/RNTester/js/NavigatorIOSExample.js b/RNTester/js/NavigatorIOSExample.js index 79ee6f0fd07065..3712b7c4dba878 100644 --- a/RNTester/js/NavigatorIOSExample.js +++ b/RNTester/js/NavigatorIOSExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule NavigatorIOSExample */ 'use strict'; diff --git a/RNTester/js/NetInfoExample.js b/RNTester/js/NetInfoExample.js index 0ba8dd2ff8c895..b81251949dad34 100644 --- a/RNTester/js/NetInfoExample.js +++ b/RNTester/js/NetInfoExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule NetInfoExample */ 'use strict'; diff --git a/RNTester/js/OrientationChangeExample.js b/RNTester/js/OrientationChangeExample.js index af6f9b1feeca09..0c07d21a02b344 100644 --- a/RNTester/js/OrientationChangeExample.js +++ b/RNTester/js/OrientationChangeExample.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule OrientationChangeExample * @flow */ 'use strict'; diff --git a/RNTester/js/PanResponderExample.js b/RNTester/js/PanResponderExample.js index 27d9a8016677b4..598de1eac80cc6 100644 --- a/RNTester/js/PanResponderExample.js +++ b/RNTester/js/PanResponderExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow weak - * @providesModule PanResponderExample */ 'use strict'; diff --git a/RNTester/js/PermissionsExampleAndroid.android.js b/RNTester/js/PermissionsExampleAndroid.android.js index cb837183a6295d..322307f32706af 100644 --- a/RNTester/js/PermissionsExampleAndroid.android.js +++ b/RNTester/js/PermissionsExampleAndroid.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule PermissionsExampleAndroid * @flow */ 'use strict'; diff --git a/RNTester/js/PickerExample.js b/RNTester/js/PickerExample.js index 1a1005cdaa2d03..4bd2fd2c362211 100644 --- a/RNTester/js/PickerExample.js +++ b/RNTester/js/PickerExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule PickerExample */ 'use strict'; diff --git a/RNTester/js/PickerIOSExample.js b/RNTester/js/PickerIOSExample.js index a4d5de63a046c7..4202fd517e50ca 100644 --- a/RNTester/js/PickerIOSExample.js +++ b/RNTester/js/PickerIOSExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule PickerIOSExample */ 'use strict'; diff --git a/RNTester/js/PointerEventsExample.js b/RNTester/js/PointerEventsExample.js index ac15811c96ddf7..1fc85702a38d4b 100644 --- a/RNTester/js/PointerEventsExample.js +++ b/RNTester/js/PointerEventsExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule PointerEventsExample */ 'use strict'; diff --git a/RNTester/js/ProgressBarAndroidExample.android.js b/RNTester/js/ProgressBarAndroidExample.android.js index baa75b9ff1e6d2..1d55779d5780c1 100644 --- a/RNTester/js/ProgressBarAndroidExample.android.js +++ b/RNTester/js/ProgressBarAndroidExample.android.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule ProgressBarAndroidExample */ 'use strict'; diff --git a/RNTester/js/ProgressViewIOSExample.js b/RNTester/js/ProgressViewIOSExample.js index d0641760965c6a..821fe2e2520ed4 100644 --- a/RNTester/js/ProgressViewIOSExample.js +++ b/RNTester/js/ProgressViewIOSExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule ProgressViewIOSExample */ 'use strict'; diff --git a/RNTester/js/PushNotificationIOSExample.js b/RNTester/js/PushNotificationIOSExample.js index c2368e9a782b14..b2c54165a1c504 100644 --- a/RNTester/js/PushNotificationIOSExample.js +++ b/RNTester/js/PushNotificationIOSExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule PushNotificationIOSExample */ 'use strict'; diff --git a/RNTester/js/RCTRootViewIOSExample.js b/RNTester/js/RCTRootViewIOSExample.js index f6b3b20536efa4..5eba0e8cae70e7 100644 --- a/RNTester/js/RCTRootViewIOSExample.js +++ b/RNTester/js/RCTRootViewIOSExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule RCTRootViewIOSExample */ 'use strict'; diff --git a/RNTester/js/RNTesterActions.js b/RNTester/js/RNTesterActions.js index 2bf967b3c2e66b..cc89277dcf9cb2 100644 --- a/RNTester/js/RNTesterActions.js +++ b/RNTester/js/RNTesterActions.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule RNTesterActions */ 'use strict'; diff --git a/RNTester/js/RNTesterApp.android.js b/RNTester/js/RNTesterApp.android.js index d5f05d12a90a3c..ad377b85a54fcc 100644 --- a/RNTester/js/RNTesterApp.android.js +++ b/RNTester/js/RNTesterApp.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule RNTesterApp * @flow */ 'use strict'; diff --git a/RNTester/js/RNTesterApp.ios.js b/RNTester/js/RNTesterApp.ios.js index 26ee1ebbdd976d..a72ebb724edb32 100644 --- a/RNTester/js/RNTesterApp.ios.js +++ b/RNTester/js/RNTesterApp.ios.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule RNTesterApp * @flow */ 'use strict'; diff --git a/RNTester/js/RNTesterBlock.js b/RNTester/js/RNTesterBlock.js index 58ca4d0a5f0c03..fa3c44f7873bed 100644 --- a/RNTester/js/RNTesterBlock.js +++ b/RNTester/js/RNTesterBlock.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule RNTesterBlock * @flow */ 'use strict'; diff --git a/RNTester/js/RNTesterButton.js b/RNTester/js/RNTesterButton.js index 835eb9db113edd..9ac5f6e8e81832 100644 --- a/RNTester/js/RNTesterButton.js +++ b/RNTester/js/RNTesterButton.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule RNTesterButton */ 'use strict'; diff --git a/RNTester/js/RNTesterExampleContainer.js b/RNTester/js/RNTesterExampleContainer.js index e5d1ab816d1dcb..02e010771f45f4 100644 --- a/RNTester/js/RNTesterExampleContainer.js +++ b/RNTester/js/RNTesterExampleContainer.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule RNTesterExampleContainer */ 'use strict'; diff --git a/RNTester/js/RNTesterExampleList.js b/RNTester/js/RNTesterExampleList.js index e043e2d5cba1d2..c7d974c48409ac 100644 --- a/RNTester/js/RNTesterExampleList.js +++ b/RNTester/js/RNTesterExampleList.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule RNTesterExampleList */ 'use strict'; diff --git a/RNTester/js/RNTesterList.android.js b/RNTester/js/RNTesterList.android.js index feea07f72cdb85..d038354b25c7d7 100644 --- a/RNTester/js/RNTesterList.android.js +++ b/RNTester/js/RNTesterList.android.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule RNTesterList */ 'use strict'; diff --git a/RNTester/js/RNTesterList.ios.js b/RNTester/js/RNTesterList.ios.js index fa95044d77dd49..812abde4fe7192 100644 --- a/RNTester/js/RNTesterList.ios.js +++ b/RNTester/js/RNTesterList.ios.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule RNTesterList */ 'use strict'; diff --git a/RNTester/js/RNTesterNavigationReducer.js b/RNTester/js/RNTesterNavigationReducer.js index c8ffa5a5fe7c00..60c21a7106a244 100644 --- a/RNTester/js/RNTesterNavigationReducer.js +++ b/RNTester/js/RNTesterNavigationReducer.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule RNTesterNavigationReducer */ 'use strict'; diff --git a/RNTester/js/RNTesterPage.js b/RNTester/js/RNTesterPage.js index 96b016a00000fb..4af103ea816651 100644 --- a/RNTester/js/RNTesterPage.js +++ b/RNTester/js/RNTesterPage.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule RNTesterPage * @flow */ 'use strict'; diff --git a/RNTester/js/RNTesterSettingSwitchRow.js b/RNTester/js/RNTesterSettingSwitchRow.js index 97d2f8d60be40a..01cca6336c9e5b 100644 --- a/RNTester/js/RNTesterSettingSwitchRow.js +++ b/RNTester/js/RNTesterSettingSwitchRow.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule RNTesterSettingSwitchRow * @flow */ 'use strict'; diff --git a/RNTester/js/RNTesterStatePersister.js b/RNTester/js/RNTesterStatePersister.js index 310386c49bb7f4..455f429225a78e 100644 --- a/RNTester/js/RNTesterStatePersister.js +++ b/RNTester/js/RNTesterStatePersister.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule RNTesterStatePersister */ 'use strict'; diff --git a/RNTester/js/RNTesterTitle.js b/RNTester/js/RNTesterTitle.js index 9afd68a66a7c05..17687d98bd8f78 100644 --- a/RNTester/js/RNTesterTitle.js +++ b/RNTester/js/RNTesterTitle.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule RNTesterTitle * @flow */ 'use strict'; diff --git a/RNTester/js/RTLExample.js b/RNTester/js/RTLExample.js index aad38a9fedc9df..67120d06bb2df3 100644 --- a/RNTester/js/RTLExample.js +++ b/RNTester/js/RTLExample.js @@ -6,7 +6,6 @@ * * @flow * @format - * @providesModule RTLExample */ 'use strict'; diff --git a/RNTester/js/RefreshControlExample.js b/RNTester/js/RefreshControlExample.js index 7962a457e29bc0..055a85c5f64413 100644 --- a/RNTester/js/RefreshControlExample.js +++ b/RNTester/js/RefreshControlExample.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule RefreshControlExample */ 'use strict'; diff --git a/RNTester/js/RootViewSizeFlexibilityExampleApp.js b/RNTester/js/RootViewSizeFlexibilityExampleApp.js index 066a6d425e926b..c08a2ec578d510 100644 --- a/RNTester/js/RootViewSizeFlexibilityExampleApp.js +++ b/RNTester/js/RootViewSizeFlexibilityExampleApp.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule RootViewSizeFlexibilityExampleApp */ 'use strict'; diff --git a/RNTester/js/SafeAreaViewExample.js b/RNTester/js/SafeAreaViewExample.js index c3d5a99f8208e6..927a26651a4f8f 100644 --- a/RNTester/js/SafeAreaViewExample.js +++ b/RNTester/js/SafeAreaViewExample.js @@ -6,7 +6,6 @@ * * @flow * @format - * @providesModule SafeAreaViewExample */ 'use strict'; diff --git a/RNTester/js/ScrollViewExample.js b/RNTester/js/ScrollViewExample.js index 66bedc93552c7c..c1d634b8ebf598 100644 --- a/RNTester/js/ScrollViewExample.js +++ b/RNTester/js/ScrollViewExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule ScrollViewExample * @format */ 'use strict'; diff --git a/RNTester/js/ScrollViewSimpleExample.js b/RNTester/js/ScrollViewSimpleExample.js index 0a6713122a885d..a4fc25fe14e205 100644 --- a/RNTester/js/ScrollViewSimpleExample.js +++ b/RNTester/js/ScrollViewSimpleExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule ScrollViewSimpleExample */ 'use strict'; diff --git a/RNTester/js/SectionListExample.js b/RNTester/js/SectionListExample.js index 920be1768644fd..5410251853ed1d 100644 --- a/RNTester/js/SectionListExample.js +++ b/RNTester/js/SectionListExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule SectionListExample */ 'use strict'; diff --git a/RNTester/js/SegmentedControlIOSExample.js b/RNTester/js/SegmentedControlIOSExample.js index c5441e7cc4dc87..c0098b5fafd4ff 100644 --- a/RNTester/js/SegmentedControlIOSExample.js +++ b/RNTester/js/SegmentedControlIOSExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule SegmentedControlIOSExample */ 'use strict'; diff --git a/RNTester/js/SetPropertiesExampleApp.js b/RNTester/js/SetPropertiesExampleApp.js index 8113f5279570db..95034438b0a1be 100644 --- a/RNTester/js/SetPropertiesExampleApp.js +++ b/RNTester/js/SetPropertiesExampleApp.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule SetPropertiesExampleApp */ 'use strict'; diff --git a/RNTester/js/ShareExample.js b/RNTester/js/ShareExample.js index 00d3330d83c27c..7df3edd360f7e1 100644 --- a/RNTester/js/ShareExample.js +++ b/RNTester/js/ShareExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule ShareExample */ 'use strict'; diff --git a/RNTester/js/SliderExample.js b/RNTester/js/SliderExample.js index 3b4980ac800488..b05877572e7058 100644 --- a/RNTester/js/SliderExample.js +++ b/RNTester/js/SliderExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule SliderExample */ 'use strict'; diff --git a/RNTester/js/SnapshotExample.js b/RNTester/js/SnapshotExample.js index 160434b53b260b..f77277a53cbf32 100644 --- a/RNTester/js/SnapshotExample.js +++ b/RNTester/js/SnapshotExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule SnapshotExample * @format */ 'use strict'; diff --git a/RNTester/js/StatusBarExample.js b/RNTester/js/StatusBarExample.js index e5dae5c77c49c2..b9949c17cce151 100644 --- a/RNTester/js/StatusBarExample.js +++ b/RNTester/js/StatusBarExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule StatusBarExample */ 'use strict'; diff --git a/RNTester/js/SwipeableFlatListExample.js b/RNTester/js/SwipeableFlatListExample.js index 432e6d813d5053..4c8716e8c838a3 100644 --- a/RNTester/js/SwipeableFlatListExample.js +++ b/RNTester/js/SwipeableFlatListExample.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule SwipeableFlatListExample * @flow * @format */ diff --git a/RNTester/js/SwipeableListViewExample.js b/RNTester/js/SwipeableListViewExample.js index c004f86e3e6aad..db91633962cf39 100644 --- a/RNTester/js/SwipeableListViewExample.js +++ b/RNTester/js/SwipeableListViewExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule SwipeableListViewExample */ 'use strict'; diff --git a/RNTester/js/SwitchExample.js b/RNTester/js/SwitchExample.js index ca721ce4488e6c..e040c76a1c79cf 100644 --- a/RNTester/js/SwitchExample.js +++ b/RNTester/js/SwitchExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule SwitchExample */ 'use strict'; diff --git a/RNTester/js/TVEventHandlerExample.js b/RNTester/js/TVEventHandlerExample.js index bc6346d0d2b04f..84067863268c18 100644 --- a/RNTester/js/TVEventHandlerExample.js +++ b/RNTester/js/TVEventHandlerExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule TVEventHandlerExample */ 'use strict'; diff --git a/RNTester/js/TabBarIOSBarStyleExample.js b/RNTester/js/TabBarIOSBarStyleExample.js index 5c42c5ccf1ef11..972235698133bf 100644 --- a/RNTester/js/TabBarIOSBarStyleExample.js +++ b/RNTester/js/TabBarIOSBarStyleExample.js @@ -16,7 +16,6 @@ * 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. * - * @providesModule TabBarIOSBarStyleExample * @flow */ diff --git a/RNTester/js/TabBarIOSExample.js b/RNTester/js/TabBarIOSExample.js index 82c47cccdfe2f3..12906b0e176ef6 100644 --- a/RNTester/js/TabBarIOSExample.js +++ b/RNTester/js/TabBarIOSExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule TabBarIOSExample */ 'use strict'; diff --git a/RNTester/js/TextExample.android.js b/RNTester/js/TextExample.android.js index b912337827a279..6f824e01132efe 100644 --- a/RNTester/js/TextExample.android.js +++ b/RNTester/js/TextExample.android.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule TextExample */ 'use strict'; diff --git a/RNTester/js/TextExample.ios.js b/RNTester/js/TextExample.ios.js index 939774aa06a0f6..968e0a42c8f8af 100644 --- a/RNTester/js/TextExample.ios.js +++ b/RNTester/js/TextExample.ios.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule TextExample */ 'use strict'; diff --git a/RNTester/js/TextInputExample.android.js b/RNTester/js/TextInputExample.android.js index 358d3fd043b02d..f0b3403d618f9f 100644 --- a/RNTester/js/TextInputExample.android.js +++ b/RNTester/js/TextInputExample.android.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule TextInputExample */ 'use strict'; diff --git a/RNTester/js/TextInputExample.ios.js b/RNTester/js/TextInputExample.ios.js index 9ace0a94ae6fab..fdcddc1f793dda 100644 --- a/RNTester/js/TextInputExample.ios.js +++ b/RNTester/js/TextInputExample.ios.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule TextInputExample */ 'use strict'; diff --git a/RNTester/js/TimePickerAndroidExample.js b/RNTester/js/TimePickerAndroidExample.js index 7e1afa6367d7d1..517f674665acc7 100644 --- a/RNTester/js/TimePickerAndroidExample.js +++ b/RNTester/js/TimePickerAndroidExample.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TimePickerAndroidExample */ 'use strict'; diff --git a/RNTester/js/TimerExample.js b/RNTester/js/TimerExample.js index d7e966010f9ada..a56fd5ad3fe06f 100644 --- a/RNTester/js/TimerExample.js +++ b/RNTester/js/TimerExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule TimerExample */ 'use strict'; diff --git a/RNTester/js/ToastAndroidExample.android.js b/RNTester/js/ToastAndroidExample.android.js index e86a21cb83ef3b..6ca7b9c4f8b78b 100644 --- a/RNTester/js/ToastAndroidExample.android.js +++ b/RNTester/js/ToastAndroidExample.android.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule ToastAndroidExample */ 'use strict'; diff --git a/RNTester/js/ToolbarAndroidExample.android.js b/RNTester/js/ToolbarAndroidExample.android.js index e197518704740f..7a17105698c4c8 100644 --- a/RNTester/js/ToolbarAndroidExample.android.js +++ b/RNTester/js/ToolbarAndroidExample.android.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule ToolbarAndroidExample */ 'use strict'; diff --git a/RNTester/js/ToolbarAndroidExample.ios.js b/RNTester/js/ToolbarAndroidExample.ios.js index b2553dc1b2bc9f..5e8c57f7a81dce 100644 --- a/RNTester/js/ToolbarAndroidExample.ios.js +++ b/RNTester/js/ToolbarAndroidExample.ios.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule ToolbarAndroidExample */ 'use strict'; diff --git a/RNTester/js/TouchableExample.js b/RNTester/js/TouchableExample.js index e0c227d9ca3f7f..069dff9d26c0c2 100644 --- a/RNTester/js/TouchableExample.js +++ b/RNTester/js/TouchableExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule TouchableExample */ 'use strict'; diff --git a/RNTester/js/TransformExample.js b/RNTester/js/TransformExample.js index 17e2a89fc98d26..4271e074a0179b 100644 --- a/RNTester/js/TransformExample.js +++ b/RNTester/js/TransformExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule TransformExample */ 'use strict'; diff --git a/RNTester/js/TransparentHitTestExample.js b/RNTester/js/TransparentHitTestExample.js index 89db856a473500..e1baa00964ed6b 100644 --- a/RNTester/js/TransparentHitTestExample.js +++ b/RNTester/js/TransparentHitTestExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule TransparentHitTestExample */ 'use strict'; diff --git a/RNTester/js/URIActionMap.js b/RNTester/js/URIActionMap.js index fb47214aadd5c0..f303fa21a499b3 100644 --- a/RNTester/js/URIActionMap.js +++ b/RNTester/js/URIActionMap.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule URIActionMap */ 'use strict'; diff --git a/RNTester/js/VibrationExample.js b/RNTester/js/VibrationExample.js index 9e6d6d7d768b8a..a213799902f81c 100644 --- a/RNTester/js/VibrationExample.js +++ b/RNTester/js/VibrationExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule VibrationExample */ 'use strict'; diff --git a/RNTester/js/VibrationIOSExample.js b/RNTester/js/VibrationIOSExample.js index 9093ff87af28ce..5f642519da1889 100644 --- a/RNTester/js/VibrationIOSExample.js +++ b/RNTester/js/VibrationIOSExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule VibrationIOSExample */ 'use strict'; diff --git a/RNTester/js/ViewExample.js b/RNTester/js/ViewExample.js index b4c4a6c2a65818..5d643a12fa0986 100644 --- a/RNTester/js/ViewExample.js +++ b/RNTester/js/ViewExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule ViewExample */ 'use strict'; diff --git a/RNTester/js/ViewPagerAndroidExample.android.js b/RNTester/js/ViewPagerAndroidExample.android.js index 1f2ac75d8f22eb..1c5da99bae641e 100644 --- a/RNTester/js/ViewPagerAndroidExample.android.js +++ b/RNTester/js/ViewPagerAndroidExample.android.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ViewPagerAndroidExample */ 'use strict'; diff --git a/RNTester/js/WebSocketExample.js b/RNTester/js/WebSocketExample.js index ad4a6f8be4719a..b1cffe3e5dc6d4 100644 --- a/RNTester/js/WebSocketExample.js +++ b/RNTester/js/WebSocketExample.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule WebSocketExample * @format */ 'use strict'; diff --git a/RNTester/js/WebViewExample.js b/RNTester/js/WebViewExample.js index d3bc575361e5fd..d55d17ca60ec9b 100644 --- a/RNTester/js/WebViewExample.js +++ b/RNTester/js/WebViewExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule WebViewExample */ 'use strict'; diff --git a/RNTester/js/XHRExample.js b/RNTester/js/XHRExample.js index 1ee8315d03ba67..fc7cb8c213768e 100644 --- a/RNTester/js/XHRExample.js +++ b/RNTester/js/XHRExample.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule XHRExample */ 'use strict'; diff --git a/RNTester/js/XHRExampleBinaryUpload.js b/RNTester/js/XHRExampleBinaryUpload.js index e5635724378683..efe96dea0f2232 100644 --- a/RNTester/js/XHRExampleBinaryUpload.js +++ b/RNTester/js/XHRExampleBinaryUpload.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule XHRExampleBinaryUpload */ 'use strict'; diff --git a/RNTester/js/XHRExampleCookies.js b/RNTester/js/XHRExampleCookies.js index 08ff72b369cb22..2050f555eb91d5 100644 --- a/RNTester/js/XHRExampleCookies.js +++ b/RNTester/js/XHRExampleCookies.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule XHRExampleCookies */ 'use strict'; diff --git a/RNTester/js/XHRExampleDownload.js b/RNTester/js/XHRExampleDownload.js index a419f9ba539ed2..2ffe801fbcc16d 100644 --- a/RNTester/js/XHRExampleDownload.js +++ b/RNTester/js/XHRExampleDownload.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule XHRExampleDownload */ 'use strict'; diff --git a/RNTester/js/XHRExampleFetch.js b/RNTester/js/XHRExampleFetch.js index 2aea3be975f4fb..c4915ce5677a52 100644 --- a/RNTester/js/XHRExampleFetch.js +++ b/RNTester/js/XHRExampleFetch.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule XHRExampleFetch */ 'use strict'; diff --git a/RNTester/js/XHRExampleFormData.js b/RNTester/js/XHRExampleFormData.js index 228af6345bd4a0..8c0080ea11b773 100644 --- a/RNTester/js/XHRExampleFormData.js +++ b/RNTester/js/XHRExampleFormData.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule XHRExampleFormData */ 'use strict'; diff --git a/RNTester/js/XHRExampleHeaders.js b/RNTester/js/XHRExampleHeaders.js index 8476b1600ef670..b3dc69edc21a23 100644 --- a/RNTester/js/XHRExampleHeaders.js +++ b/RNTester/js/XHRExampleHeaders.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @noflow - * @providesModule XHRExampleHeaders */ 'use strict'; diff --git a/RNTester/js/XHRExampleOnTimeOut.js b/RNTester/js/XHRExampleOnTimeOut.js index d3c50025c2d0fe..1afb3990420117 100644 --- a/RNTester/js/XHRExampleOnTimeOut.js +++ b/RNTester/js/XHRExampleOnTimeOut.js @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule XHRExampleOnTimeOut */ 'use strict'; diff --git a/RNTester/js/createExamplePage.js b/RNTester/js/createExamplePage.js index e381f05b8d2c54..1ae3733b969ac1 100644 --- a/RNTester/js/createExamplePage.js +++ b/RNTester/js/createExamplePage.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule createExamplePage * @flow */ 'use strict'; diff --git a/RNTester/js/http_test_server.js b/RNTester/js/http_test_server.js index cd9e18e5407d7f..998d73dbf19455 100755 --- a/RNTester/js/http_test_server.js +++ b/RNTester/js/http_test_server.js @@ -6,7 +6,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule http_test_server */ 'use strict'; diff --git a/RNTester/js/websocket_test_server.js b/RNTester/js/websocket_test_server.js index 83a48ed213f062..3f3a23cfa04c98 100755 --- a/RNTester/js/websocket_test_server.js +++ b/RNTester/js/websocket_test_server.js @@ -6,7 +6,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule websocket_test_server */ 'use strict'; diff --git a/ReactAndroid/src/androidTest/js/Asserts.js b/ReactAndroid/src/androidTest/js/Asserts.js index 0cebeea419d20d..95fd89f272d168 100644 --- a/ReactAndroid/src/androidTest/js/Asserts.js +++ b/ReactAndroid/src/androidTest/js/Asserts.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule Asserts */ 'use strict'; diff --git a/ReactAndroid/src/androidTest/js/CatalystRootViewTestModule.js b/ReactAndroid/src/androidTest/js/CatalystRootViewTestModule.js index 33f0592a4832ef..b0e5571b277a18 100644 --- a/ReactAndroid/src/androidTest/js/CatalystRootViewTestModule.js +++ b/ReactAndroid/src/androidTest/js/CatalystRootViewTestModule.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule CatalystRootViewTestModule */ 'use strict'; diff --git a/ReactAndroid/src/androidTest/js/DatePickerDialogTestModule.js b/ReactAndroid/src/androidTest/js/DatePickerDialogTestModule.js index 0cd5685820cacc..4ba296cc757a6c 100644 --- a/ReactAndroid/src/androidTest/js/DatePickerDialogTestModule.js +++ b/ReactAndroid/src/androidTest/js/DatePickerDialogTestModule.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule DatePickerDialogTestModule */ 'use strict'; diff --git a/ReactAndroid/src/androidTest/js/InitialPropsTestApp.js b/ReactAndroid/src/androidTest/js/InitialPropsTestApp.js index 173ef647f48267..002ebf0cc68b66 100644 --- a/ReactAndroid/src/androidTest/js/InitialPropsTestApp.js +++ b/ReactAndroid/src/androidTest/js/InitialPropsTestApp.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule InitialPropsTestApp */ 'use strict'; diff --git a/ReactAndroid/src/androidTest/js/JSResponderTestApp.js b/ReactAndroid/src/androidTest/js/JSResponderTestApp.js index 50612afb9e2e91..d6e7f878defb1f 100644 --- a/ReactAndroid/src/androidTest/js/JSResponderTestApp.js +++ b/ReactAndroid/src/androidTest/js/JSResponderTestApp.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule JSResponderTestApp */ 'use strict'; diff --git a/ReactAndroid/src/androidTest/js/LayoutEventsTestApp.js b/ReactAndroid/src/androidTest/js/LayoutEventsTestApp.js index d9ecf2ca1b54e7..153089437e4c9f 100644 --- a/ReactAndroid/src/androidTest/js/LayoutEventsTestApp.js +++ b/ReactAndroid/src/androidTest/js/LayoutEventsTestApp.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule LayoutEventsTestApp */ 'use strict'; diff --git a/ReactAndroid/src/androidTest/js/MeasureLayoutTestModule.js b/ReactAndroid/src/androidTest/js/MeasureLayoutTestModule.js index 92ac114b6cc7fd..baf4f7bc03ba3b 100644 --- a/ReactAndroid/src/androidTest/js/MeasureLayoutTestModule.js +++ b/ReactAndroid/src/androidTest/js/MeasureLayoutTestModule.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule MeasureLayoutTestModule */ 'use strict'; diff --git a/ReactAndroid/src/androidTest/js/MultitouchHandlingTestAppModule.js b/ReactAndroid/src/androidTest/js/MultitouchHandlingTestAppModule.js index 7daa884359fa9a..0c591483f6c129 100644 --- a/ReactAndroid/src/androidTest/js/MultitouchHandlingTestAppModule.js +++ b/ReactAndroid/src/androidTest/js/MultitouchHandlingTestAppModule.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule MultitouchHandlingTestAppModule */ 'use strict'; diff --git a/ReactAndroid/src/androidTest/js/NativeIdTestModule.js b/ReactAndroid/src/androidTest/js/NativeIdTestModule.js index 2e1acad3422756..be457b3c569922 100644 --- a/ReactAndroid/src/androidTest/js/NativeIdTestModule.js +++ b/ReactAndroid/src/androidTest/js/NativeIdTestModule.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule NativeIdTestModule * @flow */ diff --git a/ReactAndroid/src/androidTest/js/PickerAndroidTestModule.js b/ReactAndroid/src/androidTest/js/PickerAndroidTestModule.js index 0f7255d1564089..237dacba21bf43 100644 --- a/ReactAndroid/src/androidTest/js/PickerAndroidTestModule.js +++ b/ReactAndroid/src/androidTest/js/PickerAndroidTestModule.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule PickerAndroidTestModule */ 'use strict'; diff --git a/ReactAndroid/src/androidTest/js/ProgressBarTestModule.js b/ReactAndroid/src/androidTest/js/ProgressBarTestModule.js index bd466144c522d7..a6e3849e0d238b 100644 --- a/ReactAndroid/src/androidTest/js/ProgressBarTestModule.js +++ b/ReactAndroid/src/androidTest/js/ProgressBarTestModule.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ProgressBarTestModule */ 'use strict'; diff --git a/ReactAndroid/src/androidTest/js/ScrollViewTestModule.js b/ReactAndroid/src/androidTest/js/ScrollViewTestModule.js index 24371b0f76570c..7654f106087a27 100644 --- a/ReactAndroid/src/androidTest/js/ScrollViewTestModule.js +++ b/ReactAndroid/src/androidTest/js/ScrollViewTestModule.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ScrollViewTestModule */ 'use strict'; diff --git a/ReactAndroid/src/androidTest/js/ShareTestModule.js b/ReactAndroid/src/androidTest/js/ShareTestModule.js index f7311f656041e9..dd0f7fc9646d13 100644 --- a/ReactAndroid/src/androidTest/js/ShareTestModule.js +++ b/ReactAndroid/src/androidTest/js/ShareTestModule.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ShareTestModule */ 'use strict'; diff --git a/ReactAndroid/src/androidTest/js/SubviewsClippingTestModule.js b/ReactAndroid/src/androidTest/js/SubviewsClippingTestModule.js index 70fa837eed6b7a..859acfc92c6ab9 100644 --- a/ReactAndroid/src/androidTest/js/SubviewsClippingTestModule.js +++ b/ReactAndroid/src/androidTest/js/SubviewsClippingTestModule.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule SubviewsClippingTestModule */ 'use strict'; diff --git a/ReactAndroid/src/androidTest/js/SwipeRefreshLayoutTestModule.js b/ReactAndroid/src/androidTest/js/SwipeRefreshLayoutTestModule.js index 277a768e9430f4..5a126772ef56e0 100644 --- a/ReactAndroid/src/androidTest/js/SwipeRefreshLayoutTestModule.js +++ b/ReactAndroid/src/androidTest/js/SwipeRefreshLayoutTestModule.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule SwipeRefreshLayoutTestModule */ 'use strict'; diff --git a/ReactAndroid/src/androidTest/js/TestBundle.js b/ReactAndroid/src/androidTest/js/TestBundle.js index 21fd06247e415f..64d2c57d26f3b6 100644 --- a/ReactAndroid/src/androidTest/js/TestBundle.js +++ b/ReactAndroid/src/androidTest/js/TestBundle.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TestBundle */ 'use strict'; diff --git a/ReactAndroid/src/androidTest/js/TestIdTestModule.js b/ReactAndroid/src/androidTest/js/TestIdTestModule.js index eee76fbc05c00c..0320f3cf8be7e9 100644 --- a/ReactAndroid/src/androidTest/js/TestIdTestModule.js +++ b/ReactAndroid/src/androidTest/js/TestIdTestModule.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TestIdTestModule */ 'use strict'; diff --git a/ReactAndroid/src/androidTest/js/TestJSLocaleModule.js b/ReactAndroid/src/androidTest/js/TestJSLocaleModule.js index be6bfc12a3a208..a9aca7983d231f 100644 --- a/ReactAndroid/src/androidTest/js/TestJSLocaleModule.js +++ b/ReactAndroid/src/androidTest/js/TestJSLocaleModule.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TestJSLocaleModule */ 'use strict'; diff --git a/ReactAndroid/src/androidTest/js/TestJSToJavaParametersModule.js b/ReactAndroid/src/androidTest/js/TestJSToJavaParametersModule.js index bc526e7722ba2d..5e5527846ae0ef 100644 --- a/ReactAndroid/src/androidTest/js/TestJSToJavaParametersModule.js +++ b/ReactAndroid/src/androidTest/js/TestJSToJavaParametersModule.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TestJSToJavaParametersModule */ 'use strict'; diff --git a/ReactAndroid/src/androidTest/js/TestJavaToJSArgumentsModule.js b/ReactAndroid/src/androidTest/js/TestJavaToJSArgumentsModule.js index b5abe26a8eeb57..6e71061666bf00 100644 --- a/ReactAndroid/src/androidTest/js/TestJavaToJSArgumentsModule.js +++ b/ReactAndroid/src/androidTest/js/TestJavaToJSArgumentsModule.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TestJavaToJSArgumentsModule */ 'use strict'; diff --git a/ReactAndroid/src/androidTest/js/TestJavaToJSReturnValuesModule.js b/ReactAndroid/src/androidTest/js/TestJavaToJSReturnValuesModule.js index 135816a5c9d659..1aa72f0b85727f 100644 --- a/ReactAndroid/src/androidTest/js/TestJavaToJSReturnValuesModule.js +++ b/ReactAndroid/src/androidTest/js/TestJavaToJSReturnValuesModule.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TestJavaToJSReturnValuesModule */ 'use strict'; diff --git a/ReactAndroid/src/androidTest/js/TextInputTestModule.js b/ReactAndroid/src/androidTest/js/TextInputTestModule.js index 94593a3ab71449..fff1fc5bca68c7 100644 --- a/ReactAndroid/src/androidTest/js/TextInputTestModule.js +++ b/ReactAndroid/src/androidTest/js/TextInputTestModule.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TextInputTestModule */ 'use strict'; diff --git a/ReactAndroid/src/androidTest/js/TimePickerDialogTestModule.js b/ReactAndroid/src/androidTest/js/TimePickerDialogTestModule.js index ebf8cdb4f1271a..80e355c951ec70 100644 --- a/ReactAndroid/src/androidTest/js/TimePickerDialogTestModule.js +++ b/ReactAndroid/src/androidTest/js/TimePickerDialogTestModule.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TimePickerDialogTestModule */ 'use strict'; diff --git a/ReactAndroid/src/androidTest/js/TouchBubblingTestAppModule.js b/ReactAndroid/src/androidTest/js/TouchBubblingTestAppModule.js index cd8bcb51c52842..6f8e6226ad5815 100644 --- a/ReactAndroid/src/androidTest/js/TouchBubblingTestAppModule.js +++ b/ReactAndroid/src/androidTest/js/TouchBubblingTestAppModule.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule TouchBubblingTestAppModule */ 'use strict'; diff --git a/ReactAndroid/src/androidTest/js/UIManagerTestModule.js b/ReactAndroid/src/androidTest/js/UIManagerTestModule.js index 5c976ce76dc3f9..93f73d44c0d67c 100644 --- a/ReactAndroid/src/androidTest/js/UIManagerTestModule.js +++ b/ReactAndroid/src/androidTest/js/UIManagerTestModule.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule UIManagerTestModule */ 'use strict'; diff --git a/ReactAndroid/src/androidTest/js/ViewRenderingTestModule.js b/ReactAndroid/src/androidTest/js/ViewRenderingTestModule.js index 36d9328c93e209..0ddaa86f07e9da 100644 --- a/ReactAndroid/src/androidTest/js/ViewRenderingTestModule.js +++ b/ReactAndroid/src/androidTest/js/ViewRenderingTestModule.js @@ -4,7 +4,6 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @providesModule ViewRenderingTestModule */ 'use strict'; diff --git a/jest/hasteImpl.js b/jest/hasteImpl.js new file mode 100644 index 00000000000000..cb5ac4a049c4f6 --- /dev/null +++ b/jest/hasteImpl.js @@ -0,0 +1,75 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * + * 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 path = require('path'); + +const ROOT = path.join(__dirname, '..'); + +const BLACKLISTED_PATTERNS/*: Array*/ = [ + /.*\/__(mocks|tests)__\/.*/, + /^Libraries\/Animated\/src\/polyfills\/.*/, +]; + +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 .android/.ios/.native/.web suffix + [/^(.*)\.(android|ios|native|web)$/, '$1'], +]; + +const haste = { + /* + * @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; + }, +}; + +function isHastePath(filePath/*: string*/)/*: bool*/ { + if (!filePath.endsWith('.js') && !filePath.endsWith('.js.flow')) { + return false; + } + + if (!filePath.startsWith(ROOT)) { + return false; + } + + filePath = filePath.substr(ROOT.length + 1); + if (BLACKLISTED_PATTERNS.some(pattern => pattern.test(filePath))) { + return false; + } + return WHITELISTED_PREFIXES.some(prefix => filePath.startsWith(prefix)); +} + +module.exports = haste; diff --git a/local-cli/core/index.js b/local-cli/core/index.js index e5f2ba33af6b37..f3059be0a62748 100644 --- a/local-cli/core/index.js +++ b/local-cli/core/index.js @@ -68,6 +68,8 @@ const pluginPlatforms = plugins const defaultRNConfig = { + hasteImplModulePath: require.resolve('../../jest/hasteImpl'), + getProjectCommands(): Array { const commands = plugins .commands diff --git a/package.json b/package.json index ced5fcabbd6381..d951833578883f 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ ], "haste": { "defaultPlatform": "ios", + "hasteImplModulePath": "/jest/hasteImpl.js", "providesModuleNodeModules": [ "react-native" ], From c6b96c0df789717d53ec520ad28ba0ae00db6ec2 Mon Sep 17 00:00:00 2001 From: Jean Lauliac Date: Wed, 25 Apr 2018 07:03:24 -0700 Subject: [PATCH 0373/1109] react-native-github: remove old fs mock implementation Reviewed By: rafeca Differential Revision: D7652914 fbshipit-source-id: 5494305750e7616b5120169266c519f460ae7e6d --- local-cli/__mocks__/fs.js | 437 +----------------- local-cli/__tests__/fs-mock-test.js | 89 ---- .../link/__tests__/ios/writePlist.spec.js | 3 + package.json | 1 + 4 files changed, 26 insertions(+), 504 deletions(-) delete mode 100644 local-cli/__tests__/fs-mock-test.js diff --git a/local-cli/__mocks__/fs.js b/local-cli/__mocks__/fs.js index bd4d5c10001c8e..0ac81ced62db0e 100644 --- a/local-cli/__mocks__/fs.js +++ b/local-cli/__mocks__/fs.js @@ -9,428 +9,35 @@ 'use strict'; -const asyncify = require('async/asyncify'); -const {EventEmitter} = require('events'); -const {dirname} = require.requireActual('path'); -const fs = jest.genMockFromModule('fs'); -const invariant = require('fbjs/lib/invariant'); -const path = require('path'); -const stream = require.requireActual('stream'); +const fs = new (require('metro-memory-fs'))(); -const noop = () => {}; - -function asyncCallback(cb) { - return function() { - setImmediate(() => cb.apply(this, arguments)); - }; +function setMockFilesystem(object) { + fs.reset(); + const root = process.platform === 'win32' ? 'c:\\' : '/'; + mockDir(root, {...object}); } -const mtime = { - getTime: () => Math.ceil(Math.random() * 10000000), -}; - -fs.realpath.mockImplementation((filepath, callback) => { - callback = asyncCallback(callback); - let node; - try { - node = getToNode(filepath); - } catch (e) { - return callback(e); - } - if (node && typeof node === 'object' && node.SYMLINK != null) { - return callback(null, node.SYMLINK); - } - return callback(null, filepath); -}); - -fs.readdirSync.mockImplementation(filepath => Object.keys(getToNode(filepath))); - -fs.readdir.mockImplementation((filepath, callback) => { - callback = asyncCallback(callback); - let node; - try { - node = getToNode(filepath); - if (node && typeof node === 'object' && node.SYMLINK != null) { - node = getToNode(node.SYMLINK); +function mockDir(dirPath, desc) { + for (const entName in desc) { + const ent = desc[entName]; + const entPath = require('path').join(dirPath, entName); + if (typeof ent === 'string' || ent instanceof Buffer) { + fs.writeFileSync(entPath, ent); + continue; } - } catch (e) { - return callback(e); - } - - if (!(node && typeof node === 'object' && node.SYMLINK == null)) { - return callback(new Error(filepath + ' is not a directory.')); - } - - return callback(null, Object.keys(node)); -}); - -fs.readFile.mockImplementation(asyncify(fs.readFileSync)); - -fs.readFileSync.mockImplementation(function(filepath, encoding) { - filepath = path.normalize(filepath); - const node = getToNode(filepath); - if (isDirNode(node)) { - throw new Error('Error readFileSync a dir: ' + filepath); - } - if (Buffer.isBuffer(node) && typeof encoding !== 'undefined') { - return node.toString(); - } - return node; -}); - -fs.writeFile.mockImplementation(asyncify(fs.writeFileSync)); - -fs.writeFileSync.mockImplementation((filePath, content, options) => { - filePath = path.normalize(filePath); - if (options == null || typeof options === 'string') { - options = {encoding: options}; - } - invariant( - options.encoding == null || options.encoding === 'utf8', - '`options` argument supports only `null` or `"utf8"`', - ); - const dirPath = path.dirname(filePath); - const node = getToNode(dirPath); - if (!isDirNode(node)) { - throw fsError('ENOTDIR', 'not a directory: ' + dirPath); - } - node[path.basename(filePath)] = content; -}); - -const openFds = new Map(); -let nextFd = 3; - -fs.openSync.mockImplementation((filePath, flags) => { - const dirPath = path.dirname(filePath); - const node = getToNode(dirPath); - if (!isDirNode(node)) { - throw fsError('ENOTDIR', 'not a directory: ' + dirPath); - } - node[path.basename(filePath)] = ''; - openFds.set(nextFd, {filePath, flags, node}); - return nextFd++; -}); - -fs.writeSync.mockImplementation((fd, str) => { - invariant(typeof str === 'string', 'only strings supported'); - const data = openFds.get(fd); - if (data == null || data.flags !== 'w') { - throw fsError('EBADF', 'bad file descriptor, write'); - } - data.node[path.basename(data.filePath)] += str; -}); - -fs.closeSync.mockImplementation(fd => { - openFds.delete(fd); -}); - -fs.mkdir.mockImplementation(asyncify(fs.mkdirSync)); - -fs.mkdirSync.mockImplementation((dirPath, mode) => { - const parentPath = path.dirname(dirPath); - const node = getToNode(parentPath); - if (!isDirNode(node)) { - throw fsError('ENOTDIR', 'not a directory: ' + parentPath); - } - if (node[path.basename(dirPath)] == null) { - node[path.basename(dirPath)] = {}; - } -}); - -function fsError(code, message) { - const error = new Error(code + ': ' + message); - error.code = code; - return error; -} - -function isDirNode(node) { - return ( - node && - typeof node === 'object' && - node.SYMLINK == null && - Buffer.isBuffer(node) === false - ); -} - -function readlinkSync(filepath) { - const node = getToNode(filepath); - if (node !== null && typeof node === 'object' && !!node.SYMLINK) { - return node.SYMLINK; - } else { - throw new Error(`EINVAL: invalid argument, readlink '${filepath}'`); - } -} - -fs.readlink.mockImplementation((filepath, callback) => { - callback = asyncCallback(callback); - let result; - try { - result = readlinkSync(filepath); - } catch (e) { - callback(e); - return; - } - callback(null, result); -}); - -fs.readlinkSync.mockImplementation(readlinkSync); - -function existsSync(filepath) { - try { - const node = getToNode(filepath); - return node !== null; - } catch (e) { - return false; - } -} - -fs.exists.mockImplementation((filepath, callback) => { - callback = asyncCallback(callback); - let result; - try { - result = existsSync(filepath); - } catch (e) { - callback(e); - return; - } - callback(null, result); -}); - -fs.existsSync.mockImplementation(existsSync); - -function makeStatResult(node) { - const isSymlink = node != null && node.SYMLINK != null; - return { - isBlockDevice: () => false, - isCharacterDevice: () => false, - isDirectory: () => node != null && typeof node === 'object' && !isSymlink, - isFIFO: () => false, - isFile: () => node != null && typeof node === 'string', - isSocket: () => false, - isSymbolicLink: () => isSymlink, - mtime, - }; -} - -function statSync(filepath) { - const node = getToNode(filepath); - if (node != null && node.SYMLINK) { - return statSync(node.SYMLINK); - } - return makeStatResult(node); -} - -fs.stat.mockImplementation((filepath, callback) => { - callback = asyncCallback(callback); - let result; - try { - result = statSync(filepath); - } catch (e) { - callback(e); - return; - } - callback(null, result); -}); - -fs.statSync.mockImplementation(statSync); - -function lstatSync(filepath) { - const node = getToNode(filepath); - return makeStatResult(node); -} - -fs.lstat.mockImplementation((filepath, callback) => { - callback = asyncCallback(callback); - let result; - try { - result = lstatSync(filepath); - } catch (e) { - callback(e); - return; - } - callback(null, result); -}); - -fs.lstatSync.mockImplementation(lstatSync); - -fs.open.mockImplementation(function(filepath) { - const callback = arguments[arguments.length - 1] || noop; - let data, error, fd; - try { - data = getToNode(filepath); - } catch (e) { - error = e; - } - - if (error || data == null) { - error = Error(`ENOENT: no such file or directory: \`${filepath}\``); - } - if (data != null) { - /* global Buffer: true */ - fd = {buffer: new Buffer(data, 'utf8'), position: 0}; - } - - callback(error, fd); -}); - -fs.read.mockImplementation( - (fd, buffer, writeOffset, length, position, callback = noop) => { - let bytesWritten; - try { - if (position == null || position < 0) { - ({position} = fd); - } - bytesWritten = fd.buffer.copy( - buffer, - writeOffset, - position, - position + length, - ); - fd.position = position + bytesWritten; - } catch (e) { - callback(Error('invalid argument')); - return; - } - callback(null, bytesWritten, buffer); - }, -); - -fs.close.mockImplementation((fd, callback = noop) => { - try { - fd.buffer = fs.position = undefined; - } catch (e) { - callback(Error('invalid argument')); - return; - } - callback(null); -}); - -let filesystem = {}; - -fs.mock = { - clear() { - filesystem = {}; - }, -}; - -fs.createReadStream.mockImplementation(filepath => { - if (!filepath.startsWith('/')) { - throw Error('Cannot open file ' + filepath); - } - - const parts = filepath.split('/').slice(1); - let file = filesystem; - - for (const part of parts) { - file = file[part]; - if (!file) { - break; + if (typeof ent !== 'object') { + throw new Error(require('util').format('invalid entity:', ent)); } - } - - if (typeof file !== 'string') { - throw Error('Cannot open file ' + filepath); - } - - return new stream.Readable({ - read() { - this.push(file, 'utf8'); - this.push(null); - }, - }); -}); - -fs.createWriteStream.mockImplementation(filePath => { - let node; - const writeStream = new stream.Writable({ - write(chunk, encoding, callback) { - this.__chunks.push(chunk); - node[path.basename(filePath)] = this.__chunks.join(''); - callback(); - }, - }); - writeStream.__file = filePath; - writeStream.__chunks = []; - writeStream.end = jest.fn(writeStream.end); - fs.createWriteStream.mock.returned.push(writeStream); - try { - const dirPath = dirname(filePath); - node = getToNode(dirPath); - if (!isDirNode(node)) { - throw fsError('ENOTDIR', 'not a directory: ' + dirPath); + if (ent.SYMLINK != null) { + fs.symlinkSync(ent.SYMLINK, entPath); + continue; } - // Truncate the file on opening. - node[path.basename(filePath)] = ''; - } catch (error) { - process.nextTick(() => writeStream.emit('error', error)); - } - return writeStream; -}); -fs.createWriteStream.mock.returned = []; - -fs.__setMockFilesystem = object => (filesystem = object); - -const watcherListByPath = new Map(); - -fs.watch.mockImplementation((filename, options, listener) => { - if (options.recursive) { - throw new Error('recursive watch not implemented'); + fs.mkdirSync(entPath); + mockDir(entPath, ent); } - let watcherList = watcherListByPath.get(filename); - if (watcherList == null) { - watcherList = []; - watcherListByPath.set(filename, watcherList); - } - const fsWatcher = new EventEmitter(); - fsWatcher.on('change', listener); - fsWatcher.close = () => { - watcherList.splice(watcherList.indexOf(fsWatcher), 1); - fsWatcher.close = () => { - throw new Error('FSWatcher is already closed'); - }; - }; - watcherList.push(fsWatcher); -}); - -fs.__triggerWatchEvent = (eventType, filename) => { - const directWatchers = watcherListByPath.get(filename) || []; - directWatchers.forEach(wtc => wtc.emit('change', eventType)); - const dirPath = path.dirname(filename); - const dirWatchers = watcherListByPath.get(dirPath) || []; - dirWatchers.forEach(wtc => - wtc.emit('change', eventType, path.relative(dirPath, filename)), - ); -}; - -function getToNode(filepath) { - // Ignore the drive for Windows paths. - if (filepath.match(/^[a-zA-Z]:\\/)) { - filepath = filepath.substring(2); - } - - if (filepath.endsWith(path.sep)) { - filepath = filepath.slice(0, -1); - } - const parts = filepath.split(/[\/\\]/); - if (parts[0] !== '') { - throw new Error('Make sure all paths are absolute.'); - } - let node = filesystem; - parts.slice(1).forEach(part => { - if (node && node.SYMLINK) { - node = getToNode(node.SYMLINK); - } - node = node[part]; - if (node == null) { - const err = new Error( - `ENOENT: no such file or directory: \`${filepath}\``, - ); - err.code = 'ENOENT'; - throw err; - } - }); - - return node; } +fs.__setMockFilesystem = setMockFilesystem; +fs.mock = {clear: () => fs.reset()}; + module.exports = fs; diff --git a/local-cli/__tests__/fs-mock-test.js b/local-cli/__tests__/fs-mock-test.js deleted file mode 100644 index 4928f3bd9ecf23..00000000000000 --- a/local-cli/__tests__/fs-mock-test.js +++ /dev/null @@ -1,89 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @emails oncall+javascript_foundation - * @flow - * @format - */ - -'use strict'; - -declare var jest: any; -declare var describe: any; -declare var beforeEach: any; -declare var expect: any; -declare var it: any; - -jest.mock('fs'); - -const fs = require('fs'); - -describe('fs mock', () => { - beforeEach(() => { - (fs: $FlowFixMe).mock.clear(); - }); - - describe('writeFileSync()', () => { - it('stores content correctly', () => { - fs.writeFileSync('/test', 'foobar', 'utf8'); - const content = fs.readFileSync('/test', 'utf8'); - expect(content).toEqual('foobar'); - }); - - it('fails on missing path', () => { - expect(() => - fs.writeFileSync('/dir/test', 'foobar', 'utf8'), - ).toThrowError('ENOENT: no such file or directory'); - }); - - it('properly normalizes paths', () => { - fs.writeFileSync('/test/foo/../bar/../../tadam', 'beep', 'utf8'); - const content = fs.readFileSync('/glo/../tadam', 'utf8'); - expect(content).toEqual('beep'); - }); - }); - - describe('mkdirSync()', () => { - it('creates folders that we can write files in', () => { - fs.mkdirSync('/dir', 0o777); - fs.writeFileSync('/dir/test', 'foobar', 'utf8'); - const content = fs.readFileSync('/dir/test', 'utf8'); - expect(content).toEqual('foobar'); - }); - - it('does not erase directories', () => { - fs.mkdirSync('/dir', 0o777); - fs.writeFileSync('/dir/test', 'foobar', 'utf8'); - fs.mkdirSync('/dir', 0o777); - const content = fs.readFileSync('/dir/test', 'utf8'); - expect(content).toEqual('foobar'); - }); - }); - - describe('createWriteStream()', () => { - it('writes content', done => { - const stream = fs.createWriteStream('/test'); - stream.write('hello, '); - stream.write('world'); - stream.end('!'); - process.nextTick(() => { - const content = fs.readFileSync('/test', 'utf8'); - expect(content).toEqual('hello, world!'); - done(); - }); - }); - }); - - describe('writeSync()', () => { - it('writes content', () => { - const fd = fs.openSync('/test', 'w'); - fs.writeSync(fd, 'hello, world!'); - fs.closeSync(fd); - const content = fs.readFileSync('/test', 'utf8'); - expect(content).toEqual('hello, world!'); - }); - }); -}); diff --git a/local-cli/link/__tests__/ios/writePlist.spec.js b/local-cli/link/__tests__/ios/writePlist.spec.js index 0d2e086d00132e..7e32b72aacc8c2 100644 --- a/local-cli/link/__tests__/ios/writePlist.spec.js +++ b/local-cli/link/__tests__/ios/writePlist.spec.js @@ -26,6 +26,9 @@ const infoPlistPath = path.join(__dirname, '../../__fixtures__/Info.plist'); fs.readFileSync = jest.fn(() => readFileSync(projectPath).toString()); +const {writeFileSync} = fs; +fs.writeFileSync = jest.fn(writeFileSync); + const project = xcode.project('/Basic/project.pbxproj'); const plist = { diff --git a/package.json b/package.json index d951833578883f..9e2e48f7ecd7ab 100644 --- a/package.json +++ b/package.json @@ -170,6 +170,7 @@ "metro": "^0.34.0", "metro-babel-register": "^0.34.2", "metro-core": "^0.34.0", + "metro-memory-fs": "^0.34.0", "mime": "^1.3.4", "minimist": "^1.2.0", "mkdirp": "^0.5.1", From 409dbd2057ad440afa08725bc8f8c5f69ed7abac Mon Sep 17 00:00:00 2001 From: David Vacca Date: Wed, 25 Apr 2018 09:43:27 -0700 Subject: [PATCH 0374/1109] Fix setMeasureFunction during cloning Reviewed By: achen1 Differential Revision: D7753602 fbshipit-source-id: 284ec13b4cd784dfc61eeb0205f5779847854aac --- .../progressbar/ProgressBarShadowNode.java | 22 +++++++++++-- .../views/slider/ReactSliderManager.java | 15 +++++++++ .../views/switchview/ReactSwitchManager.java | 16 +++++++++- .../textinput/ReactTextInputShadowNode.java | 10 ++++-- .../test/java/com/facebook/react/fabric/BUCK | 1 + .../react/fabric/FabricUIManagerTest.java | 31 ++++++++----------- 6 files changed, 71 insertions(+), 24 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarShadowNode.java index 367f4a90bd3d71..779d647f658ba3 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarShadowNode.java @@ -7,6 +7,7 @@ package com.facebook.react.views.progressbar; +import com.facebook.react.uimanager.ReactShadowNodeImpl; import javax.annotation.Nullable; import java.util.HashSet; @@ -41,7 +42,7 @@ public ProgressBarShadowNode() { mHeight = new SparseIntArray(); mWidth = new SparseIntArray(); mMeasured = new HashSet<>(); - setMeasureFunction(this); + initMeasureFunction(); } public ProgressBarShadowNode(ProgressBarShadowNode node) { @@ -49,11 +50,28 @@ public ProgressBarShadowNode(ProgressBarShadowNode node) { mWidth = node.mWidth.clone(); mHeight = node.mHeight.clone(); mMeasured = new HashSet<>(node.mMeasured); + } + + @Override + public ReactShadowNodeImpl mutableCopyWithNewChildren() { + ProgressBarShadowNode node = (ProgressBarShadowNode) super.mutableCopyWithNewChildren(); + node.initMeasureFunction(); + return node; + } + + private void initMeasureFunction() { setMeasureFunction(this); } @Override - protected ProgressBarShadowNode copy() { + public ReactShadowNodeImpl mutableCopy() { + ProgressBarShadowNode node = (ProgressBarShadowNode) super.mutableCopy(); + node.initMeasureFunction(); + return node; + } + + @Override + public ProgressBarShadowNode copy() { return new ProgressBarShadowNode(this); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/slider/ReactSliderManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/slider/ReactSliderManager.java index a73aa6ec72f6ce..10f714c9429756 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/slider/ReactSliderManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/slider/ReactSliderManager.java @@ -17,6 +17,7 @@ import com.facebook.react.bridge.ReactContext; import com.facebook.react.common.MapBuilder; import com.facebook.react.uimanager.LayoutShadowNode; +import com.facebook.react.uimanager.ReactShadowNodeImpl; import com.facebook.react.uimanager.SimpleViewManager; import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.UIManagerModule; @@ -63,6 +64,20 @@ private void initMeasureFunction() { setMeasureFunction(this); } + @Override + public ReactShadowNodeImpl mutableCopy() { + ReactSliderShadowNode reactShadowNode = (ReactSliderShadowNode) super.mutableCopy(); + reactShadowNode.initMeasureFunction(); + return reactShadowNode; + } + + @Override + public ReactShadowNodeImpl mutableCopyWithNewChildren() { + ReactSliderShadowNode reactShadowNode = (ReactSliderShadowNode) super.mutableCopyWithNewChildren(); + reactShadowNode.initMeasureFunction(); + return reactShadowNode; + } + @Override protected ReactSliderShadowNode copy() { return new ReactSliderShadowNode(this); diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java index 1c9bff1ce1b9ad..70c5a5123e949a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java @@ -13,6 +13,7 @@ import android.view.ViewGroup; import android.widget.CompoundButton; +import com.facebook.react.uimanager.ReactShadowNodeImpl; import com.facebook.yoga.YogaMeasureMode; import com.facebook.yoga.YogaMeasureFunction; import com.facebook.yoga.YogaNode; @@ -48,13 +49,26 @@ private ReactSwitchShadowNode(ReactSwitchShadowNode node) { mWidth = node.mWidth; mHeight = node.mHeight; mMeasured = node.mMeasured; - initMeasureFunction(); } private void initMeasureFunction() { setMeasureFunction(this); } + @Override + public ReactShadowNodeImpl mutableCopy() { + ReactSwitchShadowNode reactShadowNode = (ReactSwitchShadowNode) super.mutableCopy(); + reactShadowNode.initMeasureFunction(); + return reactShadowNode; + } + + @Override + public ReactShadowNodeImpl mutableCopyWithNewChildren() { + ReactSwitchShadowNode reactShadowNode = (ReactSwitchShadowNode) super.mutableCopyWithNewChildren(); + reactShadowNode.initMeasureFunction(); + return reactShadowNode; + } + @Override protected ReactSwitchShadowNode copy() { return new ReactSwitchShadowNode(this); diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java index 1336314cdae3ba..7ff8d488d72888 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java @@ -46,7 +46,7 @@ public ReactTextInputShadowNode() { mTextBreakStrategy = (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) ? 0 : Layout.BREAK_STRATEGY_SIMPLE; - setMeasureFunction(this); + initMeasureFunction(); } private ReactTextInputShadowNode(ReactTextInputShadowNode node) { @@ -64,7 +64,7 @@ protected ReactTextInputShadowNode copy() { @Override public ReactTextInputShadowNode mutableCopy() { ReactTextInputShadowNode node = (ReactTextInputShadowNode) super.mutableCopy(); - node.setMeasureFunction(this); + node.initMeasureFunction(); ThemedReactContext themedContext = getThemedContext(); if (themedContext != null) { node.setThemedContext(themedContext); @@ -72,10 +72,14 @@ public ReactTextInputShadowNode mutableCopy() { return node; } + private void initMeasureFunction() { + setMeasureFunction(this); + } + @Override public ReactTextInputShadowNode mutableCopyWithNewChildren() { ReactTextInputShadowNode node = (ReactTextInputShadowNode) super.mutableCopyWithNewChildren(); - node.setMeasureFunction(this); + node.initMeasureFunction(); ThemedReactContext themedContext = getThemedContext(); if (themedContext != null) { node.setThemedContext(themedContext); diff --git a/ReactAndroid/src/test/java/com/facebook/react/fabric/BUCK b/ReactAndroid/src/test/java/com/facebook/react/fabric/BUCK index 55eb26ebc3e6ff..faa1e3fa21a8ed 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/fabric/BUCK +++ b/ReactAndroid/src/test/java/com/facebook/react/fabric/BUCK @@ -34,6 +34,7 @@ rn_robolectric_test( react_native_target("java/com/facebook/react/uimanager:uimanager"), react_native_target("java/com/facebook/react/views/text:text"), react_native_target("java/com/facebook/react/views/view:view"), + react_native_target("java/com/facebook/react/views/progressbar:progressbar"), react_native_tests_target("java/com/facebook/react/bridge:testhelpers"), ], ) diff --git a/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java b/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java index 32a0bbb40015e3..159352c776fe28 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java @@ -2,41 +2,29 @@ package com.facebook.react.fabric; import static org.fest.assertions.api.Assertions.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; import com.facebook.react.ReactRootView; -import com.facebook.react.bridge.CatalystInstance; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactTestHelper; import com.facebook.react.bridge.ReadableNativeMap; -import com.facebook.react.common.ClearableSynchronizedPool; -import com.facebook.react.fabric.FabricUIManager; import com.facebook.react.uimanager.ReactShadowNode; import com.facebook.react.uimanager.ReactShadowNodeImpl; import com.facebook.react.uimanager.Spacing; import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.ViewManager; import com.facebook.react.uimanager.ViewManagerRegistry; +import com.facebook.react.views.progressbar.ProgressBarShadowNode; import com.facebook.react.views.text.ReactRawTextManager; import com.facebook.react.views.text.ReactRawTextShadowNode; import com.facebook.react.views.text.ReactTextViewManager; import com.facebook.react.views.view.ReactViewManager; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedList; import java.util.List; import org.fest.assertions.data.Offset; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; @@ -52,11 +40,10 @@ public class FabricUIManagerTest { @Before public void setUp() throws Exception { mNextReactTag = 2; - mThemedReactContext = mock(ThemedReactContext.class); - CatalystInstance catalystInstance = ReactTestHelper.createMockCatalystInstance(); - ReactApplicationContext reactContext = - new ReactApplicationContext(RuntimeEnvironment.application); - reactContext.initializeWithInstance(catalystInstance); + ReactApplicationContext reactContext = new ReactApplicationContext(RuntimeEnvironment.application); + reactContext.initializeWithInstance(ReactTestHelper.createMockCatalystInstance()); + mThemedReactContext = new ThemedReactContext(reactContext, reactContext); + List viewManagers = Arrays.asList( new ReactViewManager(), new ReactTextViewManager(), new ReactRawTextManager()); @@ -143,6 +130,14 @@ public void testCloneVirtualNode() { assertThat(clonedNode).isNotEqualTo(node); } + @Test + public void testLayoutProgressBarAfterClonning() { + ProgressBarShadowNode node = new ProgressBarShadowNode(); + node.setThemedContext(mThemedReactContext); + ProgressBarShadowNode clone = (ProgressBarShadowNode) node.mutableCopy(); + clone.calculateLayout(); + } + @Test public void testCloneNodeWithNewChildren() { ReactShadowNode node = createViewNode(); From a62aac5952c2d94120b7ed63d518da2bfbf4316d Mon Sep 17 00:00:00 2001 From: David Vacca Date: Wed, 25 Apr 2018 09:43:32 -0700 Subject: [PATCH 0375/1109] Fix rootview layout when using flex Reviewed By: achen1 Differential Revision: D7753463 fbshipit-source-id: 5d2d70f9b5130ffe3b59a5364c589f437988ef37 --- .../react/fabric/FabricUIManager.java | 42 ++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) 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 cd6045f00d88ce..ce8046092b299a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -14,10 +14,12 @@ import android.util.Log; import android.view.View; import com.facebook.infer.annotation.Assertions; +import com.facebook.react.bridge.GuardedRunnable; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReadableNativeMap; import com.facebook.react.bridge.UIManager; +import com.facebook.react.common.ReactConstants; import com.facebook.react.common.annotations.VisibleForTesting; import com.facebook.react.modules.i18nmanager.I18nUtil; import com.facebook.react.uimanager.DisplayMetricsHolder; @@ -33,6 +35,7 @@ import com.facebook.react.uimanager.common.MeasureSpecProvider; import com.facebook.react.uimanager.common.SizeMonitoringFrameLayout; import java.util.ArrayList; +import java.util.LinkedList; import java.util.List; import javax.annotation.Nullable; @@ -248,11 +251,12 @@ public void appendChildToSet(List childList, ReactShadowNode ch childList.add(child); } - public synchronized void completeRoot(int rootTag, List childList) { - if (DEBUG) { - Log.d(TAG, "completeRoot rootTag: " + rootTag + ", childList: " + childList); - } + public synchronized void completeRoot(int rootTag, @Nullable List childList) { try { + childList = childList == null ? new LinkedList() : childList; + if (DEBUG) { + Log.d(TAG, "completeRoot rootTag: " + rootTag + ", childList: " + childList); + } ReactShadowNode currentRootShadowNode = getRootNode(rootTag); Assertions.assertNotNull( currentRootShadowNode, @@ -340,7 +344,7 @@ private void applyUpdatesRecursive(ReactShadowNode node, float absoluteX, float @Override public int addRootView( final T rootView) { - int rootTag = ReactRootViewTagGenerator.getNextRootViewTag(); + final int rootTag = ReactRootViewTagGenerator.getNextRootViewTag(); ThemedReactContext themedRootContext = new ThemedReactContext(mReactApplicationContext, rootView.getContext()); @@ -350,11 +354,39 @@ public int addRootVi int heightMeasureSpec = rootView.getHeightMeasureSpec(); updateRootView(rootShadowNode, widthMeasureSpec, heightMeasureSpec); + rootView.setOnSizeChangedListener( + new SizeMonitoringFrameLayout.OnSizeChangedListener() { + @Override + public void onSizeChanged(final int width, final int height, int oldW, int oldH) { + updateRootSize(rootTag, width, height); + } + }); + mRootShadowNodeRegistry.registerNode(rootShadowNode); mUIViewOperationQueue.addRootView(rootTag, rootView, themedRootContext); return rootTag; } + /** + * Updates the root view size and re-render the RN surface. + * + * //TODO: change synchronization to integrate with new #render loop. + */ + private synchronized void updateRootSize(int rootTag, int newWidth, int newHeight) { + ReactShadowNode rootNode = mRootShadowNodeRegistry.getNode(rootTag); + if (rootNode == null) { + Log.w( + ReactConstants.TAG, + "Tried to update size of non-existent tag: " + rootTag); + return; + } + int newWidthSpec = View.MeasureSpec.makeMeasureSpec(newWidth, View.MeasureSpec.EXACTLY); + int newHeightSpec = View.MeasureSpec.makeMeasureSpec(newHeight, View.MeasureSpec.EXACTLY); + updateRootView(rootNode, newWidthSpec, newHeightSpec); + + completeRoot(rootTag, rootNode.getChildrenList()); + } + public void removeRootView(int rootTag) { mRootShadowNodeRegistry.removeNode(rootTag); } From a3a98eb1c7fa0054a236d45421393874ce8ce558 Mon Sep 17 00:00:00 2001 From: Mika Andrianarijaona Date: Wed, 25 Apr 2018 23:27:48 -0700 Subject: [PATCH 0376/1109] BREAKING - default underlineColorAndroid to transparent Summary: Set default `underlineColorAndroid` to `transparent`. Fixes #18938 Use a TextInput in a component without defining `underlineColorAndroid`, the underline color should be transparent. [ANDROID] [BREAKING] [TextInput] - set default underlineColorAndroid to transparent Closes https://github.com/facebook/react-native/pull/18988 Reviewed By: mdvacca Differential Revision: D7765569 Pulled By: yungsters fbshipit-source-id: f7ad57a46fc0d18b47271ca39faae8c635995fbb --- Libraries/Components/TextInput/TextInput.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js index e887b07438f412..f0cf5b955e9612 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -637,6 +637,7 @@ const TextInput = createReactClass({ getDefaultProps(): Object { return { allowFontScaling: true, + underlineColorAndroid: 'transparent', }; }, /** From c656fa80724489f4e92695ddb594bb7c6af9d572 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Norte?= Date: Thu, 26 Apr 2018 05:56:48 -0700 Subject: [PATCH 0377/1109] Removed some @providesModule tags and references Reviewed By: jeanlauliac Differential Revision: D7758118 fbshipit-source-id: 556bdcac54f92e3143d98e0ae3d9016a5b7de2bd --- Libraries/Components/ScrollResponder.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/Components/ScrollResponder.js b/Libraries/Components/ScrollResponder.js index 93431293a348ac..6a38cc7523dda4 100644 --- a/Libraries/Components/ScrollResponder.js +++ b/Libraries/Components/ScrollResponder.js @@ -574,7 +574,7 @@ const ScrollResponderMixin = { * - willHide {startCoordinates, endCoordinates} several times * - didHide several times * - * The `ScrollResponder` providesModule callbacks for each of these events. + * The `ScrollResponder` module callbacks for each of these events. * Even though any user could have easily listened to keyboard events * themselves, using these `props` callbacks ensures that ordering of events * is consistent - and not dependent on the order that the keyboard events are From 34ee828b2e8e37b5c54bb9664139e2c791af6be7 Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Thu, 26 Apr 2018 06:05:16 -0700 Subject: [PATCH 0378/1109] Bump metro@0.35.0 Reviewed By: mjesun Differential Revision: D7759224 fbshipit-source-id: d21a371c196ff5c6e691fb7cce8c73dade02d385 --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 9e2e48f7ecd7ab..63695f29a6a97a 100644 --- a/package.json +++ b/package.json @@ -167,10 +167,10 @@ "graceful-fs": "^4.1.3", "inquirer": "^3.0.6", "lodash": "^4.17.5", - "metro": "^0.34.0", - "metro-babel-register": "^0.34.2", - "metro-core": "^0.34.0", - "metro-memory-fs": "^0.34.0", + "metro": "^0.35.0", + "metro-babel-register": "^0.35.0", + "metro-core": "^0.35.0", + "metro-memory-fs": "^0.35.0", "mime": "^1.3.4", "minimist": "^1.2.0", "mkdirp": "^0.5.1", From eeab57aa26385656cc69f057c9db5c7f4da293ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Norte?= Date: Thu, 26 Apr 2018 07:48:16 -0700 Subject: [PATCH 0379/1109] Removed last traces of @providesModule from React Native Reviewed By: jeanlauliac Differential Revision: D7774204 fbshipit-source-id: d80e4b4d1dc5fe7686aff7340368d0f2670e449f --- CONTRIBUTING.md | 2 -- scripts/versiontemplates/ReactNativeVersion.js.template | 1 - 2 files changed, 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bc151d02603d62..25ba2d5c1e1d51 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -147,8 +147,6 @@ Copy and paste this to the top of your new file(s): */ ``` -If you've added a new module, add a `@providesModule ` at the end of the comment. This will allow the haste package manager to find it. - #### Contributor License Agreement (CLA) In order to accept your pull request, we need you to submit a CLA. You only need to do this once, so if you've done this for another Facebook open source project, you're good to go. If you are submitting a pull request for the first time, the Facebook GitHub Bot will reply with a link to the CLA form. You may also [complete your CLA here](https://code.facebook.com/cla). diff --git a/scripts/versiontemplates/ReactNativeVersion.js.template b/scripts/versiontemplates/ReactNativeVersion.js.template index 1f1ccdd741dd32..80f4b280a86fc6 100644 --- a/scripts/versiontemplates/ReactNativeVersion.js.template +++ b/scripts/versiontemplates/ReactNativeVersion.js.template @@ -7,7 +7,6 @@ * LICENSE file in the root directory of this source tree. * * @flow - * @providesModule ReactNativeVersion */ exports.version = { From de08f4ab6c799e9610688e72be7b4cacbc15472b Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Thu, 26 Apr 2018 08:46:32 -0700 Subject: [PATCH 0380/1109] Blacklist FB RN renderer for RN GitHub OSS tests Reviewed By: rubennorte Differential Revision: D7774634 fbshipit-source-id: f293e897e31daf1e7230f55cc932c25ee6f8558a --- jest/hasteImpl.js | 1 + 1 file changed, 1 insertion(+) diff --git a/jest/hasteImpl.js b/jest/hasteImpl.js index cb5ac4a049c4f6..ec838a1d47d046 100644 --- a/jest/hasteImpl.js +++ b/jest/hasteImpl.js @@ -16,6 +16,7 @@ const ROOT = path.join(__dirname, '..'); const BLACKLISTED_PATTERNS/*: Array*/ = [ /.*\/__(mocks|tests)__\/.*/, /^Libraries\/Animated\/src\/polyfills\/.*/, + /^Libraries\/Renderer\/fb\/.*/, ]; const WHITELISTED_PREFIXES/*: Array*/ = [ From 2e7dbc82b3e604de2195790085c2a025dc5f06a6 Mon Sep 17 00:00:00 2001 From: Himabindu Gadupudi Date: Thu, 26 Apr 2018 14:17:09 -0700 Subject: [PATCH 0381/1109] Center align image in a span Reviewed By: achen1 Differential Revision: D7750114 fbshipit-source-id: 84b4eaa2da01ac9c49a569d37f7a32eab1e5aca8 --- .../frescosupport/FrescoBasedReactTextInlineImageSpan.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageSpan.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageSpan.java index 39cd24c6fd3cd9..08d3ed9d2f7692 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageSpan.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageSpan.java @@ -160,8 +160,10 @@ public void draw( canvas.save(); - // Align to baseline by default - int transY = y - mDrawable.getBounds().bottom; + // Align to center + int fontHeight = (int)(paint.descent() - paint.ascent()); + int centerY = y + (int)paint.descent() - fontHeight / 2; + int transY = centerY - (mDrawable.getBounds().bottom - mDrawable.getBounds().top) / 2; canvas.translate(x, transY); mDrawable.draw(canvas); From bd91eaf6647d94d216e49520ff75e7a962084078 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Thu, 26 Apr 2018 17:51:27 -0700 Subject: [PATCH 0382/1109] Fabric/Text: ShadowNode::clone() - dynamic self-cloning mechanism Summary: The previous approach simply didn't work. :( As you might notice, in previous implementation of ViewShadowNode::cloneAndReplaceChild we used `ViewShadowNode` class for cloning `childNode`, and this is incorrect becasue `childNode` might be instance of any class. Reviewed By: fkgozali Differential Revision: D7595016 fbshipit-source-id: 2215414926f2f7a2e2fd05ca2d065f10d6d32b74 --- .../ConcreteComponentDescriptor.h | 22 +++++++++++- .../core/shadownode/ConcreteShadowNode.h | 6 ++-- .../fabric/core/shadownode/ShadowNode.cpp | 13 ++++++- .../fabric/core/shadownode/ShadowNode.h | 23 ++++++++++-- .../fabric/core/tests/ShadowNodeTest.cpp | 35 +++++++++++++++++++ ReactCommon/fabric/view/ViewShadowNode.cpp | 19 +++++----- ReactCommon/fabric/view/ViewShadowNode.h | 3 +- 7 files changed, 106 insertions(+), 15 deletions(-) diff --git a/ReactCommon/fabric/core/componentdescriptor/ConcreteComponentDescriptor.h b/ReactCommon/fabric/core/componentdescriptor/ConcreteComponentDescriptor.h index 8739d849a4a1f9..2e2ee37fd2082c 100644 --- a/ReactCommon/fabric/core/componentdescriptor/ConcreteComponentDescriptor.h +++ b/ReactCommon/fabric/core/componentdescriptor/ConcreteComponentDescriptor.h @@ -8,6 +8,7 @@ #pragma once #include +#include #include #include @@ -40,7 +41,14 @@ class ConcreteComponentDescriptor: public ComponentDescriptor { const InstanceHandle &instanceHandle, const SharedProps &props ) const override { - return std::make_shared(tag, rootTag, instanceHandle, std::static_pointer_cast(props)); + return std::make_shared( + tag, + rootTag, + instanceHandle, + std::static_pointer_cast(props), + ShadowNode::emptySharedShadowNodeSharedList(), + getCloneFunction() + ); } SharedShadowNode cloneShadowNode( @@ -67,6 +75,18 @@ class ConcreteComponentDescriptor: public ComponentDescriptor { return ShadowNodeT::Props(rawProps, props); }; +private: + mutable ShadowNodeCloneFunction cloneFunction_; + + ShadowNodeCloneFunction getCloneFunction() const { + if (!cloneFunction_) { + cloneFunction_ = [this](const SharedShadowNode &shadowNode, const SharedProps &props, const SharedShadowNodeSharedList &children) { + return this->cloneShadowNode(shadowNode, props, children); + }; + } + + return cloneFunction_; + } }; } // namespace react diff --git a/ReactCommon/fabric/core/shadownode/ConcreteShadowNode.h b/ReactCommon/fabric/core/shadownode/ConcreteShadowNode.h index 278d448708c886..9a18cf7e1edc00 100644 --- a/ReactCommon/fabric/core/shadownode/ConcreteShadowNode.h +++ b/ReactCommon/fabric/core/shadownode/ConcreteShadowNode.h @@ -51,14 +51,16 @@ class ConcreteShadowNode: public ShadowNode { const Tag &rootTag, const InstanceHandle &instanceHandle, const SharedConcreteProps &props = ConcreteShadowNode::defaultSharedProps(), - const SharedShadowNodeSharedList &children = ShadowNode::emptySharedShadowNodeSharedList() + const SharedShadowNodeSharedList &children = ShadowNode::emptySharedShadowNodeSharedList(), + const ShadowNodeCloneFunction &cloneFunction = nullptr ): ShadowNode( tag, rootTag, instanceHandle, (SharedProps)props, - children + children, + cloneFunction ) {}; ConcreteShadowNode( diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp index e7c6b68f22ef65..f1272c32696fbf 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp @@ -25,13 +25,15 @@ ShadowNode::ShadowNode( const Tag &rootTag, const InstanceHandle &instanceHandle, const SharedProps &props, - const SharedShadowNodeSharedList &children + const SharedShadowNodeSharedList &children, + const ShadowNodeCloneFunction &cloneFunction ): tag_(tag), rootTag_(rootTag), instanceHandle_(instanceHandle), props_(props), children_(std::make_shared(*children)), + cloneFunction_(cloneFunction), revision_(1) {} ShadowNode::ShadowNode( @@ -45,8 +47,17 @@ ShadowNode::ShadowNode( props_(props ? props : shadowNode->props_), children_(std::make_shared(*(children ? children : shadowNode->children_))), sourceNode_(shadowNode), + cloneFunction_(shadowNode->cloneFunction_), revision_(shadowNode->revision_ + 1) {} +SharedShadowNode ShadowNode::clone( + const SharedProps &props, + const SharedShadowNodeSharedList &children +) const { + assert(cloneFunction_); + return cloneFunction_(shared_from_this(), props_, children_); +} + #pragma mark - Getters SharedShadowNodeSharedList ShadowNode::getChildren() const { diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.h b/ReactCommon/fabric/core/shadownode/ShadowNode.h index a5b8a2ff9da6eb..e83e6227634221 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.h +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.h @@ -8,6 +8,7 @@ #pragma once #include +#include #include #include @@ -26,9 +27,12 @@ using SharedShadowNodeSharedList = std::shared_ptr; using SharedShadowNodeUnsharedList = std::shared_ptr; using WeakShadowNode = std::weak_ptr; +using ShadowNodeCloneFunction = std::function; + class ShadowNode: public virtual Sealable, - public virtual DebugStringConvertible { + public virtual DebugStringConvertible, + public std::enable_shared_from_this { public: static SharedShadowNodeSharedList emptySharedShadowNodeSharedList(); @@ -39,7 +43,8 @@ class ShadowNode: const Tag &rootTag, const InstanceHandle &instanceHandle, const SharedProps &props = SharedProps(), - const SharedShadowNodeSharedList &children = SharedShadowNodeSharedList() + const SharedShadowNodeSharedList &children = SharedShadowNodeSharedList(), + const ShadowNodeCloneFunction &cloneFunction = nullptr ); ShadowNode( @@ -48,6 +53,14 @@ class ShadowNode: const SharedShadowNodeSharedList &children = nullptr ); + /* + * Clones the shadow node using stored `cloneFunction`. + */ + SharedShadowNode clone( + const SharedProps &props = nullptr, + const SharedShadowNodeSharedList &children = nullptr + ) const; + #pragma mark - Getters virtual ComponentHandle getComponentHandle() const = 0; @@ -112,6 +125,12 @@ class ShadowNode: private: + /* + * A reference to a cloning function that understands how to clone + * the specific type of ShadowNode. + */ + ShadowNodeCloneFunction cloneFunction_; + /* * A number of the generation of the ShadowNode instance; * is used and useful for debug-printing purposes *only*. diff --git a/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp b/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp index 168cf48869850f..8c8204684b7813 100644 --- a/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp +++ b/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp @@ -115,3 +115,38 @@ TEST(ShadowNodeTest, handleSourceNode) { ASSERT_EQ(nodeThirdGeneration->getSourceNode(), nodeSecondGeneration); ASSERT_EQ(nodeSecondGeneration->getSourceNode(), nodeFirstGeneration); } + +TEST(ShadowNodeTest, handleCloneFunction) { + auto firstNode = std::make_shared(9, 1, (void *)NULL); + + // The shadow node is not clonable if `cloneFunction` is not provided, + ASSERT_DEATH_IF_SUPPORTED(firstNode->clone(), "cloneFunction_"); + + auto secondNode = std::make_shared( + 9, + 1, + (void *)NULL, + std::make_shared(), + ShadowNode::emptySharedShadowNodeSharedList(), + [](const SharedShadowNode &shadowNode, const SharedProps &props, const SharedShadowNodeSharedList &children) { + return std::make_shared( + std::static_pointer_cast(shadowNode), + props, + children + ); + } + ); + + auto secondNodeClone = secondNode->clone(); + + // Those two nodes are *not* same. + ASSERT_NE(secondNode, secondNodeClone); + + // `secondNodeClone` is an instance of `TestShadowNode`. + ASSERT_NE(std::dynamic_pointer_cast(secondNodeClone), nullptr); + + // Both nodes have same content. + ASSERT_EQ(secondNode->getTag(), secondNodeClone->getTag()); + ASSERT_EQ(secondNode->getRootTag(), secondNodeClone->getRootTag()); + ASSERT_EQ(secondNode->getProps(), secondNodeClone->getProps()); +} diff --git a/ReactCommon/fabric/view/ViewShadowNode.cpp b/ReactCommon/fabric/view/ViewShadowNode.cpp index 111d220ec12d52..51d4be23ba383b 100644 --- a/ReactCommon/fabric/view/ViewShadowNode.cpp +++ b/ReactCommon/fabric/view/ViewShadowNode.cpp @@ -21,14 +21,16 @@ ViewShadowNode::ViewShadowNode( const Tag &rootTag, const InstanceHandle &instanceHandle, const SharedViewProps &props, - const SharedShadowNodeSharedList &children + const SharedShadowNodeSharedList &children, + const ShadowNodeCloneFunction &cloneFunction ): ConcreteShadowNode( tag, rootTag, instanceHandle, props, - children + children, + cloneFunction ), AccessibleShadowNode( props @@ -92,9 +94,9 @@ SharedLayoutableShadowNodeList ViewShadowNode::getLayoutableChildNodes() const { SharedLayoutableShadowNode ViewShadowNode::cloneAndReplaceChild(const SharedLayoutableShadowNode &child) { ensureUnsealed(); - auto viewShadowNodeChild = std::dynamic_pointer_cast(child); - assert(viewShadowNodeChild); - auto viewShadowNodeChildClone = std::make_shared(viewShadowNodeChild); + auto childShadowNode = std::dynamic_pointer_cast(child); + assert(childShadowNode); + auto childShadowNodeClone = childShadowNode->clone(); // This is overloading of `SharedLayoutableShadowNode::cloneAndReplaceChild`, // the method is used to clone some node as a preparation for future mutation @@ -107,10 +109,11 @@ SharedLayoutableShadowNode ViewShadowNode::cloneAndReplaceChild(const SharedLayo // In other words, if we don't compensate this change here, // the Diffing algorithm will compare wrong trees // ("new-but-not-laid-out-yet vs. new" instead of "committed vs. new"). - viewShadowNodeChildClone->shallowSourceNode(); + auto nonConstChildShadowNodeClone = std::const_pointer_cast(childShadowNodeClone); + nonConstChildShadowNodeClone->shallowSourceNode(); - ShadowNode::replaceChild(viewShadowNodeChild, viewShadowNodeChildClone); - return std::static_pointer_cast(viewShadowNodeChildClone); + ShadowNode::replaceChild(childShadowNode, childShadowNodeClone); + return std::dynamic_pointer_cast(childShadowNodeClone); } #pragma mark - Equality diff --git a/ReactCommon/fabric/view/ViewShadowNode.h b/ReactCommon/fabric/view/ViewShadowNode.h index 230aad5694fe4e..5809430df67b48 100644 --- a/ReactCommon/fabric/view/ViewShadowNode.h +++ b/ReactCommon/fabric/view/ViewShadowNode.h @@ -35,7 +35,8 @@ class ViewShadowNode: const Tag &rootTag, const InstanceHandle &instanceHandle, const SharedViewProps &props = ViewShadowNode::defaultSharedProps(), - const SharedShadowNodeSharedList &children = ShadowNode::emptySharedShadowNodeSharedList() + const SharedShadowNodeSharedList &children = ShadowNode::emptySharedShadowNodeSharedList(), + const ShadowNodeCloneFunction &cloneFunction = nullptr ); ViewShadowNode( From f72df7a6e71fcc32f1cc33a8427f548c51e9b759 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Thu, 26 Apr 2018 17:51:29 -0700 Subject: [PATCH 0383/1109] Fabric/Text: ConcreteViewShadowNode - base class for all `View`-like shadow nodes Summary: Quite trivial split ViewShadowNode into concrete class and templace class. Reviewed By: fkgozali Differential Revision: D7595017 fbshipit-source-id: b1ac1dfa187e5cfd0a34fbf84b3e1ae308bb0c99 --- .../fabric/view/ConcreteViewShadowNode.h | 167 ++++++++++++++++++ ReactCommon/fabric/view/ViewShadowNode.cpp | 126 ------------- ReactCommon/fabric/view/ViewShadowNode.h | 48 +---- 3 files changed, 173 insertions(+), 168 deletions(-) create mode 100644 ReactCommon/fabric/view/ConcreteViewShadowNode.h diff --git a/ReactCommon/fabric/view/ConcreteViewShadowNode.h b/ReactCommon/fabric/view/ConcreteViewShadowNode.h new file mode 100644 index 00000000000000..320fbb0d4eb5e4 --- /dev/null +++ b/ReactCommon/fabric/view/ConcreteViewShadowNode.h @@ -0,0 +1,167 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 +#include +#include + +namespace facebook { +namespace react { + +/* + * Template for all -like classes (classes which have all same props + * as and similar basic behaviour). + * For example: , , but not , . + */ +template +class ConcreteViewShadowNode: + public ConcreteShadowNode, + public AccessibleShadowNode, + public YogaLayoutableShadowNode { + + static_assert(std::is_base_of::value, "ViewPropsT must be a descendant of ViewProps"); + static_assert(std::is_base_of::value, "ViewPropsT must be a descendant of YogaStylableProps"); + static_assert(std::is_base_of::value, "ViewPropsT must be a descendant of AccessibilityProps"); + +public: + + using ConcreteViewProps = ViewPropsT; + using SharedConcreteViewProps = std::shared_ptr; + using SharedConcreteViewShadowNode = std::shared_ptr; + + ConcreteViewShadowNode( + const Tag &tag, + const Tag &rootTag, + const InstanceHandle &instanceHandle, + const SharedViewProps &props = ConcreteViewShadowNode::defaultSharedProps(), + const SharedShadowNodeSharedList &children = ShadowNode::emptySharedShadowNodeSharedList(), + const ShadowNodeCloneFunction &cloneFunction = nullptr + ): + ConcreteShadowNode( + tag, + rootTag, + instanceHandle, + props, + children, + cloneFunction + ), + AccessibleShadowNode( + props + ), + YogaLayoutableShadowNode( + props, + children + ) {}; + + ConcreteViewShadowNode( + const SharedConcreteViewShadowNode &shadowNode, + const SharedViewProps &props = nullptr, + const SharedShadowNodeSharedList &children = nullptr + ): + ConcreteShadowNode( + shadowNode, + props, + children + ), + AccessibleShadowNode( + shadowNode, + props + ), + YogaLayoutableShadowNode( + shadowNode, + props, + children + ) {}; + + void appendChild(const SharedShadowNode &child) { + ensureUnsealed(); + + ShadowNode::appendChild(child); + + auto yogaLayoutableChild = std::dynamic_pointer_cast(child); + if (yogaLayoutableChild) { + YogaLayoutableShadowNode::appendChild(yogaLayoutableChild); + } + } + + SharedLayoutableShadowNode cloneAndReplaceChild(const SharedLayoutableShadowNode &child) override { + ensureUnsealed(); + + auto childShadowNode = std::dynamic_pointer_cast(child); + assert(childShadowNode); + auto childShadowNodeClone = childShadowNode->clone(); + + // This is overloading of `SharedLayoutableShadowNode::cloneAndReplaceChild`, + // the method is used to clone some node as a preparation for future mutation + // caused by relayout. + // Because those changes are not requested by UIManager, they add a layer + // of node generation (between the committed stage and new proposed stage). + // That additional layer confuses the Diffing algorithm which uses + // `sourceNode` for referencing the previous (aka committed) stage + // of the tree to produce mutation instructions. + // In other words, if we don't compensate this change here, + // the Diffing algorithm will compare wrong trees + // ("new-but-not-laid-out-yet vs. new" instead of "committed vs. new"). + auto nonConstChildShadowNodeClone = std::const_pointer_cast(childShadowNodeClone); + nonConstChildShadowNodeClone->shallowSourceNode(); + + ShadowNode::replaceChild(childShadowNode, childShadowNodeClone); + return std::dynamic_pointer_cast(childShadowNodeClone); + } + +#pragma mark - Equality + + bool operator==(const ShadowNode& rhs) const override { + if (!ShadowNode::operator==(rhs)) { + return false; + } + + auto &&other = static_cast(rhs); + return getLayoutMetrics() == other.getLayoutMetrics(); + } + +#pragma mark - DebugStringConvertible + + SharedDebugStringConvertibleList getDebugProps() const override { + SharedDebugStringConvertibleList list = {}; + + auto basePropsList = ShadowNode::getDebugProps(); + std::move(basePropsList.begin(), basePropsList.end(), std::back_inserter(list)); + + list.push_back(std::make_shared("layout", "", YogaLayoutableShadowNode::getDebugProps())); + + return list; + } + +private: + +#pragma mark - LayoutableShadowNode + + SharedLayoutableShadowNodeList getLayoutableChildNodes() const override { + SharedLayoutableShadowNodeList sharedLayoutableShadowNodeList = {}; + for (auto child : *ShadowNode::children_) { + const SharedLayoutableShadowNode layoutableShadowNode = std::dynamic_pointer_cast(child); + if (!layoutableShadowNode) { + continue; + } + + sharedLayoutableShadowNodeList.push_back(layoutableShadowNode); + } + + return sharedLayoutableShadowNodeList; + } + +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/view/ViewShadowNode.cpp b/ReactCommon/fabric/view/ViewShadowNode.cpp index 51d4be23ba383b..2bf7f30d76aeea 100644 --- a/ReactCommon/fabric/view/ViewShadowNode.cpp +++ b/ReactCommon/fabric/view/ViewShadowNode.cpp @@ -7,138 +7,12 @@ #include "ViewShadowNode.h" -#include - -#include - namespace facebook { namespace react { -#pragma mark - Constructors - -ViewShadowNode::ViewShadowNode( - const Tag &tag, - const Tag &rootTag, - const InstanceHandle &instanceHandle, - const SharedViewProps &props, - const SharedShadowNodeSharedList &children, - const ShadowNodeCloneFunction &cloneFunction -): - ConcreteShadowNode( - tag, - rootTag, - instanceHandle, - props, - children, - cloneFunction - ), - AccessibleShadowNode( - props - ), - YogaLayoutableShadowNode( - props, - children - ) {}; - -ViewShadowNode::ViewShadowNode( - const SharedViewShadowNode &shadowNode, - const SharedViewProps &props, - const SharedShadowNodeSharedList &children -): - ConcreteShadowNode( - shadowNode, - props, - children - ), - AccessibleShadowNode( - shadowNode, - props - ), - YogaLayoutableShadowNode( - shadowNode, - props, - children - ) {}; - ComponentName ViewShadowNode::getComponentName() const { return ComponentName("View"); } -void ViewShadowNode::appendChild(const SharedShadowNode &child) { - ensureUnsealed(); - - ShadowNode::appendChild(child); - - auto yogaLayoutableChild = std::dynamic_pointer_cast(child); - if (yogaLayoutableChild) { - YogaLayoutableShadowNode::appendChild(yogaLayoutableChild); - } -} - -#pragma mark - YogaLayoutableShadowNode - -SharedLayoutableShadowNodeList ViewShadowNode::getLayoutableChildNodes() const { - SharedLayoutableShadowNodeList sharedLayoutableShadowNodeList = {}; - for (auto child : *children_) { - const SharedLayoutableShadowNode layoutableShadowNode = std::dynamic_pointer_cast(child); - if (!layoutableShadowNode) { - continue; - } - - sharedLayoutableShadowNodeList.push_back(layoutableShadowNode); - } - - return sharedLayoutableShadowNodeList; -} - -SharedLayoutableShadowNode ViewShadowNode::cloneAndReplaceChild(const SharedLayoutableShadowNode &child) { - ensureUnsealed(); - - auto childShadowNode = std::dynamic_pointer_cast(child); - assert(childShadowNode); - auto childShadowNodeClone = childShadowNode->clone(); - - // This is overloading of `SharedLayoutableShadowNode::cloneAndReplaceChild`, - // the method is used to clone some node as a preparation for future mutation - // caused by relayout. - // Because those changes are not requested by UIManager, they add a layer - // of node generation (between the committed stage and new proposed stage). - // That additional layer confuses the Diffing algorithm which uses - // `sourceNode` for referencing the previous (aka committed) stage - // of the tree to produce mutation instructions. - // In other words, if we don't compensate this change here, - // the Diffing algorithm will compare wrong trees - // ("new-but-not-laid-out-yet vs. new" instead of "committed vs. new"). - auto nonConstChildShadowNodeClone = std::const_pointer_cast(childShadowNodeClone); - nonConstChildShadowNodeClone->shallowSourceNode(); - - ShadowNode::replaceChild(childShadowNode, childShadowNodeClone); - return std::dynamic_pointer_cast(childShadowNodeClone); -} - -#pragma mark - Equality - -bool ViewShadowNode::operator==(const ShadowNode& rhs) const { - if (!ShadowNode::operator==(rhs)) { - return false; - } - - auto &&other = static_cast(rhs); - return getLayoutMetrics() == other.getLayoutMetrics(); -} - -#pragma mark - DebugStringConvertible - -SharedDebugStringConvertibleList ViewShadowNode::getDebugProps() const { - SharedDebugStringConvertibleList list = {}; - - auto basePropsList = ShadowNode::getDebugProps(); - std::move(basePropsList.begin(), basePropsList.end(), std::back_inserter(list)); - - list.push_back(std::make_shared("layout", "", YogaLayoutableShadowNode::getDebugProps())); - - return list; -} - } // namespace react } // namespace facebook diff --git a/ReactCommon/fabric/view/ViewShadowNode.h b/ReactCommon/fabric/view/ViewShadowNode.h index 5809430df67b48..d063b0196fc319 100644 --- a/ReactCommon/fabric/view/ViewShadowNode.h +++ b/ReactCommon/fabric/view/ViewShadowNode.h @@ -7,12 +7,10 @@ #pragma once -#include -#include -#include -#include +#include + #include -#include +#include namespace facebook { namespace react { @@ -21,48 +19,14 @@ class ViewShadowNode; using SharedViewShadowNode = std::shared_ptr; -class ViewShadowNode: - public ConcreteShadowNode, - public AccessibleShadowNode, - public YogaLayoutableShadowNode { - - static_assert(std::is_base_of::value, "ViewProps must be a descendant of YogaStylableProps"); - static_assert(std::is_base_of::value, "ViewProps must be a descendant of AccessibilityProps"); +class ViewShadowNode final: + public ConcreteViewShadowNode { public: - ViewShadowNode( - const Tag &tag, - const Tag &rootTag, - const InstanceHandle &instanceHandle, - const SharedViewProps &props = ViewShadowNode::defaultSharedProps(), - const SharedShadowNodeSharedList &children = ShadowNode::emptySharedShadowNodeSharedList(), - const ShadowNodeCloneFunction &cloneFunction = nullptr - ); - ViewShadowNode( - const SharedViewShadowNode &shadowNode, - const SharedViewProps &props = nullptr, - const SharedShadowNodeSharedList &children = nullptr - ); + using ConcreteViewShadowNode::ConcreteViewShadowNode; ComponentName getComponentName() const override; - - void appendChild(const SharedShadowNode &child); - -#pragma mark - Equality - - bool operator==(const ShadowNode& rhs) const override; - -#pragma mark - DebugStringConvertible - - SharedDebugStringConvertibleList getDebugProps() const override; - -private: - -#pragma mark - LayoutableShadowNode - - SharedLayoutableShadowNodeList getLayoutableChildNodes() const override; - SharedLayoutableShadowNode cloneAndReplaceChild(const SharedLayoutableShadowNode &child) override; }; } // namespace react From 88c368b488139ad7e25aa55065fde53ef4727d30 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Thu, 26 Apr 2018 17:51:31 -0700 Subject: [PATCH 0384/1109] Fabric/Graphics: New graphic values conversion functions and type refinments Summary: Quite trivial. We need this to debug print LayoutMetrics. Reviewed By: fkgozali Differential Revision: D7607417 fbshipit-source-id: f4fa52ad04be9757545a8ac627db184f171288e5 --- .../graphics/graphicValuesConversions.cpp | 26 +++++++++++++++++-- .../graphics/graphicValuesConversions.h | 14 ++++++++-- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/ReactCommon/fabric/graphics/graphicValuesConversions.cpp b/ReactCommon/fabric/graphics/graphicValuesConversions.cpp index cfd80a4a1149d9..8a09a460f27999 100644 --- a/ReactCommon/fabric/graphics/graphicValuesConversions.cpp +++ b/ReactCommon/fabric/graphics/graphicValuesConversions.cpp @@ -7,10 +7,12 @@ #include "graphicValuesConversions.h" +#include + namespace facebook { namespace react { -SharedColor colorFromDynamic(folly::dynamic value) { +SharedColor colorFromDynamic(const folly::dynamic &value) { float red; float green; float blue; @@ -37,7 +39,7 @@ SharedColor colorFromDynamic(folly::dynamic value) { return colorFromComponents(red, green, blue, alpha); } -std::string colorNameFromColor(SharedColor value) { +std::string colorNameFromColor(const SharedColor &value) { ColorComponents components = colorComponentsFromColor(value); const float ratio = 256; return "rgba(" + @@ -47,5 +49,25 @@ std::string colorNameFromColor(SharedColor value) { folly::to(round(components.alpha * ratio)) + ")"; } +std::string stringFromPoint(const Point &point) { + return "{" + folly::to(point.x) + ", " + folly::to(point.y) + "}"; +} + +std::string stringFromSize(const Size &size) { + return "{" + folly::to(size.width) + ", " + folly::to(size.height) + "}"; +} + +std::string stringFromRect(const Rect &rect) { + return "{" + stringFromPoint(rect.origin) + ", " + stringFromSize(rect.size) + "}"; +} + +std::string stringFromEdgeInsets(const EdgeInsets &edgeInsets) { + return "{" + + folly::to(edgeInsets.left) + ", " + + folly::to(edgeInsets.top) + ", " + + folly::to(edgeInsets.right) + ", " + + folly::to(edgeInsets.bottom) + "}"; +} + } // namespace react } // namespace facebook diff --git a/ReactCommon/fabric/graphics/graphicValuesConversions.h b/ReactCommon/fabric/graphics/graphicValuesConversions.h index 8ee9e2799d35b2..99774a41fe0942 100644 --- a/ReactCommon/fabric/graphics/graphicValuesConversions.h +++ b/ReactCommon/fabric/graphics/graphicValuesConversions.h @@ -9,12 +9,22 @@ #include #include +#include namespace facebook { namespace react { -SharedColor colorFromDynamic(folly::dynamic value); -std::string colorNameFromColor(SharedColor value); +#pragma mark - Color + +SharedColor colorFromDynamic(const folly::dynamic &value); +std::string colorNameFromColor(const SharedColor &value); + +#pragma mark - Geometry + +std::string stringFromPoint(const Point &point); +std::string stringFromSize(const Size &size); +std::string stringFromRect(const Rect &rect); +std::string stringFromEdgeInsets(const EdgeInsets &edgeInsets); } // namespace react } // namespace facebook From 98b4747041fe64ff9b7c85d96d00b9530abb2828 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Thu, 26 Apr 2018 17:51:35 -0700 Subject: [PATCH 0385/1109] Fabric/View: Debug printing logic in YogaLayoutableShadowNode was moved to superclass Summary: It's more useful and consistent now because: - We print compound layout metrics from the correct storage (not from Yoga nodes); - It works fro any kind of layout now (but we still have just one); - It's much clear and straight-forward. Reviewed By: fkgozali Differential Revision: D7607422 fbshipit-source-id: 4c3cd2848e785a7f77c7f591e376d00c7c09ade9 --- .../core/layout/LayoutableShadowNode.cpp | 37 +++++++++++++++++++ .../fabric/core/layout/LayoutableShadowNode.h | 5 +++ .../fabric/view/ConcreteViewShadowNode.h | 2 +- .../view/yoga/YogaLayoutableShadowNode.cpp | 36 ------------------ .../view/yoga/YogaLayoutableShadowNode.h | 4 -- 5 files changed, 43 insertions(+), 41 deletions(-) diff --git a/ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp b/ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp index 3e2b4a0e8f7b6a..a1fd9623fb86eb 100644 --- a/ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp +++ b/ReactCommon/fabric/core/layout/LayoutableShadowNode.cpp @@ -10,6 +10,8 @@ #include #include #include +#include +#include namespace facebook { namespace react { @@ -94,5 +96,40 @@ void LayoutableShadowNode::layoutChildren(LayoutContext layoutContext) { // Default implementation does nothing. } +SharedDebugStringConvertibleList LayoutableShadowNode::getDebugProps() const { + SharedDebugStringConvertibleList list = {}; + + if (getHasNewLayout()) { + list.push_back(std::make_shared("hasNewLayout")); + } + + if (!getIsLayoutClean()) { + list.push_back(std::make_shared("dirty")); + } + + LayoutMetrics layoutMetrics = getLayoutMetrics(); + LayoutMetrics defaultLayoutMetrics = LayoutMetrics(); + + list.push_back(std::make_shared("frame", stringFromRect(layoutMetrics.frame))); + + if (layoutMetrics.borderWidth != defaultLayoutMetrics.borderWidth) { + list.push_back(std::make_shared("borderWidth", stringFromEdgeInsets(layoutMetrics.borderWidth))); + } + + if (layoutMetrics.contentInsets != defaultLayoutMetrics.contentInsets) { + list.push_back(std::make_shared("contentInsets", stringFromEdgeInsets(layoutMetrics.contentInsets))); + } + + if (layoutMetrics.displayType == DisplayType::None) { + list.push_back(std::make_shared("hidden")); + } + + if (layoutMetrics.layoutDirection == LayoutDirection::RightToLeft) { + list.push_back(std::make_shared("rtl")); + } + + return list; +} + } // namespace react } // namespace facebook diff --git a/ReactCommon/fabric/core/layout/LayoutableShadowNode.h b/ReactCommon/fabric/core/layout/LayoutableShadowNode.h index d1c9ce1d6a3e7f..d664498779dca3 100644 --- a/ReactCommon/fabric/core/layout/LayoutableShadowNode.h +++ b/ReactCommon/fabric/core/layout/LayoutableShadowNode.h @@ -13,6 +13,7 @@ #include #include +#include namespace facebook { namespace react { @@ -102,6 +103,10 @@ class LayoutableShadowNode: */ virtual bool setLayoutMetrics(LayoutMetrics layoutMetrics); +#pragma mark - DebugStringConvertible + + SharedDebugStringConvertibleList getDebugProps() const; + private: LayoutMetrics layoutMetrics_ {}; bool hasNewLayout_ {false}; diff --git a/ReactCommon/fabric/view/ConcreteViewShadowNode.h b/ReactCommon/fabric/view/ConcreteViewShadowNode.h index 320fbb0d4eb5e4..a6994fe3e23276 100644 --- a/ReactCommon/fabric/view/ConcreteViewShadowNode.h +++ b/ReactCommon/fabric/view/ConcreteViewShadowNode.h @@ -138,7 +138,7 @@ class ConcreteViewShadowNode: auto basePropsList = ShadowNode::getDebugProps(); std::move(basePropsList.begin(), basePropsList.end(), std::back_inserter(list)); - list.push_back(std::make_shared("layout", "", YogaLayoutableShadowNode::getDebugProps())); + list.push_back(std::make_shared("layout", "", LayoutableShadowNode::getDebugProps())); return list; } diff --git a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp index 2851fa4d985b64..2b6a6e233ef31e 100644 --- a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp +++ b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp @@ -130,42 +130,6 @@ void YogaLayoutableShadowNode::layoutChildren(LayoutContext layoutContext) { } } -#pragma mark - DebugStringConvertible - -SharedDebugStringConvertibleList YogaLayoutableShadowNode::getDebugProps() const { - // TODO: Move to the base class and return `layoutMetrics` instead. - - SharedDebugStringConvertibleList list = {}; - - if (getHasNewLayout()) { - list.push_back(std::make_shared("hasNewLayout")); - } - - YGLayout defaultYogaLayout = YGLayout(); - defaultYogaLayout.direction = YGDirectionLTR; - YGLayout currentYogaLayout = std::const_pointer_cast(yogaNode_)->getLayout(); - -#define YOGA_LAYOUT_PROPS_ADD_TO_SET(stringName, propertyName, accessor, convertor) \ - { \ - auto currentValueString = convertor(currentYogaLayout.propertyName accessor); \ - auto defaultValueString = convertor(defaultYogaLayout.propertyName accessor); \ - if (currentValueString != defaultValueString) { \ - list.push_back(std::make_shared(#stringName, currentValueString)); \ - } \ - } - - YOGA_LAYOUT_PROPS_ADD_TO_SET(position, position, , stringFromYogaPosition) - YOGA_LAYOUT_PROPS_ADD_TO_SET(dimensions, dimensions, , stringFromYogaDimensions) - YOGA_LAYOUT_PROPS_ADD_TO_SET(margin, margin, , stringFromYogaEdges) - YOGA_LAYOUT_PROPS_ADD_TO_SET(border, border, , stringFromYogaEdges) - YOGA_LAYOUT_PROPS_ADD_TO_SET(padding, padding, , stringFromYogaEdges) - YOGA_LAYOUT_PROPS_ADD_TO_SET(direction, direction, , stringFromYogaStyleDirection) - - return list; -} - -#pragma mark - Helpers - #pragma mark - Yoga Connectors YGNode *YogaLayoutableShadowNode::yogaNodeCloneCallbackConnector(YGNode *oldYogaNode, YGNode *parentYogaNode, int childIndex) { diff --git a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.h b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.h index 15f25cdf4043ec..8b367e5e9e3ca1 100644 --- a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.h +++ b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.h @@ -76,10 +76,6 @@ class YogaLayoutableShadowNode: void layoutChildren(LayoutContext layoutContext) override; -#pragma mark - DebugStringConvertible - - SharedDebugStringConvertibleList getDebugProps() const override; - private: mutable SharedYogaNode yogaNode_; From 3428808b97bf8390d802d7863295d8625fbda64a Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Thu, 26 Apr 2018 17:51:39 -0700 Subject: [PATCH 0386/1109] Fabric: Using view name argument in `FabricUIManager.createNode()` Summary: We are going to have not only component soon! Reviewed By: mdvacca Differential Revision: D7738579 fbshipit-source-id: 5165762b98d94f74d40d016722be36a04d45f264 --- ReactCommon/fabric/uimanager/FabricUIManager.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/ReactCommon/fabric/uimanager/FabricUIManager.cpp b/ReactCommon/fabric/uimanager/FabricUIManager.cpp index 2020732831211f..dc73808f4c3dd9 100644 --- a/ReactCommon/fabric/uimanager/FabricUIManager.cpp +++ b/ReactCommon/fabric/uimanager/FabricUIManager.cpp @@ -38,6 +38,16 @@ static const RawProps rawPropsFromDynamic(const folly::dynamic object) { return result; } +static const std::string componentNameByReactViewName(std::string viewName) { + std::string rctPrefix("RCT"); + if (std::mismatch(rctPrefix.begin(), rctPrefix.end(), viewName.begin()).first == rctPrefix.end()) { + // If `viewName` has "RCT" prefix, remove it. + viewName.erase(0, 3); + } + + return viewName; +} + FabricUIManager::FabricUIManager(SharedComponentDescriptorRegistry componentDescriptorRegistry) { componentDescriptorRegistry_ = componentDescriptorRegistry; } @@ -52,7 +62,9 @@ UIManagerDelegate *FabricUIManager::getDelegate() { SharedShadowNode FabricUIManager::createNode(int tag, std::string viewName, int rootTag, folly::dynamic props, void *instanceHandle) { LOG(INFO) << "FabricUIManager::createNode(tag: " << tag << ", name: " << viewName << ", rootTag" << rootTag << ", props: " << props << ")"; - const SharedComponentDescriptor &componentDescriptor = (*componentDescriptorRegistry_)["View"]; + + ComponentName componentName = componentNameByReactViewName(viewName); + const SharedComponentDescriptor &componentDescriptor = (*componentDescriptorRegistry_)[componentName]; RawProps rawProps = rawPropsFromDynamic(props); SharedShadowNode shadowNode = From 6aa52f2684301ee2fd5afa192c6790b426cf0d6a Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Thu, 26 Apr 2018 17:51:41 -0700 Subject: [PATCH 0387/1109] Fabric: Using a proper Component Descriptor for node cloning Summary: To clone a ShadowNode we must use node's ComponentDescriptot, not parent node's one. Reviewed By: mdvacca Differential Revision: D7738583 fbshipit-source-id: 83656f9a761530cdaedf65663ae28b3119af75f5 --- .../core/componentdescriptor/ConcreteComponentDescriptor.h | 1 + ReactCommon/fabric/uimanager/FabricUIManager.cpp | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ReactCommon/fabric/core/componentdescriptor/ConcreteComponentDescriptor.h b/ReactCommon/fabric/core/componentdescriptor/ConcreteComponentDescriptor.h index 2e2ee37fd2082c..11b82b32feb345 100644 --- a/ReactCommon/fabric/core/componentdescriptor/ConcreteComponentDescriptor.h +++ b/ReactCommon/fabric/core/componentdescriptor/ConcreteComponentDescriptor.h @@ -81,6 +81,7 @@ class ConcreteComponentDescriptor: public ComponentDescriptor { ShadowNodeCloneFunction getCloneFunction() const { if (!cloneFunction_) { cloneFunction_ = [this](const SharedShadowNode &shadowNode, const SharedProps &props, const SharedShadowNodeSharedList &children) { + assert(std::dynamic_pointer_cast(shadowNode)); return this->cloneShadowNode(shadowNode, props, children); }; } diff --git a/ReactCommon/fabric/uimanager/FabricUIManager.cpp b/ReactCommon/fabric/uimanager/FabricUIManager.cpp index dc73808f4c3dd9..3b8786b29889ec 100644 --- a/ReactCommon/fabric/uimanager/FabricUIManager.cpp +++ b/ReactCommon/fabric/uimanager/FabricUIManager.cpp @@ -151,7 +151,8 @@ void FabricUIManager::appendChild(const SharedShadowNode &parentShadowNode, cons // TODO: Remove this after we move this to JS side. if (childShadowNode->getSealed()) { - auto clonedChildShadowNode = componentDescriptor->cloneShadowNode(childShadowNode); + auto childComponentDescriptor = (*componentDescriptorRegistry_)[childShadowNode]; + auto clonedChildShadowNode = childComponentDescriptor->cloneShadowNode(childShadowNode); auto nonConstClonedChildShadowNode = std::const_pointer_cast(clonedChildShadowNode); nonConstClonedChildShadowNode->shallowSourceNode(); componentDescriptor->appendChild(parentShadowNode, clonedChildShadowNode); From 139db66a3ed5ac55f71173d99428d8a656e4d6a3 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Thu, 26 Apr 2018 17:51:44 -0700 Subject: [PATCH 0388/1109] Fabric: More graphic values conversions from dynamic type Summary: Trivial. Reviewed By: mdvacca Differential Revision: D7738578 fbshipit-source-id: 3112e523dd1cdceff90a8596033f9516aa2c8156 --- .../graphics/graphicValuesConversions.cpp | 18 ++++++++++++++++++ .../fabric/graphics/graphicValuesConversions.h | 4 ++++ 2 files changed, 22 insertions(+) diff --git a/ReactCommon/fabric/graphics/graphicValuesConversions.cpp b/ReactCommon/fabric/graphics/graphicValuesConversions.cpp index 8a09a460f27999..85909b3a01cd8b 100644 --- a/ReactCommon/fabric/graphics/graphicValuesConversions.cpp +++ b/ReactCommon/fabric/graphics/graphicValuesConversions.cpp @@ -69,5 +69,23 @@ std::string stringFromEdgeInsets(const EdgeInsets &edgeInsets) { folly::to(edgeInsets.bottom) + "}"; } +Float floatFromDynamic(const folly::dynamic &value) { + return value.asDouble(); +} + +Point pointFromDynamic(const folly::dynamic &value) { + if (value.isArray()) { + return Point {(Float)value[0].asDouble(), (Float)value[1].asDouble()}; + } + abort(); +} + +Size sizeFromDynamic(const folly::dynamic &value) { + if (value.isArray()) { + return Size {(Float)value[0].asDouble(), (Float)value[1].asDouble()}; + } + abort(); +} + } // namespace react } // namespace facebook diff --git a/ReactCommon/fabric/graphics/graphicValuesConversions.h b/ReactCommon/fabric/graphics/graphicValuesConversions.h index 99774a41fe0942..7d49cdf970589a 100644 --- a/ReactCommon/fabric/graphics/graphicValuesConversions.h +++ b/ReactCommon/fabric/graphics/graphicValuesConversions.h @@ -26,5 +26,9 @@ std::string stringFromSize(const Size &size); std::string stringFromRect(const Rect &rect); std::string stringFromEdgeInsets(const EdgeInsets &edgeInsets); +Float floatFromDynamic(const folly::dynamic &value); +Point pointFromDynamic(const folly::dynamic &value); +Size sizeFromDynamic(const folly::dynamic &value); + } // namespace react } // namespace facebook From 9d08e2afaef0081cccff69cf292f251c7015f582 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Thu, 26 Apr 2018 17:51:46 -0700 Subject: [PATCH 0389/1109] Fabric: Using `ColorComponents` in `colorFromComponents` function Summary: Trivial. We have a special data structure for it, why do not use it here? Reviewed By: mdvacca Differential Revision: D7738577 fbshipit-source-id: 750aa649b06f17d27906d44df07172a907cde2e5 --- ReactCommon/fabric/graphics/Color.cpp | 12 +++++++++--- ReactCommon/fabric/graphics/Color.h | 2 +- .../fabric/graphics/graphicValuesConversions.cpp | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/ReactCommon/fabric/graphics/Color.cpp b/ReactCommon/fabric/graphics/Color.cpp index ba6c897b49320d..151e2923a403ed 100644 --- a/ReactCommon/fabric/graphics/Color.cpp +++ b/ReactCommon/fabric/graphics/Color.cpp @@ -13,11 +13,17 @@ namespace facebook { namespace react { -SharedColor colorFromComponents(float red, float green, float blue, float alpha) { - const CGFloat components[] = {red, green, blue, alpha}; +SharedColor colorFromComponents(ColorComponents components) { + const CGFloat componentsArray[] = { + components.red, + components.green, + components.blue, + components.alpha + }; + CGColorRef color = CGColorCreate( CGColorSpaceCreateDeviceRGB(), - components + componentsArray ); return SharedColor(color, CFRelease); diff --git a/ReactCommon/fabric/graphics/Color.h b/ReactCommon/fabric/graphics/Color.h index 0a84e7b3a97090..f7622d213bae40 100644 --- a/ReactCommon/fabric/graphics/Color.h +++ b/ReactCommon/fabric/graphics/Color.h @@ -23,7 +23,7 @@ struct ColorComponents { float alpha {0}; }; -SharedColor colorFromComponents(float red, float green, float blue, float alpha); +SharedColor colorFromComponents(ColorComponents components); ColorComponents colorComponentsFromColor(SharedColor color); } // namespace react diff --git a/ReactCommon/fabric/graphics/graphicValuesConversions.cpp b/ReactCommon/fabric/graphics/graphicValuesConversions.cpp index 85909b3a01cd8b..874c70b69045c0 100644 --- a/ReactCommon/fabric/graphics/graphicValuesConversions.cpp +++ b/ReactCommon/fabric/graphics/graphicValuesConversions.cpp @@ -36,7 +36,7 @@ SharedColor colorFromDynamic(const folly::dynamic &value) { abort(); } - return colorFromComponents(red, green, blue, alpha); + return colorFromComponents({red, green, blue, alpha}); } std::string colorNameFromColor(const SharedColor &value) { From 368388bfc88f42cadecc21923767c0c7a1f72712 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Thu, 26 Apr 2018 17:51:49 -0700 Subject: [PATCH 0390/1109] Fabric: Introducing `LocalData` concept Summary: LocalData might be used to communicate some infomation between `ShadowNode`s and native component views. We will use it soon to store (and transmit to mounting layer) prepared for rendering attributed text in Text component. Reviewed By: mdvacca Differential Revision: D7738582 fbshipit-source-id: 1ead23ffd105cce0b3d9aeb9fc1d0df47673be50 --- .../fabric/core/shadownode/LocalData.h | 36 +++++++++++++++++++ .../fabric/core/shadownode/ShadowNode.cpp | 13 ++++++- .../fabric/core/shadownode/ShadowNode.h | 19 +++++++++- .../fabric/core/tests/ShadowNodeTest.cpp | 29 +++++++++++++++ ReactCommon/fabric/core/tests/TestComponent.h | 15 ++++++++ 5 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 ReactCommon/fabric/core/shadownode/LocalData.h diff --git a/ReactCommon/fabric/core/shadownode/LocalData.h b/ReactCommon/fabric/core/shadownode/LocalData.h new file mode 100644 index 00000000000000..8b5b0fca093b7e --- /dev/null +++ b/ReactCommon/fabric/core/shadownode/LocalData.h @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 LocalData; + +using SharedLocalData = std::shared_ptr; + +/* + * Abstract class for any kind of concrete pieces of local data specific for + * some kinds of `ShadowNode`s. + * LocalData might be used to communicate some infomation between `ShadowNode`s + * and native component views. + * All `LocalData` objects *must* be immutable (sealed) when they became + * a part of the shadow tree. + */ +class LocalData: + public Sealable, + public DebugStringConvertible { + + // Nothing. +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp index f1272c32696fbf..b4883c22f4d8be 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp @@ -47,6 +47,7 @@ ShadowNode::ShadowNode( props_(props ? props : shadowNode->props_), children_(std::make_shared(*(children ? children : shadowNode->children_))), sourceNode_(shadowNode), + localData_(shadowNode->localData_), cloneFunction_(shadowNode->cloneFunction_), revision_(shadowNode->revision_ + 1) {} @@ -84,6 +85,10 @@ SharedShadowNode ShadowNode::getSourceNode() const { return sourceNode_.lock(); } +SharedLocalData ShadowNode::getLocalData() const { + return localData_; +} + void ShadowNode::sealRecursive() const { if (getSealed()) { return; @@ -119,6 +124,11 @@ void ShadowNode::clearSourceNode() { sourceNode_.reset(); } +void ShadowNode::setLocalData(const SharedLocalData &localData) { + ensureUnsealed(); + localData_ = localData; +} + void ShadowNode::shallowSourceNode() { ensureUnsealed(); @@ -135,7 +145,8 @@ bool ShadowNode::operator==(const ShadowNode& rhs) const { return tag_ == rhs.tag_ && rootTag_ == rhs.rootTag_ && - props_ == rhs.props_; + props_ == rhs.props_ && + localData_ == rhs.localData_; } bool ShadowNode::operator!=(const ShadowNode& rhs) const { diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.h b/ReactCommon/fabric/core/shadownode/ShadowNode.h index e83e6227634221..9cad65eadfb915 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.h +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.h @@ -11,9 +11,10 @@ #include #include +#include #include -#include #include +#include #include namespace facebook { @@ -80,6 +81,14 @@ class ShadowNode: */ SharedShadowNode getSourceNode() const; + /* + * Returns a local data associated with the node. + * `LocalData` object might be used for data exchange between native view and + * shadow node instances. + * Concrete type of the object depends on concrete type of the `ShadowNode`. + */ + SharedLocalData getLocalData() const; + void sealRecursive() const; #pragma mark - Mutating Methods @@ -88,11 +97,18 @@ class ShadowNode: void replaceChild(const SharedShadowNode &oldChild, const SharedShadowNode &newChild); void clearSourceNode(); + /* + * Sets local data assosiated with the node. + * The node must be unsealed at this point. + */ + void setLocalData(const SharedLocalData &localData); + /* * Replaces the current source node with its source node. * This method might be used for illuminating side-effects caused by the last * cloning operation which are not desirable from the diffing algorithm * perspective. + * The node must be unsealed at this point. */ void shallowSourceNode(); @@ -122,6 +138,7 @@ class ShadowNode: SharedProps props_; SharedShadowNodeSharedList children_; WeakShadowNode sourceNode_; + SharedLocalData localData_; private: diff --git a/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp b/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp index 8c8204684b7813..7a945bf40fb1bc 100644 --- a/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp +++ b/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp @@ -150,3 +150,32 @@ TEST(ShadowNodeTest, handleCloneFunction) { ASSERT_EQ(secondNode->getRootTag(), secondNodeClone->getRootTag()); ASSERT_EQ(secondNode->getProps(), secondNodeClone->getProps()); } + +TEST(ShadowNodeTest, handleLocalData) { + auto localData42 = std::make_shared(); + localData42->setNumber(42); + + auto anotherLocalData42 = std::make_shared(); + anotherLocalData42->setNumber(42); + + auto localDataOver9000 = std::make_shared(); + localDataOver9000->setNumber(9001); + + auto firstNode = std::make_shared(9, 1, (void *)NULL); + auto secondNode = std::make_shared(9, 1, (void *)NULL); + auto thirdNode = std::make_shared(9, 1, (void *)NULL); + + firstNode->setLocalData(localData42); + secondNode->setLocalData(localData42); + thirdNode->setLocalData(localDataOver9000); + + // LocalData object are compared by pointer, not by value. + ASSERT_EQ(*firstNode, *secondNode); + ASSERT_NE(*firstNode, *thirdNode); + secondNode->setLocalData(anotherLocalData42); + ASSERT_NE(*firstNode, *secondNode); + + // LocalData cannot be changed for sealed shadow node. + secondNode->sealRecursive(); + ASSERT_ANY_THROW(secondNode->setLocalData(localDataOver9000)); +} diff --git a/ReactCommon/fabric/core/tests/TestComponent.h b/ReactCommon/fabric/core/tests/TestComponent.h index 18890daeb03dd5..87372ffea8c2b7 100644 --- a/ReactCommon/fabric/core/tests/TestComponent.h +++ b/ReactCommon/fabric/core/tests/TestComponent.h @@ -11,6 +11,7 @@ #include #include +#include #include using namespace facebook::react; @@ -20,6 +21,20 @@ using namespace facebook::react; * To be used for testing purpose. */ +class TestLocalData: public LocalData { +public: + void setNumber(const int &number) { + number_ = number; + } + + int getNumber() const { + return number_; + } + +private: + int number_ {0}; +}; + class TestProps : public Props { public: TestProps() { From 9f46f425f4809d0a266f350a2e8a34bdef4fda1f Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Thu, 26 Apr 2018 17:51:52 -0700 Subject: [PATCH 0391/1109] Fabric: Managing `LocalData` instances in mounting pipeline Summary: Managing and transmitting LocalData object to native views. Reviewed By: mdvacca Differential Revision: D7738580 fbshipit-source-id: c889da58d3afe7ac14f411576afe659bd079f641 --- .../MountItems/RCTUpdateLocalDataMountItem.h | 27 +++++++++++++ .../MountItems/RCTUpdateLocalDataMountItem.mm | 39 +++++++++++++++++++ .../Mounting/RCTComponentViewProtocol.h | 9 +++++ React/Fabric/Mounting/RCTMountingManager.mm | 17 ++++++++ .../Mounting/UIView+ComponentViewProtocol.h | 3 ++ .../Mounting/UIView+ComponentViewProtocol.mm | 6 +++ 6 files changed, 101 insertions(+) create mode 100644 React/Fabric/Mounting/MountItems/RCTUpdateLocalDataMountItem.h create mode 100644 React/Fabric/Mounting/MountItems/RCTUpdateLocalDataMountItem.mm diff --git a/React/Fabric/Mounting/MountItems/RCTUpdateLocalDataMountItem.h b/React/Fabric/Mounting/MountItems/RCTUpdateLocalDataMountItem.h new file mode 100644 index 00000000000000..b5aedcadecd125 --- /dev/null +++ b/React/Fabric/Mounting/MountItems/RCTUpdateLocalDataMountItem.h @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * Updates local data of a component view. + */ +@interface RCTUpdateLocalDataMountItem : NSObject + +- (instancetype)initWithTag:(ReactTag)tag + oldLocalData:(facebook::react::SharedLocalData)oldLocalData + newLocalData:(facebook::react::SharedLocalData)newLocalData; + +@end + +NS_ASSUME_NONNULL_END diff --git a/React/Fabric/Mounting/MountItems/RCTUpdateLocalDataMountItem.mm b/React/Fabric/Mounting/MountItems/RCTUpdateLocalDataMountItem.mm new file mode 100644 index 00000000000000..c10bc3c4b40f8f --- /dev/null +++ b/React/Fabric/Mounting/MountItems/RCTUpdateLocalDataMountItem.mm @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTUpdateLocalDataMountItem.h" + +#import "RCTComponentViewRegistry.h" + +using namespace facebook::react; + +@implementation RCTUpdateLocalDataMountItem { + ReactTag _tag; + SharedLocalData _oldLocalData; + SharedLocalData _newLocalData; +} + +- (instancetype)initWithTag:(ReactTag)tag + oldLocalData:(facebook::react::SharedLocalData)oldLocalData + newLocalData:(facebook::react::SharedLocalData)newLocalData +{ + if (self = [super init]) { + _tag = tag; + _oldLocalData = oldLocalData; + _newLocalData = newLocalData; + } + + return self; +} + +- (void)executeWithRegistry:(RCTComponentViewRegistry *)registry +{ + UIView *componentView = [registry componentViewByTag:_tag]; + [componentView updateLocalData:_newLocalData oldLocalData:_oldLocalData]; +} + +@end diff --git a/React/Fabric/Mounting/RCTComponentViewProtocol.h b/React/Fabric/Mounting/RCTComponentViewProtocol.h index d23ac72adfef53..fc56aa7e08e9f4 100644 --- a/React/Fabric/Mounting/RCTComponentViewProtocol.h +++ b/React/Fabric/Mounting/RCTComponentViewProtocol.h @@ -7,6 +7,7 @@ #import +#import #import #import #import @@ -44,6 +45,14 @@ NS_ASSUME_NONNULL_BEGIN - (void)updateProps:(facebook::react::SharedProps)props oldProps:(facebook::react::SharedProps)oldProps; +/* + * Called for updating component's local data. + * Receiver must update native view props accordingly changed local data. + */ +- (void)updateLocalData:(facebook::react::SharedLocalData)localData + oldLocalData:(facebook::react::SharedLocalData)oldLocalData; + + /* * Called for updating component's layout metrics. * Receiver must update `UIView` layout-related fields (such as `frame`, diff --git a/React/Fabric/Mounting/RCTMountingManager.mm b/React/Fabric/Mounting/RCTMountingManager.mm index 5f16ac2513dce2..5b7e7f1311d561 100644 --- a/React/Fabric/Mounting/RCTMountingManager.mm +++ b/React/Fabric/Mounting/RCTMountingManager.mm @@ -20,6 +20,7 @@ #import "RCTInsertMountItem.h" #import "RCTRemoveMountItem.h" #import "RCTUpdatePropsMountItem.h" +#import "RCTUpdateLocalDataMountItem.h" #import "RCTUpdateLayoutMetricsMountItem.h" using namespace facebook::react; @@ -74,6 +75,13 @@ - (void)mutateComponentViewTreeWithMutationInstructions:(facebook::react::TreeMu oldProps:nullptr newProps:instruction.getNewChildNode()->getProps()]]; + // LocalData + if (instruction.getNewChildNode()->getLocalData()) { + [mountItems addObject:[[RCTUpdateLocalDataMountItem alloc] initWithTag:instruction.getNewChildNode()->getTag() + oldLocalData:nullptr + newLocalData:instruction.getNewChildNode()->getLocalData()]]; + } + // Layout SharedLayoutableShadowNode layoutableNewShadowNode = std::dynamic_pointer_cast(instruction.getNewChildNode()); @@ -108,6 +116,15 @@ - (void)mutateComponentViewTreeWithMutationInstructions:(facebook::react::TreeMu [mountItems addObject:mountItem]; } + // LocalData + if (oldShadowNode->getLocalData() != newShadowNode->getLocalData()) { + RCTUpdateLocalDataMountItem *mountItem = + [[RCTUpdateLocalDataMountItem alloc] initWithTag:newShadowNode->getTag() + oldLocalData:oldShadowNode->getLocalData() + newLocalData:newShadowNode->getLocalData()]; + [mountItems addObject:mountItem]; + } + // Layout SharedLayoutableShadowNode layoutableOldShadowNode = std::dynamic_pointer_cast(oldShadowNode); diff --git a/React/Fabric/Mounting/UIView+ComponentViewProtocol.h b/React/Fabric/Mounting/UIView+ComponentViewProtocol.h index b38b41ba5cfb75..cffe51a2f85116 100644 --- a/React/Fabric/Mounting/UIView+ComponentViewProtocol.h +++ b/React/Fabric/Mounting/UIView+ComponentViewProtocol.h @@ -25,6 +25,9 @@ NS_ASSUME_NONNULL_BEGIN - (void)updateProps:(facebook::react::SharedProps)props oldProps:(facebook::react::SharedProps)oldProps; +- (void)updateLocalData:(facebook::react::SharedLocalData)localData + oldLocalData:(facebook::react::SharedLocalData)oldLocalData; + - (void)updateLayoutMetrics:(facebook::react::LayoutMetrics)layoutMetrics oldLayoutMetrics:(facebook::react::LayoutMetrics)oldLayoutMetrics; diff --git a/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm b/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm index 93b5784e3d92c0..1a4136cfd5117e 100644 --- a/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm +++ b/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm @@ -30,6 +30,12 @@ - (void)updateProps:(facebook::react::SharedProps)props // Default implementation does nothing. } +- (void)updateLocalData:(facebook::react::SharedLocalData)localData + oldLocalData:(facebook::react::SharedLocalData)oldLocalData +{ + // Default implementation does nothing. +} + - (void)updateLayoutMetrics:(facebook::react::LayoutMetrics)layoutMetrics oldLayoutMetrics:(facebook::react::LayoutMetrics)oldLayoutMetrics { From 6bbc2ec921597ec26e68a41278e3514f88b9bb12 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Thu, 26 Apr 2018 17:51:54 -0700 Subject: [PATCH 0392/1109] Fabric: Introcucing `ConcreteComponentDescriptor::adopt()` Summary: Overriding `adopt` method allows subclasses to configure just created or cloned shadow nodes without overriding `create` and `clone` methods. Reviewed By: mdvacca Differential Revision: D7738581 fbshipit-source-id: bfe4e4e2d3d448591a3267b5ea7ca4e0800f5ba0 --- .../ConcreteComponentDescriptor.h | 18 +++++++++++++++--- .../core/shadownode/ConcreteShadowNode.h | 3 +++ .../fabric/core/shadownode/ShadowNode.h | 1 + 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/ReactCommon/fabric/core/componentdescriptor/ConcreteComponentDescriptor.h b/ReactCommon/fabric/core/componentdescriptor/ConcreteComponentDescriptor.h index 11b82b32feb345..f690cb652f7b12 100644 --- a/ReactCommon/fabric/core/componentdescriptor/ConcreteComponentDescriptor.h +++ b/ReactCommon/fabric/core/componentdescriptor/ConcreteComponentDescriptor.h @@ -41,7 +41,7 @@ class ConcreteComponentDescriptor: public ComponentDescriptor { const InstanceHandle &instanceHandle, const SharedProps &props ) const override { - return std::make_shared( + UnsharedShadowNode shadowNode = std::make_shared( tag, rootTag, instanceHandle, @@ -49,14 +49,19 @@ class ConcreteComponentDescriptor: public ComponentDescriptor { ShadowNode::emptySharedShadowNodeSharedList(), getCloneFunction() ); + adopt(shadowNode); + return shadowNode; } SharedShadowNode cloneShadowNode( - const SharedShadowNode &shadowNode, + const SharedShadowNode &sourceShadowNode, const SharedProps &props = nullptr, const SharedShadowNodeSharedList &children = nullptr ) const override { - return std::make_shared(std::static_pointer_cast(shadowNode), std::static_pointer_cast(props), children); + assert(std::dynamic_pointer_cast(sourceShadowNode)); + UnsharedShadowNode shadowNode = std::make_shared(std::static_pointer_cast(sourceShadowNode), std::static_pointer_cast(props), children); + adopt(shadowNode); + return shadowNode; } void appendChild( @@ -75,7 +80,14 @@ class ConcreteComponentDescriptor: public ComponentDescriptor { return ShadowNodeT::Props(rawProps, props); }; +protected: + + virtual void adopt(UnsharedShadowNode shadowNode) const { + // Default implementation does nothing. + } + private: + mutable ShadowNodeCloneFunction cloneFunction_; ShadowNodeCloneFunction getCloneFunction() const { diff --git a/ReactCommon/fabric/core/shadownode/ConcreteShadowNode.h b/ReactCommon/fabric/core/shadownode/ConcreteShadowNode.h index 9a18cf7e1edc00..aca5fc32bea853 100644 --- a/ReactCommon/fabric/core/shadownode/ConcreteShadowNode.h +++ b/ReactCommon/fabric/core/shadownode/ConcreteShadowNode.h @@ -36,6 +36,7 @@ class ConcreteShadowNode: public ShadowNode { } auto concreteBaseProps = std::dynamic_pointer_cast(baseProps); + assert(concreteBaseProps); auto props = std::make_shared(*concreteBaseProps); props->apply(rawProps); return props; @@ -79,6 +80,8 @@ class ConcreteShadowNode: public ShadowNode { } const SharedConcreteProps getProps() const { + assert(std::dynamic_pointer_cast(props_)); + return std::static_pointer_cast(props_); } diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.h b/ReactCommon/fabric/core/shadownode/ShadowNode.h index 9cad65eadfb915..fec74d3ab9dd9a 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.h +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.h @@ -23,6 +23,7 @@ namespace react { class ShadowNode; using SharedShadowNode = std::shared_ptr; +using UnsharedShadowNode = std::shared_ptr; using SharedShadowNodeList = std::vector>; using SharedShadowNodeSharedList = std::shared_ptr; using SharedShadowNodeUnsharedList = std::shared_ptr; From f8ab0e0b08da5a2318a6a583983ab4dc9b0867a0 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Thu, 26 Apr 2018 17:51:57 -0700 Subject: [PATCH 0393/1109] Fabric: YogaLayoutableShadowNode::enableMeasurement() enables custom measuring for Yoga based shadow nodes Summary: YogaLayoutableShadowNode::enableMeasurement() connects Yoga's measuring API and Fabric measuring API. `enableMeasurement` should be called for leaf Yoga nodes with custom content which should be measured manually during layout. Reviewed By: mdvacca Differential Revision: D7738574 fbshipit-source-id: ffe883905c4809290d4d973ad29dc5f0e1ec7573 --- ReactCommon/fabric/graphics/Geometry.h | 3 ++ .../view/yoga/YogaLayoutableShadowNode.cpp | 46 +++++++++++++++++++ .../view/yoga/YogaLayoutableShadowNode.h | 7 +++ 3 files changed, 56 insertions(+) diff --git a/ReactCommon/fabric/graphics/Geometry.h b/ReactCommon/fabric/graphics/Geometry.h index 6c2b0f041fae96..00efbe62f2aca3 100644 --- a/ReactCommon/fabric/graphics/Geometry.h +++ b/ReactCommon/fabric/graphics/Geometry.h @@ -20,6 +20,9 @@ using Float = CGFloat; */ const Float kFloatUndefined = CGFLOAT_MAX; +const Float kFloatMax = CGFLOAT_MAX; +const Float kFloatMin = CGFLOAT_MIN; + /* * Point */ diff --git a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp index 2b6a6e233ef31e..d91def613c2d67 100644 --- a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp +++ b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include "yogaValuesConversions.h" @@ -90,6 +91,12 @@ void YogaLayoutableShadowNode::setHasNewLayout(bool hasNewLayout) { #pragma mark - Mutating Methods +void YogaLayoutableShadowNode::enableMeasurement() { + ensureUnsealed(); + + yogaNode_->setMeasureFunc(YogaLayoutableShadowNode::yogaNodeMeasureCallbackConnector); +} + void YogaLayoutableShadowNode::appendChild(SharedYogaLayoutableShadowNode child) { ensureUnsealed(); @@ -164,6 +171,45 @@ YGNode *YogaLayoutableShadowNode::yogaNodeCloneCallbackConnector(YGNode *oldYoga return newShadowNode->yogaNode_.get(); } +YGSize YogaLayoutableShadowNode::yogaNodeMeasureCallbackConnector(YGNode *yogaNode, float width, YGMeasureMode widthMode, float height, YGMeasureMode heightMode) { + YogaLayoutableShadowNode *shadowNodeRawPtr = (YogaLayoutableShadowNode *)yogaNode->getContext(); + assert(shadowNodeRawPtr); + + Size minimumSize = Size {0, 0}; + Size maximumSize = Size {kFloatMax, kFloatMax}; + + switch (widthMode) { + case YGMeasureModeUndefined: + break; + case YGMeasureModeExactly: + minimumSize.width = fabricFloatFromYogaFloat(width); + maximumSize.width = fabricFloatFromYogaFloat(width); + break; + case YGMeasureModeAtMost: + maximumSize.width = fabricFloatFromYogaFloat(width); + break; + } + + switch (heightMode) { + case YGMeasureModeUndefined: + break; + case YGMeasureModeExactly: + minimumSize.height = fabricFloatFromYogaFloat(height); + maximumSize.height = fabricFloatFromYogaFloat(height); + break; + case YGMeasureModeAtMost: + maximumSize.height = fabricFloatFromYogaFloat(height); + break; + } + + Size size = shadowNodeRawPtr->measure(LayoutConstraints {minimumSize, maximumSize}); + + return YGSize { + yogaFloatFromFabricFloat(size.width), + yogaFloatFromFabricFloat(size.height) + }; +} + void YogaLayoutableShadowNode::setYogaNodeChildrenBasedOnShadowNodeChildren(YGNode &yogaNode, const SharedShadowNodeSharedList &children) { auto yogaNodeChildren = YGVector(); diff --git a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.h b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.h index 8b367e5e9e3ca1..0d00a3f3690ba3 100644 --- a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.h +++ b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.h @@ -54,6 +54,12 @@ class YogaLayoutableShadowNode: #pragma mark - Mutating Methods + /* + * Connects `measureFunc` function of Yoga node with + * `LayoutableShadowNode::measure()` method. + */ + void enableMeasurement(); + /* * Appends `child`'s Yoga node to the own Yoga node. * So, it complements `ShadowNode::appendChild(...)` functionality from Yoga @@ -82,6 +88,7 @@ class YogaLayoutableShadowNode: static SharedYogaConfig suitableYogaConfig(); static void setYogaNodeChildrenBasedOnShadowNodeChildren(YGNode &yogaNode, const SharedShadowNodeSharedList &children); static YGNode *yogaNodeCloneCallbackConnector(YGNode *oldYogaNode, YGNode *parentYogaNode, int childIndex); + static YGSize yogaNodeMeasureCallbackConnector(YGNode *yogaNode, float width, YGMeasureMode widthMode, float height, YGMeasureMode heightMode); }; } // namespace react From edc6cb571110592b7aa0378b852da6e417d3a28c Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Thu, 26 Apr 2018 17:51:59 -0700 Subject: [PATCH 0394/1109] Fabric: New, much fancier, approach to parse dynamic props Summary: The new approach uses C++ overloading feature instead of specifying exact types in macros manually. *Almost* macro-free! Reviewed By: mdvacca Differential Revision: D7738584 fbshipit-source-id: 85f8e4c1037b452df5e73b093dced9392cb2f73e --- ReactCommon/fabric/core/shadownode/Props.cpp | 10 +--- .../fabric/core/shadownode/propsConversions.h | 52 +++++++++++++++++++ ReactCommon/fabric/view/ViewProps.cpp | 31 ++--------- ReactCommon/fabric/view/ViewProps.h | 10 ++-- 4 files changed, 64 insertions(+), 39 deletions(-) create mode 100644 ReactCommon/fabric/core/shadownode/propsConversions.h diff --git a/ReactCommon/fabric/core/shadownode/Props.cpp b/ReactCommon/fabric/core/shadownode/Props.cpp index cd5655ee588a58..688b288fd50826 100644 --- a/ReactCommon/fabric/core/shadownode/Props.cpp +++ b/ReactCommon/fabric/core/shadownode/Props.cpp @@ -7,6 +7,7 @@ #include "Props.h" +#include #include namespace facebook { @@ -15,14 +16,7 @@ namespace react { void Props::apply(const RawProps &rawProps) { ensureUnsealed(); - for (auto const &pair : rawProps) { - auto const &name = pair.first; - auto const &value = pair.second; - - if (name == "nativeID") { - nativeId_ = value.asString(); - } - } + applyRawProp(rawProps, "nativeID", nativeId_); } const std::string &Props::getNativeId() const { diff --git a/ReactCommon/fabric/core/shadownode/propsConversions.h b/ReactCommon/fabric/core/shadownode/propsConversions.h new file mode 100644 index 00000000000000..689caf0ed801fa --- /dev/null +++ b/ReactCommon/fabric/core/shadownode/propsConversions.h @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 { + +inline bool boolFromDynamic(const folly::dynamic &value) { return value.getBool(); } +inline int intFromDynamic(const folly::dynamic &value) { return value.getInt(); } +inline Float floatFromDynamic(const folly::dynamic &value) { return value.getDouble(); } +inline std::string stringFromDynamic(const folly::dynamic &value) { return value.getString(); } + +#define APPLY_RAW_PROP_TEMPLATE(type, converter) \ +inline static void applyRawProp(const RawProps &rawProps, const std::string &name, type &property) { \ + auto &&iterator = rawProps.find(name); \ + if (iterator != rawProps.end()) { \ + property = converter(iterator->second); \ + } \ +} \ +\ +inline static void applyRawProp(const RawProps &rawProps, const std::string &name, folly::Optional &property) { \ + auto &&iterator = rawProps.find(name); \ + if (iterator != rawProps.end()) { \ + auto &&value = iterator->second; \ + if (value.isNull()) { \ + property = {}; \ + } else { \ + property = converter(value); \ + } \ + } \ +} + +APPLY_RAW_PROP_TEMPLATE(bool, boolFromDynamic) +APPLY_RAW_PROP_TEMPLATE(int, intFromDynamic) +APPLY_RAW_PROP_TEMPLATE(Float, floatFromDynamic) +APPLY_RAW_PROP_TEMPLATE(std::string, stringFromDynamic) +APPLY_RAW_PROP_TEMPLATE(SharedColor, colorFromDynamic) +APPLY_RAW_PROP_TEMPLATE(Point, pointFromDynamic) +APPLY_RAW_PROP_TEMPLATE(Size, sizeFromDynamic) + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/view/ViewProps.cpp b/ReactCommon/fabric/view/ViewProps.cpp index 725c2014bc276d..e49de1a6fe48a4 100644 --- a/ReactCommon/fabric/view/ViewProps.cpp +++ b/ReactCommon/fabric/view/ViewProps.cpp @@ -9,6 +9,7 @@ #include #include +#include namespace facebook { namespace react { @@ -17,32 +18,10 @@ void ViewProps::apply(const RawProps &rawProps) { Props::apply(rawProps); YogaStylableProps::apply(rawProps); - for (auto const &pair : rawProps) { - auto const &name = pair.first; - auto const &value = pair.second; - - #pragma mark View Specific Properties - - if (name == "zIndex") { - zIndex_ = value.asInt(); - continue; - } - - if (name == "opacity") { - opacity_ = value.asDouble(); - continue; - } - - if (name == "color") { - foregroundColor_ = colorFromDynamic(value); - continue; - } - - if (name == "backgroundColor") { - backgroundColor_ = colorFromDynamic(value); - continue; - } - } + applyRawProp(rawProps, "zIndex", zIndex_); + applyRawProp(rawProps, "opacity", opacity_); + applyRawProp(rawProps, "color", foregroundColor_); + applyRawProp(rawProps, "backgroundColor", backgroundColor_); } #pragma mark - Getters diff --git a/ReactCommon/fabric/view/ViewProps.h b/ReactCommon/fabric/view/ViewProps.h index 365d469f746bf6..4aceb7f117483c 100644 --- a/ReactCommon/fabric/view/ViewProps.h +++ b/ReactCommon/fabric/view/ViewProps.h @@ -33,19 +33,19 @@ class ViewProps: SharedColor getForegroundColor() const; SharedColor getBackgroundColor() const; +#pragma mark - DebugStringConvertible + + SharedDebugStringConvertibleList getDebugProps() const override; + private: int zIndex_ {0}; - float opacity_ {1.0}; + Float opacity_ {1.0}; SharedColor foregroundColor_ {nullptr}; SharedColor backgroundColor_ {nullptr}; SharedColor shadowColor_ {nullptr}; Point shadowOffset_ {0, 0}; - -#pragma mark - DebugStringConvertible - - SharedDebugStringConvertibleList getDebugProps() const override; }; } // namespace react From 6ce2823afe26d63e3828c5fbd7171dbe80b45385 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Thu, 26 Apr 2018 17:52:02 -0700 Subject: [PATCH 0395/1109] Fabric: Proper types and default arguments in ConcreteViewShadowNode Summary: Trivial. Those are artefacts from copy-pasting from `ViewShadowNode`. Reviewed By: mdvacca Differential Revision: D7738576 fbshipit-source-id: 2d362cd0ff56420d54cdd0e339458ebe57049ddc --- ReactCommon/fabric/view/ConcreteViewShadowNode.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ReactCommon/fabric/view/ConcreteViewShadowNode.h b/ReactCommon/fabric/view/ConcreteViewShadowNode.h index a6994fe3e23276..02ee969427f13a 100644 --- a/ReactCommon/fabric/view/ConcreteViewShadowNode.h +++ b/ReactCommon/fabric/view/ConcreteViewShadowNode.h @@ -43,7 +43,7 @@ class ConcreteViewShadowNode: const Tag &tag, const Tag &rootTag, const InstanceHandle &instanceHandle, - const SharedViewProps &props = ConcreteViewShadowNode::defaultSharedProps(), + const SharedConcreteViewProps &props = ConcreteViewShadowNode::defaultSharedProps(), const SharedShadowNodeSharedList &children = ShadowNode::emptySharedShadowNodeSharedList(), const ShadowNodeCloneFunction &cloneFunction = nullptr ): @@ -65,7 +65,7 @@ class ConcreteViewShadowNode: ConcreteViewShadowNode( const SharedConcreteViewShadowNode &shadowNode, - const SharedViewProps &props = nullptr, + const SharedConcreteViewProps &props = nullptr, const SharedShadowNodeSharedList &children = nullptr ): ConcreteShadowNode( From 7b6dd2a661d13a4bd3c5ea97705fbd8caf176062 Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Fri, 27 Apr 2018 00:26:10 -0700 Subject: [PATCH 0396/1109] Metro v0.36.0 Summary: bumps the version after cache updates. Reviewed By: mjesun Differential Revision: D7776561 fbshipit-source-id: 8afe97323544116f147b93b92e5aa42ec1124d3a --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 63695f29a6a97a..b8979e9ab59ce8 100644 --- a/package.json +++ b/package.json @@ -167,10 +167,10 @@ "graceful-fs": "^4.1.3", "inquirer": "^3.0.6", "lodash": "^4.17.5", - "metro": "^0.35.0", - "metro-babel-register": "^0.35.0", - "metro-core": "^0.35.0", - "metro-memory-fs": "^0.35.0", + "metro": "^0.36.0", + "metro-babel-register": "^0.36.0", + "metro-core": "^0.36.0", + "metro-memory-fs": "^0.36.0", "mime": "^1.3.4", "minimist": "^1.2.0", "mkdirp": "^0.5.1", From 57774a4a981e2f12cfe9b029447e34f203221b18 Mon Sep 17 00:00:00 2001 From: Chirag Shah Date: Fri, 27 Apr 2018 05:58:42 -0700 Subject: [PATCH 0397/1109] Use app name from app.json for registering application Summary: Currently when we change the app name in `app.json`, run `react-native eject` and then run the application, we get the following error `Application HelloWorld2 has not been registered` This PR picks up the app name from app.json while registering the application, which prevents the additional step for the user to change the app name while registering in the `index.js` Tested using sinopia. The new app generated with the `react-native init HelloWorld` contains the changes made. [CLI] [ENHANCEMENT] [index.js] - App name picked from from app.json for registering application. Closes https://github.com/facebook/react-native/pull/17472 Differential Revision: D7788652 Pulled By: hramos fbshipit-source-id: bf23318ae1994b06e5d5908f53818040db1ad5af --- local-cli/templates/HelloWorld/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/local-cli/templates/HelloWorld/index.js b/local-cli/templates/HelloWorld/index.js index 2d090c1de7b1c6..ab0ecbf4f87881 100644 --- a/local-cli/templates/HelloWorld/index.js +++ b/local-cli/templates/HelloWorld/index.js @@ -1,4 +1,5 @@ import { AppRegistry } from 'react-native'; import App from './App'; +import { name as appName } from './app.json'; -AppRegistry.registerComponent('HelloWorld', () => App); +AppRegistry.registerComponent(appName, () => App); From e2bea00c33c85e88935aadf7644c26087a0025d7 Mon Sep 17 00:00:00 2001 From: Miguel Jimenez Esun Date: Fri, 27 Apr 2018 06:08:15 -0700 Subject: [PATCH 0398/1109] Remove TransformCaching.js Reviewed By: jeanlauliac Differential Revision: D7707146 fbshipit-source-id: 47f4c47b22cf65cfee05f63ad7dd81a5faf9c504 --- local-cli/bundle/buildBundle.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/local-cli/bundle/buildBundle.js b/local-cli/bundle/buildBundle.js index c5d2314805290b..66872a9c816202 100644 --- a/local-cli/bundle/buildBundle.js +++ b/local-cli/bundle/buildBundle.js @@ -14,8 +14,6 @@ const log = require('../util/log').out('bundle'); const Server = require('metro/src/Server'); const {Terminal} = require('metro-core'); const TerminalReporter = require('metro/src/lib/TerminalReporter'); -/* $FlowFixMe(site=react_native_oss) */ -const TransformCaching = require('metro/src/lib/TransformCaching'); const {defaults} = require('metro'); /* $FlowFixMe(site=react_native_oss) */ @@ -102,7 +100,6 @@ async function buildBundle( resetCache: args.resetCache, resolveRequest: config.resolveRequest, sourceExts: sourceExts.concat(defaultSourceExts), - transformCache: TransformCaching.useTempDir(), transformModulePath: transformModulePath, watch: false, workerPath: config.getWorkerPath && config.getWorkerPath(), From 5b0a5b98562f1092363ae36b6c16c8631b7a6a7f Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Fri, 27 Apr 2018 06:59:09 -0700 Subject: [PATCH 0399/1109] Remove shelljs(?) leftover Summary: `try-n-times` is used in some integration tests of React Native, but was using a non-existent `echo` function. Here, we replace that with `console.warn` Reviewed By: mjesun Differential Revision: D7788436 fbshipit-source-id: 0f42a00b7be780ee31cbf397fdd12ad4ccd500b1 --- scripts/try-n-times.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/try-n-times.js b/scripts/try-n-times.js index 51cba900c22b72..59abeca1731703 100644 --- a/scripts/try-n-times.js +++ b/scripts/try-n-times.js @@ -26,7 +26,7 @@ function tryExecNTimes(funcToRetry, retriesLeft, onEveryError) { onEveryError(); } retriesLeft--; - echo(`Command failed, ${retriesLeft} retries left`); + console.warn(`Command failed, ${retriesLeft} retries left`); if (retriesLeft === 0) { return exitCode; } else { From 065b9991a98a43d381d1653b57a26bb27a3e46a3 Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Fri, 27 Apr 2018 06:59:11 -0700 Subject: [PATCH 0400/1109] Metro v0.36.1 Summary: contains fixes to `metro-babel-register` necessary for node 6 compat (as supported by React Native) Reviewed By: mjesun Differential Revision: D7788437 fbshipit-source-id: 805b185dd970bf376f11664aeabea0bb8ac94b8b --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index b8979e9ab59ce8..794c13d1ac2e85 100644 --- a/package.json +++ b/package.json @@ -167,10 +167,10 @@ "graceful-fs": "^4.1.3", "inquirer": "^3.0.6", "lodash": "^4.17.5", - "metro": "^0.36.0", - "metro-babel-register": "^0.36.0", - "metro-core": "^0.36.0", - "metro-memory-fs": "^0.36.0", + "metro": "^0.36.1", + "metro-babel-register": "^0.36.1", + "metro-core": "^0.36.1", + "metro-memory-fs": "^0.36.1", "mime": "^1.3.4", "minimist": "^1.2.0", "mkdirp": "^0.5.1", From 333602b9f2cc23c43ea75d5b74993e75c1d8a82a Mon Sep 17 00:00:00 2001 From: Alex Dvornikov Date: Fri, 27 Apr 2018 14:49:12 -0700 Subject: [PATCH 0401/1109] Introduce "Options" argument to "fetchSegment()" function Reviewed By: jeanlauliac Differential Revision: D7791186 fbshipit-source-id: e3954a525e6e3b02a48ac19f78cc3716969dd6bf --- Libraries/Core/InitializeCore.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Libraries/Core/InitializeCore.js b/Libraries/Core/InitializeCore.js index d739ab78231748..2f10d5fc0e05e9 100644 --- a/Libraries/Core/InitializeCore.js +++ b/Libraries/Core/InitializeCore.js @@ -162,6 +162,7 @@ BatchedBridge.registerLazyCallableModule('JSDevSupportModule', () => require('JS global.__fetchSegment = function( segmentId: number, + options: {|+otaBuildNumber: ?string|}, callback: (?Error) => void, ) { const {SegmentFetcher} = require('NativeModules'); @@ -170,7 +171,7 @@ global.__fetchSegment = function( 'included as a NativeModule.'); } - SegmentFetcher.fetchSegment(segmentId, (errorObject: ?{message: string, code: string}) => { + SegmentFetcher.fetchSegment(segmentId, options, (errorObject: ?{message: string, code: string}) => { if (errorObject) { const error = new Error(errorObject.message); (error: any).code = errorObject.code; From 5fa9d789784f2960945ac021b16c833052b7f90c Mon Sep 17 00:00:00 2001 From: David Vacca Date: Fri, 27 Apr 2018 18:44:11 -0700 Subject: [PATCH 0402/1109] Fix viewflattening for views with on_layout props Reviewed By: achen1 Differential Revision: D7796986 fbshipit-source-id: beb0725d4edc15ec23deba592e53b700abb3bcb5 --- .../src/main/java/com/facebook/react/uimanager/ViewProps.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java index aee1a0c7d9a7ab..f85236d4842dc1 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java @@ -254,8 +254,6 @@ public static boolean isLayoutOnly(ReadableMap map, String prop) { return map.isNull(BORDER_RIGHT_WIDTH) || map.getDouble(BORDER_RIGHT_WIDTH) == 0d; case BORDER_BOTTOM_WIDTH: return map.isNull(BORDER_BOTTOM_WIDTH) || map.getDouble(BORDER_BOTTOM_WIDTH) == 0d; - case ON_LAYOUT: - return true; case OVERFLOW: // We do nothing with this right now. return true; default: From be32cbef007dada23bf830b3b12df8beefbbdac6 Mon Sep 17 00:00:00 2001 From: Nikolai Tillmann Date: Fri, 27 Apr 2018 19:09:34 -0700 Subject: [PATCH 0403/1109] Make UIManager prepackable Reviewed By: sebmarkbage Differential Revision: D7736403 fbshipit-source-id: 6154b76d9d948658394488fe4472d8b5bbcd3d9f --- Libraries/ReactNative/UIManager.js | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/Libraries/ReactNative/UIManager.js b/Libraries/ReactNative/UIManager.js index 9f34734a731cd5..5f6c61619d9b52 100644 --- a/Libraries/ReactNative/UIManager.js +++ b/Libraries/ReactNative/UIManager.js @@ -77,11 +77,24 @@ if (Platform.OS === 'ios') { } }); } else if (UIManager.ViewManagerNames) { - UIManager.ViewManagerNames.forEach(viewManagerName => { - defineLazyObjectProperty(UIManager, viewManagerName, { - get: () => UIManager.getConstantsForViewManager(viewManagerName), + // 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. + // So we wrap it in a special __residual call, which basically tells Prepack to ignore it. + let residual = global.__residual ? global.__residual : (_, f, ...args) => f.apply(undefined, args); + residual("void", (UIManager, defineLazyObjectProperty) => { + UIManager.ViewManagerNames.forEach(viewManagerName => { + defineLazyObjectProperty(UIManager, viewManagerName, { + get: () => UIManager.getConstantsForViewManager(viewManagerName), + }); }); - }); + }, UIManager, defineLazyObjectProperty); + + // As Prepack now no longer knows which properties exactly the UIManager has, + // we also tell Prepack that it has only partial knowledge of the UIManager, + // so that any accesses to unknown properties along the global code will fail + // when Prepack encounters them. + if (global.__makePartial) global.__makePartial(UIManager); } module.exports = UIManager; From c18d2a9669825228b0c26d01a3819d3fb4babbd9 Mon Sep 17 00:00:00 2001 From: Miguel Jimenez Esun Date: Fri, 27 Apr 2018 20:17:14 -0700 Subject: [PATCH 0404/1109] Upgrade Jest to 23.0.0-beta.2 Reviewed By: davidaurelio Differential Revision: D7789525 fbshipit-source-id: 0d0ebe30d66dbc5cd07c7517a513ac7be2c1e128 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 794c13d1ac2e85..62b09618c92621 100644 --- a/package.json +++ b/package.json @@ -213,8 +213,8 @@ "eslint-plugin-prettier": "2.6.0", "eslint-plugin-react": "7.6.1", "flow-bin": "^0.70.0", - "jest": "23.0.0-beta.1", - "jest-junit": "3.6.0", + "jest": "23.0.0-beta.2", + "jest-junit": "3.7.0", "prettier": "1.12.1", "react": "16.3.2", "react-test-renderer": "16.3.2", From d0822c3bccebd9f0573c571dd1b1c2d05c714367 Mon Sep 17 00:00:00 2001 From: Mayank Patke Date: Sat, 28 Apr 2018 01:57:37 -0700 Subject: [PATCH 0405/1109] v0.71.0 in xplat/js Reviewed By: yungsters Differential Revision: D7787035 fbshipit-source-id: 07defbbaa6fdc8f3016727fe6d6b1640efbf8ab6 --- .flowconfig | 2 +- local-cli/core/index.js | 2 -- local-cli/templates/HelloWorld/_flowconfig | 2 +- package.json | 2 +- 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.flowconfig b/.flowconfig index cd3dd707a7223b..aea408653180f9 100644 --- a/.flowconfig +++ b/.flowconfig @@ -69,4 +69,4 @@ suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError [version] -^0.70.0 +^0.71.0 diff --git a/local-cli/core/index.js b/local-cli/core/index.js index f3059be0a62748..3bb0481421b8bb 100644 --- a/local-cli/core/index.js +++ b/local-cli/core/index.js @@ -77,9 +77,7 @@ const defaultRNConfig = { const name = pathToCommands.split(path.sep)[0]; return attachPackage( - // $FlowFixMe non-literal require require(path.join(appRoot, 'node_modules', pathToCommands)), - // $FlowFixMe non-literal require require(path.join(appRoot, 'node_modules', name, 'package.json')) ); }); diff --git a/local-cli/templates/HelloWorld/_flowconfig b/local-cli/templates/HelloWorld/_flowconfig index 4f75b3cb1405f3..187b25e48158e2 100644 --- a/local-cli/templates/HelloWorld/_flowconfig +++ b/local-cli/templates/HelloWorld/_flowconfig @@ -51,4 +51,4 @@ suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError [version] -^0.70.0 +^0.71.0 diff --git a/package.json b/package.json index 62b09618c92621..37b3feb4ca0bbb 100644 --- a/package.json +++ b/package.json @@ -212,7 +212,7 @@ "eslint-plugin-jest": "21.8.0", "eslint-plugin-prettier": "2.6.0", "eslint-plugin-react": "7.6.1", - "flow-bin": "^0.70.0", + "flow-bin": "^0.71.0", "jest": "23.0.0-beta.2", "jest-junit": "3.7.0", "prettier": "1.12.1", From 62784f35d84a331ad04139ca7877808796feb393 Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Sun, 29 Apr 2018 15:57:49 -0700 Subject: [PATCH 0406/1109] load in platform macros Reviewed By: ttsugriy Differential Revision: D7809673 fbshipit-source-id: aacff1a99ba50393ed8f74842afa59384b846e63 --- ReactCommon/cxxreact/BUCK | 10 ++++++---- ReactCommon/jschelpers/BUCK | 2 +- ReactNative/DEFS.bzl | 11 ++++++++++- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/ReactCommon/cxxreact/BUCK b/ReactCommon/cxxreact/BUCK index 14aa2e3c999dc9..515ff8cb35df9b 100644 --- a/ReactCommon/cxxreact/BUCK +++ b/ReactCommon/cxxreact/BUCK @@ -1,5 +1,4 @@ -load("@xplat//configurations/buck/apple:flag_defs.bzl", "get_debug_preprocessor_flags") -load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "rn_xplat_cxx_library", "get_android_inspector_flags", "get_apple_inspector_flags", "ANDROID_JSC_DEPS", "APPLE_JSC_DEPS", "react_native_xplat_target") +load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "rn_xplat_cxx_library", "get_android_inspector_flags", "get_apple_inspector_flags", "ANDROID_JSC_DEPS", "APPLE_JSC_DEPS", "react_native_xplat_target", "ANDROID", "APPLE") CXX_LIBRARY_COMPILER_FLAGS = [ "-std=c++14", @@ -8,9 +7,12 @@ CXX_LIBRARY_COMPILER_FLAGS = [ APPLE_COMPILER_FLAGS = [] +DEBUG_PREPROCESSOR_FLAGS = [] + if not IS_OSS_BUILD: - load("@xplat//configurations/buck/apple:flag_defs.bzl", "get_static_library_ios_flags", "flags") + load("@xplat//configurations/buck/apple:flag_defs.bzl", "get_debug_preprocessor_flags", "get_static_library_ios_flags", "flags") APPLE_COMPILER_FLAGS = flags.get_flag_value(get_static_library_ios_flags(), 'compiler_flags') + DEBUG_PREPROCESSOR_FLAGS = get_debug_preprocessor_flags() rn_xplat_cxx_library( name = "module", @@ -140,7 +142,7 @@ rn_xplat_cxx_library( fbobjc_frameworks = [ "$SDKROOT/System/Library/Frameworks/JavaScriptCore.framework", ], - fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), + fbobjc_preprocessor_flags = DEBUG_PREPROCESSOR_FLAGS + get_apple_inspector_flags(), force_static = True, macosx_tests_override = [], platforms = (ANDROID, APPLE), diff --git a/ReactCommon/jschelpers/BUCK b/ReactCommon/jschelpers/BUCK index 37dc1abb0df57d..c0bb888ea0c9bc 100644 --- a/ReactCommon/jschelpers/BUCK +++ b/ReactCommon/jschelpers/BUCK @@ -1,4 +1,4 @@ -load("//ReactNative:DEFS.bzl", "rn_xplat_cxx_library", "react_native_xplat_target", "ANDROID_JSC_INTERNAL_DEPS", "APPLE_JSC_INTERNAL_DEPS") +load("//ReactNative:DEFS.bzl", "rn_xplat_cxx_library", "react_native_xplat_target", "ANDROID_JSC_INTERNAL_DEPS", "APPLE_JSC_INTERNAL_DEPS", "ANDROID", "APPLE") EXPORTED_HEADERS = [ "JavaScriptCore.h", diff --git a/ReactNative/DEFS.bzl b/ReactNative/DEFS.bzl index 135bacfbc93d2c..b0c85a1aaf7efb 100644 --- a/ReactNative/DEFS.bzl +++ b/ReactNative/DEFS.bzl @@ -4,7 +4,7 @@ This lets us build React Native: - At Facebook by running buck from the root of the fb repo - Outside of Facebook by running buck in the root of the git repo """ -# @lint-ignore-every SKYLINT +# @lint-ignore-every SKYLINT BUCKRESTRICTEDSYNTAX IS_OSS_BUILD = True @@ -22,6 +22,7 @@ ANDROID_JSC_INTERNAL_DEPS = [ ] ANDROID_JSC_DEPS = ANDROID_JSC_INTERNAL_DEPS ANDROID = "Android" +APPLE = "" YOGA_TARGET = '//ReactAndroid/src/main/java/com/facebook:yoga' FBGLOGINIT_TARGET = '//ReactAndroid/src/main/jni/first-party/fbgloginit:fbgloginit' @@ -33,6 +34,14 @@ with allow_unsafe_import(): import os +def get_apple_inspector_flags(): + return [] + + +def get_android_inspector_flags(): + return [] + + # Building is not supported in OSS right now def rn_xplat_cxx_library(name, **kwargs): new_kwargs = { From 5b923e0eafb44cef50b18838308889d2330dbf2a Mon Sep 17 00:00:00 2001 From: Spencer Ahrens Date: Mon, 30 Apr 2018 09:52:34 -0700 Subject: [PATCH 0407/1109] Add args to bridge function call systrace markers Reviewed By: yungsters Differential Revision: D7797728 fbshipit-source-id: 615affc57e658d4dd08a88f829d38be930804372 --- Libraries/BatchedBridge/MessageQueue.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Libraries/BatchedBridge/MessageQueue.js b/Libraries/BatchedBridge/MessageQueue.js index 5c2338d033e833..93a759154cb0f5 100644 --- a/Libraries/BatchedBridge/MessageQueue.js +++ b/Libraries/BatchedBridge/MessageQueue.js @@ -328,7 +328,11 @@ class MessageQueue { __callFunction(module: string, method: string, args: any[]): any { this._lastFlush = new Date().getTime(); this._eventLoopStartTime = this._lastFlush; - Systrace.beginEvent(`${module}.${method}()`); + if (__DEV__ || this.__spy) { + Systrace.beginEvent(`${module}.${method}(${stringifySafe(args)})`); + } else { + Systrace.beginEvent(`${module}.${method}(...)`); + } if (this.__spy) { this.__spy({type: TO_JS, module, method, args}); } From 0f6762ba50b92a16fa11f10142b4416aace57f5e Mon Sep 17 00:00:00 2001 From: Spencer Ahrens Date: Mon, 30 Apr 2018 11:41:14 -0700 Subject: [PATCH 0408/1109] improve console logging Summary: * Always log when PRINT_TO_CONSOLE true - o reason to also check DEV. * Log when `clearExceptTimespans` is called. * Type `PRINT_TO_CONSOLE: false` to prevent accidental commits setting it true. Reviewed By: alexeylang Differential Revision: D7816623 fbshipit-source-id: 47cf7e158133045e20b345139efb1a79e5e6553b --- Libraries/Utilities/PerformanceLogger.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Libraries/Utilities/PerformanceLogger.js b/Libraries/Utilities/PerformanceLogger.js index aa4633fceb9c6e..a48f1adb4b6e99 100644 --- a/Libraries/Utilities/PerformanceLogger.js +++ b/Libraries/Utilities/PerformanceLogger.js @@ -29,7 +29,7 @@ let timespans: {[key: string]: Timespan} = {}; let extras: {[key: string]: any} = {}; const cookies: {[key: string]: number} = {}; -const PRINT_TO_CONSOLE = false; +const PRINT_TO_CONSOLE: false = false; // Type as false to prevent accidentally committing `true`; /** * This is meant to collect and log performance data in production, which means @@ -69,7 +69,7 @@ const PerformanceLogger = { startTime: performanceNow(), }; cookies[key] = Systrace.beginAsyncEvent(key); - if (__DEV__ && PRINT_TO_CONSOLE) { + if (PRINT_TO_CONSOLE) { infoLog('PerformanceLogger.js', 'start: ' + key); } }, @@ -97,7 +97,7 @@ const PerformanceLogger = { timespan.endTime = performanceNow(); timespan.totalTime = timespan.endTime - (timespan.startTime || 0); - if (__DEV__ && PRINT_TO_CONSOLE) { + if (PRINT_TO_CONSOLE) { infoLog('PerformanceLogger.js', 'end: ' + key); } @@ -108,7 +108,7 @@ const PerformanceLogger = { clear() { timespans = {}; extras = {}; - if (__DEV__ && PRINT_TO_CONSOLE) { + if (PRINT_TO_CONSOLE) { infoLog('PerformanceLogger.js', 'clear'); } }, @@ -120,7 +120,7 @@ const PerformanceLogger = { } } extras = {}; - if (__DEV__ && PRINT_TO_CONSOLE) { + if (PRINT_TO_CONSOLE) { infoLog('PerformanceLogger.js', 'clearCompleted'); } }, @@ -133,6 +133,9 @@ const PerformanceLogger = { return previous; }, {}); extras = {}; + if (PRINT_TO_CONSOLE) { + infoLog('PerformanceLogger.js', 'clearExceptTimespans', keys); + } }, currentTimestamp() { From f99ca3c03fbd92995ef2559198a8b7fa7721ca92 Mon Sep 17 00:00:00 2001 From: Brent Erickson Date: Mon, 30 Apr 2018 17:25:02 -0700 Subject: [PATCH 0409/1109] Fix a race condition in AppState that prevents listeners from being notified Summary: If someone has setup a subscription on AppState and we correct AppState via getCurrentAppState call, we need to notify all the subscribers of AppState. 1 ) Initial AppState.currentState = 'active' 2-start) Subscribe to AppState Changes 3-start) Fetch Current AppState 4 ) App Code subscribes to AppState module 5 ) App becomes backgrounded 2-finish) AppState listeners are setup (missing background event) 3-finish) AppState.currentState updated to background At this point the subscription setup in 4) will never be called with the change. AppState should always call subscribers on change This is very difficult to formally test since it's due to a race condition. We've seen this condition via bug reports but have had no local repro. [GENERAL][BUGFIX][AppState] - Fix a race condition that could prevent AppState subscription change listener from firing on initial launch Closes https://github.com/facebook/react-native/pull/18236 Differential Revision: D7823370 Pulled By: hramos fbshipit-source-id: 99b174df70262ceaf9da141d005131facd624594 --- Libraries/AppState/AppState.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Libraries/AppState/AppState.js b/Libraries/AppState/AppState.js index ecb106bb24e863..904bf2b0e65843 100644 --- a/Libraries/AppState/AppState.js +++ b/Libraries/AppState/AppState.js @@ -60,8 +60,10 @@ class AppState extends NativeEventEmitter { // prop and expose `getCurrentAppState` method directly. RCTAppState.getCurrentAppState( (appStateData) => { - if (!eventUpdated) { + // It's possible that the state will have changed here & listeners need to be notified + if (!eventUpdated && this.currentState !== appStateData.app_state) { this.currentState = appStateData.app_state; + this.emit('appStateDidChange', appStateData); } }, logError From 2d9e2f30e17b8e79f2c44ef533ecdd550671304c Mon Sep 17 00:00:00 2001 From: John Shelley Date: Tue, 1 May 2018 04:01:29 -0700 Subject: [PATCH 0410/1109] Android - Fix Drawable v4 paths in Android Artifact Resources (Libraries) Summary: _Quick apologies for the lengthiness of this description. Want to make sure I'm clear and it is understood what is being altered._ Thanks for submitting a PR! Please read these instructions carefully: - [x] Explain the **motivation** for making this change. - [x] Provide a **test plan** demonstrating that the code is solid. - [x] Match the **code formatting** of the rest of the codebase. - [x] Target the `master` branch, NOT a "stable" branch. https://github.com/facebook/react-native/issues/5787 ``` Unknown source file : /home/tom/projects/blueprint-native/android/app/build/intermediates/res/merged/release/drawable-mdpi-v4/images_google.png: error: Duplicate file. Unknown source file : /home/tom/projects/blueprint-native/android/app/build/intermediates/res/merged/release/drawable-mdpi/images_google.png: Original is here. The version qualifier may be implied. ``` At Hudl, we've been attempting to package our React Native code into Library Dependencies _(Cocoapods / Android Artifact Resource (aar))_. Recently in React Native 0.42.0, there was an upgrade to the Android Project's gradle plugin from 1.3.1 to 2.2.3. This update drastically effected the outcome of drawable resources in Android without anyone noticing. **There are 4 outcomes to consider with this change:** 1. You are developing in an Android Application using Gradle 1.3.1 or lower 2. You are developing in an Android Application using Gradle 2.2.3 or higher 3. You are developing in an Android Library Module using Gradle 1.3.1 or lower 4. You are developing in an Android Library Module using Gradle 2.2.3 or higher With the upgrade to 2.2.3, Android changed the way aapt builds its resources. Any Library created with 2.2.3, has its resources ending with a `v4` suffix. The reasoning behind this I'm not sure of but assume it deals with Vector support that was added around that time. The change I've added checks if React Native is being ran in an Android Library vs an Application, and appends the v4 suffix to the merged asset folders. Multiple test were performed. 1. I first started out validating my assumption about the asset merger by creating a new Android Project to verify my assumptions above. 1. [Application + >= 2.2.3](https://github.com/jpshelley/TestAndroidLibraryDrawables/tree/master/app/build/intermediates/res/merged/debug) -- `hdpi` contains my drawable. `hdpi-v4` contains dependency's drawables. 2. [Application + <= 1.3.1](https://github.com/jpshelley/TestAndroidLibraryDrawables/tree/Android-LegacyVersion/app/build/intermediates/res/merged/debug) -- Same as above (I expect because deps are compiled against gradle 2.2.3+ themselves. 3. [Library + >= 2.2.3](https://github.com/jpshelley/TestAndroidLibraryDrawables/tree/Android-UsingAndroidLibrary/library/build/intermediates/res/merged/debug) -- Only `-v4` folders found! Resources from the library are packages in the app's build output in similar `-v4` folder too. 4. [Library + <= 1.3.1](https://github.com/jpshelley/TestAndroidLibraryDrawables/tree/Android-UsingAndroidLibraryLegacyVersion/library/build/intermediates/res/merged/debug) -- Same as ii. & iii. `-v4` contains other resources, but my resources are located in non -v4 folder. 2. I then wanted to validate against React Native itself. So I updated my react native code using this PR/Branch, and tested against my project locally. Unfortunately I cannot share that code as it is private, but before this change I was getting the same error as mentioned in #5787 and now my build runs as intended with the assets being placed where they should be. Additional resources: * https://github.com/facebook/react-native/issues/5787 * http://stackoverflow.com/questions/35700272/android-build-tool-adds-v4-qualifier-to-drawable-folders-by-default-in-generated * https://github.com/facebook/react-native/issues/12710 Please let me know if more information is needed, further test plans, etc. With this change we should be able to upgrade to Gradle 2.3.0 as well to support the latest version of Android Studio. Closes https://github.com/facebook/react-native/pull/13128 Differential Revision: D7828618 Pulled By: hramos fbshipit-source-id: a7ad7b63b1b51cbfd2ea7656e4d77321306ce33a --- react.gradle | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/react.gradle b/react.gradle index bdf392ad9a717b..f048c07d4e3e82 100644 --- a/react.gradle +++ b/react.gradle @@ -24,6 +24,7 @@ void runBefore(String dependentTaskName, Task task) { } afterEvaluate { + def isAndroidLibrary = plugins.hasPlugin("com.android.library") // Grab all build types and product flavors def buildTypes = android.buildTypes.collect { type -> type.name } def productFlavors = android.productFlavors.collect { flavor -> flavor.name } @@ -101,6 +102,24 @@ afterEvaluate { enabled config."bundleIn${targetName}" || config."bundleIn${buildTypeName.capitalize()}" ?: targetName.toLowerCase().contains("release") + + if (isAndroidLibrary) { + doLast { + def moveFunc = { resSuffix -> + File originalDir = file("${resourcesDir}/drawable-${resSuffix}") + if (originalDir.exists()) { + File destDir = file("${resourcesDir}/drawable-${resSuffix}-v4") + ant.move(file: originalDir, tofile: destDir) + } + } + moveFunc.curry("ldpi").call() + moveFunc.curry("mdpi").call() + moveFunc.curry("hdpi").call() + moveFunc.curry("xhdpi").call() + moveFunc.curry("xxhdpi").call() + moveFunc.curry("xxxhdpi").call() + } + } } // Hook bundle${productFlavor}${buildType}JsAndAssets into the android build process From 837d496ac8fd8da5528ecbb21dfa7f7a611d6cbf Mon Sep 17 00:00:00 2001 From: David Vacca Date: Tue, 1 May 2018 08:01:48 -0700 Subject: [PATCH 0411/1109] Fix clone of MutableYogaValue inside LayoutShadowNode Reviewed By: achen1 Differential Revision: D7815809 fbshipit-source-id: 833af43387895b0b5193d6bef54c99023da01c9c --- .../java/com/facebook/react/uimanager/LayoutShadowNode.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java index ae85bbdccd7646..c9d8de0eaef78b 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java @@ -74,7 +74,7 @@ public LayoutShadowNode() { protected LayoutShadowNode(LayoutShadowNode node) { super(node); - mTempYogaValue = new MutableYogaValue(); + mTempYogaValue = new MutableYogaValue(node.mTempYogaValue); } @Override @@ -527,7 +527,6 @@ public void setOverflow(@Nullable String overflow) { if (isVirtual()) { return; } - if (overflow == null) { setOverflow(YogaOverflow.VISIBLE); return; From 8e3105dbcecd9b7c400cff031c22ecd74719704d Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Tue, 1 May 2018 13:02:32 -0700 Subject: [PATCH 0412/1109] Add `getName()` method Summary: adds a `getName()` method to all `JavaScriptExecutor` classes that can be used by `ReactInstanceManager` to identify the bridge type when logging markers. Reviewed By: fromcelticpark Differential Revision: D7790531 fbshipit-source-id: efe485588738a38936accc4a7956840784b2dd08 --- .../com/facebook/react/bridge/JSCJavaScriptExecutor.java | 6 ++++++ .../java/com/facebook/react/bridge/JavaScriptExecutor.java | 5 +++++ .../com/facebook/react/bridge/ProxyJavaScriptExecutor.java | 5 +++++ 3 files changed, 16 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSCJavaScriptExecutor.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSCJavaScriptExecutor.java index ee77eda70b984c..ead9806f50960b 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSCJavaScriptExecutor.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSCJavaScriptExecutor.java @@ -20,5 +20,11 @@ super(initHybrid(jscConfig)); } + @Override + public String getName() { + return "JSCJavaScriptExecutor"; + } + + private native static HybridData initHybrid(ReadableNativeMap jscConfig); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptExecutor.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptExecutor.java index e4195aff332841..9c72fd1f8e54d0 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptExecutor.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptExecutor.java @@ -26,4 +26,9 @@ protected JavaScriptExecutor(HybridData hybridData) { public void close() { mHybridData.resetNative(); } + + /** + * Returns the name of the executor, identifying the underlying runtime. + */ + abstract public String getName(); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ProxyJavaScriptExecutor.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ProxyJavaScriptExecutor.java index db04655d35479c..5442daa3a96c75 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ProxyJavaScriptExecutor.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ProxyJavaScriptExecutor.java @@ -59,5 +59,10 @@ public void close() { } } + @Override + public String getName() { + return "ProxyJavaScriptExecutor"; + } + private native static HybridData initHybrid(JavaJSExecutor executor); } From fa25311d274e380773e0ef2d71fc510ec3e3c85a Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Tue, 1 May 2018 13:02:38 -0700 Subject: [PATCH 0413/1109] ReactInstanceManager: post executor name with `CREATE_REACT_CONTEXT_START` marker Summary: Adds the name of the active JS executor when logging the `CREATE_REACT_CONTEXT_START` marker. Reviewed By: fromcelticpark Differential Revision: D7800760 fbshipit-source-id: d5090a9f90cf4b7bcfb7218e75621becebd70675 --- .../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 26ee98a9a03417..b97f6f45bab221 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java @@ -1067,7 +1067,7 @@ private ReactApplicationContext createReactContext( JavaScriptExecutor jsExecutor, JSBundleLoader jsBundleLoader) { Log.d(ReactConstants.TAG, "ReactInstanceManager.createReactContext()"); - ReactMarker.logMarker(CREATE_REACT_CONTEXT_START); + ReactMarker.logMarker(CREATE_REACT_CONTEXT_START, jsExecutor.getName()); final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext); NativeModuleCallExceptionHandler exceptionHandler = mNativeModuleCallExceptionHandler != null From bf83600996298f21698fc1fd0b90ab597d411d92 Mon Sep 17 00:00:00 2001 From: Eric Samelson Date: Tue, 1 May 2018 13:57:58 -0700 Subject: [PATCH 0414/1109] Remove race condition in initial layout of ReactRootView Summary: There is a race condition stemming from `ReactRootView.onCreate` that occasionally causes the initial root layout calculation to never occur. In this method currently, `updateRootLayoutSpecs(...)` is called before `enableLayoutCalculation()`, meaning that it's possible for the native modules thread to reach `UIImplementation.updateViewHierarchy` before layout calculation has been enabled (i.e. before the rootViewTag is added to `UIImplementation.mMeasuredRootNodes` on the UI thread). When this occurs, `UIImplementation.applyUpdatesRecursive` is never called. This causes the app to hang on the splash screen indefinitely, the JS never gets past the first call to `render`, and no layout events are ever sent to the JS. This PR reverses the order of those two method calls to ensure that the rootViewTag is always added to `mMeasuredRootNodes` before `UIImplementation.updateViewHierarchy` expects it. We inspected all of the code paths of both `enableLayoutCalculation()` and `updateRootLayoutSpecs()` to ensure that in this new order, the rootViewTag will *always* be added to `mMeasuredRootNodes` before the call to `updateViewHierarchy` is dispatched, and that no other side effects would be introduced. Tested with an app that reliably had this issue (hanging splash screen) on 1 out of every ~10 launches. Logged values to ensure that empty `mMeasuredRootNodes` was the difference between failed and successful launches. After this change, I launched the same app 50+ times without any issues. [ANDROID][BUGFIX][ReactRootView] - remove race condition in initial layout of ReactRootView Closes https://github.com/facebook/react-native/pull/19038 Differential Revision: D7834270 Pulled By: hramos fbshipit-source-id: 6040da900f807dcacbc86ae2c36b4ca004f80178 --- .../src/main/java/com/facebook/react/ReactRootView.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java index baa2a6e30d96f6..4c4a7952990dfb 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java @@ -147,12 +147,12 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // Check if we were waiting for onMeasure to attach the root view. if (mReactInstanceManager != null && !mIsAttachedToInstance) { attachToReactInstanceManager(); + enableLayoutCalculation(); } else { + enableLayoutCalculation(); updateRootLayoutSpecs(mWidthMeasureSpec, mHeightMeasureSpec); } - enableLayoutCalculation(); - } finally { Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE); } From 99a6c0af405b9cde9ecefc1666afcd537a52f710 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Tue, 1 May 2018 19:19:45 -0700 Subject: [PATCH 0415/1109] Fix NPE in ReactSliderManager.initMeasureFunction Reviewed By: fkgozali Differential Revision: D7825102 fbshipit-source-id: af7502a5e6ffa83965a66a0a099d729152d7627f --- .../java/com/facebook/react/views/slider/ReactSliderManager.java | 1 - 1 file changed, 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/slider/ReactSliderManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/slider/ReactSliderManager.java index 10f714c9429756..1cd9c261103e3a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/slider/ReactSliderManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/slider/ReactSliderManager.java @@ -57,7 +57,6 @@ private ReactSliderShadowNode(ReactSliderShadowNode node) { mWidth = node.mWidth; mHeight = node.mHeight; mMeasured = node.mMeasured; - initMeasureFunction(); } private void initMeasureFunction() { From 37c820f16e33746241af05e188d69502f518f80d Mon Sep 17 00:00:00 2001 From: Jerry Horton Date: Tue, 1 May 2018 19:25:06 -0700 Subject: [PATCH 0416/1109] =?UTF-8?q?Fix=20for=20issue=20#19086=20RCTHasFo?= =?UTF-8?q?ntHandlerSet();=20This=20function=20definition=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: … is not a protoype #19086 Thank you for sending the PR! We appreciate you spending the time to work on these changes. Help us understand your motivation by explaining why you decided to make this change. Fixes #19086 Related to react-native-navigation issue #3019 Created a fresh react native >= 0.55.2 project and only install React Native Navigation. The error "This function declaration is not a prototype" message occurs. Downgrading to React Native 0.54.4 builds fine. ![screen shot 2018-05-01 at 3 17 51 pm](https://user-images.githubusercontent.com/5680239/39491718-ddfdd6a0-4d52-11e8-937f-7ed9702a2e30.png) No documentation change [iOS] [BUGFIX] [react-native-navigation] - For compatibility with react-native-navigation >= 2.0.2237 https://github.com/facebook/react-native/issues/19086 Closes https://github.com/facebook/react-native/pull/19089 Differential Revision: D7841198 Pulled By: shergin fbshipit-source-id: 31638274055c3f143342d2d6dde6d4af7a2ac304 --- React/Views/RCTFont.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/React/Views/RCTFont.h b/React/Views/RCTFont.h index e812f69df353e5..a8f347a7d52f48 100644 --- a/React/Views/RCTFont.h +++ b/React/Views/RCTFont.h @@ -18,7 +18,7 @@ typedef UIFont *(^RCTFontHandler)(CGFloat fontSize, NSString *fontWeightDescript * "semibold", "extrabold", "bold", "heavy", or "black". */ RCT_EXTERN void RCTSetDefaultFontHandler(RCTFontHandler handler); -RCT_EXTERN BOOL RCTHasFontHandlerSet(); +RCT_EXTERN BOOL RCTHasFontHandlerSet(void); @interface RCTFont : NSObject From 5b2a2bee7a88cd25e30d8767622a8e20b3753e9d Mon Sep 17 00:00:00 2001 From: Spencer Ahrens Date: Tue, 1 May 2018 19:35:48 -0700 Subject: [PATCH 0417/1109] PureComponentDebug Summary: Drop in replacement for `React.PureComponent` or can replace `React.PureComponent` for all components. Logs out what exactly triggered a re-render of a `PureComponent` to make it easier to track down why a component is re-rendering. With some other changes we'll also get component stacks in the YellowBox to make it even easier. I thought about logging the values, but it's too easy to render something gross or cyclical like react components, so I figured people could break in the debugger to get more detail as needed. Special flow type should cause errors if people try to commit any usage of this - it should only be used for local debugging. Reviewed By: yungsters Differential Revision: D7826325 fbshipit-source-id: fdf7910336452ac1c7acd328c04d441dfb186b59 --- Libraries/Performance/PureComponentDebug.js | 73 +++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 Libraries/Performance/PureComponentDebug.js diff --git a/Libraries/Performance/PureComponentDebug.js b/Libraries/Performance/PureComponentDebug.js new file mode 100644 index 00000000000000..c06dbbb71431b1 --- /dev/null +++ b/Libraries/Performance/PureComponentDebug.js @@ -0,0 +1,73 @@ +/** + * Copyright (c) 2013-present, Facebook, Inc. + * + * 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 React = require('React'); + +opaque type DoNotCommitUsageOfPureComponentDebug = {}; + +/** + * Identifies which prop or state changes triggered a re-render of a PureComponent. Usage: + * + * Change `extends React.PureComponent` to `extends PureComponentDebug` or inject it + * everywhere by putting this line in your app setup: + * + * React.PureComponent = require('PureComponentDebug'); + * + * Should only be used for local testing, and will trigger a flow failure if you try to + * commit any usages. + */ +class PureComponentDebug< + P: DoNotCommitUsageOfPureComponentDebug, + S: ?Object = void, +> extends React.Component { + shouldComponentUpdate(nextProps: P, nextState: S): boolean { + const tag = this.constructor.name; + let ret = false; + const prevPropsKeys = Object.keys(this.props); + const nextPropsKeys = Object.keys(nextProps); + if (prevPropsKeys.length !== nextPropsKeys.length) { + ret = true; + console.warn( + 'PureComponentDebug: different prop keys', + tag, + prevPropsKeys.filter(key => !nextPropsKeys.includes(key)), + nextPropsKeys.filter(key => !prevPropsKeys.includes(key)), + ); + } + const prevStateKeys = Object.keys(this.state || {}); + const nextStateKeys = Object.keys(nextState || {}); + if (prevStateKeys.length !== nextStateKeys.length) { + ret = true; + console.warn( + 'PureComponentDebug: different state keys', + tag, + prevStateKeys.filter(key => !nextStateKeys.includes(key)), + nextStateKeys.filter(key => !prevStateKeys.includes(key)), + ); + } + for (const key in this.props) { + if (this.props[key] !== nextProps[key]) { + ret = true; + console.warn('PureComponentDebug: different prop values', tag, key); + } + } + for (const key in this.state) { + if (this.state[key] !== (nextState || {})[key]) { + ret = true; + console.warn('PureComponentDebug: different state values', tag, key); + } + } + return ret; + } +} + +module.exports = PureComponentDebug; From fffae996406537595696bbb03a0c8ad6c87cd6d9 Mon Sep 17 00:00:00 2001 From: Spencer Ahrens Date: Tue, 1 May 2018 21:53:22 -0700 Subject: [PATCH 0418/1109] deepDiffer: add maxDepth arg Reviewed By: blairvanderhoof Differential Revision: D7839729 fbshipit-source-id: fe9a06d2aaed9dfbfb3e52779ba4b1b98007b9ce --- .../Utilities/differ/__tests__/deepDiffer-test.js | 12 ++++++++++++ Libraries/Utilities/differ/deepDiffer.js | 9 ++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/Libraries/Utilities/differ/__tests__/deepDiffer-test.js b/Libraries/Utilities/differ/__tests__/deepDiffer-test.js index 6fadfdbe575478..4fb31ee05fb39b 100644 --- a/Libraries/Utilities/differ/__tests__/deepDiffer-test.js +++ b/Libraries/Utilities/differ/__tests__/deepDiffer-test.js @@ -98,4 +98,16 @@ describe('deepDiffer', function() { var obj = [1,[2,3]]; expect(deepDiffer(obj, obj)).toBe(false); }); + it('should respect maxDepth arg', () => { + expect(deepDiffer( + {a: {A: {aA: 1, bB: 1}}, b: 1}, + {a: {A: {aA: 1, bB: 1}}, b: 1}, + 3 + )).toBe(true); + expect(deepDiffer( + {a: {A: {aA: 1, bB: 1}}, b: 1}, + {a: {A: {aA: 1, bB: 1}}, b: 1}, + 4 + )).toBe(false); + }); }); diff --git a/Libraries/Utilities/differ/deepDiffer.js b/Libraries/Utilities/differ/deepDiffer.js index 700733f51f6bcf..f3f826fe91169a 100644 --- a/Libraries/Utilities/differ/deepDiffer.js +++ b/Libraries/Utilities/differ/deepDiffer.js @@ -11,7 +11,10 @@ /* * @returns {bool} true if different, false if equal */ -var deepDiffer = function(one: any, two: any): bool { +var deepDiffer = function(one: any, two: any, maxDepth: number = -1): bool { + if (maxDepth === 0) { + return true; + } if (one === two) { // Short circuit on identical object references instead of traversing them. return false; @@ -39,13 +42,13 @@ var deepDiffer = function(one: any, two: any): bool { return true; } for (var ii = 0; ii < len; ii++) { - if (deepDiffer(one[ii], two[ii])) { + if (deepDiffer(one[ii], two[ii], maxDepth - 1)) { return true; } } } else { for (var key in one) { - if (deepDiffer(one[key], two[key])) { + if (deepDiffer(one[key], two[key], maxDepth - 1)) { return true; } } From 9927d209271a4d29326f79546b6501f556eeea92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Norte?= Date: Wed, 2 May 2018 03:42:56 -0700 Subject: [PATCH 0419/1109] Set hasteImplModulePath in React Native Jest preset Reviewed By: cpojer Differential Revision: D7843566 fbshipit-source-id: 98be0d7286351475248f53b7c028e6c85d411a10 --- jest-preset.json | 1 + 1 file changed, 1 insertion(+) diff --git a/jest-preset.json b/jest-preset.json index a5ef95af6773c7..afd12eb96e7326 100644 --- a/jest-preset.json +++ b/jest-preset.json @@ -2,6 +2,7 @@ "haste": { "defaultPlatform": "ios", "platforms": ["android", "ios", "native"], + "hasteImplModulePath": "/node_modules/react-native/jest/hasteImpl.js", "providesModuleNodeModules": [ "react-native" ] From aa6f394c4236e5a4998c3be8ed61ec1bab950775 Mon Sep 17 00:00:00 2001 From: Peter van der Zee Date: Wed, 2 May 2018 07:37:35 -0700 Subject: [PATCH 0420/1109] Enable `?.` plugins in RN Summary: Enable the optional chaining operator plugins for React Native. Reviewed By: rafeca Differential Revision: D7828244 fbshipit-source-id: 659a8a82ff6d656a5cb2f33377d85b668b93a9ea --- babel-preset/configs/main.js | 4 ++++ babel-preset/package.json | 1 + 2 files changed, 5 insertions(+) diff --git a/babel-preset/configs/main.js b/babel-preset/configs/main.js index 0b972f595b7428..e6aeeec39865ba 100644 --- a/babel-preset/configs/main.js +++ b/babel-preset/configs/main.js @@ -52,6 +52,7 @@ const exponentiationOperator = [ ]; const objectAssign = [require('@babel/plugin-transform-object-assign')]; const objectRestSpread = [require('@babel/plugin-proposal-object-rest-spread')]; +const optionalChaining = [require('@babel/plugin-proposal-optional-chaining')]; const reactDisplayName = [ require('@babel/plugin-transform-react-display-name'), ]; @@ -98,6 +99,9 @@ const getPreset = (src, options) => { ) { extraPlugins.push(reactDisplayName); } + if (isNull || src.indexOf('?.') !== -1) { + extraPlugins.push(optionalChaining); + } if (options && options.dev) { extraPlugins.push(reactJsxSource); diff --git a/babel-preset/package.json b/babel-preset/package.json index 691941cf378b7f..b69d3d301cc8b0 100644 --- a/babel-preset/package.json +++ b/babel-preset/package.json @@ -17,6 +17,7 @@ "dependencies": { "@babel/plugin-proposal-class-properties": "7.0.0-beta.40", "@babel/plugin-proposal-object-rest-spread": "7.0.0-beta.40", + "@babel/plugin-proposal-optional-chaining": "7.0.0-beta.40", "@babel/plugin-transform-arrow-functions": "7.0.0-beta.40", "@babel/plugin-transform-block-scoping": "7.0.0-beta.40", "@babel/plugin-transform-classes": "7.0.0-beta.40", From ba88292130de42fa4117d1ad1c079f779746593e Mon Sep 17 00:00:00 2001 From: Eric Rozell Date: Wed, 2 May 2018 10:56:23 -0700 Subject: [PATCH 0421/1109] Support platform-specific prop type overrides Summary: Moves `PlatformViewPropTypes` to the end of `ViewPropTypes` so platforms can override prop type values. An example of this is in `react-native-windows`, we want to support additional values for the `importantForAccessibility` prop type that are specific to Windows (more details in [this PR](https://github.com/Microsoft/react-native-windows/pull/1807)). Thank you for sending the PR! We appreciate you spending the time to work on these changes. Help us understand your motivation by explaining why you decided to make this change. Run jest tests, test RNTester on iOS and Android. Did not test tvOS, but this should not impact tvOS as the only props included from `PlatformViewPropTypes` are unique (i.e., are not overridden in this file). https://github.com/Microsoft/react-native-windows/pull/1807 [CATEGORY] [TYPE] [LOCATION] - Message [GENERAL][Enhancement][View] - Make `ViewPropTypes` more friendly to platform extensions. Closes https://github.com/facebook/react-native/pull/19090 Differential Revision: D7846438 Pulled By: shergin fbshipit-source-id: e51ee3256d1c21001b371bd07da21319f3ecd810 --- Libraries/Components/View/ViewPropTypes.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Libraries/Components/View/ViewPropTypes.js b/Libraries/Components/View/ViewPropTypes.js index f5f03bf10efd83..40cd8121cd9958 100644 --- a/Libraries/Components/View/ViewPropTypes.js +++ b/Libraries/Components/View/ViewPropTypes.js @@ -73,8 +73,6 @@ export type ViewProps = { } & TVViewProps; module.exports = { - ...PlatformViewPropTypes, - /** * When `true`, indicates that the view is an accessibility element. * By default, all the touchable elements are accessible. @@ -427,4 +425,9 @@ module.exports = { * See http://facebook.github.io/react-native/docs/view.html#needsoffscreenalphacompositing */ needsOffscreenAlphaCompositing: PropTypes.bool, + + /** + * Any additional platform-specific view prop types, or prop type overrides. + */ + ...PlatformViewPropTypes, }; From 23d61b35fb6fdbfb84f77b6d99ff155a0ff868e6 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Wed, 2 May 2018 15:19:50 -0700 Subject: [PATCH 0422/1109] Breaking change - Disable WebView geolocation by default Reviewed By: yungsters Differential Revision: D7846198 fbshipit-source-id: 8d6daff4b794d3569b5ddba2d8d62af8c7ff5b03 --- Libraries/Components/WebView/WebView.android.js | 7 +++++++ .../facebook/react/views/webview/ReactWebViewManager.java | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/Libraries/Components/WebView/WebView.android.js b/Libraries/Components/WebView/WebView.android.js index a457298f96f65f..6f0ac9b57fb033 100644 --- a/Libraries/Components/WebView/WebView.android.js +++ b/Libraries/Components/WebView/WebView.android.js @@ -138,6 +138,12 @@ class WebView extends React.Component { */ domStorageEnabled: PropTypes.bool, + /** + * Sets whether Geolocation is enabled. The default is false. + * @platform android + */ + geolocationEnabled: PropTypes.bool, + /** * Sets the JS to be injected when the webpage loads. */ @@ -310,6 +316,7 @@ class WebView extends React.Component { onLoadingFinish={this.onLoadingFinish} onLoadingError={this.onLoadingError} testID={this.props.testID} + geolocationEnabled={this.props.geolocationEnabled} mediaPlaybackRequiresUserAction={this.props.mediaPlaybackRequiresUserAction} allowUniversalAccessFromFileURLs={this.props.allowUniversalAccessFromFileURLs} mixedContentMode={this.props.mixedContentMode} diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java index 3097beea5aadd6..a580a2bc4a18af 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java @@ -384,6 +384,7 @@ public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermiss new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); + setGeolocationEnabled(webView, false); if (ReactBuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { WebView.setWebContentsDebuggingEnabled(true); } @@ -538,6 +539,13 @@ public void setUrlPrefixesForDefaultIntent( } } + @ReactProp(name = "geolocationEnabled") + public void setGeolocationEnabled( + WebView view, + @Nullable Boolean isGeolocationEnabled) { + view.getSettings().setGeolocationEnabled(isGeolocationEnabled != null && isGeolocationEnabled); + } + @Override protected void addEventEmitters(ThemedReactContext reactContext, WebView view) { // Do not register default touch emitter and let WebView implementation handle touches From 56d48bd9ecd2d0f08625259121312531064a09f2 Mon Sep 17 00:00:00 2001 From: Jacky Wijaya Date: Wed, 2 May 2018 18:49:17 -0700 Subject: [PATCH 0423/1109] Fix Android, DevServerHelper from calling okhttp3 response.body.string() twice Summary: Fixing from call response.body.string() twice in DevServerHelper.java. https://github.com/square/okhttp/issues/1240#issuecomment-68142603 I'm getting error like this ``` 05-01 21:16:47.080 22836-23064/com.my.company.bundle E/AndroidRuntime: FATAL EXCEPTION: OkHttp Dispatcher Process: com.my.company.bundle, PID: 22836 java.lang.IllegalStateException: closed at okio.RealBufferedSource.rangeEquals(RealBufferedSource.java:398) at okio.RealBufferedSource.rangeEquals(RealBufferedSource.java:392) at okhttp3.internal.c.a(Util.java:449) at okhttp3.v.string(ResponseBody.java:174) at com.facebook.react.devsupport.f$8.onResponse(DevServerHelper.java:487) at com.newrelic.agent.android.instrumentation.okhttp3.CallbackExtension.onResponse(CallbackExtension.java:41) at okhttp3.s$a.c(RealCall.java:153) at okhttp3.internal.b.run(NamedRunnable.java:32) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) at java.lang.Thread.run(Thread.java:764) ``` - In my case, My device is using a Proxy, and tried to connect the packager. When it failed from connecting packager through websocket, It crash by this line of code. [ANDROID] [BUGFIX] [DevServerHelper] - fixing from calling body.string() twice. Closes https://github.com/facebook/react-native/pull/19088 Differential Revision: D7853822 Pulled By: mdvacca fbshipit-source-id: c11a73ce2fa6d40b0a7bd8bc0fca7b07c6bc27ed --- .../java/com/facebook/react/devsupport/DevServerHelper.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 09d87f28088001..946377680e6922 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java @@ -479,10 +479,11 @@ public void onResponse(Call call, Response response) throws IOException { callback.onPackagerStatusFetched(false); return; } - if (!PACKAGER_OK_STATUS.equals(body.string())) { + String bodyString = body.string(); // cannot call body.string() twice, stored it into variable. https://github.com/square/okhttp/issues/1240#issuecomment-68142603 + if (!PACKAGER_OK_STATUS.equals(bodyString)) { FLog.e( ReactConstants.TAG, - "Got unexpected response from packager when requesting status: " + body.string()); + "Got unexpected response from packager when requesting status: " + bodyString); callback.onPackagerStatusFetched(false); return; } From be379efc9b677eac039a3d241d03aa4bb10d6a64 Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Wed, 2 May 2018 22:09:17 -0700 Subject: [PATCH 0424/1109] Minimize included defs by adding a level of indirection Reviewed By: zertosh Differential Revision: D7851714 fbshipit-source-id: aa14e003a612173c6f316cb76a26f7e78e7f15d4 --- ReactCommon/fabric/uimanager/BUCK | 7 +++---- ReactCommon/fabric/view/BUCK | 8 +++----- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/ReactCommon/fabric/uimanager/BUCK b/ReactCommon/fabric/uimanager/BUCK index 209502316d2b7b..6745136cf81715 100644 --- a/ReactCommon/fabric/uimanager/BUCK +++ b/ReactCommon/fabric/uimanager/BUCK @@ -1,5 +1,5 @@ load("//configurations/buck/apple:flag_defs.bzl", "get_debug_preprocessor_flags") -load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "get_apple_inspector_flags") +load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "get_apple_inspector_flags", "ANDROID", "APPLE") APPLE_COMPILER_FLAGS = [] @@ -57,9 +57,8 @@ rn_xplat_cxx_library( ) if not IS_OSS_BUILD: - load("@xplat//configurations/buck:default_platform_defs.bzl", "APPLE") - - cxx_test( + load("@xplat//build_defs:fb_xplat_cxx_test.bzl", "fb_xplat_cxx_test") + fb_xplat_cxx_test( name = "tests", srcs = glob(["tests/**/*.cpp"]), headers = glob(["tests/**/*.h"]), diff --git a/ReactCommon/fabric/view/BUCK b/ReactCommon/fabric/view/BUCK index d6ef5a048cfb30..1f2cff2c3fc77e 100644 --- a/ReactCommon/fabric/view/BUCK +++ b/ReactCommon/fabric/view/BUCK @@ -1,6 +1,5 @@ load("//configurations/buck/apple:flag_defs.bzl", "get_application_ios_flags", "get_debug_preprocessor_flags", "OBJC_ARC_PREPROCESSOR_FLAGS") -load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "rn_xplat_cxx_library", "get_apple_inspector_flags") -load("//ReactNative:DEFS.bzl", "react_native_xplat_target") +load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "rn_xplat_cxx_library", "get_apple_inspector_flags", "react_native_xplat_target", "ANDROID", "APPLE") APPLE_COMPILER_FLAGS = [] @@ -61,9 +60,8 @@ rn_xplat_cxx_library( ) if not IS_OSS_BUILD: - load("@xplat//configurations/buck:default_platform_defs.bzl", "APPLE") - - cxx_test( + load("@xplat//build_defs:fb_xplat_cxx_test.bzl", "fb_xplat_cxx_test") + fb_xplat_cxx_test( name = "tests", srcs = glob(["tests/**/*.cpp"]), headers = glob(["tests/**/*.h"]), From e8662a2123a0dfd4caefb2233a6df29faa0774b0 Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Thu, 3 May 2018 08:38:00 -0700 Subject: [PATCH 0425/1109] Add react dev menu setting for cpp deltas Summary: Adds a menu item to enable handling of JS module deltas in native code. The check box is dependent on JS Deltas being activated in the first place. Reviewed By: cpojer Differential Revision: D7380167 fbshipit-source-id: 3001d12140542b4e52b1ce96be3c5f56e52a15f8 --- .../react/devsupport/DevInternalSettings.java | 12 ++++++++++++ .../src/main/res/devsupport/xml/preferences.xml | 7 +++++++ 2 files changed, 19 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevInternalSettings.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevInternalSettings.java index e3204e6457bf9f..5c07b7ead430c2 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevInternalSettings.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevInternalSettings.java @@ -30,6 +30,7 @@ public class DevInternalSettings implements private static final String PREFS_JS_DEV_MODE_DEBUG_KEY = "js_dev_mode_debug"; private static final String PREFS_JS_MINIFY_DEBUG_KEY = "js_minify_debug"; private static final String PREFS_JS_BUNDLE_DELTAS_KEY = "js_bundle_deltas"; + private static final String PREFS_JS_BUNDLE_DELTAS_CPP_KEY = "js_bundle_deltas_cpp"; private static final String PREFS_ANIMATIONS_DEBUG_KEY = "animations_debug"; private static final String PREFS_RELOAD_ON_JS_CHANGE_KEY = "reload_on_js_change"; private static final String PREFS_INSPECTOR_DEBUG_KEY = "inspector_debug"; @@ -83,6 +84,7 @@ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, Strin || PREFS_RELOAD_ON_JS_CHANGE_KEY.equals(key) || PREFS_JS_DEV_MODE_DEBUG_KEY.equals(key) || PREFS_JS_BUNDLE_DELTAS_KEY.equals(key) + || PREFS_JS_BUNDLE_DELTAS_CPP_KEY.equals(key) || PREFS_JS_MINIFY_DEBUG_KEY.equals(key)) { mListener.onInternalSettingsChanged(); } @@ -123,6 +125,16 @@ public void setBundleDeltasEnabled(boolean enabled) { mPreferences.edit().putBoolean(PREFS_JS_BUNDLE_DELTAS_KEY, enabled).apply(); } + @SuppressLint("SharedPreferencesUse") + public boolean isBundleDeltasCppEnabled() { + return mPreferences.getBoolean(PREFS_JS_BUNDLE_DELTAS_CPP_KEY, false); + } + + @SuppressLint("SharedPreferencesUse") + public void setBundleDeltasCppEnabled(boolean enabled) { + mPreferences.edit().putBoolean(PREFS_JS_BUNDLE_DELTAS_CPP_KEY, enabled).apply(); + } + @Override public boolean isNuclideJSDebugEnabled() { return ReactBuildConfig.IS_INTERNAL_BUILD && ReactBuildConfig.DEBUG; diff --git a/ReactAndroid/src/main/res/devsupport/xml/preferences.xml b/ReactAndroid/src/main/res/devsupport/xml/preferences.xml index 7ce20de3fa5bc2..bb98248b93f0da 100644 --- a/ReactAndroid/src/main/res/devsupport/xml/preferences.xml +++ b/ReactAndroid/src/main/res/devsupport/xml/preferences.xml @@ -25,6 +25,13 @@ android:summary="Request delta bundles from metro to get faster reloads (Experimental)" android:defaultValue="true" /> + Date: Thu, 3 May 2018 08:38:01 -0700 Subject: [PATCH 0426/1109] Add native delta client for Metro Summary: Adds C++ delta client that keeps modules in memory, and can be used as a RAM bundle. For now, this client expects a `folly::dynamic` object as payload for patches, i.e. the JSON response retrieved from Metro needs to be parsed with `folly::parseJson` by the caller. In the future, we will replace JSON with a streaming friendly binary format. Reviewed By: fromcelticpark Differential Revision: D7845136 fbshipit-source-id: f003f98a2607c8354c427a7e60e01e19e20295b1 --- .../jni/react/jni/JniJSModulesUnbundle.cpp | 2 +- ReactCommon/cxxreact/Android.mk | 1 + ReactCommon/cxxreact/BUCK | 1 + ReactCommon/cxxreact/JSDeltaBundleClient.cpp | 72 +++++++++++++++++++ ReactCommon/cxxreact/JSDeltaBundleClient.h | 42 +++++++++++ ReactCommon/cxxreact/JSModulesUnbundle.h | 4 ++ 6 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 ReactCommon/cxxreact/JSDeltaBundleClient.cpp create mode 100644 ReactCommon/cxxreact/JSDeltaBundleClient.h diff --git a/ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.cpp b/ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.cpp index be00bfdcbee268..504f937c0cf283 100644 --- a/ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.cpp +++ b/ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.cpp @@ -82,7 +82,7 @@ JSModulesUnbundle::Module JniJSModulesUnbundle::getModule(uint32_t moduleId) con buffer = static_cast(AAsset_getBuffer(asset.get())); } if (buffer == nullptr) { - throw ModuleNotFound("Module not found: " + sourceUrl); + throw ModuleNotFound(moduleId); } return {sourceUrl, std::string(buffer, AAsset_getLength(asset.get()))}; } diff --git a/ReactCommon/cxxreact/Android.mk b/ReactCommon/cxxreact/Android.mk index 1c22c761e6ef93..8efb42a3a15018 100644 --- a/ReactCommon/cxxreact/Android.mk +++ b/ReactCommon/cxxreact/Android.mk @@ -17,6 +17,7 @@ LOCAL_SRC_FILES := \ JSCSamplingProfiler.cpp \ JSCTracing.cpp \ JSCUtils.cpp \ + JSDeltaBundleClient.cpp \ JSExecutor.cpp \ JSIndexedRAMBundle.cpp \ MethodCall.cpp \ diff --git a/ReactCommon/cxxreact/BUCK b/ReactCommon/cxxreact/BUCK index 515ff8cb35df9b..c5b958918f7b35 100644 --- a/ReactCommon/cxxreact/BUCK +++ b/ReactCommon/cxxreact/BUCK @@ -92,6 +92,7 @@ CXXREACT_PUBLIC_HEADERS = [ "JSCExecutor.h", "JSCNativeModules.h", "JSCUtils.h", + "JSDeltaBundleClient.h", "JSIndexedRAMBundle.h", "JSModulesUnbundle.h", "MessageQueueThread.h", diff --git a/ReactCommon/cxxreact/JSDeltaBundleClient.cpp b/ReactCommon/cxxreact/JSDeltaBundleClient.cpp new file mode 100644 index 00000000000000..8c082d04c8fb10 --- /dev/null +++ b/ReactCommon/cxxreact/JSDeltaBundleClient.cpp @@ -0,0 +1,72 @@ +#include "JSDeltaBundleClient.h" + +#include + +#include + +namespace facebook { +namespace react { + +namespace { + std::string startupCode(const folly::dynamic *pre, const folly::dynamic *post) { + std::ostringstream startupCode; + + for (auto section : {pre, post}) { + if (section != nullptr) { + for (folly::dynamic pair : *section) { + startupCode << pair[1].getString() << '\n'; + } + } + } + + return startupCode.str(); + } +} // namespace + +void JSDeltaBundleClient::patch(const folly::dynamic& delta) { + auto const reset = delta.get_ptr("reset"); + if (reset != nullptr && reset->asBool()) { + clear(); + } + + auto const pre = delta.get_ptr("pre"); + auto const post = delta.get_ptr("post"); + + if ((pre != nullptr && pre->size() > 0) || (post != nullptr && post->size() > 0)) { + startupCode_ = startupCode(pre, post); + } + + const folly::dynamic *modules = delta.get_ptr("delta"); + if (modules != nullptr) { + for (const folly::dynamic pair : *modules) { + auto id = pair[0].getInt(); + auto module = pair[1]; + if (module.isNull()) { + modules_.erase(id); + } else { + modules_.emplace(id, module.getString()); + } + } + } +} + +JSModulesUnbundle::Module JSDeltaBundleClient::getModule(uint32_t moduleId) const { + auto search = modules_.find(moduleId); + if (search != modules_.end()) { + return {folly::to(search->first, ".js"), search->second}; + } + + throw JSModulesUnbundle::ModuleNotFound(moduleId); +} + +std::unique_ptr JSDeltaBundleClient::getStartupCode() const { + return folly::make_unique(startupCode_); +} + +void JSDeltaBundleClient::clear() { + modules_.clear(); + startupCode_.clear(); +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/cxxreact/JSDeltaBundleClient.h b/ReactCommon/cxxreact/JSDeltaBundleClient.h new file mode 100644 index 00000000000000..107bd39880df68 --- /dev/null +++ b/ReactCommon/cxxreact/JSDeltaBundleClient.h @@ -0,0 +1,42 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include +#include +#include + +#include +#include +#include + +namespace facebook { +namespace react { + +class JSDeltaBundleClient { +public: + void patch(const folly::dynamic& delta); + JSModulesUnbundle::Module getModule(uint32_t moduleId) const; + std::unique_ptr getStartupCode() const; + void clear(); + +private: + std::unordered_map modules_; + std::string startupCode_; +}; + +class JSDeltaBundleClientRAMBundle : public JSModulesUnbundle { +public: + JSDeltaBundleClientRAMBundle( + std::shared_ptr client) : client_(client) {} + + Module getModule(uint32_t moduleId) const override { + return client_->getModule(moduleId); + } +private: + const std::shared_ptr client_; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/cxxreact/JSModulesUnbundle.h b/ReactCommon/cxxreact/JSModulesUnbundle.h index a04d5808ccd70b..bbf3a6c8d8c020 100644 --- a/ReactCommon/cxxreact/JSModulesUnbundle.h +++ b/ReactCommon/cxxreact/JSModulesUnbundle.h @@ -6,6 +6,7 @@ #include #include +#include #include namespace facebook { @@ -21,7 +22,10 @@ class JSModulesUnbundle : noncopyable { */ public: class ModuleNotFound : public std::out_of_range { + public: using std::out_of_range::out_of_range; + ModuleNotFound(uint32_t moduleId) : std::out_of_range::out_of_range( + folly::to("Module not found: ", moduleId)) {} }; struct Module { std::string name; From 82b8a9221ace6e13340d9e0dba27f69dca4edd99 Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Thu, 3 May 2018 08:38:03 -0700 Subject: [PATCH 0427/1109] Add hybrid class to hold native delta client Summary: Adds hybrid JNI wrapper class that can hold a native delta client. This class allows Java code in the `devsupport` package to hold onto a native delta client across reloads. It also takes care of passing `okhttp` response objects to native code, where we build a `std::string` to hold JSON messages coming from Metro, and parse them with `folly::parseJson`. In a follow-up, we will switch to a streaming-friendly binary format that will make allocating memory for the whole message unnecessary. Reviewed By: fromcelticpark Differential Revision: D7845138 fbshipit-source-id: 7a29b30645331addf843097dd0d05c03b3143991 --- .../react/bridge/NativeDeltaClient.java | 25 +++++++++ .../src/main/jni/react/jni/Android.mk | 1 + .../main/jni/react/jni/NativeDeltaClient.cpp | 54 +++++++++++++++++++ .../main/jni/react/jni/NativeDeltaClient.h | 38 +++++++++++++ .../src/main/jni/react/jni/OnLoad.cpp | 2 + 5 files changed, 120 insertions(+) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/bridge/NativeDeltaClient.java create mode 100644 ReactAndroid/src/main/jni/react/jni/NativeDeltaClient.cpp create mode 100644 ReactAndroid/src/main/jni/react/jni/NativeDeltaClient.h diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeDeltaClient.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeDeltaClient.java new file mode 100644 index 00000000000000..6b87c972c275d6 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeDeltaClient.java @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2018-present, Facebook, Inc. + * + * 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; + +import java.nio.channels.ReadableByteChannel; + +import com.facebook.jni.HybridData; + +public class NativeDeltaClient { + static { + ReactBridge.staticInit(); + } + + // C++ parts + private final HybridData mHybridData = initHybrid(); + private native static HybridData initHybrid(); + + public native void reset(); + public native void processDelta(ReadableByteChannel deltaMessage); +} diff --git a/ReactAndroid/src/main/jni/react/jni/Android.mk b/ReactAndroid/src/main/jni/react/jni/Android.mk index 8d8b992d52432e..313950674e13d9 100644 --- a/ReactAndroid/src/main/jni/react/jni/Android.mk +++ b/ReactAndroid/src/main/jni/react/jni/Android.mk @@ -18,6 +18,7 @@ LOCAL_SRC_FILES := \ ModuleRegistryBuilder.cpp \ NativeArray.cpp \ NativeCommon.cpp \ + NativeDeltaClient.cpp \ NativeMap.cpp \ OnLoad.cpp \ ProxyExecutor.cpp \ diff --git a/ReactAndroid/src/main/jni/react/jni/NativeDeltaClient.cpp b/ReactAndroid/src/main/jni/react/jni/NativeDeltaClient.cpp new file mode 100644 index 00000000000000..2c35306caf8421 --- /dev/null +++ b/ReactAndroid/src/main/jni/react/jni/NativeDeltaClient.cpp @@ -0,0 +1,54 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include "NativeDeltaClient.h" + +#include +#include +#include + +namespace facebook { +namespace react { + +jni::local_ref NativeDeltaClient::initHybrid( + jni::alias_ref) { + return makeCxxInstance(); +} + +void NativeDeltaClient::registerNatives() { + registerHybrid({ + makeNativeMethod("initHybrid", NativeDeltaClient::initHybrid), + makeNativeMethod("processDelta", NativeDeltaClient::jniProcessDelta), + makeNativeMethod("reset", NativeDeltaClient::jniReset), + }); +} + +void NativeDeltaClient::jniProcessDelta( + jni::alias_ref delta) { + + std::ostringstream deltaMessage; + std::vector buffer(8192); + auto byteBuffer = jni::JByteBuffer::wrapBytes(buffer.data(), buffer.size()); + + size_t pos = 0; + int read = 0; + do { + read = delta->read(byteBuffer); + if (read < 1) { + deltaMessage.write(reinterpret_cast(buffer.data()), pos); + byteBuffer->rewind(); + pos = 0; + } else { + pos += read; + } + } while (read != -1); + + + deltaClient_->patch(folly::parseJson(deltaMessage.str())); +} + +void NativeDeltaClient::jniReset() { + deltaClient_->clear(); +} + +} // namespace react +} // namespace facebook diff --git a/ReactAndroid/src/main/jni/react/jni/NativeDeltaClient.h b/ReactAndroid/src/main/jni/react/jni/NativeDeltaClient.h new file mode 100644 index 00000000000000..5e2eea14ae225b --- /dev/null +++ b/ReactAndroid/src/main/jni/react/jni/NativeDeltaClient.h @@ -0,0 +1,38 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include + +#include +#include +#include +#include + +namespace facebook { +namespace react { + +class NativeDeltaClient : public jni::HybridClass { + +public: + static constexpr auto kJavaDescriptor = + "Lcom/facebook/react/bridge/NativeDeltaClient;"; + static jni::local_ref initHybrid(jni::alias_ref); + static void registerNatives(); + + ~NativeDeltaClient() override = default; + + std::shared_ptr getDeltaClient() { + return deltaClient_; + } + +private: + friend HybridBase; + void jniProcessDelta(jni::alias_ref delta); + void jniReset(); + const std::shared_ptr deltaClient_ = + std::make_shared(); +}; + +} // namespace react +} // namespace facebook diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp index ec97e56e5b1d02..81cc8f33419641 100644 --- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp +++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp @@ -16,6 +16,7 @@ #include "CxxModuleWrapper.h" #include "JavaScriptExecutorHolder.h" #include "JCallback.h" +#include "NativeDeltaClient.h" #include "ProxyExecutor.h" #include "WritableNativeArray.h" #include "WritableNativeMap.h" @@ -91,6 +92,7 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { CxxModuleWrapper::registerNatives(); JCxxCallbackImpl::registerNatives(); NativeArray::registerNatives(); + NativeDeltaClient::registerNatives(); ReadableNativeArray::registerNatives(); WritableNativeArray::registerNatives(); NativeMap::registerNatives(); From 36f254aa75316d3605d4becee8a6dc8fb2e202cc Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Thu, 3 May 2018 08:38:06 -0700 Subject: [PATCH 0428/1109] `CatalystInstanceImpl`: Method for loading from delta client Summary: Adds `loadScriptFromDeltaBundle` / `jniLoadScriptFromDeltaBundle` methods to `CatalystInstanceImpl`. These methods allow to run JS coming from a native delta client as RAM bundles, to leverage the RAM bundle mechanism for development / reload scenarios. Reviewed By: fromcelticpark Differential Revision: D7845140 fbshipit-source-id: b79b340f36c28939a31eb63a3c463d0792a208f7 --- .../react/bridge/CatalystInstanceImpl.java | 9 +++++++++ .../jni/react/jni/CatalystInstanceImpl.cpp | 18 ++++++++++++++++++ .../main/jni/react/jni/CatalystInstanceImpl.h | 2 ++ 3 files changed, 29 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java index 7ab1216267db6c..b8930d1a4154f8 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java @@ -221,10 +221,19 @@ public void registerSegment(int segmentId, String path) { jniLoadScriptFromFile(fileName, sourceURL, loadSynchronously); } + /* package */ void loadScriptFromDeltaBundle( + String sourceURL, + NativeDeltaClient deltaClient, + boolean loadSynchronously) { + mSourceURL = sourceURL; + jniLoadScriptFromDeltaBundle(sourceURL, deltaClient, loadSynchronously); + } + private native void jniSetSourceURL(String sourceURL); private native void jniRegisterSegment(int segmentId, String path); private native void jniLoadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously); private native void jniLoadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously); + private native void jniLoadScriptFromDeltaBundle(String sourceURL, NativeDeltaClient deltaClient, boolean loadSynchronously); @Override public void runJSBundle() { diff --git a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp index 7b136f0d0cdf14..aeb4cc55e1099b 100644 --- a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp +++ b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp @@ -4,17 +4,21 @@ #include #include +#include +#include #include #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -100,6 +104,7 @@ void CatalystInstanceImpl::registerNatives() { makeNativeMethod("jniRegisterSegment", CatalystInstanceImpl::jniRegisterSegment), makeNativeMethod("jniLoadScriptFromAssets", CatalystInstanceImpl::jniLoadScriptFromAssets), makeNativeMethod("jniLoadScriptFromFile", CatalystInstanceImpl::jniLoadScriptFromFile), + makeNativeMethod("jniLoadScriptFromDeltaBundle", CatalystInstanceImpl::jniLoadScriptFromDeltaBundle), makeNativeMethod("jniCallJSFunction", CatalystInstanceImpl::jniCallJSFunction), makeNativeMethod("jniCallJSCallback", CatalystInstanceImpl::jniCallJSCallback), makeNativeMethod("setGlobalVariable", CatalystInstanceImpl::setGlobalVariable), @@ -210,6 +215,19 @@ void CatalystInstanceImpl::jniLoadScriptFromFile(const std::string& fileName, } } +void CatalystInstanceImpl::jniLoadScriptFromDeltaBundle( + const std::string& sourceURL, + jni::alias_ref jDeltaClient, + bool loadSynchronously) { + + auto deltaClient = jDeltaClient->cthis()->getDeltaClient(); + auto registry = RAMBundleRegistry::singleBundleRegistry( + folly::make_unique(deltaClient)); + + instance_->loadRAMBundle( + std::move(registry), deltaClient->getStartupCode(), sourceURL, loadSynchronously); +} + void CatalystInstanceImpl::jniCallJSFunction(std::string module, std::string method, NativeArray* arguments) { // We want to share the C++ code, and on iOS, modules pass module/method // names as strings all the way through to JS, and there's no way to do diff --git a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h index 5f7b1be15157e6..622edb769d0f7e 100644 --- a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h +++ b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h @@ -10,6 +10,7 @@ #include "JMessageQueueThread.h" #include "JSLoader.h" #include "ModuleRegistryBuilder.h" +#include "NativeDeltaClient.h" namespace facebook { namespace react { @@ -66,6 +67,7 @@ class CatalystInstanceImpl : public jni::HybridClass { void jniLoadScriptFromAssets(jni::alias_ref assetManager, const std::string& assetURL, bool loadSynchronously); void jniLoadScriptFromFile(const std::string& fileName, const std::string& sourceURL, bool loadSynchronously); + void jniLoadScriptFromDeltaBundle(const std::string& sourceURL, jni::alias_ref deltaClient, bool loadSynchronously); void jniCallJSFunction(std::string module, std::string method, NativeArray* arguments); void jniCallJSCallback(jint callbackId, NativeArray* arguments); void setGlobalVariable(std::string propName, From 3e730528eea3c2a8dc4dda58bed87377122a288a Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Thu, 3 May 2018 08:38:08 -0700 Subject: [PATCH 0429/1109] Allow to not use native delta client Summary: Adds the possibility to disable native delta clients in `DevInternalSettings` Depending on the bridge in use, there might not be support for native delta clients, but since the settings are shared app-wide, it can not be enabled individually. Reviewed By: johnislarry Differential Revision: D7845137 fbshipit-source-id: ab368e6fed0f4bec49032c4a20466e156d20fdae --- .../react/devsupport/DevInternalSettings.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevInternalSettings.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevInternalSettings.java index 5c07b7ead430c2..e9ebe0c2492fb6 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevInternalSettings.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevInternalSettings.java @@ -40,14 +40,29 @@ public class DevInternalSettings implements private final SharedPreferences mPreferences; private final Listener mListener; private final PackagerConnectionSettings mPackagerConnectionSettings; + private final boolean mSupportsNativeDeltaClients; + + public static DevInternalSettings withoutNativeDeltaClient( + Context applicationContext, + Listener listener) { + return new DevInternalSettings(applicationContext, listener, false); + } public DevInternalSettings( Context applicationContext, Listener listener) { + this(applicationContext, listener, true); + } + + private DevInternalSettings( + Context applicationContext, + Listener listener, + boolean supportsNativeDeltaClients) { mListener = listener; mPreferences = PreferenceManager.getDefaultSharedPreferences(applicationContext); mPreferences.registerOnSharedPreferenceChangeListener(this); mPackagerConnectionSettings = new PackagerConnectionSettings(applicationContext); + mSupportsNativeDeltaClients = supportsNativeDeltaClients; } public PackagerConnectionSettings getPackagerConnectionSettings() { @@ -127,7 +142,7 @@ public void setBundleDeltasEnabled(boolean enabled) { @SuppressLint("SharedPreferencesUse") public boolean isBundleDeltasCppEnabled() { - return mPreferences.getBoolean(PREFS_JS_BUNDLE_DELTAS_CPP_KEY, false); + return mSupportsNativeDeltaClients && mPreferences.getBoolean(PREFS_JS_BUNDLE_DELTAS_CPP_KEY, false); } @SuppressLint("SharedPreferencesUse") From 8f85abdb14b4e4abf521e23cf69e15d06a8c3480 Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Thu, 3 May 2018 08:38:11 -0700 Subject: [PATCH 0430/1109] `JSBundleLoader`: allow to load with delta client Summary: Adds glue between `CatalystInstance` and `JSBundleLoader`: Adds the possibility to create a `JSBundleLoader` instance that calls into `CatalystInstanceImpl#loadScriptFromDeltaBundle(...)`. Reviewed By: fromcelticpark Differential Revision: D7845134 fbshipit-source-id: 9585b44a6e7c63245c9f634543642be55c928896 --- .../facebook/react/bridge/JSBundleLoader.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) 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 61bc6f01816273..c62b1675aa0fa3 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java @@ -8,6 +8,7 @@ package com.facebook.react.bridge; import android.content.Context; +import com.facebook.react.bridge.NativeDeltaClient; import com.facebook.react.common.DebugServerException; /** @@ -78,6 +79,28 @@ public String loadScript(CatalystInstanceImpl instance) { }; } + /** + * This loader is used to load delta bundles from the dev server. We pass each delta message to + * the loader and process it in C++. Passing it as a string leads to inefficiencies due to memory + * copies, which will have to be addressed in a follow-up. + * @param nativeDeltaClient + */ + public static JSBundleLoader createDeltaFromNetworkLoader( + final String sourceURL, + final NativeDeltaClient nativeDeltaClient) { + return new JSBundleLoader() { + @Override + public String loadScript(CatalystInstanceImpl instance) { + try { + instance.loadScriptFromDeltaBundle(sourceURL, nativeDeltaClient, false); + return sourceURL; + } catch (Exception e) { + throw DebugServerException.makeGeneric(e.getMessage(), e); + } + } + }; + } + /** * This loader is used when proxy debugging is enabled. In that case there is no point in fetching * the bundle from device as remote executor will have to do it anyway. From dd036c23284c52da693302727b4d1b112c37e807 Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Thu, 3 May 2018 08:38:13 -0700 Subject: [PATCH 0431/1109] Hook up native delta client Summary: Adds support for native clients to `ReactAndroid`: - `.devsupport.BundleDeltaClient` is now abstract with two implementations: the existing Java client, and a native client - `BundleDeltaClient#processDelta(...)` can now return a native delta client object - if that client object is non-null, the bridge is started up with that client rather than a script written to disk Reviewed By: fromcelticpark Differential Revision: D7845135 fbshipit-source-id: 379a9c6f9319c62eec3c370cda9ffa0969266a29 --- .../facebook/react/ReactInstanceManager.java | 23 +- .../react/devsupport/BundleDeltaClient.java | 224 ++++++++++++------ .../react/devsupport/BundleDownloader.java | 52 ++-- .../react/devsupport/DevServerHelper.java | 12 +- .../devsupport/DevSupportManagerImpl.java | 7 +- .../ReactInstanceManagerDevHelper.java | 4 +- .../interfaces/DevBundleDownloadListener.java | 3 +- 7 files changed, 222 insertions(+), 103 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java index b97f6f45bab221..24a57c759b157a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java @@ -50,6 +50,7 @@ import com.facebook.react.bridge.JavaJSExecutor; import com.facebook.react.bridge.JavaScriptExecutor; import com.facebook.react.bridge.JavaScriptExecutorFactory; +import com.facebook.react.bridge.NativeDeltaClient; import com.facebook.react.bridge.NativeModuleCallExceptionHandler; import com.facebook.react.bridge.NativeModuleRegistry; import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener; @@ -84,6 +85,7 @@ import com.facebook.soloader.SoLoader; import com.facebook.systrace.Systrace; import com.facebook.systrace.SystraceMessage; + import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -270,8 +272,8 @@ public void onReloadWithJSDebugger(JavaJSExecutor.Factory jsExecutorFactory) { } @Override - public void onJSBundleLoadedFromServer() { - ReactInstanceManager.this.onJSBundleLoadedFromServer(); + public void onJSBundleLoadedFromServer(@Nullable NativeDeltaClient nativeDeltaClient) { + ReactInstanceManager.this.onJSBundleLoadedFromServer(nativeDeltaClient); } @Override @@ -360,7 +362,7 @@ private void recreateReactContextInBackgroundInner() { !devSettings.isRemoteJSDebugEnabled()) { // If there is a up-to-date bundle downloaded from server, // with remote JS debugging disabled, always use that. - onJSBundleLoadedFromServer(); + onJSBundleLoadedFromServer(null); } else if (mBundleLoader == null) { mDevSupportManager.handleReloadJS(); } else { @@ -848,12 +850,17 @@ private void onReloadWithJSDebugger(JavaJSExecutor.Factory jsExecutorFactory) { } @ThreadConfined(UI) - private void onJSBundleLoadedFromServer() { + private void onJSBundleLoadedFromServer(@Nullable NativeDeltaClient nativeDeltaClient) { Log.d(ReactConstants.TAG, "ReactInstanceManager.onJSBundleLoadedFromServer()"); - recreateReactContextInBackground( - mJavaScriptExecutorFactory, - JSBundleLoader.createCachedBundleFromNetworkLoader( - mDevSupportManager.getSourceUrl(), mDevSupportManager.getDownloadedJSBundleFile())); + + JSBundleLoader bundleLoader = nativeDeltaClient == null + ? JSBundleLoader.createCachedBundleFromNetworkLoader( + mDevSupportManager.getSourceUrl(), + mDevSupportManager.getDownloadedJSBundleFile()) + : JSBundleLoader.createDeltaFromNetworkLoader( + mDevSupportManager.getSourceUrl(), nativeDeltaClient); + + recreateReactContextInBackground(mJavaScriptExecutorFactory, bundleLoader); } @ThreadConfined(UI) diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDeltaClient.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDeltaClient.java index 68ef0ce138ae51..93fbb49679e753 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDeltaClient.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDeltaClient.java @@ -1,121 +1,197 @@ +/** + * Copyright (c) 2018-present, Facebook, Inc. + * + * 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 android.util.JsonReader; -import android.util.JsonToken; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.util.LinkedHashMap; import javax.annotation.Nullable; + +import android.util.JsonReader; +import android.util.JsonToken; +import android.util.Pair; +import com.facebook.react.bridge.NativeDeltaClient; +import okhttp3.Headers; +import okio.Buffer; import okio.BufferedSource; -public class BundleDeltaClient { +public abstract class BundleDeltaClient { - final LinkedHashMap mPreModules = new LinkedHashMap(); - final LinkedHashMap mDeltaModules = new LinkedHashMap(); - final LinkedHashMap mPostModules = new LinkedHashMap(); - @Nullable String mDeltaId; + private static final String METRO_DELTA_ID_HEADER = "X-Metro-Delta-ID"; + @Nullable private String mDeltaId; - static boolean isDeltaUrl(String bundleUrl) { - return bundleUrl.indexOf(".delta?") != -1; + public enum ClientType { + NONE, + DEV_SUPPORT, + NATIVE } - public void reset() { - mDeltaId = null; - mDeltaModules.clear(); - mPreModules.clear(); - mPostModules.clear(); + static boolean isDeltaUrl(String bundleUrl) { + return bundleUrl.indexOf(".delta?") != -1; } - public String toDeltaUrl(String bundleURL) { - if (isDeltaUrl(bundleURL) && mDeltaId != null) { - return bundleURL + "&deltaBundleId=" + mDeltaId; + @Nullable + static BundleDeltaClient create(ClientType type) { + switch (type) { + case DEV_SUPPORT: + return new BundleDeltaJavaClient(); + case NATIVE: + return new BundleDeltaNativeClient(); } - return bundleURL; + return null; } - public synchronized boolean storeDeltaInFile(BufferedSource body, File outputFile) - throws IOException { + abstract public boolean canHandle(ClientType type); - JsonReader jsonReader = new JsonReader(new InputStreamReader(body.inputStream())); + abstract protected Pair processDelta( + BufferedSource body, + File outputFile) throws IOException; - jsonReader.beginObject(); + final public String extendUrlForDelta(String bundleURL) { + return mDeltaId != null ? bundleURL + "&deltaBundleId=" + mDeltaId : bundleURL; + } - int numChangedModules = 0; + public void reset() { + mDeltaId = null; + } - while (jsonReader.hasNext()) { - String name = jsonReader.nextName(); - if (name.equals("id")) { - mDeltaId = jsonReader.nextString(); - } else if (name.equals("pre")) { - numChangedModules += patchDelta(jsonReader, mPreModules); - } else if (name.equals("post")) { - numChangedModules += patchDelta(jsonReader, mPostModules); - } else if (name.equals("delta")) { - numChangedModules += patchDelta(jsonReader, mDeltaModules); - } else { - jsonReader.skipValue(); - } - } + public Pair processDelta( + Headers headers, + BufferedSource body, + File outputFile) throws IOException { + + mDeltaId = headers.get(METRO_DELTA_ID_HEADER); + return processDelta(body, outputFile); + } - jsonReader.endObject(); - jsonReader.close(); + private static class BundleDeltaJavaClient extends BundleDeltaClient { - if (numChangedModules == 0) { - // If we receive an empty delta, we don't need to save the file again (it'll have the - // same content). - return false; + final LinkedHashMap mPreModules = new LinkedHashMap(); + final LinkedHashMap mDeltaModules = new LinkedHashMap(); + final LinkedHashMap mPostModules = new LinkedHashMap(); + + @Override + public boolean canHandle(ClientType type) { + return type == ClientType.DEV_SUPPORT; } - FileOutputStream fileOutputStream = new FileOutputStream(outputFile); + public void reset() { + super.reset(); + mDeltaModules.clear(); + mPreModules.clear(); + mPostModules.clear(); + } - try { - for (byte[] code : mPreModules.values()) { - fileOutputStream.write(code); - fileOutputStream.write('\n'); + @Override + public synchronized Pair processDelta( + BufferedSource body, + File outputFile) throws IOException { + + JsonReader jsonReader = new JsonReader(new InputStreamReader(body.inputStream())); + jsonReader.beginObject(); + int numChangedModules = 0; + + while (jsonReader.hasNext()) { + String name = jsonReader.nextName(); + if (name.equals("pre")) { + numChangedModules += patchDelta(jsonReader, mPreModules); + } else if (name.equals("post")) { + numChangedModules += patchDelta(jsonReader, mPostModules); + } else if (name.equals("delta")) { + numChangedModules += patchDelta(jsonReader, mDeltaModules); + } else { + jsonReader.skipValue(); + } } - for (byte[] code : mDeltaModules.values()) { - fileOutputStream.write(code); - fileOutputStream.write('\n'); + jsonReader.endObject(); + jsonReader.close(); + + if (numChangedModules == 0) { + // If we receive an empty delta, we don't need to save the file again (it'll have the + // same content). + return Pair.create(Boolean.FALSE, null); } - for (byte[] code : mPostModules.values()) { - fileOutputStream.write(code); - fileOutputStream.write('\n'); + FileOutputStream fileOutputStream = new FileOutputStream(outputFile); + + try { + for (byte[] code : mPreModules.values()) { + fileOutputStream.write(code); + fileOutputStream.write('\n'); + } + + for (byte[] code : mDeltaModules.values()) { + fileOutputStream.write(code); + fileOutputStream.write('\n'); + } + + for (byte[] code : mPostModules.values()) { + fileOutputStream.write(code); + fileOutputStream.write('\n'); + } + } finally { + fileOutputStream.flush(); + fileOutputStream.close(); } - } finally { - fileOutputStream.flush(); - fileOutputStream.close(); + + return Pair.create(Boolean.TRUE, null); } - return true; - } + private static int patchDelta(JsonReader jsonReader, LinkedHashMap map) + throws IOException { + jsonReader.beginArray(); - private static int patchDelta(JsonReader jsonReader, LinkedHashMap map) - throws IOException { - jsonReader.beginArray(); + int numModules = 0; + while (jsonReader.hasNext()) { + jsonReader.beginArray(); - int numModules = 0; - while (jsonReader.hasNext()) { - jsonReader.beginArray(); + int moduleId = jsonReader.nextInt(); - int moduleId = jsonReader.nextInt(); + if (jsonReader.peek() == JsonToken.NULL) { + jsonReader.skipValue(); + map.remove(moduleId); + } else { + map.put(moduleId, jsonReader.nextString().getBytes()); + } - if (jsonReader.peek() == JsonToken.NULL) { - jsonReader.skipValue(); - map.remove(moduleId); - } else { - map.put(moduleId, jsonReader.nextString().getBytes()); + jsonReader.endArray(); + numModules++; } jsonReader.endArray(); - numModules++; + + return numModules; + } + } + + private static class BundleDeltaNativeClient extends BundleDeltaClient { + private final NativeDeltaClient nativeClient = new NativeDeltaClient(); + + @Override + public boolean canHandle(ClientType type) { + return type == ClientType.NATIVE; } - jsonReader.endArray(); + @Override + protected Pair processDelta( + BufferedSource body, + File outputFile) throws IOException { + nativeClient.processDelta(body); + return Pair.create(Boolean.FALSE, nativeClient); + } - return numModules; + @Override + public void reset() { + super.reset(); + nativeClient.reset(); + } } } 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 b7c7ed7b962a8a..69f50a832e98ee 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDownloader.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDownloader.java @@ -8,8 +8,10 @@ package com.facebook.react.devsupport; import android.util.Log; +import android.util.Pair; import com.facebook.common.logging.FLog; import com.facebook.infer.annotation.Assertions; +import com.facebook.react.bridge.NativeDeltaClient; import com.facebook.react.common.DebugServerException; import com.facebook.react.common.ReactConstants; import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener; @@ -40,7 +42,7 @@ public class BundleDownloader { private final OkHttpClient mClient; - private final BundleDeltaClient mBundleDeltaClient = new BundleDeltaClient(); + private BundleDeltaClient mBundleDeltaClient; private @Nullable Call mDownloadBundleFromURLCall; @@ -95,14 +97,15 @@ public BundleDownloader(OkHttpClient client) { } public void downloadBundleFromURL( - final DevBundleDownloadListener callback, - final File outputFile, - final String bundleURL, - final @Nullable BundleInfo bundleInfo) { + final DevBundleDownloadListener callback, + final File outputFile, + final String bundleURL, + final @Nullable BundleInfo bundleInfo, + final BundleDeltaClient.ClientType clientType) { final Request request = new Request.Builder() - .url(mBundleDeltaClient.toDeltaUrl(bundleURL)) + .url(formatBundleUrl(bundleURL, clientType)) // FIXME: there is a bug that makes MultipartStreamReader to never find the end of the // multipart message. This temporarily disables the multipart mode to work around it, // but @@ -146,7 +149,7 @@ public void onResponse(Call call, final Response response) throws IOException { try (Response r = response) { if (match.find()) { processMultipartResponse( - url, r, match.group(1), outputFile, bundleInfo, callback); + url, r, match.group(1), outputFile, bundleInfo, clientType, callback); } else { // In case the server doesn't support multipart/mixed responses, fallback to normal // download. @@ -157,6 +160,7 @@ public void onResponse(Call call, final Response response) throws IOException { Okio.buffer(r.body().source()), outputFile, bundleInfo, + clientType, callback); } } @@ -164,12 +168,19 @@ public void onResponse(Call call, final Response response) throws IOException { }); } + private String formatBundleUrl(String bundleURL, BundleDeltaClient.ClientType clientType) { + return BundleDeltaClient.isDeltaUrl(bundleURL) && mBundleDeltaClient != null && mBundleDeltaClient.canHandle(clientType) + ? mBundleDeltaClient.extendUrlForDelta(bundleURL) + : bundleURL; + } + private void processMultipartResponse( final String url, final Response response, String boundary, final File outputFile, @Nullable final BundleInfo bundleInfo, + final BundleDeltaClient.ClientType clientType, final DevBundleDownloadListener callback) throws IOException { @@ -193,7 +204,7 @@ public void onChunkComplete( status = Integer.parseInt(headers.get("X-Http-Status")); } processBundleResult( - url, status, Headers.of(headers), body, outputFile, bundleInfo, callback); + url, status, Headers.of(headers), body, outputFile, bundleInfo, clientType, callback); } else { if (!headers.containsKey("Content-Type") || !headers.get("Content-Type").equals("application/json")) { @@ -249,6 +260,7 @@ private void processBundleResult( BufferedSource body, File outputFile, BundleInfo bundleInfo, + BundleDeltaClient.ClientType clientType, DevBundleDownloadListener callback) throws IOException { // Check for server errors. If the server error has the expected form, fail with more info. @@ -274,24 +286,36 @@ private void processBundleResult( File tmpFile = new File(outputFile.getPath() + ".tmp"); - boolean bundleUpdated; + boolean bundleWritten; + NativeDeltaClient nativeDeltaClient = null; if (BundleDeltaClient.isDeltaUrl(url)) { // If the bundle URL has the delta extension, we need to use the delta patching logic. - bundleUpdated = mBundleDeltaClient.storeDeltaInFile(body, tmpFile); + BundleDeltaClient deltaClient = getBundleDeltaClient(clientType); + Assertions.assertNotNull(deltaClient); + Pair result = deltaClient.processDelta(headers, body, tmpFile); + bundleWritten = result.first; + nativeDeltaClient = result.second; } else { - mBundleDeltaClient.reset(); - bundleUpdated = storePlainJSInFile(body, tmpFile); + mBundleDeltaClient = null; + bundleWritten = storePlainJSInFile(body, tmpFile); } - if (bundleUpdated) { + if (bundleWritten) { // If we have received a new bundle from the server, move it to its final destination. if (!tmpFile.renameTo(outputFile)) { throw new IOException("Couldn't rename " + tmpFile + " to " + outputFile); } } - callback.onSuccess(); + callback.onSuccess(nativeDeltaClient); + } + + private BundleDeltaClient getBundleDeltaClient(BundleDeltaClient.ClientType clientType) { + if (mBundleDeltaClient == null || !mBundleDeltaClient.canHandle(clientType)) { + mBundleDeltaClient = BundleDeltaClient.create(clientType); + } + return mBundleDeltaClient; } private static boolean storePlainJSInFile(BufferedSource body, File outputFile) 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 946377680e6922..f0638b0b41c2ac 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java @@ -375,7 +375,17 @@ private String getInspectorAttachUrl(String title) { public void downloadBundleFromURL( DevBundleDownloadListener callback, File outputFile, String bundleURL, BundleDownloader.BundleInfo bundleInfo) { - mBundleDownloader.downloadBundleFromURL(callback, outputFile, bundleURL, bundleInfo); + mBundleDownloader.downloadBundleFromURL(callback, outputFile, bundleURL, bundleInfo, getDeltaClientType()); + } + + private BundleDeltaClient.ClientType getDeltaClientType() { + if (mSettings.isBundleDeltasCppEnabled()) { + return BundleDeltaClient.ClientType.NATIVE; + } else if (mSettings.isBundleDeltasEnabled()) { + return BundleDeltaClient.ClientType.DEV_SUPPORT; + } else { + return BundleDeltaClient.ClientType.NONE; + } } /** 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 ea25bf86c42ae7..6673503703d726 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java @@ -32,6 +32,7 @@ import com.facebook.react.bridge.DefaultNativeModuleCallExceptionHandler; import com.facebook.react.bridge.JavaJSExecutor; import com.facebook.react.bridge.JavaScriptContextHolder; +import com.facebook.react.bridge.NativeDeltaClient; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReactMarker; import com.facebook.react.bridge.ReactMarkerConstants; @@ -973,7 +974,7 @@ public void reloadJSFromServer(final String bundleURL) { mDevServerHelper.downloadBundleFromURL( new DevBundleDownloadListener() { @Override - public void onSuccess() { + public void onSuccess(final @Nullable NativeDeltaClient nativeDeltaClient) { mDevLoadingViewController.hide(); mDevLoadingViewVisible = false; synchronized (DevSupportManagerImpl.this) { @@ -981,14 +982,14 @@ public void onSuccess() { mBundleStatus.updateTimestamp = System.currentTimeMillis(); } if (mBundleDownloadListener != null) { - mBundleDownloadListener.onSuccess(); + mBundleDownloadListener.onSuccess(nativeDeltaClient); } UiThreadUtil.runOnUiThread( new Runnable() { @Override public void run() { ReactMarker.logMarker(ReactMarkerConstants.DOWNLOAD_END, bundleInfo.toJSONString()); - mReactInstanceManagerHelper.onJSBundleLoadedFromServer(); + mReactInstanceManagerHelper.onJSBundleLoadedFromServer(nativeDeltaClient); } }); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/ReactInstanceManagerDevHelper.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/ReactInstanceManagerDevHelper.java index 7694c68db9dbca..7033a21fda478f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/ReactInstanceManagerDevHelper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/ReactInstanceManagerDevHelper.java @@ -8,9 +8,9 @@ package com.facebook.react.devsupport; import android.app.Activity; - import com.facebook.react.bridge.JavaJSExecutor; +import com.facebook.react.bridge.NativeDeltaClient; import javax.annotation.Nullable; /** @@ -27,7 +27,7 @@ public interface ReactInstanceManagerDevHelper { /** * Notify react instance manager about new JS bundle version downloaded from the server. */ - void onJSBundleLoadedFromServer(); + void onJSBundleLoadedFromServer(@Nullable NativeDeltaClient nativeDeltaClient); /** * Request to toggle the react element inspector. diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/interfaces/DevBundleDownloadListener.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/interfaces/DevBundleDownloadListener.java index 661a8cba243613..b08ba97066a341 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/interfaces/DevBundleDownloadListener.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/interfaces/DevBundleDownloadListener.java @@ -7,10 +7,11 @@ package com.facebook.react.devsupport.interfaces; +import com.facebook.react.bridge.NativeDeltaClient; import javax.annotation.Nullable; public interface DevBundleDownloadListener { - void onSuccess(); + void onSuccess(@Nullable NativeDeltaClient nativeDeltaClient); void onProgress(@Nullable String status, @Nullable Integer done, @Nullable Integer total); void onFailure(Exception cause); } From 786c1ecc2a6856967d676da68eb02f89eb38fb79 Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Thu, 3 May 2018 08:38:15 -0700 Subject: [PATCH 0432/1109] Markers: add info about type of delta client Summary: Adds information which type of delta client is used (if at all) to the `BundleInfo` object. Reviewed By: fromcelticpark Differential Revision: D7845139 fbshipit-source-id: e4bf6cda62c71a78aaff97aa69daec263e6d3cdf --- .../facebook/react/devsupport/BundleDownloader.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) 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 69f50a832e98ee..e64d02edbb974b 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDownloader.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDownloader.java @@ -47,6 +47,7 @@ public class BundleDownloader { private @Nullable Call mDownloadBundleFromURLCall; public static class BundleInfo { + private @Nullable String mDeltaClientName; private @Nullable String mUrl; private int mFilesChangedCount; @@ -59,6 +60,7 @@ public static class BundleInfo { try { JSONObject obj = new JSONObject(jsonStr); + info.mDeltaClientName = obj.getString("deltaClient"); info.mUrl = obj.getString("url"); info.mFilesChangedCount = obj.getInt("filesChangedCount"); } catch (JSONException e) { @@ -73,6 +75,7 @@ public static class BundleInfo { JSONObject obj = new JSONObject(); try { + obj.put("deltaClient", mDeltaClientName); obj.put("url", mUrl); obj.put("filesChangedCount", mFilesChangedCount); } catch (JSONException e) { @@ -83,6 +86,10 @@ public static class BundleInfo { return obj.toString(); } + public @Nullable String getDeltaClient() { + return mDeltaClientName; + } + public String getUrl() { return mUrl != null ? mUrl : "unknown"; } @@ -281,7 +288,7 @@ private void processBundleResult( } if (bundleInfo != null) { - populateBundleInfo(url, headers, bundleInfo); + populateBundleInfo(url, headers, clientType, bundleInfo); } File tmpFile = new File(outputFile.getPath() + ".tmp"); @@ -333,7 +340,8 @@ private static boolean storePlainJSInFile(BufferedSource body, File outputFile) return true; } - private static void populateBundleInfo(String url, Headers headers, BundleInfo bundleInfo) { + private static void populateBundleInfo(String url, Headers headers, BundleDeltaClient.ClientType clientType, BundleInfo bundleInfo) { + bundleInfo.mDeltaClientName = clientType == BundleDeltaClient.ClientType.NONE ? null : clientType.name(); bundleInfo.mUrl = url; String filesChangedCountStr = headers.get("X-Metro-Files-Changed-Count"); From 5a6147c4f8e66183be40cc0646226b066daaaed7 Mon Sep 17 00:00:00 2001 From: "Andrew Chen (Eng)" Date: Thu, 3 May 2018 13:01:28 -0700 Subject: [PATCH 0433/1109] Fix DevLoadingViewController Reviewed By: mdvacca Differential Revision: D7860219 fbshipit-source-id: 3770a2064808bf4ae4c61f15c6d68c3b93fe9f38 --- .../devsupport/DevLoadingViewController.java | 92 +++++++++---------- .../devsupport/DevSupportManagerImpl.java | 2 +- .../devsupport/layout/dev_loading_view.xml | 9 +- 3 files changed, 48 insertions(+), 55 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 bc6e6c3b7a7f7a..9d8ed683a85861 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevLoadingViewController.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevLoadingViewController.java @@ -7,28 +7,25 @@ package com.facebook.react.devsupport; +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; +import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; + import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; -import android.graphics.Color; import android.graphics.Rect; import android.os.Build; import android.view.Gravity; import android.view.LayoutInflater; -import android.view.ViewGroup; -import android.view.Window; import android.widget.PopupWindow; import android.widget.TextView; - import com.facebook.common.logging.FLog; import com.facebook.react.R; import com.facebook.react.bridge.UiThreadUtil; import com.facebook.react.common.ReactConstants; - import java.net.MalformedURLException; import java.net.URL; import java.util.Locale; - import javax.annotation.Nullable; /** @@ -36,12 +33,9 @@ */ @TargetApi(Build.VERSION_CODES.CUPCAKE) public class DevLoadingViewController { - private static final int COLOR_DARK_GREEN = Color.parseColor("#035900"); - private static boolean sEnabled = true; - private final Context mContext; private final ReactInstanceManagerDevHelper mReactInstanceManagerHelper; - private final TextView mDevLoadingView; + private @Nullable TextView mDevLoadingView; private @Nullable PopupWindow mDevLoadingPopup; public static void setDevLoadingEnabled(boolean enabled) { @@ -49,13 +43,10 @@ public static void setDevLoadingEnabled(boolean enabled) { } public DevLoadingViewController(Context context, ReactInstanceManagerDevHelper reactInstanceManagerHelper) { - mContext = context; mReactInstanceManagerHelper = reactInstanceManagerHelper; - LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - mDevLoadingView = (TextView) inflater.inflate(R.layout.dev_loading_view, null); } - public void showMessage(final String message, final int color, final int backgroundColor) { + public void showMessage(final String message) { if (!sEnabled) { return; } @@ -63,16 +54,17 @@ public void showMessage(final String message, final int color, final int backgro UiThreadUtil.runOnUiThread(new Runnable() { @Override public void run() { - mDevLoadingView.setBackgroundColor(backgroundColor); - mDevLoadingView.setText(message); - mDevLoadingView.setTextColor(color); - - showInternal(); + showInternal(message); } }); } public void showForUrl(String url) { + Context context = getContext(); + if (context == null) { + return; + } + URL parsedURL; try { parsedURL = new URL(url); @@ -82,13 +74,17 @@ public void showForUrl(String url) { } showMessage( - mContext.getString(R.string.catalyst_loading_from_url, parsedURL.getHost() + ":" + parsedURL.getPort()), - Color.WHITE, - COLOR_DARK_GREEN); + context.getString(R.string.catalyst_loading_from_url, + parsedURL.getHost() + ":" + parsedURL.getPort())); } public void showForRemoteJSEnabled() { - showMessage(mContext.getString(R.string.catalyst_remotedbg_message), Color.WHITE, COLOR_DARK_GREEN); + Context context = getContext(); + if (context == null) { + return; + } + + showMessage(context.getString(R.string.catalyst_remotedbg_message)); } public void updateProgress(final @Nullable String status, final @Nullable Integer done, final @Nullable Integer total) { @@ -105,21 +101,9 @@ public void run() { message.append(String.format(Locale.getDefault(), " %.1f%% (%d/%d)", (float) done / total * 100, done, total)); } message.append("\u2026"); // `...` character - - mDevLoadingView.setText(message); - } - }); - } - - public void show() { - if (!sEnabled) { - return; - } - - UiThreadUtil.runOnUiThread(new Runnable() { - @Override - public void run() { - showInternal(); + if (mDevLoadingView != null) { + mDevLoadingView.setText(message); + } } }); } @@ -137,7 +121,7 @@ public void run() { }); } - private void showInternal() { + private void showInternal(String message) { if (mDevLoadingPopup != null && mDevLoadingPopup.isShowing()) { // already showing return; @@ -150,20 +134,21 @@ private void showInternal() { return; } - int topOffset = 0; - if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) { - // On Android SDK <= 19 PopupWindow#showAtLocation uses absolute screen position. In order for - // loading view to be placed below status bar (if the status bar is present) we need to pass - // an appropriate Y offset. - Rect rectangle = new Rect(); - currentActivity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rectangle); - topOffset = rectangle.top; - } + // PopupWindow#showAtLocation uses absolute screen position. In order for + // loading view to be placed below status bar (if the status bar is present) we need to pass + // an appropriate Y offset. + Rect rectangle = new Rect(); + currentActivity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rectangle); + int topOffset = rectangle.top; + + LayoutInflater inflater = + (LayoutInflater) currentActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - mDevLoadingPopup = new PopupWindow(currentActivity); + mDevLoadingView = (TextView) inflater.inflate(R.layout.dev_loading_view, null); + mDevLoadingView.setText(message); + + mDevLoadingPopup = new PopupWindow(mDevLoadingView, MATCH_PARENT, WRAP_CONTENT); mDevLoadingPopup.setTouchable(false); - mDevLoadingPopup.setWidth(ViewGroup.LayoutParams.MATCH_PARENT); - mDevLoadingPopup.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT); mDevLoadingPopup.showAtLocation( currentActivity.getWindow().getDecorView(), @@ -176,6 +161,11 @@ private void hideInternal() { if (mDevLoadingPopup != null && mDevLoadingPopup.isShowing()) { mDevLoadingPopup.dismiss(); mDevLoadingPopup = null; + mDevLoadingView = null; } } + + private @Nullable Context getContext() { + return mReactInstanceManagerHelper.getCurrentActivity(); + } } 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 6673503703d726..241bd0dbf1ddb3 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java @@ -1073,7 +1073,7 @@ private void reload() { // show the dev loading if it should be if (mDevLoadingViewVisible) { - mDevLoadingViewController.show(); + mDevLoadingViewController.showMessage("Reloading..."); } mDevServerHelper.openPackagerConnection(this.getClass().getSimpleName(), this); diff --git a/ReactAndroid/src/main/res/devsupport/layout/dev_loading_view.xml b/ReactAndroid/src/main/res/devsupport/layout/dev_loading_view.xml index c503c9c7d01e5e..9bf8bca6aabdaf 100644 --- a/ReactAndroid/src/main/res/devsupport/layout/dev_loading_view.xml +++ b/ReactAndroid/src/main/res/devsupport/layout/dev_loading_view.xml @@ -4,11 +4,14 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" + android:background="#035900" + android:ellipsize="end" + android:gravity="center" android:paddingTop="5dp" android:paddingBottom="5dp" android:paddingStart="8dp" android:paddingEnd="8dp" - android:textSize="12sp" android:maxLines="1" - android:ellipsize="end" - android:gravity="center"/> + android:textColor="@android:color/white" + android:textSize="12sp" + /> From b63015d34ef51585c452142f666d4f36ceaa1b56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Thu, 3 May 2018 14:05:30 -0700 Subject: [PATCH 0434/1109] Bumps Jest to 23.0.0-charlie.1 [fbsource] Differential Revision: D7859604 fbshipit-source-id: 6a2d74679f5eae3cb0102f461272b7cbd5716cba --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 37b3feb4ca0bbb..3be9d818e675e0 100644 --- a/package.json +++ b/package.json @@ -213,7 +213,7 @@ "eslint-plugin-prettier": "2.6.0", "eslint-plugin-react": "7.6.1", "flow-bin": "^0.71.0", - "jest": "23.0.0-beta.2", + "jest": "23.0.0-charlie.1", "jest-junit": "3.7.0", "prettier": "1.12.1", "react": "16.3.2", From 255b97ddd1e0baaf180069a6994e4711e22603a2 Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Thu, 3 May 2018 15:42:23 -0700 Subject: [PATCH 0435/1109] Load and use fb_xplat_cxx_test Reviewed By: mzlee Differential Revision: D7854278 fbshipit-source-id: 2a4c4fc27fc665a192fc04a8c8fae19f7f221566 --- ReactCommon/cxxreact/tests/BUCK | 4 ++-- ReactCommon/fabric/core/BUCK | 6 +++--- ReactCommon/fabric/debug/BUCK | 6 +++--- ReactCommon/fabric/graphics/BUCK | 6 +++--- ReactCommon/fabric/uimanager/BUCK | 1 + ReactCommon/fabric/view/BUCK | 1 + 6 files changed, 13 insertions(+), 11 deletions(-) diff --git a/ReactCommon/cxxreact/tests/BUCK b/ReactCommon/cxxreact/tests/BUCK index 1d7657cc01ec33..e78b7692b1d7fb 100644 --- a/ReactCommon/cxxreact/tests/BUCK +++ b/ReactCommon/cxxreact/tests/BUCK @@ -11,7 +11,7 @@ TEST_SRCS = [ ] if not IS_OSS_BUILD: - load("@xplat//build_defs:fb_xplat_cxx_test.bzl", "cxx_test") + load("@xplat//build_defs:fb_xplat_cxx_test.bzl", "fb_xplat_cxx_test") load("@xplat//configurations/buck/android:jni_instrumentation_test", "jni_instrumentation_test_lib") load("@xplat//configurations/buck:default_platform_defs.bzl", "APPLE") jni_instrumentation_test_lib( @@ -34,7 +34,7 @@ if not IS_OSS_BUILD: ], ) - cxx_test( + fb_xplat_cxx_test( name = 'tests', srcs = TEST_SRCS, compiler_flags = [ diff --git a/ReactCommon/fabric/core/BUCK b/ReactCommon/fabric/core/BUCK index 23a9f30cfc0cb4..981dd874f40045 100644 --- a/ReactCommon/fabric/core/BUCK +++ b/ReactCommon/fabric/core/BUCK @@ -1,5 +1,5 @@ load("//configurations/buck/apple:flag_defs.bzl", "get_debug_preprocessor_flags") -load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "get_apple_inspector_flags") +load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "get_apple_inspector_flags", "APPLE") APPLE_COMPILER_FLAGS = [] @@ -58,9 +58,9 @@ rn_xplat_cxx_library( ) if not IS_OSS_BUILD: - load("@xplat//configurations/buck:default_platform_defs.bzl", "APPLE") + load("@xplat//build_defs:fb_xplat_cxx_test.bzl", "fb_xplat_cxx_test") - cxx_test( + fb_xplat_cxx_test( name = "tests", srcs = glob(["tests/**/*.cpp"]), headers = glob(["tests/**/*.h"]), diff --git a/ReactCommon/fabric/debug/BUCK b/ReactCommon/fabric/debug/BUCK index 88f7bc47828c43..782b7452253f47 100644 --- a/ReactCommon/fabric/debug/BUCK +++ b/ReactCommon/fabric/debug/BUCK @@ -1,5 +1,5 @@ load("@xplat//configurations/buck/apple:flag_defs.bzl", "get_debug_preprocessor_flags") -load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "get_apple_inspector_flags") +load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "get_apple_inspector_flags", "APPLE") APPLE_COMPILER_FLAGS = [] @@ -49,9 +49,9 @@ rn_xplat_cxx_library( ) if not IS_OSS_BUILD: - load("@xplat//configurations/buck:default_platform_defs.bzl", "APPLE") + load("@xplat//build_defs:fb_xplat_cxx_test.bzl", "fb_xplat_cxx_test") - cxx_test( + fb_xplat_cxx_test( name = "tests", srcs = glob(["tests/**/*.cpp"]), headers = glob(["tests/**/*.h"]), diff --git a/ReactCommon/fabric/graphics/BUCK b/ReactCommon/fabric/graphics/BUCK index 7cdb8c59b90f2b..52a42e39208fa5 100644 --- a/ReactCommon/fabric/graphics/BUCK +++ b/ReactCommon/fabric/graphics/BUCK @@ -1,5 +1,5 @@ load("//configurations/buck/apple:flag_defs.bzl", "get_debug_preprocessor_flags") -load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "get_apple_inspector_flags") +load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "get_apple_inspector_flags", "APPLE") APPLE_COMPILER_FLAGS = [] @@ -53,9 +53,9 @@ rn_xplat_cxx_library( ) if not IS_OSS_BUILD: - load("@xplat//configurations/buck:default_platform_defs.bzl", "APPLE") + load("@xplat//build_defs:fb_xplat_cxx_test.bzl", "fb_xplat_cxx_test") - cxx_test( + fb_xplat_cxx_test( name = "tests", srcs = glob(["tests/**/*.cpp"]), headers = glob(["tests/**/*.h"]), diff --git a/ReactCommon/fabric/uimanager/BUCK b/ReactCommon/fabric/uimanager/BUCK index 6745136cf81715..4a3eeae2ba5fc0 100644 --- a/ReactCommon/fabric/uimanager/BUCK +++ b/ReactCommon/fabric/uimanager/BUCK @@ -58,6 +58,7 @@ rn_xplat_cxx_library( if not IS_OSS_BUILD: load("@xplat//build_defs:fb_xplat_cxx_test.bzl", "fb_xplat_cxx_test") + fb_xplat_cxx_test( name = "tests", srcs = glob(["tests/**/*.cpp"]), diff --git a/ReactCommon/fabric/view/BUCK b/ReactCommon/fabric/view/BUCK index 1f2cff2c3fc77e..20b7108c25c753 100644 --- a/ReactCommon/fabric/view/BUCK +++ b/ReactCommon/fabric/view/BUCK @@ -61,6 +61,7 @@ rn_xplat_cxx_library( if not IS_OSS_BUILD: load("@xplat//build_defs:fb_xplat_cxx_test.bzl", "fb_xplat_cxx_test") + fb_xplat_cxx_test( name = "tests", srcs = glob(["tests/**/*.cpp"]), From f5fcebabeb6d5f93e7eb912f26bfcb755bf0eb66 Mon Sep 17 00:00:00 2001 From: Logan Daniels Date: Thu, 3 May 2018 16:14:34 -0700 Subject: [PATCH 0436/1109] PerformanceLogger: log extras to console in DEV mode Differential Revision: D7862011 fbshipit-source-id: 591caf37d6c91ccb07f13005c0f6c57dcaaa22c5 --- Libraries/Utilities/PerformanceLogger.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Libraries/Utilities/PerformanceLogger.js b/Libraries/Utilities/PerformanceLogger.js index a48f1adb4b6e99..23fcac7951f7b6 100644 --- a/Libraries/Utilities/PerformanceLogger.js +++ b/Libraries/Utilities/PerformanceLogger.js @@ -185,6 +185,10 @@ const PerformanceLogger = { getExtras() { return extras; }, + + logExtras() { + infoLog(extras); + }, }; module.exports = PerformanceLogger; From cd48a6130b13562467a5e1a93b2fc0f30f03bb1c Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Fri, 4 May 2018 10:56:14 -0700 Subject: [PATCH 0437/1109] RN: Disable testImageCachePolicyTest Reviewed By: fkgozali Differential Revision: D7878430 fbshipit-source-id: 60f0ca3f2b59987d618982c91a7e91a2f4b6a18b --- RNTester/RNTesterIntegrationTests/RNTesterIntegrationTests.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RNTester/RNTesterIntegrationTests/RNTesterIntegrationTests.m b/RNTester/RNTesterIntegrationTests/RNTesterIntegrationTests.m index 5f432ec0580dff..1549898e4377e4 100644 --- a/RNTester/RNTesterIntegrationTests/RNTesterIntegrationTests.m +++ b/RNTester/RNTesterIntegrationTests/RNTesterIntegrationTests.m @@ -65,7 +65,7 @@ - (void)testTheTester_ExpectError RCT_TEST(TimersTest) RCT_TEST(AsyncStorageTest) RCT_TEST(AppEventsTest) -RCT_TEST(ImageCachePolicyTest) +//RCT_TEST(ImageCachePolicyTest) // This test never passed. RCT_TEST(ImageSnapshotTest) //RCT_TEST(LayoutEventsTest) // Disabled due to flakiness: #8686784 RCT_TEST(SimpleSnapshotTest) From 634e7e11e3ad39e0b13bf20cc7722c0cfd3c3e28 Mon Sep 17 00:00:00 2001 From: Mehdi Mulani Date: Fri, 4 May 2018 13:47:42 -0700 Subject: [PATCH 0438/1109] iOS only: Breaking Change: Restrict WebView to only http(s) URLs Summary: To prevent people from linking file:// or other URLs inside RN WebViews, default to not allowing those types of URLs. This adds the originWhitelist to specify other schemes or domains to be allowed. If the url is not allowed, it will be opened in Safari/by the OS instead. Reviewed By: yungsters Differential Revision: D7833203 fbshipit-source-id: 6881acd3b434d17910240e4edd585c0a10b5df8c --- IntegrationTests/WebViewTest.js | 1 + Libraries/Components/WebView/WebView.ios.js | 32 ++++++++++++--- Libraries/Components/WebView/WebViewShared.js | 24 +++++++++++ .../WebView/__tests__/WebViewShared-test.js | 41 +++++++++++++++++++ package.json | 1 + 5 files changed, 94 insertions(+), 5 deletions(-) create mode 100644 Libraries/Components/WebView/WebViewShared.js create mode 100644 Libraries/Components/WebView/__tests__/WebViewShared-test.js diff --git a/IntegrationTests/WebViewTest.js b/IntegrationTests/WebViewTest.js index 499e1c095400aa..818b4e980216f0 100644 --- a/IntegrationTests/WebViewTest.js +++ b/IntegrationTests/WebViewTest.js @@ -48,6 +48,7 @@ class WebViewTest extends React.Component { ); } diff --git a/Libraries/Components/WebView/WebView.ios.js b/Libraries/Components/WebView/WebView.ios.js index 56a4465fea6b97..1d54f663f01b3f 100644 --- a/Libraries/Components/WebView/WebView.ios.js +++ b/Libraries/Components/WebView/WebView.ios.js @@ -10,15 +10,17 @@ const ActivityIndicator = require('ActivityIndicator'); const EdgeInsetsPropType = require('EdgeInsetsPropType'); -const React = require('React'); +const Linking = require('Linking'); const PropTypes = require('prop-types'); +const React = require('React'); const ReactNative = require('ReactNative'); +const ScrollView = require('ScrollView'); const StyleSheet = require('StyleSheet'); const Text = require('Text'); const UIManager = require('UIManager'); const View = require('View'); const ViewPropTypes = require('ViewPropTypes'); -const ScrollView = require('ScrollView'); +const WebViewShared = require('WebViewShared'); const deprecatedPropType = require('deprecatedPropType'); const invariant = require('fbjs/lib/invariant'); @@ -353,6 +355,15 @@ class WebView extends React.Component { */ mediaPlaybackRequiresUserAction: PropTypes.bool, + /** + * List of origin strings to allow being navigated to. The strings allow + * wildcards and get matched against *just* the origin (not the full URL). + * If the user taps to navigate to a new page but the new page is not in + * this whitelist, we will open the URL in Safari. + * The default whitelisted origins are "http://*" and "https://*". + */ + originWhitelist: PropTypes.arrayOf(PropTypes.string), + /** * Function that accepts a string that will be passed to the WebView and * executed immediately as JavaScript. @@ -398,6 +409,7 @@ class WebView extends React.Component { }; static defaultProps = { + originWhitelist: WebViewShared.defaultOriginWhitelist, scalesPageToFit: true, }; @@ -446,9 +458,19 @@ class WebView extends React.Component { const viewManager = nativeConfig.viewManager || RCTWebViewManager; - const onShouldStartLoadWithRequest = this.props.onShouldStartLoadWithRequest && ((event: Event) => { - const shouldStart = this.props.onShouldStartLoadWithRequest && - this.props.onShouldStartLoadWithRequest(event.nativeEvent); + const compiledWhitelist = (this.props.originWhitelist || []).map(WebViewShared.originWhitelistToRegex); + const onShouldStartLoadWithRequest = ((event: Event) => { + let shouldStart = true; + const {url} = event.nativeEvent; + const origin = WebViewShared.extractOrigin(url); + const passesWhitelist = compiledWhitelist.some(x => new RegExp(x).test(origin)); + shouldStart = shouldStart && passesWhitelist; + if (!passesWhitelist) { + Linking.openURL(url); + } + if (this.props.onShouldStartLoadWithRequest) { + shouldStart = shouldStart && this.props.onShouldStartLoadWithRequest(event.nativeEvent); + } viewManager.startLoadWithResult(!!shouldStart, event.nativeEvent.lockIdentifier); }); diff --git a/Libraries/Components/WebView/WebViewShared.js b/Libraries/Components/WebView/WebViewShared.js new file mode 100644 index 00000000000000..744ea201f4670b --- /dev/null +++ b/Libraries/Components/WebView/WebViewShared.js @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 escapeStringRegexp = require('escape-string-regexp'); + +const WebViewShared = { + defaultOriginWhitelist: ['http://*', 'https://*'], + extractOrigin: (url: string): ?string => { + const result = /^[A-Za-z0-9]+:(\/\/)?[^/]*/.exec(url); + return result === null ? null : result[0]; + }, + originWhitelistToRegex: (originWhitelist: string): string => { + return escapeStringRegexp(originWhitelist).replace(/\\\*/g, '.*'); + }, +}; + +module.exports = WebViewShared; diff --git a/Libraries/Components/WebView/__tests__/WebViewShared-test.js b/Libraries/Components/WebView/__tests__/WebViewShared-test.js new file mode 100644 index 00000000000000..37f52064c431e9 --- /dev/null +++ b/Libraries/Components/WebView/__tests__/WebViewShared-test.js @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2013-present, Facebook, Inc. + * + * 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 + */ + + 'use strict'; + +const WebViewShared = require('WebViewShared'); + +describe('WebViewShared', () => { + it('extracts the origin correctly', () => { + expect(WebViewShared.extractOrigin('http://facebook.com')).toBe('http://facebook.com'); + expect(WebViewShared.extractOrigin('https://facebook.com')).toBe('https://facebook.com'); + expect(WebViewShared.extractOrigin('http://facebook.com:8081')).toBe('http://facebook.com:8081'); + expect(WebViewShared.extractOrigin('ftp://facebook.com')).toBe('ftp://facebook.com'); + expect(WebViewShared.extractOrigin('myweirdscheme://')).toBe('myweirdscheme://'); + expect(WebViewShared.extractOrigin('http://facebook.com/')).toBe('http://facebook.com'); + expect(WebViewShared.extractOrigin('http://facebook.com/longerurl')).toBe('http://facebook.com'); + expect(WebViewShared.extractOrigin('http://facebook.com/http://facebook.com')).toBe('http://facebook.com'); + expect(WebViewShared.extractOrigin('http://facebook.com//http://facebook.com')).toBe('http://facebook.com'); + expect(WebViewShared.extractOrigin('http://facebook.com//http://facebook.com//')).toBe('http://facebook.com'); + expect(WebViewShared.extractOrigin('about:blank')).toBe('about:blank'); + }); + + it('rejects bad urls', () => { + expect(WebViewShared.extractOrigin('a/b')).toBeNull(); + expect(WebViewShared.extractOrigin('a//b')).toBeNull(); + }); + + it('creates a whitelist regex correctly', () => { + expect(WebViewShared.originWhitelistToRegex('http://*')).toBe('http://.*'); + expect(WebViewShared.originWhitelistToRegex('*')).toBe('.*'); + expect(WebViewShared.originWhitelistToRegex('*//test')).toBe('.*//test'); + expect(WebViewShared.originWhitelistToRegex('*/*')).toBe('.*/.*'); + expect(WebViewShared.originWhitelistToRegex('*.com')).toBe('.*\\.com'); + }); +}); diff --git a/package.json b/package.json index 3be9d818e675e0..02d8deb8c636d4 100644 --- a/package.json +++ b/package.json @@ -158,6 +158,7 @@ "denodeify": "^1.2.1", "envinfo": "^3.0.0", "errorhandler": "^1.5.0", + "escape-string-regexp": "^1.0.5", "eslint-plugin-react-native": "^3.2.1", "event-target-shim": "^1.0.5", "fbjs": "^0.8.14", From b7562818e651785ed869b6ea52688f4a2cc578e8 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Fri, 4 May 2018 17:28:40 -0700 Subject: [PATCH 0439/1109] Add molly dependency in Fabric/jsc/jni project Reviewed By: fkgozali Differential Revision: D7816676 fbshipit-source-id: 8f227482eb1129f51d758bc13e619af30d6c2b1f --- .../src/main/java/com/facebook/react/fabric/jsc/jni/BUCK | 1 + 1 file changed, 1 insertion(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/BUCK b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/BUCK index 4c4dd27047f949..9998937d4703ea 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/jni/BUCK @@ -14,6 +14,7 @@ rn_xplat_cxx_library( visibility = ["PUBLIC"], deps = [ FBJNI_TARGET, + "xplat//folly:molly", react_native_xplat_target("jschelpers:jschelpers"), react_native_target("jni/react/jni:jni"), ], From 1e68ca7dc817771ee7e9b749f391f53288d91c13 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Fri, 4 May 2018 17:50:37 -0700 Subject: [PATCH 0440/1109] Cleanup android warnings related to static interface declarations Reviewed By: fkgozali Differential Revision: D7853681 fbshipit-source-id: d342e9dc9a1efa921d1421d545798e0b706745b4 --- .../java/com/facebook/react/testing/ReactTestFactory.java | 2 +- .../react/testing/network/NetworkRecordingModuleMock.java | 2 +- .../src/main/java/com/facebook/react/common/ShakeDetector.java | 2 +- .../react/uimanager/common/SizeMonitoringFrameLayout.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestFactory.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestFactory.java index c15ffc29f2590c..20cbfb938b4018 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestFactory.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestFactory.java @@ -14,7 +14,7 @@ import com.facebook.react.bridge.NativeModule; public interface ReactTestFactory { - public static interface ReactInstanceEasyBuilder { + interface ReactInstanceEasyBuilder { ReactInstanceEasyBuilder setContext(Context context); ReactInstanceEasyBuilder addNativeModule(NativeModule module); CatalystInstance build(); diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/network/NetworkRecordingModuleMock.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/network/NetworkRecordingModuleMock.java index 9a6917078c78b5..0f5c96831099c5 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/network/NetworkRecordingModuleMock.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/network/NetworkRecordingModuleMock.java @@ -47,7 +47,7 @@ public NetworkRecordingModuleMock(ReactApplicationContext reactContext, boolean mCompleteRequest = completeRequest; } - public static interface RequestListener { + public interface RequestListener { public void onRequest(String method, String url, ReadableArray header, ReadableMap data); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/common/ShakeDetector.java b/ReactAndroid/src/main/java/com/facebook/react/common/ShakeDetector.java index 5d14415072fd20..ad45c64d2d5dfd 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/common/ShakeDetector.java +++ b/ReactAndroid/src/main/java/com/facebook/react/common/ShakeDetector.java @@ -34,7 +34,7 @@ public class ShakeDetector implements SensorEventListener { private float mAccelerationX, mAccelerationY, mAccelerationZ; - public static interface ShakeListener { + public interface ShakeListener { void onShake(); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/common/SizeMonitoringFrameLayout.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/common/SizeMonitoringFrameLayout.java index 19af1031a8e804..f7dd744c4b11b2 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/common/SizeMonitoringFrameLayout.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/common/SizeMonitoringFrameLayout.java @@ -20,7 +20,7 @@ */ public class SizeMonitoringFrameLayout extends FrameLayout { - public static interface OnSizeChangedListener { + public interface OnSizeChangedListener { void onSizeChanged(int width, int height, int oldWidth, int oldHeight); } From 23f8f7aecb1f21f4f5e44fb9e4a7456ea97935c9 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Fri, 4 May 2018 22:44:30 -0700 Subject: [PATCH 0441/1109] Breaking Change: Restrict WebView to only manage navigation of whitelisted URLs: http(s) by default Reviewed By: achen1 Differential Revision: D7834050 fbshipit-source-id: 80f7fd3cd20979590b75804819e154afc14a3c64 --- .../Components/WebView/WebView.android.js | 16 ++- .../views/webview/ReactWebViewManager.java | 100 +++++++++++++----- 2 files changed, 91 insertions(+), 25 deletions(-) diff --git a/Libraries/Components/WebView/WebView.android.js b/Libraries/Components/WebView/WebView.android.js index 6f0ac9b57fb033..b6995458e59001 100644 --- a/Libraries/Components/WebView/WebView.android.js +++ b/Libraries/Components/WebView/WebView.android.js @@ -16,6 +16,7 @@ const StyleSheet = require('StyleSheet'); const UIManager = require('UIManager'); const View = require('View'); const ViewPropTypes = require('ViewPropTypes'); +const WebViewShared = require('WebViewShared'); const deprecatedPropType = require('deprecatedPropType'); const keyMirror = require('fbjs/lib/keyMirror'); @@ -179,6 +180,15 @@ class WebView extends React.Component { */ allowUniversalAccessFromFileURLs: PropTypes.bool, + /** + * List of origin strings to allow being navigated to. The strings allow + * wildcards and get matched against *just* the origin (not the full URL). + * If the user taps to navigate to a new page but the new page is not in + * this whitelist, the URL will be oppened by the Android OS. + * The default whitelisted origins are "http://*" and "https://*". + */ + originWhitelist: PropTypes.arrayOf(PropTypes.string), + /** * Function that accepts a string that will be passed to the WebView and * executed immediately as JavaScript. @@ -241,7 +251,8 @@ class WebView extends React.Component { javaScriptEnabled : true, thirdPartyCookiesEnabled: true, scalesPageToFit: true, - saveFormDataDisabled: false + saveFormDataDisabled: false, + originWhitelist: WebViewShared.defaultOriginWhitelist, }; state = { @@ -293,6 +304,8 @@ class WebView extends React.Component { const nativeConfig = this.props.nativeConfig || {}; + const originWhitelist = (this.props.originWhitelist || []).map(WebViewShared.originWhitelistToRegex); + let NativeWebView = nativeConfig.component || RCTWebView; const webView = @@ -319,6 +332,7 @@ class WebView extends React.Component { geolocationEnabled={this.props.geolocationEnabled} mediaPlaybackRequiresUserAction={this.props.mediaPlaybackRequiresUserAction} allowUniversalAccessFromFileURLs={this.props.allowUniversalAccessFromFileURLs} + originWhitelist={originWhitelist} mixedContentMode={this.props.mixedContentMode} saveFormDataDisabled={this.props.saveFormDataDisabled} urlPrefixesForDefaultIntent={this.props.urlPrefixesForDefaultIntent} diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java index a580a2bc4a18af..7f07b2742677ab 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java @@ -7,6 +7,11 @@ package com.facebook.react.views.webview; +import android.annotation.TargetApi; +import android.content.Context; +import java.util.LinkedList; +import java.util.List; +import java.util.regex.Pattern; import javax.annotation.Nullable; import java.io.UnsupportedEncodingException; @@ -110,6 +115,7 @@ protected static class ReactWebViewClient extends WebViewClient { protected boolean mLastLoadFailed = false; protected @Nullable ReadableArray mUrlPrefixesForDefaultIntent; + protected @Nullable List mOriginWhitelist; @Override public void onPageFinished(WebView webView, String url) { @@ -137,32 +143,50 @@ public void onPageStarted(WebView webView, String url, Bitmap favicon) { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { - boolean useDefaultIntent = false; - if (mUrlPrefixesForDefaultIntent != null && mUrlPrefixesForDefaultIntent.size() > 0) { - ArrayList urlPrefixesForDefaultIntent = - mUrlPrefixesForDefaultIntent.toArrayList(); - for (Object urlPrefix : urlPrefixesForDefaultIntent) { - if (url.startsWith((String) urlPrefix)) { - useDefaultIntent = true; - break; - } + if (url.equals(BLANK_URL)) return false; + + // url blacklisting + if (mUrlPrefixesForDefaultIntent != null && mUrlPrefixesForDefaultIntent.size() > 0) { + ArrayList urlPrefixesForDefaultIntent = + mUrlPrefixesForDefaultIntent.toArrayList(); + for (Object urlPrefix : urlPrefixesForDefaultIntent) { + if (url.startsWith((String) urlPrefix)) { + launchIntent(view.getContext(), url); + return true; } } + } - if (!useDefaultIntent && - (url.startsWith("http://") || url.startsWith("https://") || - url.startsWith("file://") || url.equals("about:blank"))) { - return false; - } else { - try { - Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - view.getContext().startActivity(intent); - } catch (ActivityNotFoundException e) { - FLog.w(ReactConstants.TAG, "activity not found to handle uri scheme for: " + url, e); - } + if (mOriginWhitelist != null && shouldHandleURL(mOriginWhitelist, url)) { + return false; + } + + launchIntent(view.getContext(), url); + return true; + } + + private void launchIntent(Context context, String url) { + try { + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.addCategory(Intent.CATEGORY_BROWSABLE); + context.startActivity(intent); + } catch (ActivityNotFoundException e) { + FLog.w(ReactConstants.TAG, "activity not found to handle uri scheme for: " + url, e); + } + } + + private boolean shouldHandleURL(List originWhitelist, String url) { + Uri uri = Uri.parse(url); + String scheme = uri.getScheme() != null ? uri.getScheme() : ""; + String authority = uri.getAuthority() != null ? uri.getAuthority() : ""; + String urlToCheck = scheme + "://" + authority; + for (Pattern pattern : originWhitelist) { + if (pattern.matcher(urlToCheck).matches()) { return true; } + } + return false; } @Override @@ -211,6 +235,10 @@ protected WritableMap createWebViewEvent(WebView webView, String url) { public void setUrlPrefixesForDefaultIntent(ReadableArray specialUrls) { mUrlPrefixesForDefaultIntent = specialUrls; } + + public void setOriginWhitelist(List originWhitelist) { + mOriginWhitelist = originWhitelist; + } } /** @@ -356,6 +384,7 @@ protected ReactWebView createReactWebViewInstance(ThemedReactContext reactContex } @Override + @TargetApi(Build.VERSION_CODES.LOLLIPOP) protected WebView createViewInstance(ThemedReactContext reactContext) { ReactWebView webView = createReactWebViewInstance(reactContext); webView.setWebChromeClient(new WebChromeClient() { @@ -375,9 +404,18 @@ public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermiss }); reactContext.addLifecycleEventListener(webView); mWebViewConfig.configWebView(webView); - webView.getSettings().setBuiltInZoomControls(true); - webView.getSettings().setDisplayZoomControls(false); - webView.getSettings().setDomStorageEnabled(true); + WebSettings settings = webView.getSettings(); + settings.setBuiltInZoomControls(true); + settings.setDisplayZoomControls(false); + settings.setDomStorageEnabled(true); + + settings.setAllowFileAccess(false); + settings.setAllowContentAccess(false); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + settings.setAllowFileAccessFromFileURLs(false); + setAllowUniversalAccessFromFileURLs(webView, false); + } + setMixedContentMode(webView, "never"); // Fixes broken full-screen modals/galleries due to body height being 0. webView.setLayoutParams( @@ -546,6 +584,20 @@ public void setGeolocationEnabled( view.getSettings().setGeolocationEnabled(isGeolocationEnabled != null && isGeolocationEnabled); } + @ReactProp(name = "originWhitelist") + public void setOriginWhitelist( + WebView view, + @Nullable ReadableArray originWhitelist) { + ReactWebViewClient client = ((ReactWebView) view).getReactWebViewClient(); + if (client != null && originWhitelist != null) { + List whiteList = new LinkedList<>(); + for (int i = 0 ; i < originWhitelist.size() ; i++) { + whiteList.add(Pattern.compile(originWhitelist.getString(i))); + } + client.setOriginWhitelist(whiteList); + } + } + @Override protected void addEventEmitters(ThemedReactContext reactContext, WebView view) { // Do not register default touch emitter and let WebView implementation handle touches From 1ab7d49c2df5673dd214eb8a9b7fd3defb0ff857 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Mon, 7 May 2018 09:41:48 -0700 Subject: [PATCH 0442/1109] RN: Cleanup `__propTypesSecretDontUseThesePlease` Reviewed By: bvaughn Differential Revision: D7892903 fbshipit-source-id: aab0537fe508ac740d0a2798a04f54411c8c038d --- .../ReactNative/requireNativeComponent.js | 20 ++----------------- Libraries/ReactNative/verifyPropTypes.js | 9 +-------- 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/Libraries/ReactNative/requireNativeComponent.js b/Libraries/ReactNative/requireNativeComponent.js index 83a071c7066f23..0e09ad9f8096ec 100644 --- a/Libraries/ReactNative/requireNativeComponent.js +++ b/Libraries/ReactNative/requireNativeComponent.js @@ -108,24 +108,8 @@ function requireNativeComponent( viewConfig.uiViewClassName = viewName; viewConfig.validAttributes = {}; - - // ReactNative `View.propTypes` have been deprecated in favor of - // `ViewPropTypes`. In their place a temporary getter has been added with a - // deprecated warning message. Avoid triggering that warning here by using - // temporary workaround, __propTypesSecretDontUseThesePlease. - // TODO (bvaughn) Revert this particular change any time after April 1 - if (componentInterface) { - viewConfig.propTypes = - /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an - * error found when Flow v0.68 was deployed. To see the error delete - * this comment and run Flow. */ - typeof componentInterface.__propTypesSecretDontUseThesePlease === - 'object' - ? componentInterface.__propTypesSecretDontUseThesePlease - : componentInterface.propTypes; - } else { - viewConfig.propTypes = null; - } + viewConfig.propTypes = + componentInterface == null ? null : componentInterface.propTypes; let baseModuleName = viewConfig.baseModuleName; let bubblingEventTypes = viewConfig.bubblingEventTypes; diff --git a/Libraries/ReactNative/verifyPropTypes.js b/Libraries/ReactNative/verifyPropTypes.js index b7b04d013c2315..c88f9c1c802904 100644 --- a/Libraries/ReactNative/verifyPropTypes.js +++ b/Libraries/ReactNative/verifyPropTypes.js @@ -30,14 +30,7 @@ function verifyPropTypes( var componentName = componentInterface.displayName || componentInterface.name || 'unknown'; - // ReactNative `View.propTypes` have been deprecated in favor of - // `ViewPropTypes`. In their place a temporary getter has been added with a - // deprecated warning message. Avoid triggering that warning here by using - // temporary workaround, __propTypesSecretDontUseThesePlease. - // TODO (bvaughn) Revert this particular change any time after April 1 - var propTypes = - (componentInterface: any).__propTypesSecretDontUseThesePlease || - componentInterface.propTypes; + var propTypes = componentInterface.propTypes; if (!propTypes) { return; From 0125813f213662ec1d9bb4a456f5671adcff9d83 Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Mon, 7 May 2018 11:06:52 -0700 Subject: [PATCH 0443/1109] React sync for revisions 0887c7d...25dda90 Reviewed By: sebmarkbage Differential Revision: D7886956 fbshipit-source-id: 5a94df618ce26dee0876b627fbbaaf0a14a403fe --- Libraries/Renderer/REVISION | 2 +- Libraries/Renderer/oss/ReactFabric-dev.js | 2162 +++++++++-------- Libraries/Renderer/oss/ReactFabric-prod.js | 1757 +++++++------- .../Renderer/oss/ReactNativeRenderer-dev.js | 2162 +++++++++-------- .../Renderer/oss/ReactNativeRenderer-prod.js | 1797 +++++++------- .../Renderer/shims/NativeMethodsMixin.js | 1 + Libraries/Renderer/shims/ReactDebugTool.js | 1 + Libraries/Renderer/shims/ReactFabric.js | 1 + Libraries/Renderer/shims/ReactNative.js | 1 + .../shims/ReactNativeComponentTree.js | 1 + Libraries/Renderer/shims/ReactNativeTypes.js | 1 + .../shims/ReactNativeViewConfigRegistry.js | 1 + Libraries/Renderer/shims/ReactPerf.js | 1 + Libraries/Renderer/shims/ReactTypes.js | 1 + .../shims/createReactNativeComponentClass.js | 1 + 15 files changed, 4130 insertions(+), 3760 deletions(-) diff --git a/Libraries/Renderer/REVISION b/Libraries/Renderer/REVISION index ba0ce2996c4812..1899fb635260b6 100644 --- a/Libraries/Renderer/REVISION +++ b/Libraries/Renderer/REVISION @@ -1 +1 @@ -0887c7d56cb9b83f36dcb490b4245d7bc33bda1f \ No newline at end of file +25dda90c1ecb0c662ab06e2c80c1ee31e0ae9d36 \ No newline at end of file diff --git a/Libraries/Renderer/oss/ReactFabric-dev.js b/Libraries/Renderer/oss/ReactFabric-dev.js index 0424315c8ed6b5..3b52fb146ce85d 100644 --- a/Libraries/Renderer/oss/ReactFabric-dev.js +++ b/Libraries/Renderer/oss/ReactFabric-dev.js @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. * * @noflow + * @providesModule ReactFabric-dev * @preventMunge */ @@ -25,8 +26,8 @@ var deepDiffer = require("deepDiffer"); var flattenStyle = require("flattenStyle"); var React = require("react"); var emptyObject = require("fbjs/lib/emptyObject"); -var shallowEqual = require("fbjs/lib/shallowEqual"); var checkPropTypes = require("prop-types/checkPropTypes"); +var shallowEqual = require("fbjs/lib/shallowEqual"); var deepFreezeAndThrowOnMutationInDev = require("deepFreezeAndThrowOnMutationInDev"); var FabricUIManager = require("FabricUIManager"); @@ -815,7 +816,7 @@ var ForwardRef = 14; function getParent(inst) { do { - inst = inst["return"]; + 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 @@ -2312,23 +2313,21 @@ injection.injectEventPluginsByName({ // 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 hasSymbol = typeof Symbol === "function" && Symbol.for; -var REACT_ELEMENT_TYPE = hasSymbol ? Symbol["for"]("react.element") : 0xeac7; -var REACT_CALL_TYPE = hasSymbol ? Symbol["for"]("react.call") : 0xeac8; -var REACT_RETURN_TYPE = hasSymbol ? Symbol["for"]("react.return") : 0xeac9; -var REACT_PORTAL_TYPE = hasSymbol ? Symbol["for"]("react.portal") : 0xeaca; -var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol["for"]("react.fragment") : 0xeacb; +var REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for("react.element") : 0xeac7; +var REACT_CALL_TYPE = hasSymbol ? Symbol.for("react.call") : 0xeac8; +var REACT_RETURN_TYPE = hasSymbol ? Symbol.for("react.return") : 0xeac9; +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") + ? Symbol.for("react.strict_mode") : 0xeacc; -var REACT_PROVIDER_TYPE = hasSymbol ? Symbol["for"]("react.provider") : 0xeacd; -var REACT_CONTEXT_TYPE = hasSymbol ? Symbol["for"]("react.context") : 0xeace; -var REACT_ASYNC_MODE_TYPE = hasSymbol - ? Symbol["for"]("react.async_mode") - : 0xeacf; +var REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for("react.provider") : 0xeacd; +var REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for("react.context") : 0xeace; +var REACT_ASYNC_MODE_TYPE = hasSymbol ? Symbol.for("react.async_mode") : 0xeacf; var REACT_FORWARD_REF_TYPE = hasSymbol - ? Symbol["for"]("react.forward_ref") + ? Symbol.for("react.forward_ref") : 0xead0; var MAYBE_ITERATOR_SYMBOL = typeof Symbol === "function" && Symbol.iterator; @@ -3411,11 +3410,10 @@ var ContentReset = /* */ 16; var Callback = /* */ 32; var DidCapture = /* */ 64; var Ref = /* */ 128; -var ErrLog = /* */ 256; -var Snapshot = /* */ 2048; +var Snapshot = /* */ 256; // Union of all host effects -var HostEffectMask = /* */ 2559; +var HostEffectMask = /* */ 511; var Incomplete = /* */ 512; var ShouldCapture = /* */ 1024; @@ -3432,15 +3430,15 @@ function isFiberMountedImpl(fiber) { if ((node.effectTag & Placement) !== NoEffect) { return MOUNTING; } - while (node["return"]) { - node = node["return"]; + while (node.return) { + node = node.return; if ((node.effectTag & Placement) !== NoEffect) { return MOUNTING; } } } else { - while (node["return"]) { - node = node["return"]; + while (node.return) { + node = node.return; } } if (node.tag === HostRoot) { @@ -3512,7 +3510,7 @@ function findCurrentFiberUsingSlowPath(fiber) { var a = fiber; var b = alternate; while (true) { - var parentA = a["return"]; + var parentA = a.return; var parentB = parentA ? parentA.alternate : null; if (!parentA || !parentB) { // We're at the root. @@ -3542,7 +3540,7 @@ function findCurrentFiberUsingSlowPath(fiber) { invariant(false, "Unable to find node on an unmounted component."); } - if (a["return"] !== b["return"]) { + 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 @@ -3630,7 +3628,7 @@ function findCurrentHostFiber(parent) { if (node.tag === HostComponent || node.tag === HostText) { return node; } else if (node.child) { - node.child["return"] = node; + node.child.return = node; node = node.child; continue; } @@ -3638,12 +3636,12 @@ function findCurrentHostFiber(parent) { return null; } while (!node.sibling) { - if (!node["return"] || node["return"] === currentParent) { + if (!node.return || node.return === currentParent) { return null; } - node = node["return"]; + node = node.return; } - node.sibling["return"] = node["return"]; + node.sibling.return = node.return; node = node.sibling; } // Flow needs the return null here, but ESLint complains about it. @@ -3663,7 +3661,7 @@ function findCurrentHostFiberWithNoPortals(parent) { if (node.tag === HostComponent || node.tag === HostText) { return node; } else if (node.child && node.tag !== HostPortal) { - node.child["return"] = node; + node.child.return = node; node = node.child; continue; } @@ -3671,12 +3669,12 @@ function findCurrentHostFiberWithNoPortals(parent) { return null; } while (!node.sibling) { - if (!node["return"] || node["return"] === currentParent) { + if (!node.return || node.return === currentParent) { return null; } - node = node["return"]; + node = node.return; } - node.sibling["return"] = node["return"]; + node.sibling.return = node.return; node = node.sibling; } // Flow needs the return null here, but ESLint complains about it. @@ -3759,7 +3757,7 @@ function FiberNode(tag, pendingProps, key, mode) { this.stateNode = null; // Fiber - this["return"] = null; + this.return = null; this.child = null; this.sibling = null; this.index = 0; @@ -4044,7 +4042,7 @@ function assignFiberPropertiesInDEV(target, source) { target.key = source.key; target.type = source.type; target.stateNode = source.stateNode; - target["return"] = source["return"]; + target.return = source.return; target.child = source.child; target.sibling = source.sibling; target.index = source.index; @@ -4204,7 +4202,7 @@ function getStackAddendumByWorkInProgressFiber(workInProgress) { do { info += describeFiber(node); // Otherwise this return pointer might point to the wrong tree: - node = node["return"]; + node = node.return; } while (node); return info; } @@ -4374,7 +4372,7 @@ var ReactStrictModeWarnings = { maybeStrictRoot = fiber; } - fiber = fiber["return"]; + fiber = fiber.return; } return maybeStrictRoot; @@ -4495,16 +4493,6 @@ var ReactStrictModeWarnings = { return; } - // Don't warn about react-lifecycles-compat polyfilled components. - // Note that it is sufficient to check for the presence of a - // single lifecycle, componentWillMount, with the polyfill flag. - if ( - typeof instance.componentWillMount === "function" && - instance.componentWillMount.__suppressDeprecationWarning === true - ) { - return; - } - var warningsForRoot = void 0; if (!pendingUnsafeLifecycleWarnings.has(strictRoot)) { warningsForRoot = { @@ -4520,19 +4508,23 @@ var ReactStrictModeWarnings = { var unsafeLifecycles = []; if ( - typeof instance.componentWillMount === "function" || + (typeof instance.componentWillMount === "function" && + instance.componentWillMount.__suppressDeprecationWarning !== true) || typeof instance.UNSAFE_componentWillMount === "function" ) { unsafeLifecycles.push("UNSAFE_componentWillMount"); } if ( - typeof instance.componentWillReceiveProps === "function" || + (typeof instance.componentWillReceiveProps === "function" && + instance.componentWillReceiveProps.__suppressDeprecationWarning !== + true) || typeof instance.UNSAFE_componentWillReceiveProps === "function" ) { unsafeLifecycles.push("UNSAFE_componentWillReceiveProps"); } if ( - typeof instance.componentWillUpdate === "function" || + (typeof instance.componentWillUpdate === "function" && + instance.componentWillUpdate.__suppressDeprecationWarning !== true) || typeof instance.UNSAFE_componentWillUpdate === "function" ) { unsafeLifecycles.push("UNSAFE_componentWillUpdate"); @@ -4574,7 +4566,7 @@ function getCurrentFiberOwnerName() { return null; } -function getCurrentFiberStackAddendum() { +function getCurrentFiberStackAddendum$1() { { var fiber = ReactDebugCurrentFiber.current; if (fiber === null) { @@ -4594,7 +4586,7 @@ function resetCurrentFiber() { } function setCurrentFiber(fiber) { - ReactDebugCurrentFrame.getCurrentStack = getCurrentFiberStackAddendum; + ReactDebugCurrentFrame.getCurrentStack = getCurrentFiberStackAddendum$1; ReactDebugCurrentFiber.current = fiber; ReactDebugCurrentFiber.phase = null; } @@ -4610,7 +4602,7 @@ var ReactDebugCurrentFiber = { setCurrentFiber: setCurrentFiber, setCurrentPhase: setCurrentPhase, getCurrentFiberOwnerName: getCurrentFiberOwnerName, - getCurrentFiberStackAddendum: getCurrentFiberStackAddendum + getCurrentFiberStackAddendum: getCurrentFiberStackAddendum$1 }; // Prefix measurements so that it's possible to filter them. @@ -4767,13 +4759,13 @@ var pauseTimers = function() { if (fiber._debugIsCurrentlyTiming) { endFiberMark(fiber, null, null); } - fiber = fiber["return"]; + fiber = fiber.return; } }; var resumeTimersRecursively = function(fiber) { - if (fiber["return"] !== null) { - resumeTimersRecursively(fiber["return"]); + if (fiber.return !== null) { + resumeTimersRecursively(fiber.return); } if (fiber._debugIsCurrentlyTiming) { beginFiberMark(fiber, null); @@ -4865,7 +4857,7 @@ function stopWorkTimer(fiber) { return; } // If we pause, its parent is the fiber to unwind from. - currentFiber = fiber["return"]; + currentFiber = fiber.return; if (!fiber._debugIsCurrentlyTiming) { return; } @@ -4880,7 +4872,7 @@ function stopFailedWorkTimer(fiber) { return; } // If we pause, its parent is the fiber to unwind from. - currentFiber = fiber["return"]; + currentFiber = fiber.return; if (!fiber._debugIsCurrentlyTiming) { return; } @@ -5070,100 +5062,232 @@ function stopCommitLifeCyclesTimer() { } } -var didWarnUpdateInsideUpdate = void 0; +// 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 is +// 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; +var didWarnUpdateInsideUpdate = void 0; +var currentlyProcessingQueue = void 0; +var resetCurrentlyProcessingQueue = void 0; { didWarnUpdateInsideUpdate = false; + currentlyProcessingQueue = null; + resetCurrentlyProcessingQueue = function() { + currentlyProcessingQueue = null; + }; } -// Callbacks are not validated until invocation - -// Singly linked-list of updates. When an update is scheduled, it is added to -// the queue of the current fiber and the work-in-progress fiber. The two queues -// are separate but they share a persistent structure. -// -// During reconciliation, updates are removed from the work-in-progress fiber, -// but they remain on the current fiber. That ensures that if a work-in-progress -// is aborted, the aborted updates are recovered by cloning from current. -// -// The work-in-progress queue is always a subset of the current queue. -// -// When the tree is committed, the work-in-progress becomes the current. - function createUpdateQueue(baseState) { var queue = { - baseState: baseState, expirationTime: NoWork, - first: null, - last: null, - callbackList: null, + baseState: baseState, + firstUpdate: null, + lastUpdate: null, + firstCapturedUpdate: null, + lastCapturedUpdate: null, + firstEffect: null, + lastEffect: null, + firstCapturedEffect: null, + lastCapturedEffect: null, + hasForceUpdate: false + }; + return queue; +} + +function cloneUpdateQueue(currentQueue) { + var queue = { + expirationTime: currentQueue.expirationTime, + 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, + hasForceUpdate: false, - isInitialized: false, - capturedValues: null + + firstEffect: null, + lastEffect: null, + + firstCapturedEffect: null, + lastCapturedEffect: null }; - { - queue.isProcessing = false; - } return queue; } -function insertUpdateIntoQueue(queue, update) { +function createUpdate(expirationTime) { + return { + expirationTime: expirationTime, + + tag: UpdateState, + payload: null, + callback: null, + + next: null, + nextEffect: null + }; +} + +function appendUpdateToQueue(queue, update, expirationTime) { // Append the update to the end of the list. - if (queue.last === null) { + if (queue.lastUpdate === null) { // Queue is empty - queue.first = queue.last = update; + queue.firstUpdate = queue.lastUpdate = update; } else { - queue.last.next = update; - queue.last = update; + queue.lastUpdate.next = update; + queue.lastUpdate = update; } if ( queue.expirationTime === NoWork || - queue.expirationTime > update.expirationTime + queue.expirationTime > expirationTime ) { - queue.expirationTime = update.expirationTime; + // The incoming update has the earliest expiration of any update in the + // queue. Update the queue's expiration time. + queue.expirationTime = expirationTime; } } -var q1 = void 0; -var q2 = void 0; -function ensureUpdateQueues(fiber) { - q1 = q2 = null; - // We'll have at least one and at most two distinct update queues. - var alternateFiber = fiber.alternate; - var queue1 = fiber.updateQueue; - if (queue1 === null) { - // TODO: We don't know what the base state will be until we begin work. - // It depends on which fiber is the next current. Initialize with an empty - // base state, then set to the memoizedState when rendering. Not super - // happy with this approach. - queue1 = fiber.updateQueue = createUpdateQueue(null); - } - +function enqueueUpdate(fiber, update, expirationTime) { + // Update queues are created lazily. + var alternate = fiber.alternate; + var queue1 = void 0; var queue2 = void 0; - if (alternateFiber !== null) { - queue2 = alternateFiber.updateQueue; - if (queue2 === null) { - queue2 = alternateFiber.updateQueue = createUpdateQueue(null); + if (alternate === null) { + // There's only one fiber. + queue1 = fiber.updateQueue; + queue2 = null; + if (queue1 === null) { + queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState); } } else { - queue2 = null; + // 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, expirationTime); + } 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, expirationTime); + appendUpdateToQueue(queue2, update, expirationTime); + } 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, expirationTime); + // But we still need to update the `lastUpdate` pointer of queue2. + queue2.lastUpdate = update; + } } - queue2 = queue2 !== queue1 ? queue2 : null; - - // Use module variables instead of returning a tuple - q1 = queue1; - q2 = queue2; -} - -function insertUpdateIntoFiber(fiber, update) { - ensureUpdateQueues(fiber); - var queue1 = q1; - var queue2 = q2; - // Warn if an update is scheduled from inside an updater function. { if ( - (queue1.isProcessing || (queue2 !== null && queue2.isProcessing)) && + fiber.tag === ClassComponent && + (currentlyProcessingQueue === queue1 || + (queue2 !== null && currentlyProcessingQueue === queue2)) && !didWarnUpdateInsideUpdate ) { warning( @@ -5176,225 +5300,328 @@ function insertUpdateIntoFiber(fiber, update) { didWarnUpdateInsideUpdate = true; } } +} - // If there's only one queue, add the update to that queue and exit. - if (queue2 === null) { - insertUpdateIntoQueue(queue1, update); - return; +function enqueueCapturedUpdate(workInProgress, update, renderExpirationTime) { + // 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 + ); } - // If either queue is empty, we need to add to both queues. - if (queue1.last === null || queue2.last === null) { - insertUpdateIntoQueue(queue1, update); - insertUpdateIntoQueue(queue2, update); - return; + // 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; + } + if ( + workInProgressQueue.expirationTime === NoWork || + workInProgressQueue.expirationTime > renderExpirationTime + ) { + // The incoming update has the earliest expiration of any update in the + // queue. Update the queue's expiration time. + workInProgressQueue.expirationTime = renderExpirationTime; } - - // If both lists are not empty, the last update is the same for both lists - // because of structural sharing. So, we should only append to one of - // the lists. - insertUpdateIntoQueue(queue1, update); - // But we still need to update the `last` pointer of queue2. - queue2.last = update; } -function getUpdateExpirationTime(fiber) { - switch (fiber.tag) { - case HostRoot: - case ClassComponent: - var updateQueue = fiber.updateQueue; - if (updateQueue === null) { - return NoWork; - } - return updateQueue.expirationTime; - default: - return NoWork; +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(update, instance, prevState, props) { - var partialState = update.partialState; - if (typeof partialState === "function") { - return partialState.call(instance, prevState, props); - } else { - return partialState; +function getStateFromUpdate( + workInProgress, + queue, + update, + prevState, + nextProps, + instance +) { + switch (update.tag) { + case ReplaceState: { + var _payload = update.payload; + if (typeof _payload === "function") { + // Updater function + { + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + _payload.call(instance, prevState, nextProps); + } + } + return _payload.call(instance, prevState, nextProps); + } + // 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 + { + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + _payload2.call(instance, prevState, nextProps); + } + } + partialState = _payload2.call(instance, prevState, nextProps); + } 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: { + queue.hasForceUpdate = true; + return prevState; + } } + return prevState; } function processUpdateQueue( - current, workInProgress, queue, - instance, props, + instance, renderExpirationTime ) { - if (current !== null && current.updateQueue === queue) { - // We need to create a work-in-progress queue, by cloning the current queue. - var currentQueue = queue; - queue = workInProgress.updateQueue = { - baseState: currentQueue.baseState, - expirationTime: currentQueue.expirationTime, - first: currentQueue.first, - last: currentQueue.last, - isInitialized: currentQueue.isInitialized, - capturedValues: currentQueue.capturedValues, - // These fields are no longer valid because they were already committed. - // Reset them. - callbackList: null, - hasForceUpdate: false - }; + if ( + queue.expirationTime === NoWork || + queue.expirationTime > renderExpirationTime + ) { + // Insufficient priority. Bailout. + return; } + queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue); + { - // Set this flag so we can warn if setState is called inside the update - // function of another setState. - queue.isProcessing = true; - } - - // Reset the remaining expiration time. If we skip over any updates, we'll - // increase this accordingly. - queue.expirationTime = NoWork; - - // TODO: We don't know what the base state will be until we begin work. - // It depends on which fiber is the next current. Initialize with an empty - // base state, then set to the memoizedState when rendering. Not super - // happy with this approach. - var state = void 0; - if (queue.isInitialized) { - state = queue.baseState; - } else { - state = queue.baseState = workInProgress.memoizedState; - queue.isInitialized = true; + currentlyProcessingQueue = queue; } - var dontMutatePrevState = true; - var update = queue.first; - var didSkip = false; + + // 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. - var remainingExpirationTime = queue.expirationTime; + 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 ( - remainingExpirationTime === NoWork || - remainingExpirationTime > updateExpirationTime + newExpirationTime === NoWork || + newExpirationTime > updateExpirationTime ) { - // Update the remaining expiration time. - queue.expirationTime = updateExpirationTime; + newExpirationTime = updateExpirationTime; } - if (!didSkip) { - didSkip = true; - queue.baseState = state; + } else { + // This update does have sufficient priority. 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; - continue; } + // Continue to the next update. + update = update.next; + } - // This update does have sufficient priority. - - // If no previous updates were skipped, drop this update from the queue by - // advancing the head of the list. - if (!didSkip) { - queue.first = update.next; - if (queue.first === null) { - queue.last = null; + // 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 === NoWork || + newExpirationTime > _updateExpirationTime + ) { + newExpirationTime = _updateExpirationTime; } - } - - // Invoke setState callback an extra time to help detect side-effects. - // Ignore the return value in this case. - if ( - debugRenderPhaseSideEffects || - (debugRenderPhaseSideEffectsForStrictMode && - workInProgress.mode & StrictMode) - ) { - getStateFromUpdate(update, instance, state, props); - } - - // Process the update - var _partialState = void 0; - if (update.isReplace) { - state = getStateFromUpdate(update, instance, state, props); - dontMutatePrevState = true; } else { - _partialState = getStateFromUpdate(update, instance, state, props); - if (_partialState) { - if (dontMutatePrevState) { - // $FlowFixMe: Idk how to type this properly. - state = Object.assign({}, state, _partialState); + // 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 { - state = Object.assign(state, _partialState); + queue.lastCapturedEffect.nextEffect = update; + queue.lastCapturedEffect = update; } - dontMutatePrevState = false; - } - } - if (update.isForced) { - queue.hasForceUpdate = true; - } - if (update.callback !== null) { - // Append to list of callbacks. - var _callbackList = queue.callbackList; - if (_callbackList === null) { - _callbackList = queue.callbackList = []; - } - _callbackList.push(update); - } - if (update.capturedValue !== null) { - var _capturedValues = queue.capturedValues; - if (_capturedValues === null) { - queue.capturedValues = [update.capturedValue]; - } else { - _capturedValues.push(update.capturedValue); } } update = update.next; } - if (queue.callbackList !== null) { + if (newFirstUpdate === null) { + queue.lastUpdate = null; + } + if (newFirstCapturedUpdate === null) { + queue.lastCapturedUpdate = null; + } else { workInProgress.effectTag |= Callback; - } else if ( - queue.first === null && - !queue.hasForceUpdate && - queue.capturedValues === null - ) { - // The queue is empty. We can reset it. - workInProgress.updateQueue = null; } - - if (!didSkip) { - didSkip = true; - queue.baseState = state; + 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; + queue.expirationTime = newExpirationTime; + + workInProgress.memoizedState = resultState; + { - // No longer processing. - queue.isProcessing = false; + currentlyProcessingQueue = null; } +} - return state; +function callCallback(callback, context) { + invariant( + typeof callback === "function", + "Invalid argument passed as callback. Expected a function. Instead " + + "received: %s", + callback + ); + callback.call(context); } -function commitCallbacks(queue, context) { - var callbackList = queue.callbackList; - if (callbackList === null) { - return; +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; } - // Set the list to null to make sure they don't get called more than once. - queue.callbackList = null; - for (var i = 0; i < callbackList.length; i++) { - var update = callbackList[i]; - var _callback = update.callback; - // This update might be processed again. Clear the callback so it's only - // called once. - update.callback = null; - invariant( - typeof _callback === "function", - "Invalid argument passed as callback. Expected a function. Instead " + - "received: %s", - _callback - ); - _callback.call(context); + + // Commit the effects + var effect = finishedQueue.firstEffect; + finishedQueue.firstEffect = finishedQueue.lastEffect = null; + while (effect !== null) { + var _callback3 = effect.callback; + if (_callback3 !== null) { + effect.callback = null; + callCallback(_callback3, instance); + } + effect = effect.nextEffect; + } + + effect = finishedQueue.firstCapturedEffect; + finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null; + while (effect !== null) { + var _callback4 = effect.callback; + if (_callback4 !== null) { + effect.callback = null; + callCallback(_callback4, instance); + } + effect = effect.nextEffect; } } @@ -5402,18 +5629,19 @@ var fakeInternalInstance = {}; var isArray = Array.isArray; var didWarnAboutStateAssignmentForComponent = void 0; -var didWarnAboutUndefinedDerivedState = 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; { didWarnAboutStateAssignmentForComponent = new Set(); - didWarnAboutUndefinedDerivedState = new Set(); didWarnAboutUninitializedState = new Set(); didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = new Set(); didWarnAboutLegacyLifecyclesAndDerivedState = new Set(); + didWarnAboutUndefinedDerivedState = new Set(); var didWarnOnInvalidCallback = new Set(); @@ -5434,6 +5662,21 @@ var warnOnInvalidCallback = void 0; } }; + warnOnUndefinedDerivedState = function(workInProgress, partialState) { + if (partialState === undefined) { + var componentName = getComponentName(workInProgress) || "Component"; + if (!didWarnAboutUndefinedDerivedState.has(componentName)) { + didWarnAboutUndefinedDerivedState.add(componentName); + warning( + 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, @@ -5455,17 +5698,43 @@ var warnOnInvalidCallback = void 0; }); Object.freeze(fakeInternalInstance); } -function callGetDerivedStateFromCatch(ctor, capturedValues) { - var resultState = {}; - for (var i = 0; i < capturedValues.length; i++) { - var capturedValue = capturedValues[i]; - var error = capturedValue.value; - var partialState = ctor.getDerivedStateFromCatch.call(null, error); - if (partialState !== null && partialState !== undefined) { - Object.assign(resultState, partialState); + +function applyDerivedStateFromProps( + workInProgress, + 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); } } - return resultState; + + var partialState = getDerivedStateFromProps(nextProps, prevState); + + { + warnOnUndefinedDerivedState(workInProgress, 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 && updateQueue.expirationTime === NoWork) { + updateQueue.baseState = memoizedState; + } } var ReactFiberClassComponent = function( @@ -5481,65 +5750,57 @@ var ReactFiberClassComponent = function( isContextConsumer = legacyContext.isContextConsumer, hasContextChanged = legacyContext.hasContextChanged; - // Class component state updater - - var updater = { + var classComponentUpdater = { isMounted: isMounted, - enqueueSetState: function(instance, partialState, callback) { - var fiber = get$1(instance); - callback = callback === undefined ? null : callback; - { - warnOnInvalidCallback(callback, "setState"); - } + enqueueSetState: function(inst, payload, callback) { + var fiber = get$1(inst); var expirationTime = computeExpirationForFiber(fiber); - var update = { - expirationTime: expirationTime, - partialState: partialState, - callback: callback, - isReplace: false, - isForced: false, - capturedValue: null, - next: null - }; - insertUpdateIntoFiber(fiber, update); + + var update = createUpdate(expirationTime); + update.payload = payload; + if (callback !== undefined && callback !== null) { + { + warnOnInvalidCallback(callback, "setState"); + } + update.callback = callback; + } + + enqueueUpdate(fiber, update, expirationTime); scheduleWork(fiber, expirationTime); }, - enqueueReplaceState: function(instance, state, callback) { - var fiber = get$1(instance); - callback = callback === undefined ? null : callback; - { - warnOnInvalidCallback(callback, "replaceState"); - } + enqueueReplaceState: function(inst, payload, callback) { + var fiber = get$1(inst); var expirationTime = computeExpirationForFiber(fiber); - var update = { - expirationTime: expirationTime, - partialState: state, - callback: callback, - isReplace: true, - isForced: false, - capturedValue: null, - next: null - }; - insertUpdateIntoFiber(fiber, update); + + var update = createUpdate(expirationTime); + update.tag = ReplaceState; + update.payload = payload; + + if (callback !== undefined && callback !== null) { + { + warnOnInvalidCallback(callback, "replaceState"); + } + update.callback = callback; + } + + enqueueUpdate(fiber, update, expirationTime); scheduleWork(fiber, expirationTime); }, - enqueueForceUpdate: function(instance, callback) { - var fiber = get$1(instance); - callback = callback === undefined ? null : callback; - { - warnOnInvalidCallback(callback, "forceUpdate"); - } + enqueueForceUpdate: function(inst, callback) { + var fiber = get$1(inst); var expirationTime = computeExpirationForFiber(fiber); - var update = { - expirationTime: expirationTime, - partialState: null, - callback: callback, - isReplace: false, - isForced: true, - capturedValue: null, - next: null - }; - insertUpdateIntoFiber(fiber, update); + + var update = createUpdate(expirationTime); + update.tag = ForceUpdate; + + if (callback !== undefined && callback !== null) { + { + warnOnInvalidCallback(callback, "forceUpdate"); + } + update.callback = callback; + } + + enqueueUpdate(fiber, update, expirationTime); scheduleWork(fiber, expirationTime); } }; @@ -5553,11 +5814,10 @@ var ReactFiberClassComponent = function( newContext ) { if ( - oldProps === null || - (workInProgress.updateQueue !== null && - workInProgress.updateQueue.hasForceUpdate) + workInProgress.updateQueue !== null && + workInProgress.updateQueue.hasForceUpdate ) { - // If the workInProgress already has an Update effect, return true + // If forceUpdate was called, disregard sCU. return true; } @@ -5814,13 +6074,8 @@ var ReactFiberClassComponent = function( } } - function resetInputPointers(workInProgress, instance) { - instance.props = workInProgress.memoizedProps; - instance.state = workInProgress.memoizedState; - } - function adoptClassInstance(workInProgress, instance) { - instance.updater = updater; + instance.updater = classComponentUpdater; workInProgress.stateNode = instance; // The instance needs access to the fiber so that it can schedule updates set(instance, workInProgress); @@ -5829,7 +6084,7 @@ var ReactFiberClassComponent = function( } } - function constructClassInstance(workInProgress, props) { + function constructClassInstance(workInProgress, props, renderExpirationTime) { var ctor = workInProgress.type; var unmaskedContext = getUnmaskedContext(workInProgress); var needsContext = isContextConsumer(workInProgress); @@ -5838,19 +6093,21 @@ var ReactFiberClassComponent = function( : emptyObject; // Instantiate twice to help detect side-effects. - if ( - debugRenderPhaseSideEffects || - (debugRenderPhaseSideEffectsForStrictMode && - workInProgress.mode & StrictMode) - ) { - new ctor(props, context); // eslint-disable-line no-new + { + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + new ctor(props, context); // eslint-disable-line no-new + } } var instance = new ctor(props, context); - var state = + var state = (workInProgress.memoizedState = instance.state !== null && instance.state !== undefined ? instance.state - : null; + : null); adoptClassInstance(workInProgress, instance); { @@ -5941,26 +6198,6 @@ var ReactFiberClassComponent = function( } } - workInProgress.memoizedState = state; - - var partialState = callGetDerivedStateFromProps( - workInProgress, - instance, - props, - state - ); - - if (partialState !== null && partialState !== undefined) { - // Render-phase updates (like this) should not be added to the update queue, - // So that multiple render passes do not enqueue multiple updates. - // Instead, just synchronously merge the returned state into the instance. - workInProgress.memoizedState = Object.assign( - {}, - workInProgress.memoizedState, - partialState - ); - } - // 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 (needsContext) { @@ -5993,7 +6230,7 @@ var ReactFiberClassComponent = function( getComponentName(workInProgress) || "Component" ); } - updater.enqueueReplaceState(instance, instance.state, null); + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); } } @@ -6027,57 +6264,13 @@ var ReactFiberClassComponent = function( ); } } - updater.enqueueReplaceState(instance, instance.state, null); - } - } - - function callGetDerivedStateFromProps( - workInProgress, - instance, - nextProps, - prevState - ) { - var type = workInProgress.type; - - if (typeof type.getDerivedStateFromProps === "function") { - if ( - debugRenderPhaseSideEffects || - (debugRenderPhaseSideEffectsForStrictMode && - workInProgress.mode & StrictMode) - ) { - // Invoke method an extra time to help detect side-effects. - type.getDerivedStateFromProps.call(null, nextProps, prevState); - } - - var partialState = type.getDerivedStateFromProps.call( - null, - nextProps, - prevState - ); - - { - if (partialState === undefined) { - var componentName = getComponentName(workInProgress) || "Component"; - if (!didWarnAboutUndefinedDerivedState.has(componentName)) { - didWarnAboutUndefinedDerivedState.add(componentName); - warning( - false, - "%s.getDerivedStateFromProps(): A valid state object (or null) must be returned. " + - "You have returned undefined.", - componentName - ); - } - } - } - - return partialState; + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); } } // Invokes the mount life-cycles on a previously never rendered instance. function mountClassInstance(workInProgress, renderExpirationTime) { var ctor = workInProgress.type; - var current = workInProgress.alternate; { checkClassInstance(workInProgress); @@ -6108,6 +6301,28 @@ var ReactFiberClassComponent = function( } } + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + processUpdateQueue( + workInProgress, + updateQueue, + props, + instance, + renderExpirationTime + ); + instance.state = workInProgress.memoizedState; + } + + var getDerivedStateFromProps = workInProgress.type.getDerivedStateFromProps; + if (typeof getDerivedStateFromProps === "function") { + applyDerivedStateFromProps( + workInProgress, + getDerivedStateFromProps, + props + ); + 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 ( @@ -6119,18 +6334,19 @@ var ReactFiberClassComponent = function( callComponentWillMount(workInProgress, instance); // If we had additional state updates during this life-cycle, let's // process them now. - var updateQueue = workInProgress.updateQueue; + updateQueue = workInProgress.updateQueue; if (updateQueue !== null) { - instance.state = processUpdateQueue( - current, + processUpdateQueue( workInProgress, updateQueue, - instance, props, + instance, renderExpirationTime ); + instance.state = workInProgress.memoizedState; } } + if (typeof instance.componentDidMount === "function") { workInProgress.effectTag |= Update; } @@ -6139,16 +6355,18 @@ var ReactFiberClassComponent = function( function resumeMountClassInstance(workInProgress, renderExpirationTime) { var ctor = workInProgress.type; var instance = workInProgress.stateNode; - resetInputPointers(workInProgress, instance); var oldProps = workInProgress.memoizedProps; var newProps = workInProgress.pendingProps; + instance.props = oldProps; + var oldContext = instance.context; var newUnmaskedContext = getUnmaskedContext(workInProgress); var newContext = getMaskedContext(workInProgress, newUnmaskedContext); + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; var hasNewLifecycles = - typeof ctor.getDerivedStateFromProps === "function" || + typeof getDerivedStateFromProps === "function" || typeof instance.getSnapshotBeforeUpdate === "function"; // Note: During these life-cycles, instance.props/instance.state are what @@ -6172,93 +6390,27 @@ var ReactFiberClassComponent = function( } } - // Compute the next state using the memoized state and the update queue. var oldState = workInProgress.memoizedState; - // TODO: Previous state can be null. - var newState = void 0; - var derivedStateFromCatch = void 0; - if (workInProgress.updateQueue !== null) { - newState = processUpdateQueue( - null, + var newState = (instance.state = oldState); + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + processUpdateQueue( workInProgress, - workInProgress.updateQueue, - instance, + updateQueue, newProps, + instance, renderExpirationTime ); - - var updateQueue = workInProgress.updateQueue; - if ( - updateQueue !== null && - updateQueue.capturedValues !== null && - enableGetDerivedStateFromCatch && - typeof ctor.getDerivedStateFromCatch === "function" - ) { - var capturedValues = updateQueue.capturedValues; - // Don't remove these from the update queue yet. We need them in - // finishClassComponent. Do the reset there. - // TODO: This is awkward. Refactor class components. - // updateQueue.capturedValues = null; - derivedStateFromCatch = callGetDerivedStateFromCatch( - ctor, - capturedValues - ); - } - } else { - newState = oldState; + newState = workInProgress.memoizedState; } - var derivedStateFromProps = void 0; - if (oldProps !== newProps) { - // The prevState parameter should be the partially updated state. - // Otherwise, spreading state in return values could override updates. - derivedStateFromProps = callGetDerivedStateFromProps( + if (typeof getDerivedStateFromProps === "function") { + applyDerivedStateFromProps( workInProgress, - instance, - newProps, - newState + getDerivedStateFromProps, + newProps ); - } - - if (derivedStateFromProps !== null && derivedStateFromProps !== undefined) { - // Render-phase updates (like this) should not be added to the update queue, - // So that multiple render passes do not enqueue multiple updates. - // Instead, just synchronously merge the returned state into the instance. - newState = - newState === null || newState === undefined - ? derivedStateFromProps - : Object.assign({}, newState, derivedStateFromProps); - - // Update the base state of the update queue. - // FIXME: This is getting ridiculous. Refactor plz! - var _updateQueue = workInProgress.updateQueue; - if (_updateQueue !== null) { - _updateQueue.baseState = Object.assign( - {}, - _updateQueue.baseState, - derivedStateFromProps - ); - } - } - if (derivedStateFromCatch !== null && derivedStateFromCatch !== undefined) { - // Render-phase updates (like this) should not be added to the update queue, - // So that multiple render passes do not enqueue multiple updates. - // Instead, just synchronously merge the returned state into the instance. - newState = - newState === null || newState === undefined - ? derivedStateFromCatch - : Object.assign({}, newState, derivedStateFromCatch); - - // Update the base state of the update queue. - // FIXME: This is getting ridiculous. Refactor plz! - var _updateQueue2 = workInProgress.updateQueue; - if (_updateQueue2 !== null) { - _updateQueue2.baseState = Object.assign( - {}, - _updateQueue2.baseState, - derivedStateFromCatch - ); - } + newState = workInProgress.memoizedState; } if ( @@ -6315,9 +6467,9 @@ var ReactFiberClassComponent = function( } // If shouldComponentUpdate returned false, we should still update the - // memoized props/state to indicate that this work can be reused. - memoizeProps(workInProgress, newProps); - memoizeState(workInProgress, newState); + // 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 @@ -6333,16 +6485,18 @@ var ReactFiberClassComponent = function( function updateClassInstance(current, workInProgress, renderExpirationTime) { var ctor = workInProgress.type; var instance = workInProgress.stateNode; - resetInputPointers(workInProgress, instance); var oldProps = workInProgress.memoizedProps; var newProps = workInProgress.pendingProps; + instance.props = oldProps; + var oldContext = instance.context; var newUnmaskedContext = getUnmaskedContext(workInProgress); var newContext = getMaskedContext(workInProgress, newUnmaskedContext); + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; var hasNewLifecycles = - typeof ctor.getDerivedStateFromProps === "function" || + typeof getDerivedStateFromProps === "function" || typeof instance.getSnapshotBeforeUpdate === "function"; // Note: During these life-cycles, instance.props/instance.state are what @@ -6366,94 +6520,27 @@ var ReactFiberClassComponent = function( } } - // Compute the next state using the memoized state and the update queue. var oldState = workInProgress.memoizedState; - // TODO: Previous state can be null. - var newState = void 0; - var derivedStateFromCatch = void 0; - - if (workInProgress.updateQueue !== null) { - newState = processUpdateQueue( - current, + var newState = (instance.state = oldState); + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + processUpdateQueue( workInProgress, - workInProgress.updateQueue, - instance, + updateQueue, newProps, + instance, renderExpirationTime ); - - var updateQueue = workInProgress.updateQueue; - if ( - updateQueue !== null && - updateQueue.capturedValues !== null && - enableGetDerivedStateFromCatch && - typeof ctor.getDerivedStateFromCatch === "function" - ) { - var capturedValues = updateQueue.capturedValues; - // Don't remove these from the update queue yet. We need them in - // finishClassComponent. Do the reset there. - // TODO: This is awkward. Refactor class components. - // updateQueue.capturedValues = null; - derivedStateFromCatch = callGetDerivedStateFromCatch( - ctor, - capturedValues - ); - } - } else { - newState = oldState; + newState = workInProgress.memoizedState; } - var derivedStateFromProps = void 0; - if (oldProps !== newProps) { - // The prevState parameter should be the partially updated state. - // Otherwise, spreading state in return values could override updates. - derivedStateFromProps = callGetDerivedStateFromProps( + if (typeof getDerivedStateFromProps === "function") { + applyDerivedStateFromProps( workInProgress, - instance, - newProps, - newState + getDerivedStateFromProps, + newProps ); - } - - if (derivedStateFromProps !== null && derivedStateFromProps !== undefined) { - // Render-phase updates (like this) should not be added to the update queue, - // So that multiple render passes do not enqueue multiple updates. - // Instead, just synchronously merge the returned state into the instance. - newState = - newState === null || newState === undefined - ? derivedStateFromProps - : Object.assign({}, newState, derivedStateFromProps); - - // Update the base state of the update queue. - // FIXME: This is getting ridiculous. Refactor plz! - var _updateQueue3 = workInProgress.updateQueue; - if (_updateQueue3 !== null) { - _updateQueue3.baseState = Object.assign( - {}, - _updateQueue3.baseState, - derivedStateFromProps - ); - } - } - if (derivedStateFromCatch !== null && derivedStateFromCatch !== undefined) { - // Render-phase updates (like this) should not be added to the update queue, - // So that multiple render passes do not enqueue multiple updates. - // Instead, just synchronously merge the returned state into the instance. - newState = - newState === null || newState === undefined - ? derivedStateFromCatch - : Object.assign({}, newState, derivedStateFromCatch); - - // Update the base state of the update queue. - // FIXME: This is getting ridiculous. Refactor plz! - var _updateQueue4 = workInProgress.updateQueue; - if (_updateQueue4 !== null) { - _updateQueue4.baseState = Object.assign( - {}, - _updateQueue4.baseState, - derivedStateFromCatch - ); - } + newState = workInProgress.memoizedState; } if ( @@ -6540,8 +6627,8 @@ var ReactFiberClassComponent = function( // If shouldComponentUpdate returned false, we should still update the // memoized props/state to indicate that this work can be reused. - memoizeProps(workInProgress, newProps); - memoizeState(workInProgress, newState); + workInProgress.memoizedProps = newProps; + workInProgress.memoizedState = newState; } // Update the existing instance's state, props, and context pointers even @@ -6555,7 +6642,6 @@ var ReactFiberClassComponent = function( return { adoptClassInstance: adoptClassInstance, - callGetDerivedStateFromProps: callGetDerivedStateFromProps, constructClassInstance: constructClassInstance, mountClassInstance: mountClassInstance, resumeMountClassInstance: resumeMountClassInstance, @@ -6563,7 +6649,7 @@ var ReactFiberClassComponent = function( }; }; -var getCurrentFiberStackAddendum$1 = +var getCurrentFiberStackAddendum$2 = ReactDebugCurrentFiber.getCurrentFiberStackAddendum; var didWarnAboutMaps = void 0; @@ -6602,7 +6688,7 @@ var warnForMissingKey = function(child) {}; "Each child in an array or iterator should have a unique " + '"key" prop. See https://fb.me/react-warning-keys for ' + "more information." + - (getCurrentFiberStackAddendum$1() || ""); + (getCurrentFiberStackAddendum$2() || ""); if (ownerHasKeyUseWarning[currentComponentErrorInfo]) { return; } @@ -6613,7 +6699,7 @@ var warnForMissingKey = function(child) {}; "Each child in an array or iterator should have a unique " + '"key" prop. See https://fb.me/react-warning-keys for ' + "more information.%s", - getCurrentFiberStackAddendum$1() + getCurrentFiberStackAddendum$2() ); }; } @@ -6710,7 +6796,7 @@ function throwOnInvalidObjectType(returnFiber, newChild) { addendum = " If you meant to render a collection of children, use an array " + "instead." + - (getCurrentFiberStackAddendum$1() || ""); + (getCurrentFiberStackAddendum$2() || ""); } invariant( false, @@ -6728,7 +6814,7 @@ function warnOnFunctionType() { "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." + - (getCurrentFiberStackAddendum$1() || ""); + (getCurrentFiberStackAddendum$2() || ""); if (ownerHasFunctionTypeWarning[currentComponentErrorInfo]) { return; @@ -6740,7 +6826,7 @@ function warnOnFunctionType() { "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.%s", - getCurrentFiberStackAddendum$1() || "" + getCurrentFiberStackAddendum$2() || "" ); } @@ -6853,12 +6939,12 @@ function ChildReconciler(shouldTrackSideEffects) { returnFiber.mode, expirationTime ); - created["return"] = returnFiber; + created.return = returnFiber; return created; } else { // Update var existing = useFiber(current, textContent, expirationTime); - existing["return"] = returnFiber; + existing.return = returnFiber; return existing; } } @@ -6868,7 +6954,7 @@ function ChildReconciler(shouldTrackSideEffects) { // Move based on index var existing = useFiber(current, element.props, expirationTime); existing.ref = coerceRef(returnFiber, current, element); - existing["return"] = returnFiber; + existing.return = returnFiber; { existing._debugSource = element._source; existing._debugOwner = element._owner; @@ -6882,7 +6968,7 @@ function ChildReconciler(shouldTrackSideEffects) { expirationTime ); created.ref = coerceRef(returnFiber, current, element); - created["return"] = returnFiber; + created.return = returnFiber; return created; } } @@ -6900,12 +6986,12 @@ function ChildReconciler(shouldTrackSideEffects) { returnFiber.mode, expirationTime ); - created["return"] = returnFiber; + created.return = returnFiber; return created; } else { // Update var existing = useFiber(current, portal.children || [], expirationTime); - existing["return"] = returnFiber; + existing.return = returnFiber; return existing; } } @@ -6919,12 +7005,12 @@ function ChildReconciler(shouldTrackSideEffects) { expirationTime, key ); - created["return"] = returnFiber; + created.return = returnFiber; return created; } else { // Update var existing = useFiber(current, fragment, expirationTime); - existing["return"] = returnFiber; + existing.return = returnFiber; return existing; } } @@ -6939,7 +7025,7 @@ function ChildReconciler(shouldTrackSideEffects) { returnFiber.mode, expirationTime ); - created["return"] = returnFiber; + created.return = returnFiber; return created; } @@ -6952,7 +7038,7 @@ function ChildReconciler(shouldTrackSideEffects) { expirationTime ); _created.ref = coerceRef(returnFiber, null, newChild); - _created["return"] = returnFiber; + _created.return = returnFiber; return _created; } case REACT_PORTAL_TYPE: { @@ -6961,7 +7047,7 @@ function ChildReconciler(shouldTrackSideEffects) { returnFiber.mode, expirationTime ); - _created2["return"] = returnFiber; + _created2.return = returnFiber; return _created2; } } @@ -6973,7 +7059,7 @@ function ChildReconciler(shouldTrackSideEffects) { expirationTime, null ); - _created3["return"] = returnFiber; + _created3.return = returnFiber; return _created3; } @@ -7184,7 +7270,7 @@ function ChildReconciler(shouldTrackSideEffects) { "duplicated and/or omitted — the behavior is unsupported and " + "could change in a future version.%s", key, - getCurrentFiberStackAddendum$1() + getCurrentFiberStackAddendum$2() ); break; default: @@ -7329,7 +7415,7 @@ function ChildReconciler(shouldTrackSideEffects) { // 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"]( + existingChildren.delete( _newFiber2.key === null ? newIdx : _newFiber2.key ); } @@ -7382,7 +7468,7 @@ function ChildReconciler(shouldTrackSideEffects) { "Using Maps as children is unsupported and will likely yield " + "unexpected results. Convert it to a sequence/iterable of keyed " + "ReactElements instead.%s", - getCurrentFiberStackAddendum$1() + getCurrentFiberStackAddendum$2() ) : void 0; didWarnAboutMaps = true; @@ -7508,7 +7594,7 @@ function ChildReconciler(shouldTrackSideEffects) { // 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"]( + existingChildren.delete( _newFiber4.key === null ? newIdx : _newFiber4.key ); } @@ -7547,7 +7633,7 @@ function ChildReconciler(shouldTrackSideEffects) { // the rest. deleteRemainingChildren(returnFiber, currentFirstChild.sibling); var existing = useFiber(currentFirstChild, textContent, expirationTime); - existing["return"] = returnFiber; + existing.return = returnFiber; return existing; } // The existing first child is not a text node so we need to create one @@ -7558,7 +7644,7 @@ function ChildReconciler(shouldTrackSideEffects) { returnFiber.mode, expirationTime ); - created["return"] = returnFiber; + created.return = returnFiber; return created; } @@ -7588,7 +7674,7 @@ function ChildReconciler(shouldTrackSideEffects) { expirationTime ); existing.ref = coerceRef(returnFiber, child, element); - existing["return"] = returnFiber; + existing.return = returnFiber; { existing._debugSource = element._source; existing._debugOwner = element._owner; @@ -7611,7 +7697,7 @@ function ChildReconciler(shouldTrackSideEffects) { expirationTime, element.key ); - created["return"] = returnFiber; + created.return = returnFiber; return created; } else { var _created4 = createFiberFromElement( @@ -7620,7 +7706,7 @@ function ChildReconciler(shouldTrackSideEffects) { expirationTime ); _created4.ref = coerceRef(returnFiber, currentFirstChild, element); - _created4["return"] = returnFiber; + _created4.return = returnFiber; return _created4; } } @@ -7644,7 +7730,7 @@ function ChildReconciler(shouldTrackSideEffects) { ) { deleteRemainingChildren(returnFiber, child.sibling); var existing = useFiber(child, portal.children || [], expirationTime); - existing["return"] = returnFiber; + existing.return = returnFiber; return existing; } else { deleteRemainingChildren(returnFiber, child); @@ -7661,7 +7747,7 @@ function ChildReconciler(shouldTrackSideEffects) { returnFiber.mode, expirationTime ); - created["return"] = returnFiber; + created.return = returnFiber; return created; } @@ -7813,7 +7899,7 @@ function cloneChildFibers(current, workInProgress) { ); workInProgress.child = newChild; - newChild["return"] = workInProgress; + newChild.return = workInProgress; while (currentChild.sibling !== null) { currentChild = currentChild.sibling; newChild = newChild.sibling = createWorkInProgress( @@ -7821,11 +7907,14 @@ function cloneChildFibers(current, workInProgress) { currentChild.pendingProps, currentChild.expirationTime ); - newChild["return"] = workInProgress; + newChild.return = workInProgress; } newChild.sibling = null; } +var getCurrentFiberStackAddendum = + ReactDebugCurrentFiber.getCurrentFiberStackAddendum; + var didWarnAboutBadClass = void 0; var didWarnAboutGetDerivedStateOnFunctionalComponent = void 0; var didWarnAboutStatelessRefs = void 0; @@ -7869,8 +7958,6 @@ var ReactFiberBeginWork = function( memoizeState ), adoptClassInstance = _ReactFiberClassCompo.adoptClassInstance, - callGetDerivedStateFromProps = - _ReactFiberClassCompo.callGetDerivedStateFromProps, constructClassInstance = _ReactFiberClassCompo.constructClassInstance, mountClassInstance = _ReactFiberClassCompo.mountClassInstance, resumeMountClassInstance = _ReactFiberClassCompo.resumeMountClassInstance, @@ -7922,9 +8009,20 @@ var ReactFiberBeginWork = function( function updateForwardRef(current, workInProgress) { var render = workInProgress.type.render; - var nextChildren = render(workInProgress.pendingProps, workInProgress.ref); + var nextProps = workInProgress.pendingProps; + var ref = workInProgress.ref; + if (hasLegacyContextChanged()) { + // Normally we can bail out on props equality but if context has changed + // we don't do the bailout and we have to reuse existing props instead. + } else if (workInProgress.memoizedProps === nextProps) { + var currentRef = current !== null ? current.ref : null; + if (ref === currentRef) { + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + } + var nextChildren = render(nextProps, ref); reconcileChildren(current, workInProgress, nextChildren); - memoizeProps(workInProgress, nextChildren); + memoizeProps(workInProgress, nextProps); return workInProgress.child; } @@ -8010,7 +8108,11 @@ var ReactFiberBeginWork = function( if (current === null) { if (workInProgress.stateNode === null) { // In the initial pass we might need to construct the instance. - constructClassInstance(workInProgress, workInProgress.pendingProps); + constructClassInstance( + workInProgress, + workInProgress.pendingProps, + renderExpirationTime + ); mountClassInstance(workInProgress, renderExpirationTime); shouldUpdate = true; @@ -8028,22 +8130,11 @@ var ReactFiberBeginWork = function( renderExpirationTime ); } - - // We processed the update queue inside updateClassInstance. It may have - // included some errors that were dispatched during the commit phase. - // TODO: Refactor class components so this is less awkward. - var didCaptureError = false; - var updateQueue = workInProgress.updateQueue; - if (updateQueue !== null && updateQueue.capturedValues !== null) { - shouldUpdate = true; - didCaptureError = true; - } return finishClassComponent( current, workInProgress, shouldUpdate, hasContext, - didCaptureError, renderExpirationTime ); } @@ -8053,12 +8144,13 @@ var ReactFiberBeginWork = function( workInProgress, shouldUpdate, hasContext, - didCaptureError, renderExpirationTime ) { // Refs should update even if shouldComponentUpdate returns false markRef(current, workInProgress); + var didCaptureError = (workInProgress.effectTag & DidCapture) !== NoEffect; + if (!shouldUpdate && !didCaptureError) { // Context providers should defer to sCU for rendering if (hasContext) { @@ -8154,29 +8246,26 @@ var ReactFiberBeginWork = function( pushHostRootContext(workInProgress); var updateQueue = workInProgress.updateQueue; if (updateQueue !== null) { + var nextProps = workInProgress.pendingProps; var prevState = workInProgress.memoizedState; - var state = processUpdateQueue( - current, + var prevChildren = prevState !== null ? prevState.element : null; + processUpdateQueue( workInProgress, updateQueue, - null, + nextProps, null, renderExpirationTime ); - memoizeState(workInProgress, state); - updateQueue = workInProgress.updateQueue; + var nextState = workInProgress.memoizedState; + // Caution: React DevTools currently depends on this property + // being called "element". + var nextChildren = nextState.element; - var element = void 0; - if (updateQueue !== null && updateQueue.capturedValues !== null) { - // There's an uncaught error. Unmount the whole root. - element = null; - } else if (prevState === state) { + 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, workInProgress); - } else { - element = state.element; } var root = workInProgress.stateNode; if ( @@ -8201,16 +8290,15 @@ var ReactFiberBeginWork = function( workInProgress.child = mountChildFibers( workInProgress, null, - element, + nextChildren, renderExpirationTime ); } else { // Otherwise reset hydration state in case we aborted and resumed another // root. resetHydrationState(); - reconcileChildren(current, workInProgress, element); + reconcileChildren(current, workInProgress, nextChildren); } - memoizeState(workInProgress, state); return workInProgress.child; } resetHydrationState(); @@ -8346,21 +8434,13 @@ var ReactFiberBeginWork = function( workInProgress.memoizedState = value.state !== null && value.state !== undefined ? value.state : null; - if (typeof Component.getDerivedStateFromProps === "function") { - var partialState = callGetDerivedStateFromProps( + var getDerivedStateFromProps = Component.getDerivedStateFromProps; + if (typeof getDerivedStateFromProps === "function") { + applyDerivedStateFromProps( workInProgress, - value, - props, - workInProgress.memoizedState + getDerivedStateFromProps, + props ); - - if (partialState !== null && partialState !== undefined) { - workInProgress.memoizedState = Object.assign( - {}, - workInProgress.memoizedState, - partialState - ); - } } // Push context providers early to prevent context stack mismatches. @@ -8374,7 +8454,6 @@ var ReactFiberBeginWork = function( workInProgress, true, hasContext, - false, renderExpirationTime ); } else { @@ -8520,7 +8599,7 @@ var ReactFiberBeginWork = function( var fiber = workInProgress.child; if (fiber !== null) { // Set the return pointer of the child to the work-in-progress fiber. - fiber["return"] = workInProgress; + fiber.return = workInProgress; } while (fiber !== null) { var nextFiber = void 0; @@ -8558,7 +8637,7 @@ var ReactFiberBeginWork = function( // ancestor path already has sufficient priority. break; } - node = node["return"]; + node = node.return; } // Don't scan deeper than a matching consumer. When we render the // consumer, we'll continue scanning from that point. This way the @@ -8580,7 +8659,7 @@ var ReactFiberBeginWork = function( } if (nextFiber !== null) { // Set the return pointer of the child to the work-in-progress fiber. - nextFiber["return"] = fiber; + nextFiber.return = fiber; } else { // No child. Traverse to next sibling. nextFiber = fiber; @@ -8592,11 +8671,13 @@ var ReactFiberBeginWork = function( } 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"]; + nextFiber = nextFiber.return; } } fiber = nextFiber; @@ -8613,8 +8694,10 @@ var ReactFiberBeginWork = function( var newProps = workInProgress.pendingProps; var oldProps = workInProgress.memoizedProps; + var canBailOnProps = true; if (hasLegacyContextChanged()) { + canBailOnProps = false; // Normally we can bail out on props equality but if context has changed // we don't do the bailout and we have to reuse existing props instead. } else if (oldProps === newProps) { @@ -8626,6 +8709,20 @@ var ReactFiberBeginWork = function( var newValue = newProps.value; workInProgress.memoizedProps = newProps; + { + var providerPropTypes = workInProgress.type.propTypes; + + if (providerPropTypes) { + checkPropTypes( + providerPropTypes, + newProps, + "prop", + "Context.Provider", + getCurrentFiberStackAddendum + ); + } + } + var changedBits = void 0; if (oldProps === null) { // Initial render @@ -8633,7 +8730,7 @@ var ReactFiberBeginWork = function( } else { if (oldProps.value === newProps.value) { // No change. Bailout early if children are the same. - if (oldProps.children === newProps.children) { + if (oldProps.children === newProps.children && canBailOnProps) { workInProgress.stateNode = 0; pushProvider(workInProgress); return bailoutOnAlreadyFinishedWork(current, workInProgress); @@ -8650,7 +8747,7 @@ var ReactFiberBeginWork = function( (oldValue !== oldValue && newValue !== newValue) // eslint-disable-line no-self-compare ) { // No change. Bailout early if children are the same. - if (oldProps.children === newProps.children) { + if (oldProps.children === newProps.children && canBailOnProps) { workInProgress.stateNode = 0; pushProvider(workInProgress); return bailoutOnAlreadyFinishedWork(current, workInProgress); @@ -8675,7 +8772,7 @@ var ReactFiberBeginWork = function( if (changedBits === 0) { // No change. Bailout early if children are the same. - if (oldProps.children === newProps.children) { + if (oldProps.children === newProps.children && canBailOnProps) { workInProgress.stateNode = 0; pushProvider(workInProgress); return bailoutOnAlreadyFinishedWork(current, workInProgress); @@ -8761,6 +8858,8 @@ var ReactFiberBeginWork = function( } var newChildren = render(newValue); + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; reconcileChildren(current, workInProgress, newChildren); return workInProgress.child; } @@ -8968,7 +9067,7 @@ var ReactFiberCompleteWork = function( function appendAllReturns(returns, workInProgress) { var node = workInProgress.stateNode; if (node) { - node["return"] = workInProgress; + node.return = workInProgress; } while (node !== null) { if ( @@ -8980,17 +9079,17 @@ var ReactFiberCompleteWork = function( } else if (node.tag === ReturnComponent) { returns.push(node.pendingProps.value); } else if (node.child !== null) { - node.child["return"] = node; + node.child.return = node; node = node.child; continue; } while (node.sibling === null) { - if (node["return"] === null || node["return"] === workInProgress) { + if (node.return === null || node.return === workInProgress) { return; } - node = node["return"]; + node = node.return; } - node.sibling["return"] = node["return"]; + node.sibling.return = node.return; node = node.sibling; } } @@ -9046,7 +9145,7 @@ var ReactFiberCompleteWork = function( // 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.child.return = node; node = node.child; continue; } @@ -9054,12 +9153,12 @@ var ReactFiberCompleteWork = function( return; } while (node.sibling === null) { - if (node["return"] === null || node["return"] === workInProgress) { + if (node.return === null || node.return === workInProgress) { return; } - node = node["return"]; + node = node.return; } - node.sibling["return"] = node["return"]; + node.sibling.return = node.return; node = node.sibling; } } @@ -9126,7 +9225,7 @@ var ReactFiberCompleteWork = function( // 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.child.return = node; node = node.child; continue; } @@ -9134,12 +9233,12 @@ var ReactFiberCompleteWork = function( return; } while (node.sibling === null) { - if (node["return"] === null || node["return"] === workInProgress) { + if (node.return === null || node.return === workInProgress) { return; } - node = node["return"]; + node = node.return; } - node.sibling["return"] = node["return"]; + node.sibling.return = node.return; node = node.sibling; } }; @@ -9265,20 +9364,6 @@ var ReactFiberCompleteWork = function( case ClassComponent: { // We are leaving this subtree, so pop context if any. popLegacyContextProvider(workInProgress); - - // If this component caught an error, schedule an error log effect. - var instance = workInProgress.stateNode; - var updateQueue = workInProgress.updateQueue; - if (updateQueue !== null && updateQueue.capturedValues !== null) { - workInProgress.effectTag &= ~DidCapture; - if (typeof instance.componentDidCatch === "function") { - workInProgress.effectTag |= ErrLog; - } else { - // Normally we clear this in the commit phase, but since we did not - // schedule an effect, we need to reset it here. - updateQueue.capturedValues = null; - } - } return null; } case HostRoot: { @@ -9298,11 +9383,6 @@ var ReactFiberCompleteWork = function( workInProgress.effectTag &= ~Placement; } updateHostContainer(workInProgress); - - var _updateQueue = workInProgress.updateQueue; - if (_updateQueue !== null && _updateQueue.capturedValues !== null) { - workInProgress.effectTag |= ErrLog; - } return null; } case HostComponent: { @@ -9317,13 +9397,13 @@ var ReactFiberCompleteWork = function( // 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 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, + instance, type, oldProps, newProps, @@ -9377,7 +9457,7 @@ var ReactFiberCompleteWork = function( markUpdate(workInProgress); } } else { - var _instance2 = createInstance( + var _instance = createInstance( type, newProps, rootContainerInstance, @@ -9385,14 +9465,14 @@ var ReactFiberCompleteWork = function( workInProgress ); - appendAllChildren(_instance2, workInProgress); + appendAllChildren(_instance, workInProgress); // 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( - _instance2, + _instance, type, newProps, rootContainerInstance, @@ -9401,7 +9481,7 @@ var ReactFiberCompleteWork = function( ) { markUpdate(workInProgress); } - workInProgress.stateNode = _instance2; + workInProgress.stateNode = _instance; } if (workInProgress.ref !== null) { @@ -9508,139 +9588,6 @@ function createCapturedValue(value, source) { }; } -var ReactFiberUnwindWork = function( - hostContext, - legacyContext, - newContext, - scheduleWork, - isAlreadyFailedLegacyErrorBoundary -) { - var popHostContainer = hostContext.popHostContainer, - popHostContext = hostContext.popHostContext; - var popLegacyContextProvider = legacyContext.popContextProvider, - popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject; - var popProvider = newContext.popProvider; - - function throwException(returnFiber, sourceFiber, rawValue) { - // The source fiber did not complete. - sourceFiber.effectTag |= Incomplete; - // Its effect list is no longer valid. - sourceFiber.firstEffect = sourceFiber.lastEffect = null; - - var value = createCapturedValue(rawValue, sourceFiber); - - var workInProgress = returnFiber; - do { - switch (workInProgress.tag) { - case HostRoot: { - // Uncaught error - var errorInfo = value; - ensureUpdateQueues(workInProgress); - var updateQueue = workInProgress.updateQueue; - updateQueue.capturedValues = [errorInfo]; - workInProgress.effectTag |= ShouldCapture; - return; - } - case ClassComponent: - // Capture and retry - var ctor = workInProgress.type; - var _instance = workInProgress.stateNode; - if ( - (workInProgress.effectTag & DidCapture) === NoEffect && - ((typeof ctor.getDerivedStateFromCatch === "function" && - enableGetDerivedStateFromCatch) || - (_instance !== null && - typeof _instance.componentDidCatch === "function" && - !isAlreadyFailedLegacyErrorBoundary(_instance))) - ) { - ensureUpdateQueues(workInProgress); - var _updateQueue = workInProgress.updateQueue; - var capturedValues = _updateQueue.capturedValues; - if (capturedValues === null) { - _updateQueue.capturedValues = [value]; - } else { - capturedValues.push(value); - } - workInProgress.effectTag |= ShouldCapture; - return; - } - break; - default: - break; - } - workInProgress = workInProgress["return"]; - } while (workInProgress !== null); - } - - function unwindWork(workInProgress) { - switch (workInProgress.tag) { - case ClassComponent: { - popLegacyContextProvider(workInProgress); - var effectTag = workInProgress.effectTag; - if (effectTag & ShouldCapture) { - workInProgress.effectTag = (effectTag & ~ShouldCapture) | DidCapture; - return workInProgress; - } - return null; - } - case HostRoot: { - popHostContainer(workInProgress); - popTopLevelLegacyContextObject(workInProgress); - var _effectTag = workInProgress.effectTag; - if (_effectTag & ShouldCapture) { - workInProgress.effectTag = (_effectTag & ~ShouldCapture) | DidCapture; - return workInProgress; - } - return null; - } - case HostComponent: { - popHostContext(workInProgress); - return null; - } - case HostPortal: - popHostContainer(workInProgress); - return null; - case ContextProvider: - popProvider(workInProgress); - return null; - default: - return null; - } - } - - function unwindInterruptedWork(interruptedWork) { - switch (interruptedWork.tag) { - case ClassComponent: { - popLegacyContextProvider(interruptedWork); - break; - } - case HostRoot: { - popHostContainer(interruptedWork); - popTopLevelLegacyContextObject(interruptedWork); - break; - } - case HostComponent: { - popHostContext(interruptedWork); - break; - } - case HostPortal: - popHostContainer(interruptedWork); - break; - case ContextProvider: - popProvider(interruptedWork); - break; - default: - break; - } - } - - return { - throwException: throwException, - unwindWork: unwindWork, - unwindInterruptedWork: unwindInterruptedWork - }; -}; - // This module is forked in different environments. // By default, return `true` to log errors to the console. // Forks can return `false` if this isn't desirable. @@ -9892,7 +9839,14 @@ var ReactFiberCommitWork = function( } var updateQueue = finishedWork.updateQueue; if (updateQueue !== null) { - commitCallbacks(updateQueue, _instance2); + _instance2.props = finishedWork.memoizedProps; + _instance2.state = finishedWork.memoizedState; + commitUpdateQueue( + finishedWork, + updateQueue, + _instance2, + committedExpirationTime + ); } return; } @@ -9910,7 +9864,12 @@ var ReactFiberCommitWork = function( break; } } - commitCallbacks(_updateQueue, _instance3); + commitUpdateQueue( + finishedWork, + _updateQueue, + _instance3, + committedExpirationTime + ); } return; } @@ -9947,81 +9906,17 @@ var ReactFiberCommitWork = function( } } - function commitErrorLogging(finishedWork, onUncaughtError) { - switch (finishedWork.tag) { - case ClassComponent: - { - var ctor = finishedWork.type; - var _instance5 = finishedWork.stateNode; - var updateQueue = finishedWork.updateQueue; - invariant( - updateQueue !== null && updateQueue.capturedValues !== null, - "An error logging effect should not have been scheduled if no errors " + - "were captured. This error is likely caused by a bug in React. " + - "Please file an issue." - ); - var capturedErrors = updateQueue.capturedValues; - updateQueue.capturedValues = null; - - if (typeof ctor.getDerivedStateFromCatch !== "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 getDerivedStateFromCatch is - // not defined. - markLegacyErrorBoundaryAsFailed(_instance5); - } - - _instance5.props = finishedWork.memoizedProps; - _instance5.state = finishedWork.memoizedState; - for (var i = 0; i < capturedErrors.length; i++) { - var errorInfo = capturedErrors[i]; - var _error = errorInfo.value; - var stack = errorInfo.stack; - logError(finishedWork, errorInfo); - _instance5.componentDidCatch(_error, { - componentStack: stack !== null ? stack : "" - }); - } - } - break; - case HostRoot: { - var _updateQueue2 = finishedWork.updateQueue; - invariant( - _updateQueue2 !== null && _updateQueue2.capturedValues !== null, - "An error logging effect should not have been scheduled if no errors " + - "were captured. This error is likely caused by a bug in React. " + - "Please file an issue." - ); - var _capturedErrors = _updateQueue2.capturedValues; - _updateQueue2.capturedValues = null; - for (var _i = 0; _i < _capturedErrors.length; _i++) { - var _errorInfo = _capturedErrors[_i]; - logError(finishedWork, _errorInfo); - onUncaughtError(_errorInfo.value); - } - break; - } - default: - invariant( - false, - "This unit of work tag cannot capture errors. This error is " + - "likely caused by a bug in React. Please file an issue." - ); - } - } - function commitAttachRef(finishedWork) { var ref = finishedWork.ref; if (ref !== null) { - var _instance6 = finishedWork.stateNode; + var _instance5 = finishedWork.stateNode; var instanceToUse = void 0; switch (finishedWork.tag) { case HostComponent: - instanceToUse = getPublicInstance(_instance6); + instanceToUse = getPublicInstance(_instance5); break; default: - instanceToUse = _instance6; + instanceToUse = _instance5; } if (typeof ref === "function") { ref(instanceToUse); @@ -10065,9 +9960,9 @@ var ReactFiberCommitWork = function( switch (current.tag) { case ClassComponent: { safelyDetachRef(current); - var _instance7 = current.stateNode; - if (typeof _instance7.componentWillUnmount === "function") { - safelyCallComponentWillUnmount(current, _instance7); + var _instance6 = current.stateNode; + if (typeof _instance6.componentWillUnmount === "function") { + safelyCallComponentWillUnmount(current, _instance6); } return; } @@ -10109,7 +10004,7 @@ var ReactFiberCommitWork = function( // If we don't use mutation we drill down into portals here instead. (!mutation || node.tag !== HostPortal) ) { - node.child["return"] = node; + node.child.return = node; node = node.child; continue; } @@ -10117,12 +10012,12 @@ var ReactFiberCommitWork = function( return; } while (node.sibling === null) { - if (node["return"] === null || node["return"] === root) { + if (node.return === null || node.return === root) { return; } - node = node["return"]; + node = node.return; } - node.sibling["return"] = node["return"]; + node.sibling.return = node.return; node = node.sibling; } } @@ -10133,11 +10028,11 @@ var ReactFiberCommitWork = function( // 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["return"] = null; + current.return = null; current.child = null; if (current.alternate) { current.alternate.child = null; - current.alternate["return"] = null; + current.alternate.return = null; } } @@ -10205,7 +10100,6 @@ var ReactFiberCommitWork = function( commitLifeCycles: commitLifeCycles, commitBeforeMutationLifeCycles: commitBeforeMutationLifeCycles, - commitErrorLogging: commitErrorLogging, commitAttachRef: commitAttachRef, commitDetachRef: commitDetachRef }; @@ -10227,12 +10121,12 @@ var ReactFiberCommitWork = function( removeChildFromContainer = mutation.removeChildFromContainer; function getHostParentFiber(fiber) { - var parent = fiber["return"]; + var parent = fiber.return; while (parent !== null) { if (isHostParent(parent)) { return parent; } - parent = parent["return"]; + parent = parent.return; } invariant( false, @@ -10257,14 +10151,14 @@ var ReactFiberCommitWork = function( 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 (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 = node.return; } - node.sibling["return"] = node["return"]; + node.sibling.return = node.return; node = node.sibling; while (node.tag !== HostComponent && node.tag !== HostText) { // If it is not host node and, we might have a host node inside it. @@ -10278,7 +10172,7 @@ var ReactFiberCommitWork = function( if (node.child === null || node.tag === HostPortal) { continue siblings; } else { - node.child["return"] = node; + node.child.return = node; node = node.child; } } @@ -10346,7 +10240,7 @@ var ReactFiberCommitWork = function( // 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.child.return = node; node = node.child; continue; } @@ -10354,12 +10248,12 @@ var ReactFiberCommitWork = function( return; } while (node.sibling === null) { - if (node["return"] === null || node["return"] === finishedWork) { + if (node.return === null || node.return === finishedWork) { return; } - node = node["return"]; + node = node.return; } - node.sibling["return"] = node["return"]; + node.sibling.return = node.return; node = node.sibling; } } @@ -10376,7 +10270,7 @@ var ReactFiberCommitWork = function( while (true) { if (!currentParentIsValid) { - var parent = node["return"]; + var parent = node.return; findParent: while (true) { invariant( parent !== null, @@ -10397,7 +10291,7 @@ var ReactFiberCommitWork = function( currentParentIsContainer = true; break findParent; } - parent = parent["return"]; + parent = parent.return; } currentParentIsValid = true; } @@ -10418,7 +10312,7 @@ var ReactFiberCommitWork = function( currentParent = node.stateNode.containerInfo; // Visit children because portals might contain host components. if (node.child !== null) { - node.child["return"] = node; + node.child.return = node; node = node.child; continue; } @@ -10426,7 +10320,7 @@ var ReactFiberCommitWork = function( commitUnmount(node); // Visit children because we may find more host components below. if (node.child !== null) { - node.child["return"] = node; + node.child.return = node; node = node.child; continue; } @@ -10435,17 +10329,17 @@ var ReactFiberCommitWork = function( return; } while (node.sibling === null) { - if (node["return"] === null || node["return"] === current) { + if (node.return === null || node.return === current) { return; } - node = node["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.sibling.return = node.return; node = node.sibling; } } @@ -10463,8 +10357,8 @@ var ReactFiberCommitWork = function( return; } case HostComponent: { - var _instance8 = finishedWork.stateNode; - if (_instance8 != null) { + var _instance7 = finishedWork.stateNode; + if (_instance7 != null) { // Commit the work prepared earlier. var newProps = finishedWork.memoizedProps; // For hydration we reuse the update path but we treat the oldProps @@ -10477,7 +10371,7 @@ var ReactFiberCommitWork = function( finishedWork.updateQueue = null; if (updatePayload !== null) { commitUpdate( - _instance8, + _instance7, updatePayload, type, oldProps, @@ -10528,7 +10422,6 @@ var ReactFiberCommitWork = function( commitDeletion: commitDeletion, commitWork: commitWork, commitLifeCycles: commitLifeCycles, - commitErrorLogging: commitErrorLogging, commitAttachRef: commitAttachRef, commitDetachRef: commitDetachRef }; @@ -10537,6 +10430,208 @@ var ReactFiberCommitWork = function( } }; +var ReactFiberUnwindWork = function( + hostContext, + legacyContext, + newContext, + scheduleWork, + markLegacyErrorBoundaryAsFailed, + isAlreadyFailedLegacyErrorBoundary, + onUncaughtError +) { + var popHostContainer = hostContext.popHostContainer, + popHostContext = hostContext.popHostContext; + var popLegacyContextProvider = legacyContext.popContextProvider, + popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject; + var popProvider = newContext.popProvider; + + 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 getDerivedStateFromCatch = fiber.type.getDerivedStateFromCatch; + if ( + enableGetDerivedStateFromCatch && + typeof getDerivedStateFromCatch === "function" + ) { + var _error = errorInfo.value; + update.payload = function() { + return getDerivedStateFromCatch(_error); + }; + } + + var inst = fiber.stateNode; + if (inst !== null && typeof inst.componentDidCatch === "function") { + update.callback = function callback() { + if ( + !enableGetDerivedStateFromCatch || + getDerivedStateFromCatch !== "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 getDerivedStateFromCatch is + // not defined. + markLegacyErrorBoundaryAsFailed(this); + } + var error = errorInfo.value; + var stack = errorInfo.stack; + logError(fiber, errorInfo); + this.componentDidCatch(error, { + componentStack: stack !== null ? stack : "" + }); + }; + } + return update; + } + + function throwException( + returnFiber, + sourceFiber, + rawValue, + renderExpirationTime + ) { + // The source fiber did not complete. + sourceFiber.effectTag |= Incomplete; + // Its effect list is no longer valid. + sourceFiber.firstEffect = sourceFiber.lastEffect = null; + + var value = createCapturedValue(rawValue, sourceFiber); + + var workInProgress = returnFiber; + do { + switch (workInProgress.tag) { + case HostRoot: { + var _errorInfo = value; + workInProgress.effectTag |= ShouldCapture; + var update = createRootErrorUpdate( + workInProgress, + _errorInfo, + renderExpirationTime + ); + enqueueCapturedUpdate(workInProgress, update, renderExpirationTime); + return; + } + case ClassComponent: + // Capture and retry + var errorInfo = value; + var ctor = workInProgress.type; + var _instance = workInProgress.stateNode; + if ( + (workInProgress.effectTag & DidCapture) === NoEffect && + ((typeof ctor.getDerivedStateFromCatch === "function" && + enableGetDerivedStateFromCatch) || + (_instance !== null && + typeof _instance.componentDidCatch === "function" && + !isAlreadyFailedLegacyErrorBoundary(_instance))) + ) { + workInProgress.effectTag |= ShouldCapture; + // Schedule the error boundary to re-render using updated state + var _update = createClassErrorUpdate( + workInProgress, + errorInfo, + renderExpirationTime + ); + enqueueCapturedUpdate( + workInProgress, + _update, + renderExpirationTime + ); + return; + } + break; + default: + break; + } + workInProgress = workInProgress.return; + } while (workInProgress !== null); + } + + function unwindWork(workInProgress) { + switch (workInProgress.tag) { + case ClassComponent: { + popLegacyContextProvider(workInProgress); + var effectTag = workInProgress.effectTag; + if (effectTag & ShouldCapture) { + workInProgress.effectTag = (effectTag & ~ShouldCapture) | DidCapture; + return workInProgress; + } + return null; + } + case HostRoot: { + popHostContainer(workInProgress); + popTopLevelLegacyContextObject(workInProgress); + var _effectTag = workInProgress.effectTag; + if (_effectTag & ShouldCapture) { + workInProgress.effectTag = (_effectTag & ~ShouldCapture) | DidCapture; + return workInProgress; + } + return null; + } + case HostComponent: { + popHostContext(workInProgress); + return null; + } + case HostPortal: + popHostContainer(workInProgress); + return null; + case ContextProvider: + popProvider(workInProgress); + return null; + default: + return null; + } + } + + function unwindInterruptedWork(interruptedWork) { + switch (interruptedWork.tag) { + case ClassComponent: { + popLegacyContextProvider(interruptedWork); + break; + } + case HostRoot: { + popHostContainer(interruptedWork); + popTopLevelLegacyContextObject(interruptedWork); + break; + } + case HostComponent: { + popHostContext(interruptedWork); + break; + } + case HostPortal: + popHostContainer(interruptedWork); + break; + case ContextProvider: + popProvider(interruptedWork); + break; + default: + break; + } + } + + return { + throwException: throwException, + unwindWork: unwindWork, + unwindInterruptedWork: unwindInterruptedWork, + createRootErrorUpdate: createRootErrorUpdate, + createClassErrorUpdate: createClassErrorUpdate + }; +}; + var NO_CONTEXT = {}; var ReactFiberHostContext = function(config, stack) { @@ -10721,7 +10816,7 @@ var ReactFiberHydrationContext = function(config) { var childToDelete = createFiberFromHostInstanceForDeletion(); childToDelete.stateNode = instance; - childToDelete["return"] = returnFiber; + childToDelete.return = returnFiber; childToDelete.effectTag = Deletion; // This might seem like it belongs on progressedFirstDeletion. However, @@ -10919,13 +11014,13 @@ var ReactFiberHydrationContext = function(config) { } function popToNextHostParent(fiber) { - var parent = fiber["return"]; + var parent = fiber.return; while ( parent !== null && parent.tag !== HostComponent && parent.tag !== HostRoot ) { - parent = parent["return"]; + parent = parent.return; } hydrationParentFiber = parent; } @@ -11247,7 +11342,7 @@ var ReactFiberLegacyContext = function(stack) { if (isContextProvider(node)) { return node.stateNode.__reactInternalMemoizedMergedChildContext; } - var parent = node["return"]; + var parent = node.return; invariant( parent, "Found unexpected detached subtree parent. " + @@ -11520,11 +11615,15 @@ var ReactFiberScheduler = function(config) { legacyContext, newContext, scheduleWork, - isAlreadyFailedLegacyErrorBoundary + markLegacyErrorBoundaryAsFailed, + isAlreadyFailedLegacyErrorBoundary, + onUncaughtError ), throwException = _ReactFiberUnwindWork.throwException, unwindWork = _ReactFiberUnwindWork.unwindWork, - unwindInterruptedWork = _ReactFiberUnwindWork.unwindInterruptedWork; + unwindInterruptedWork = _ReactFiberUnwindWork.unwindInterruptedWork, + createRootErrorUpdate = _ReactFiberUnwindWork.createRootErrorUpdate, + createClassErrorUpdate = _ReactFiberUnwindWork.createClassErrorUpdate; var _ReactFiberCommitWork = ReactFiberCommitWork( config, @@ -11541,7 +11640,6 @@ var ReactFiberScheduler = function(config) { commitDeletion = _ReactFiberCommitWork.commitDeletion, commitWork = _ReactFiberCommitWork.commitWork, commitLifeCycles = _ReactFiberCommitWork.commitLifeCycles, - commitErrorLogging = _ReactFiberCommitWork.commitErrorLogging, commitAttachRef = _ReactFiberCommitWork.commitAttachRef, commitDetachRef = _ReactFiberCommitWork.commitDetachRef; @@ -11639,10 +11737,10 @@ var ReactFiberScheduler = function(config) { function resetStack() { if (nextUnitOfWork !== null) { - var interruptedWork = nextUnitOfWork["return"]; + var interruptedWork = nextUnitOfWork.return; while (interruptedWork !== null) { unwindInterruptedWork(interruptedWork); - interruptedWork = interruptedWork["return"]; + interruptedWork = interruptedWork.return; } } @@ -11767,10 +11865,6 @@ var ReactFiberScheduler = function(config) { ); } - if (effectTag & ErrLog) { - commitErrorLogging(nextEffect, onUncaughtError); - } - if (effectTag & Ref) { recordEffect(); commitAttachRef(nextEffect); @@ -11977,7 +12071,16 @@ var ReactFiberScheduler = function(config) { } // Check for pending updates. - var newExpirationTime = getUpdateExpirationTime(workInProgress); + var newExpirationTime = NoWork; + switch (workInProgress.tag) { + case HostRoot: + case ClassComponent: { + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + newExpirationTime = updateQueue.expirationTime; + } + } + } // TODO: Calls need to visit stateNode @@ -12010,7 +12113,7 @@ var ReactFiberScheduler = function(config) { ReactDebugCurrentFiber.setCurrentFiber(workInProgress); } - var returnFiber = workInProgress["return"]; + var returnFiber = workInProgress.return; var siblingFiber = workInProgress.sibling; if ((workInProgress.effectTag & Incomplete) === NoEffect) { @@ -12252,13 +12355,19 @@ var ReactFiberScheduler = function(config) { break; } + { + // Reset global debug state + // We assume this is defined in DEV + resetCurrentlyProcessingQueue(); + } + if (true && replayFailedUnitOfWorkWithInvokeGuardedCallback) { var failedUnitOfWork = nextUnitOfWork; replayUnitOfWork(failedUnitOfWork, thrownValue, isAsync); } var sourceFiber = nextUnitOfWork; - var returnFiber = sourceFiber["return"]; + var returnFiber = sourceFiber.return; if (returnFiber === null) { // This is the root. The root could capture its own errors. However, // we don't know if it errors before or after we pushed the host @@ -12270,7 +12379,12 @@ var ReactFiberScheduler = function(config) { onUncaughtError(thrownValue); break; } - throwException(returnFiber, sourceFiber, thrownValue); + throwException( + returnFiber, + sourceFiber, + thrownValue, + nextRenderExpirationTime + ); nextUnitOfWork = completeUnitOfWork(sourceFiber); } break; @@ -12318,31 +12432,13 @@ var ReactFiberScheduler = function(config) { } } - function scheduleCapture(sourceFiber, boundaryFiber, value, expirationTime) { - // TODO: We only support dispatching errors. - var capturedValue = createCapturedValue(value, sourceFiber); - var update = { - expirationTime: expirationTime, - partialState: null, - callback: null, - isReplace: false, - isForced: false, - capturedValue: capturedValue, - next: null - }; - insertUpdateIntoFiber(boundaryFiber, update); - scheduleWork(boundaryFiber, expirationTime); - } - function dispatch(sourceFiber, value, expirationTime) { invariant( !isWorking || isCommitting, "dispatch: Cannot dispatch during the render phase." ); - // TODO: Handle arrays - - var fiber = sourceFiber["return"]; + var fiber = sourceFiber.return; while (fiber !== null) { switch (fiber.tag) { case ClassComponent: @@ -12353,22 +12449,44 @@ var ReactFiberScheduler = function(config) { (typeof instance.componentDidCatch === "function" && !isAlreadyFailedLegacyErrorBoundary(instance)) ) { - scheduleCapture(sourceFiber, fiber, value, expirationTime); + var errorInfo = createCapturedValue(value, sourceFiber); + var update = createClassErrorUpdate( + fiber, + errorInfo, + expirationTime + ); + enqueueUpdate(fiber, update, expirationTime); + scheduleWork(fiber, expirationTime); return; } break; - // TODO: Handle async boundaries - case HostRoot: - scheduleCapture(sourceFiber, fiber, value, expirationTime); + case HostRoot: { + var _errorInfo = createCapturedValue(value, sourceFiber); + var _update = createRootErrorUpdate( + fiber, + _errorInfo, + expirationTime + ); + enqueueUpdate(fiber, _update, expirationTime); + scheduleWork(fiber, expirationTime); return; + } } - fiber = fiber["return"]; + fiber = fiber.return; } if (sourceFiber.tag === HostRoot) { // Error was thrown at the root. There is no parent, so the root // itself should capture it. - scheduleCapture(sourceFiber, sourceFiber, value, expirationTime); + var rootFiber = sourceFiber; + var _errorInfo2 = createCapturedValue(value, rootFiber); + var _update2 = createRootErrorUpdate( + rootFiber, + _errorInfo2, + expirationTime + ); + enqueueUpdate(rootFiber, _update2, expirationTime); + scheduleWork(rootFiber, expirationTime); } } @@ -12496,7 +12614,7 @@ var ReactFiberScheduler = function(config) { node.alternate.expirationTime = expirationTime; } } - if (node["return"] === null) { + if (node.return === null) { if (node.tag === HostRoot) { var root = node.stateNode; if ( @@ -12537,7 +12655,7 @@ var ReactFiberScheduler = function(config) { return; } } - node = node["return"]; + node = node.return; } } @@ -13166,9 +13284,14 @@ var ReactFiberReconciler$1 = function(config) { } } + var update = createUpdate(expirationTime); + // Caution: React DevTools currently depends on this property + // being called "element". + update.payload = { element: element }; + callback = callback === undefined ? null : callback; - { - !(callback === null || typeof callback === "function") + if (callback !== null) { + !(typeof callback === "function") ? warning( false, "render(...): Expected the last optional `callback` argument to be a " + @@ -13176,20 +13299,11 @@ var ReactFiberReconciler$1 = function(config) { callback ) : void 0; + update.callback = callback; } + enqueueUpdate(current, update, expirationTime); - var update = { - expirationTime: expirationTime, - partialState: { element: element }, - callback: callback, - isReplace: false, - isForced: false, - capturedValue: null, - next: null - }; - insertUpdateIntoFiber(current, update); scheduleWork(current, expirationTime); - return expirationTime; } @@ -13367,8 +13481,8 @@ var ReactFiberReconciler$3 = // TODO: decide on the top-level export form. // This is hacky but makes it work with both Rollup and Jest. -var reactReconciler = ReactFiberReconciler$3["default"] - ? ReactFiberReconciler$3["default"] +var reactReconciler = ReactFiberReconciler$3.default + ? ReactFiberReconciler$3.default : ReactFiberReconciler$3; function _classCallCheck$1(instance, Constructor) { @@ -13795,7 +13909,7 @@ var ReactFabric = { if (root) { // TODO: Is it safe to reset this now or should I wait since this unmount could be deferred? ReactFabricRenderer.updateContainer(null, root, null, function() { - roots["delete"](containerTag); + roots.delete(containerTag); }); } }, @@ -13852,9 +13966,7 @@ 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["default"] - : ReactFabric$3; +var fabric = ReactFabric$3.default ? ReactFabric$3.default : ReactFabric$3; module.exports = fabric; diff --git a/Libraries/Renderer/oss/ReactFabric-prod.js b/Libraries/Renderer/oss/ReactFabric-prod.js index 19ca0dde9e33cf..32b02cc8387586 100644 --- a/Libraries/Renderer/oss/ReactFabric-prod.js +++ b/Libraries/Renderer/oss/ReactFabric-prod.js @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. * * @noflow + * @providesModule ReactFabric-prod * @preventMunge */ @@ -210,7 +211,7 @@ function getListener(inst, registrationName) { return listener; } function getParent(inst) { - do inst = inst["return"]; + do inst = inst.return; while (inst && 5 !== inst.tag); return inst ? inst : null; } @@ -917,21 +918,17 @@ injection.injectEventPluginsByName({ ResponderEventPlugin: ResponderEventPlugin, ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin }); -var hasSymbol = "function" === typeof Symbol && Symbol["for"], - REACT_ELEMENT_TYPE = hasSymbol ? Symbol["for"]("react.element") : 60103, - REACT_CALL_TYPE = hasSymbol ? Symbol["for"]("react.call") : 60104, - REACT_RETURN_TYPE = hasSymbol ? Symbol["for"]("react.return") : 60105, - 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_PROVIDER_TYPE = hasSymbol ? Symbol["for"]("react.provider") : 60109, - REACT_CONTEXT_TYPE = hasSymbol ? Symbol["for"]("react.context") : 60110, - REACT_ASYNC_MODE_TYPE = hasSymbol ? Symbol["for"]("react.async_mode") : 60111, - REACT_FORWARD_REF_TYPE = hasSymbol - ? Symbol["for"]("react.forward_ref") - : 60112, +var hasSymbol = "function" === typeof Symbol && Symbol.for, + REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for("react.element") : 60103, + REACT_CALL_TYPE = hasSymbol ? Symbol.for("react.call") : 60104, + REACT_RETURN_TYPE = hasSymbol ? Symbol.for("react.return") : 60105, + 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_PROVIDER_TYPE = hasSymbol ? Symbol.for("react.provider") : 60109, + REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for("react.context") : 60110, + REACT_ASYNC_MODE_TYPE = hasSymbol ? Symbol.for("react.async_mode") : 60111, + REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for("react.forward_ref") : 60112, MAYBE_ITERATOR_SYMBOL = "function" === typeof Symbol && Symbol.iterator; function getIteratorFn(maybeIterable) { if (null === maybeIterable || "undefined" === typeof maybeIterable) @@ -1253,11 +1250,11 @@ function getComponentName(fiber) { } function isFiberMountedImpl(fiber) { var node = fiber; - if (fiber.alternate) for (; node["return"]; ) node = node["return"]; + 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; + for (; node.return; ) + if (((node = node.return), 0 !== (node.effectTag & 2))) return 1; } return 3 === node.tag ? 2 : 3; } @@ -1284,7 +1281,7 @@ function findCurrentFiberUsingSlowPath(fiber) { 1 === alternate ? null : fiber ); for (var a = fiber, b = alternate; ; ) { - var parentA = a["return"], + var parentA = a.return, parentB = parentA ? parentA.alternate : null; if (!parentA || !parentB) break; if (parentA.child === parentB.child) { @@ -1295,7 +1292,7 @@ function findCurrentFiberUsingSlowPath(fiber) { } invariant(!1, "Unable to find node on an unmounted component."); } - if (a["return"] !== b["return"]) (a = parentA), (b = parentB); + if (a.return !== b.return) (a = parentA), (b = parentB); else { child = !1; for (var _child = parentA.child; _child; ) { @@ -1348,14 +1345,14 @@ function findCurrentHostFiber(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); + 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"]; + if (!node.return || node.return === parent) return null; + node = node.return; } - node.sibling["return"] = node["return"]; + node.sibling.return = node.return; node = node.sibling; } } @@ -1367,14 +1364,14 @@ function findCurrentHostFiberWithNoPortals(parent) { for (var node = parent; ; ) { if (5 === node.tag || 6 === node.tag) return node; if (node.child && 4 !== node.tag) - (node.child["return"] = node), (node = 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"]; + if (!node.return || node.return === parent) return null; + node = node.return; } - node.sibling["return"] = node["return"]; + node.sibling.return = node.return; node = node.sibling; } } @@ -1383,8 +1380,7 @@ function findCurrentHostFiberWithNoPortals(parent) { function FiberNode(tag, pendingProps, key, mode) { this.tag = tag; this.key = key; - this.stateNode = this.type = null; - this.sibling = this.child = this["return"] = null; + this.sibling = this.child = this.return = this.stateNode = this.type = null; this.index = 0; this.ref = null; this.pendingProps = pendingProps; @@ -1575,171 +1571,289 @@ function getStackAddendumByWorkInProgressFiber(workInProgress) { JSCompiler_inline_result = ""; } info += JSCompiler_inline_result; - workInProgress = workInProgress["return"]; + workInProgress = workInProgress.return; } while (workInProgress); return info; } new Set(); function createUpdateQueue(baseState) { return { - baseState: baseState, expirationTime: 0, - first: null, - last: null, - callbackList: null, + baseState: baseState, + firstUpdate: null, + lastUpdate: null, + firstCapturedUpdate: null, + lastCapturedUpdate: null, + firstEffect: null, + lastEffect: null, + firstCapturedEffect: null, + lastCapturedEffect: null, + hasForceUpdate: !1 + }; +} +function cloneUpdateQueue(currentQueue) { + return { + expirationTime: currentQueue.expirationTime, + baseState: currentQueue.baseState, + firstUpdate: currentQueue.firstUpdate, + lastUpdate: currentQueue.lastUpdate, + firstCapturedUpdate: null, + lastCapturedUpdate: null, hasForceUpdate: !1, - isInitialized: !1, - capturedValues: 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 insertUpdateIntoQueue(queue, update) { - null === queue.last - ? (queue.first = queue.last = update) - : ((queue.last.next = update), (queue.last = update)); +function appendUpdateToQueue(queue, update, expirationTime) { + null === queue.lastUpdate + ? (queue.firstUpdate = queue.lastUpdate = update) + : ((queue.lastUpdate.next = update), (queue.lastUpdate = update)); + if (0 === queue.expirationTime || queue.expirationTime > expirationTime) + queue.expirationTime = expirationTime; +} +function enqueueUpdate(fiber, update, expirationTime) { + 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, expirationTime) + : null === queue1.lastUpdate || null === queue2.lastUpdate + ? (appendUpdateToQueue(queue1, update, expirationTime), + appendUpdateToQueue(queue2, update, expirationTime)) + : (appendUpdateToQueue(queue1, update, expirationTime), + (queue2.lastUpdate = update)); +} +function enqueueCapturedUpdate(workInProgress, update, renderExpirationTime) { + 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)); if ( - 0 === queue.expirationTime || - queue.expirationTime > update.expirationTime + 0 === workInProgressQueue.expirationTime || + workInProgressQueue.expirationTime > renderExpirationTime ) - queue.expirationTime = update.expirationTime; -} -var q1 = void 0, - q2 = void 0; -function ensureUpdateQueues(fiber) { - q1 = q2 = null; - var alternateFiber = fiber.alternate, - queue1 = fiber.updateQueue; - null === queue1 && (queue1 = fiber.updateQueue = createUpdateQueue(null)); - null !== alternateFiber - ? ((fiber = alternateFiber.updateQueue), - null === fiber && - (fiber = alternateFiber.updateQueue = createUpdateQueue(null))) - : (fiber = null); - q1 = queue1; - q2 = fiber !== queue1 ? fiber : null; + workInProgressQueue.expirationTime = renderExpirationTime; } -function insertUpdateIntoFiber(fiber, update) { - ensureUpdateQueues(fiber); - fiber = q1; - var queue2 = q2; - null === queue2 - ? insertUpdateIntoQueue(fiber, update) - : null === fiber.last || null === queue2.last - ? (insertUpdateIntoQueue(fiber, update), - insertUpdateIntoQueue(queue2, update)) - : (insertUpdateIntoQueue(fiber, update), (queue2.last = update)); +function ensureWorkInProgressQueueIsAClone(workInProgress, queue) { + var current = workInProgress.alternate; + null !== current && + queue === current.updateQueue && + (queue = workInProgress.updateQueue = cloneUpdateQueue(queue)); + return queue; } -function getStateFromUpdate(update, instance, prevState, props) { - update = update.partialState; - return "function" === typeof update - ? update.call(instance, prevState, props) - : update; +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 & -1025) | 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: + queue.hasForceUpdate = !0; + } + return prevState; } function processUpdateQueue( - current, workInProgress, queue, - instance, props, + instance, renderExpirationTime ) { - null !== current && - current.updateQueue === queue && - (queue = workInProgress.updateQueue = { - baseState: queue.baseState, - expirationTime: queue.expirationTime, - first: queue.first, - last: queue.last, - isInitialized: queue.isInitialized, - capturedValues: queue.capturedValues, - callbackList: null, - hasForceUpdate: !1 - }); - queue.expirationTime = 0; - queue.isInitialized - ? (current = queue.baseState) - : ((current = queue.baseState = workInProgress.memoizedState), - (queue.isInitialized = !0)); - for ( - var dontMutatePrevState = !0, update = queue.first, didSkip = !1; - null !== update; - + if ( + !(0 === queue.expirationTime || queue.expirationTime > renderExpirationTime) ) { - var updateExpirationTime = update.expirationTime; - if (updateExpirationTime > renderExpirationTime) { - var remainingExpirationTime = queue.expirationTime; - if ( - 0 === remainingExpirationTime || - remainingExpirationTime > updateExpirationTime - ) - queue.expirationTime = updateExpirationTime; - didSkip || ((didSkip = !0), (queue.baseState = current)); - } else { - didSkip || - ((queue.first = update.next), - null === queue.first && (queue.last = null)); - if (update.isReplace) - (current = getStateFromUpdate(update, instance, current, props)), - (dontMutatePrevState = !0); - else if ( - (updateExpirationTime = getStateFromUpdate( + queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue); + for ( + var newBaseState = queue.baseState, + newFirstUpdate = null, + newExpirationTime = 0, + update = queue.firstUpdate, + resultState = newBaseState; + null !== update; + + ) { + var updateExpirationTime = update.expirationTime; + if (updateExpirationTime > renderExpirationTime) { + if ( + (null === newFirstUpdate && + ((newFirstUpdate = update), (newBaseState = resultState)), + 0 === newExpirationTime || newExpirationTime > updateExpirationTime) + ) + newExpirationTime = updateExpirationTime; + } else + (resultState = getStateFromUpdate( + workInProgress, + queue, update, - instance, - current, - props - )) - ) - (current = dontMutatePrevState - ? Object.assign({}, current, updateExpirationTime) - : Object.assign(current, updateExpirationTime)), - (dontMutatePrevState = !1); - update.isForced && (queue.hasForceUpdate = !0); - null !== update.callback && - ((updateExpirationTime = queue.callbackList), - null === updateExpirationTime && - (updateExpirationTime = queue.callbackList = []), - updateExpirationTime.push(update)); - null !== update.capturedValue && - ((updateExpirationTime = queue.capturedValues), - null === updateExpirationTime - ? (queue.capturedValues = [update.capturedValue]) - : updateExpirationTime.push(update.capturedValue)); + 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; + if (_updateExpirationTime > renderExpirationTime) { + if ( + (null === updateExpirationTime && + ((updateExpirationTime = update), + null === newFirstUpdate && (newBaseState = resultState)), + 0 === newExpirationTime || newExpirationTime > _updateExpirationTime) + ) + newExpirationTime = _updateExpirationTime; + } else + (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; } - 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; + queue.expirationTime = newExpirationTime; + workInProgress.memoizedState = resultState; } - null !== queue.callbackList - ? (workInProgress.effectTag |= 32) - : null !== queue.first || - queue.hasForceUpdate || - null !== queue.capturedValues || - (workInProgress.updateQueue = null); - didSkip || (queue.baseState = current); - return current; } -function commitCallbacks(queue, context) { - var callbackList = queue.callbackList; - if (null !== callbackList) - for ( - queue.callbackList = null, queue = 0; - queue < callbackList.length; - queue++ - ) { - var update = callbackList[queue], - _callback = update.callback; - update.callback = null; - invariant( - "function" === typeof _callback, - "Invalid argument passed as callback. Expected a function. Instead received: %s", - _callback - ); - _callback.call(context); - } +function callCallback(callback, context) { + invariant( + "function" === typeof callback, + "Invalid argument passed as callback. Expected a function. Instead received: %s", + callback + ); + callback.call(context); +} +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)); + finishedWork = finishedQueue.firstEffect; + for ( + finishedQueue.firstEffect = finishedQueue.lastEffect = null; + null !== finishedWork; + + ) { + var _callback3 = finishedWork.callback; + null !== _callback3 && + ((finishedWork.callback = null), callCallback(_callback3, instance)); + finishedWork = finishedWork.nextEffect; + } + finishedWork = finishedQueue.firstCapturedEffect; + for ( + finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null; + null !== finishedWork; + + ) + (finishedQueue = finishedWork.callback), + null !== finishedQueue && + ((finishedWork.callback = null), callCallback(finishedQueue, instance)), + (finishedWork = finishedWork.nextEffect); +} +function applyDerivedStateFromProps( + workInProgress, + getDerivedStateFromProps, + nextProps +) { + var prevState = workInProgress.memoizedState; + getDerivedStateFromProps = getDerivedStateFromProps(nextProps, prevState); + prevState = + null === getDerivedStateFromProps || void 0 === getDerivedStateFromProps + ? prevState + : Object.assign({}, prevState, getDerivedStateFromProps); + workInProgress.memoizedState = prevState; + workInProgress = workInProgress.updateQueue; + null !== workInProgress && + 0 === workInProgress.expirationTime && + (workInProgress.baseState = prevState); } function ReactFiberClassComponent( legacyContext, scheduleWork, - computeExpirationForFiber, - memoizeProps, - memoizeState + computeExpirationForFiber ) { function checkShouldComponentUpdate( workInProgress, @@ -1750,9 +1864,8 @@ function ReactFiberClassComponent( newContext ) { if ( - null === oldProps || - (null !== workInProgress.updateQueue && - workInProgress.updateQueue.hasForceUpdate) + null !== workInProgress.updateQueue && + workInProgress.updateQueue.hasForceUpdate ) return !0; var instance = workInProgress.stateNode; @@ -1765,7 +1878,7 @@ function ReactFiberClassComponent( : !0; } function adoptClassInstance(workInProgress, instance) { - instance.updater = updater; + instance.updater = classComponentUpdater; workInProgress.stateNode = instance; instance._reactInternalFiber = workInProgress; } @@ -1781,78 +1894,52 @@ function ReactFiberClassComponent( "function" === typeof instance.UNSAFE_componentWillReceiveProps && instance.UNSAFE_componentWillReceiveProps(newProps, newContext); instance.state !== workInProgress && - updater.enqueueReplaceState(instance, instance.state, null); - } - function callGetDerivedStateFromProps( - workInProgress, - instance, - nextProps, - prevState - ) { - workInProgress = workInProgress.type; - if ("function" === typeof workInProgress.getDerivedStateFromProps) - return workInProgress.getDerivedStateFromProps.call( - null, - nextProps, - prevState - ); + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); } var cacheContext = legacyContext.cacheContext, getMaskedContext = legacyContext.getMaskedContext, getUnmaskedContext = legacyContext.getUnmaskedContext, isContextConsumer = legacyContext.isContextConsumer, hasContextChanged = legacyContext.hasContextChanged, - updater = { + classComponentUpdater = { isMounted: isMounted, - enqueueSetState: function(instance, partialState, callback) { - instance = instance._reactInternalFiber; - callback = void 0 === callback ? null : callback; - var expirationTime = computeExpirationForFiber(instance); - insertUpdateIntoFiber(instance, { - expirationTime: expirationTime, - partialState: partialState, - callback: callback, - isReplace: !1, - isForced: !1, - capturedValue: null, - next: null - }); - scheduleWork(instance, expirationTime); + enqueueSetState: function(inst, payload, callback) { + inst = inst._reactInternalFiber; + var expirationTime = computeExpirationForFiber(inst), + update = createUpdate(expirationTime); + update.payload = payload; + void 0 !== callback && + null !== callback && + (update.callback = callback); + enqueueUpdate(inst, update, expirationTime); + scheduleWork(inst, expirationTime); }, - enqueueReplaceState: function(instance, state, callback) { - instance = instance._reactInternalFiber; - callback = void 0 === callback ? null : callback; - var expirationTime = computeExpirationForFiber(instance); - insertUpdateIntoFiber(instance, { - expirationTime: expirationTime, - partialState: state, - callback: callback, - isReplace: !0, - isForced: !1, - capturedValue: null, - next: null - }); - scheduleWork(instance, expirationTime); + enqueueReplaceState: function(inst, payload, callback) { + inst = inst._reactInternalFiber; + var expirationTime = computeExpirationForFiber(inst), + update = createUpdate(expirationTime); + update.tag = 1; + update.payload = payload; + void 0 !== callback && + null !== callback && + (update.callback = callback); + enqueueUpdate(inst, update, expirationTime); + scheduleWork(inst, expirationTime); }, - enqueueForceUpdate: function(instance, callback) { - instance = instance._reactInternalFiber; - callback = void 0 === callback ? null : callback; - var expirationTime = computeExpirationForFiber(instance); - insertUpdateIntoFiber(instance, { - expirationTime: expirationTime, - partialState: null, - callback: callback, - isReplace: !1, - isForced: !0, - capturedValue: null, - next: null - }); - scheduleWork(instance, expirationTime); + enqueueForceUpdate: function(inst, callback) { + inst = inst._reactInternalFiber; + var expirationTime = computeExpirationForFiber(inst), + update = createUpdate(expirationTime); + update.tag = 2; + void 0 !== callback && + null !== callback && + (update.callback = callback); + enqueueUpdate(inst, update, expirationTime); + scheduleWork(inst, expirationTime); } }; return { adoptClassInstance: adoptClassInstance, - callGetDerivedStateFromProps: callGetDerivedStateFromProps, constructClassInstance: function(workInProgress, props) { var ctor = workInProgress.type, unmaskedContext = getUnmaskedContext(workInProgress), @@ -1860,25 +1947,15 @@ function ReactFiberClassComponent( context = needsContext ? getMaskedContext(workInProgress, unmaskedContext) : emptyObject; - ctor = new ctor(props, context); - var state = - null !== ctor.state && void 0 !== ctor.state ? ctor.state : null; - adoptClassInstance(workInProgress, ctor); - workInProgress.memoizedState = state; - props = callGetDerivedStateFromProps(workInProgress, ctor, props, state); - null !== props && - void 0 !== props && - (workInProgress.memoizedState = Object.assign( - {}, - workInProgress.memoizedState, - props - )); + props = new ctor(props, context); + workInProgress.memoizedState = + null !== props.state && void 0 !== props.state ? props.state : null; + adoptClassInstance(workInProgress, props); needsContext && cacheContext(workInProgress, unmaskedContext, context); - return ctor; + return props; }, mountClassInstance: function(workInProgress, renderExpirationTime) { var ctor = workInProgress.type, - current = workInProgress.alternate, instance = workInProgress.stateNode, props = workInProgress.pendingProps, unmaskedContext = getUnmaskedContext(workInProgress); @@ -1886,6 +1963,20 @@ function ReactFiberClassComponent( instance.state = workInProgress.memoizedState; instance.refs = emptyObject; instance.context = getMaskedContext(workInProgress, unmaskedContext); + unmaskedContext = workInProgress.updateQueue; + null !== unmaskedContext && + (processUpdateQueue( + workInProgress, + unmaskedContext, + props, + instance, + renderExpirationTime + ), + (instance.state = workInProgress.memoizedState)); + unmaskedContext = workInProgress.type.getDerivedStateFromProps; + "function" === typeof unmaskedContext && + (applyDerivedStateFromProps(workInProgress, unmaskedContext, props), + (instance.state = workInProgress.memoizedState)); "function" === typeof ctor.getDerivedStateFromProps || "function" === typeof instance.getSnapshotBeforeUpdate || ("function" !== typeof instance.UNSAFE_componentWillMount && @@ -1896,32 +1987,36 @@ function ReactFiberClassComponent( "function" === typeof instance.UNSAFE_componentWillMount && instance.UNSAFE_componentWillMount(), ctor !== instance.state && - updater.enqueueReplaceState(instance, instance.state, null), - (ctor = workInProgress.updateQueue), - null !== ctor && - (instance.state = processUpdateQueue( - current, - workInProgress, - ctor, + classComponentUpdater.enqueueReplaceState( instance, + instance.state, + null + ), + (unmaskedContext = workInProgress.updateQueue), + null !== unmaskedContext && + (processUpdateQueue( + workInProgress, + unmaskedContext, props, + instance, renderExpirationTime - ))); + ), + (instance.state = workInProgress.memoizedState))); "function" === typeof instance.componentDidMount && (workInProgress.effectTag |= 4); }, resumeMountClassInstance: function(workInProgress, renderExpirationTime) { var ctor = workInProgress.type, - instance = workInProgress.stateNode; - instance.props = workInProgress.memoizedProps; - instance.state = workInProgress.memoizedState; - var oldProps = workInProgress.memoizedProps, - newProps = workInProgress.pendingProps, - oldContext = instance.context, + instance = workInProgress.stateNode, + oldProps = workInProgress.memoizedProps, + newProps = workInProgress.pendingProps; + instance.props = oldProps; + var oldContext = instance.context, newUnmaskedContext = getUnmaskedContext(workInProgress); newUnmaskedContext = getMaskedContext(workInProgress, newUnmaskedContext); + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; (ctor = - "function" === typeof ctor.getDerivedStateFromProps || + "function" === typeof getDerivedStateFromProps || "function" === typeof instance.getSnapshotBeforeUpdate) || ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && "function" !== typeof instance.componentWillReceiveProps) || @@ -1932,43 +2027,29 @@ function ReactFiberClassComponent( newProps, newUnmaskedContext )); - oldContext = workInProgress.memoizedState; - renderExpirationTime = - null !== workInProgress.updateQueue - ? processUpdateQueue( - null, - workInProgress, - workInProgress.updateQueue, - instance, - newProps, - renderExpirationTime - ) - : oldContext; - var derivedStateFromProps = void 0; - oldProps !== newProps && - (derivedStateFromProps = callGetDerivedStateFromProps( + var oldState = workInProgress.memoizedState; + oldContext = instance.state = oldState; + var updateQueue = workInProgress.updateQueue; + null !== updateQueue && + (processUpdateQueue( workInProgress, - instance, + updateQueue, newProps, + instance, renderExpirationTime - )); - if (null !== derivedStateFromProps && void 0 !== derivedStateFromProps) { - renderExpirationTime = - null === renderExpirationTime || void 0 === renderExpirationTime - ? derivedStateFromProps - : Object.assign({}, renderExpirationTime, derivedStateFromProps); - var _updateQueue = workInProgress.updateQueue; - null !== _updateQueue && - (_updateQueue.baseState = Object.assign( - {}, - _updateQueue.baseState, - derivedStateFromProps - )); - } + ), + (oldContext = workInProgress.memoizedState)); + "function" === typeof getDerivedStateFromProps && + (applyDerivedStateFromProps( + workInProgress, + getDerivedStateFromProps, + newProps + ), + (oldContext = workInProgress.memoizedState)); if ( !( oldProps !== newProps || - oldContext !== renderExpirationTime || + oldState !== oldContext || hasContextChanged() || (null !== workInProgress.updateQueue && workInProgress.updateQueue.hasForceUpdate) @@ -1979,12 +2060,12 @@ function ReactFiberClassComponent( (workInProgress.effectTag |= 4), !1 ); - (oldProps = checkShouldComponentUpdate( + (renderExpirationTime = checkShouldComponentUpdate( workInProgress, oldProps, newProps, + oldState, oldContext, - renderExpirationTime, newUnmaskedContext )) ? (ctor || @@ -1998,12 +2079,12 @@ function ReactFiberClassComponent( (workInProgress.effectTag |= 4)) : ("function" === typeof instance.componentDidMount && (workInProgress.effectTag |= 4), - memoizeProps(workInProgress, newProps), - memoizeState(workInProgress, renderExpirationTime)); + (workInProgress.memoizedProps = newProps), + (workInProgress.memoizedState = oldContext)); instance.props = newProps; - instance.state = renderExpirationTime; + instance.state = oldContext; instance.context = newUnmaskedContext; - return oldProps; + return renderExpirationTime; }, updateClassInstance: function( current, @@ -2011,16 +2092,16 @@ function ReactFiberClassComponent( renderExpirationTime ) { var ctor = workInProgress.type, - instance = workInProgress.stateNode; - instance.props = workInProgress.memoizedProps; - instance.state = workInProgress.memoizedState; - var oldProps = workInProgress.memoizedProps, - newProps = workInProgress.pendingProps, - oldContext = instance.context, + instance = workInProgress.stateNode, + oldProps = workInProgress.memoizedProps, + newProps = workInProgress.pendingProps; + instance.props = oldProps; + var oldContext = instance.context, newUnmaskedContext = getUnmaskedContext(workInProgress); newUnmaskedContext = getMaskedContext(workInProgress, newUnmaskedContext); + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; (ctor = - "function" === typeof ctor.getDerivedStateFromProps || + "function" === typeof getDerivedStateFromProps || "function" === typeof instance.getSnapshotBeforeUpdate) || ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && "function" !== typeof instance.componentWillReceiveProps) || @@ -2032,42 +2113,28 @@ function ReactFiberClassComponent( newUnmaskedContext )); oldContext = workInProgress.memoizedState; - renderExpirationTime = - null !== workInProgress.updateQueue - ? processUpdateQueue( - current, - workInProgress, - workInProgress.updateQueue, - instance, - newProps, - renderExpirationTime - ) - : oldContext; - var derivedStateFromProps = void 0; - oldProps !== newProps && - (derivedStateFromProps = callGetDerivedStateFromProps( + var newState = (instance.state = oldContext), + updateQueue = workInProgress.updateQueue; + null !== updateQueue && + (processUpdateQueue( workInProgress, - instance, + updateQueue, newProps, + instance, renderExpirationTime - )); - if (null !== derivedStateFromProps && void 0 !== derivedStateFromProps) { - renderExpirationTime = - null === renderExpirationTime || void 0 === renderExpirationTime - ? derivedStateFromProps - : Object.assign({}, renderExpirationTime, derivedStateFromProps); - var _updateQueue3 = workInProgress.updateQueue; - null !== _updateQueue3 && - (_updateQueue3.baseState = Object.assign( - {}, - _updateQueue3.baseState, - derivedStateFromProps - )); - } + ), + (newState = workInProgress.memoizedState)); + "function" === typeof getDerivedStateFromProps && + (applyDerivedStateFromProps( + workInProgress, + getDerivedStateFromProps, + newProps + ), + (newState = workInProgress.memoizedState)); if ( !( oldProps !== newProps || - oldContext !== renderExpirationTime || + oldContext !== newState || hasContextChanged() || (null !== workInProgress.updateQueue && workInProgress.updateQueue.hasForceUpdate) @@ -2081,15 +2148,15 @@ function ReactFiberClassComponent( "function" !== typeof instance.getSnapshotBeforeUpdate || (oldProps === current.memoizedProps && oldContext === current.memoizedState) || - (workInProgress.effectTag |= 2048), + (workInProgress.effectTag |= 256), !1 ); - (derivedStateFromProps = checkShouldComponentUpdate( + (renderExpirationTime = checkShouldComponentUpdate( workInProgress, oldProps, newProps, oldContext, - renderExpirationTime, + newState, newUnmaskedContext )) ? (ctor || @@ -2098,19 +2165,19 @@ function ReactFiberClassComponent( ("function" === typeof instance.componentWillUpdate && instance.componentWillUpdate( newProps, - renderExpirationTime, + newState, newUnmaskedContext ), "function" === typeof instance.UNSAFE_componentWillUpdate && instance.UNSAFE_componentWillUpdate( newProps, - renderExpirationTime, + newState, newUnmaskedContext )), "function" === typeof instance.componentDidUpdate && (workInProgress.effectTag |= 4), "function" === typeof instance.getSnapshotBeforeUpdate && - (workInProgress.effectTag |= 2048)) + (workInProgress.effectTag |= 256)) : ("function" !== typeof instance.componentDidUpdate || (oldProps === current.memoizedProps && oldContext === current.memoizedState) || @@ -2118,13 +2185,13 @@ function ReactFiberClassComponent( "function" !== typeof instance.getSnapshotBeforeUpdate || (oldProps === current.memoizedProps && oldContext === current.memoizedState) || - (workInProgress.effectTag |= 2048), - memoizeProps(workInProgress, newProps), - memoizeState(workInProgress, renderExpirationTime)); + (workInProgress.effectTag |= 256), + (workInProgress.memoizedProps = newProps), + (workInProgress.memoizedState = newState)); instance.props = newProps; - instance.state = renderExpirationTime; + instance.state = newState; instance.context = newUnmaskedContext; - return derivedStateFromProps; + return renderExpirationTime; } }; } @@ -2248,11 +2315,11 @@ function ChildReconciler(shouldTrackSideEffects) { returnFiber.mode, expirationTime )), - (current["return"] = returnFiber), + (current.return = returnFiber), current ); current = useFiber(current, textContent, expirationTime); - current["return"] = returnFiber; + current.return = returnFiber; return current; } function updateElement(returnFiber, current, element, expirationTime) { @@ -2260,7 +2327,7 @@ function ChildReconciler(shouldTrackSideEffects) { return ( (expirationTime = useFiber(current, element.props, expirationTime)), (expirationTime.ref = coerceRef(returnFiber, current, element)), - (expirationTime["return"] = returnFiber), + (expirationTime.return = returnFiber), expirationTime ); expirationTime = createFiberFromElement( @@ -2269,7 +2336,7 @@ function ChildReconciler(shouldTrackSideEffects) { expirationTime ); expirationTime.ref = coerceRef(returnFiber, current, element); - expirationTime["return"] = returnFiber; + expirationTime.return = returnFiber; return expirationTime; } function updatePortal(returnFiber, current, portal, expirationTime) { @@ -2285,11 +2352,11 @@ function ChildReconciler(shouldTrackSideEffects) { returnFiber.mode, expirationTime )), - (current["return"] = returnFiber), + (current.return = returnFiber), current ); current = useFiber(current, portal.children || [], expirationTime); - current["return"] = returnFiber; + current.return = returnFiber; return current; } function updateFragment(returnFiber, current, fragment, expirationTime, key) { @@ -2301,11 +2368,11 @@ function ChildReconciler(shouldTrackSideEffects) { expirationTime, key )), - (current["return"] = returnFiber), + (current.return = returnFiber), current ); current = useFiber(current, fragment, expirationTime); - current["return"] = returnFiber; + current.return = returnFiber; return current; } function createChild(returnFiber, newChild, expirationTime) { @@ -2316,7 +2383,7 @@ function ChildReconciler(shouldTrackSideEffects) { returnFiber.mode, expirationTime )), - (newChild["return"] = returnFiber), + (newChild.return = returnFiber), newChild ); if ("object" === typeof newChild && null !== newChild) { @@ -2329,7 +2396,7 @@ function ChildReconciler(shouldTrackSideEffects) { expirationTime )), (expirationTime.ref = coerceRef(returnFiber, null, newChild)), - (expirationTime["return"] = returnFiber), + (expirationTime.return = returnFiber), expirationTime ); case REACT_PORTAL_TYPE: @@ -2339,7 +2406,7 @@ function ChildReconciler(shouldTrackSideEffects) { returnFiber.mode, expirationTime )), - (newChild["return"] = returnFiber), + (newChild.return = returnFiber), newChild ); } @@ -2351,7 +2418,7 @@ function ChildReconciler(shouldTrackSideEffects) { expirationTime, null )), - (newChild["return"] = returnFiber), + (newChild.return = returnFiber), newChild ); throwOnInvalidObjectType(returnFiber, newChild); @@ -2538,17 +2605,21 @@ function ChildReconciler(shouldTrackSideEffects) { newChildren[newIdx], expirationTime )) - ) { - if (shouldTrackSideEffects && null !== nextOldFiber.alternate) - oldFiber["delete"]( + ) + 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; - } + ), + (currentFirstChild = placeChild( + nextOldFiber, + currentFirstChild, + newIdx + )), + null === previousNewFiber + ? (resultingFirstChild = nextOldFiber) + : (previousNewFiber.sibling = nextOldFiber), + (previousNewFiber = nextOldFiber); shouldTrackSideEffects && oldFiber.forEach(function(child) { return deleteChild(returnFiber, child); @@ -2622,24 +2693,22 @@ function ChildReconciler(shouldTrackSideEffects) { !step.done; newIdx++, step = newChildrenIterable.next() ) - if ( - ((step = updateFromMap( - oldFiber, - returnFiber, - newIdx, - step.value, - expirationTime - )), - null !== step) - ) { - if (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; - } + (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); @@ -2678,7 +2747,7 @@ function ChildReconciler(shouldTrackSideEffects) { isObject, newChild ); - currentFirstChild["return"] = returnFiber; + currentFirstChild.return = returnFiber; returnFiber = currentFirstChild; break a; } else { @@ -2695,7 +2764,7 @@ function ChildReconciler(shouldTrackSideEffects) { expirationTime, newChild.key )), - (currentFirstChild["return"] = returnFiber), + (currentFirstChild.return = returnFiber), (returnFiber = currentFirstChild)) : ((expirationTime = createFiberFromElement( newChild, @@ -2707,7 +2776,7 @@ function ChildReconciler(shouldTrackSideEffects) { currentFirstChild, newChild )), - (expirationTime["return"] = returnFiber), + (expirationTime.return = returnFiber), (returnFiber = expirationTime)); } return placeSingleChild(returnFiber); @@ -2731,7 +2800,7 @@ function ChildReconciler(shouldTrackSideEffects) { newChild.children || [], expirationTime ); - currentFirstChild["return"] = returnFiber; + currentFirstChild.return = returnFiber; returnFiber = currentFirstChild; break a; } else { @@ -2746,7 +2815,7 @@ function ChildReconciler(shouldTrackSideEffects) { returnFiber.mode, expirationTime ); - currentFirstChild["return"] = returnFiber; + currentFirstChild.return = returnFiber; returnFiber = currentFirstChild; } return placeSingleChild(returnFiber); @@ -2761,7 +2830,7 @@ function ChildReconciler(shouldTrackSideEffects) { newChild, expirationTime )), - (currentFirstChild["return"] = returnFiber), + (currentFirstChild.return = returnFiber), (returnFiber = currentFirstChild)) : (deleteRemainingChildren(returnFiber, currentFirstChild), (currentFirstChild = createFiberFromText( @@ -2769,7 +2838,7 @@ function ChildReconciler(shouldTrackSideEffects) { returnFiber.mode, expirationTime )), - (currentFirstChild["return"] = returnFiber), + (currentFirstChild.return = returnFiber), (returnFiber = currentFirstChild)), placeSingleChild(returnFiber) ); @@ -2855,10 +2924,10 @@ function ReactFiberBeginWork( workInProgress, shouldUpdate, hasContext, - didCaptureError, renderExpirationTime ) { markRef(current, workInProgress); + var didCaptureError = 0 !== (workInProgress.effectTag & 64); if (!shouldUpdate && !didCaptureError) return ( hasContext && invalidateContextProvider(workInProgress, !1), @@ -2906,11 +2975,8 @@ function ReactFiberBeginWork( renderExpirationTime ) { var fiber = workInProgress.child; - for ( - null !== fiber && (fiber["return"] = workInProgress); - null !== fiber; - - ) { + null !== fiber && (fiber.return = workInProgress); + for (; null !== fiber; ) { switch (fiber.tag) { case 12: var nextFiber = fiber.stateNode | 0; @@ -2933,7 +2999,7 @@ function ReactFiberBeginWork( ) alternate.expirationTime = renderExpirationTime; else break; - nextFiber = nextFiber["return"]; + nextFiber = nextFiber.return; } nextFiber = null; } else nextFiber = fiber.child; @@ -2944,7 +3010,7 @@ function ReactFiberBeginWork( default: nextFiber = fiber.child; } - if (null !== nextFiber) nextFiber["return"] = fiber; + if (null !== nextFiber) nextFiber.return = fiber; else for (nextFiber = fiber; null !== nextFiber; ) { if (nextFiber === workInProgress) { @@ -2953,10 +3019,11 @@ function ReactFiberBeginWork( } fiber = nextFiber.sibling; if (null !== fiber) { + fiber.return = nextFiber.return; nextFiber = fiber; break; } - nextFiber = nextFiber["return"]; + nextFiber = nextFiber.return; } fiber = nextFiber; } @@ -2968,8 +3035,10 @@ function ReactFiberBeginWork( ) { var context = workInProgress.type._context, newProps = workInProgress.pendingProps, - oldProps = workInProgress.memoizedProps; - if (!hasLegacyContextChanged() && oldProps === newProps) + oldProps = workInProgress.memoizedProps, + canBailOnProps = !0; + if (hasLegacyContextChanged()) canBailOnProps = !1; + else if (oldProps === newProps) return ( (workInProgress.stateNode = 0), pushProvider(workInProgress), @@ -2979,7 +3048,7 @@ function ReactFiberBeginWork( workInProgress.memoizedProps = newProps; if (null === oldProps) newValue = 1073741823; else if (oldProps.value === newProps.value) { - if (oldProps.children === newProps.children) + if (oldProps.children === newProps.children && canBailOnProps) return ( (workInProgress.stateNode = 0), pushProvider(workInProgress), @@ -2993,7 +3062,7 @@ function ReactFiberBeginWork( (0 !== oldValue || 1 / oldValue === 1 / newValue)) || (oldValue !== oldValue && newValue !== newValue) ) { - if (oldProps.children === newProps.children) + if (oldProps.children === newProps.children && canBailOnProps) return ( (workInProgress.stateNode = 0), pushProvider(workInProgress), @@ -3008,7 +3077,7 @@ function ReactFiberBeginWork( (newValue |= 0), 0 === newValue) ) { - if (oldProps.children === newProps.children) + if (oldProps.children === newProps.children && canBailOnProps) return ( (workInProgress.stateNode = 0), pushProvider(workInProgress), @@ -3040,14 +3109,14 @@ function ReactFiberBeginWork( current.expirationTime ); workInProgress.child = newChild; - for (newChild["return"] = workInProgress; null !== current.sibling; ) + for (newChild.return = workInProgress; null !== current.sibling; ) (current = current.sibling), (newChild = newChild.sibling = createWorkInProgress( current, current.pendingProps, current.expirationTime )), - (newChild["return"] = workInProgress); + (newChild.return = workInProgress); newChild.sibling = null; } return workInProgress.child; @@ -3079,7 +3148,6 @@ function ReactFiberBeginWork( } ); var adoptClassInstance = config.adoptClassInstance, - callGetDerivedStateFromProps = config.callGetDerivedStateFromProps, constructClassInstance = config.constructClassInstance, mountClassInstance = config.mountClassInstance, resumeMountClassInstance = config.resumeMountClassInstance, @@ -3128,20 +3196,13 @@ function ReactFiberBeginWork( (workInProgress.tag = 2), (workInProgress.memoizedState = null !== fn.state && void 0 !== fn.state ? fn.state : null), - "function" === typeof unmaskedContext.getDerivedStateFromProps && - ((props = callGetDerivedStateFromProps( + (unmaskedContext = unmaskedContext.getDerivedStateFromProps), + "function" === typeof unmaskedContext && + applyDerivedStateFromProps( workInProgress, - fn, - props, - workInProgress.memoizedState - )), - null !== props && - void 0 !== props && - (workInProgress.memoizedState = Object.assign( - {}, - workInProgress.memoizedState, - props - ))), + unmaskedContext, + props + ), (props = pushLegacyContextProvider(workInProgress)), adoptClassInstance(workInProgress, fn), mountClassInstance(workInProgress, renderExpirationTime), @@ -3150,7 +3211,6 @@ function ReactFiberBeginWork( workInProgress, !0, props, - !1, renderExpirationTime ))) : ((workInProgress.tag = 1), @@ -3178,103 +3238,100 @@ function ReactFiberBeginWork( current ); case 2: - props = pushLegacyContextProvider(workInProgress); - null === current - ? null === workInProgress.stateNode - ? (constructClassInstance( - workInProgress, - workInProgress.pendingProps - ), - mountClassInstance(workInProgress, renderExpirationTime), - (fn = !0)) - : (fn = resumeMountClassInstance( + return ( + (props = pushLegacyContextProvider(workInProgress)), + null === current + ? null === workInProgress.stateNode + ? (constructClassInstance( + workInProgress, + workInProgress.pendingProps, + renderExpirationTime + ), + mountClassInstance(workInProgress, renderExpirationTime), + (fn = !0)) + : (fn = resumeMountClassInstance( + workInProgress, + renderExpirationTime + )) + : (fn = updateClassInstance( + current, workInProgress, renderExpirationTime - )) - : (fn = updateClassInstance( - current, - workInProgress, - renderExpirationTime - )); - unmaskedContext = !1; - var updateQueue = workInProgress.updateQueue; - null !== updateQueue && - null !== updateQueue.capturedValues && - (unmaskedContext = fn = !0); - return finishClassComponent( - current, - workInProgress, - fn, - props, - unmaskedContext, - renderExpirationTime - ); - case 3: - a: if ( - (pushHostRootContext(workInProgress), - (fn = workInProgress.updateQueue), - null !== fn) - ) { - unmaskedContext = workInProgress.memoizedState; - props = processUpdateQueue( + )), + finishClassComponent( current, workInProgress, fn, - null, - null, + props, renderExpirationTime - ); - workInProgress.memoizedState = props; - fn = workInProgress.updateQueue; - if (null !== fn && null !== fn.capturedValues) fn = null; - else if (unmaskedContext === props) { - resetHydrationState(); - current = bailoutOnAlreadyFinishedWork(current, workInProgress); - break a; - } else fn = props.element; - unmaskedContext = workInProgress.stateNode; - (null === current || null === current.child) && - unmaskedContext.hydrate && - enterHydrationState(workInProgress) - ? ((workInProgress.effectTag |= 2), - (workInProgress.child = mountChildFibers( + ) + ); + case 3: + return ( + pushHostRootContext(workInProgress), + (props = workInProgress.updateQueue), + null !== props + ? ((fn = workInProgress.memoizedState), + (fn = null !== fn ? fn.element : null), + processUpdateQueue( workInProgress, + props, + workInProgress.pendingProps, null, - fn, renderExpirationTime - ))) + ), + (props = workInProgress.memoizedState.element), + props === fn + ? (resetHydrationState(), + (current = bailoutOnAlreadyFinishedWork( + current, + workInProgress + ))) + : ((fn = workInProgress.stateNode), + (null === current || null === current.child) && + fn.hydrate && + enterHydrationState(workInProgress) + ? ((workInProgress.effectTag |= 2), + (workInProgress.child = mountChildFibers( + workInProgress, + null, + props, + renderExpirationTime + ))) + : (resetHydrationState(), + reconcileChildren(current, workInProgress, props)), + (current = workInProgress.child))) : (resetHydrationState(), - reconcileChildren(current, workInProgress, fn)); - workInProgress.memoizedState = props; - current = workInProgress.child; - } else - resetHydrationState(), - (current = bailoutOnAlreadyFinishedWork(current, workInProgress)); - return current; + (current = bailoutOnAlreadyFinishedWork( + current, + workInProgress + ))), + current + ); case 5: a: { pushHostContext(workInProgress); null === current && tryToClaimNextHydratableInstance(workInProgress); props = workInProgress.type; - updateQueue = workInProgress.memoizedProps; + var memoizedProps = workInProgress.memoizedProps; fn = workInProgress.pendingProps; unmaskedContext = null !== current ? current.memoizedProps : null; - if (!hasLegacyContextChanged() && updateQueue === fn) { + if (!hasLegacyContextChanged() && memoizedProps === fn) { if ( - (updateQueue = + (memoizedProps = workInProgress.mode & 1 && shouldDeprioritizeSubtree(props, fn)) ) workInProgress.expirationTime = 1073741823; - if (!updateQueue || 1073741823 !== renderExpirationTime) { + if (!memoizedProps || 1073741823 !== renderExpirationTime) { current = bailoutOnAlreadyFinishedWork(current, workInProgress); break a; } } - updateQueue = fn.children; + memoizedProps = fn.children; shouldSetTextContent(props, fn) - ? (updateQueue = null) + ? (memoizedProps = null) : unmaskedContext && shouldSetTextContent(props, unmaskedContext) && (workInProgress.effectTag |= 16); @@ -3285,7 +3342,7 @@ function ReactFiberBeginWork( ? ((workInProgress.expirationTime = 1073741823), (workInProgress.memoizedProps = fn), (current = null)) - : (reconcileChildren(current, workInProgress, updateQueue), + : (reconcileChildren(current, workInProgress, memoizedProps), (workInProgress.memoizedProps = fn), (current = workInProgress.child)); } @@ -3351,14 +3408,21 @@ function ReactFiberBeginWork( ); case 14: return ( - (renderExpirationTime = workInProgress.type.render), - (renderExpirationTime = renderExpirationTime( - workInProgress.pendingProps, - workInProgress.ref - )), - reconcileChildren(current, workInProgress, renderExpirationTime), - (workInProgress.memoizedProps = renderExpirationTime), - workInProgress.child + (props = workInProgress.type.render), + (renderExpirationTime = workInProgress.pendingProps), + (fn = workInProgress.ref), + hasLegacyContextChanged() || + workInProgress.memoizedProps !== renderExpirationTime || + fn !== (null !== current ? current.ref : null) + ? ((props = props(renderExpirationTime, fn)), + reconcileChildren(current, workInProgress, props), + (workInProgress.memoizedProps = renderExpirationTime), + (current = workInProgress.child)) + : (current = bailoutOnAlreadyFinishedWork( + current, + workInProgress + )), + current ); case 10: return ( @@ -3407,13 +3471,13 @@ function ReactFiberBeginWork( a: { fn = workInProgress.type; unmaskedContext = workInProgress.pendingProps; - updateQueue = workInProgress.memoizedProps; + memoizedProps = workInProgress.memoizedProps; props = fn._currentValue; var changedBits = fn._changedBits; if ( hasLegacyContextChanged() || 0 !== changedBits || - updateQueue !== unmaskedContext + memoizedProps !== unmaskedContext ) { workInProgress.memoizedProps = unmaskedContext; var observedBits = unmaskedContext.unstable_observedBits; @@ -3427,12 +3491,13 @@ function ReactFiberBeginWork( changedBits, renderExpirationTime ); - else if (updateQueue === unmaskedContext) { + else if (memoizedProps === unmaskedContext) { current = bailoutOnAlreadyFinishedWork(current, workInProgress); break a; } renderExpirationTime = unmaskedContext.children; renderExpirationTime = renderExpirationTime(props); + workInProgress.effectTag |= 1; reconcileChildren(current, workInProgress, renderExpirationTime); current = workInProgress.child; } else @@ -3463,17 +3528,16 @@ function ReactFiberCompleteWork( if (5 === node.tag || 6 === node.tag) appendInitialChild(parent, node.stateNode); else if (4 !== node.tag && null !== node.child) { - node.child["return"] = node; + 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"]; + if (null === node.return || node.return === workInProgress) return; + node = node.return; } - node.sibling["return"] = node["return"]; + node.sibling.return = node.return; node = node.sibling; } } @@ -3514,17 +3578,16 @@ function ReactFiberCompleteWork( if (5 === node.tag || 6 === node.tag) appendChildToContainerChildSet(newChildSet, node.stateNode); else if (4 !== node.tag && null !== node.child) { - node.child["return"] = node; + node.child.return = node; node = node.child; continue; } if (node === workInProgress) break a; for (; null === node.sibling; ) { - if (null === node["return"] || node["return"] === workInProgress) - break a; - node = node["return"]; + if (null === node.return || node.return === workInProgress) break a; + node = node.return; } - node.sibling["return"] = node["return"]; + node.sibling.return = node.return; node = node.sibling; } portalOrRoot.pendingChildren = newChildSet; @@ -3588,18 +3651,7 @@ function ReactFiberCompleteWork( case 1: return null; case 2: - return ( - popLegacyContextProvider(workInProgress), - (current = workInProgress.stateNode), - (newProps = workInProgress.updateQueue), - null !== newProps && - null !== newProps.capturedValues && - ((workInProgress.effectTag &= -65), - "function" === typeof current.componentDidCatch - ? (workInProgress.effectTag |= 256) - : (newProps.capturedValues = null)), - null - ); + return popLegacyContextProvider(workInProgress), null; case 3: popHostContainer(workInProgress); popTopLevelLegacyContextObject(workInProgress); @@ -3610,10 +3662,6 @@ function ReactFiberCompleteWork( if (null === current || null === current.child) popHydrationState(workInProgress), (workInProgress.effectTag &= -3); updateHostContainer(workInProgress); - current = workInProgress.updateQueue; - null !== current && - null !== current.capturedValues && - (workInProgress.effectTag |= 256); return null; case 5: popHostContext(workInProgress); @@ -3621,10 +3669,10 @@ function ReactFiberCompleteWork( var type = workInProgress.type; if (null !== current && null != workInProgress.stateNode) { var oldProps = current.memoizedProps, - _instance = workInProgress.stateNode, + instance = workInProgress.stateNode, currentHostContext = getHostContext(); - _instance = prepareUpdate( - _instance, + instance = prepareUpdate( + instance, type, oldProps, newProps, @@ -3634,7 +3682,7 @@ function ReactFiberCompleteWork( updateHostComponent( current, workInProgress, - _instance, + instance, type, oldProps, newProps, @@ -3716,30 +3764,34 @@ function ReactFiberCompleteWork( ); workInProgress.tag = 8; type = []; - a: for ( - (oldProps = workInProgress.stateNode) && - (oldProps["return"] = workInProgress); - null !== oldProps; - - ) { - if (5 === oldProps.tag || 6 === oldProps.tag || 4 === oldProps.tag) - invariant(!1, "A call cannot have host component children."); - else if (9 === oldProps.tag) type.push(oldProps.pendingProps.value); - else if (null !== oldProps.child) { - oldProps.child["return"] = oldProps; - oldProps = oldProps.child; - continue; - } - for (; null === oldProps.sibling; ) { + a: { + if ((oldProps = workInProgress.stateNode)) + oldProps.return = workInProgress; + for (; null !== oldProps; ) { if ( - null === oldProps["return"] || - oldProps["return"] === workInProgress + 5 === oldProps.tag || + 6 === oldProps.tag || + 4 === oldProps.tag ) - break a; - oldProps = oldProps["return"]; + invariant(!1, "A call cannot have host component children."); + else if (9 === oldProps.tag) + type.push(oldProps.pendingProps.value); + else if (null !== oldProps.child) { + oldProps.child.return = oldProps; + oldProps = oldProps.child; + continue; + } + for (; null === oldProps.sibling; ) { + if ( + null === oldProps.return || + oldProps.return === workInProgress + ) + break a; + oldProps = oldProps.return; + } + oldProps.sibling.return = oldProps.return; + oldProps = oldProps.sibling; } - oldProps.sibling["return"] = oldProps["return"]; - oldProps = oldProps.sibling; } oldProps = newProps.handler; newProps = oldProps(newProps.props, type); @@ -3784,103 +3836,11 @@ function ReactFiberCompleteWork( } }; } -function ReactFiberUnwindWork( - hostContext, - legacyContext, - newContext, - scheduleWork, - isAlreadyFailedLegacyErrorBoundary -) { - var popHostContainer = hostContext.popHostContainer, - popHostContext = hostContext.popHostContext, - popLegacyContextProvider = legacyContext.popContextProvider, - popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject, - popProvider = newContext.popProvider; +function createCapturedValue(value, source) { return { - throwException: function(returnFiber, sourceFiber, rawValue) { - sourceFiber.effectTag |= 512; - sourceFiber.firstEffect = sourceFiber.lastEffect = null; - sourceFiber = { - value: rawValue, - source: sourceFiber, - stack: getStackAddendumByWorkInProgressFiber(sourceFiber) - }; - do { - switch (returnFiber.tag) { - case 3: - ensureUpdateQueues(returnFiber); - returnFiber.updateQueue.capturedValues = [sourceFiber]; - returnFiber.effectTag |= 1024; - return; - case 2: - if ( - ((rawValue = returnFiber.stateNode), - 0 === (returnFiber.effectTag & 64) && - null !== rawValue && - "function" === typeof rawValue.componentDidCatch && - !isAlreadyFailedLegacyErrorBoundary(rawValue)) - ) { - ensureUpdateQueues(returnFiber); - rawValue = returnFiber.updateQueue; - var capturedValues = rawValue.capturedValues; - null === capturedValues - ? (rawValue.capturedValues = [sourceFiber]) - : capturedValues.push(sourceFiber); - returnFiber.effectTag |= 1024; - return; - } - } - returnFiber = returnFiber["return"]; - } while (null !== returnFiber); - }, - unwindWork: function(workInProgress) { - switch (workInProgress.tag) { - case 2: - popLegacyContextProvider(workInProgress); - var effectTag = workInProgress.effectTag; - return effectTag & 1024 - ? ((workInProgress.effectTag = (effectTag & -1025) | 64), - workInProgress) - : null; - case 3: - return ( - popHostContainer(workInProgress), - popTopLevelLegacyContextObject(workInProgress), - (effectTag = workInProgress.effectTag), - effectTag & 1024 - ? ((workInProgress.effectTag = (effectTag & -1025) | 64), - workInProgress) - : null - ); - case 5: - return popHostContext(workInProgress), null; - case 4: - return popHostContainer(workInProgress), null; - case 13: - return popProvider(workInProgress), null; - default: - return null; - } - }, - unwindInterruptedWork: function(interruptedWork) { - switch (interruptedWork.tag) { - case 2: - popLegacyContextProvider(interruptedWork); - break; - case 3: - popHostContainer(interruptedWork); - popTopLevelLegacyContextObject(interruptedWork); - break; - case 5: - popHostContext(interruptedWork); - break; - case 4: - popHostContainer(interruptedWork); - break; - case 13: - popProvider(interruptedWork); - } - } + value: value, + source: source, + stack: getStackAddendumByWorkInProgressFiber(source) }; } function logError(boundary, errorInfo) { @@ -3896,13 +3856,7 @@ function logError(boundary, errorInfo) { (e && e.suppressReactErrorLogging) || console.error(e); } } -function ReactFiberCommitWork( - config, - captureError, - scheduleWork, - computeExpirationForFiber, - markLegacyErrorBoundaryAsFailed -) { +function ReactFiberCommitWork(config, captureError) { function safelyDetachRef(current) { var ref = current.ref; if (null !== ref) @@ -3917,7 +3871,7 @@ function ReactFiberCommitWork( function commitBeforeMutationLifeCycles(current, finishedWork) { switch (finishedWork.tag) { case 2: - if (finishedWork.effectTag & 2048 && null !== current) { + if (finishedWork.effectTag & 256 && null !== current) { var prevProps = current.memoizedProps, prevState = current.memoizedState; current = finishedWork.stateNode; @@ -3939,28 +3893,40 @@ function ReactFiberCommitWork( ); } } - function commitLifeCycles(finishedRoot, current, finishedWork) { + function commitLifeCycles( + finishedRoot, + current, + finishedWork, + currentTime, + committedExpirationTime + ) { switch (finishedWork.tag) { case 2: finishedRoot = finishedWork.stateNode; - if (finishedWork.effectTag & 4) - if (null === current) - (finishedRoot.props = finishedWork.memoizedProps), + finishedWork.effectTag & 4 && + (null === current + ? ((finishedRoot.props = finishedWork.memoizedProps), (finishedRoot.state = finishedWork.memoizedState), - finishedRoot.componentDidMount(); - else { - var prevProps = current.memoizedProps; - current = current.memoizedState; - finishedRoot.props = finishedWork.memoizedProps; - finishedRoot.state = finishedWork.memoizedState; - finishedRoot.componentDidUpdate( - prevProps, - current, - finishedRoot.__reactInternalSnapshotBeforeUpdate - ); - } - finishedWork = finishedWork.updateQueue; - null !== finishedWork && commitCallbacks(finishedWork, finishedRoot); + finishedRoot.componentDidMount()) + : ((currentTime = current.memoizedProps), + (current = current.memoizedState), + (finishedRoot.props = finishedWork.memoizedProps), + (finishedRoot.state = finishedWork.memoizedState), + finishedRoot.componentDidUpdate( + currentTime, + current, + finishedRoot.__reactInternalSnapshotBeforeUpdate + ))); + current = finishedWork.updateQueue; + null !== current && + ((finishedRoot.props = finishedWork.memoizedProps), + (finishedRoot.state = finishedWork.memoizedState), + commitUpdateQueue( + finishedWork, + current, + finishedRoot, + committedExpirationTime + )); break; case 3: current = finishedWork.updateQueue; @@ -3974,15 +3940,20 @@ function ReactFiberCommitWork( case 2: finishedRoot = finishedWork.child.stateNode; } - commitCallbacks(current, finishedRoot); + commitUpdateQueue( + finishedWork, + current, + finishedRoot, + committedExpirationTime + ); } break; case 5: - finishedRoot = finishedWork.stateNode; + committedExpirationTime = finishedWork.stateNode; null === current && finishedWork.effectTag & 4 && commitMount( - finishedRoot, + committedExpirationTime, finishedWork.type, finishedWork.memoizedProps, finishedWork @@ -3999,62 +3970,16 @@ function ReactFiberCommitWork( ); } } - function commitErrorLogging(finishedWork, onUncaughtError) { - switch (finishedWork.tag) { - case 2: - var ctor = finishedWork.type; - onUncaughtError = finishedWork.stateNode; - var updateQueue = finishedWork.updateQueue; - invariant( - null !== updateQueue && null !== updateQueue.capturedValues, - "An error logging effect should not have been scheduled if no errors were captured. This error is likely caused by a bug in React. Please file an issue." - ); - var capturedErrors = updateQueue.capturedValues; - updateQueue.capturedValues = null; - "function" !== typeof ctor.getDerivedStateFromCatch && - markLegacyErrorBoundaryAsFailed(onUncaughtError); - onUncaughtError.props = finishedWork.memoizedProps; - onUncaughtError.state = finishedWork.memoizedState; - for (ctor = 0; ctor < capturedErrors.length; ctor++) { - updateQueue = capturedErrors[ctor]; - var _error = updateQueue.value, - stack = updateQueue.stack; - logError(finishedWork, updateQueue); - onUncaughtError.componentDidCatch(_error, { - componentStack: null !== stack ? stack : "" - }); - } - break; - case 3: - ctor = finishedWork.updateQueue; - invariant( - null !== ctor && null !== ctor.capturedValues, - "An error logging effect should not have been scheduled if no errors were captured. This error is likely caused by a bug in React. Please file an issue." - ); - capturedErrors = ctor.capturedValues; - ctor.capturedValues = null; - for (ctor = 0; ctor < capturedErrors.length; ctor++) - (updateQueue = capturedErrors[ctor]), - logError(finishedWork, updateQueue), - onUncaughtError(updateQueue.value); - break; - default: - invariant( - !1, - "This unit of work tag cannot capture errors. This error is likely caused by a bug in React. Please file an issue." - ); - } - } function commitAttachRef(finishedWork) { var ref = finishedWork.ref; if (null !== ref) { - var _instance6 = finishedWork.stateNode; + var _instance5 = finishedWork.stateNode; switch (finishedWork.tag) { case 5: - finishedWork = getPublicInstance(_instance6); + finishedWork = getPublicInstance(_instance5); break; default: - finishedWork = _instance6; + finishedWork = _instance5; } "function" === typeof ref ? ref(finishedWork) @@ -4075,12 +4000,12 @@ function ReactFiberCommitWork( switch (current.tag) { case 2: safelyDetachRef(current); - var _instance7 = current.stateNode; - if ("function" === typeof _instance7.componentWillUnmount) + var _instance6 = current.stateNode; + if ("function" === typeof _instance6.componentWillUnmount) try { - (_instance7.props = current.memoizedProps), - (_instance7.state = current.memoizedState), - _instance7.componentWillUnmount(); + (_instance6.props = current.memoizedProps), + (_instance6.state = current.memoizedState), + _instance6.componentWillUnmount(); } catch (unmountError) { captureError(current, unmountError); } @@ -4097,12 +4022,12 @@ function ReactFiberCommitWork( if (null === node.child || (mutation && 4 === node.tag)) { if (node === root) break; for (; null === node.sibling; ) { - if (null === node["return"] || node["return"] === root) return; - node = node["return"]; + if (null === node.return || node.return === root) return; + node = node.return; } - node.sibling["return"] = node["return"]; + node.sibling.return = node.return; node = node.sibling; - } else (node.child["return"] = node), (node = node.child); + } else (node.child.return = node), (node = node.child); } } var getPublicInstance = config.getPublicInstance, @@ -4148,18 +4073,16 @@ function ReactFiberCommitWork( commitPlacement: function() {}, commitDeletion: function(current) { commitNestedUnmounts(current); - current["return"] = null; + current.return = null; current.child = null; current.alternate && - ((current.alternate.child = null), - (current.alternate["return"] = null)); + ((current.alternate.child = null), (current.alternate.return = null)); }, commitWork: function(current, finishedWork) { commitContainer(finishedWork); }, commitLifeCycles: commitLifeCycles, commitBeforeMutationLifeCycles: commitBeforeMutationLifeCycles, - commitErrorLogging: commitErrorLogging, commitAttachRef: commitAttachRef, commitDetachRef: commitDetachRef }; @@ -4167,6 +4090,151 @@ function ReactFiberCommitWork( var commitMount = mutation.commitMount; invariant(!1, "Mutating reconciler is disabled."); } +function ReactFiberUnwindWork( + hostContext, + legacyContext, + newContext, + scheduleWork, + markLegacyErrorBoundaryAsFailed, + isAlreadyFailedLegacyErrorBoundary, + onUncaughtError +) { + function createRootErrorUpdate(fiber, errorInfo, expirationTime) { + expirationTime = createUpdate(expirationTime); + expirationTime.tag = 3; + expirationTime.payload = { element: null }; + var error = errorInfo.value; + expirationTime.callback = function() { + onUncaughtError(error); + logError(fiber, errorInfo); + }; + return expirationTime; + } + function createClassErrorUpdate(fiber, errorInfo, expirationTime) { + expirationTime = createUpdate(expirationTime); + expirationTime.tag = 3; + var inst = fiber.stateNode; + null !== inst && + "function" === typeof inst.componentDidCatch && + (expirationTime.callback = function() { + markLegacyErrorBoundaryAsFailed(this); + var error = errorInfo.value, + stack = errorInfo.stack; + logError(fiber, errorInfo); + this.componentDidCatch(error, { + componentStack: null !== stack ? stack : "" + }); + }); + return expirationTime; + } + var popHostContainer = hostContext.popHostContainer, + popHostContext = hostContext.popHostContext, + popLegacyContextProvider = legacyContext.popContextProvider, + popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject, + popProvider = newContext.popProvider; + return { + throwException: function( + returnFiber, + sourceFiber, + rawValue, + renderExpirationTime + ) { + sourceFiber.effectTag |= 512; + sourceFiber.firstEffect = sourceFiber.lastEffect = null; + sourceFiber = createCapturedValue(rawValue, sourceFiber); + do { + switch (returnFiber.tag) { + case 3: + returnFiber.effectTag |= 1024; + sourceFiber = createRootErrorUpdate( + returnFiber, + sourceFiber, + renderExpirationTime + ); + enqueueCapturedUpdate( + returnFiber, + sourceFiber, + renderExpirationTime + ); + return; + case 2: + rawValue = sourceFiber; + var _instance = returnFiber.stateNode; + if ( + 0 === (returnFiber.effectTag & 64) && + null !== _instance && + "function" === typeof _instance.componentDidCatch && + !isAlreadyFailedLegacyErrorBoundary(_instance) + ) { + returnFiber.effectTag |= 1024; + sourceFiber = createClassErrorUpdate( + returnFiber, + rawValue, + renderExpirationTime + ); + enqueueCapturedUpdate( + returnFiber, + sourceFiber, + renderExpirationTime + ); + return; + } + } + returnFiber = returnFiber.return; + } while (null !== returnFiber); + }, + unwindWork: function(workInProgress) { + switch (workInProgress.tag) { + case 2: + popLegacyContextProvider(workInProgress); + var effectTag = workInProgress.effectTag; + return effectTag & 1024 + ? ((workInProgress.effectTag = (effectTag & -1025) | 64), + workInProgress) + : null; + case 3: + return ( + popHostContainer(workInProgress), + popTopLevelLegacyContextObject(workInProgress), + (effectTag = workInProgress.effectTag), + effectTag & 1024 + ? ((workInProgress.effectTag = (effectTag & -1025) | 64), + workInProgress) + : null + ); + case 5: + return popHostContext(workInProgress), null; + case 4: + return popHostContainer(workInProgress), null; + case 13: + return popProvider(workInProgress), null; + default: + return null; + } + }, + unwindInterruptedWork: function(interruptedWork) { + switch (interruptedWork.tag) { + case 2: + popLegacyContextProvider(interruptedWork); + break; + case 3: + popHostContainer(interruptedWork); + popTopLevelLegacyContextObject(interruptedWork); + break; + case 5: + popHostContext(interruptedWork); + break; + case 4: + popHostContainer(interruptedWork); + break; + case 13: + popProvider(interruptedWork); + } + }, + createRootErrorUpdate: createRootErrorUpdate, + createClassErrorUpdate: createClassErrorUpdate + }; +} var NO_CONTEXT = {}; function ReactFiberHostContext(config, stack) { function requiredContext(c) { @@ -4223,7 +4291,7 @@ function ReactFiberHydrationContext(config) { var fiber = new FiberNode(5, null, null, 0); fiber.type = "DELETED"; fiber.stateNode = instance; - fiber["return"] = returnFiber; + fiber.return = returnFiber; fiber.effectTag = 8; null !== returnFiber.lastEffect ? ((returnFiber.lastEffect.nextEffect = fiber), @@ -4255,11 +4323,11 @@ function ReactFiberHydrationContext(config) { } function popToNextHostParent(fiber) { for ( - fiber = fiber["return"]; + fiber = fiber.return; null !== fiber && 5 !== fiber.tag && 3 !== fiber.tag; ) - fiber = fiber["return"]; + fiber = fiber.return; hydrationParentFiber = fiber; } var shouldSetTextContent = config.shouldSetTextContent; @@ -4493,7 +4561,7 @@ function ReactFiberLegacyContext(stack) { ) { if (isContextProvider(fiber)) return fiber.stateNode.__reactInternalMemoizedMergedChildContext; - fiber = fiber["return"]; + fiber = fiber.return; invariant( fiber, "Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue." @@ -4560,12 +4628,12 @@ function ReactFiberScheduler(config) { function resetStack() { if (null !== nextUnitOfWork) for ( - var interruptedWork = nextUnitOfWork["return"]; + var interruptedWork = nextUnitOfWork.return; null !== interruptedWork; ) unwindInterruptedWork(interruptedWork), - (interruptedWork = interruptedWork["return"]); + (interruptedWork = interruptedWork.return); nextRoot = null; nextRenderExpirationTime = 0; nextUnitOfWork = null; @@ -4577,74 +4645,71 @@ function ReactFiberScheduler(config) { legacyErrorBoundariesThatAlreadyFailed.has(instance) ); } - function completeUnitOfWork(workInProgress$jscomp$0) { + function markLegacyErrorBoundaryAsFailed(instance) { + null === legacyErrorBoundariesThatAlreadyFailed + ? (legacyErrorBoundariesThatAlreadyFailed = new Set([instance])) + : legacyErrorBoundariesThatAlreadyFailed.add(instance); + } + function completeUnitOfWork(workInProgress) { for (;;) { - var current = workInProgress$jscomp$0.alternate, - returnFiber = workInProgress$jscomp$0["return"], - siblingFiber = workInProgress$jscomp$0.sibling; - if (0 === (workInProgress$jscomp$0.effectTag & 512)) { + var current = workInProgress.alternate, + returnFiber = workInProgress.return, + siblingFiber = workInProgress.sibling; + if (0 === (workInProgress.effectTag & 512)) { current = completeWork( current, - workInProgress$jscomp$0, + workInProgress, nextRenderExpirationTime ); - var workInProgress = workInProgress$jscomp$0; if ( 1073741823 === nextRenderExpirationTime || 1073741823 !== workInProgress.expirationTime ) { - b: switch (workInProgress.tag) { + var newExpirationTime = 0; + switch (workInProgress.tag) { case 3: case 2: - var newExpirationTime = workInProgress.updateQueue; - newExpirationTime = - null === newExpirationTime - ? 0 - : newExpirationTime.expirationTime; - break b; - default: - newExpirationTime = 0; + var updateQueue = workInProgress.updateQueue; + null !== updateQueue && + (newExpirationTime = updateQueue.expirationTime); } - for (var child = workInProgress.child; null !== child; ) - 0 !== child.expirationTime && + for (updateQueue = workInProgress.child; null !== updateQueue; ) + 0 !== updateQueue.expirationTime && (0 === newExpirationTime || - newExpirationTime > child.expirationTime) && - (newExpirationTime = child.expirationTime), - (child = child.sibling); + newExpirationTime > updateQueue.expirationTime) && + (newExpirationTime = updateQueue.expirationTime), + (updateQueue = updateQueue.sibling); workInProgress.expirationTime = newExpirationTime; } if (null !== current) return current; null !== returnFiber && 0 === (returnFiber.effectTag & 512) && (null === returnFiber.firstEffect && - (returnFiber.firstEffect = workInProgress$jscomp$0.firstEffect), - null !== workInProgress$jscomp$0.lastEffect && + (returnFiber.firstEffect = workInProgress.firstEffect), + null !== workInProgress.lastEffect && (null !== returnFiber.lastEffect && - (returnFiber.lastEffect.nextEffect = - workInProgress$jscomp$0.firstEffect), - (returnFiber.lastEffect = workInProgress$jscomp$0.lastEffect)), - 1 < workInProgress$jscomp$0.effectTag && + (returnFiber.lastEffect.nextEffect = workInProgress.firstEffect), + (returnFiber.lastEffect = workInProgress.lastEffect)), + 1 < workInProgress.effectTag && (null !== returnFiber.lastEffect - ? (returnFiber.lastEffect.nextEffect = workInProgress$jscomp$0) - : (returnFiber.firstEffect = workInProgress$jscomp$0), - (returnFiber.lastEffect = workInProgress$jscomp$0))); + ? (returnFiber.lastEffect.nextEffect = workInProgress) + : (returnFiber.firstEffect = workInProgress), + (returnFiber.lastEffect = workInProgress))); if (null !== siblingFiber) return siblingFiber; - if (null !== returnFiber) workInProgress$jscomp$0 = returnFiber; + if (null !== returnFiber) workInProgress = returnFiber; else { isRootReadyForCommit = !0; break; } } else { - workInProgress$jscomp$0 = unwindWork(workInProgress$jscomp$0); - if (null !== workInProgress$jscomp$0) - return ( - (workInProgress$jscomp$0.effectTag &= 2559), workInProgress$jscomp$0 - ); + workInProgress = unwindWork(workInProgress); + if (null !== workInProgress) + return (workInProgress.effectTag &= 511), workInProgress; null !== returnFiber && ((returnFiber.firstEffect = returnFiber.lastEffect = null), (returnFiber.effectTag |= 512)); if (null !== siblingFiber) return siblingFiber; - if (null !== returnFiber) workInProgress$jscomp$0 = returnFiber; + if (null !== returnFiber) workInProgress = returnFiber; else break; } } @@ -4696,13 +4761,18 @@ function ReactFiberScheduler(config) { break; } isAsync = nextUnitOfWork; - var returnFiber = isAsync["return"]; + var returnFiber = isAsync.return; if (null === returnFiber) { didFatal = !0; onUncaughtError(thrownValue); break; } - throwException(returnFiber, isAsync, thrownValue); + throwException( + returnFiber, + isAsync, + thrownValue, + nextRenderExpirationTime + ); nextUnitOfWork = completeUnitOfWork(isAsync); } break; @@ -4719,55 +4789,61 @@ function ReactFiberScheduler(config) { "Expired work should have completed. This error is likely caused by a bug in React. Please file an issue." ); } - function scheduleCapture(sourceFiber, boundaryFiber, value, expirationTime) { - sourceFiber = { - value: value, - source: sourceFiber, - stack: getStackAddendumByWorkInProgressFiber(sourceFiber) - }; - insertUpdateIntoFiber(boundaryFiber, { - expirationTime: expirationTime, - partialState: null, - callback: null, - isReplace: !1, - isForced: !1, - capturedValue: sourceFiber, - next: null - }); - scheduleWork(boundaryFiber, expirationTime); - } - function onCommitPhaseError(fiber$jscomp$0, error) { + function onCommitPhaseError(fiber, error) { + var JSCompiler_inline_result; a: { invariant( !isWorking || isCommitting, "dispatch: Cannot dispatch during the render phase." ); - for (var fiber = fiber$jscomp$0["return"]; null !== fiber; ) { - switch (fiber.tag) { + for ( + JSCompiler_inline_result = fiber.return; + null !== JSCompiler_inline_result; + + ) { + switch (JSCompiler_inline_result.tag) { case 2: - var instance = fiber.stateNode; + var instance = JSCompiler_inline_result.stateNode; if ( - "function" === typeof fiber.type.getDerivedStateFromCatch || + "function" === + typeof JSCompiler_inline_result.type.getDerivedStateFromCatch || ("function" === typeof instance.componentDidCatch && !isAlreadyFailedLegacyErrorBoundary(instance)) ) { - scheduleCapture(fiber$jscomp$0, fiber, error, 1); - fiber$jscomp$0 = void 0; + fiber = createCapturedValue(error, fiber); + fiber = createClassErrorUpdate( + JSCompiler_inline_result, + fiber, + 1 + ); + enqueueUpdate(JSCompiler_inline_result, fiber, 1); + scheduleWork(JSCompiler_inline_result, 1); + JSCompiler_inline_result = void 0; break a; } break; case 3: - scheduleCapture(fiber$jscomp$0, fiber, error, 1); - fiber$jscomp$0 = void 0; + fiber = createCapturedValue(error, fiber); + fiber = createRootErrorUpdate(JSCompiler_inline_result, fiber, 1); + enqueueUpdate(JSCompiler_inline_result, fiber, 1); + scheduleWork(JSCompiler_inline_result, 1); + JSCompiler_inline_result = void 0; break a; } - fiber = fiber["return"]; + JSCompiler_inline_result = JSCompiler_inline_result.return; } - 3 === fiber$jscomp$0.tag && - scheduleCapture(fiber$jscomp$0, fiber$jscomp$0, error, 1); - fiber$jscomp$0 = void 0; + 3 === fiber.tag && + ((JSCompiler_inline_result = createCapturedValue(error, fiber)), + (JSCompiler_inline_result = createRootErrorUpdate( + fiber, + JSCompiler_inline_result, + 1 + )), + enqueueUpdate(fiber, JSCompiler_inline_result, 1), + scheduleWork(fiber, 1)); + JSCompiler_inline_result = void 0; } - return fiber$jscomp$0; + return JSCompiler_inline_result; } function computeExpirationForFiber(fiber) { fiber = @@ -4795,7 +4871,7 @@ function ReactFiberScheduler(config) { (0 === fiber.alternate.expirationTime || fiber.alternate.expirationTime > expirationTime) && (fiber.alternate.expirationTime = expirationTime); - if (null === fiber["return"]) + if (null === fiber.return) if (3 === fiber.tag) { var root = fiber.stateNode; !isWorking && @@ -4813,7 +4889,7 @@ function ReactFiberScheduler(config) { expirationTime = void 0; break a; } - fiber = fiber["return"]; + fiber = fiber.return; } expirationTime = void 0; } @@ -5053,7 +5129,7 @@ function ReactFiberScheduler(config) { error = void 0; try { for (; null !== nextEffect; ) - nextEffect.effectTag & 2048 && + nextEffect.effectTag & 256 && commitBeforeMutationLifeCycles(nextEffect.alternate, nextEffect), (nextEffect = nextEffect.nextEffect); } catch (e) { @@ -5129,8 +5205,6 @@ function ReactFiberScheduler(config) { didError, error ); - effectTag$jscomp$0 & 256 && - commitErrorLogging(nextEffect, onUncaughtError); effectTag$jscomp$0 & 128 && commitAttachRef(nextEffect); var next = nextEffect.nextEffect; nextEffect.nextEffect = null; @@ -5193,21 +5267,21 @@ function ReactFiberScheduler(config) { legacyContext, stack, scheduleWork, - isAlreadyFailedLegacyErrorBoundary + markLegacyErrorBoundaryAsFailed, + isAlreadyFailedLegacyErrorBoundary, + onUncaughtError ); var throwException = hostContext.throwException, unwindWork = hostContext.unwindWork, - unwindInterruptedWork = hostContext.unwindInterruptedWork; + unwindInterruptedWork = hostContext.unwindInterruptedWork, + createRootErrorUpdate = hostContext.createRootErrorUpdate, + createClassErrorUpdate = hostContext.createClassErrorUpdate; hostContext = ReactFiberCommitWork( config, onCommitPhaseError, scheduleWork, computeExpirationForFiber, - function(instance) { - null === legacyErrorBoundariesThatAlreadyFailed - ? (legacyErrorBoundariesThatAlreadyFailed = new Set([instance])) - : legacyErrorBoundariesThatAlreadyFailed.add(instance); - }, + markLegacyErrorBoundaryAsFailed, recalculateCurrentTime ); var commitBeforeMutationLifeCycles = @@ -5217,7 +5291,6 @@ function ReactFiberScheduler(config) { commitDeletion = hostContext.commitDeletion, commitWork = hostContext.commitWork, commitLifeCycles = hostContext.commitLifeCycles, - commitErrorLogging = hostContext.commitErrorLogging, commitAttachRef = hostContext.commitAttachRef, commitDetachRef = hostContext.commitDetachRef, now = config.now, @@ -5385,15 +5458,11 @@ function ReactFiberReconciler$1(config) { ? (container.context = parentComponent) : (container.pendingContext = parentComponent); container = callback; - insertUpdateIntoFiber(currentTime, { - expirationTime: expirationTime, - partialState: { element: element }, - callback: void 0 === container ? null : container, - isReplace: !1, - isForced: !1, - capturedValue: null, - next: null - }); + callback = createUpdate(expirationTime); + callback.payload = { element: element }; + container = void 0 === container ? null : container; + null !== container && (callback.callback = container); + enqueueUpdate(currentTime, callback, expirationTime); scheduleWork(currentTime, expirationTime); return expirationTime; } @@ -5514,8 +5583,8 @@ var ReactFiberReconciler$2 = Object.freeze({ default: ReactFiberReconciler$1 }), ReactFiberReconciler$3 = (ReactFiberReconciler$2 && ReactFiberReconciler$1) || ReactFiberReconciler$2, - reactReconciler = ReactFiberReconciler$3["default"] - ? ReactFiberReconciler$3["default"] + reactReconciler = ReactFiberReconciler$3.default + ? ReactFiberReconciler$3.default : ReactFiberReconciler$3, nextReactTag = 2, ReactFabricHostComponent = (function() { @@ -5795,7 +5864,7 @@ var roots = new Map(), var root = roots.get(containerTag); root && ReactFabricRenderer.updateContainer(null, root, null, function() { - roots["delete"](containerTag); + roots.delete(containerTag); }); }, createPortal: function(children, containerTag) { @@ -5870,6 +5939,4 @@ ReactFabricRenderer.injectIntoDevTools({ }); var ReactFabric$2 = Object.freeze({ default: ReactFabric }), ReactFabric$3 = (ReactFabric$2 && ReactFabric) || ReactFabric$2; -module.exports = ReactFabric$3["default"] - ? ReactFabric$3["default"] - : ReactFabric$3; +module.exports = ReactFabric$3.default ? ReactFabric$3.default : ReactFabric$3; diff --git a/Libraries/Renderer/oss/ReactNativeRenderer-dev.js b/Libraries/Renderer/oss/ReactNativeRenderer-dev.js index 21d9a6c1d54399..6c6430d3eff196 100644 --- a/Libraries/Renderer/oss/ReactNativeRenderer-dev.js +++ b/Libraries/Renderer/oss/ReactNativeRenderer-dev.js @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. * * @noflow + * @providesModule ReactNativeRenderer-dev * @preventMunge */ @@ -26,9 +27,9 @@ var deepDiffer = require("deepDiffer"); var flattenStyle = require("flattenStyle"); var React = require("react"); var emptyObject = require("fbjs/lib/emptyObject"); +var checkPropTypes = require("prop-types/checkPropTypes"); var shallowEqual = require("fbjs/lib/shallowEqual"); var ExceptionsManager = require("ExceptionsManager"); -var checkPropTypes = require("prop-types/checkPropTypes"); var deepFreezeAndThrowOnMutationInDev = require("deepFreezeAndThrowOnMutationInDev"); var invokeGuardedCallback = function(name, func, context, a, b, c, d, e, f) { @@ -970,7 +971,7 @@ var ForwardRef = 14; function getParent(inst) { do { - inst = inst["return"]; + 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 @@ -2716,23 +2717,21 @@ RCTEventEmitter.register(ReactNativeEventEmitter); // 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 hasSymbol = typeof Symbol === "function" && Symbol.for; -var REACT_ELEMENT_TYPE = hasSymbol ? Symbol["for"]("react.element") : 0xeac7; -var REACT_CALL_TYPE = hasSymbol ? Symbol["for"]("react.call") : 0xeac8; -var REACT_RETURN_TYPE = hasSymbol ? Symbol["for"]("react.return") : 0xeac9; -var REACT_PORTAL_TYPE = hasSymbol ? Symbol["for"]("react.portal") : 0xeaca; -var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol["for"]("react.fragment") : 0xeacb; +var REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for("react.element") : 0xeac7; +var REACT_CALL_TYPE = hasSymbol ? Symbol.for("react.call") : 0xeac8; +var REACT_RETURN_TYPE = hasSymbol ? Symbol.for("react.return") : 0xeac9; +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") + ? Symbol.for("react.strict_mode") : 0xeacc; -var REACT_PROVIDER_TYPE = hasSymbol ? Symbol["for"]("react.provider") : 0xeacd; -var REACT_CONTEXT_TYPE = hasSymbol ? Symbol["for"]("react.context") : 0xeace; -var REACT_ASYNC_MODE_TYPE = hasSymbol - ? Symbol["for"]("react.async_mode") - : 0xeacf; +var REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for("react.provider") : 0xeacd; +var REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for("react.context") : 0xeace; +var REACT_ASYNC_MODE_TYPE = hasSymbol ? Symbol.for("react.async_mode") : 0xeacf; var REACT_FORWARD_REF_TYPE = hasSymbol - ? Symbol["for"]("react.forward_ref") + ? Symbol.for("react.forward_ref") : 0xead0; var MAYBE_ITERATOR_SYMBOL = typeof Symbol === "function" && Symbol.iterator; @@ -2847,7 +2846,7 @@ function getStackAddendumByWorkInProgressFiber(workInProgress) { do { info += describeFiber(node); // Otherwise this return pointer might point to the wrong tree: - node = node["return"]; + node = node.return; } while (node); return info; } @@ -3790,11 +3789,10 @@ var ContentReset = /* */ 16; var Callback = /* */ 32; var DidCapture = /* */ 64; var Ref = /* */ 128; -var ErrLog = /* */ 256; -var Snapshot = /* */ 2048; +var Snapshot = /* */ 256; // Union of all host effects -var HostEffectMask = /* */ 2559; +var HostEffectMask = /* */ 511; var Incomplete = /* */ 512; var ShouldCapture = /* */ 1024; @@ -3811,15 +3809,15 @@ function isFiberMountedImpl(fiber) { if ((node.effectTag & Placement) !== NoEffect) { return MOUNTING; } - while (node["return"]) { - node = node["return"]; + while (node.return) { + node = node.return; if ((node.effectTag & Placement) !== NoEffect) { return MOUNTING; } } } else { - while (node["return"]) { - node = node["return"]; + while (node.return) { + node = node.return; } } if (node.tag === HostRoot) { @@ -3891,7 +3889,7 @@ function findCurrentFiberUsingSlowPath(fiber) { var a = fiber; var b = alternate; while (true) { - var parentA = a["return"]; + var parentA = a.return; var parentB = parentA ? parentA.alternate : null; if (!parentA || !parentB) { // We're at the root. @@ -3921,7 +3919,7 @@ function findCurrentFiberUsingSlowPath(fiber) { invariant(false, "Unable to find node on an unmounted component."); } - if (a["return"] !== b["return"]) { + 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 @@ -4009,7 +4007,7 @@ function findCurrentHostFiber(parent) { if (node.tag === HostComponent || node.tag === HostText) { return node; } else if (node.child) { - node.child["return"] = node; + node.child.return = node; node = node.child; continue; } @@ -4017,12 +4015,12 @@ function findCurrentHostFiber(parent) { return null; } while (!node.sibling) { - if (!node["return"] || node["return"] === currentParent) { + if (!node.return || node.return === currentParent) { return null; } - node = node["return"]; + node = node.return; } - node.sibling["return"] = node["return"]; + node.sibling.return = node.return; node = node.sibling; } // Flow needs the return null here, but ESLint complains about it. @@ -4042,7 +4040,7 @@ function findCurrentHostFiberWithNoPortals(parent) { if (node.tag === HostComponent || node.tag === HostText) { return node; } else if (node.child && node.tag !== HostPortal) { - node.child["return"] = node; + node.child.return = node; node = node.child; continue; } @@ -4050,12 +4048,12 @@ function findCurrentHostFiberWithNoPortals(parent) { return null; } while (!node.sibling) { - if (!node["return"] || node["return"] === currentParent) { + if (!node.return || node.return === currentParent) { return null; } - node = node["return"]; + node = node.return; } - node.sibling["return"] = node["return"]; + node.sibling.return = node.return; node = node.sibling; } // Flow needs the return null here, but ESLint complains about it. @@ -4138,7 +4136,7 @@ function FiberNode(tag, pendingProps, key, mode) { this.stateNode = null; // Fiber - this["return"] = null; + this.return = null; this.child = null; this.sibling = null; this.index = 0; @@ -4423,7 +4421,7 @@ function assignFiberPropertiesInDEV(target, source) { target.key = source.key; target.type = source.type; target.stateNode = source.stateNode; - target["return"] = source["return"]; + target.return = source.return; target.child = source.child; target.sibling = source.sibling; target.index = source.index; @@ -4706,7 +4704,7 @@ var ReactStrictModeWarnings = { maybeStrictRoot = fiber; } - fiber = fiber["return"]; + fiber = fiber.return; } return maybeStrictRoot; @@ -4827,16 +4825,6 @@ var ReactStrictModeWarnings = { return; } - // Don't warn about react-lifecycles-compat polyfilled components. - // Note that it is sufficient to check for the presence of a - // single lifecycle, componentWillMount, with the polyfill flag. - if ( - typeof instance.componentWillMount === "function" && - instance.componentWillMount.__suppressDeprecationWarning === true - ) { - return; - } - var warningsForRoot = void 0; if (!pendingUnsafeLifecycleWarnings.has(strictRoot)) { warningsForRoot = { @@ -4852,19 +4840,23 @@ var ReactStrictModeWarnings = { var unsafeLifecycles = []; if ( - typeof instance.componentWillMount === "function" || + (typeof instance.componentWillMount === "function" && + instance.componentWillMount.__suppressDeprecationWarning !== true) || typeof instance.UNSAFE_componentWillMount === "function" ) { unsafeLifecycles.push("UNSAFE_componentWillMount"); } if ( - typeof instance.componentWillReceiveProps === "function" || + (typeof instance.componentWillReceiveProps === "function" && + instance.componentWillReceiveProps.__suppressDeprecationWarning !== + true) || typeof instance.UNSAFE_componentWillReceiveProps === "function" ) { unsafeLifecycles.push("UNSAFE_componentWillReceiveProps"); } if ( - typeof instance.componentWillUpdate === "function" || + (typeof instance.componentWillUpdate === "function" && + instance.componentWillUpdate.__suppressDeprecationWarning !== true) || typeof instance.UNSAFE_componentWillUpdate === "function" ) { unsafeLifecycles.push("UNSAFE_componentWillUpdate"); @@ -4904,7 +4896,7 @@ function getCurrentFiberOwnerName() { return null; } -function getCurrentFiberStackAddendum() { +function getCurrentFiberStackAddendum$1() { { var fiber = ReactDebugCurrentFiber.current; if (fiber === null) { @@ -4924,7 +4916,7 @@ function resetCurrentFiber() { } function setCurrentFiber(fiber) { - ReactDebugCurrentFrame.getCurrentStack = getCurrentFiberStackAddendum; + ReactDebugCurrentFrame.getCurrentStack = getCurrentFiberStackAddendum$1; ReactDebugCurrentFiber.current = fiber; ReactDebugCurrentFiber.phase = null; } @@ -4940,7 +4932,7 @@ var ReactDebugCurrentFiber = { setCurrentFiber: setCurrentFiber, setCurrentPhase: setCurrentPhase, getCurrentFiberOwnerName: getCurrentFiberOwnerName, - getCurrentFiberStackAddendum: getCurrentFiberStackAddendum + getCurrentFiberStackAddendum: getCurrentFiberStackAddendum$1 }; // Prefix measurements so that it's possible to filter them. @@ -5097,13 +5089,13 @@ var pauseTimers = function() { if (fiber._debugIsCurrentlyTiming) { endFiberMark(fiber, null, null); } - fiber = fiber["return"]; + fiber = fiber.return; } }; var resumeTimersRecursively = function(fiber) { - if (fiber["return"] !== null) { - resumeTimersRecursively(fiber["return"]); + if (fiber.return !== null) { + resumeTimersRecursively(fiber.return); } if (fiber._debugIsCurrentlyTiming) { beginFiberMark(fiber, null); @@ -5195,7 +5187,7 @@ function stopWorkTimer(fiber) { return; } // If we pause, its parent is the fiber to unwind from. - currentFiber = fiber["return"]; + currentFiber = fiber.return; if (!fiber._debugIsCurrentlyTiming) { return; } @@ -5210,7 +5202,7 @@ function stopFailedWorkTimer(fiber) { return; } // If we pause, its parent is the fiber to unwind from. - currentFiber = fiber["return"]; + currentFiber = fiber.return; if (!fiber._debugIsCurrentlyTiming) { return; } @@ -5400,100 +5392,232 @@ function stopCommitLifeCyclesTimer() { } } -var didWarnUpdateInsideUpdate = void 0; +// 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 is +// 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; +var didWarnUpdateInsideUpdate = void 0; +var currentlyProcessingQueue = void 0; +var resetCurrentlyProcessingQueue = void 0; { didWarnUpdateInsideUpdate = false; + currentlyProcessingQueue = null; + resetCurrentlyProcessingQueue = function() { + currentlyProcessingQueue = null; + }; } -// Callbacks are not validated until invocation - -// Singly linked-list of updates. When an update is scheduled, it is added to -// the queue of the current fiber and the work-in-progress fiber. The two queues -// are separate but they share a persistent structure. -// -// During reconciliation, updates are removed from the work-in-progress fiber, -// but they remain on the current fiber. That ensures that if a work-in-progress -// is aborted, the aborted updates are recovered by cloning from current. -// -// The work-in-progress queue is always a subset of the current queue. -// -// When the tree is committed, the work-in-progress becomes the current. - function createUpdateQueue(baseState) { var queue = { - baseState: baseState, expirationTime: NoWork, - first: null, - last: null, - callbackList: null, + baseState: baseState, + firstUpdate: null, + lastUpdate: null, + firstCapturedUpdate: null, + lastCapturedUpdate: null, + firstEffect: null, + lastEffect: null, + firstCapturedEffect: null, + lastCapturedEffect: null, + hasForceUpdate: false + }; + return queue; +} + +function cloneUpdateQueue(currentQueue) { + var queue = { + expirationTime: currentQueue.expirationTime, + 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, + hasForceUpdate: false, - isInitialized: false, - capturedValues: null + + firstEffect: null, + lastEffect: null, + + firstCapturedEffect: null, + lastCapturedEffect: null }; - { - queue.isProcessing = false; - } return queue; } -function insertUpdateIntoQueue(queue, update) { +function createUpdate(expirationTime) { + return { + expirationTime: expirationTime, + + tag: UpdateState, + payload: null, + callback: null, + + next: null, + nextEffect: null + }; +} + +function appendUpdateToQueue(queue, update, expirationTime) { // Append the update to the end of the list. - if (queue.last === null) { + if (queue.lastUpdate === null) { // Queue is empty - queue.first = queue.last = update; + queue.firstUpdate = queue.lastUpdate = update; } else { - queue.last.next = update; - queue.last = update; + queue.lastUpdate.next = update; + queue.lastUpdate = update; } if ( queue.expirationTime === NoWork || - queue.expirationTime > update.expirationTime + queue.expirationTime > expirationTime ) { - queue.expirationTime = update.expirationTime; + // The incoming update has the earliest expiration of any update in the + // queue. Update the queue's expiration time. + queue.expirationTime = expirationTime; } } -var q1 = void 0; -var q2 = void 0; -function ensureUpdateQueues(fiber) { - q1 = q2 = null; - // We'll have at least one and at most two distinct update queues. - var alternateFiber = fiber.alternate; - var queue1 = fiber.updateQueue; - if (queue1 === null) { - // TODO: We don't know what the base state will be until we begin work. - // It depends on which fiber is the next current. Initialize with an empty - // base state, then set to the memoizedState when rendering. Not super - // happy with this approach. - queue1 = fiber.updateQueue = createUpdateQueue(null); - } - +function enqueueUpdate(fiber, update, expirationTime) { + // Update queues are created lazily. + var alternate = fiber.alternate; + var queue1 = void 0; var queue2 = void 0; - if (alternateFiber !== null) { - queue2 = alternateFiber.updateQueue; - if (queue2 === null) { - queue2 = alternateFiber.updateQueue = createUpdateQueue(null); + if (alternate === null) { + // There's only one fiber. + queue1 = fiber.updateQueue; + queue2 = null; + if (queue1 === null) { + queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState); } } else { - queue2 = null; + // 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, expirationTime); + } 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, expirationTime); + appendUpdateToQueue(queue2, update, expirationTime); + } 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, expirationTime); + // But we still need to update the `lastUpdate` pointer of queue2. + queue2.lastUpdate = update; + } } - queue2 = queue2 !== queue1 ? queue2 : null; - - // Use module variables instead of returning a tuple - q1 = queue1; - q2 = queue2; -} - -function insertUpdateIntoFiber(fiber, update) { - ensureUpdateQueues(fiber); - var queue1 = q1; - var queue2 = q2; - // Warn if an update is scheduled from inside an updater function. { if ( - (queue1.isProcessing || (queue2 !== null && queue2.isProcessing)) && + fiber.tag === ClassComponent && + (currentlyProcessingQueue === queue1 || + (queue2 !== null && currentlyProcessingQueue === queue2)) && !didWarnUpdateInsideUpdate ) { warning( @@ -5506,225 +5630,328 @@ function insertUpdateIntoFiber(fiber, update) { didWarnUpdateInsideUpdate = true; } } +} - // If there's only one queue, add the update to that queue and exit. - if (queue2 === null) { - insertUpdateIntoQueue(queue1, update); - return; +function enqueueCapturedUpdate(workInProgress, update, renderExpirationTime) { + // 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 + ); } - // If either queue is empty, we need to add to both queues. - if (queue1.last === null || queue2.last === null) { - insertUpdateIntoQueue(queue1, update); - insertUpdateIntoQueue(queue2, update); - return; + // 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; + } + if ( + workInProgressQueue.expirationTime === NoWork || + workInProgressQueue.expirationTime > renderExpirationTime + ) { + // The incoming update has the earliest expiration of any update in the + // queue. Update the queue's expiration time. + workInProgressQueue.expirationTime = renderExpirationTime; } - - // If both lists are not empty, the last update is the same for both lists - // because of structural sharing. So, we should only append to one of - // the lists. - insertUpdateIntoQueue(queue1, update); - // But we still need to update the `last` pointer of queue2. - queue2.last = update; } -function getUpdateExpirationTime(fiber) { - switch (fiber.tag) { - case HostRoot: - case ClassComponent: - var updateQueue = fiber.updateQueue; - if (updateQueue === null) { - return NoWork; - } - return updateQueue.expirationTime; - default: - return NoWork; +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(update, instance, prevState, props) { - var partialState = update.partialState; - if (typeof partialState === "function") { - return partialState.call(instance, prevState, props); - } else { - return partialState; +function getStateFromUpdate( + workInProgress, + queue, + update, + prevState, + nextProps, + instance +) { + switch (update.tag) { + case ReplaceState: { + var _payload = update.payload; + if (typeof _payload === "function") { + // Updater function + { + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + _payload.call(instance, prevState, nextProps); + } + } + return _payload.call(instance, prevState, nextProps); + } + // 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 + { + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + _payload2.call(instance, prevState, nextProps); + } + } + partialState = _payload2.call(instance, prevState, nextProps); + } 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: { + queue.hasForceUpdate = true; + return prevState; + } } + return prevState; } function processUpdateQueue( - current, workInProgress, queue, - instance, props, + instance, renderExpirationTime ) { - if (current !== null && current.updateQueue === queue) { - // We need to create a work-in-progress queue, by cloning the current queue. - var currentQueue = queue; - queue = workInProgress.updateQueue = { - baseState: currentQueue.baseState, - expirationTime: currentQueue.expirationTime, - first: currentQueue.first, - last: currentQueue.last, - isInitialized: currentQueue.isInitialized, - capturedValues: currentQueue.capturedValues, - // These fields are no longer valid because they were already committed. - // Reset them. - callbackList: null, - hasForceUpdate: false - }; + if ( + queue.expirationTime === NoWork || + queue.expirationTime > renderExpirationTime + ) { + // Insufficient priority. Bailout. + return; } + queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue); + { - // Set this flag so we can warn if setState is called inside the update - // function of another setState. - queue.isProcessing = true; - } - - // Reset the remaining expiration time. If we skip over any updates, we'll - // increase this accordingly. - queue.expirationTime = NoWork; - - // TODO: We don't know what the base state will be until we begin work. - // It depends on which fiber is the next current. Initialize with an empty - // base state, then set to the memoizedState when rendering. Not super - // happy with this approach. - var state = void 0; - if (queue.isInitialized) { - state = queue.baseState; - } else { - state = queue.baseState = workInProgress.memoizedState; - queue.isInitialized = true; + currentlyProcessingQueue = queue; } - var dontMutatePrevState = true; - var update = queue.first; - var didSkip = false; + + // 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. - var remainingExpirationTime = queue.expirationTime; + 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 ( - remainingExpirationTime === NoWork || - remainingExpirationTime > updateExpirationTime + newExpirationTime === NoWork || + newExpirationTime > updateExpirationTime ) { - // Update the remaining expiration time. - queue.expirationTime = updateExpirationTime; + newExpirationTime = updateExpirationTime; } - if (!didSkip) { - didSkip = true; - queue.baseState = state; + } else { + // This update does have sufficient priority. 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; - continue; } + // Continue to the next update. + update = update.next; + } - // This update does have sufficient priority. - - // If no previous updates were skipped, drop this update from the queue by - // advancing the head of the list. - if (!didSkip) { - queue.first = update.next; - if (queue.first === null) { - queue.last = null; + // 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 === NoWork || + newExpirationTime > _updateExpirationTime + ) { + newExpirationTime = _updateExpirationTime; } - } - - // Invoke setState callback an extra time to help detect side-effects. - // Ignore the return value in this case. - if ( - debugRenderPhaseSideEffects || - (debugRenderPhaseSideEffectsForStrictMode && - workInProgress.mode & StrictMode) - ) { - getStateFromUpdate(update, instance, state, props); - } - - // Process the update - var _partialState = void 0; - if (update.isReplace) { - state = getStateFromUpdate(update, instance, state, props); - dontMutatePrevState = true; } else { - _partialState = getStateFromUpdate(update, instance, state, props); - if (_partialState) { - if (dontMutatePrevState) { - // $FlowFixMe: Idk how to type this properly. - state = Object.assign({}, state, _partialState); + // 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 { - state = Object.assign(state, _partialState); + queue.lastCapturedEffect.nextEffect = update; + queue.lastCapturedEffect = update; } - dontMutatePrevState = false; - } - } - if (update.isForced) { - queue.hasForceUpdate = true; - } - if (update.callback !== null) { - // Append to list of callbacks. - var _callbackList = queue.callbackList; - if (_callbackList === null) { - _callbackList = queue.callbackList = []; - } - _callbackList.push(update); - } - if (update.capturedValue !== null) { - var _capturedValues = queue.capturedValues; - if (_capturedValues === null) { - queue.capturedValues = [update.capturedValue]; - } else { - _capturedValues.push(update.capturedValue); } } update = update.next; } - if (queue.callbackList !== null) { + if (newFirstUpdate === null) { + queue.lastUpdate = null; + } + if (newFirstCapturedUpdate === null) { + queue.lastCapturedUpdate = null; + } else { workInProgress.effectTag |= Callback; - } else if ( - queue.first === null && - !queue.hasForceUpdate && - queue.capturedValues === null - ) { - // The queue is empty. We can reset it. - workInProgress.updateQueue = null; } - - if (!didSkip) { - didSkip = true; - queue.baseState = state; + 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; + queue.expirationTime = newExpirationTime; + + workInProgress.memoizedState = resultState; + { - // No longer processing. - queue.isProcessing = false; + currentlyProcessingQueue = null; } +} - return state; +function callCallback(callback, context) { + invariant( + typeof callback === "function", + "Invalid argument passed as callback. Expected a function. Instead " + + "received: %s", + callback + ); + callback.call(context); } -function commitCallbacks(queue, context) { - var callbackList = queue.callbackList; - if (callbackList === null) { - return; +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; } - // Set the list to null to make sure they don't get called more than once. - queue.callbackList = null; - for (var i = 0; i < callbackList.length; i++) { - var update = callbackList[i]; - var _callback = update.callback; - // This update might be processed again. Clear the callback so it's only - // called once. - update.callback = null; - invariant( - typeof _callback === "function", - "Invalid argument passed as callback. Expected a function. Instead " + - "received: %s", - _callback - ); - _callback.call(context); + + // Commit the effects + var effect = finishedQueue.firstEffect; + finishedQueue.firstEffect = finishedQueue.lastEffect = null; + while (effect !== null) { + var _callback3 = effect.callback; + if (_callback3 !== null) { + effect.callback = null; + callCallback(_callback3, instance); + } + effect = effect.nextEffect; + } + + effect = finishedQueue.firstCapturedEffect; + finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null; + while (effect !== null) { + var _callback4 = effect.callback; + if (_callback4 !== null) { + effect.callback = null; + callCallback(_callback4, instance); + } + effect = effect.nextEffect; } } @@ -5732,18 +5959,19 @@ var fakeInternalInstance = {}; var isArray = Array.isArray; var didWarnAboutStateAssignmentForComponent = void 0; -var didWarnAboutUndefinedDerivedState = 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; { didWarnAboutStateAssignmentForComponent = new Set(); - didWarnAboutUndefinedDerivedState = new Set(); didWarnAboutUninitializedState = new Set(); didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = new Set(); didWarnAboutLegacyLifecyclesAndDerivedState = new Set(); + didWarnAboutUndefinedDerivedState = new Set(); var didWarnOnInvalidCallback = new Set(); @@ -5764,6 +5992,21 @@ var warnOnInvalidCallback = void 0; } }; + warnOnUndefinedDerivedState = function(workInProgress, partialState) { + if (partialState === undefined) { + var componentName = getComponentName(workInProgress) || "Component"; + if (!didWarnAboutUndefinedDerivedState.has(componentName)) { + didWarnAboutUndefinedDerivedState.add(componentName); + warning( + 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, @@ -5785,17 +6028,43 @@ var warnOnInvalidCallback = void 0; }); Object.freeze(fakeInternalInstance); } -function callGetDerivedStateFromCatch(ctor, capturedValues) { - var resultState = {}; - for (var i = 0; i < capturedValues.length; i++) { - var capturedValue = capturedValues[i]; - var error = capturedValue.value; - var partialState = ctor.getDerivedStateFromCatch.call(null, error); - if (partialState !== null && partialState !== undefined) { - Object.assign(resultState, partialState); + +function applyDerivedStateFromProps( + workInProgress, + 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); } } - return resultState; + + var partialState = getDerivedStateFromProps(nextProps, prevState); + + { + warnOnUndefinedDerivedState(workInProgress, 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 && updateQueue.expirationTime === NoWork) { + updateQueue.baseState = memoizedState; + } } var ReactFiberClassComponent = function( @@ -5811,65 +6080,57 @@ var ReactFiberClassComponent = function( isContextConsumer = legacyContext.isContextConsumer, hasContextChanged = legacyContext.hasContextChanged; - // Class component state updater - - var updater = { + var classComponentUpdater = { isMounted: isMounted, - enqueueSetState: function(instance, partialState, callback) { - var fiber = get$1(instance); - callback = callback === undefined ? null : callback; - { - warnOnInvalidCallback(callback, "setState"); - } + enqueueSetState: function(inst, payload, callback) { + var fiber = get$1(inst); var expirationTime = computeExpirationForFiber(fiber); - var update = { - expirationTime: expirationTime, - partialState: partialState, - callback: callback, - isReplace: false, - isForced: false, - capturedValue: null, - next: null - }; - insertUpdateIntoFiber(fiber, update); + + var update = createUpdate(expirationTime); + update.payload = payload; + if (callback !== undefined && callback !== null) { + { + warnOnInvalidCallback(callback, "setState"); + } + update.callback = callback; + } + + enqueueUpdate(fiber, update, expirationTime); scheduleWork(fiber, expirationTime); }, - enqueueReplaceState: function(instance, state, callback) { - var fiber = get$1(instance); - callback = callback === undefined ? null : callback; - { - warnOnInvalidCallback(callback, "replaceState"); - } + enqueueReplaceState: function(inst, payload, callback) { + var fiber = get$1(inst); var expirationTime = computeExpirationForFiber(fiber); - var update = { - expirationTime: expirationTime, - partialState: state, - callback: callback, - isReplace: true, - isForced: false, - capturedValue: null, - next: null - }; - insertUpdateIntoFiber(fiber, update); + + var update = createUpdate(expirationTime); + update.tag = ReplaceState; + update.payload = payload; + + if (callback !== undefined && callback !== null) { + { + warnOnInvalidCallback(callback, "replaceState"); + } + update.callback = callback; + } + + enqueueUpdate(fiber, update, expirationTime); scheduleWork(fiber, expirationTime); }, - enqueueForceUpdate: function(instance, callback) { - var fiber = get$1(instance); - callback = callback === undefined ? null : callback; - { - warnOnInvalidCallback(callback, "forceUpdate"); - } + enqueueForceUpdate: function(inst, callback) { + var fiber = get$1(inst); var expirationTime = computeExpirationForFiber(fiber); - var update = { - expirationTime: expirationTime, - partialState: null, - callback: callback, - isReplace: false, - isForced: true, - capturedValue: null, - next: null - }; - insertUpdateIntoFiber(fiber, update); + + var update = createUpdate(expirationTime); + update.tag = ForceUpdate; + + if (callback !== undefined && callback !== null) { + { + warnOnInvalidCallback(callback, "forceUpdate"); + } + update.callback = callback; + } + + enqueueUpdate(fiber, update, expirationTime); scheduleWork(fiber, expirationTime); } }; @@ -5883,11 +6144,10 @@ var ReactFiberClassComponent = function( newContext ) { if ( - oldProps === null || - (workInProgress.updateQueue !== null && - workInProgress.updateQueue.hasForceUpdate) + workInProgress.updateQueue !== null && + workInProgress.updateQueue.hasForceUpdate ) { - // If the workInProgress already has an Update effect, return true + // If forceUpdate was called, disregard sCU. return true; } @@ -6144,13 +6404,8 @@ var ReactFiberClassComponent = function( } } - function resetInputPointers(workInProgress, instance) { - instance.props = workInProgress.memoizedProps; - instance.state = workInProgress.memoizedState; - } - function adoptClassInstance(workInProgress, instance) { - instance.updater = updater; + instance.updater = classComponentUpdater; workInProgress.stateNode = instance; // The instance needs access to the fiber so that it can schedule updates set(instance, workInProgress); @@ -6159,7 +6414,7 @@ var ReactFiberClassComponent = function( } } - function constructClassInstance(workInProgress, props) { + function constructClassInstance(workInProgress, props, renderExpirationTime) { var ctor = workInProgress.type; var unmaskedContext = getUnmaskedContext(workInProgress); var needsContext = isContextConsumer(workInProgress); @@ -6168,19 +6423,21 @@ var ReactFiberClassComponent = function( : emptyObject; // Instantiate twice to help detect side-effects. - if ( - debugRenderPhaseSideEffects || - (debugRenderPhaseSideEffectsForStrictMode && - workInProgress.mode & StrictMode) - ) { - new ctor(props, context); // eslint-disable-line no-new + { + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + new ctor(props, context); // eslint-disable-line no-new + } } var instance = new ctor(props, context); - var state = + var state = (workInProgress.memoizedState = instance.state !== null && instance.state !== undefined ? instance.state - : null; + : null); adoptClassInstance(workInProgress, instance); { @@ -6271,26 +6528,6 @@ var ReactFiberClassComponent = function( } } - workInProgress.memoizedState = state; - - var partialState = callGetDerivedStateFromProps( - workInProgress, - instance, - props, - state - ); - - if (partialState !== null && partialState !== undefined) { - // Render-phase updates (like this) should not be added to the update queue, - // So that multiple render passes do not enqueue multiple updates. - // Instead, just synchronously merge the returned state into the instance. - workInProgress.memoizedState = Object.assign( - {}, - workInProgress.memoizedState, - partialState - ); - } - // 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 (needsContext) { @@ -6323,7 +6560,7 @@ var ReactFiberClassComponent = function( getComponentName(workInProgress) || "Component" ); } - updater.enqueueReplaceState(instance, instance.state, null); + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); } } @@ -6357,57 +6594,13 @@ var ReactFiberClassComponent = function( ); } } - updater.enqueueReplaceState(instance, instance.state, null); - } - } - - function callGetDerivedStateFromProps( - workInProgress, - instance, - nextProps, - prevState - ) { - var type = workInProgress.type; - - if (typeof type.getDerivedStateFromProps === "function") { - if ( - debugRenderPhaseSideEffects || - (debugRenderPhaseSideEffectsForStrictMode && - workInProgress.mode & StrictMode) - ) { - // Invoke method an extra time to help detect side-effects. - type.getDerivedStateFromProps.call(null, nextProps, prevState); - } - - var partialState = type.getDerivedStateFromProps.call( - null, - nextProps, - prevState - ); - - { - if (partialState === undefined) { - var componentName = getComponentName(workInProgress) || "Component"; - if (!didWarnAboutUndefinedDerivedState.has(componentName)) { - didWarnAboutUndefinedDerivedState.add(componentName); - warning( - false, - "%s.getDerivedStateFromProps(): A valid state object (or null) must be returned. " + - "You have returned undefined.", - componentName - ); - } - } - } - - return partialState; + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); } } // Invokes the mount life-cycles on a previously never rendered instance. function mountClassInstance(workInProgress, renderExpirationTime) { var ctor = workInProgress.type; - var current = workInProgress.alternate; { checkClassInstance(workInProgress); @@ -6438,6 +6631,28 @@ var ReactFiberClassComponent = function( } } + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + processUpdateQueue( + workInProgress, + updateQueue, + props, + instance, + renderExpirationTime + ); + instance.state = workInProgress.memoizedState; + } + + var getDerivedStateFromProps = workInProgress.type.getDerivedStateFromProps; + if (typeof getDerivedStateFromProps === "function") { + applyDerivedStateFromProps( + workInProgress, + getDerivedStateFromProps, + props + ); + 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 ( @@ -6449,18 +6664,19 @@ var ReactFiberClassComponent = function( callComponentWillMount(workInProgress, instance); // If we had additional state updates during this life-cycle, let's // process them now. - var updateQueue = workInProgress.updateQueue; + updateQueue = workInProgress.updateQueue; if (updateQueue !== null) { - instance.state = processUpdateQueue( - current, + processUpdateQueue( workInProgress, updateQueue, - instance, props, + instance, renderExpirationTime ); + instance.state = workInProgress.memoizedState; } } + if (typeof instance.componentDidMount === "function") { workInProgress.effectTag |= Update; } @@ -6469,16 +6685,18 @@ var ReactFiberClassComponent = function( function resumeMountClassInstance(workInProgress, renderExpirationTime) { var ctor = workInProgress.type; var instance = workInProgress.stateNode; - resetInputPointers(workInProgress, instance); var oldProps = workInProgress.memoizedProps; var newProps = workInProgress.pendingProps; + instance.props = oldProps; + var oldContext = instance.context; var newUnmaskedContext = getUnmaskedContext(workInProgress); var newContext = getMaskedContext(workInProgress, newUnmaskedContext); + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; var hasNewLifecycles = - typeof ctor.getDerivedStateFromProps === "function" || + typeof getDerivedStateFromProps === "function" || typeof instance.getSnapshotBeforeUpdate === "function"; // Note: During these life-cycles, instance.props/instance.state are what @@ -6502,93 +6720,27 @@ var ReactFiberClassComponent = function( } } - // Compute the next state using the memoized state and the update queue. var oldState = workInProgress.memoizedState; - // TODO: Previous state can be null. - var newState = void 0; - var derivedStateFromCatch = void 0; - if (workInProgress.updateQueue !== null) { - newState = processUpdateQueue( - null, + var newState = (instance.state = oldState); + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + processUpdateQueue( workInProgress, - workInProgress.updateQueue, - instance, + updateQueue, newProps, + instance, renderExpirationTime ); - - var updateQueue = workInProgress.updateQueue; - if ( - updateQueue !== null && - updateQueue.capturedValues !== null && - enableGetDerivedStateFromCatch && - typeof ctor.getDerivedStateFromCatch === "function" - ) { - var capturedValues = updateQueue.capturedValues; - // Don't remove these from the update queue yet. We need them in - // finishClassComponent. Do the reset there. - // TODO: This is awkward. Refactor class components. - // updateQueue.capturedValues = null; - derivedStateFromCatch = callGetDerivedStateFromCatch( - ctor, - capturedValues - ); - } - } else { - newState = oldState; + newState = workInProgress.memoizedState; } - var derivedStateFromProps = void 0; - if (oldProps !== newProps) { - // The prevState parameter should be the partially updated state. - // Otherwise, spreading state in return values could override updates. - derivedStateFromProps = callGetDerivedStateFromProps( + if (typeof getDerivedStateFromProps === "function") { + applyDerivedStateFromProps( workInProgress, - instance, - newProps, - newState + getDerivedStateFromProps, + newProps ); - } - - if (derivedStateFromProps !== null && derivedStateFromProps !== undefined) { - // Render-phase updates (like this) should not be added to the update queue, - // So that multiple render passes do not enqueue multiple updates. - // Instead, just synchronously merge the returned state into the instance. - newState = - newState === null || newState === undefined - ? derivedStateFromProps - : Object.assign({}, newState, derivedStateFromProps); - - // Update the base state of the update queue. - // FIXME: This is getting ridiculous. Refactor plz! - var _updateQueue = workInProgress.updateQueue; - if (_updateQueue !== null) { - _updateQueue.baseState = Object.assign( - {}, - _updateQueue.baseState, - derivedStateFromProps - ); - } - } - if (derivedStateFromCatch !== null && derivedStateFromCatch !== undefined) { - // Render-phase updates (like this) should not be added to the update queue, - // So that multiple render passes do not enqueue multiple updates. - // Instead, just synchronously merge the returned state into the instance. - newState = - newState === null || newState === undefined - ? derivedStateFromCatch - : Object.assign({}, newState, derivedStateFromCatch); - - // Update the base state of the update queue. - // FIXME: This is getting ridiculous. Refactor plz! - var _updateQueue2 = workInProgress.updateQueue; - if (_updateQueue2 !== null) { - _updateQueue2.baseState = Object.assign( - {}, - _updateQueue2.baseState, - derivedStateFromCatch - ); - } + newState = workInProgress.memoizedState; } if ( @@ -6645,9 +6797,9 @@ var ReactFiberClassComponent = function( } // If shouldComponentUpdate returned false, we should still update the - // memoized props/state to indicate that this work can be reused. - memoizeProps(workInProgress, newProps); - memoizeState(workInProgress, newState); + // 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 @@ -6663,16 +6815,18 @@ var ReactFiberClassComponent = function( function updateClassInstance(current, workInProgress, renderExpirationTime) { var ctor = workInProgress.type; var instance = workInProgress.stateNode; - resetInputPointers(workInProgress, instance); var oldProps = workInProgress.memoizedProps; var newProps = workInProgress.pendingProps; + instance.props = oldProps; + var oldContext = instance.context; var newUnmaskedContext = getUnmaskedContext(workInProgress); var newContext = getMaskedContext(workInProgress, newUnmaskedContext); + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; var hasNewLifecycles = - typeof ctor.getDerivedStateFromProps === "function" || + typeof getDerivedStateFromProps === "function" || typeof instance.getSnapshotBeforeUpdate === "function"; // Note: During these life-cycles, instance.props/instance.state are what @@ -6696,94 +6850,27 @@ var ReactFiberClassComponent = function( } } - // Compute the next state using the memoized state and the update queue. var oldState = workInProgress.memoizedState; - // TODO: Previous state can be null. - var newState = void 0; - var derivedStateFromCatch = void 0; - - if (workInProgress.updateQueue !== null) { - newState = processUpdateQueue( - current, + var newState = (instance.state = oldState); + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + processUpdateQueue( workInProgress, - workInProgress.updateQueue, - instance, + updateQueue, newProps, + instance, renderExpirationTime ); - - var updateQueue = workInProgress.updateQueue; - if ( - updateQueue !== null && - updateQueue.capturedValues !== null && - enableGetDerivedStateFromCatch && - typeof ctor.getDerivedStateFromCatch === "function" - ) { - var capturedValues = updateQueue.capturedValues; - // Don't remove these from the update queue yet. We need them in - // finishClassComponent. Do the reset there. - // TODO: This is awkward. Refactor class components. - // updateQueue.capturedValues = null; - derivedStateFromCatch = callGetDerivedStateFromCatch( - ctor, - capturedValues - ); - } - } else { - newState = oldState; + newState = workInProgress.memoizedState; } - var derivedStateFromProps = void 0; - if (oldProps !== newProps) { - // The prevState parameter should be the partially updated state. - // Otherwise, spreading state in return values could override updates. - derivedStateFromProps = callGetDerivedStateFromProps( + if (typeof getDerivedStateFromProps === "function") { + applyDerivedStateFromProps( workInProgress, - instance, - newProps, - newState + getDerivedStateFromProps, + newProps ); - } - - if (derivedStateFromProps !== null && derivedStateFromProps !== undefined) { - // Render-phase updates (like this) should not be added to the update queue, - // So that multiple render passes do not enqueue multiple updates. - // Instead, just synchronously merge the returned state into the instance. - newState = - newState === null || newState === undefined - ? derivedStateFromProps - : Object.assign({}, newState, derivedStateFromProps); - - // Update the base state of the update queue. - // FIXME: This is getting ridiculous. Refactor plz! - var _updateQueue3 = workInProgress.updateQueue; - if (_updateQueue3 !== null) { - _updateQueue3.baseState = Object.assign( - {}, - _updateQueue3.baseState, - derivedStateFromProps - ); - } - } - if (derivedStateFromCatch !== null && derivedStateFromCatch !== undefined) { - // Render-phase updates (like this) should not be added to the update queue, - // So that multiple render passes do not enqueue multiple updates. - // Instead, just synchronously merge the returned state into the instance. - newState = - newState === null || newState === undefined - ? derivedStateFromCatch - : Object.assign({}, newState, derivedStateFromCatch); - - // Update the base state of the update queue. - // FIXME: This is getting ridiculous. Refactor plz! - var _updateQueue4 = workInProgress.updateQueue; - if (_updateQueue4 !== null) { - _updateQueue4.baseState = Object.assign( - {}, - _updateQueue4.baseState, - derivedStateFromCatch - ); - } + newState = workInProgress.memoizedState; } if ( @@ -6870,8 +6957,8 @@ var ReactFiberClassComponent = function( // If shouldComponentUpdate returned false, we should still update the // memoized props/state to indicate that this work can be reused. - memoizeProps(workInProgress, newProps); - memoizeState(workInProgress, newState); + workInProgress.memoizedProps = newProps; + workInProgress.memoizedState = newState; } // Update the existing instance's state, props, and context pointers even @@ -6885,7 +6972,6 @@ var ReactFiberClassComponent = function( return { adoptClassInstance: adoptClassInstance, - callGetDerivedStateFromProps: callGetDerivedStateFromProps, constructClassInstance: constructClassInstance, mountClassInstance: mountClassInstance, resumeMountClassInstance: resumeMountClassInstance, @@ -6893,7 +6979,7 @@ var ReactFiberClassComponent = function( }; }; -var getCurrentFiberStackAddendum$1 = +var getCurrentFiberStackAddendum$2 = ReactDebugCurrentFiber.getCurrentFiberStackAddendum; var didWarnAboutMaps = void 0; @@ -6932,7 +7018,7 @@ var warnForMissingKey = function(child) {}; "Each child in an array or iterator should have a unique " + '"key" prop. See https://fb.me/react-warning-keys for ' + "more information." + - (getCurrentFiberStackAddendum$1() || ""); + (getCurrentFiberStackAddendum$2() || ""); if (ownerHasKeyUseWarning[currentComponentErrorInfo]) { return; } @@ -6943,7 +7029,7 @@ var warnForMissingKey = function(child) {}; "Each child in an array or iterator should have a unique " + '"key" prop. See https://fb.me/react-warning-keys for ' + "more information.%s", - getCurrentFiberStackAddendum$1() + getCurrentFiberStackAddendum$2() ); }; } @@ -7040,7 +7126,7 @@ function throwOnInvalidObjectType(returnFiber, newChild) { addendum = " If you meant to render a collection of children, use an array " + "instead." + - (getCurrentFiberStackAddendum$1() || ""); + (getCurrentFiberStackAddendum$2() || ""); } invariant( false, @@ -7058,7 +7144,7 @@ function warnOnFunctionType() { "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." + - (getCurrentFiberStackAddendum$1() || ""); + (getCurrentFiberStackAddendum$2() || ""); if (ownerHasFunctionTypeWarning[currentComponentErrorInfo]) { return; @@ -7070,7 +7156,7 @@ function warnOnFunctionType() { "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.%s", - getCurrentFiberStackAddendum$1() || "" + getCurrentFiberStackAddendum$2() || "" ); } @@ -7183,12 +7269,12 @@ function ChildReconciler(shouldTrackSideEffects) { returnFiber.mode, expirationTime ); - created["return"] = returnFiber; + created.return = returnFiber; return created; } else { // Update var existing = useFiber(current, textContent, expirationTime); - existing["return"] = returnFiber; + existing.return = returnFiber; return existing; } } @@ -7198,7 +7284,7 @@ function ChildReconciler(shouldTrackSideEffects) { // Move based on index var existing = useFiber(current, element.props, expirationTime); existing.ref = coerceRef(returnFiber, current, element); - existing["return"] = returnFiber; + existing.return = returnFiber; { existing._debugSource = element._source; existing._debugOwner = element._owner; @@ -7212,7 +7298,7 @@ function ChildReconciler(shouldTrackSideEffects) { expirationTime ); created.ref = coerceRef(returnFiber, current, element); - created["return"] = returnFiber; + created.return = returnFiber; return created; } } @@ -7230,12 +7316,12 @@ function ChildReconciler(shouldTrackSideEffects) { returnFiber.mode, expirationTime ); - created["return"] = returnFiber; + created.return = returnFiber; return created; } else { // Update var existing = useFiber(current, portal.children || [], expirationTime); - existing["return"] = returnFiber; + existing.return = returnFiber; return existing; } } @@ -7249,12 +7335,12 @@ function ChildReconciler(shouldTrackSideEffects) { expirationTime, key ); - created["return"] = returnFiber; + created.return = returnFiber; return created; } else { // Update var existing = useFiber(current, fragment, expirationTime); - existing["return"] = returnFiber; + existing.return = returnFiber; return existing; } } @@ -7269,7 +7355,7 @@ function ChildReconciler(shouldTrackSideEffects) { returnFiber.mode, expirationTime ); - created["return"] = returnFiber; + created.return = returnFiber; return created; } @@ -7282,7 +7368,7 @@ function ChildReconciler(shouldTrackSideEffects) { expirationTime ); _created.ref = coerceRef(returnFiber, null, newChild); - _created["return"] = returnFiber; + _created.return = returnFiber; return _created; } case REACT_PORTAL_TYPE: { @@ -7291,7 +7377,7 @@ function ChildReconciler(shouldTrackSideEffects) { returnFiber.mode, expirationTime ); - _created2["return"] = returnFiber; + _created2.return = returnFiber; return _created2; } } @@ -7303,7 +7389,7 @@ function ChildReconciler(shouldTrackSideEffects) { expirationTime, null ); - _created3["return"] = returnFiber; + _created3.return = returnFiber; return _created3; } @@ -7514,7 +7600,7 @@ function ChildReconciler(shouldTrackSideEffects) { "duplicated and/or omitted — the behavior is unsupported and " + "could change in a future version.%s", key, - getCurrentFiberStackAddendum$1() + getCurrentFiberStackAddendum$2() ); break; default: @@ -7659,7 +7745,7 @@ function ChildReconciler(shouldTrackSideEffects) { // 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"]( + existingChildren.delete( _newFiber2.key === null ? newIdx : _newFiber2.key ); } @@ -7712,7 +7798,7 @@ function ChildReconciler(shouldTrackSideEffects) { "Using Maps as children is unsupported and will likely yield " + "unexpected results. Convert it to a sequence/iterable of keyed " + "ReactElements instead.%s", - getCurrentFiberStackAddendum$1() + getCurrentFiberStackAddendum$2() ) : void 0; didWarnAboutMaps = true; @@ -7838,7 +7924,7 @@ function ChildReconciler(shouldTrackSideEffects) { // 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"]( + existingChildren.delete( _newFiber4.key === null ? newIdx : _newFiber4.key ); } @@ -7877,7 +7963,7 @@ function ChildReconciler(shouldTrackSideEffects) { // the rest. deleteRemainingChildren(returnFiber, currentFirstChild.sibling); var existing = useFiber(currentFirstChild, textContent, expirationTime); - existing["return"] = returnFiber; + existing.return = returnFiber; return existing; } // The existing first child is not a text node so we need to create one @@ -7888,7 +7974,7 @@ function ChildReconciler(shouldTrackSideEffects) { returnFiber.mode, expirationTime ); - created["return"] = returnFiber; + created.return = returnFiber; return created; } @@ -7918,7 +8004,7 @@ function ChildReconciler(shouldTrackSideEffects) { expirationTime ); existing.ref = coerceRef(returnFiber, child, element); - existing["return"] = returnFiber; + existing.return = returnFiber; { existing._debugSource = element._source; existing._debugOwner = element._owner; @@ -7941,7 +8027,7 @@ function ChildReconciler(shouldTrackSideEffects) { expirationTime, element.key ); - created["return"] = returnFiber; + created.return = returnFiber; return created; } else { var _created4 = createFiberFromElement( @@ -7950,7 +8036,7 @@ function ChildReconciler(shouldTrackSideEffects) { expirationTime ); _created4.ref = coerceRef(returnFiber, currentFirstChild, element); - _created4["return"] = returnFiber; + _created4.return = returnFiber; return _created4; } } @@ -7974,7 +8060,7 @@ function ChildReconciler(shouldTrackSideEffects) { ) { deleteRemainingChildren(returnFiber, child.sibling); var existing = useFiber(child, portal.children || [], expirationTime); - existing["return"] = returnFiber; + existing.return = returnFiber; return existing; } else { deleteRemainingChildren(returnFiber, child); @@ -7991,7 +8077,7 @@ function ChildReconciler(shouldTrackSideEffects) { returnFiber.mode, expirationTime ); - created["return"] = returnFiber; + created.return = returnFiber; return created; } @@ -8143,7 +8229,7 @@ function cloneChildFibers(current, workInProgress) { ); workInProgress.child = newChild; - newChild["return"] = workInProgress; + newChild.return = workInProgress; while (currentChild.sibling !== null) { currentChild = currentChild.sibling; newChild = newChild.sibling = createWorkInProgress( @@ -8151,11 +8237,14 @@ function cloneChildFibers(current, workInProgress) { currentChild.pendingProps, currentChild.expirationTime ); - newChild["return"] = workInProgress; + newChild.return = workInProgress; } newChild.sibling = null; } +var getCurrentFiberStackAddendum = + ReactDebugCurrentFiber.getCurrentFiberStackAddendum; + var didWarnAboutBadClass = void 0; var didWarnAboutGetDerivedStateOnFunctionalComponent = void 0; var didWarnAboutStatelessRefs = void 0; @@ -8199,8 +8288,6 @@ var ReactFiberBeginWork = function( memoizeState ), adoptClassInstance = _ReactFiberClassCompo.adoptClassInstance, - callGetDerivedStateFromProps = - _ReactFiberClassCompo.callGetDerivedStateFromProps, constructClassInstance = _ReactFiberClassCompo.constructClassInstance, mountClassInstance = _ReactFiberClassCompo.mountClassInstance, resumeMountClassInstance = _ReactFiberClassCompo.resumeMountClassInstance, @@ -8252,9 +8339,20 @@ var ReactFiberBeginWork = function( function updateForwardRef(current, workInProgress) { var render = workInProgress.type.render; - var nextChildren = render(workInProgress.pendingProps, workInProgress.ref); + var nextProps = workInProgress.pendingProps; + var ref = workInProgress.ref; + if (hasLegacyContextChanged()) { + // Normally we can bail out on props equality but if context has changed + // we don't do the bailout and we have to reuse existing props instead. + } else if (workInProgress.memoizedProps === nextProps) { + var currentRef = current !== null ? current.ref : null; + if (ref === currentRef) { + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + } + var nextChildren = render(nextProps, ref); reconcileChildren(current, workInProgress, nextChildren); - memoizeProps(workInProgress, nextChildren); + memoizeProps(workInProgress, nextProps); return workInProgress.child; } @@ -8340,7 +8438,11 @@ var ReactFiberBeginWork = function( if (current === null) { if (workInProgress.stateNode === null) { // In the initial pass we might need to construct the instance. - constructClassInstance(workInProgress, workInProgress.pendingProps); + constructClassInstance( + workInProgress, + workInProgress.pendingProps, + renderExpirationTime + ); mountClassInstance(workInProgress, renderExpirationTime); shouldUpdate = true; @@ -8358,22 +8460,11 @@ var ReactFiberBeginWork = function( renderExpirationTime ); } - - // We processed the update queue inside updateClassInstance. It may have - // included some errors that were dispatched during the commit phase. - // TODO: Refactor class components so this is less awkward. - var didCaptureError = false; - var updateQueue = workInProgress.updateQueue; - if (updateQueue !== null && updateQueue.capturedValues !== null) { - shouldUpdate = true; - didCaptureError = true; - } return finishClassComponent( current, workInProgress, shouldUpdate, hasContext, - didCaptureError, renderExpirationTime ); } @@ -8383,12 +8474,13 @@ var ReactFiberBeginWork = function( workInProgress, shouldUpdate, hasContext, - didCaptureError, renderExpirationTime ) { // Refs should update even if shouldComponentUpdate returns false markRef(current, workInProgress); + var didCaptureError = (workInProgress.effectTag & DidCapture) !== NoEffect; + if (!shouldUpdate && !didCaptureError) { // Context providers should defer to sCU for rendering if (hasContext) { @@ -8484,29 +8576,26 @@ var ReactFiberBeginWork = function( pushHostRootContext(workInProgress); var updateQueue = workInProgress.updateQueue; if (updateQueue !== null) { + var nextProps = workInProgress.pendingProps; var prevState = workInProgress.memoizedState; - var state = processUpdateQueue( - current, + var prevChildren = prevState !== null ? prevState.element : null; + processUpdateQueue( workInProgress, updateQueue, - null, + nextProps, null, renderExpirationTime ); - memoizeState(workInProgress, state); - updateQueue = workInProgress.updateQueue; + var nextState = workInProgress.memoizedState; + // Caution: React DevTools currently depends on this property + // being called "element". + var nextChildren = nextState.element; - var element = void 0; - if (updateQueue !== null && updateQueue.capturedValues !== null) { - // There's an uncaught error. Unmount the whole root. - element = null; - } else if (prevState === state) { + 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, workInProgress); - } else { - element = state.element; } var root = workInProgress.stateNode; if ( @@ -8531,16 +8620,15 @@ var ReactFiberBeginWork = function( workInProgress.child = mountChildFibers( workInProgress, null, - element, + nextChildren, renderExpirationTime ); } else { // Otherwise reset hydration state in case we aborted and resumed another // root. resetHydrationState(); - reconcileChildren(current, workInProgress, element); + reconcileChildren(current, workInProgress, nextChildren); } - memoizeState(workInProgress, state); return workInProgress.child; } resetHydrationState(); @@ -8676,21 +8764,13 @@ var ReactFiberBeginWork = function( workInProgress.memoizedState = value.state !== null && value.state !== undefined ? value.state : null; - if (typeof Component.getDerivedStateFromProps === "function") { - var partialState = callGetDerivedStateFromProps( + var getDerivedStateFromProps = Component.getDerivedStateFromProps; + if (typeof getDerivedStateFromProps === "function") { + applyDerivedStateFromProps( workInProgress, - value, - props, - workInProgress.memoizedState + getDerivedStateFromProps, + props ); - - if (partialState !== null && partialState !== undefined) { - workInProgress.memoizedState = Object.assign( - {}, - workInProgress.memoizedState, - partialState - ); - } } // Push context providers early to prevent context stack mismatches. @@ -8704,7 +8784,6 @@ var ReactFiberBeginWork = function( workInProgress, true, hasContext, - false, renderExpirationTime ); } else { @@ -8850,7 +8929,7 @@ var ReactFiberBeginWork = function( var fiber = workInProgress.child; if (fiber !== null) { // Set the return pointer of the child to the work-in-progress fiber. - fiber["return"] = workInProgress; + fiber.return = workInProgress; } while (fiber !== null) { var nextFiber = void 0; @@ -8888,7 +8967,7 @@ var ReactFiberBeginWork = function( // ancestor path already has sufficient priority. break; } - node = node["return"]; + node = node.return; } // Don't scan deeper than a matching consumer. When we render the // consumer, we'll continue scanning from that point. This way the @@ -8910,7 +8989,7 @@ var ReactFiberBeginWork = function( } if (nextFiber !== null) { // Set the return pointer of the child to the work-in-progress fiber. - nextFiber["return"] = fiber; + nextFiber.return = fiber; } else { // No child. Traverse to next sibling. nextFiber = fiber; @@ -8922,11 +9001,13 @@ var ReactFiberBeginWork = function( } 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"]; + nextFiber = nextFiber.return; } } fiber = nextFiber; @@ -8943,8 +9024,10 @@ var ReactFiberBeginWork = function( var newProps = workInProgress.pendingProps; var oldProps = workInProgress.memoizedProps; + var canBailOnProps = true; if (hasLegacyContextChanged()) { + canBailOnProps = false; // Normally we can bail out on props equality but if context has changed // we don't do the bailout and we have to reuse existing props instead. } else if (oldProps === newProps) { @@ -8956,6 +9039,20 @@ var ReactFiberBeginWork = function( var newValue = newProps.value; workInProgress.memoizedProps = newProps; + { + var providerPropTypes = workInProgress.type.propTypes; + + if (providerPropTypes) { + checkPropTypes( + providerPropTypes, + newProps, + "prop", + "Context.Provider", + getCurrentFiberStackAddendum + ); + } + } + var changedBits = void 0; if (oldProps === null) { // Initial render @@ -8963,7 +9060,7 @@ var ReactFiberBeginWork = function( } else { if (oldProps.value === newProps.value) { // No change. Bailout early if children are the same. - if (oldProps.children === newProps.children) { + if (oldProps.children === newProps.children && canBailOnProps) { workInProgress.stateNode = 0; pushProvider(workInProgress); return bailoutOnAlreadyFinishedWork(current, workInProgress); @@ -8980,7 +9077,7 @@ var ReactFiberBeginWork = function( (oldValue !== oldValue && newValue !== newValue) // eslint-disable-line no-self-compare ) { // No change. Bailout early if children are the same. - if (oldProps.children === newProps.children) { + if (oldProps.children === newProps.children && canBailOnProps) { workInProgress.stateNode = 0; pushProvider(workInProgress); return bailoutOnAlreadyFinishedWork(current, workInProgress); @@ -9005,7 +9102,7 @@ var ReactFiberBeginWork = function( if (changedBits === 0) { // No change. Bailout early if children are the same. - if (oldProps.children === newProps.children) { + if (oldProps.children === newProps.children && canBailOnProps) { workInProgress.stateNode = 0; pushProvider(workInProgress); return bailoutOnAlreadyFinishedWork(current, workInProgress); @@ -9091,6 +9188,8 @@ var ReactFiberBeginWork = function( } var newChildren = render(newValue); + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; reconcileChildren(current, workInProgress, newChildren); return workInProgress.child; } @@ -9298,7 +9397,7 @@ var ReactFiberCompleteWork = function( function appendAllReturns(returns, workInProgress) { var node = workInProgress.stateNode; if (node) { - node["return"] = workInProgress; + node.return = workInProgress; } while (node !== null) { if ( @@ -9310,17 +9409,17 @@ var ReactFiberCompleteWork = function( } else if (node.tag === ReturnComponent) { returns.push(node.pendingProps.value); } else if (node.child !== null) { - node.child["return"] = node; + node.child.return = node; node = node.child; continue; } while (node.sibling === null) { - if (node["return"] === null || node["return"] === workInProgress) { + if (node.return === null || node.return === workInProgress) { return; } - node = node["return"]; + node = node.return; } - node.sibling["return"] = node["return"]; + node.sibling.return = node.return; node = node.sibling; } } @@ -9376,7 +9475,7 @@ var ReactFiberCompleteWork = function( // 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.child.return = node; node = node.child; continue; } @@ -9384,12 +9483,12 @@ var ReactFiberCompleteWork = function( return; } while (node.sibling === null) { - if (node["return"] === null || node["return"] === workInProgress) { + if (node.return === null || node.return === workInProgress) { return; } - node = node["return"]; + node = node.return; } - node.sibling["return"] = node["return"]; + node.sibling.return = node.return; node = node.sibling; } } @@ -9456,7 +9555,7 @@ var ReactFiberCompleteWork = function( // 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.child.return = node; node = node.child; continue; } @@ -9464,12 +9563,12 @@ var ReactFiberCompleteWork = function( return; } while (node.sibling === null) { - if (node["return"] === null || node["return"] === workInProgress) { + if (node.return === null || node.return === workInProgress) { return; } - node = node["return"]; + node = node.return; } - node.sibling["return"] = node["return"]; + node.sibling.return = node.return; node = node.sibling; } }; @@ -9595,20 +9694,6 @@ var ReactFiberCompleteWork = function( case ClassComponent: { // We are leaving this subtree, so pop context if any. popLegacyContextProvider(workInProgress); - - // If this component caught an error, schedule an error log effect. - var instance = workInProgress.stateNode; - var updateQueue = workInProgress.updateQueue; - if (updateQueue !== null && updateQueue.capturedValues !== null) { - workInProgress.effectTag &= ~DidCapture; - if (typeof instance.componentDidCatch === "function") { - workInProgress.effectTag |= ErrLog; - } else { - // Normally we clear this in the commit phase, but since we did not - // schedule an effect, we need to reset it here. - updateQueue.capturedValues = null; - } - } return null; } case HostRoot: { @@ -9628,11 +9713,6 @@ var ReactFiberCompleteWork = function( workInProgress.effectTag &= ~Placement; } updateHostContainer(workInProgress); - - var _updateQueue = workInProgress.updateQueue; - if (_updateQueue !== null && _updateQueue.capturedValues !== null) { - workInProgress.effectTag |= ErrLog; - } return null; } case HostComponent: { @@ -9647,13 +9727,13 @@ var ReactFiberCompleteWork = function( // 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 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, + instance, type, oldProps, newProps, @@ -9707,7 +9787,7 @@ var ReactFiberCompleteWork = function( markUpdate(workInProgress); } } else { - var _instance2 = createInstance( + var _instance = createInstance( type, newProps, rootContainerInstance, @@ -9715,14 +9795,14 @@ var ReactFiberCompleteWork = function( workInProgress ); - appendAllChildren(_instance2, workInProgress); + appendAllChildren(_instance, workInProgress); // 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( - _instance2, + _instance, type, newProps, rootContainerInstance, @@ -9731,7 +9811,7 @@ var ReactFiberCompleteWork = function( ) { markUpdate(workInProgress); } - workInProgress.stateNode = _instance2; + workInProgress.stateNode = _instance; } if (workInProgress.ref !== null) { @@ -9838,139 +9918,6 @@ function createCapturedValue(value, source) { }; } -var ReactFiberUnwindWork = function( - hostContext, - legacyContext, - newContext, - scheduleWork, - isAlreadyFailedLegacyErrorBoundary -) { - var popHostContainer = hostContext.popHostContainer, - popHostContext = hostContext.popHostContext; - var popLegacyContextProvider = legacyContext.popContextProvider, - popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject; - var popProvider = newContext.popProvider; - - function throwException(returnFiber, sourceFiber, rawValue) { - // The source fiber did not complete. - sourceFiber.effectTag |= Incomplete; - // Its effect list is no longer valid. - sourceFiber.firstEffect = sourceFiber.lastEffect = null; - - var value = createCapturedValue(rawValue, sourceFiber); - - var workInProgress = returnFiber; - do { - switch (workInProgress.tag) { - case HostRoot: { - // Uncaught error - var errorInfo = value; - ensureUpdateQueues(workInProgress); - var updateQueue = workInProgress.updateQueue; - updateQueue.capturedValues = [errorInfo]; - workInProgress.effectTag |= ShouldCapture; - return; - } - case ClassComponent: - // Capture and retry - var ctor = workInProgress.type; - var _instance = workInProgress.stateNode; - if ( - (workInProgress.effectTag & DidCapture) === NoEffect && - ((typeof ctor.getDerivedStateFromCatch === "function" && - enableGetDerivedStateFromCatch) || - (_instance !== null && - typeof _instance.componentDidCatch === "function" && - !isAlreadyFailedLegacyErrorBoundary(_instance))) - ) { - ensureUpdateQueues(workInProgress); - var _updateQueue = workInProgress.updateQueue; - var capturedValues = _updateQueue.capturedValues; - if (capturedValues === null) { - _updateQueue.capturedValues = [value]; - } else { - capturedValues.push(value); - } - workInProgress.effectTag |= ShouldCapture; - return; - } - break; - default: - break; - } - workInProgress = workInProgress["return"]; - } while (workInProgress !== null); - } - - function unwindWork(workInProgress) { - switch (workInProgress.tag) { - case ClassComponent: { - popLegacyContextProvider(workInProgress); - var effectTag = workInProgress.effectTag; - if (effectTag & ShouldCapture) { - workInProgress.effectTag = (effectTag & ~ShouldCapture) | DidCapture; - return workInProgress; - } - return null; - } - case HostRoot: { - popHostContainer(workInProgress); - popTopLevelLegacyContextObject(workInProgress); - var _effectTag = workInProgress.effectTag; - if (_effectTag & ShouldCapture) { - workInProgress.effectTag = (_effectTag & ~ShouldCapture) | DidCapture; - return workInProgress; - } - return null; - } - case HostComponent: { - popHostContext(workInProgress); - return null; - } - case HostPortal: - popHostContainer(workInProgress); - return null; - case ContextProvider: - popProvider(workInProgress); - return null; - default: - return null; - } - } - - function unwindInterruptedWork(interruptedWork) { - switch (interruptedWork.tag) { - case ClassComponent: { - popLegacyContextProvider(interruptedWork); - break; - } - case HostRoot: { - popHostContainer(interruptedWork); - popTopLevelLegacyContextObject(interruptedWork); - break; - } - case HostComponent: { - popHostContext(interruptedWork); - break; - } - case HostPortal: - popHostContainer(interruptedWork); - break; - case ContextProvider: - popProvider(interruptedWork); - break; - default: - break; - } - } - - return { - throwException: throwException, - unwindWork: unwindWork, - unwindInterruptedWork: unwindInterruptedWork - }; -}; - // Module provided by RN: /** * Intercept lifecycle errors and ensure they are shown with the correct stack @@ -10256,7 +10203,14 @@ var ReactFiberCommitWork = function( } var updateQueue = finishedWork.updateQueue; if (updateQueue !== null) { - commitCallbacks(updateQueue, _instance2); + _instance2.props = finishedWork.memoizedProps; + _instance2.state = finishedWork.memoizedState; + commitUpdateQueue( + finishedWork, + updateQueue, + _instance2, + committedExpirationTime + ); } return; } @@ -10274,7 +10228,12 @@ var ReactFiberCommitWork = function( break; } } - commitCallbacks(_updateQueue, _instance3); + commitUpdateQueue( + finishedWork, + _updateQueue, + _instance3, + committedExpirationTime + ); } return; } @@ -10311,81 +10270,17 @@ var ReactFiberCommitWork = function( } } - function commitErrorLogging(finishedWork, onUncaughtError) { - switch (finishedWork.tag) { - case ClassComponent: - { - var ctor = finishedWork.type; - var _instance5 = finishedWork.stateNode; - var updateQueue = finishedWork.updateQueue; - invariant( - updateQueue !== null && updateQueue.capturedValues !== null, - "An error logging effect should not have been scheduled if no errors " + - "were captured. This error is likely caused by a bug in React. " + - "Please file an issue." - ); - var capturedErrors = updateQueue.capturedValues; - updateQueue.capturedValues = null; - - if (typeof ctor.getDerivedStateFromCatch !== "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 getDerivedStateFromCatch is - // not defined. - markLegacyErrorBoundaryAsFailed(_instance5); - } - - _instance5.props = finishedWork.memoizedProps; - _instance5.state = finishedWork.memoizedState; - for (var i = 0; i < capturedErrors.length; i++) { - var errorInfo = capturedErrors[i]; - var _error = errorInfo.value; - var stack = errorInfo.stack; - logError(finishedWork, errorInfo); - _instance5.componentDidCatch(_error, { - componentStack: stack !== null ? stack : "" - }); - } - } - break; - case HostRoot: { - var _updateQueue2 = finishedWork.updateQueue; - invariant( - _updateQueue2 !== null && _updateQueue2.capturedValues !== null, - "An error logging effect should not have been scheduled if no errors " + - "were captured. This error is likely caused by a bug in React. " + - "Please file an issue." - ); - var _capturedErrors = _updateQueue2.capturedValues; - _updateQueue2.capturedValues = null; - for (var _i = 0; _i < _capturedErrors.length; _i++) { - var _errorInfo = _capturedErrors[_i]; - logError(finishedWork, _errorInfo); - onUncaughtError(_errorInfo.value); - } - break; - } - default: - invariant( - false, - "This unit of work tag cannot capture errors. This error is " + - "likely caused by a bug in React. Please file an issue." - ); - } - } - function commitAttachRef(finishedWork) { var ref = finishedWork.ref; if (ref !== null) { - var _instance6 = finishedWork.stateNode; + var _instance5 = finishedWork.stateNode; var instanceToUse = void 0; switch (finishedWork.tag) { case HostComponent: - instanceToUse = getPublicInstance(_instance6); + instanceToUse = getPublicInstance(_instance5); break; default: - instanceToUse = _instance6; + instanceToUse = _instance5; } if (typeof ref === "function") { ref(instanceToUse); @@ -10429,9 +10324,9 @@ var ReactFiberCommitWork = function( switch (current.tag) { case ClassComponent: { safelyDetachRef(current); - var _instance7 = current.stateNode; - if (typeof _instance7.componentWillUnmount === "function") { - safelyCallComponentWillUnmount(current, _instance7); + var _instance6 = current.stateNode; + if (typeof _instance6.componentWillUnmount === "function") { + safelyCallComponentWillUnmount(current, _instance6); } return; } @@ -10473,7 +10368,7 @@ var ReactFiberCommitWork = function( // If we don't use mutation we drill down into portals here instead. (!mutation || node.tag !== HostPortal) ) { - node.child["return"] = node; + node.child.return = node; node = node.child; continue; } @@ -10481,12 +10376,12 @@ var ReactFiberCommitWork = function( return; } while (node.sibling === null) { - if (node["return"] === null || node["return"] === root) { + if (node.return === null || node.return === root) { return; } - node = node["return"]; + node = node.return; } - node.sibling["return"] = node["return"]; + node.sibling.return = node.return; node = node.sibling; } } @@ -10497,11 +10392,11 @@ var ReactFiberCommitWork = function( // 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["return"] = null; + current.return = null; current.child = null; if (current.alternate) { current.alternate.child = null; - current.alternate["return"] = null; + current.alternate.return = null; } } @@ -10569,7 +10464,6 @@ var ReactFiberCommitWork = function( commitLifeCycles: commitLifeCycles, commitBeforeMutationLifeCycles: commitBeforeMutationLifeCycles, - commitErrorLogging: commitErrorLogging, commitAttachRef: commitAttachRef, commitDetachRef: commitDetachRef }; @@ -10591,12 +10485,12 @@ var ReactFiberCommitWork = function( removeChildFromContainer = mutation.removeChildFromContainer; function getHostParentFiber(fiber) { - var parent = fiber["return"]; + var parent = fiber.return; while (parent !== null) { if (isHostParent(parent)) { return parent; } - parent = parent["return"]; + parent = parent.return; } invariant( false, @@ -10621,14 +10515,14 @@ var ReactFiberCommitWork = function( 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 (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 = node.return; } - node.sibling["return"] = node["return"]; + node.sibling.return = node.return; node = node.sibling; while (node.tag !== HostComponent && node.tag !== HostText) { // If it is not host node and, we might have a host node inside it. @@ -10642,7 +10536,7 @@ var ReactFiberCommitWork = function( if (node.child === null || node.tag === HostPortal) { continue siblings; } else { - node.child["return"] = node; + node.child.return = node; node = node.child; } } @@ -10710,7 +10604,7 @@ var ReactFiberCommitWork = function( // 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.child.return = node; node = node.child; continue; } @@ -10718,12 +10612,12 @@ var ReactFiberCommitWork = function( return; } while (node.sibling === null) { - if (node["return"] === null || node["return"] === finishedWork) { + if (node.return === null || node.return === finishedWork) { return; } - node = node["return"]; + node = node.return; } - node.sibling["return"] = node["return"]; + node.sibling.return = node.return; node = node.sibling; } } @@ -10740,7 +10634,7 @@ var ReactFiberCommitWork = function( while (true) { if (!currentParentIsValid) { - var parent = node["return"]; + var parent = node.return; findParent: while (true) { invariant( parent !== null, @@ -10761,7 +10655,7 @@ var ReactFiberCommitWork = function( currentParentIsContainer = true; break findParent; } - parent = parent["return"]; + parent = parent.return; } currentParentIsValid = true; } @@ -10782,7 +10676,7 @@ var ReactFiberCommitWork = function( currentParent = node.stateNode.containerInfo; // Visit children because portals might contain host components. if (node.child !== null) { - node.child["return"] = node; + node.child.return = node; node = node.child; continue; } @@ -10790,7 +10684,7 @@ var ReactFiberCommitWork = function( commitUnmount(node); // Visit children because we may find more host components below. if (node.child !== null) { - node.child["return"] = node; + node.child.return = node; node = node.child; continue; } @@ -10799,17 +10693,17 @@ var ReactFiberCommitWork = function( return; } while (node.sibling === null) { - if (node["return"] === null || node["return"] === current) { + if (node.return === null || node.return === current) { return; } - node = node["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.sibling.return = node.return; node = node.sibling; } } @@ -10827,8 +10721,8 @@ var ReactFiberCommitWork = function( return; } case HostComponent: { - var _instance8 = finishedWork.stateNode; - if (_instance8 != null) { + var _instance7 = finishedWork.stateNode; + if (_instance7 != null) { // Commit the work prepared earlier. var newProps = finishedWork.memoizedProps; // For hydration we reuse the update path but we treat the oldProps @@ -10841,7 +10735,7 @@ var ReactFiberCommitWork = function( finishedWork.updateQueue = null; if (updatePayload !== null) { commitUpdate( - _instance8, + _instance7, updatePayload, type, oldProps, @@ -10892,7 +10786,6 @@ var ReactFiberCommitWork = function( commitDeletion: commitDeletion, commitWork: commitWork, commitLifeCycles: commitLifeCycles, - commitErrorLogging: commitErrorLogging, commitAttachRef: commitAttachRef, commitDetachRef: commitDetachRef }; @@ -10901,6 +10794,208 @@ var ReactFiberCommitWork = function( } }; +var ReactFiberUnwindWork = function( + hostContext, + legacyContext, + newContext, + scheduleWork, + markLegacyErrorBoundaryAsFailed, + isAlreadyFailedLegacyErrorBoundary, + onUncaughtError +) { + var popHostContainer = hostContext.popHostContainer, + popHostContext = hostContext.popHostContext; + var popLegacyContextProvider = legacyContext.popContextProvider, + popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject; + var popProvider = newContext.popProvider; + + 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 getDerivedStateFromCatch = fiber.type.getDerivedStateFromCatch; + if ( + enableGetDerivedStateFromCatch && + typeof getDerivedStateFromCatch === "function" + ) { + var _error = errorInfo.value; + update.payload = function() { + return getDerivedStateFromCatch(_error); + }; + } + + var inst = fiber.stateNode; + if (inst !== null && typeof inst.componentDidCatch === "function") { + update.callback = function callback() { + if ( + !enableGetDerivedStateFromCatch || + getDerivedStateFromCatch !== "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 getDerivedStateFromCatch is + // not defined. + markLegacyErrorBoundaryAsFailed(this); + } + var error = errorInfo.value; + var stack = errorInfo.stack; + logError(fiber, errorInfo); + this.componentDidCatch(error, { + componentStack: stack !== null ? stack : "" + }); + }; + } + return update; + } + + function throwException( + returnFiber, + sourceFiber, + rawValue, + renderExpirationTime + ) { + // The source fiber did not complete. + sourceFiber.effectTag |= Incomplete; + // Its effect list is no longer valid. + sourceFiber.firstEffect = sourceFiber.lastEffect = null; + + var value = createCapturedValue(rawValue, sourceFiber); + + var workInProgress = returnFiber; + do { + switch (workInProgress.tag) { + case HostRoot: { + var _errorInfo = value; + workInProgress.effectTag |= ShouldCapture; + var update = createRootErrorUpdate( + workInProgress, + _errorInfo, + renderExpirationTime + ); + enqueueCapturedUpdate(workInProgress, update, renderExpirationTime); + return; + } + case ClassComponent: + // Capture and retry + var errorInfo = value; + var ctor = workInProgress.type; + var _instance = workInProgress.stateNode; + if ( + (workInProgress.effectTag & DidCapture) === NoEffect && + ((typeof ctor.getDerivedStateFromCatch === "function" && + enableGetDerivedStateFromCatch) || + (_instance !== null && + typeof _instance.componentDidCatch === "function" && + !isAlreadyFailedLegacyErrorBoundary(_instance))) + ) { + workInProgress.effectTag |= ShouldCapture; + // Schedule the error boundary to re-render using updated state + var _update = createClassErrorUpdate( + workInProgress, + errorInfo, + renderExpirationTime + ); + enqueueCapturedUpdate( + workInProgress, + _update, + renderExpirationTime + ); + return; + } + break; + default: + break; + } + workInProgress = workInProgress.return; + } while (workInProgress !== null); + } + + function unwindWork(workInProgress) { + switch (workInProgress.tag) { + case ClassComponent: { + popLegacyContextProvider(workInProgress); + var effectTag = workInProgress.effectTag; + if (effectTag & ShouldCapture) { + workInProgress.effectTag = (effectTag & ~ShouldCapture) | DidCapture; + return workInProgress; + } + return null; + } + case HostRoot: { + popHostContainer(workInProgress); + popTopLevelLegacyContextObject(workInProgress); + var _effectTag = workInProgress.effectTag; + if (_effectTag & ShouldCapture) { + workInProgress.effectTag = (_effectTag & ~ShouldCapture) | DidCapture; + return workInProgress; + } + return null; + } + case HostComponent: { + popHostContext(workInProgress); + return null; + } + case HostPortal: + popHostContainer(workInProgress); + return null; + case ContextProvider: + popProvider(workInProgress); + return null; + default: + return null; + } + } + + function unwindInterruptedWork(interruptedWork) { + switch (interruptedWork.tag) { + case ClassComponent: { + popLegacyContextProvider(interruptedWork); + break; + } + case HostRoot: { + popHostContainer(interruptedWork); + popTopLevelLegacyContextObject(interruptedWork); + break; + } + case HostComponent: { + popHostContext(interruptedWork); + break; + } + case HostPortal: + popHostContainer(interruptedWork); + break; + case ContextProvider: + popProvider(interruptedWork); + break; + default: + break; + } + } + + return { + throwException: throwException, + unwindWork: unwindWork, + unwindInterruptedWork: unwindInterruptedWork, + createRootErrorUpdate: createRootErrorUpdate, + createClassErrorUpdate: createClassErrorUpdate + }; +}; + var NO_CONTEXT = {}; var ReactFiberHostContext = function(config, stack) { @@ -11085,7 +11180,7 @@ var ReactFiberHydrationContext = function(config) { var childToDelete = createFiberFromHostInstanceForDeletion(); childToDelete.stateNode = instance; - childToDelete["return"] = returnFiber; + childToDelete.return = returnFiber; childToDelete.effectTag = Deletion; // This might seem like it belongs on progressedFirstDeletion. However, @@ -11283,13 +11378,13 @@ var ReactFiberHydrationContext = function(config) { } function popToNextHostParent(fiber) { - var parent = fiber["return"]; + var parent = fiber.return; while ( parent !== null && parent.tag !== HostComponent && parent.tag !== HostRoot ) { - parent = parent["return"]; + parent = parent.return; } hydrationParentFiber = parent; } @@ -11611,7 +11706,7 @@ var ReactFiberLegacyContext = function(stack) { if (isContextProvider(node)) { return node.stateNode.__reactInternalMemoizedMergedChildContext; } - var parent = node["return"]; + var parent = node.return; invariant( parent, "Found unexpected detached subtree parent. " + @@ -11884,11 +11979,15 @@ var ReactFiberScheduler = function(config) { legacyContext, newContext, scheduleWork, - isAlreadyFailedLegacyErrorBoundary + markLegacyErrorBoundaryAsFailed, + isAlreadyFailedLegacyErrorBoundary, + onUncaughtError ), throwException = _ReactFiberUnwindWork.throwException, unwindWork = _ReactFiberUnwindWork.unwindWork, - unwindInterruptedWork = _ReactFiberUnwindWork.unwindInterruptedWork; + unwindInterruptedWork = _ReactFiberUnwindWork.unwindInterruptedWork, + createRootErrorUpdate = _ReactFiberUnwindWork.createRootErrorUpdate, + createClassErrorUpdate = _ReactFiberUnwindWork.createClassErrorUpdate; var _ReactFiberCommitWork = ReactFiberCommitWork( config, @@ -11905,7 +12004,6 @@ var ReactFiberScheduler = function(config) { commitDeletion = _ReactFiberCommitWork.commitDeletion, commitWork = _ReactFiberCommitWork.commitWork, commitLifeCycles = _ReactFiberCommitWork.commitLifeCycles, - commitErrorLogging = _ReactFiberCommitWork.commitErrorLogging, commitAttachRef = _ReactFiberCommitWork.commitAttachRef, commitDetachRef = _ReactFiberCommitWork.commitDetachRef; @@ -12003,10 +12101,10 @@ var ReactFiberScheduler = function(config) { function resetStack() { if (nextUnitOfWork !== null) { - var interruptedWork = nextUnitOfWork["return"]; + var interruptedWork = nextUnitOfWork.return; while (interruptedWork !== null) { unwindInterruptedWork(interruptedWork); - interruptedWork = interruptedWork["return"]; + interruptedWork = interruptedWork.return; } } @@ -12131,10 +12229,6 @@ var ReactFiberScheduler = function(config) { ); } - if (effectTag & ErrLog) { - commitErrorLogging(nextEffect, onUncaughtError); - } - if (effectTag & Ref) { recordEffect(); commitAttachRef(nextEffect); @@ -12341,7 +12435,16 @@ var ReactFiberScheduler = function(config) { } // Check for pending updates. - var newExpirationTime = getUpdateExpirationTime(workInProgress); + var newExpirationTime = NoWork; + switch (workInProgress.tag) { + case HostRoot: + case ClassComponent: { + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + newExpirationTime = updateQueue.expirationTime; + } + } + } // TODO: Calls need to visit stateNode @@ -12374,7 +12477,7 @@ var ReactFiberScheduler = function(config) { ReactDebugCurrentFiber.setCurrentFiber(workInProgress); } - var returnFiber = workInProgress["return"]; + var returnFiber = workInProgress.return; var siblingFiber = workInProgress.sibling; if ((workInProgress.effectTag & Incomplete) === NoEffect) { @@ -12616,13 +12719,19 @@ var ReactFiberScheduler = function(config) { break; } + { + // Reset global debug state + // We assume this is defined in DEV + resetCurrentlyProcessingQueue(); + } + if (true && replayFailedUnitOfWorkWithInvokeGuardedCallback) { var failedUnitOfWork = nextUnitOfWork; replayUnitOfWork(failedUnitOfWork, thrownValue, isAsync); } var sourceFiber = nextUnitOfWork; - var returnFiber = sourceFiber["return"]; + var returnFiber = sourceFiber.return; if (returnFiber === null) { // This is the root. The root could capture its own errors. However, // we don't know if it errors before or after we pushed the host @@ -12634,7 +12743,12 @@ var ReactFiberScheduler = function(config) { onUncaughtError(thrownValue); break; } - throwException(returnFiber, sourceFiber, thrownValue); + throwException( + returnFiber, + sourceFiber, + thrownValue, + nextRenderExpirationTime + ); nextUnitOfWork = completeUnitOfWork(sourceFiber); } break; @@ -12682,31 +12796,13 @@ var ReactFiberScheduler = function(config) { } } - function scheduleCapture(sourceFiber, boundaryFiber, value, expirationTime) { - // TODO: We only support dispatching errors. - var capturedValue = createCapturedValue(value, sourceFiber); - var update = { - expirationTime: expirationTime, - partialState: null, - callback: null, - isReplace: false, - isForced: false, - capturedValue: capturedValue, - next: null - }; - insertUpdateIntoFiber(boundaryFiber, update); - scheduleWork(boundaryFiber, expirationTime); - } - function dispatch(sourceFiber, value, expirationTime) { invariant( !isWorking || isCommitting, "dispatch: Cannot dispatch during the render phase." ); - // TODO: Handle arrays - - var fiber = sourceFiber["return"]; + var fiber = sourceFiber.return; while (fiber !== null) { switch (fiber.tag) { case ClassComponent: @@ -12717,22 +12813,44 @@ var ReactFiberScheduler = function(config) { (typeof instance.componentDidCatch === "function" && !isAlreadyFailedLegacyErrorBoundary(instance)) ) { - scheduleCapture(sourceFiber, fiber, value, expirationTime); + var errorInfo = createCapturedValue(value, sourceFiber); + var update = createClassErrorUpdate( + fiber, + errorInfo, + expirationTime + ); + enqueueUpdate(fiber, update, expirationTime); + scheduleWork(fiber, expirationTime); return; } break; - // TODO: Handle async boundaries - case HostRoot: - scheduleCapture(sourceFiber, fiber, value, expirationTime); + case HostRoot: { + var _errorInfo = createCapturedValue(value, sourceFiber); + var _update = createRootErrorUpdate( + fiber, + _errorInfo, + expirationTime + ); + enqueueUpdate(fiber, _update, expirationTime); + scheduleWork(fiber, expirationTime); return; + } } - fiber = fiber["return"]; + fiber = fiber.return; } if (sourceFiber.tag === HostRoot) { // Error was thrown at the root. There is no parent, so the root // itself should capture it. - scheduleCapture(sourceFiber, sourceFiber, value, expirationTime); + var rootFiber = sourceFiber; + var _errorInfo2 = createCapturedValue(value, rootFiber); + var _update2 = createRootErrorUpdate( + rootFiber, + _errorInfo2, + expirationTime + ); + enqueueUpdate(rootFiber, _update2, expirationTime); + scheduleWork(rootFiber, expirationTime); } } @@ -12860,7 +12978,7 @@ var ReactFiberScheduler = function(config) { node.alternate.expirationTime = expirationTime; } } - if (node["return"] === null) { + if (node.return === null) { if (node.tag === HostRoot) { var root = node.stateNode; if ( @@ -12901,7 +13019,7 @@ var ReactFiberScheduler = function(config) { return; } } - node = node["return"]; + node = node.return; } } @@ -13530,9 +13648,14 @@ var ReactFiberReconciler$1 = function(config) { } } + var update = createUpdate(expirationTime); + // Caution: React DevTools currently depends on this property + // being called "element". + update.payload = { element: element }; + callback = callback === undefined ? null : callback; - { - !(callback === null || typeof callback === "function") + if (callback !== null) { + !(typeof callback === "function") ? warning( false, "render(...): Expected the last optional `callback` argument to be a " + @@ -13540,20 +13663,11 @@ var ReactFiberReconciler$1 = function(config) { callback ) : void 0; + update.callback = callback; } + enqueueUpdate(current, update, expirationTime); - var update = { - expirationTime: expirationTime, - partialState: { element: element }, - callback: callback, - isReplace: false, - isForced: false, - capturedValue: null, - next: null - }; - insertUpdateIntoFiber(current, update); scheduleWork(current, expirationTime); - return expirationTime; } @@ -13731,8 +13845,8 @@ var ReactFiberReconciler$3 = // TODO: decide on the top-level export form. // This is hacky but makes it work with both Rollup and Jest. -var reactReconciler = ReactFiberReconciler$3["default"] - ? ReactFiberReconciler$3["default"] +var reactReconciler = ReactFiberReconciler$3.default + ? ReactFiberReconciler$3.default : ReactFiberReconciler$3; function _classCallCheck$1(instance, Constructor) { @@ -14354,7 +14468,7 @@ var ReactNativeRenderer = { if (root) { // TODO: Is it safe to reset this now or should I wait since this unmount could be deferred? NativeRenderer.updateContainer(null, root, null, function() { - roots["delete"](containerTag); + roots.delete(containerTag); }); } }, @@ -14421,8 +14535,8 @@ var ReactNativeRenderer$3 = // 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["default"] +var reactNativeRenderer = ReactNativeRenderer$3.default + ? ReactNativeRenderer$3.default : ReactNativeRenderer$3; module.exports = reactNativeRenderer; diff --git a/Libraries/Renderer/oss/ReactNativeRenderer-prod.js b/Libraries/Renderer/oss/ReactNativeRenderer-prod.js index f7eb9e09f0dce6..09031ec3a6c900 100644 --- a/Libraries/Renderer/oss/ReactNativeRenderer-prod.js +++ b/Libraries/Renderer/oss/ReactNativeRenderer-prod.js @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. * * @noflow + * @providesModule ReactNativeRenderer-prod * @preventMunge */ @@ -306,7 +307,7 @@ function getListener(inst, registrationName) { return listener; } function getParent(inst) { - do inst = inst["return"]; + do inst = inst.return; while (inst && 5 !== inst.tag); return inst ? inst : null; } @@ -1122,21 +1123,17 @@ var ReactNativeEventEmitter = Object.freeze({ } }); RCTEventEmitter.register(ReactNativeEventEmitter); -var hasSymbol = "function" === typeof Symbol && Symbol["for"], - REACT_ELEMENT_TYPE = hasSymbol ? Symbol["for"]("react.element") : 60103, - REACT_CALL_TYPE = hasSymbol ? Symbol["for"]("react.call") : 60104, - REACT_RETURN_TYPE = hasSymbol ? Symbol["for"]("react.return") : 60105, - 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_PROVIDER_TYPE = hasSymbol ? Symbol["for"]("react.provider") : 60109, - REACT_CONTEXT_TYPE = hasSymbol ? Symbol["for"]("react.context") : 60110, - REACT_ASYNC_MODE_TYPE = hasSymbol ? Symbol["for"]("react.async_mode") : 60111, - REACT_FORWARD_REF_TYPE = hasSymbol - ? Symbol["for"]("react.forward_ref") - : 60112, +var hasSymbol = "function" === typeof Symbol && Symbol.for, + REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for("react.element") : 60103, + REACT_CALL_TYPE = hasSymbol ? Symbol.for("react.call") : 60104, + REACT_RETURN_TYPE = hasSymbol ? Symbol.for("react.return") : 60105, + 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_PROVIDER_TYPE = hasSymbol ? Symbol.for("react.provider") : 60109, + REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for("react.context") : 60110, + REACT_ASYNC_MODE_TYPE = hasSymbol ? Symbol.for("react.async_mode") : 60111, + REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for("react.forward_ref") : 60112, MAYBE_ITERATOR_SYMBOL = "function" === typeof Symbol && Symbol.iterator; function getIteratorFn(maybeIterable) { if (null === maybeIterable || "undefined" === typeof maybeIterable) @@ -1210,7 +1207,7 @@ function getStackAddendumByWorkInProgressFiber(workInProgress) { JSCompiler_inline_result = ""; } info += JSCompiler_inline_result; - workInProgress = workInProgress["return"]; + workInProgress = workInProgress.return; } while (workInProgress); return info; } @@ -1469,11 +1466,11 @@ var ReactCurrentOwner = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner; function isFiberMountedImpl(fiber) { var node = fiber; - if (fiber.alternate) for (; node["return"]; ) node = node["return"]; + 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; + for (; node.return; ) + if (((node = node.return), 0 !== (node.effectTag & 2))) return 1; } return 3 === node.tag ? 2 : 3; } @@ -1500,7 +1497,7 @@ function findCurrentFiberUsingSlowPath(fiber) { 1 === alternate ? null : fiber ); for (var a = fiber, b = alternate; ; ) { - var parentA = a["return"], + var parentA = a.return, parentB = parentA ? parentA.alternate : null; if (!parentA || !parentB) break; if (parentA.child === parentB.child) { @@ -1511,7 +1508,7 @@ function findCurrentFiberUsingSlowPath(fiber) { } invariant(!1, "Unable to find node on an unmounted component."); } - if (a["return"] !== b["return"]) (a = parentA), (b = parentB); + if (a.return !== b.return) (a = parentA), (b = parentB); else { child = !1; for (var _child = parentA.child; _child; ) { @@ -1564,14 +1561,14 @@ function findCurrentHostFiber(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); + 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"]; + if (!node.return || node.return === parent) return null; + node = node.return; } - node.sibling["return"] = node["return"]; + node.sibling.return = node.return; node = node.sibling; } } @@ -1583,14 +1580,14 @@ function findCurrentHostFiberWithNoPortals(parent) { for (var node = parent; ; ) { if (5 === node.tag || 6 === node.tag) return node; if (node.child && 4 !== node.tag) - (node.child["return"] = node), (node = 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"]; + if (!node.return || node.return === parent) return null; + node = node.return; } - node.sibling["return"] = node["return"]; + node.sibling.return = node.return; node = node.sibling; } } @@ -1599,8 +1596,7 @@ function findCurrentHostFiberWithNoPortals(parent) { function FiberNode(tag, pendingProps, key, mode) { this.tag = tag; this.key = key; - this.stateNode = this.type = null; - this.sibling = this.child = this["return"] = null; + this.sibling = this.child = this.return = this.stateNode = this.type = null; this.index = 0; this.ref = null; this.pendingProps = pendingProps; @@ -1765,164 +1761,282 @@ function onCommitUnmount(fiber) { new Set(); function createUpdateQueue(baseState) { return { - baseState: baseState, expirationTime: 0, - first: null, - last: null, - callbackList: null, + baseState: baseState, + firstUpdate: null, + lastUpdate: null, + firstCapturedUpdate: null, + lastCapturedUpdate: null, + firstEffect: null, + lastEffect: null, + firstCapturedEffect: null, + lastCapturedEffect: null, + hasForceUpdate: !1 + }; +} +function cloneUpdateQueue(currentQueue) { + return { + expirationTime: currentQueue.expirationTime, + baseState: currentQueue.baseState, + firstUpdate: currentQueue.firstUpdate, + lastUpdate: currentQueue.lastUpdate, + firstCapturedUpdate: null, + lastCapturedUpdate: null, hasForceUpdate: !1, - isInitialized: !1, - capturedValues: 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 insertUpdateIntoQueue(queue, update) { - null === queue.last - ? (queue.first = queue.last = update) - : ((queue.last.next = update), (queue.last = update)); +function appendUpdateToQueue(queue, update, expirationTime) { + null === queue.lastUpdate + ? (queue.firstUpdate = queue.lastUpdate = update) + : ((queue.lastUpdate.next = update), (queue.lastUpdate = update)); + if (0 === queue.expirationTime || queue.expirationTime > expirationTime) + queue.expirationTime = expirationTime; +} +function enqueueUpdate(fiber, update, expirationTime) { + 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, expirationTime) + : null === queue1.lastUpdate || null === queue2.lastUpdate + ? (appendUpdateToQueue(queue1, update, expirationTime), + appendUpdateToQueue(queue2, update, expirationTime)) + : (appendUpdateToQueue(queue1, update, expirationTime), + (queue2.lastUpdate = update)); +} +function enqueueCapturedUpdate(workInProgress, update, renderExpirationTime) { + 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)); if ( - 0 === queue.expirationTime || - queue.expirationTime > update.expirationTime + 0 === workInProgressQueue.expirationTime || + workInProgressQueue.expirationTime > renderExpirationTime ) - queue.expirationTime = update.expirationTime; -} -var q1 = void 0, - q2 = void 0; -function ensureUpdateQueues(fiber) { - q1 = q2 = null; - var alternateFiber = fiber.alternate, - queue1 = fiber.updateQueue; - null === queue1 && (queue1 = fiber.updateQueue = createUpdateQueue(null)); - null !== alternateFiber - ? ((fiber = alternateFiber.updateQueue), - null === fiber && - (fiber = alternateFiber.updateQueue = createUpdateQueue(null))) - : (fiber = null); - q1 = queue1; - q2 = fiber !== queue1 ? fiber : null; + workInProgressQueue.expirationTime = renderExpirationTime; } -function insertUpdateIntoFiber(fiber, update) { - ensureUpdateQueues(fiber); - fiber = q1; - var queue2 = q2; - null === queue2 - ? insertUpdateIntoQueue(fiber, update) - : null === fiber.last || null === queue2.last - ? (insertUpdateIntoQueue(fiber, update), - insertUpdateIntoQueue(queue2, update)) - : (insertUpdateIntoQueue(fiber, update), (queue2.last = update)); +function ensureWorkInProgressQueueIsAClone(workInProgress, queue) { + var current = workInProgress.alternate; + null !== current && + queue === current.updateQueue && + (queue = workInProgress.updateQueue = cloneUpdateQueue(queue)); + return queue; } -function getStateFromUpdate(update, instance, prevState, props) { - update = update.partialState; - return "function" === typeof update - ? update.call(instance, prevState, props) - : update; +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 & -1025) | 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: + queue.hasForceUpdate = !0; + } + return prevState; } function processUpdateQueue( - current, workInProgress, queue, - instance, props, + instance, renderExpirationTime ) { - null !== current && - current.updateQueue === queue && - (queue = workInProgress.updateQueue = { - baseState: queue.baseState, - expirationTime: queue.expirationTime, - first: queue.first, - last: queue.last, - isInitialized: queue.isInitialized, - capturedValues: queue.capturedValues, - callbackList: null, - hasForceUpdate: !1 - }); - queue.expirationTime = 0; - queue.isInitialized - ? (current = queue.baseState) - : ((current = queue.baseState = workInProgress.memoizedState), - (queue.isInitialized = !0)); - for ( - var dontMutatePrevState = !0, update = queue.first, didSkip = !1; - null !== update; - + if ( + !(0 === queue.expirationTime || queue.expirationTime > renderExpirationTime) ) { - var updateExpirationTime = update.expirationTime; - if (updateExpirationTime > renderExpirationTime) { - var remainingExpirationTime = queue.expirationTime; - if ( - 0 === remainingExpirationTime || - remainingExpirationTime > updateExpirationTime - ) - queue.expirationTime = updateExpirationTime; - didSkip || ((didSkip = !0), (queue.baseState = current)); - } else { - didSkip || - ((queue.first = update.next), - null === queue.first && (queue.last = null)); - if (update.isReplace) - (current = getStateFromUpdate(update, instance, current, props)), - (dontMutatePrevState = !0); - else if ( - (updateExpirationTime = getStateFromUpdate( + queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue); + for ( + var newBaseState = queue.baseState, + newFirstUpdate = null, + newExpirationTime = 0, + update = queue.firstUpdate, + resultState = newBaseState; + null !== update; + + ) { + var updateExpirationTime = update.expirationTime; + if (updateExpirationTime > renderExpirationTime) { + if ( + (null === newFirstUpdate && + ((newFirstUpdate = update), (newBaseState = resultState)), + 0 === newExpirationTime || newExpirationTime > updateExpirationTime) + ) + newExpirationTime = updateExpirationTime; + } else + (resultState = getStateFromUpdate( + workInProgress, + queue, update, - instance, - current, - props - )) - ) - (current = dontMutatePrevState - ? Object.assign({}, current, updateExpirationTime) - : Object.assign(current, updateExpirationTime)), - (dontMutatePrevState = !1); - update.isForced && (queue.hasForceUpdate = !0); - null !== update.callback && - ((updateExpirationTime = queue.callbackList), - null === updateExpirationTime && - (updateExpirationTime = queue.callbackList = []), - updateExpirationTime.push(update)); - null !== update.capturedValue && - ((updateExpirationTime = queue.capturedValues), - null === updateExpirationTime - ? (queue.capturedValues = [update.capturedValue]) - : updateExpirationTime.push(update.capturedValue)); + 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; + if (_updateExpirationTime > renderExpirationTime) { + if ( + (null === updateExpirationTime && + ((updateExpirationTime = update), + null === newFirstUpdate && (newBaseState = resultState)), + 0 === newExpirationTime || newExpirationTime > _updateExpirationTime) + ) + newExpirationTime = _updateExpirationTime; + } else + (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; } - 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; + queue.expirationTime = newExpirationTime; + workInProgress.memoizedState = resultState; } - null !== queue.callbackList - ? (workInProgress.effectTag |= 32) - : null !== queue.first || - queue.hasForceUpdate || - null !== queue.capturedValues || - (workInProgress.updateQueue = null); - didSkip || (queue.baseState = current); - return current; } -function commitCallbacks(queue, context) { - var callbackList = queue.callbackList; - if (null !== callbackList) - for ( - queue.callbackList = null, queue = 0; - queue < callbackList.length; - queue++ - ) { - var update = callbackList[queue], - _callback = update.callback; - update.callback = null; - invariant( - "function" === typeof _callback, - "Invalid argument passed as callback. Expected a function. Instead received: %s", - _callback - ); - _callback.call(context); - } +function callCallback(callback, context) { + invariant( + "function" === typeof callback, + "Invalid argument passed as callback. Expected a function. Instead received: %s", + callback + ); + callback.call(context); +} +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)); + finishedWork = finishedQueue.firstEffect; + for ( + finishedQueue.firstEffect = finishedQueue.lastEffect = null; + null !== finishedWork; + + ) { + var _callback3 = finishedWork.callback; + null !== _callback3 && + ((finishedWork.callback = null), callCallback(_callback3, instance)); + finishedWork = finishedWork.nextEffect; + } + finishedWork = finishedQueue.firstCapturedEffect; + for ( + finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null; + null !== finishedWork; + + ) + (finishedQueue = finishedWork.callback), + null !== finishedQueue && + ((finishedWork.callback = null), callCallback(finishedQueue, instance)), + (finishedWork = finishedWork.nextEffect); +} +function applyDerivedStateFromProps( + workInProgress, + getDerivedStateFromProps, + nextProps +) { + var prevState = workInProgress.memoizedState; + getDerivedStateFromProps = getDerivedStateFromProps(nextProps, prevState); + prevState = + null === getDerivedStateFromProps || void 0 === getDerivedStateFromProps + ? prevState + : Object.assign({}, prevState, getDerivedStateFromProps); + workInProgress.memoizedState = prevState; + workInProgress = workInProgress.updateQueue; + null !== workInProgress && + 0 === workInProgress.expirationTime && + (workInProgress.baseState = prevState); } function ReactFiberClassComponent( legacyContext, scheduleWork, - computeExpirationForFiber, - memoizeProps, - memoizeState + computeExpirationForFiber ) { function checkShouldComponentUpdate( workInProgress, @@ -1933,9 +2047,8 @@ function ReactFiberClassComponent( newContext ) { if ( - null === oldProps || - (null !== workInProgress.updateQueue && - workInProgress.updateQueue.hasForceUpdate) + null !== workInProgress.updateQueue && + workInProgress.updateQueue.hasForceUpdate ) return !0; var instance = workInProgress.stateNode; @@ -1948,7 +2061,7 @@ function ReactFiberClassComponent( : !0; } function adoptClassInstance(workInProgress, instance) { - instance.updater = updater; + instance.updater = classComponentUpdater; workInProgress.stateNode = instance; instance._reactInternalFiber = workInProgress; } @@ -1964,78 +2077,52 @@ function ReactFiberClassComponent( "function" === typeof instance.UNSAFE_componentWillReceiveProps && instance.UNSAFE_componentWillReceiveProps(newProps, newContext); instance.state !== workInProgress && - updater.enqueueReplaceState(instance, instance.state, null); - } - function callGetDerivedStateFromProps( - workInProgress, - instance, - nextProps, - prevState - ) { - workInProgress = workInProgress.type; - if ("function" === typeof workInProgress.getDerivedStateFromProps) - return workInProgress.getDerivedStateFromProps.call( - null, - nextProps, - prevState - ); + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); } var cacheContext = legacyContext.cacheContext, getMaskedContext = legacyContext.getMaskedContext, getUnmaskedContext = legacyContext.getUnmaskedContext, isContextConsumer = legacyContext.isContextConsumer, hasContextChanged = legacyContext.hasContextChanged, - updater = { + classComponentUpdater = { isMounted: isMounted, - enqueueSetState: function(instance, partialState, callback) { - instance = instance._reactInternalFiber; - callback = void 0 === callback ? null : callback; - var expirationTime = computeExpirationForFiber(instance); - insertUpdateIntoFiber(instance, { - expirationTime: expirationTime, - partialState: partialState, - callback: callback, - isReplace: !1, - isForced: !1, - capturedValue: null, - next: null - }); - scheduleWork(instance, expirationTime); + enqueueSetState: function(inst, payload, callback) { + inst = inst._reactInternalFiber; + var expirationTime = computeExpirationForFiber(inst), + update = createUpdate(expirationTime); + update.payload = payload; + void 0 !== callback && + null !== callback && + (update.callback = callback); + enqueueUpdate(inst, update, expirationTime); + scheduleWork(inst, expirationTime); }, - enqueueReplaceState: function(instance, state, callback) { - instance = instance._reactInternalFiber; - callback = void 0 === callback ? null : callback; - var expirationTime = computeExpirationForFiber(instance); - insertUpdateIntoFiber(instance, { - expirationTime: expirationTime, - partialState: state, - callback: callback, - isReplace: !0, - isForced: !1, - capturedValue: null, - next: null - }); - scheduleWork(instance, expirationTime); + enqueueReplaceState: function(inst, payload, callback) { + inst = inst._reactInternalFiber; + var expirationTime = computeExpirationForFiber(inst), + update = createUpdate(expirationTime); + update.tag = 1; + update.payload = payload; + void 0 !== callback && + null !== callback && + (update.callback = callback); + enqueueUpdate(inst, update, expirationTime); + scheduleWork(inst, expirationTime); }, - enqueueForceUpdate: function(instance, callback) { - instance = instance._reactInternalFiber; - callback = void 0 === callback ? null : callback; - var expirationTime = computeExpirationForFiber(instance); - insertUpdateIntoFiber(instance, { - expirationTime: expirationTime, - partialState: null, - callback: callback, - isReplace: !1, - isForced: !0, - capturedValue: null, - next: null - }); - scheduleWork(instance, expirationTime); + enqueueForceUpdate: function(inst, callback) { + inst = inst._reactInternalFiber; + var expirationTime = computeExpirationForFiber(inst), + update = createUpdate(expirationTime); + update.tag = 2; + void 0 !== callback && + null !== callback && + (update.callback = callback); + enqueueUpdate(inst, update, expirationTime); + scheduleWork(inst, expirationTime); } }; return { adoptClassInstance: adoptClassInstance, - callGetDerivedStateFromProps: callGetDerivedStateFromProps, constructClassInstance: function(workInProgress, props) { var ctor = workInProgress.type, unmaskedContext = getUnmaskedContext(workInProgress), @@ -2043,25 +2130,15 @@ function ReactFiberClassComponent( context = needsContext ? getMaskedContext(workInProgress, unmaskedContext) : emptyObject; - ctor = new ctor(props, context); - var state = - null !== ctor.state && void 0 !== ctor.state ? ctor.state : null; - adoptClassInstance(workInProgress, ctor); - workInProgress.memoizedState = state; - props = callGetDerivedStateFromProps(workInProgress, ctor, props, state); - null !== props && - void 0 !== props && - (workInProgress.memoizedState = Object.assign( - {}, - workInProgress.memoizedState, - props - )); + props = new ctor(props, context); + workInProgress.memoizedState = + null !== props.state && void 0 !== props.state ? props.state : null; + adoptClassInstance(workInProgress, props); needsContext && cacheContext(workInProgress, unmaskedContext, context); - return ctor; + return props; }, mountClassInstance: function(workInProgress, renderExpirationTime) { var ctor = workInProgress.type, - current = workInProgress.alternate, instance = workInProgress.stateNode, props = workInProgress.pendingProps, unmaskedContext = getUnmaskedContext(workInProgress); @@ -2069,6 +2146,20 @@ function ReactFiberClassComponent( instance.state = workInProgress.memoizedState; instance.refs = emptyObject; instance.context = getMaskedContext(workInProgress, unmaskedContext); + unmaskedContext = workInProgress.updateQueue; + null !== unmaskedContext && + (processUpdateQueue( + workInProgress, + unmaskedContext, + props, + instance, + renderExpirationTime + ), + (instance.state = workInProgress.memoizedState)); + unmaskedContext = workInProgress.type.getDerivedStateFromProps; + "function" === typeof unmaskedContext && + (applyDerivedStateFromProps(workInProgress, unmaskedContext, props), + (instance.state = workInProgress.memoizedState)); "function" === typeof ctor.getDerivedStateFromProps || "function" === typeof instance.getSnapshotBeforeUpdate || ("function" !== typeof instance.UNSAFE_componentWillMount && @@ -2079,32 +2170,36 @@ function ReactFiberClassComponent( "function" === typeof instance.UNSAFE_componentWillMount && instance.UNSAFE_componentWillMount(), ctor !== instance.state && - updater.enqueueReplaceState(instance, instance.state, null), - (ctor = workInProgress.updateQueue), - null !== ctor && - (instance.state = processUpdateQueue( - current, - workInProgress, - ctor, + classComponentUpdater.enqueueReplaceState( instance, + instance.state, + null + ), + (unmaskedContext = workInProgress.updateQueue), + null !== unmaskedContext && + (processUpdateQueue( + workInProgress, + unmaskedContext, props, + instance, renderExpirationTime - ))); + ), + (instance.state = workInProgress.memoizedState))); "function" === typeof instance.componentDidMount && (workInProgress.effectTag |= 4); }, resumeMountClassInstance: function(workInProgress, renderExpirationTime) { var ctor = workInProgress.type, - instance = workInProgress.stateNode; - instance.props = workInProgress.memoizedProps; - instance.state = workInProgress.memoizedState; - var oldProps = workInProgress.memoizedProps, - newProps = workInProgress.pendingProps, - oldContext = instance.context, + instance = workInProgress.stateNode, + oldProps = workInProgress.memoizedProps, + newProps = workInProgress.pendingProps; + instance.props = oldProps; + var oldContext = instance.context, newUnmaskedContext = getUnmaskedContext(workInProgress); newUnmaskedContext = getMaskedContext(workInProgress, newUnmaskedContext); + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; (ctor = - "function" === typeof ctor.getDerivedStateFromProps || + "function" === typeof getDerivedStateFromProps || "function" === typeof instance.getSnapshotBeforeUpdate) || ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && "function" !== typeof instance.componentWillReceiveProps) || @@ -2115,43 +2210,29 @@ function ReactFiberClassComponent( newProps, newUnmaskedContext )); - oldContext = workInProgress.memoizedState; - renderExpirationTime = - null !== workInProgress.updateQueue - ? processUpdateQueue( - null, - workInProgress, - workInProgress.updateQueue, - instance, - newProps, - renderExpirationTime - ) - : oldContext; - var derivedStateFromProps = void 0; - oldProps !== newProps && - (derivedStateFromProps = callGetDerivedStateFromProps( + var oldState = workInProgress.memoizedState; + oldContext = instance.state = oldState; + var updateQueue = workInProgress.updateQueue; + null !== updateQueue && + (processUpdateQueue( workInProgress, - instance, + updateQueue, newProps, + instance, renderExpirationTime - )); - if (null !== derivedStateFromProps && void 0 !== derivedStateFromProps) { - renderExpirationTime = - null === renderExpirationTime || void 0 === renderExpirationTime - ? derivedStateFromProps - : Object.assign({}, renderExpirationTime, derivedStateFromProps); - var _updateQueue = workInProgress.updateQueue; - null !== _updateQueue && - (_updateQueue.baseState = Object.assign( - {}, - _updateQueue.baseState, - derivedStateFromProps - )); - } + ), + (oldContext = workInProgress.memoizedState)); + "function" === typeof getDerivedStateFromProps && + (applyDerivedStateFromProps( + workInProgress, + getDerivedStateFromProps, + newProps + ), + (oldContext = workInProgress.memoizedState)); if ( !( oldProps !== newProps || - oldContext !== renderExpirationTime || + oldState !== oldContext || hasContextChanged() || (null !== workInProgress.updateQueue && workInProgress.updateQueue.hasForceUpdate) @@ -2162,12 +2243,12 @@ function ReactFiberClassComponent( (workInProgress.effectTag |= 4), !1 ); - (oldProps = checkShouldComponentUpdate( + (renderExpirationTime = checkShouldComponentUpdate( workInProgress, oldProps, newProps, + oldState, oldContext, - renderExpirationTime, newUnmaskedContext )) ? (ctor || @@ -2181,12 +2262,12 @@ function ReactFiberClassComponent( (workInProgress.effectTag |= 4)) : ("function" === typeof instance.componentDidMount && (workInProgress.effectTag |= 4), - memoizeProps(workInProgress, newProps), - memoizeState(workInProgress, renderExpirationTime)); + (workInProgress.memoizedProps = newProps), + (workInProgress.memoizedState = oldContext)); instance.props = newProps; - instance.state = renderExpirationTime; + instance.state = oldContext; instance.context = newUnmaskedContext; - return oldProps; + return renderExpirationTime; }, updateClassInstance: function( current, @@ -2194,16 +2275,16 @@ function ReactFiberClassComponent( renderExpirationTime ) { var ctor = workInProgress.type, - instance = workInProgress.stateNode; - instance.props = workInProgress.memoizedProps; - instance.state = workInProgress.memoizedState; - var oldProps = workInProgress.memoizedProps, - newProps = workInProgress.pendingProps, - oldContext = instance.context, + instance = workInProgress.stateNode, + oldProps = workInProgress.memoizedProps, + newProps = workInProgress.pendingProps; + instance.props = oldProps; + var oldContext = instance.context, newUnmaskedContext = getUnmaskedContext(workInProgress); newUnmaskedContext = getMaskedContext(workInProgress, newUnmaskedContext); + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; (ctor = - "function" === typeof ctor.getDerivedStateFromProps || + "function" === typeof getDerivedStateFromProps || "function" === typeof instance.getSnapshotBeforeUpdate) || ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && "function" !== typeof instance.componentWillReceiveProps) || @@ -2215,42 +2296,28 @@ function ReactFiberClassComponent( newUnmaskedContext )); oldContext = workInProgress.memoizedState; - renderExpirationTime = - null !== workInProgress.updateQueue - ? processUpdateQueue( - current, - workInProgress, - workInProgress.updateQueue, - instance, - newProps, - renderExpirationTime - ) - : oldContext; - var derivedStateFromProps = void 0; - oldProps !== newProps && - (derivedStateFromProps = callGetDerivedStateFromProps( + var newState = (instance.state = oldContext), + updateQueue = workInProgress.updateQueue; + null !== updateQueue && + (processUpdateQueue( workInProgress, - instance, + updateQueue, newProps, + instance, renderExpirationTime - )); - if (null !== derivedStateFromProps && void 0 !== derivedStateFromProps) { - renderExpirationTime = - null === renderExpirationTime || void 0 === renderExpirationTime - ? derivedStateFromProps - : Object.assign({}, renderExpirationTime, derivedStateFromProps); - var _updateQueue3 = workInProgress.updateQueue; - null !== _updateQueue3 && - (_updateQueue3.baseState = Object.assign( - {}, - _updateQueue3.baseState, - derivedStateFromProps - )); - } + ), + (newState = workInProgress.memoizedState)); + "function" === typeof getDerivedStateFromProps && + (applyDerivedStateFromProps( + workInProgress, + getDerivedStateFromProps, + newProps + ), + (newState = workInProgress.memoizedState)); if ( !( oldProps !== newProps || - oldContext !== renderExpirationTime || + oldContext !== newState || hasContextChanged() || (null !== workInProgress.updateQueue && workInProgress.updateQueue.hasForceUpdate) @@ -2264,15 +2331,15 @@ function ReactFiberClassComponent( "function" !== typeof instance.getSnapshotBeforeUpdate || (oldProps === current.memoizedProps && oldContext === current.memoizedState) || - (workInProgress.effectTag |= 2048), + (workInProgress.effectTag |= 256), !1 ); - (derivedStateFromProps = checkShouldComponentUpdate( + (renderExpirationTime = checkShouldComponentUpdate( workInProgress, oldProps, newProps, oldContext, - renderExpirationTime, + newState, newUnmaskedContext )) ? (ctor || @@ -2281,19 +2348,19 @@ function ReactFiberClassComponent( ("function" === typeof instance.componentWillUpdate && instance.componentWillUpdate( newProps, - renderExpirationTime, + newState, newUnmaskedContext ), "function" === typeof instance.UNSAFE_componentWillUpdate && instance.UNSAFE_componentWillUpdate( newProps, - renderExpirationTime, + newState, newUnmaskedContext )), "function" === typeof instance.componentDidUpdate && (workInProgress.effectTag |= 4), "function" === typeof instance.getSnapshotBeforeUpdate && - (workInProgress.effectTag |= 2048)) + (workInProgress.effectTag |= 256)) : ("function" !== typeof instance.componentDidUpdate || (oldProps === current.memoizedProps && oldContext === current.memoizedState) || @@ -2301,13 +2368,13 @@ function ReactFiberClassComponent( "function" !== typeof instance.getSnapshotBeforeUpdate || (oldProps === current.memoizedProps && oldContext === current.memoizedState) || - (workInProgress.effectTag |= 2048), - memoizeProps(workInProgress, newProps), - memoizeState(workInProgress, renderExpirationTime)); + (workInProgress.effectTag |= 256), + (workInProgress.memoizedProps = newProps), + (workInProgress.memoizedState = newState)); instance.props = newProps; - instance.state = renderExpirationTime; + instance.state = newState; instance.context = newUnmaskedContext; - return derivedStateFromProps; + return renderExpirationTime; } }; } @@ -2431,11 +2498,11 @@ function ChildReconciler(shouldTrackSideEffects) { returnFiber.mode, expirationTime )), - (current["return"] = returnFiber), + (current.return = returnFiber), current ); current = useFiber(current, textContent, expirationTime); - current["return"] = returnFiber; + current.return = returnFiber; return current; } function updateElement(returnFiber, current, element, expirationTime) { @@ -2443,7 +2510,7 @@ function ChildReconciler(shouldTrackSideEffects) { return ( (expirationTime = useFiber(current, element.props, expirationTime)), (expirationTime.ref = coerceRef(returnFiber, current, element)), - (expirationTime["return"] = returnFiber), + (expirationTime.return = returnFiber), expirationTime ); expirationTime = createFiberFromElement( @@ -2452,7 +2519,7 @@ function ChildReconciler(shouldTrackSideEffects) { expirationTime ); expirationTime.ref = coerceRef(returnFiber, current, element); - expirationTime["return"] = returnFiber; + expirationTime.return = returnFiber; return expirationTime; } function updatePortal(returnFiber, current, portal, expirationTime) { @@ -2468,11 +2535,11 @@ function ChildReconciler(shouldTrackSideEffects) { returnFiber.mode, expirationTime )), - (current["return"] = returnFiber), + (current.return = returnFiber), current ); current = useFiber(current, portal.children || [], expirationTime); - current["return"] = returnFiber; + current.return = returnFiber; return current; } function updateFragment(returnFiber, current, fragment, expirationTime, key) { @@ -2484,11 +2551,11 @@ function ChildReconciler(shouldTrackSideEffects) { expirationTime, key )), - (current["return"] = returnFiber), + (current.return = returnFiber), current ); current = useFiber(current, fragment, expirationTime); - current["return"] = returnFiber; + current.return = returnFiber; return current; } function createChild(returnFiber, newChild, expirationTime) { @@ -2499,7 +2566,7 @@ function ChildReconciler(shouldTrackSideEffects) { returnFiber.mode, expirationTime )), - (newChild["return"] = returnFiber), + (newChild.return = returnFiber), newChild ); if ("object" === typeof newChild && null !== newChild) { @@ -2512,7 +2579,7 @@ function ChildReconciler(shouldTrackSideEffects) { expirationTime )), (expirationTime.ref = coerceRef(returnFiber, null, newChild)), - (expirationTime["return"] = returnFiber), + (expirationTime.return = returnFiber), expirationTime ); case REACT_PORTAL_TYPE: @@ -2522,7 +2589,7 @@ function ChildReconciler(shouldTrackSideEffects) { returnFiber.mode, expirationTime )), - (newChild["return"] = returnFiber), + (newChild.return = returnFiber), newChild ); } @@ -2534,7 +2601,7 @@ function ChildReconciler(shouldTrackSideEffects) { expirationTime, null )), - (newChild["return"] = returnFiber), + (newChild.return = returnFiber), newChild ); throwOnInvalidObjectType(returnFiber, newChild); @@ -2721,17 +2788,21 @@ function ChildReconciler(shouldTrackSideEffects) { newChildren[newIdx], expirationTime )) - ) { - if (shouldTrackSideEffects && null !== nextOldFiber.alternate) - oldFiber["delete"]( + ) + 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; - } + ), + (currentFirstChild = placeChild( + nextOldFiber, + currentFirstChild, + newIdx + )), + null === previousNewFiber + ? (resultingFirstChild = nextOldFiber) + : (previousNewFiber.sibling = nextOldFiber), + (previousNewFiber = nextOldFiber); shouldTrackSideEffects && oldFiber.forEach(function(child) { return deleteChild(returnFiber, child); @@ -2805,24 +2876,22 @@ function ChildReconciler(shouldTrackSideEffects) { !step.done; newIdx++, step = newChildrenIterable.next() ) - if ( - ((step = updateFromMap( - oldFiber, - returnFiber, - newIdx, - step.value, - expirationTime - )), - null !== step) - ) { - if (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; - } + (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); @@ -2861,7 +2930,7 @@ function ChildReconciler(shouldTrackSideEffects) { isObject, newChild ); - currentFirstChild["return"] = returnFiber; + currentFirstChild.return = returnFiber; returnFiber = currentFirstChild; break a; } else { @@ -2878,7 +2947,7 @@ function ChildReconciler(shouldTrackSideEffects) { expirationTime, newChild.key )), - (currentFirstChild["return"] = returnFiber), + (currentFirstChild.return = returnFiber), (returnFiber = currentFirstChild)) : ((expirationTime = createFiberFromElement( newChild, @@ -2890,7 +2959,7 @@ function ChildReconciler(shouldTrackSideEffects) { currentFirstChild, newChild )), - (expirationTime["return"] = returnFiber), + (expirationTime.return = returnFiber), (returnFiber = expirationTime)); } return placeSingleChild(returnFiber); @@ -2914,7 +2983,7 @@ function ChildReconciler(shouldTrackSideEffects) { newChild.children || [], expirationTime ); - currentFirstChild["return"] = returnFiber; + currentFirstChild.return = returnFiber; returnFiber = currentFirstChild; break a; } else { @@ -2929,7 +2998,7 @@ function ChildReconciler(shouldTrackSideEffects) { returnFiber.mode, expirationTime ); - currentFirstChild["return"] = returnFiber; + currentFirstChild.return = returnFiber; returnFiber = currentFirstChild; } return placeSingleChild(returnFiber); @@ -2944,7 +3013,7 @@ function ChildReconciler(shouldTrackSideEffects) { newChild, expirationTime )), - (currentFirstChild["return"] = returnFiber), + (currentFirstChild.return = returnFiber), (returnFiber = currentFirstChild)) : (deleteRemainingChildren(returnFiber, currentFirstChild), (currentFirstChild = createFiberFromText( @@ -2952,7 +3021,7 @@ function ChildReconciler(shouldTrackSideEffects) { returnFiber.mode, expirationTime )), - (currentFirstChild["return"] = returnFiber), + (currentFirstChild.return = returnFiber), (returnFiber = currentFirstChild)), placeSingleChild(returnFiber) ); @@ -3038,10 +3107,10 @@ function ReactFiberBeginWork( workInProgress, shouldUpdate, hasContext, - didCaptureError, renderExpirationTime ) { markRef(current, workInProgress); + var didCaptureError = 0 !== (workInProgress.effectTag & 64); if (!shouldUpdate && !didCaptureError) return ( hasContext && invalidateContextProvider(workInProgress, !1), @@ -3089,11 +3158,8 @@ function ReactFiberBeginWork( renderExpirationTime ) { var fiber = workInProgress.child; - for ( - null !== fiber && (fiber["return"] = workInProgress); - null !== fiber; - - ) { + null !== fiber && (fiber.return = workInProgress); + for (; null !== fiber; ) { switch (fiber.tag) { case 12: var nextFiber = fiber.stateNode | 0; @@ -3116,7 +3182,7 @@ function ReactFiberBeginWork( ) alternate.expirationTime = renderExpirationTime; else break; - nextFiber = nextFiber["return"]; + nextFiber = nextFiber.return; } nextFiber = null; } else nextFiber = fiber.child; @@ -3127,7 +3193,7 @@ function ReactFiberBeginWork( default: nextFiber = fiber.child; } - if (null !== nextFiber) nextFiber["return"] = fiber; + if (null !== nextFiber) nextFiber.return = fiber; else for (nextFiber = fiber; null !== nextFiber; ) { if (nextFiber === workInProgress) { @@ -3136,10 +3202,11 @@ function ReactFiberBeginWork( } fiber = nextFiber.sibling; if (null !== fiber) { + fiber.return = nextFiber.return; nextFiber = fiber; break; } - nextFiber = nextFiber["return"]; + nextFiber = nextFiber.return; } fiber = nextFiber; } @@ -3151,8 +3218,10 @@ function ReactFiberBeginWork( ) { var context = workInProgress.type._context, newProps = workInProgress.pendingProps, - oldProps = workInProgress.memoizedProps; - if (!hasLegacyContextChanged() && oldProps === newProps) + oldProps = workInProgress.memoizedProps, + canBailOnProps = !0; + if (hasLegacyContextChanged()) canBailOnProps = !1; + else if (oldProps === newProps) return ( (workInProgress.stateNode = 0), pushProvider(workInProgress), @@ -3162,7 +3231,7 @@ function ReactFiberBeginWork( workInProgress.memoizedProps = newProps; if (null === oldProps) newValue = 1073741823; else if (oldProps.value === newProps.value) { - if (oldProps.children === newProps.children) + if (oldProps.children === newProps.children && canBailOnProps) return ( (workInProgress.stateNode = 0), pushProvider(workInProgress), @@ -3176,7 +3245,7 @@ function ReactFiberBeginWork( (0 !== oldValue || 1 / oldValue === 1 / newValue)) || (oldValue !== oldValue && newValue !== newValue) ) { - if (oldProps.children === newProps.children) + if (oldProps.children === newProps.children && canBailOnProps) return ( (workInProgress.stateNode = 0), pushProvider(workInProgress), @@ -3191,7 +3260,7 @@ function ReactFiberBeginWork( (newValue |= 0), 0 === newValue) ) { - if (oldProps.children === newProps.children) + if (oldProps.children === newProps.children && canBailOnProps) return ( (workInProgress.stateNode = 0), pushProvider(workInProgress), @@ -3223,14 +3292,14 @@ function ReactFiberBeginWork( current.expirationTime ); workInProgress.child = newChild; - for (newChild["return"] = workInProgress; null !== current.sibling; ) + for (newChild.return = workInProgress; null !== current.sibling; ) (current = current.sibling), (newChild = newChild.sibling = createWorkInProgress( current, current.pendingProps, current.expirationTime )), - (newChild["return"] = workInProgress); + (newChild.return = workInProgress); newChild.sibling = null; } return workInProgress.child; @@ -3262,7 +3331,6 @@ function ReactFiberBeginWork( } ); var adoptClassInstance = config.adoptClassInstance, - callGetDerivedStateFromProps = config.callGetDerivedStateFromProps, constructClassInstance = config.constructClassInstance, mountClassInstance = config.mountClassInstance, resumeMountClassInstance = config.resumeMountClassInstance, @@ -3311,20 +3379,13 @@ function ReactFiberBeginWork( (workInProgress.tag = 2), (workInProgress.memoizedState = null !== fn.state && void 0 !== fn.state ? fn.state : null), - "function" === typeof unmaskedContext.getDerivedStateFromProps && - ((props = callGetDerivedStateFromProps( + (unmaskedContext = unmaskedContext.getDerivedStateFromProps), + "function" === typeof unmaskedContext && + applyDerivedStateFromProps( workInProgress, - fn, - props, - workInProgress.memoizedState - )), - null !== props && - void 0 !== props && - (workInProgress.memoizedState = Object.assign( - {}, - workInProgress.memoizedState, - props - ))), + unmaskedContext, + props + ), (props = pushLegacyContextProvider(workInProgress)), adoptClassInstance(workInProgress, fn), mountClassInstance(workInProgress, renderExpirationTime), @@ -3333,7 +3394,6 @@ function ReactFiberBeginWork( workInProgress, !0, props, - !1, renderExpirationTime ))) : ((workInProgress.tag = 1), @@ -3361,103 +3421,100 @@ function ReactFiberBeginWork( current ); case 2: - props = pushLegacyContextProvider(workInProgress); - null === current - ? null === workInProgress.stateNode - ? (constructClassInstance( - workInProgress, - workInProgress.pendingProps - ), - mountClassInstance(workInProgress, renderExpirationTime), - (fn = !0)) - : (fn = resumeMountClassInstance( + return ( + (props = pushLegacyContextProvider(workInProgress)), + null === current + ? null === workInProgress.stateNode + ? (constructClassInstance( + workInProgress, + workInProgress.pendingProps, + renderExpirationTime + ), + mountClassInstance(workInProgress, renderExpirationTime), + (fn = !0)) + : (fn = resumeMountClassInstance( + workInProgress, + renderExpirationTime + )) + : (fn = updateClassInstance( + current, workInProgress, renderExpirationTime - )) - : (fn = updateClassInstance( - current, - workInProgress, - renderExpirationTime - )); - unmaskedContext = !1; - var updateQueue = workInProgress.updateQueue; - null !== updateQueue && - null !== updateQueue.capturedValues && - (unmaskedContext = fn = !0); - return finishClassComponent( - current, - workInProgress, - fn, - props, - unmaskedContext, - renderExpirationTime - ); - case 3: - a: if ( - (pushHostRootContext(workInProgress), - (fn = workInProgress.updateQueue), - null !== fn) - ) { - unmaskedContext = workInProgress.memoizedState; - props = processUpdateQueue( + )), + finishClassComponent( current, workInProgress, fn, - null, - null, + props, renderExpirationTime - ); - workInProgress.memoizedState = props; - fn = workInProgress.updateQueue; - if (null !== fn && null !== fn.capturedValues) fn = null; - else if (unmaskedContext === props) { - resetHydrationState(); - current = bailoutOnAlreadyFinishedWork(current, workInProgress); - break a; - } else fn = props.element; - unmaskedContext = workInProgress.stateNode; - (null === current || null === current.child) && - unmaskedContext.hydrate && - enterHydrationState(workInProgress) - ? ((workInProgress.effectTag |= 2), - (workInProgress.child = mountChildFibers( + ) + ); + case 3: + return ( + pushHostRootContext(workInProgress), + (props = workInProgress.updateQueue), + null !== props + ? ((fn = workInProgress.memoizedState), + (fn = null !== fn ? fn.element : null), + processUpdateQueue( workInProgress, + props, + workInProgress.pendingProps, null, - fn, renderExpirationTime - ))) + ), + (props = workInProgress.memoizedState.element), + props === fn + ? (resetHydrationState(), + (current = bailoutOnAlreadyFinishedWork( + current, + workInProgress + ))) + : ((fn = workInProgress.stateNode), + (null === current || null === current.child) && + fn.hydrate && + enterHydrationState(workInProgress) + ? ((workInProgress.effectTag |= 2), + (workInProgress.child = mountChildFibers( + workInProgress, + null, + props, + renderExpirationTime + ))) + : (resetHydrationState(), + reconcileChildren(current, workInProgress, props)), + (current = workInProgress.child))) : (resetHydrationState(), - reconcileChildren(current, workInProgress, fn)); - workInProgress.memoizedState = props; - current = workInProgress.child; - } else - resetHydrationState(), - (current = bailoutOnAlreadyFinishedWork(current, workInProgress)); - return current; + (current = bailoutOnAlreadyFinishedWork( + current, + workInProgress + ))), + current + ); case 5: a: { pushHostContext(workInProgress); null === current && tryToClaimNextHydratableInstance(workInProgress); props = workInProgress.type; - updateQueue = workInProgress.memoizedProps; + var memoizedProps = workInProgress.memoizedProps; fn = workInProgress.pendingProps; unmaskedContext = null !== current ? current.memoizedProps : null; - if (!hasLegacyContextChanged() && updateQueue === fn) { + if (!hasLegacyContextChanged() && memoizedProps === fn) { if ( - (updateQueue = + (memoizedProps = workInProgress.mode & 1 && shouldDeprioritizeSubtree(props, fn)) ) workInProgress.expirationTime = 1073741823; - if (!updateQueue || 1073741823 !== renderExpirationTime) { + if (!memoizedProps || 1073741823 !== renderExpirationTime) { current = bailoutOnAlreadyFinishedWork(current, workInProgress); break a; } } - updateQueue = fn.children; + memoizedProps = fn.children; shouldSetTextContent(props, fn) - ? (updateQueue = null) + ? (memoizedProps = null) : unmaskedContext && shouldSetTextContent(props, unmaskedContext) && (workInProgress.effectTag |= 16); @@ -3468,7 +3525,7 @@ function ReactFiberBeginWork( ? ((workInProgress.expirationTime = 1073741823), (workInProgress.memoizedProps = fn), (current = null)) - : (reconcileChildren(current, workInProgress, updateQueue), + : (reconcileChildren(current, workInProgress, memoizedProps), (workInProgress.memoizedProps = fn), (current = workInProgress.child)); } @@ -3534,14 +3591,21 @@ function ReactFiberBeginWork( ); case 14: return ( - (renderExpirationTime = workInProgress.type.render), - (renderExpirationTime = renderExpirationTime( - workInProgress.pendingProps, - workInProgress.ref - )), - reconcileChildren(current, workInProgress, renderExpirationTime), - (workInProgress.memoizedProps = renderExpirationTime), - workInProgress.child + (props = workInProgress.type.render), + (renderExpirationTime = workInProgress.pendingProps), + (fn = workInProgress.ref), + hasLegacyContextChanged() || + workInProgress.memoizedProps !== renderExpirationTime || + fn !== (null !== current ? current.ref : null) + ? ((props = props(renderExpirationTime, fn)), + reconcileChildren(current, workInProgress, props), + (workInProgress.memoizedProps = renderExpirationTime), + (current = workInProgress.child)) + : (current = bailoutOnAlreadyFinishedWork( + current, + workInProgress + )), + current ); case 10: return ( @@ -3590,13 +3654,13 @@ function ReactFiberBeginWork( a: { fn = workInProgress.type; unmaskedContext = workInProgress.pendingProps; - updateQueue = workInProgress.memoizedProps; + memoizedProps = workInProgress.memoizedProps; props = fn._currentValue; var changedBits = fn._changedBits; if ( hasLegacyContextChanged() || 0 !== changedBits || - updateQueue !== unmaskedContext + memoizedProps !== unmaskedContext ) { workInProgress.memoizedProps = unmaskedContext; var observedBits = unmaskedContext.unstable_observedBits; @@ -3610,12 +3674,13 @@ function ReactFiberBeginWork( changedBits, renderExpirationTime ); - else if (updateQueue === unmaskedContext) { + else if (memoizedProps === unmaskedContext) { current = bailoutOnAlreadyFinishedWork(current, workInProgress); break a; } renderExpirationTime = unmaskedContext.children; renderExpirationTime = renderExpirationTime(props); + workInProgress.effectTag |= 1; reconcileChildren(current, workInProgress, renderExpirationTime); current = workInProgress.child; } else @@ -3681,18 +3746,7 @@ function ReactFiberCompleteWork( case 1: return null; case 2: - return ( - popLegacyContextProvider(workInProgress), - (current = workInProgress.stateNode), - (newProps = workInProgress.updateQueue), - null !== newProps && - null !== newProps.capturedValues && - ((workInProgress.effectTag &= -65), - "function" === typeof current.componentDidCatch - ? (workInProgress.effectTag |= 256) - : (newProps.capturedValues = null)), - null - ); + return popLegacyContextProvider(workInProgress), null; case 3: popHostContainer(workInProgress); popTopLevelLegacyContextObject(workInProgress); @@ -3703,10 +3757,6 @@ function ReactFiberCompleteWork( if (null === current || null === current.child) popHydrationState(workInProgress), (workInProgress.effectTag &= -3); updateHostContainer(workInProgress); - current = workInProgress.updateQueue; - null !== current && - null !== current.capturedValues && - (workInProgress.effectTag |= 256); return null; case 5: popHostContext(workInProgress); @@ -3714,10 +3764,10 @@ function ReactFiberCompleteWork( var type = workInProgress.type; if (null !== current && null != workInProgress.stateNode) { var oldProps = current.memoizedProps, - _instance = workInProgress.stateNode, + instance = workInProgress.stateNode, currentHostContext = getHostContext(); - _instance = prepareUpdate( - _instance, + instance = prepareUpdate( + instance, type, oldProps, newProps, @@ -3727,7 +3777,7 @@ function ReactFiberCompleteWork( updateHostComponent( current, workInProgress, - _instance, + instance, type, oldProps, newProps, @@ -3774,21 +3824,20 @@ function ReactFiberCompleteWork( 4 !== currentHostContext.tag && null !== currentHostContext.child ) { - currentHostContext.child["return"] = currentHostContext; + currentHostContext.child.return = currentHostContext; currentHostContext = currentHostContext.child; continue; } if (currentHostContext === workInProgress) break; for (; null === currentHostContext.sibling; ) { if ( - null === currentHostContext["return"] || - currentHostContext["return"] === workInProgress + null === currentHostContext.return || + currentHostContext.return === workInProgress ) break a; - currentHostContext = currentHostContext["return"]; + currentHostContext = currentHostContext.return; } - currentHostContext.sibling["return"] = - currentHostContext["return"]; + currentHostContext.sibling.return = currentHostContext.return; currentHostContext = currentHostContext.sibling; } finalizeInitialChildren( @@ -3841,30 +3890,34 @@ function ReactFiberCompleteWork( ); workInProgress.tag = 8; type = []; - a: for ( - (oldProps = workInProgress.stateNode) && - (oldProps["return"] = workInProgress); - null !== oldProps; - - ) { - if (5 === oldProps.tag || 6 === oldProps.tag || 4 === oldProps.tag) - invariant(!1, "A call cannot have host component children."); - else if (9 === oldProps.tag) type.push(oldProps.pendingProps.value); - else if (null !== oldProps.child) { - oldProps.child["return"] = oldProps; - oldProps = oldProps.child; - continue; - } - for (; null === oldProps.sibling; ) { + a: { + if ((oldProps = workInProgress.stateNode)) + oldProps.return = workInProgress; + for (; null !== oldProps; ) { if ( - null === oldProps["return"] || - oldProps["return"] === workInProgress + 5 === oldProps.tag || + 6 === oldProps.tag || + 4 === oldProps.tag ) - break a; - oldProps = oldProps["return"]; + invariant(!1, "A call cannot have host component children."); + else if (9 === oldProps.tag) + type.push(oldProps.pendingProps.value); + else if (null !== oldProps.child) { + oldProps.child.return = oldProps; + oldProps = oldProps.child; + continue; + } + for (; null === oldProps.sibling; ) { + if ( + null === oldProps.return || + oldProps.return === workInProgress + ) + break a; + oldProps = oldProps.return; + } + oldProps.sibling.return = oldProps.return; + oldProps = oldProps.sibling; } - oldProps.sibling["return"] = oldProps["return"]; - oldProps = oldProps.sibling; } oldProps = newProps.handler; newProps = oldProps(newProps.props, type); @@ -3909,103 +3962,11 @@ function ReactFiberCompleteWork( } }; } -function ReactFiberUnwindWork( - hostContext, - legacyContext, - newContext, - scheduleWork, - isAlreadyFailedLegacyErrorBoundary -) { - var popHostContainer = hostContext.popHostContainer, - popHostContext = hostContext.popHostContext, - popLegacyContextProvider = legacyContext.popContextProvider, - popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject, - popProvider = newContext.popProvider; +function createCapturedValue(value, source) { return { - throwException: function(returnFiber, sourceFiber, rawValue) { - sourceFiber.effectTag |= 512; - sourceFiber.firstEffect = sourceFiber.lastEffect = null; - sourceFiber = { - value: rawValue, - source: sourceFiber, - stack: getStackAddendumByWorkInProgressFiber(sourceFiber) - }; - do { - switch (returnFiber.tag) { - case 3: - ensureUpdateQueues(returnFiber); - returnFiber.updateQueue.capturedValues = [sourceFiber]; - returnFiber.effectTag |= 1024; - return; - case 2: - if ( - ((rawValue = returnFiber.stateNode), - 0 === (returnFiber.effectTag & 64) && - null !== rawValue && - "function" === typeof rawValue.componentDidCatch && - !isAlreadyFailedLegacyErrorBoundary(rawValue)) - ) { - ensureUpdateQueues(returnFiber); - rawValue = returnFiber.updateQueue; - var capturedValues = rawValue.capturedValues; - null === capturedValues - ? (rawValue.capturedValues = [sourceFiber]) - : capturedValues.push(sourceFiber); - returnFiber.effectTag |= 1024; - return; - } - } - returnFiber = returnFiber["return"]; - } while (null !== returnFiber); - }, - unwindWork: function(workInProgress) { - switch (workInProgress.tag) { - case 2: - popLegacyContextProvider(workInProgress); - var effectTag = workInProgress.effectTag; - return effectTag & 1024 - ? ((workInProgress.effectTag = (effectTag & -1025) | 64), - workInProgress) - : null; - case 3: - return ( - popHostContainer(workInProgress), - popTopLevelLegacyContextObject(workInProgress), - (effectTag = workInProgress.effectTag), - effectTag & 1024 - ? ((workInProgress.effectTag = (effectTag & -1025) | 64), - workInProgress) - : null - ); - case 5: - return popHostContext(workInProgress), null; - case 4: - return popHostContainer(workInProgress), null; - case 13: - return popProvider(workInProgress), null; - default: - return null; - } - }, - unwindInterruptedWork: function(interruptedWork) { - switch (interruptedWork.tag) { - case 2: - popLegacyContextProvider(interruptedWork); - break; - case 3: - popHostContainer(interruptedWork); - popTopLevelLegacyContextObject(interruptedWork); - break; - case 5: - popHostContext(interruptedWork); - break; - case 4: - popHostContainer(interruptedWork); - break; - case 13: - popProvider(interruptedWork); - } - } + value: value, + source: source, + stack: getStackAddendumByWorkInProgressFiber(source) }; } function logError(boundary, errorInfo) { @@ -4037,13 +3998,7 @@ function logError(boundary, errorInfo) { (e && e.suppressReactErrorLogging) || console.error(e); } } -function ReactFiberCommitWork( - config, - captureError, - scheduleWork, - computeExpirationForFiber, - markLegacyErrorBoundaryAsFailed -) { +function ReactFiberCommitWork(config, captureError) { function safelyDetachRef(current) { var ref = current.ref; if (null !== ref) @@ -4060,12 +4015,12 @@ function ReactFiberCommitWork( switch (current.tag) { case 2: safelyDetachRef(current); - var _instance7 = current.stateNode; - if ("function" === typeof _instance7.componentWillUnmount) + var _instance6 = current.stateNode; + if ("function" === typeof _instance6.componentWillUnmount) try { - (_instance7.props = current.memoizedProps), - (_instance7.state = current.memoizedState), - _instance7.componentWillUnmount(); + (_instance6.props = current.memoizedProps), + (_instance6.state = current.memoizedState), + _instance6.componentWillUnmount(); } catch (unmountError) { captureError(current, unmountError); } @@ -4088,12 +4043,12 @@ function ReactFiberCommitWork( ) { if (node === root) break; for (; null === node.sibling; ) { - if (null === node["return"] || node["return"] === root) return; - node = node["return"]; + if (null === node.return || node.return === root) return; + node = node.return; } - node.sibling["return"] = node["return"]; + node.sibling.return = node.return; node = node.sibling; - } else (node.child["return"] = node), (node = node.child); + } else (node.child.return = node), (node = node.child); } function isHostParent(fiber) { return 5 === fiber.tag || 3 === fiber.tag || 4 === fiber.tag; @@ -4108,7 +4063,7 @@ function ReactFiberCommitWork( ) { if (!currentParentIsValid) { - currentParentIsValid = node["return"]; + currentParentIsValid = node.return; a: for (;;) { invariant( null !== currentParentIsValid, @@ -4128,7 +4083,7 @@ function ReactFiberCommitWork( currentParentIsContainer = !0; break a; } - currentParentIsValid = currentParentIsValid["return"]; + currentParentIsValid = currentParentIsValid.return; } currentParentIsValid = !0; } @@ -4143,17 +4098,17 @@ function ReactFiberCommitWork( : commitUnmount(node), null !== node.child) ) { - node.child["return"] = node; + node.child.return = node; node = node.child; continue; } if (node === current) break; for (; null === node.sibling; ) { - if (null === node["return"] || node["return"] === current) return; - node = node["return"]; + if (null === node.return || node.return === current) return; + node = node.return; 4 === node.tag && (currentParentIsValid = !1); } - node.sibling["return"] = node["return"]; + node.sibling.return = node.return; node = node.sibling; } } @@ -4178,7 +4133,7 @@ function ReactFiberCommitWork( commitBeforeMutationLifeCycles: function(current, finishedWork) { switch (finishedWork.tag) { case 2: - if (finishedWork.effectTag & 2048 && null !== current) { + if (finishedWork.effectTag & 256 && null !== current) { var prevProps = current.memoizedProps, prevState = current.memoizedState; current = finishedWork.stateNode; @@ -4208,12 +4163,12 @@ function ReactFiberCommitWork( }, commitPlacement: function(finishedWork) { a: { - for (var parent = finishedWork["return"]; null !== parent; ) { + for (var parent = finishedWork.return; null !== parent; ) { if (isHostParent(parent)) { var parentFiber = parent; break a; } - parent = parent["return"]; + parent = parent.return; } invariant( !1, @@ -4245,16 +4200,13 @@ function ReactFiberCommitWork( (resetTextContent(parent), (parentFiber.effectTag &= -17)); a: b: for (parentFiber = finishedWork; ; ) { for (; null === parentFiber.sibling; ) { - if ( - null === parentFiber["return"] || - isHostParent(parentFiber["return"]) - ) { + if (null === parentFiber.return || isHostParent(parentFiber.return)) { parentFiber = null; break a; } - parentFiber = parentFiber["return"]; + parentFiber = parentFiber.return; } - parentFiber.sibling["return"] = parentFiber["return"]; + parentFiber.sibling.return = parentFiber.return; for ( parentFiber = parentFiber.sibling; 5 !== parentFiber.tag && 6 !== parentFiber.tag; @@ -4263,7 +4215,7 @@ function ReactFiberCommitWork( if (parentFiber.effectTag & 2) continue b; if (null === parentFiber.child || 4 === parentFiber.tag) continue b; else - (parentFiber.child["return"] = parentFiber), + (parentFiber.child.return = parentFiber), (parentFiber = parentFiber.child); } if (!(parentFiber.effectTag & 2)) { @@ -4281,35 +4233,33 @@ function ReactFiberCommitWork( ? appendChildToContainer(parent, node.stateNode) : appendChild(parent, node.stateNode); else if (4 !== node.tag && null !== node.child) { - node.child["return"] = node; + 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"]; + if (null === node.return || node.return === finishedWork) return; + node = node.return; } - node.sibling["return"] = node["return"]; + node.sibling.return = node.return; node = node.sibling; } }, commitDeletion: function(current) { unmountHostComponents(current); - current["return"] = null; + current.return = null; current.child = null; current.alternate && - ((current.alternate.child = null), - (current.alternate["return"] = null)); + ((current.alternate.child = null), (current.alternate.return = null)); }, commitWork: function(current, finishedWork) { switch (finishedWork.tag) { case 2: break; case 5: - var _instance8 = finishedWork.stateNode; - if (null != _instance8) { + var _instance7 = finishedWork.stateNode; + if (null != _instance7) { var newProps = finishedWork.memoizedProps; current = null !== current ? current.memoizedProps : newProps; var type = finishedWork.type, @@ -4317,7 +4267,7 @@ function ReactFiberCommitWork( finishedWork.updateQueue = null; null !== updatePayload && commitUpdate( - _instance8, + _instance7, updatePayload, type, current, @@ -4331,11 +4281,11 @@ function ReactFiberCommitWork( null !== finishedWork.stateNode, "This should have a text node initialized. This error is likely caused by a bug in React. Please file an issue." ); - _instance8 = finishedWork.memoizedProps; + _instance7 = finishedWork.memoizedProps; commitTextUpdate( finishedWork.stateNode, - null !== current ? current.memoizedProps : _instance8, - _instance8 + null !== current ? current.memoizedProps : _instance7, + _instance7 ); break; case 3: @@ -4347,28 +4297,40 @@ function ReactFiberCommitWork( ); } }, - commitLifeCycles: function(finishedRoot, current, finishedWork) { + commitLifeCycles: function( + finishedRoot, + current, + finishedWork, + currentTime, + committedExpirationTime + ) { switch (finishedWork.tag) { case 2: finishedRoot = finishedWork.stateNode; - if (finishedWork.effectTag & 4) - if (null === current) - (finishedRoot.props = finishedWork.memoizedProps), + finishedWork.effectTag & 4 && + (null === current + ? ((finishedRoot.props = finishedWork.memoizedProps), (finishedRoot.state = finishedWork.memoizedState), - finishedRoot.componentDidMount(); - else { - var prevProps = current.memoizedProps; - current = current.memoizedState; - finishedRoot.props = finishedWork.memoizedProps; - finishedRoot.state = finishedWork.memoizedState; - finishedRoot.componentDidUpdate( - prevProps, - current, - finishedRoot.__reactInternalSnapshotBeforeUpdate - ); - } - finishedWork = finishedWork.updateQueue; - null !== finishedWork && commitCallbacks(finishedWork, finishedRoot); + finishedRoot.componentDidMount()) + : ((currentTime = current.memoizedProps), + (current = current.memoizedState), + (finishedRoot.props = finishedWork.memoizedProps), + (finishedRoot.state = finishedWork.memoizedState), + finishedRoot.componentDidUpdate( + currentTime, + current, + finishedRoot.__reactInternalSnapshotBeforeUpdate + ))); + current = finishedWork.updateQueue; + null !== current && + ((finishedRoot.props = finishedWork.memoizedProps), + (finishedRoot.state = finishedWork.memoizedState), + commitUpdateQueue( + finishedWork, + current, + finishedRoot, + committedExpirationTime + )); break; case 3: current = finishedWork.updateQueue; @@ -4384,15 +4346,20 @@ function ReactFiberCommitWork( case 2: finishedRoot = finishedWork.child.stateNode; } - commitCallbacks(current, finishedRoot); + commitUpdateQueue( + finishedWork, + current, + finishedRoot, + committedExpirationTime + ); } break; case 5: - finishedRoot = finishedWork.stateNode; + committedExpirationTime = finishedWork.stateNode; null === current && finishedWork.effectTag & 4 && commitMount( - finishedRoot, + committedExpirationTime, finishedWork.type, finishedWork.memoizedProps, finishedWork @@ -4409,62 +4376,16 @@ function ReactFiberCommitWork( ); } }, - commitErrorLogging: function(finishedWork, onUncaughtError) { - switch (finishedWork.tag) { - case 2: - var ctor = finishedWork.type; - onUncaughtError = finishedWork.stateNode; - var updateQueue = finishedWork.updateQueue; - invariant( - null !== updateQueue && null !== updateQueue.capturedValues, - "An error logging effect should not have been scheduled if no errors were captured. This error is likely caused by a bug in React. Please file an issue." - ); - var capturedErrors = updateQueue.capturedValues; - updateQueue.capturedValues = null; - "function" !== typeof ctor.getDerivedStateFromCatch && - markLegacyErrorBoundaryAsFailed(onUncaughtError); - onUncaughtError.props = finishedWork.memoizedProps; - onUncaughtError.state = finishedWork.memoizedState; - for (ctor = 0; ctor < capturedErrors.length; ctor++) { - updateQueue = capturedErrors[ctor]; - var _error = updateQueue.value, - stack = updateQueue.stack; - logError(finishedWork, updateQueue); - onUncaughtError.componentDidCatch(_error, { - componentStack: null !== stack ? stack : "" - }); - } - break; - case 3: - ctor = finishedWork.updateQueue; - invariant( - null !== ctor && null !== ctor.capturedValues, - "An error logging effect should not have been scheduled if no errors were captured. This error is likely caused by a bug in React. Please file an issue." - ); - capturedErrors = ctor.capturedValues; - ctor.capturedValues = null; - for (ctor = 0; ctor < capturedErrors.length; ctor++) - (updateQueue = capturedErrors[ctor]), - logError(finishedWork, updateQueue), - onUncaughtError(updateQueue.value); - break; - default: - invariant( - !1, - "This unit of work tag cannot capture errors. This error is likely caused by a bug in React. Please file an issue." - ); - } - }, commitAttachRef: function(finishedWork) { var ref = finishedWork.ref; if (null !== ref) { - var _instance6 = finishedWork.stateNode; + var _instance5 = finishedWork.stateNode; switch (finishedWork.tag) { case 5: - finishedWork = getPublicInstance(_instance6); + finishedWork = getPublicInstance(_instance5); break; default: - finishedWork = _instance6; + finishedWork = _instance5; } "function" === typeof ref ? ref(finishedWork) @@ -4480,6 +4401,151 @@ function ReactFiberCommitWork( } }; } +function ReactFiberUnwindWork( + hostContext, + legacyContext, + newContext, + scheduleWork, + markLegacyErrorBoundaryAsFailed, + isAlreadyFailedLegacyErrorBoundary, + onUncaughtError +) { + function createRootErrorUpdate(fiber, errorInfo, expirationTime) { + expirationTime = createUpdate(expirationTime); + expirationTime.tag = 3; + expirationTime.payload = { element: null }; + var error = errorInfo.value; + expirationTime.callback = function() { + onUncaughtError(error); + logError(fiber, errorInfo); + }; + return expirationTime; + } + function createClassErrorUpdate(fiber, errorInfo, expirationTime) { + expirationTime = createUpdate(expirationTime); + expirationTime.tag = 3; + var inst = fiber.stateNode; + null !== inst && + "function" === typeof inst.componentDidCatch && + (expirationTime.callback = function() { + markLegacyErrorBoundaryAsFailed(this); + var error = errorInfo.value, + stack = errorInfo.stack; + logError(fiber, errorInfo); + this.componentDidCatch(error, { + componentStack: null !== stack ? stack : "" + }); + }); + return expirationTime; + } + var popHostContainer = hostContext.popHostContainer, + popHostContext = hostContext.popHostContext, + popLegacyContextProvider = legacyContext.popContextProvider, + popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject, + popProvider = newContext.popProvider; + return { + throwException: function( + returnFiber, + sourceFiber, + rawValue, + renderExpirationTime + ) { + sourceFiber.effectTag |= 512; + sourceFiber.firstEffect = sourceFiber.lastEffect = null; + sourceFiber = createCapturedValue(rawValue, sourceFiber); + do { + switch (returnFiber.tag) { + case 3: + returnFiber.effectTag |= 1024; + sourceFiber = createRootErrorUpdate( + returnFiber, + sourceFiber, + renderExpirationTime + ); + enqueueCapturedUpdate( + returnFiber, + sourceFiber, + renderExpirationTime + ); + return; + case 2: + rawValue = sourceFiber; + var _instance = returnFiber.stateNode; + if ( + 0 === (returnFiber.effectTag & 64) && + null !== _instance && + "function" === typeof _instance.componentDidCatch && + !isAlreadyFailedLegacyErrorBoundary(_instance) + ) { + returnFiber.effectTag |= 1024; + sourceFiber = createClassErrorUpdate( + returnFiber, + rawValue, + renderExpirationTime + ); + enqueueCapturedUpdate( + returnFiber, + sourceFiber, + renderExpirationTime + ); + return; + } + } + returnFiber = returnFiber.return; + } while (null !== returnFiber); + }, + unwindWork: function(workInProgress) { + switch (workInProgress.tag) { + case 2: + popLegacyContextProvider(workInProgress); + var effectTag = workInProgress.effectTag; + return effectTag & 1024 + ? ((workInProgress.effectTag = (effectTag & -1025) | 64), + workInProgress) + : null; + case 3: + return ( + popHostContainer(workInProgress), + popTopLevelLegacyContextObject(workInProgress), + (effectTag = workInProgress.effectTag), + effectTag & 1024 + ? ((workInProgress.effectTag = (effectTag & -1025) | 64), + workInProgress) + : null + ); + case 5: + return popHostContext(workInProgress), null; + case 4: + return popHostContainer(workInProgress), null; + case 13: + return popProvider(workInProgress), null; + default: + return null; + } + }, + unwindInterruptedWork: function(interruptedWork) { + switch (interruptedWork.tag) { + case 2: + popLegacyContextProvider(interruptedWork); + break; + case 3: + popHostContainer(interruptedWork); + popTopLevelLegacyContextObject(interruptedWork); + break; + case 5: + popHostContext(interruptedWork); + break; + case 4: + popHostContainer(interruptedWork); + break; + case 13: + popProvider(interruptedWork); + } + }, + createRootErrorUpdate: createRootErrorUpdate, + createClassErrorUpdate: createClassErrorUpdate + }; +} var NO_CONTEXT = {}; function ReactFiberHostContext(config, stack) { function requiredContext(c) { @@ -4536,7 +4602,7 @@ function ReactFiberHydrationContext(config) { var fiber = new FiberNode(5, null, null, 0); fiber.type = "DELETED"; fiber.stateNode = instance; - fiber["return"] = returnFiber; + fiber.return = returnFiber; fiber.effectTag = 8; null !== returnFiber.lastEffect ? ((returnFiber.lastEffect.nextEffect = fiber), @@ -4568,11 +4634,11 @@ function ReactFiberHydrationContext(config) { } function popToNextHostParent(fiber) { for ( - fiber = fiber["return"]; + fiber = fiber.return; null !== fiber && 5 !== fiber.tag && 3 !== fiber.tag; ) - fiber = fiber["return"]; + fiber = fiber.return; hydrationParentFiber = fiber; } var shouldSetTextContent = config.shouldSetTextContent; @@ -4806,7 +4872,7 @@ function ReactFiberLegacyContext(stack) { ) { if (isContextProvider(fiber)) return fiber.stateNode.__reactInternalMemoizedMergedChildContext; - fiber = fiber["return"]; + fiber = fiber.return; invariant( fiber, "Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue." @@ -4873,12 +4939,12 @@ function ReactFiberScheduler(config) { function resetStack() { if (null !== nextUnitOfWork) for ( - var interruptedWork = nextUnitOfWork["return"]; + var interruptedWork = nextUnitOfWork.return; null !== interruptedWork; ) unwindInterruptedWork(interruptedWork), - (interruptedWork = interruptedWork["return"]); + (interruptedWork = interruptedWork.return); nextRoot = null; nextRenderExpirationTime = 0; nextUnitOfWork = null; @@ -4890,74 +4956,71 @@ function ReactFiberScheduler(config) { legacyErrorBoundariesThatAlreadyFailed.has(instance) ); } - function completeUnitOfWork(workInProgress$jscomp$0) { + function markLegacyErrorBoundaryAsFailed(instance) { + null === legacyErrorBoundariesThatAlreadyFailed + ? (legacyErrorBoundariesThatAlreadyFailed = new Set([instance])) + : legacyErrorBoundariesThatAlreadyFailed.add(instance); + } + function completeUnitOfWork(workInProgress) { for (;;) { - var current = workInProgress$jscomp$0.alternate, - returnFiber = workInProgress$jscomp$0["return"], - siblingFiber = workInProgress$jscomp$0.sibling; - if (0 === (workInProgress$jscomp$0.effectTag & 512)) { + var current = workInProgress.alternate, + returnFiber = workInProgress.return, + siblingFiber = workInProgress.sibling; + if (0 === (workInProgress.effectTag & 512)) { current = completeWork( current, - workInProgress$jscomp$0, + workInProgress, nextRenderExpirationTime ); - var workInProgress = workInProgress$jscomp$0; if ( 1073741823 === nextRenderExpirationTime || 1073741823 !== workInProgress.expirationTime ) { - b: switch (workInProgress.tag) { + var newExpirationTime = 0; + switch (workInProgress.tag) { case 3: case 2: - var newExpirationTime = workInProgress.updateQueue; - newExpirationTime = - null === newExpirationTime - ? 0 - : newExpirationTime.expirationTime; - break b; - default: - newExpirationTime = 0; + var updateQueue = workInProgress.updateQueue; + null !== updateQueue && + (newExpirationTime = updateQueue.expirationTime); } - for (var child = workInProgress.child; null !== child; ) - 0 !== child.expirationTime && + for (updateQueue = workInProgress.child; null !== updateQueue; ) + 0 !== updateQueue.expirationTime && (0 === newExpirationTime || - newExpirationTime > child.expirationTime) && - (newExpirationTime = child.expirationTime), - (child = child.sibling); + newExpirationTime > updateQueue.expirationTime) && + (newExpirationTime = updateQueue.expirationTime), + (updateQueue = updateQueue.sibling); workInProgress.expirationTime = newExpirationTime; } if (null !== current) return current; null !== returnFiber && 0 === (returnFiber.effectTag & 512) && (null === returnFiber.firstEffect && - (returnFiber.firstEffect = workInProgress$jscomp$0.firstEffect), - null !== workInProgress$jscomp$0.lastEffect && + (returnFiber.firstEffect = workInProgress.firstEffect), + null !== workInProgress.lastEffect && (null !== returnFiber.lastEffect && - (returnFiber.lastEffect.nextEffect = - workInProgress$jscomp$0.firstEffect), - (returnFiber.lastEffect = workInProgress$jscomp$0.lastEffect)), - 1 < workInProgress$jscomp$0.effectTag && + (returnFiber.lastEffect.nextEffect = workInProgress.firstEffect), + (returnFiber.lastEffect = workInProgress.lastEffect)), + 1 < workInProgress.effectTag && (null !== returnFiber.lastEffect - ? (returnFiber.lastEffect.nextEffect = workInProgress$jscomp$0) - : (returnFiber.firstEffect = workInProgress$jscomp$0), - (returnFiber.lastEffect = workInProgress$jscomp$0))); + ? (returnFiber.lastEffect.nextEffect = workInProgress) + : (returnFiber.firstEffect = workInProgress), + (returnFiber.lastEffect = workInProgress))); if (null !== siblingFiber) return siblingFiber; - if (null !== returnFiber) workInProgress$jscomp$0 = returnFiber; + if (null !== returnFiber) workInProgress = returnFiber; else { isRootReadyForCommit = !0; break; } } else { - workInProgress$jscomp$0 = unwindWork(workInProgress$jscomp$0); - if (null !== workInProgress$jscomp$0) - return ( - (workInProgress$jscomp$0.effectTag &= 2559), workInProgress$jscomp$0 - ); + workInProgress = unwindWork(workInProgress); + if (null !== workInProgress) + return (workInProgress.effectTag &= 511), workInProgress; null !== returnFiber && ((returnFiber.firstEffect = returnFiber.lastEffect = null), (returnFiber.effectTag |= 512)); if (null !== siblingFiber) return siblingFiber; - if (null !== returnFiber) workInProgress$jscomp$0 = returnFiber; + if (null !== returnFiber) workInProgress = returnFiber; else break; } } @@ -5009,13 +5072,18 @@ function ReactFiberScheduler(config) { break; } isAsync = nextUnitOfWork; - var returnFiber = isAsync["return"]; + var returnFiber = isAsync.return; if (null === returnFiber) { didFatal = !0; onUncaughtError(thrownValue); break; } - throwException(returnFiber, isAsync, thrownValue); + throwException( + returnFiber, + isAsync, + thrownValue, + nextRenderExpirationTime + ); nextUnitOfWork = completeUnitOfWork(isAsync); } break; @@ -5032,55 +5100,61 @@ function ReactFiberScheduler(config) { "Expired work should have completed. This error is likely caused by a bug in React. Please file an issue." ); } - function scheduleCapture(sourceFiber, boundaryFiber, value, expirationTime) { - sourceFiber = { - value: value, - source: sourceFiber, - stack: getStackAddendumByWorkInProgressFiber(sourceFiber) - }; - insertUpdateIntoFiber(boundaryFiber, { - expirationTime: expirationTime, - partialState: null, - callback: null, - isReplace: !1, - isForced: !1, - capturedValue: sourceFiber, - next: null - }); - scheduleWork(boundaryFiber, expirationTime); - } - function onCommitPhaseError(fiber$jscomp$0, error) { + function onCommitPhaseError(fiber, error) { + var JSCompiler_inline_result; a: { invariant( !isWorking || isCommitting, "dispatch: Cannot dispatch during the render phase." ); - for (var fiber = fiber$jscomp$0["return"]; null !== fiber; ) { - switch (fiber.tag) { + for ( + JSCompiler_inline_result = fiber.return; + null !== JSCompiler_inline_result; + + ) { + switch (JSCompiler_inline_result.tag) { case 2: - var instance = fiber.stateNode; + var instance = JSCompiler_inline_result.stateNode; if ( - "function" === typeof fiber.type.getDerivedStateFromCatch || + "function" === + typeof JSCompiler_inline_result.type.getDerivedStateFromCatch || ("function" === typeof instance.componentDidCatch && !isAlreadyFailedLegacyErrorBoundary(instance)) ) { - scheduleCapture(fiber$jscomp$0, fiber, error, 1); - fiber$jscomp$0 = void 0; + fiber = createCapturedValue(error, fiber); + fiber = createClassErrorUpdate( + JSCompiler_inline_result, + fiber, + 1 + ); + enqueueUpdate(JSCompiler_inline_result, fiber, 1); + scheduleWork(JSCompiler_inline_result, 1); + JSCompiler_inline_result = void 0; break a; } break; case 3: - scheduleCapture(fiber$jscomp$0, fiber, error, 1); - fiber$jscomp$0 = void 0; + fiber = createCapturedValue(error, fiber); + fiber = createRootErrorUpdate(JSCompiler_inline_result, fiber, 1); + enqueueUpdate(JSCompiler_inline_result, fiber, 1); + scheduleWork(JSCompiler_inline_result, 1); + JSCompiler_inline_result = void 0; break a; } - fiber = fiber["return"]; + JSCompiler_inline_result = JSCompiler_inline_result.return; } - 3 === fiber$jscomp$0.tag && - scheduleCapture(fiber$jscomp$0, fiber$jscomp$0, error, 1); - fiber$jscomp$0 = void 0; + 3 === fiber.tag && + ((JSCompiler_inline_result = createCapturedValue(error, fiber)), + (JSCompiler_inline_result = createRootErrorUpdate( + fiber, + JSCompiler_inline_result, + 1 + )), + enqueueUpdate(fiber, JSCompiler_inline_result, 1), + scheduleWork(fiber, 1)); + JSCompiler_inline_result = void 0; } - return fiber$jscomp$0; + return JSCompiler_inline_result; } function computeExpirationForFiber(fiber) { fiber = @@ -5108,7 +5182,7 @@ function ReactFiberScheduler(config) { (0 === fiber.alternate.expirationTime || fiber.alternate.expirationTime > expirationTime) && (fiber.alternate.expirationTime = expirationTime); - if (null === fiber["return"]) + if (null === fiber.return) if (3 === fiber.tag) { var root = fiber.stateNode; !isWorking && @@ -5126,7 +5200,7 @@ function ReactFiberScheduler(config) { expirationTime = void 0; break a; } - fiber = fiber["return"]; + fiber = fiber.return; } expirationTime = void 0; } @@ -5366,7 +5440,7 @@ function ReactFiberScheduler(config) { error = void 0; try { for (; null !== nextEffect; ) - nextEffect.effectTag & 2048 && + nextEffect.effectTag & 256 && commitBeforeMutationLifeCycles(nextEffect.alternate, nextEffect), (nextEffect = nextEffect.nextEffect); } catch (e) { @@ -5442,8 +5516,6 @@ function ReactFiberScheduler(config) { didError, error ); - effectTag$jscomp$0 & 256 && - commitErrorLogging(nextEffect, onUncaughtError); effectTag$jscomp$0 & 128 && commitAttachRef(nextEffect); var next = nextEffect.nextEffect; nextEffect.nextEffect = null; @@ -5506,21 +5578,21 @@ function ReactFiberScheduler(config) { legacyContext, stack, scheduleWork, - isAlreadyFailedLegacyErrorBoundary + markLegacyErrorBoundaryAsFailed, + isAlreadyFailedLegacyErrorBoundary, + onUncaughtError ); var throwException = hostContext.throwException, unwindWork = hostContext.unwindWork, - unwindInterruptedWork = hostContext.unwindInterruptedWork; + unwindInterruptedWork = hostContext.unwindInterruptedWork, + createRootErrorUpdate = hostContext.createRootErrorUpdate, + createClassErrorUpdate = hostContext.createClassErrorUpdate; hostContext = ReactFiberCommitWork( config, onCommitPhaseError, scheduleWork, computeExpirationForFiber, - function(instance) { - null === legacyErrorBoundariesThatAlreadyFailed - ? (legacyErrorBoundariesThatAlreadyFailed = new Set([instance])) - : legacyErrorBoundariesThatAlreadyFailed.add(instance); - }, + markLegacyErrorBoundaryAsFailed, recalculateCurrentTime ); var commitBeforeMutationLifeCycles = @@ -5530,7 +5602,6 @@ function ReactFiberScheduler(config) { commitDeletion = hostContext.commitDeletion, commitWork = hostContext.commitWork, commitLifeCycles = hostContext.commitLifeCycles, - commitErrorLogging = hostContext.commitErrorLogging, commitAttachRef = hostContext.commitAttachRef, commitDetachRef = hostContext.commitDetachRef, now = config.now, @@ -5698,15 +5769,11 @@ function ReactFiberReconciler$1(config) { ? (container.context = parentComponent) : (container.pendingContext = parentComponent); container = callback; - insertUpdateIntoFiber(currentTime, { - expirationTime: expirationTime, - partialState: { element: element }, - callback: void 0 === container ? null : container, - isReplace: !1, - isForced: !1, - capturedValue: null, - next: null - }); + callback = createUpdate(expirationTime); + callback.payload = { element: element }; + container = void 0 === container ? null : container; + null !== container && (callback.callback = container); + enqueueUpdate(currentTime, callback, expirationTime); scheduleWork(currentTime, expirationTime); return expirationTime; } @@ -5827,8 +5894,8 @@ var ReactFiberReconciler$2 = Object.freeze({ default: ReactFiberReconciler$1 }), ReactFiberReconciler$3 = (ReactFiberReconciler$2 && ReactFiberReconciler$1) || ReactFiberReconciler$2, - reactReconciler = ReactFiberReconciler$3["default"] - ? ReactFiberReconciler$3["default"] + reactReconciler = ReactFiberReconciler$3.default + ? ReactFiberReconciler$3.default : ReactFiberReconciler$3, ReactNativeFiberHostComponent = (function() { function ReactNativeFiberHostComponent(tag, viewConfig) { @@ -6219,7 +6286,7 @@ var roots = new Map(), var root = roots.get(containerTag); root && NativeRenderer.updateContainer(null, root, null, function() { - roots["delete"](containerTag); + roots.delete(containerTag); }); }, unmountComponentAtNodeAndRemoveContainer: function(containerTag) { @@ -6305,6 +6372,6 @@ NativeRenderer.injectIntoDevTools({ var ReactNativeRenderer$2 = Object.freeze({ default: ReactNativeRenderer }), ReactNativeRenderer$3 = (ReactNativeRenderer$2 && ReactNativeRenderer) || ReactNativeRenderer$2; -module.exports = ReactNativeRenderer$3["default"] - ? ReactNativeRenderer$3["default"] +module.exports = ReactNativeRenderer$3.default + ? ReactNativeRenderer$3.default : ReactNativeRenderer$3; diff --git a/Libraries/Renderer/shims/NativeMethodsMixin.js b/Libraries/Renderer/shims/NativeMethodsMixin.js index 7acdf99bbd39ae..cd0e673b3bffe1 100644 --- a/Libraries/Renderer/shims/NativeMethodsMixin.js +++ b/Libraries/Renderer/shims/NativeMethodsMixin.js @@ -4,6 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * + * @providesModule NativeMethodsMixin * @flow */ diff --git a/Libraries/Renderer/shims/ReactDebugTool.js b/Libraries/Renderer/shims/ReactDebugTool.js index 8ea7ba5c1433c8..e45af4fb099433 100644 --- a/Libraries/Renderer/shims/ReactDebugTool.js +++ b/Libraries/Renderer/shims/ReactDebugTool.js @@ -4,6 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * + * @providesModule ReactDebugTool */ 'use strict'; diff --git a/Libraries/Renderer/shims/ReactFabric.js b/Libraries/Renderer/shims/ReactFabric.js index 8dce288d28a71e..4162ca62fef73d 100644 --- a/Libraries/Renderer/shims/ReactFabric.js +++ b/Libraries/Renderer/shims/ReactFabric.js @@ -4,6 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * + * @providesModule ReactFabric * @flow */ 'use strict'; diff --git a/Libraries/Renderer/shims/ReactNative.js b/Libraries/Renderer/shims/ReactNative.js index 43c5002e05f58a..a648cafbc30c22 100644 --- a/Libraries/Renderer/shims/ReactNative.js +++ b/Libraries/Renderer/shims/ReactNative.js @@ -4,6 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * + * @providesModule ReactNative * @flow */ 'use strict'; diff --git a/Libraries/Renderer/shims/ReactNativeComponentTree.js b/Libraries/Renderer/shims/ReactNativeComponentTree.js index 8e8ce6ae06c1a0..30ec5257f424c8 100644 --- a/Libraries/Renderer/shims/ReactNativeComponentTree.js +++ b/Libraries/Renderer/shims/ReactNativeComponentTree.js @@ -4,6 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * + * @providesModule ReactNativeComponentTree * @flow */ diff --git a/Libraries/Renderer/shims/ReactNativeTypes.js b/Libraries/Renderer/shims/ReactNativeTypes.js index 485ce162ecc6bd..bf94119739334d 100644 --- a/Libraries/Renderer/shims/ReactNativeTypes.js +++ b/Libraries/Renderer/shims/ReactNativeTypes.js @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. * * @flow + * @providesModule ReactNativeTypes */ export type MeasureOnSuccessCallback = ( diff --git a/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js b/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js index c8ed940a860955..ffb0fa213f3b31 100644 --- a/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js +++ b/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js @@ -4,6 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * + * @providesModule ReactNativeViewConfigRegistry * @flow */ 'use strict'; diff --git a/Libraries/Renderer/shims/ReactPerf.js b/Libraries/Renderer/shims/ReactPerf.js index e94c87501c7dc1..bb6777fff0b989 100644 --- a/Libraries/Renderer/shims/ReactPerf.js +++ b/Libraries/Renderer/shims/ReactPerf.js @@ -4,6 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * + * @providesModule ReactPerf */ 'use strict'; diff --git a/Libraries/Renderer/shims/ReactTypes.js b/Libraries/Renderer/shims/ReactTypes.js index 747a6c07b6f363..689ed18bf95294 100644 --- a/Libraries/Renderer/shims/ReactTypes.js +++ b/Libraries/Renderer/shims/ReactTypes.js @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. * * @flow + * @providesModule ReactTypes */ export type ReactNode = diff --git a/Libraries/Renderer/shims/createReactNativeComponentClass.js b/Libraries/Renderer/shims/createReactNativeComponentClass.js index cacaedab88f2c4..1a050e8b3cf0f8 100644 --- a/Libraries/Renderer/shims/createReactNativeComponentClass.js +++ b/Libraries/Renderer/shims/createReactNativeComponentClass.js @@ -4,6 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * + * @providesModule createReactNativeComponentClass * @flow */ From 30d06b42862fc5e8704e109db652d62f86f8eabc Mon Sep 17 00:00:00 2001 From: "Andrew Chen (Eng)" Date: Mon, 7 May 2018 12:16:28 -0700 Subject: [PATCH 0444/1109] Better error messages for ReadableNativeMap ClassCastExceptions Reviewed By: mdvacca Differential Revision: D7800266 fbshipit-source-id: 3fa224d3adc54a7bc59a6a37b9ad6928ac33ceb6 --- .../react/bridge/ReadableNativeMap.java | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableNativeMap.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableNativeMap.java index 0cb9c10ef1c6f5..40cbe0d8d22fe7 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableNativeMap.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableNativeMap.java @@ -121,6 +121,13 @@ private Object getValue(String name) { } throw new NoSuchKeyException(name); } + + private T getValue(String name, Class type) { + Object value = getValue(name); + checkInstance(name, value, type); + return (T) value; + } + private @Nullable Object getNullableValue(String name) { if (hasKey(name)) { return getLocalMap().get(name); @@ -128,13 +135,27 @@ private Object getValue(String name) { throw new NoSuchKeyException(name); } + private @Nullable T getNullableValue(String name, Class type) { + Object value = getNullableValue(name); + checkInstance(name, value, type); + return (T) value; + } + + private void checkInstance(String name, Object value, Class type) { + if (value != null && !type.isInstance(value)) { + throw new ClassCastException( + "Value for " + name + " cannot be cast from " + + value.getClass().getSimpleName() + " to " + type.getSimpleName()); + } + } + @Override public boolean getBoolean(String name) { if (mUseNativeAccessor) { mJniCallCounter++; return getBooleanNative(name); } - return ((Boolean) getValue(name)).booleanValue(); + return getValue(name, Boolean.class).booleanValue(); } private native boolean getBooleanNative(String name); @@ -144,7 +165,7 @@ public double getDouble(String name) { mJniCallCounter++; return getDoubleNative(name); } - return ((Double) getValue(name)).doubleValue(); + return getValue(name, Double.class).doubleValue(); } private native double getDoubleNative(String name); @@ -154,8 +175,9 @@ public int getInt(String name) { mJniCallCounter++; return getIntNative(name); } + // All numbers coming out of native are doubles, so cast here then truncate - return ((Double) getValue(name)).intValue(); + return getValue(name, Double.class).intValue(); } private native int getIntNative(String name); @@ -165,7 +187,7 @@ public int getInt(String name) { mJniCallCounter++; return getStringNative(name); } - return (String) getNullableValue(name); + return getNullableValue(name, String.class); } private native String getStringNative(String name); @@ -175,7 +197,7 @@ public int getInt(String name) { mJniCallCounter++; return getArrayNative(name); } - return (ReadableArray) getNullableValue(name); + return getNullableValue(name, ReadableArray.class); } private native ReadableNativeArray getArrayNative(String name); @@ -185,7 +207,7 @@ public int getInt(String name) { mJniCallCounter++; return getMapNative(name); } - return (ReadableNativeMap) getNullableValue(name); + return getNullableValue(name, ReadableNativeMap.class); } private native ReadableNativeMap getMapNative(String name); From 4d99daaa914398b24e9783b47858434e25bb5fcb Mon Sep 17 00:00:00 2001 From: David Vacca Date: Mon, 7 May 2018 12:23:50 -0700 Subject: [PATCH 0445/1109] Fix RNTester WebBrowser example Reviewed By: yungsters Differential Revision: D7890708 fbshipit-source-id: e96c2283f92ae151152f89bebd95141852ff40b1 --- RNTester/js/WebViewExample.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/RNTester/js/WebViewExample.js b/RNTester/js/WebViewExample.js index d55d17ca60ec9b..84b99001ecf559 100644 --- a/RNTester/js/WebViewExample.js +++ b/RNTester/js/WebViewExample.js @@ -27,6 +27,7 @@ var DISABLED_WASH = 'rgba(255,255,255,0.25)'; var TEXT_INPUT_REF = 'urlInput'; var WEBVIEW_REF = 'webview'; var DEFAULT_URL = 'https://m.facebook.com'; +const FILE_SYSTEM_ORIGIN_WHITE_LIST = ['file://*', 'http://*', 'https://*']; class WebViewExample extends React.Component<{}, $FlowFixMeState> { state = { @@ -241,6 +242,7 @@ class MessagingTest extends React.Component<{}, $FlowFixMeState> { backgroundColor: BGWASH, height: 100, }} + originWhitelist={FILE_SYSTEM_ORIGIN_WHITE_LIST} source={require('./messagingtest.html')} onMessage={this.onMessage} /> @@ -414,6 +416,7 @@ exports.examples = [ backgroundColor: BGWASH, height: 100, }} + originWhitelist={FILE_SYSTEM_ORIGIN_WHITE_LIST} source={require('./helloworld.html')} scalesPageToFit={true} /> From 15f8d7013c2308fe708599f82eba08d2c9ba743f Mon Sep 17 00:00:00 2001 From: Chirag Jain Date: Mon, 7 May 2018 14:24:32 -0700 Subject: [PATCH 0446/1109] CI: fix watchman install errors and update ios simulators to version 11.2 Summary: Fixes watchman install errors. Check that iphone 5s is booted properly on circle. Check brew install watchman succeeds. [CI] - Fix ios version on circleci and fixes brew install watchman error Closes https://github.com/facebook/react-native/pull/19166 Differential Revision: D7899295 Pulled By: hramos fbshipit-source-id: 2260a2675879cf97fb0b2f11139d9bb84ce7444e --- .circleci/config.yml | 56 ++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7452d4bd43a7b2..23c9472731c61a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -147,7 +147,7 @@ aliases: 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/. + cp -R ~/okbuck/tooling/junit/* ~/react-native/tooling/junit/. - &install-node @@ -214,7 +214,7 @@ aliases: - &gradle-download-deps name: Download C++ Dependencies command: ./scripts/circleci/gradle_download_deps.sh - + - &build-android-app name: Build Android App command: | @@ -224,7 +224,7 @@ aliases: - &create-avd name: Create Android Virtual Device command: source scripts/circle-ci-android-setup.sh && createAVD - + - &launch-avd name: Launch Android Virtual Device in Background command: source scripts/circle-ci-android-setup.sh && launchAVD @@ -250,11 +250,11 @@ aliases: - &run-android-instrumentation-tests name: Run Instrumentation Tests command: | - if [[ ! -e ReactAndroid/src/androidTest/assets/AndroidTestBundle.js ]]; then + if [[ ! -e ReactAndroid/src/androidTest/assets/AndroidTestBundle.js ]]; then echo "JavaScript bundle missing, cannot run instrumentation tests. Verify build-js-bundle step completed successfully."; exit 1; fi source scripts/circle-ci-android-setup.sh && NO_BUCKD=1 retry3 timeout 300 buck install ReactAndroid/src/androidTest/buck-runner:instrumentation-tests --config build.threads=$BUILD_THREADS - + - &collect-android-test-results name: Collect Test Results command: | @@ -266,12 +266,12 @@ aliases: - &setup-artifacts name: Initial Setup - command: | + 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/ - + - &run-objc-ios-tests name: iOS Test Suite command: ./scripts/objc-test-ios.sh test @@ -390,7 +390,9 @@ jobs: - attach_workspace: at: ~/react-native - - run: xcrun instruments -w "iPhone 5s (11.1)" || true + - run: xcrun instruments -w "iPhone 5s (11.2)" || true + # See https://github.com/Homebrew/homebrew-core/issues/26358. + - run: brew upgrade python > /dev/null - run: brew install watchman - run: *run-objc-ios-tests @@ -404,7 +406,9 @@ jobs: - attach_workspace: at: ~/react-native - - run: xcrun instruments -w "Apple TV 1080p (11.1)" || true + - run: xcrun instruments -w "Apple TV 1080p (11.2)" || true + # See https://github.com/Homebrew/homebrew-core/issues/26358. + - run: brew upgrade python > /dev/null - run: brew install watchman - run: *run-objc-tvos-tests @@ -418,7 +422,7 @@ jobs: - attach_workspace: at: ~/react-native - - run: xcrun instruments -w "iPhone 5s (11.1)" || true + - run: xcrun instruments -w "iPhone 5s (11.2)" || true - run: *run-objc-ios-e2e-tests - store_test_results: @@ -432,14 +436,14 @@ jobs: at: ~/react-native - run: ./scripts/process-podspecs.sh - + # Publishes new version onto npm publish_npm_package: <<: *android_defaults steps: # Checkout code so that we can work with `git` in publish.js - checkout - + # Configure Android SDK and related dependencies - run: *configure-android-path - run: *install-android-build-dependencies @@ -472,7 +476,7 @@ jobs: - restore-cache: *restore-cache-yarn - run: *yarn - save-cache: *save-cache-yarn - + - run: name: Publish React Native Package command: | @@ -483,7 +487,7 @@ jobs: echo "machine github.com login reactjs-bot password $GITHUB_TOKEN" > ~/.netrc node ./scripts/publish-npm.js else - echo "Skipping deploy." + echo "Skipping deploy." fi # Set up an Android environment for downstream jobs @@ -505,7 +509,7 @@ jobs: - run: *validate-android-sdk - # Starting emulator in advance as it takes some time to boot. + # Starting emulator in advance as it takes some time to boot. - run: *create-avd - run: *launch-avd @@ -547,7 +551,7 @@ jobs: # Test Suite - run: *run-android-unit-tests - run: *run-android-instrumentation-tests - + # Collect Results - run: *collect-android-test-results - store_test_results: @@ -572,7 +576,7 @@ jobs: cd bots yarn install --non-interactive --cache-folder ~/.cache/yarn else - echo "Skipping dependency installation." + echo "Skipping dependency installation." fi - save-cache: *save-cache-analysis @@ -583,7 +587,7 @@ jobs: if [ -n "$CIRCLE_PR_NUMBER" ]; then cd bots && DANGER_GITHUB_API_TOKEN="b186c9a82bab3b08ec80""c0818117619eec6f281a" yarn danger else - echo "Skipping pull request analysis." + echo "Skipping pull request analysis." fi when: always - run: @@ -593,7 +597,7 @@ jobs: if [ -n "$CIRCLE_PR_NUMBER" ]; then GITHUB_TOKEN="af6ef0d15709bc91d""06a6217a5a826a226fb57b7" CI_USER=$CIRCLE_PROJECT_USERNAME CI_REPO=$CIRCLE_PROJECT_REPONAME PULL_REQUEST_NUMBER=$CIRCLE_PR_NUMBER scripts/circleci/analyze_code.sh else - echo "Skipping code analysis." + echo "Skipping code analysis." fi when: always @@ -652,16 +656,16 @@ workflows: # Checkout repo and run Yarn - checkout_code: filters: *filter-ignore-master-stable - + # Run code checks - - analyze_pr: + - analyze_pr: filters: *filter-ignore-master-stable - requires: + requires: - checkout_code # Only runs on NN-stable branches deploy: - jobs: + jobs: # If we are on a stable branch, wait for approval to deploy to npm - approve_publish_npm_package: filters: *filter-only-stable @@ -671,9 +675,9 @@ workflows: requires: - approve_publish_npm_package - # These tests are flaky or are yet to be fixed. They are placed on their own + # These tests are flaky or are yet to be fixed. They are placed on their own # workflow to avoid marking benign PRs as broken. - # To run them, uncomment the entire block and open a PR (do not merge). + # To run them, uncomment the entire block and open a PR (do not merge). # Once a test is fixed, move the test definition to the 'tests' workflow. # disabled_tests: # jobs: @@ -681,7 +685,7 @@ workflows: # - checkout_code: # filters: *filter-ignore-gh-pages - # # The following were DISABLED because they have not run since + # # The following were DISABLED because they have not run since # # the migration from Travis, and they have broken since then, # # CocoaPods # - test_podspec: From 3145b1e62aca20b6a8bc69f76036c853db3aeaae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= <165856+hramos@users.noreply.github.com> Date: Mon, 7 May 2018 14:25:32 -0700 Subject: [PATCH 0447/1109] Update IssueCommands.txt Summary: Use new labels. Closes https://github.com/facebook/react-native/pull/19165 Differential Revision: D7899306 Pulled By: hramos fbshipit-source-id: 9a36426bcdd4af110b5c29e186b66e7eadcf69cd --- bots/IssueCommands.txt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/bots/IssueCommands.txt b/bots/IssueCommands.txt index 20ef511ff76b51..0c73a582e065c5 100644 --- a/bots/IssueCommands.txt +++ b/bots/IssueCommands.txt @@ -14,7 +14,7 @@ close @facebook-github-bot stack-overflow comment Hey {issue_author}, thanks for posting this! {author} tells me this issue looks like a question that would be best asked on [Stack Overflow](https://stackoverflow.com/questions/tagged/react-native). Stack Overflow is amazing for Q&A: it has a reputation system, voting, the ability to mark a question as answered. Because of the reputation system it is likely the community will see and answer your question there. This also helps us use the GitHub bug tracker for bugs only.

[How to Contribute](https://facebook.github.io/react-native/docs/contributing.html#bugs) • [What to Expect from Maintainers](https://facebook.github.io/react-native/docs/maintainers.html#handling-issues) -add-label For Stack Overflow +add-label ":no_entry_sign:For Stack Overflow" close @facebook-github-bot label (.*) @@ -22,12 +22,12 @@ add-label {match0} @facebook-github-bot no-reply comment Closing this issue as more information is needed to debug this and we haven't heard back from the author. -add-label Needs Response from Author +add-label ":grey_question:Needs More Information" close @facebook-github-bot no-template comment Hey {issue_author}, thanks for posting this! It looks like your issue is missing some required information. Can you please add all the details specified in the [Issue Template](https://raw.githubusercontent.com/facebook/react-native/master/.github/ISSUE_TEMPLATE.md)? This is necessary for people to be able to understand and reproduce your issue. I am going to close this, but please feel free to open a new issue with the additional information provided. Thanks!

[How to Contribute](https://facebook.github.io/react-native/docs/contributing.html#bugs) • [What to Expect from Maintainers](https://facebook.github.io/react-native/docs/maintainers.html#handling-issues) -add-label Needs more information +add-label ":grey_question:Needs More Information" close @facebook-github-bot close @@ -36,16 +36,16 @@ close @facebook-github-bot large-pr comment Thank you for your contribution. Unfortunately, this pull request seems relatively large.

In order to reduce the load on maintainers, it would be valuable if you could [split this into small, targeted PRs that changed one thing at a time](https://graysonkoonce.com/stacked-pull-requests-keeping-github-diffs-small/).

If doing this requires more than a few pull requests, please open (or update) an issue specifying your goal and the different steps you will take in your PRs. This will ensure maintainers have context on the relationship between the PRs.

If this is a codemod or other formatting change that is simple but inherently touches many files, please comment on this and let us know and we will reopen the PR. -add-label Large PR +add-label ":clipboard:Large PR :bangbang:" close @facebook-github-bot bugfix comment Hey {issue_author}, if you're sure this is a bug, can you send a pull request with a fix?

[How to Contribute](https://facebook.github.io/react-native/docs/contributing.html#bugs) • [What to Expect from Maintainers](https://facebook.github.io/react-native/docs/maintainers.html#handling-issues) -add-label Help Wanted +add-label "Help Wanted :octocat:" @facebook-github-bot needs-repro comment Can you reproduce the issue using [Snack](https://snack.expo.io)? This step is necessary for people to be able to see and debug the issue being reported.

[How to Contribute](https://facebook.github.io/react-native/docs/contributing.html#bugs) • [What to Expect from Maintainers](https://facebook.github.io/react-native/docs/maintainers.html#handling-issues) -add-label Needs more information +add-label ":grey_question:Needs More Information" @facebook-github-bot cannot-repro comment Thanks for opening the issue! It does not appear like a community member will be able to reliably reproduce this issue. This may be for several reasons; perhaps it affects a particular app but a minimal repro has not been provided, or the issue may be sporadic. As it happens, we need a concrete set of steps that can demonstrably reproduce the issue as this will allow your fellow community members to validate a fix. We'll close the issue for now, but feel free to submit a new issue once you're able to reliably reproduce the issue locally. Thanks for your understanding!

[How to Contribute](https://facebook.github.io/react-native/docs/contributing.html#bugs) • [What to Expect from Maintainers](https://facebook.github.io/react-native/docs/maintainers.html#handling-issues) @@ -57,14 +57,14 @@ reopen @facebook-github-bot feature comment Hey {issue_author}! Thanks for opening the issue, however it looks like a feature request. As noted in the [Issue template](https://raw.githubusercontent.com/facebook/react-native/master/.github/ISSUE_TEMPLATE.md) we'd like to use the GitHub issues to track bugs only. Can you implement the feature as a standalone npm module? If not, consider sending a pull request or a creating an entry on [Canny](https://react-native.canny.io/feature-requests/). It has a voting system and if the feature gets upvoted enough it might get implemented. Closing this now, thanks for understanding!

[How to Contribute](https://facebook.github.io/react-native/docs/contributing.html#bugs) • [What to Expect from Maintainers](https://facebook.github.io/react-native/docs/maintainers.html#handling-issues) -add-label Feature Request +add-label ":star2:Feature Request" close @facebook-github-bot cla comment Hey {issue_author}! Thanks for sending this pull request! We would love to review your changes however it looks like you haven't signed the CLA yet. You can do so at https://code.facebook.com/cla. See ["How to Contribute"](https://facebook.github.io/react-native/docs/contributing.html#pull-requests) to learn more. -add-label Needs Response from Author +add-label ":grey_question:Needs More Information" @facebook-github-bot icebox comment {author} tells me to close this issue because it has been inactive for a while. Maybe the issue has been fixed in a recent release, or perhaps it is not affecting a lot of people. Either way, we're automatically closing issues after a period of inactivity. Please do not take it personally!

If you think this issue should definitely remain open, please let us know. The following information is helpful when it comes to determining if the issue should be re-opened:
  • Does the issue still reproduce on the latest release candidate? Post a comment with the version you tested.
  • If so, is there any information missing from the bug report? Post a comment with all the information required by the [issue template](https://github.com/facebook/react-native/blob/master/.github/ISSUE_TEMPLATE.md).
  • Is there a pull request that addresses this issue? Post a comment with the PR number so we can follow up.
If you would like to work on a patch to fix the issue, *contributions are very welcome*! Read through the [contribution guide](https://facebook.github.io/react-native/docs/contributing.html), and feel free to hop into [#react-native](https://discordapp.com/invite/0ZcbPKXt5bZjGY5n) if you need help planning your contribution.

[How to Contribute](https://facebook.github.io/react-native/docs/contributing.html#bugs) • [What to Expect from Maintainers](https://facebook.github.io/react-native/docs/maintainers.html#handling-issues) -add-label Icebox +add-label Stale close From 1be2541ce2bbe328362d19e3eff65f3e89527105 Mon Sep 17 00:00:00 2001 From: "Andrew Chen (Eng)" Date: Mon, 7 May 2018 14:53:28 -0700 Subject: [PATCH 0448/1109] Add assertion to ensure copied shadow nodes are of the same type as the original Reviewed By: mdvacca Differential Revision: D7664638 fbshipit-source-id: e1b7acbafd8a8fd9d6301d8afbb3e5959dc15b7a --- .../react/uimanager/ReactShadowNodeImpl.java | 6 ++++++ .../react/fabric/ReactShadowNodeTest.java | 20 +++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 ReactAndroid/src/test/java/com/facebook/react/fabric/ReactShadowNodeTest.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java index a8118b1841d0b8..ff009b5b2c29a9 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNodeImpl.java @@ -166,6 +166,9 @@ protected ReactShadowNodeImpl copy() { @Override public ReactShadowNodeImpl mutableCopy() { ReactShadowNodeImpl copy = copy(); + Assertions.assertCondition( + getClass() == copy.getClass(), + "Copied shadow node must use the same class"); if (mYogaNode != null) { copy.mYogaNode = mYogaNode.clone(); copy.mYogaNode.setData(copy); @@ -182,6 +185,9 @@ public ReactShadowNodeImpl mutableCopy() { @Override public ReactShadowNodeImpl mutableCopyWithNewChildren() { ReactShadowNodeImpl copy = copy(); + Assertions.assertCondition( + getClass() == copy.getClass(), + "Copied shadow node must use the same class"); if (mYogaNode != null) { copy.mYogaNode = mYogaNode.cloneWithNewChildren(); copy.mYogaNode.setData(copy); diff --git a/ReactAndroid/src/test/java/com/facebook/react/fabric/ReactShadowNodeTest.java b/ReactAndroid/src/test/java/com/facebook/react/fabric/ReactShadowNodeTest.java new file mode 100644 index 00000000000000..1b14c9fc9c42cf --- /dev/null +++ b/ReactAndroid/src/test/java/com/facebook/react/fabric/ReactShadowNodeTest.java @@ -0,0 +1,20 @@ +// Copyright 2004-present Facebook. All Rights Reserved. +package com.facebook.react.fabric; + +import com.facebook.react.uimanager.ReactShadowNodeImpl; +import com.facebook.testing.robolectric.v3.WithTestDefaultsRunner; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** Tests {@link ReactShadowNode} */ +@RunWith(WithTestDefaultsRunner.class) +public class ReactShadowNodeTest { + + @Test(expected = AssertionError.class) + public void testClonedInstance() { + TestReactShadowNode node = new TestReactShadowNode(); + node.mutableCopy(); + } + + private static class TestReactShadowNode extends ReactShadowNodeImpl {} +} From 1c90a2b47b420a4b6aa16a55a344cc08f0eacbe3 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Mon, 7 May 2018 16:45:11 -0700 Subject: [PATCH 0449/1109] RN: Fix `requireNativeComponent` Check Reviewed By: sahrens, TheSavior Differential Revision: D7893594 fbshipit-source-id: 83f6995842e9480382c0b2abf6b6e72c6c107a49 --- Libraries/ReactNative/requireNativeComponent.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/ReactNative/requireNativeComponent.js b/Libraries/ReactNative/requireNativeComponent.js index 0e09ad9f8096ec..6d215e79fb7762 100644 --- a/Libraries/ReactNative/requireNativeComponent.js +++ b/Libraries/ReactNative/requireNativeComponent.js @@ -101,7 +101,7 @@ function requireNativeComponent( const viewConfig = UIManager[viewName]; invariant( - viewConfig != null && !viewConfig.NativeProps != null, + viewConfig != null && viewConfig.NativeProps != null, 'Native component for "%s" does not exist', viewName, ); From 28d37781c6589574de1113bd12077f6d54053ffb Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Mon, 7 May 2018 16:45:14 -0700 Subject: [PATCH 0450/1109] RN: Optimize View Attribute Initialization Reviewed By: sahrens Differential Revision: D7893593 fbshipit-source-id: a425e841c9c86b063803878c7b07704c8a90a83a --- .../ReactNative/requireNativeComponent.js | 85 ++++++++++--------- 1 file changed, 46 insertions(+), 39 deletions(-) diff --git a/Libraries/ReactNative/requireNativeComponent.js b/Libraries/ReactNative/requireNativeComponent.js index 6d215e79fb7762..dd44ea60b936b1 100644 --- a/Libraries/ReactNative/requireNativeComponent.js +++ b/Libraries/ReactNative/requireNativeComponent.js @@ -141,22 +141,12 @@ function requireNativeComponent( viewConfig.directEventTypes = directEventTypes; for (const key in nativeProps) { - let useAttribute = false; - const attribute = {}; + const typeName = nativeProps[key]; + const diff = getDifferForType(typeName); + const process = getProcessorForType(typeName); - const differ = TypeToDifferMap[nativeProps[key]]; - if (differ) { - attribute.diff = differ; - useAttribute = true; - } - - const processor = TypeToProcessorMap[nativeProps[key]]; - if (processor) { - attribute.process = processor; - useAttribute = true; - } - - viewConfig.validAttributes[key] = useAttribute ? attribute : true; + viewConfig.validAttributes[key] = + diff == null && process == null ? true : {diff, process}; } // Unfortunately, the current set up puts the style properties on the top @@ -186,32 +176,49 @@ function requireNativeComponent( return createReactNativeComponentClass(viewName, getViewConfig); } -const TypeToDifferMap = { - // iOS Types - CATransform3D: matricesDiffer, - CGPoint: pointsDiffer, - CGSize: sizesDiffer, - UIEdgeInsets: insetsDiffer, - // Android Types - // (not yet implemented) -}; +function getDifferForType( + typeName: string, +): ?(prevProp: any, nextProp: any) => boolean { + switch (typeName) { + // iOS Types + case 'CATransform3D': + return matricesDiffer; + case 'CGPoint': + return pointsDiffer; + case 'CGSize': + return sizesDiffer; + case 'UIEdgeInsets': + return insetsDiffer; + // Android Types + // (not yet implemented) + } + return null; +} + +function getProcessorForType(typeName: string): ?(nextProp: any) => any { + switch (typeName) { + // iOS Types + case 'CGColor': + case 'UIColor': + return processColor; + case 'CGColorArray': + case 'UIColorArray': + return processColorArray; + case 'CGImage': + case 'UIImage': + case 'RCTImageSource': + return resolveAssetSource; + // Android Types + case 'Color': + return processColor; + case 'ColorArray': + return processColorArray; + } + return null; +} function processColorArray(colors: ?Array): ?Array { - return colors && colors.map(processColor); + return colors == null ? null : colors.map(processColor); } -const TypeToProcessorMap = { - // iOS Types - CGColor: processColor, - CGColorArray: processColorArray, - UIColor: processColor, - UIColorArray: processColorArray, - CGImage: resolveAssetSource, - UIImage: resolveAssetSource, - RCTImageSource: resolveAssetSource, - // Android Types - Color: processColor, - ColorArray: processColorArray, -}; - module.exports = requireNativeComponent; From b549e364e0025e0e1b4005f04a9de2d767006da1 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Mon, 7 May 2018 16:45:16 -0700 Subject: [PATCH 0451/1109] RN: Simpify `requireNativeComponent` Reviewed By: sahrens Differential Revision: D7893592 fbshipit-source-id: bfe7772ff2fa785fc7c5ad1f7dc0dbe97b6ffb11 --- .../ReactNative/requireNativeComponent.js | 163 +++++++++--------- 1 file changed, 85 insertions(+), 78 deletions(-) diff --git a/Libraries/ReactNative/requireNativeComponent.js b/Libraries/ReactNative/requireNativeComponent.js index dd44ea60b936b1..fae553f27ce61f 100644 --- a/Libraries/ReactNative/requireNativeComponent.js +++ b/Libraries/ReactNative/requireNativeComponent.js @@ -7,6 +7,7 @@ * @flow * @format */ + 'use strict'; const Platform = require('Platform'); @@ -24,6 +25,14 @@ const verifyPropTypes = require('verifyPropTypes'); const invariant = require('fbjs/lib/invariant'); const warning = require('fbjs/lib/warning'); +import type {ComponentInterface} from 'verifyPropTypes'; + +type ExtraOptions = $ReadOnly<{| + nativeOnly?: $ReadOnly<{ + [propName: string]: boolean, + }>, +|}>; + /** * Used to create React components that directly wrap native component * implementations. Config information is extracted from data exported from the @@ -39,81 +48,23 @@ const warning = require('fbjs/lib/warning'); * Common types are lined up with the appropriate prop differs with * `TypeToDifferMap`. Non-scalar types not in the map default to `deepDiffer`. */ -import type {ComponentInterface} from 'verifyPropTypes'; - -let hasAttachedDefaultEventTypes: boolean = false; - -function requireNativeComponent( +const requireNativeComponent = ( viewName: string, componentInterface?: ?ComponentInterface, - extraConfig?: ?{nativeOnly?: Object}, -): React$ComponentType | string { - 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) { - // Lazy view managers enabled. - viewConfig = merge(viewConfig, UIManager.getDefaultEventTypes()); - } else { - viewConfig.bubblingEventTypes = merge( - viewConfig.bubblingEventTypes, - UIManager.genericBubblingEventTypes, - ); - viewConfig.directEventTypes = merge( - viewConfig.directEventTypes, - UIManager.genericDirectEventTypes, - ); - } - } - - function merge(destination: ?Object, source: ?Object): ?Object { - if (!source) { - return destination; - } - if (!destination) { - return source; - } - - for (const key in source) { - if (!source.hasOwnProperty(key)) { - continue; - } - - var sourceValue = source[key]; - if (destination.hasOwnProperty(key)) { - const destinationValue = destination[key]; - if ( - typeof sourceValue === 'object' && - typeof destinationValue === 'object' - ) { - sourceValue = merge(destinationValue, sourceValue); - } - } - destination[key] = sourceValue; - } - return destination; - } - - // Don't load the ViewConfig from UIManager until it's needed for rendering. - // Lazy-loading this can help avoid Prepack deopts. - function getViewConfig() { + extraConfig?: ?ExtraOptions, +): string => + createReactNativeComponentClass(viewName, () => { const viewConfig = UIManager[viewName]; invariant( viewConfig != null && viewConfig.NativeProps != null, - 'Native component for "%s" does not exist', + 'requireNativeComponent: "%s" was not found in the UIManager.', viewName, ); - viewConfig.uiViewClassName = viewName; - viewConfig.validAttributes = {}; - viewConfig.propTypes = - componentInterface == null ? null : componentInterface.propTypes; - - let baseModuleName = viewConfig.baseModuleName; - let bubblingEventTypes = viewConfig.bubblingEventTypes; - let directEventTypes = viewConfig.directEventTypes; + // TODO: This seems like a whole lot of runtime initialization for every + // native component that can be either avoided or simplified. + let {baseModuleName, bubblingEventTypes, directEventTypes} = viewConfig; let nativeProps = viewConfig.NativeProps; while (baseModuleName) { const baseModule = UIManager[baseModuleName]; @@ -137,32 +88,40 @@ function requireNativeComponent( } } - viewConfig.bubblingEventTypes = bubblingEventTypes; - viewConfig.directEventTypes = directEventTypes; + const viewAttributes = {}; for (const key in nativeProps) { const typeName = nativeProps[key]; const diff = getDifferForType(typeName); const process = getProcessorForType(typeName); - viewConfig.validAttributes[key] = + viewAttributes[key] = diff == null && process == null ? true : {diff, process}; } - // Unfortunately, the current set up puts the style properties on the top - // level props object. We also need to add the nested form for API - // compatibility. This allows these props on both the top level and the - // nested style level. TODO: Move these to nested declarations on the - // native side. - viewConfig.validAttributes.style = ReactNativeStyleAttributes; + // Unfortunately, the current setup declares style properties as top-level + // props. This makes it so we allow style properties in the `style` prop. + // TODO: Move style properties into a `style` prop and disallow them as + // top-level props on the native side. + viewAttributes.style = ReactNativeStyleAttributes; + + Object.assign(viewConfig, { + uiViewClassName: viewName, + validAttributes: viewAttributes, + propTypes: + componentInterface == null ? null : componentInterface.propTypes, + bubblingEventTypes, + directEventTypes, + }); if (__DEV__) { - componentInterface && + if (componentInterface != null) { verifyPropTypes( componentInterface, viewConfig, - extraConfig && extraConfig.nativeOnly, + extraConfig == null ? null : extraConfig.nativeOnly, ); + } } if (!hasAttachedDefaultEventTypes) { @@ -171,9 +130,57 @@ function requireNativeComponent( } return viewConfig; + }); + +// TODO: Figure out how this makes sense. We're using a global boolean to only +// initialize this on the first eagerly initialized native component. +let hasAttachedDefaultEventTypes = false; +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) { + // Lazy view managers enabled. + viewConfig = merge(viewConfig, UIManager.getDefaultEventTypes()); + } else { + viewConfig.bubblingEventTypes = merge( + viewConfig.bubblingEventTypes, + UIManager.genericBubblingEventTypes, + ); + viewConfig.directEventTypes = merge( + viewConfig.directEventTypes, + UIManager.genericDirectEventTypes, + ); } +} - return createReactNativeComponentClass(viewName, getViewConfig); +// TODO: Figure out how to avoid all this runtime initialization cost. +function merge(destination: ?Object, source: ?Object): ?Object { + if (!source) { + return destination; + } + if (!destination) { + return source; + } + + for (const key in source) { + if (!source.hasOwnProperty(key)) { + continue; + } + + let sourceValue = source[key]; + if (destination.hasOwnProperty(key)) { + const destinationValue = destination[key]; + if ( + typeof sourceValue === 'object' && + typeof destinationValue === 'object' + ) { + sourceValue = merge(destinationValue, sourceValue); + } + } + destination[key] = sourceValue; + } + return destination; } function getDifferForType( From 820673e7076b5906ba50e09e40fb9a32cf500c1b Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Mon, 7 May 2018 16:45:19 -0700 Subject: [PATCH 0452/1109] RN: Simplify `verifyPropTypes` Reviewed By: sahrens Differential Revision: D7893675 fbshipit-source-id: 74d1eff57201a2af4a12c39c4335e28ff9f14090 --- Libraries/Components/View/ViewPropTypes.js | 2 +- .../ReactNative/requireNativeComponent.js | 19 ++-- Libraries/ReactNative/verifyPropTypes.js | 94 ++++++++----------- 3 files changed, 52 insertions(+), 63 deletions(-) diff --git a/Libraries/Components/View/ViewPropTypes.js b/Libraries/Components/View/ViewPropTypes.js index 40cd8121cd9958..332059ab0a222a 100644 --- a/Libraries/Components/View/ViewPropTypes.js +++ b/Libraries/Components/View/ViewPropTypes.js @@ -425,7 +425,7 @@ module.exports = { * See http://facebook.github.io/react-native/docs/view.html#needsoffscreenalphacompositing */ needsOffscreenAlphaCompositing: PropTypes.bool, - + /** * Any additional platform-specific view prop types, or prop type overrides. */ diff --git a/Libraries/ReactNative/requireNativeComponent.js b/Libraries/ReactNative/requireNativeComponent.js index fae553f27ce61f..c6f2a35d352ac8 100644 --- a/Libraries/ReactNative/requireNativeComponent.js +++ b/Libraries/ReactNative/requireNativeComponent.js @@ -25,7 +25,13 @@ const verifyPropTypes = require('verifyPropTypes'); const invariant = require('fbjs/lib/invariant'); const warning = require('fbjs/lib/warning'); -import type {ComponentInterface} from 'verifyPropTypes'; +type ComponentInterface = + | React$ComponentType + | $ReadOnly<{ + propTypes?: $ReadOnly<{ + [propName: string]: mixed, + }>, + }>; type ExtraOptions = $ReadOnly<{| nativeOnly?: $ReadOnly<{ @@ -115,13 +121,10 @@ const requireNativeComponent = ( }); if (__DEV__) { - if (componentInterface != null) { - verifyPropTypes( - componentInterface, - viewConfig, - extraConfig == null ? null : extraConfig.nativeOnly, - ); - } + verifyPropTypes( + viewConfig, + extraConfig == null ? null : extraConfig.nativeOnly, + ); } if (!hasAttachedDefaultEventTypes) { diff --git a/Libraries/ReactNative/verifyPropTypes.js b/Libraries/ReactNative/verifyPropTypes.js index c88f9c1c802904..6193b1ac1c03c8 100644 --- a/Libraries/ReactNative/verifyPropTypes.js +++ b/Libraries/ReactNative/verifyPropTypes.js @@ -4,73 +4,59 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @flow * @format + * @flow */ -'use strict'; -var ReactNativeStyleAttributes = require('ReactNativeStyleAttributes'); +'use strict'; -export type ComponentInterface = - | React$ComponentType - | { - name?: string, - displayName?: string, - propTypes?: Object, - }; +const ReactNativeStyleAttributes = require('ReactNativeStyleAttributes'); function verifyPropTypes( - componentInterface: ComponentInterface, - viewConfig: Object, - nativePropsToIgnore?: ?Object, + viewConfig: $ReadOnly<{ + NativeProps: $ReadOnly<{ + [propName: string]: mixed, + }>, + propTypes: ?$ReadOnly<{ + [propName: string]: mixed, + }>, + uiViewClassName: string, + }>, + nativePropsToIgnore: ?$ReadOnly<{ + [propName: string]: boolean, + }>, ) { - if (!viewConfig) { - return; // This happens for UnimplementedView. - } - var componentName = - componentInterface.displayName || componentInterface.name || 'unknown'; - - var propTypes = componentInterface.propTypes; + const {NativeProps, propTypes, uiViewClassName} = viewConfig; - if (!propTypes) { + if (propTypes == null) { return; } - var nativeProps = viewConfig.NativeProps; - for (var prop in nativeProps) { + for (const propName in NativeProps) { if ( - !propTypes[prop] && - !ReactNativeStyleAttributes[prop] && - (!nativePropsToIgnore || !nativePropsToIgnore[prop]) + propTypes[propName] || + ReactNativeStyleAttributes[propName] || + (nativePropsToIgnore && nativePropsToIgnore[propName]) ) { - var message; - if (propTypes.hasOwnProperty(prop)) { - message = - '`' + - componentName + - '` has incorrectly defined propType for native prop `' + - viewConfig.uiViewClassName + - '.' + - prop + - '` of native type `' + - nativeProps[prop]; - } else { - message = - '`' + - componentName + - '` has no propType for native prop `' + - viewConfig.uiViewClassName + - '.' + - prop + - '` of native type `' + - nativeProps[prop] + - '`'; - } - message += - "\nIf you haven't changed this prop yourself, this usually means that " + - 'your versions of the native code and JavaScript code are out of sync. Updating both ' + - 'should make this error go away.'; - throw new Error(message); + continue; + } + const prettyName = `${uiViewClassName}.${propName}`; + const nativeType = String(NativeProps[propName]); + const suggestion = + '\n\nIf you have not changed this prop yourself, this usually means ' + + 'that the versions of your native and JavaScript code are out of sync. ' + + 'Updating both should make this error go away.'; + + if (propTypes.hasOwnProperty(propName)) { + console.error( + `Invalid propType to configure \`${prettyName}\` (${nativeType}).` + + suggestion, + ); + } else { + console.error( + `Missing a propType to configure \`${prettyName}\` (${nativeType}).` + + suggestion, + ); } } } From 6611fefef7559c4cd3d1824235d263bff210d5e2 Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Mon, 7 May 2018 17:22:26 -0700 Subject: [PATCH 0453/1109] iOS: Exposes the RCTFont size overrides so unit tests can use the same values Summary: `RCTFontTests` test in RNTester is broken if the target deployment is <= OS 8.2. This is because RCTFont.mm overrides the OS-defined values, but the override is only visible to RCTFont.mm internals. As the result, when the Unit test tries to create UIFont of the "same" weight, it got a different font - most likely due to internal floating rounding errors. To mitigate, code that wants to test out internals of RCTFont should import RCTFontConstantsOverride.h Reviewed By: mmmulani Differential Revision: D7900954 fbshipit-source-id: e5814ef059a8afdfb5205ca1af46c41b3cfd4318 --- RNTester/RNTesterUnitTests/RCTFontTests.m | 1 + React/React.xcodeproj/project.pbxproj | 6 +++++ React/Views/RCTFont.mm | 20 +--------------- React/Views/RCTFontConstantsOverride.h | 29 +++++++++++++++++++++++ 4 files changed, 37 insertions(+), 19 deletions(-) create mode 100644 React/Views/RCTFontConstantsOverride.h diff --git a/RNTester/RNTesterUnitTests/RCTFontTests.m b/RNTester/RNTesterUnitTests/RCTFontTests.m index 1d9573b489e1b2..5d6a3bd1b4d9bb 100644 --- a/RNTester/RNTesterUnitTests/RCTFontTests.m +++ b/RNTester/RNTesterUnitTests/RCTFontTests.m @@ -10,6 +10,7 @@ #import #import +#import @interface RCTFontTests : XCTestCase diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj index 8c89419471d0ff..ab260bb49534c9 100644 --- a/React/React.xcodeproj/project.pbxproj +++ b/React/React.xcodeproj/project.pbxproj @@ -1147,6 +1147,8 @@ 59EDBCC61FDF4E55003573DE /* (null) in Copy Headers */ = {isa = PBXBuildFile; }; 59EDBCC71FDF4E55003573DE /* RCTScrollView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 59EDBCA31FDF4E0C003573DE /* RCTScrollView.h */; }; 59EDBCC81FDF4E55003573DE /* RCTScrollViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 59EDBCA51FDF4E0C003573DE /* RCTScrollViewManager.h */; }; + 5C70426020A1004800FBEEF7 /* RCTFontConstantsOverride.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C70425F20A1004800FBEEF7 /* RCTFontConstantsOverride.h */; }; + 5C70426120A1022C00FBEEF7 /* RCTFontConstantsOverride.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5C70425F20A1004800FBEEF7 /* RCTFontConstantsOverride.h */; }; 5CE2080220772F7D009A43B3 /* YGConfig.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5CE2080020772F7C009A43B3 /* YGConfig.cpp */; }; 5CE2080320772F7D009A43B3 /* YGConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CE2080120772F7C009A43B3 /* YGConfig.h */; }; 657734841EE834C900A0E9EA /* RCTInspectorDevServerHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 657734821EE834C900A0E9EA /* RCTInspectorDevServerHelper.h */; }; @@ -1599,6 +1601,7 @@ dstPath = include/React; dstSubfolderSpec = 16; files = ( + 5C70426120A1022C00FBEEF7 /* RCTFontConstantsOverride.h in Copy Headers */, 39C50FF92046EACF00CEE534 /* RCTVersion.h in Copy Headers */, 591F78DE202ADB8F004A668C /* RCTLayout.h in Copy Headers */, 59EDBCBD1FDF4E43003573DE /* RCTScrollableProtocol.h in Copy Headers */, @@ -2240,6 +2243,7 @@ 59EDBCA41FDF4E0C003573DE /* RCTScrollView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTScrollView.m; sourceTree = ""; }; 59EDBCA51FDF4E0C003573DE /* RCTScrollViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTScrollViewManager.h; sourceTree = ""; }; 59EDBCA61FDF4E0C003573DE /* RCTScrollViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTScrollViewManager.m; sourceTree = ""; }; + 5C70425F20A1004800FBEEF7 /* RCTFontConstantsOverride.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTFontConstantsOverride.h; sourceTree = ""; }; 5CE2080020772F7C009A43B3 /* YGConfig.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YGConfig.cpp; sourceTree = ""; }; 5CE2080120772F7C009A43B3 /* YGConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGConfig.h; sourceTree = ""; }; 657734821EE834C900A0E9EA /* RCTInspectorDevServerHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTInspectorDevServerHelper.h; sourceTree = ""; }; @@ -2561,6 +2565,7 @@ 13B07FF31A6947C200A75B9A /* Views */ = { isa = PBXGroup; children = ( + 5C70425F20A1004800FBEEF7 /* RCTFontConstantsOverride.h */, B95154301D1B34B200FE7B80 /* RCTActivityIndicatorView.h */, B95154311D1B34B200FE7B80 /* RCTActivityIndicatorView.m */, 13B080181A69489C00A75B9A /* RCTActivityIndicatorViewManager.h */, @@ -3568,6 +3573,7 @@ 3D80DA621DF820620028D040 /* RCTAutoInsetsProtocol.h in Headers */, C60128AB1F3D1258009DF9FF /* RCTCxxConvert.h in Headers */, 59EDBCAD1FDF4E0C003573DE /* RCTScrollContentView.h in Headers */, + 5C70426020A1004800FBEEF7 /* RCTFontConstantsOverride.h in Headers */, 59EDBCA71FDF4E0C003573DE /* RCTScrollableProtocol.h in Headers */, 591F78DC202ADB22004A668C /* RCTLayout.h in Headers */, 5CE2080320772F7D009A43B3 /* YGConfig.h in Headers */, diff --git a/React/Views/RCTFont.mm b/React/Views/RCTFont.mm index 3fb3e36177cd19..8753510d91656a 100644 --- a/React/Views/RCTFont.mm +++ b/React/Views/RCTFont.mm @@ -7,31 +7,13 @@ #import "RCTAssert.h" #import "RCTFont.h" +#import "RCTFontConstantsOverride.h" #import "RCTLog.h" #import #import -#if !defined(__IPHONE_8_2) || __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_2 - -// These constants are defined in iPhone SDK 8.2, but the app cannot run on -// iOS < 8.2 unless we redefine them here. If you target iOS 8.2 or above -// as a base target, the standard constants will be used instead. -// These constants can only be removed when React Native drops iOS8 support. - -#define UIFontWeightUltraLight -0.8 -#define UIFontWeightThin -0.6 -#define UIFontWeightLight -0.4 -#define UIFontWeightRegular 0 -#define UIFontWeightMedium 0.23 -#define UIFontWeightSemibold 0.3 -#define UIFontWeightBold 0.4 -#define UIFontWeightHeavy 0.56 -#define UIFontWeightBlack 0.62 - -#endif - typedef CGFloat RCTFontWeight; static RCTFontWeight weightOfFont(UIFont *font) { diff --git a/React/Views/RCTFontConstantsOverride.h b/React/Views/RCTFontConstantsOverride.h new file mode 100644 index 00000000000000..1563e92e7bca85 --- /dev/null +++ b/React/Views/RCTFontConstantsOverride.h @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +// NOTE: Include this header file to ensure consistency of the constants defined here. +// The values are the ones used in RCTFont.mm. +// Example: import it for testing RCTFont internals in a unit test. + +#if !defined(__IPHONE_8_2) || __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_2 + +// These constants are defined in iPhone SDK 8.2, but the app cannot run on +// iOS < 8.2 unless we redefine them here. If you target iOS 8.2 or above +// as a base target, the standard constants will be used instead. +// These constants can only be removed when React Native drops iOS8 support. + +#define UIFontWeightUltraLight -0.8 +#define UIFontWeightThin -0.6 +#define UIFontWeightLight -0.4 +#define UIFontWeightRegular 0 +#define UIFontWeightMedium 0.23 +#define UIFontWeightSemibold 0.3 +#define UIFontWeightBold 0.4 +#define UIFontWeightHeavy 0.56 +#define UIFontWeightBlack 0.62 + +#endif From e2287976f369ed741a2ef8c2954a629a23b003cf Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Mon, 7 May 2018 17:43:07 -0700 Subject: [PATCH 0454/1109] Fabric/Text: attributedstring module, the first part Summary: `fabric/attributedstring` is a simple, cross-platfrom, react-specific implementation of attributed string (aka spanned string). This diff is the first part of this which contains text primitives (types) and conversions. Reviewed By: fkgozali Differential Revision: D7748704 fbshipit-source-id: d76e31807e5ac7ab1a16fd6ee6445c59de5b89a2 --- React.podspec | 10 +- ReactCommon/fabric/attributedstring/BUCK | 78 ++++++++++++ .../attributedstring/ParagraphAttributes.cpp | 37 ++++++ .../attributedstring/ParagraphAttributes.h | 65 ++++++++++ .../fabric/attributedstring/TextPrimitives.h | 94 ++++++++++++++ .../tests/AttributedStringTest.cpp | 18 +++ .../attributedstring/textValuesConversions.h | 120 ++++++++++++++++++ 7 files changed, 421 insertions(+), 1 deletion(-) create mode 100644 ReactCommon/fabric/attributedstring/BUCK create mode 100644 ReactCommon/fabric/attributedstring/ParagraphAttributes.cpp create mode 100644 ReactCommon/fabric/attributedstring/ParagraphAttributes.h create mode 100644 ReactCommon/fabric/attributedstring/TextPrimitives.h create mode 100644 ReactCommon/fabric/attributedstring/tests/AttributedStringTest.cpp create mode 100644 ReactCommon/fabric/attributedstring/textValuesConversions.h diff --git a/React.podspec b/React.podspec index 030989c3d31714..b985ee3ea9c427 100644 --- a/React.podspec +++ b/React.podspec @@ -149,6 +149,15 @@ Pod::Spec.new do |s| end s.subspec "fabric" do |ss| + ss.subspec "attributedstring" do |sss| + sss.dependency "Folly", folly_version + sss.compiler_flags = folly_compiler_flags + sss.source_files = "ReactCommon/fabric/attributedstring/**/*.{cpp,h}" + sss.exclude_files = "**/tests/*" + sss.header_dir = "fabric/attributedstring" + sss.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/Folly\"" } + end + ss.subspec "core" do |sss| sss.dependency "Folly", folly_version sss.compiler_flags = folly_compiler_flags @@ -194,7 +203,6 @@ Pod::Spec.new do |s| sss.header_dir = "fabric/view" sss.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/Folly\"" } end - end s.subspec "ART" do |ss| diff --git a/ReactCommon/fabric/attributedstring/BUCK b/ReactCommon/fabric/attributedstring/BUCK new file mode 100644 index 00000000000000..625639db36efd2 --- /dev/null +++ b/ReactCommon/fabric/attributedstring/BUCK @@ -0,0 +1,78 @@ +load("//configurations/buck/apple:flag_defs.bzl", "get_debug_preprocessor_flags") +load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "get_apple_inspector_flags", "APPLE") + +APPLE_COMPILER_FLAGS = [] + +if not IS_OSS_BUILD: + load("@xplat//configurations/buck/apple:flag_defs.bzl", "get_static_library_ios_flags", "flags") + APPLE_COMPILER_FLAGS = flags.get_flag_value(get_static_library_ios_flags(), 'compiler_flags') + +rn_xplat_cxx_library( + name = "attributedstring", + srcs = glob( + ["**/*.cpp"], + excludes = glob(["tests/**/*.cpp"]), + ), + headers = glob( + ["**/*.h"], + excludes = glob(["tests/**/*.h"]), + ), + header_namespace = "", + exported_headers = subdir_glob( + [ + ("", "*.h"), + ], + prefix = "fabric/attributedstring", + ), + compiler_flags = [ + "-fexceptions", + "-frtti", + "-std=c++14", + "-Wall", + ], + fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, + fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), + fbobjc_tests = [ + ":tests", + ], + force_static = True, + macosx_tests_override = [], + preprocessor_flags = [ + "-DLOG_TAG=\"ReactNative\"", + "-DWITH_FBSYSTRACE=1", + ], + tests = [], + visibility = ["PUBLIC"], + deps = [ + "xplat//fbsystrace:fbsystrace", + "xplat//folly:headers_only", + "xplat//folly:memory", + "xplat//folly:molly", + "xplat//third-party/glog:glog", + react_native_xplat_target("fabric/debug:debug"), + react_native_xplat_target("fabric/core:core"), + react_native_xplat_target("fabric/graphics:graphics"), + ], +) + +if not IS_OSS_BUILD: + load("@xplat//build_defs:fb_xplat_cxx_test.bzl", "fb_xplat_cxx_test") + + fb_xplat_cxx_test( + name = "tests", + srcs = glob(["tests/**/*.cpp"]), + headers = glob(["tests/**/*.h"]), + contacts = ["oncall+react_native@xmail.facebook.com"], + compiler_flags = [ + "-fexceptions", + "-frtti", + "-std=c++14", + "-Wall", + ], + platforms = APPLE, + deps = [ + "xplat//folly:molly", + "xplat//third-party/gmock:gtest", + ":attributedstring", + ], + ) diff --git a/ReactCommon/fabric/attributedstring/ParagraphAttributes.cpp b/ReactCommon/fabric/attributedstring/ParagraphAttributes.cpp new file mode 100644 index 00000000000000..3901c18cf38bd3 --- /dev/null +++ b/ReactCommon/fabric/attributedstring/ParagraphAttributes.cpp @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "ParagraphAttributes.h" + +#include +#include + +namespace facebook { +namespace react { + +#pragma mark - DebugStringConvertible + +SharedDebugStringConvertibleList ParagraphAttributes::getDebugProps() const { + ParagraphAttributes defaultParagraphAttributes = {}; + SharedDebugStringConvertibleList list = {}; + +#define PARAGRAPH_ATTRIBUTE(stringName, propertyName, accessor, convertor) \ + if (propertyName != defaultParagraphAttributes.propertyName) { \ + list.push_back(std::make_shared(#stringName, convertor(propertyName accessor))); \ + } + + PARAGRAPH_ATTRIBUTE(maximumNumberOfLines, maximumNumberOfLines, , std::to_string) + PARAGRAPH_ATTRIBUTE(ellipsizeMode, ellipsizeMode, , stringFromEllipsizeMode) + PARAGRAPH_ATTRIBUTE(adjustsFontSizeToFit, adjustsFontSizeToFit, , std::to_string) + PARAGRAPH_ATTRIBUTE(minimumFontSize, minimumFontSize, , std::to_string) + PARAGRAPH_ATTRIBUTE(maximumFontSize, maximumFontSize, , std::to_string) + + return list; +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/attributedstring/ParagraphAttributes.h b/ReactCommon/fabric/attributedstring/ParagraphAttributes.h new file mode 100644 index 00000000000000..42eb1aa0ab0647 --- /dev/null +++ b/ReactCommon/fabric/attributedstring/ParagraphAttributes.h @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 { + +class ParagraphAttributes; + +using SharedParagraphAttributes = std::shared_ptr; + +/* + * Represents all visual attributes of a paragraph of text. + * Two data structures, ParagraphAttributes and AttributedText, should be + * enough to define visual representation of a piece of text on the screen. + */ +class ParagraphAttributes: + public DebugStringConvertible { + +public: + +#pragma mark - Fields + + /* + * Maximum number of lines which paragraph can take. + * Zero value represents "no limit". + */ + int maximumNumberOfLines {0}; + + /* + * In case if a text cannot fit given boudaures, defines a place where + * an ellipsize should be placed. + */ + EllipsizeMode ellipsizeMode {EllipsizeMode::Clip}; + + /* + * Enables font size adjustment to fit constrained boundaries. + */ + bool adjustsFontSizeToFit {false}; + + /* + * In case of font size adjustment enabled, defines minimum and maximum + * font sizes. + */ + Float minimumFontSize {std::numeric_limits::quiet_NaN()}; + Float maximumFontSize {std::numeric_limits::quiet_NaN()}; + +#pragma mark - DebugStringConvertible + + SharedDebugStringConvertibleList getDebugProps() const override; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/attributedstring/TextPrimitives.h b/ReactCommon/fabric/attributedstring/TextPrimitives.h new file mode 100644 index 00000000000000..7d6d0a79b7cc3b --- /dev/null +++ b/ReactCommon/fabric/attributedstring/TextPrimitives.h @@ -0,0 +1,94 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +namespace facebook { +namespace react { + +enum class FontStyle { + Normal, + Italic, + Oblique +}; + +enum class FontWeight: int { + Weight100 = 100, + UltraLight = 100, + Weight200 = 200, + Thin = 200, + Weight300 = 300, + Light = 300, + Weight400 = 400, + Regular = 400, + Weight500 = 500, + Medium = 500, + Weight600 = 600, + Semibold = 600, + Demibold = 600, + Weight700 = 700, + Bold = 700, + Weight800 = 800, + Heavy = 800, + Weight900 = 900, + Black = 900 +}; + +enum class FontVariant: int { + Default = 0, + SmallCaps = 1 << 1, + OldstyleNums = 1 << 2, + LiningNums = 1 << 3, + TabularNums = 1 << 4, + ProportionalNums = 1 << 5 +}; + +enum class EllipsizeMode { + Clip, // Do not add ellipsize, simply clip. + Head, // Truncate at head of line: "...wxyz". + Tail, // Truncate at tail of line: "abcd...". + Middle // Truncate middle of line: "ab...yz". +}; + +enum class TextAlignment { + Natural, // Indicates the default alignment for script. + Left, // Visually left aligned. + Center, // Visually centered. + Right, // Visually right aligned. + Justified // Fully-justified. The last line in a paragraph is natural-aligned. +}; + +enum class WritingDirection { + Natural, // Determines direction using the Unicode Bidi Algorithm rules P2 and P3. + LeftToRight, // Left to right writing direction. + RightToLeft // Right to left writing direction. +}; + +enum class TextDecorationLineType { + None, + Underline, + Strikethrough, + UnderlineStrikethrough +}; + +enum class TextDecorationLineStyle { + Single, + Thick, + Double +}; + +enum class TextDecorationLinePattern { + Solid, + Dot, + Dash, + DashDot, + DashDotDot, +}; + +} // namespace react +} // namespace facebook + diff --git a/ReactCommon/fabric/attributedstring/tests/AttributedStringTest.cpp b/ReactCommon/fabric/attributedstring/tests/AttributedStringTest.cpp new file mode 100644 index 00000000000000..b3a8eddd343df4 --- /dev/null +++ b/ReactCommon/fabric/attributedstring/tests/AttributedStringTest.cpp @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 + +using namespace facebook::react; + +TEST(AttributedStringTest, testSomething) { + // TODO +} diff --git a/ReactCommon/fabric/attributedstring/textValuesConversions.h b/ReactCommon/fabric/attributedstring/textValuesConversions.h new file mode 100644 index 00000000000000..88480b6ff2e578 --- /dev/null +++ b/ReactCommon/fabric/attributedstring/textValuesConversions.h @@ -0,0 +1,120 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 + +namespace facebook { +namespace react { + +inline std::string stringFromEllipsizeMode(const EllipsizeMode &ellipsisMode) { + switch (ellipsisMode) { + case EllipsizeMode::Clip: return "clip"; + case EllipsizeMode::Head: return "head"; + case EllipsizeMode::Tail: return "tail"; + case EllipsizeMode::Middle: return "middle"; + } +} + +inline EllipsizeMode ellipsizeModeFromDynamic(const folly::dynamic &value) { + auto string = value.getString(); + if (string == "clip") { return EllipsizeMode::Clip; } + if (string == "head") { return EllipsizeMode::Head; } + if (string == "tail") { return EllipsizeMode::Tail; } + if (string == "middle") { return EllipsizeMode::Middle; } + abort(); +} + +inline FontWeight fontWeightFromDynamic(const folly::dynamic &value) { + auto string = value.asString(); + if (string == "normal") { return FontWeight::Regular; } + if (string == "regular") { return FontWeight::Regular; } + if (string == "bold") { return FontWeight::Bold; } + if (string == "100") { return FontWeight::Weight100; } + if (string == "200") { return FontWeight::Weight200; } + if (string == "300") { return FontWeight::Weight300; } + if (string == "400") { return FontWeight::Weight400; } + if (string == "500") { return FontWeight::Weight500; } + if (string == "600") { return FontWeight::Weight600; } + if (string == "700") { return FontWeight::Weight700; } + if (string == "800") { return FontWeight::Weight800; } + if (string == "900") { return FontWeight::Weight900; } + abort(); +} + +inline FontStyle fontStyleFromDynamic(const folly::dynamic &value) { + auto string = value.asString(); + if (string == "normal") { return FontStyle::Normal; } + if (string == "italic") { return FontStyle::Italic; } + if (string == "oblique") { return FontStyle::Oblique; } + abort(); +} + +inline FontVariant fontVariantFromDynamic(const folly::dynamic &value) { + assert(value.isArray()); + FontVariant fontVariant = FontVariant::Default; + for (auto &&item : value) { + auto string = item.asString(); + if (string == "small-caps") { fontVariant = (FontVariant)((int)fontVariant | (int)FontVariant::SmallCaps); continue; } + if (string == "oldstyle-nums") { fontVariant = (FontVariant)((int)fontVariant | (int)FontVariant::OldstyleNums); continue; } + if (string == "lining-nums") { fontVariant = (FontVariant)((int)fontVariant | (int)FontVariant::LiningNums); continue; } + if (string == "tabular-nums") { fontVariant = (FontVariant)((int)fontVariant | (int)FontVariant::TabularNums); continue; } + if (string == "proportional-nums") { fontVariant = (FontVariant)((int)fontVariant | (int)FontVariant::ProportionalNums); continue; } + } + return fontVariant; +} + +inline TextAlignment textAlignmentFromDynamic(const folly::dynamic &value) { + auto string = value.asString(); + if (string == "natural") { return TextAlignment::Natural; } + if (string == "left") { return TextAlignment::Left; } + if (string == "center") { return TextAlignment::Center; } + if (string == "right") { return TextAlignment::Right; } + if (string == "justified") { return TextAlignment::Justified; } + abort(); +} + +inline WritingDirection writingDirectionFromDynamic(const folly::dynamic &value) { + auto string = value.asString(); + if (string == "natural") { return WritingDirection::Natural; } + if (string == "ltr") { return WritingDirection::LeftToRight; } + if (string == "rtl") { return WritingDirection::RightToLeft; } + abort(); +} + +inline TextDecorationLineType textDecorationLineTypeFromDynamic(const folly::dynamic &value) { + auto string = value.asString(); + if (string == "none") { return TextDecorationLineType::None; } + if (string == "underline") { return TextDecorationLineType::Underline; } + if (string == "strikethrough") { return TextDecorationLineType::Strikethrough; } + if (string == "underline-strikethrough") { return TextDecorationLineType::UnderlineStrikethrough; } + abort(); +} + +inline TextDecorationLineStyle textDecorationLineStyleFromDynamic(const folly::dynamic &value) { + auto string = value.asString(); + if (string == "single") { return TextDecorationLineStyle::Single; } + if (string == "thick") { return TextDecorationLineStyle::Thick; } + if (string == "double") { return TextDecorationLineStyle::Double; } + abort(); +} + +inline TextDecorationLinePattern textDecorationLinePatternFromDynamic(const folly::dynamic &value) { + auto string = value.asString(); + if (string == "solid") { return TextDecorationLinePattern::Solid; } + if (string == "dot") { return TextDecorationLinePattern::Dot; } + if (string == "dash") { return TextDecorationLinePattern::Dash; } + if (string == "dash-dot") { return TextDecorationLinePattern::DashDot; } + if (string == "dash-dot-dot") { return TextDecorationLinePattern::DashDotDot; } + abort(); +} + +} // namespace react +} // namespace facebook From 62576bcb7832e08c6fd9f9482285882c37a2ece5 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Mon, 7 May 2018 17:43:08 -0700 Subject: [PATCH 0455/1109] Fabric/Text: attributedstring module, the second part Reviewed By: mdvacca Differential Revision: D7748711 fbshipit-source-id: 57b37cb2eaa20b85c6f6719b38eac2a2c0479485 --- .../attributedstring/AttributedString.cpp | 68 ++++++++++++++++ .../attributedstring/AttributedString.h | 75 ++++++++++++++++++ .../attributedstring/TextAttributes.cpp | 79 +++++++++++++++++++ .../fabric/attributedstring/TextAttributes.h | 79 +++++++++++++++++++ 4 files changed, 301 insertions(+) create mode 100644 ReactCommon/fabric/attributedstring/AttributedString.cpp create mode 100644 ReactCommon/fabric/attributedstring/AttributedString.h create mode 100644 ReactCommon/fabric/attributedstring/TextAttributes.cpp create mode 100644 ReactCommon/fabric/attributedstring/TextAttributes.h diff --git a/ReactCommon/fabric/attributedstring/AttributedString.cpp b/ReactCommon/fabric/attributedstring/AttributedString.cpp new file mode 100644 index 00000000000000..b5eb74af1aa203 --- /dev/null +++ b/ReactCommon/fabric/attributedstring/AttributedString.cpp @@ -0,0 +1,68 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "AttributedString.h" + +#include + +namespace facebook { +namespace react { + +using Fragment = AttributedString::Fragment; +using Fragments = AttributedString::Fragments; + +void AttributedString::appendFragment(const Fragment &fragment) { + ensureUnsealed(); + fragments_.push_back(fragment); +} + +void AttributedString::prependFragment(const Fragment &fragment) { + ensureUnsealed(); + fragments_.insert(fragments_.begin(), fragment); +} + +void AttributedString::appendAttributedString(const AttributedString &attributedString) { + ensureUnsealed(); + fragments_.insert(fragments_.end(), attributedString.fragments_.begin(), attributedString.fragments_.end()); +} + +void AttributedString::prependAttributedString(const AttributedString &attributedString) { + ensureUnsealed(); + fragments_.insert(fragments_.begin(), attributedString.fragments_.begin(), attributedString.fragments_.end()); +} + +const std::vector &AttributedString::getFragments() const { + return fragments_; +} + +#pragma mark - DebugStringConvertible + +SharedDebugStringConvertibleList AttributedString::getDebugChildren() const { + SharedDebugStringConvertibleList list = {}; + + for (auto &&fragment : fragments_) { + auto propsList = fragment.textAttributes.DebugStringConvertible::getDebugProps(); + + if (fragment.shadowNode) { + propsList.push_back(std::make_shared("shadowNode", fragment.shadowNode->getDebugDescription())); + } + + list.push_back( + std::make_shared( + "Fragment", + fragment.string, + SharedDebugStringConvertibleList(), + propsList + ) + ); + } + + return list; +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/attributedstring/AttributedString.h b/ReactCommon/fabric/attributedstring/AttributedString.h new file mode 100644 index 00000000000000..07cc47603e4590 --- /dev/null +++ b/ReactCommon/fabric/attributedstring/AttributedString.h @@ -0,0 +1,75 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 +#include + +namespace facebook { +namespace react { + +class AttributedString; + +using SharedAttributedString = std::shared_ptr; + +/* + * Simple, cross-platfrom, React-specific implementation of attributed string + * (aka spanned string). + * `AttributedString` is basically a list of `Fragments` which have `string` and + * `textAttributes` + `shadowNode` associated with the `string`. + */ +class AttributedString: + public Sealable, + public DebugStringConvertible { + +public: + + class Fragment { + public: + std::string string; + TextAttributes textAttributes; + SharedShadowNode shadowNode; + }; + + using Fragments = std::vector; + + /* + * Appends and prepends a `fragment` to the string. + */ + void appendFragment(const Fragment &fragment); + void prependFragment(const Fragment &fragment); + + /* + * Appends and prepends an `attributedString` (all its fragments) to + * the string. + */ + void appendAttributedString(const AttributedString &attributedString); + void prependAttributedString(const AttributedString &attributedString); + + /* + * Returns read-only reference to a list of fragments. + */ + const Fragments &getFragments() const; + +#pragma mark - DebugStringConvertible + + SharedDebugStringConvertibleList getDebugChildren() const override; + +private: + + Fragments fragments_; +}; + +} // namespace react +} // namespace facebook + diff --git a/ReactCommon/fabric/attributedstring/TextAttributes.cpp b/ReactCommon/fabric/attributedstring/TextAttributes.cpp new file mode 100644 index 00000000000000..984aba5d377f20 --- /dev/null +++ b/ReactCommon/fabric/attributedstring/TextAttributes.cpp @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "TextAttributes.h" + +#include +#include + +namespace facebook { +namespace react { + +void TextAttributes::apply(TextAttributes textAttributes) { + // Color + foregroundColor = textAttributes.foregroundColor ? textAttributes.foregroundColor : foregroundColor; + backgroundColor = textAttributes.backgroundColor ? textAttributes.backgroundColor : backgroundColor; + opacity = !isnan(textAttributes.opacity) ? textAttributes.opacity : opacity; + + // Font + fontFamily = !textAttributes.fontFamily.empty() ? textAttributes.fontFamily : fontFamily; + fontSize = !isnan(textAttributes.fontSize) ? textAttributes.fontSize : fontSize; + fontSizeMultiplier = !isnan(textAttributes.fontSizeMultiplier) ? textAttributes.fontSizeMultiplier : fontSizeMultiplier; + fontWeight = textAttributes.fontWeight.has_value() ? textAttributes.fontWeight : fontWeight; + fontStyle = textAttributes.fontStyle.has_value() ? textAttributes.fontStyle : fontStyle; + fontVariant = textAttributes.fontVariant.has_value() ? textAttributes.fontVariant : fontVariant; + allowFontScaling = textAttributes.allowFontScaling.has_value() ? textAttributes.allowFontScaling : allowFontScaling; + letterSpacing = !isnan(textAttributes.letterSpacing) ? textAttributes.letterSpacing : letterSpacing; + + // Paragraph Styles + lineHeight = !isnan(textAttributes.lineHeight) ? textAttributes.lineHeight : lineHeight; + alignment = textAttributes.alignment.has_value() ? textAttributes.alignment : alignment; + baseWritingDirection = textAttributes.baseWritingDirection.has_value() ? textAttributes.baseWritingDirection : baseWritingDirection; + + // Decoration + textDecorationColor = textAttributes.textDecorationColor ? textAttributes.textDecorationColor : textDecorationColor; + textDecorationLineType = textAttributes.textDecorationLineType.has_value() ? textAttributes.textDecorationLineType : textDecorationLineType; + textDecorationLineStyle = textAttributes.textDecorationLineStyle.has_value() ? textAttributes.textDecorationLineStyle : textDecorationLineStyle; + textDecorationLinePattern = textAttributes.textDecorationLinePattern.has_value() ? textAttributes.textDecorationLinePattern : textDecorationLinePattern; + + // Shadow + textShadowOffset = textAttributes.textShadowOffset.has_value() ? textAttributes.textShadowOffset.value() : textShadowOffset; + textShadowRadius = !isnan(textAttributes.textShadowRadius) ? textAttributes.textShadowRadius : textShadowRadius; + textShadowColor = textAttributes.textShadowColor ? textAttributes.textShadowColor : textShadowColor; + + // Special + isHighlighted = textAttributes.isHighlighted.has_value() ? textAttributes.isHighlighted : isHighlighted; + layoutDirection = textAttributes.layoutDirection.has_value() ? textAttributes.layoutDirection : layoutDirection; +} + +#pragma mark - DebugStringConvertible + +SharedDebugStringConvertibleList TextAttributes::getDebugProps() const { + TextAttributes defaultAttributes = {}; + + SharedDebugStringConvertibleList list = {}; + +#define PROPS_ADD_TO_SET(propertyName, accessor, convertor) \ + if (propertyName != defaultAttributes.propertyName) { \ + list.push_back(std::make_shared(#propertyName, convertor(propertyName accessor))); \ + } + + PROPS_ADD_TO_SET(backgroundColor, , colorNameFromColor) + PROPS_ADD_TO_SET(foregroundColor, , colorNameFromColor) + PROPS_ADD_TO_SET(opacity, , std::to_string) + + PROPS_ADD_TO_SET(fontFamily, , ) + PROPS_ADD_TO_SET(fontSize, , std::to_string) + PROPS_ADD_TO_SET(fontSizeMultiplier, , std::to_string) + + // TODO: Implement all fields. + + return list; +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/attributedstring/TextAttributes.h b/ReactCommon/fabric/attributedstring/TextAttributes.h new file mode 100644 index 00000000000000..30159eb5c8f495 --- /dev/null +++ b/ReactCommon/fabric/attributedstring/TextAttributes.h @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 +#include +#include +#include + +namespace facebook { +namespace react { + +class TextAttributes; + +using SharedTextAttributes = std::shared_ptr; + +class TextAttributes: + public DebugStringConvertible { +public: + +#pragma mark - Fields + + // Color + SharedColor foregroundColor {nullptr}; + SharedColor backgroundColor {nullptr}; + Float opacity {std::numeric_limits::quiet_NaN()}; + + // Font + std::string fontFamily {""}; + Float fontSize {std::numeric_limits::quiet_NaN()}; + Float fontSizeMultiplier {std::numeric_limits::quiet_NaN()}; + folly::Optional fontWeight {}; + folly::Optional fontStyle {}; + folly::Optional fontVariant {}; + folly::Optional allowFontScaling {}; + Float letterSpacing {std::numeric_limits::quiet_NaN()}; + + // Paragraph Styles + Float lineHeight {std::numeric_limits::quiet_NaN()}; + folly::Optional alignment {}; + folly::Optional baseWritingDirection {}; + + // Decoration + SharedColor textDecorationColor {nullptr}; + folly::Optional textDecorationLineType {}; + folly::Optional textDecorationLineStyle {}; + folly::Optional textDecorationLinePattern {}; + + // Shadow + folly::Optional textShadowOffset {}; + Float textShadowRadius {std::numeric_limits::quiet_NaN()}; + SharedColor textShadowColor {nullptr}; + + // Special + folly::Optional isHighlighted {}; + folly::Optional layoutDirection {}; + +#pragma mark - Operations + + void apply(TextAttributes textAttributes); + +#pragma mark - DebugStringConvertible + + SharedDebugStringConvertibleList getDebugProps() const override; +}; + +} // namespace react +} // namespace facebook + From 05890a5942e7e268934860bfbea648b858adfb72 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Mon, 7 May 2018 18:58:06 -0700 Subject: [PATCH 0456/1109] Fabric/Text: textlayoutmanager Summary: TextLayoutManager measures and renders text using iOS specific APIs (CoreText & TextKit). By desing, only this module should contain platfrom-specific text functionality. Reviewed By: mdvacca Differential Revision: D7751852 fbshipit-source-id: fd6e1907df617fe5a4479ea08f207946765b3a45 --- React.podspec | 9 + ReactCommon/fabric/textlayoutmanager/BUCK | 88 +++++++ .../NSTextStorage+FontScaling.h | 20 ++ .../NSTextStorage+FontScaling.m | 137 +++++++++++ .../RCTAttributedTextUtils.h | 23 ++ .../RCTAttributedTextUtils.mm | 227 ++++++++++++++++++ .../textlayoutmanager/RCTFontProperties.h | 38 +++ .../fabric/textlayoutmanager/RCTFontUtils.h | 19 ++ .../fabric/textlayoutmanager/RCTFontUtils.mm | 153 ++++++++++++ .../textlayoutmanager/RCTTextLayoutManager.h | 32 +++ .../textlayoutmanager/RCTTextLayoutManager.mm | 97 ++++++++ .../RCTTextPrimitivesConversions.h | 75 ++++++ .../textlayoutmanager/TextLayoutManager.h | 51 ++++ .../textlayoutmanager/TextLayoutManager.mm | 40 +++ .../tests/TextLayoutManagerTest.cpp | 18 ++ 15 files changed, 1027 insertions(+) create mode 100644 ReactCommon/fabric/textlayoutmanager/BUCK create mode 100644 ReactCommon/fabric/textlayoutmanager/NSTextStorage+FontScaling.h create mode 100644 ReactCommon/fabric/textlayoutmanager/NSTextStorage+FontScaling.m create mode 100644 ReactCommon/fabric/textlayoutmanager/RCTAttributedTextUtils.h create mode 100644 ReactCommon/fabric/textlayoutmanager/RCTAttributedTextUtils.mm create mode 100644 ReactCommon/fabric/textlayoutmanager/RCTFontProperties.h create mode 100644 ReactCommon/fabric/textlayoutmanager/RCTFontUtils.h create mode 100644 ReactCommon/fabric/textlayoutmanager/RCTFontUtils.mm create mode 100644 ReactCommon/fabric/textlayoutmanager/RCTTextLayoutManager.h create mode 100644 ReactCommon/fabric/textlayoutmanager/RCTTextLayoutManager.mm create mode 100644 ReactCommon/fabric/textlayoutmanager/RCTTextPrimitivesConversions.h create mode 100644 ReactCommon/fabric/textlayoutmanager/TextLayoutManager.h create mode 100644 ReactCommon/fabric/textlayoutmanager/TextLayoutManager.mm create mode 100644 ReactCommon/fabric/textlayoutmanager/tests/TextLayoutManagerTest.cpp diff --git a/React.podspec b/React.podspec index b985ee3ea9c427..44d6ef7f5886ff 100644 --- a/React.podspec +++ b/React.podspec @@ -185,6 +185,15 @@ Pod::Spec.new do |s| sss.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/Folly\"" } end + ss.subspec "textlayoutmanager" do |sss| + sss.dependency "Folly", folly_version + sss.compiler_flags = folly_compiler_flags + sss.source_files = "ReactCommon/fabric/textlayoutmanager/**/*.{cpp,h}" + sss.exclude_files = "**/tests/*" + sss.header_dir = "fabric/textlayoutmanager" + sss.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/Folly\"" } + end + ss.subspec "uimanager" do |sss| sss.dependency "Folly", folly_version sss.compiler_flags = folly_compiler_flags diff --git a/ReactCommon/fabric/textlayoutmanager/BUCK b/ReactCommon/fabric/textlayoutmanager/BUCK new file mode 100644 index 00000000000000..c7bb2f92ec06d9 --- /dev/null +++ b/ReactCommon/fabric/textlayoutmanager/BUCK @@ -0,0 +1,88 @@ +load("//configurations/buck/apple:flag_defs.bzl", "get_debug_preprocessor_flags", "get_fbobjc_enable_exception_lang_compiler_flags") +load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "get_apple_inspector_flags", "APPLE") + +APPLE_COMPILER_FLAGS = [] + +if not IS_OSS_BUILD: + load("@xplat//configurations/buck/apple:flag_defs.bzl", "get_static_library_ios_flags", "flags") + APPLE_COMPILER_FLAGS = flags.get_flag_value(get_static_library_ios_flags(), 'compiler_flags') + +rn_xplat_cxx_library( + name = "textlayoutmanager", + srcs = glob( + [ + "**/*.cpp", + "**/*.mm", + ], + excludes = glob(["tests/**/*.cpp"]), + ), + headers = glob( + ["**/*.h"], + excludes = glob(["tests/**/*.h"]), + ), + header_namespace = "", + exported_headers = subdir_glob( + [ + ("", "*.h"), + ], + prefix = "fabric/textlayoutmanager", + ), + compiler_flags = [ + "-fexceptions", + "-frtti", + "-std=c++14", + "-Wall", + ], + fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, + fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), + fbobjc_tests = [ + ":tests", + ], + force_static = True, + macosx_tests_override = [], + frameworks = [ + "$SDKROOT/System/Library/Frameworks/Foundation.framework", + "$SDKROOT/System/Library/Frameworks/QuartzCore.framework", + "$SDKROOT/System/Library/Frameworks/UIKit.framework", + ], + lang_compiler_flags = get_fbobjc_enable_exception_lang_compiler_flags(), + preprocessor_flags = get_debug_preprocessor_flags() + [ + "-DLOG_TAG=\"ReactNative\"", + "-DWITH_FBSYSTRACE=1", + ], + tests = [], + visibility = ["PUBLIC"], + deps = [ + "xplat//fbsystrace:fbsystrace", + "xplat//folly:headers_only", + "xplat//folly:memory", + "xplat//folly:molly", + "xplat//third-party/glog:glog", + react_native_xplat_target("fabric/attributedstring:attributedstring"), + react_native_xplat_target("fabric/core:core"), + react_native_xplat_target("fabric/debug:debug"), + react_native_xplat_target("fabric/graphics:graphics"), + ], +) + +if not IS_OSS_BUILD: + load("@xplat//build_defs:fb_xplat_cxx_test.bzl", "fb_xplat_cxx_test") + + fb_xplat_cxx_test( + name = "tests", + srcs = glob(["tests/**/*.cpp"]), + headers = glob(["tests/**/*.h"]), + contacts = ["oncall+react_native@xmail.facebook.com"], + compiler_flags = [ + "-fexceptions", + "-frtti", + "-std=c++14", + "-Wall", + ], + platforms = APPLE, + deps = [ + "xplat//folly:molly", + "xplat//third-party/gmock:gtest", + ":textlayoutmanager", + ], + ) diff --git a/ReactCommon/fabric/textlayoutmanager/NSTextStorage+FontScaling.h b/ReactCommon/fabric/textlayoutmanager/NSTextStorage+FontScaling.h new file mode 100644 index 00000000000000..8372a0d2be9183 --- /dev/null +++ b/ReactCommon/fabric/textlayoutmanager/NSTextStorage+FontScaling.h @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +@interface NSTextStorage (FontScaling) + +- (void)scaleFontSizeToFitSize:(CGSize)size + minimumFontSize:(CGFloat)minimumFontSize + maximumFontSize:(CGFloat)maximumFontSize; + +- (void)scaleFontSizeWithRatio:(CGFloat)ratio + minimumFontSize:(CGFloat)minimumFontSize + maximumFontSize:(CGFloat)maximumFontSize; + +@end diff --git a/ReactCommon/fabric/textlayoutmanager/NSTextStorage+FontScaling.m b/ReactCommon/fabric/textlayoutmanager/NSTextStorage+FontScaling.m new file mode 100644 index 00000000000000..5002dddd8a425c --- /dev/null +++ b/ReactCommon/fabric/textlayoutmanager/NSTextStorage+FontScaling.m @@ -0,0 +1,137 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "NSTextStorage+FontScaling.h" + +typedef NS_OPTIONS(NSInteger, RCTTextSizeComparisonOptions) { + RCTTextSizeComparisonSmaller = 1 << 0, + RCTTextSizeComparisonLarger = 1 << 1, + RCTTextSizeComparisonWithinRange = 1 << 2, +}; + +@implementation NSTextStorage (FontScaling) + +- (void)scaleFontSizeToFitSize:(CGSize)size + minimumFontSize:(CGFloat)minimumFontSize + maximumFontSize:(CGFloat)maximumFontSize +{ + CGFloat bottomRatio = 1.0/128.0; + CGFloat topRatio = 128.0; + CGFloat ratio = 1.0; + + NSAttributedString *originalAttributedString = [self copy]; + + CGFloat lastRatioWhichFits = 0.02; + + while (true) { + [self scaleFontSizeWithRatio:ratio + minimumFontSize:minimumFontSize + maximumFontSize:maximumFontSize]; + + RCTTextSizeComparisonOptions comparsion = + [self compareToSize:size thresholdRatio:0.01]; + + if ( + (comparsion & RCTTextSizeComparisonWithinRange) && + (comparsion & RCTTextSizeComparisonSmaller) + ) { + return; + } else if (comparsion & RCTTextSizeComparisonSmaller) { + bottomRatio = ratio; + lastRatioWhichFits = ratio; + } else { + topRatio = ratio; + } + + ratio = (topRatio + bottomRatio) / 2.0; + + CGFloat kRatioThreshold = 0.005; + if ( + ABS(topRatio - bottomRatio) < kRatioThreshold || + ABS(topRatio - ratio) < kRatioThreshold || + ABS(bottomRatio - ratio) < kRatioThreshold + ) { + [self replaceCharactersInRange:(NSRange){0, self.length} + withAttributedString:originalAttributedString]; + + [self scaleFontSizeWithRatio:lastRatioWhichFits + minimumFontSize:minimumFontSize + maximumFontSize:maximumFontSize]; + return; + } + + [self replaceCharactersInRange:(NSRange){0, self.length} + withAttributedString:originalAttributedString]; + } +} + + +- (RCTTextSizeComparisonOptions)compareToSize:(CGSize)size thresholdRatio:(CGFloat)thresholdRatio +{ + NSLayoutManager *layoutManager = self.layoutManagers.firstObject; + NSTextContainer *textContainer = layoutManager.textContainers.firstObject; + + [layoutManager ensureLayoutForTextContainer:textContainer]; + + // Does it fit the text container? + NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer]; + NSRange truncatedGlyphRange = [layoutManager truncatedGlyphRangeInLineFragmentForGlyphAtIndex:glyphRange.length - 1]; + + if (truncatedGlyphRange.location != NSNotFound) { + return RCTTextSizeComparisonLarger; + } + + CGSize measuredSize = [layoutManager usedRectForTextContainer:textContainer].size; + + // Does it fit the size? + BOOL fitsSize = + size.width >= measuredSize.width && + size.height >= measuredSize.height; + + CGSize thresholdSize = (CGSize){ + size.width * thresholdRatio, + size.height * thresholdRatio, + }; + + RCTTextSizeComparisonOptions result = 0; + + result |= (fitsSize) ? RCTTextSizeComparisonSmaller : RCTTextSizeComparisonLarger; + + if (ABS(measuredSize.width - size.width) < thresholdSize.width) { + result = result | RCTTextSizeComparisonWithinRange; + } + + return result; +} + +- (void)scaleFontSizeWithRatio:(CGFloat)ratio + minimumFontSize:(CGFloat)minimumFontSize + maximumFontSize:(CGFloat)maximumFontSize +{ + [self beginEditing]; + + [self enumerateAttribute:NSFontAttributeName + inRange:(NSRange){0, self.length} + options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired + usingBlock: + ^(UIFont *_Nullable font, NSRange range, BOOL *_Nonnull stop) { + if (!font) { + return; + } + + CGFloat fontSize = MAX(MIN(font.pointSize * ratio, maximumFontSize), minimumFontSize); + + [self addAttribute:NSFontAttributeName + value:[font fontWithSize:fontSize] + range:range]; + } + ]; + + [self endEditing]; +} + +@end diff --git a/ReactCommon/fabric/textlayoutmanager/RCTAttributedTextUtils.h b/ReactCommon/fabric/textlayoutmanager/RCTAttributedTextUtils.h new file mode 100644 index 00000000000000..32b0a387d85601 --- /dev/null +++ b/ReactCommon/fabric/textlayoutmanager/RCTAttributedTextUtils.h @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#include +#include + +NS_ASSUME_NONNULL_BEGIN + +NSString *const RCTAttributedStringIsHighlightedAttributeName = @"IsHighlighted"; +NSString *const RCTAttributedStringReactTagAttributeName = @"ReactTag"; + +/** + * Constructs ready-to-render `NSAttributedString` by given `AttributedString`. + */ +NSAttributedString *RCTNSAttributedStringFromAttributedString(const facebook::react::AttributedString &attributedString); + +NS_ASSUME_NONNULL_END diff --git a/ReactCommon/fabric/textlayoutmanager/RCTAttributedTextUtils.mm b/ReactCommon/fabric/textlayoutmanager/RCTAttributedTextUtils.mm new file mode 100644 index 00000000000000..da7c70fd0c6e05 --- /dev/null +++ b/ReactCommon/fabric/textlayoutmanager/RCTAttributedTextUtils.mm @@ -0,0 +1,227 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTAttributedTextUtils.h" + +#include +#include +#include +#include + +inline static UIFont *RCTEffectiveFontFromTextAttributes(const TextAttributes &textAttributes) { + NSString *fontFamily = [NSString stringWithCString:textAttributes.fontFamily.c_str() + encoding:NSASCIIStringEncoding]; + + RCTFontProperties fontProperties; + fontProperties.family = fontFamily; + fontProperties.size = textAttributes.fontSize; + fontProperties.style = textAttributes.fontStyle.has_value() ? RCTFontStyleFromFontStyle(textAttributes.fontStyle.value()) : RCTFontStyleUndefined; + fontProperties.variant = textAttributes.fontVariant.has_value() ? RCTFontVariantFromFontVariant(textAttributes.fontVariant.value()) : RCTFontVariantDefault; + fontProperties.weight = textAttributes.fontWeight.has_value() ? CGFloat(textAttributes.fontWeight.value()) : NAN; + fontProperties.sizeMultiplier = textAttributes.fontSizeMultiplier; + + return RCTFontWithFontProperties(fontProperties); +} + +inline static CGFloat RCTEffectiveFontSizeMultiplierFromTextAttributes(const TextAttributes &textAttributes) { + return textAttributes.allowFontScaling.value_or(true) && !isnan(textAttributes.fontSizeMultiplier) ? textAttributes.fontSizeMultiplier : 1.0; +} + +inline static UIColor *RCTEffectiveForegroundColorFromTextAttributes(const TextAttributes &textAttributes) { + UIColor *effectiveForegroundColor = RCTUIColorFromSharedColor(textAttributes.foregroundColor) ?: [UIColor blackColor]; + + if (!isnan(textAttributes.opacity)) { + effectiveForegroundColor = + [effectiveForegroundColor colorWithAlphaComponent:CGColorGetAlpha(effectiveForegroundColor.CGColor) * textAttributes.opacity]; + } + + return effectiveForegroundColor; +} + +inline static UIColor *RCTEffectiveBackgroundColorFromTextAttributes(const TextAttributes &textAttributes) { + UIColor *effectiveBackgroundColor = RCTUIColorFromSharedColor(textAttributes.backgroundColor); + + if (effectiveBackgroundColor && !isnan(textAttributes.opacity)) { + effectiveBackgroundColor = + [effectiveBackgroundColor colorWithAlphaComponent:CGColorGetAlpha(effectiveBackgroundColor.CGColor) * textAttributes.opacity]; + } + + return effectiveBackgroundColor ?: [UIColor clearColor]; +} + +static NSDictionary *RCTNSTextAttributesFromTextAttributes(const TextAttributes &textAttributes) { + NSMutableDictionary *attributes = + [NSMutableDictionary dictionaryWithCapacity:10]; + + // Font + UIFont *font = RCTEffectiveFontFromTextAttributes(textAttributes); + if (font) { + attributes[NSFontAttributeName] = font; + } + + // Colors + UIColor *effectiveForegroundColor = RCTEffectiveForegroundColorFromTextAttributes(textAttributes); + + if (textAttributes.foregroundColor || !isnan(textAttributes.opacity)) { + attributes[NSForegroundColorAttributeName] = effectiveForegroundColor; + } + + if (textAttributes.backgroundColor || !isnan(textAttributes.opacity)) { + attributes[NSBackgroundColorAttributeName] = RCTEffectiveBackgroundColorFromTextAttributes(textAttributes); + } + + // Kerning + if (!isnan(textAttributes.letterSpacing)) { + attributes[NSKernAttributeName] = @(textAttributes.letterSpacing); + } + + // Paragraph Style + NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new]; + BOOL isParagraphStyleUsed = NO; + if (textAttributes.alignment.has_value()) { + TextAlignment textAlignment = textAttributes.alignment.value_or(TextAlignment::Natural); + if (textAttributes.layoutDirection.value_or(LayoutDirection::LeftToRight) == LayoutDirection::RightToLeft) { + if (textAlignment == TextAlignment::Right) { + textAlignment = TextAlignment::Left; + } else if (textAlignment == TextAlignment::Left) { + textAlignment = TextAlignment::Right; + } + } + + paragraphStyle.alignment = + RCTNSTextAlignmentFromTextAlignment(textAlignment); + isParagraphStyleUsed = YES; + } + + if (textAttributes.baseWritingDirection.has_value()) { + paragraphStyle.baseWritingDirection = + RCTNSWritingDirectionFromWritingDirection(textAttributes.baseWritingDirection.value()); + isParagraphStyleUsed = YES; + } + + if (!isnan(textAttributes.lineHeight)) { + CGFloat lineHeight = + textAttributes.lineHeight * RCTEffectiveFontSizeMultiplierFromTextAttributes(textAttributes); + paragraphStyle.minimumLineHeight = lineHeight; + paragraphStyle.maximumLineHeight = lineHeight; + isParagraphStyleUsed = YES; + } + + if (isParagraphStyleUsed) { + attributes[NSParagraphStyleAttributeName] = paragraphStyle; + } + + // Decoration + if (textAttributes.textDecorationLineType.value_or(TextDecorationLineType::None) != TextDecorationLineType::None) { + auto textDecorationLineType = textAttributes.textDecorationLineType.value(); + + NSUnderlineStyle style = + RCTNSUnderlineStyleFromStyleAndPattern( + textAttributes.textDecorationLineStyle.value_or(TextDecorationLineStyle::Single), + textAttributes.textDecorationLinePattern.value_or(TextDecorationLinePattern::Solid) + ); + + UIColor *textDecorationColor = RCTUIColorFromSharedColor(textAttributes.textDecorationColor); + + // Underline + if (textDecorationLineType == TextDecorationLineType::Underline || + textDecorationLineType == TextDecorationLineType::UnderlineStrikethrough) { + + attributes[NSUnderlineStyleAttributeName] = @(style); + + if (textDecorationColor) { + attributes[NSUnderlineColorAttributeName] = textDecorationColor; + } + } + + // Strikethrough + if (textDecorationLineType == TextDecorationLineType::Strikethrough || + textDecorationLineType == TextDecorationLineType::UnderlineStrikethrough) { + + attributes[NSStrikethroughStyleAttributeName] = @(style); + + if (textDecorationColor) { + attributes[NSStrikethroughColorAttributeName] = textDecorationColor; + } + } + } + + // Shadow + if (textAttributes.textShadowOffset.has_value()) { + auto textShadowOffset = textAttributes.textShadowOffset.value(); + NSShadow *shadow = [NSShadow new]; + shadow.shadowOffset = CGSize {textShadowOffset.x, textShadowOffset.y}; + shadow.shadowBlurRadius = textAttributes.textShadowRadius; + shadow.shadowColor = RCTUIColorFromSharedColor(textAttributes.textShadowColor); + attributes[NSShadowAttributeName] = shadow; + } + + // Special + if (textAttributes.isHighlighted) { + attributes[RCTAttributedStringIsHighlightedAttributeName] = @YES; + } + + return [attributes copy]; +} + +NSAttributedString *RCTNSAttributedStringFromAttributedString(const AttributedString &attributedString) { + NSMutableAttributedString *nsAttributedString = [[NSMutableAttributedString alloc] init]; + + [nsAttributedString beginEditing]; + + for (auto fragment : attributedString.getFragments()) { + NSAttributedString *nsAttributedStringFragment; + + SharedLayoutableShadowNode layoutableShadowNode = + std::dynamic_pointer_cast(fragment.shadowNode); + + if (layoutableShadowNode) { + auto layoutMetrics = layoutableShadowNode->getLayoutMetrics(); + CGRect bounds = { + .origin = { + .x = layoutMetrics.frame.origin.x, + .y = layoutMetrics.frame.origin.y + }, + .size = { + .width = layoutMetrics.frame.size.width, + .height = layoutMetrics.frame.size.height + } + }; + + NSTextAttachment *attachment = [NSTextAttachment new]; + attachment.bounds = bounds; + + nsAttributedStringFragment = [NSAttributedString attributedStringWithAttachment:attachment]; + } else { + NSString *string = + [NSString stringWithCString:fragment.string.c_str() + encoding:NSASCIIStringEncoding]; + + nsAttributedStringFragment = + [[NSAttributedString alloc] initWithString:string + attributes:RCTNSTextAttributesFromTextAttributes(fragment.textAttributes)]; + } + + NSMutableAttributedString *nsMutableAttributedStringFragment = + [[NSMutableAttributedString alloc] initWithAttributedString:nsAttributedStringFragment]; + + if (fragment.shadowNode) { + NSDictionary *additionalTextAttributes = @{ + RCTAttributedStringReactTagAttributeName: @(fragment.shadowNode->getTag()) + }; + + [nsMutableAttributedStringFragment setAttributes:additionalTextAttributes + range:NSMakeRange(0, nsMutableAttributedStringFragment.length)]; + } + + [nsAttributedString appendAttributedString:nsMutableAttributedStringFragment]; + } + + [nsAttributedString endEditing]; + + return nsAttributedString; +} diff --git a/ReactCommon/fabric/textlayoutmanager/RCTFontProperties.h b/ReactCommon/fabric/textlayoutmanager/RCTFontProperties.h new file mode 100644 index 00000000000000..9f8680b47a4a56 --- /dev/null +++ b/ReactCommon/fabric/textlayoutmanager/RCTFontProperties.h @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSInteger, RCTFontStyle) { + RCTFontStyleUndefined = -1, + RCTFontStyleNormal, + RCTFontStyleItalic, + RCTFontStyleOblique, +}; + +typedef NS_OPTIONS(NSInteger, RCTFontVariant) { + RCTFontVariantUndefined = -1, + RCTFontVariantDefault = 0, + RCTFontVariantSmallCaps = 1 << 1, + RCTFontVariantOldstyleNums = 1 << 2, + RCTFontVariantLiningNums = 1 << 3, + RCTFontVariantTabularNums = 1 << 4, + RCTFontVariantProportionalNums = 1 << 5, +}; + +struct RCTFontProperties { + NSString *family; + CGFloat size; + UIFontWeight weight; + RCTFontStyle style; + RCTFontVariant variant; + CGFloat sizeMultiplier; +}; + +NS_ASSUME_NONNULL_END diff --git a/ReactCommon/fabric/textlayoutmanager/RCTFontUtils.h b/ReactCommon/fabric/textlayoutmanager/RCTFontUtils.h new file mode 100644 index 00000000000000..084a2b24dd0b45 --- /dev/null +++ b/ReactCommon/fabric/textlayoutmanager/RCTFontUtils.h @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * Returns UIFont instance corresponded to given font properties. + */ +UIFont *RCTFontWithFontProperties(RCTFontProperties fontProperties); + +NS_ASSUME_NONNULL_END diff --git a/ReactCommon/fabric/textlayoutmanager/RCTFontUtils.mm b/ReactCommon/fabric/textlayoutmanager/RCTFontUtils.mm new file mode 100644 index 00000000000000..38a3d80f5a5d6f --- /dev/null +++ b/ReactCommon/fabric/textlayoutmanager/RCTFontUtils.mm @@ -0,0 +1,153 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTFontUtils.h" + +#import + +static RCTFontProperties RCTDefaultFontProperties() { + static RCTFontProperties defaultFontProperties; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + defaultFontProperties.size = 14; + defaultFontProperties.family = + [UIFont systemFontOfSize:defaultFontProperties.size].familyName; + defaultFontProperties.style = RCTFontStyleNormal; + defaultFontProperties.variant = RCTFontVariantDefault; + defaultFontProperties.sizeMultiplier = 1.0; + }); + + return defaultFontProperties; +} + +static RCTFontProperties RCTResolveFontProperties(RCTFontProperties fontProperties) { + RCTFontProperties defaultFontProperties = RCTDefaultFontProperties(); + fontProperties.family = fontProperties.family.length && ![fontProperties.family isEqualToString:@"System"] ? fontProperties.family : defaultFontProperties.family; + fontProperties.size = !isnan(fontProperties.size) ? fontProperties.size : defaultFontProperties.size; + fontProperties.weight = !isnan(fontProperties.weight) ? fontProperties.weight : defaultFontProperties.weight; + fontProperties.style = fontProperties.style != RCTFontStyleUndefined ? fontProperties.style : defaultFontProperties.style; + fontProperties.variant = fontProperties.variant != RCTFontVariantUndefined ? fontProperties.variant : defaultFontProperties.variant; + return fontProperties; +} + +static UIFontWeight RCTGetFontWeight(UIFont *font) { + NSDictionary *traits = [font.fontDescriptor objectForKey:UIFontDescriptorTraitsAttribute]; + return [traits[UIFontWeightTrait] doubleValue]; +} + +static RCTFontStyle RCTGetFontStyle(UIFont *font) { + NSDictionary *traits = [font.fontDescriptor objectForKey:UIFontDescriptorTraitsAttribute]; + UIFontDescriptorSymbolicTraits symbolicTraits = [traits[UIFontSymbolicTrait] unsignedIntValue]; + if (symbolicTraits & UIFontDescriptorTraitItalic) { + return RCTFontStyleItalic; + } + + return RCTFontStyleNormal; +} + +static NSArray *RCTFontFeatures(RCTFontVariant fontVariant) { + // FIXME: + return @[]; +} + +static UIFont *RCTDefaultFontWithFontProperties(RCTFontProperties fontProperties) { + static NSCache *fontCache; + static std::mutex fontCacheMutex; + + NSString *cacheKey = [NSString stringWithFormat:@"%.1f/%.2f", fontProperties.size, fontProperties.weight]; + UIFont *font; + + { + std::lock_guard lock(fontCacheMutex); + if (!fontCache) { + fontCache = [NSCache new]; + } + font = [fontCache objectForKey:cacheKey]; + } + + if (!font) { + font = [UIFont systemFontOfSize:fontProperties.size + weight:fontProperties.weight]; + + if (fontProperties.variant == RCTFontStyleItalic) { + UIFontDescriptor *fontDescriptor = [font fontDescriptor]; + UIFontDescriptorSymbolicTraits symbolicTraits = fontDescriptor.symbolicTraits; + + symbolicTraits |= UIFontDescriptorTraitItalic; + + fontDescriptor = [fontDescriptor fontDescriptorWithSymbolicTraits:symbolicTraits]; + font = [UIFont fontWithDescriptor:fontDescriptor size:fontProperties.size]; + } + + { + std::lock_guard lock(fontCacheMutex); + [fontCache setObject:font forKey:cacheKey]; + } + } + + return font; +} + +UIFont *RCTFontWithFontProperties(RCTFontProperties fontProperties) { + RCTFontProperties defaultFontProperties = RCTDefaultFontProperties(); + fontProperties = RCTResolveFontProperties(fontProperties); + + CGFloat effectiveFontSize = fontProperties.sizeMultiplier * fontProperties.size; + UIFont *font; + if ([fontProperties.family isEqualToString:defaultFontProperties.family]) { + // Handle system font as special case. This ensures that we preserve + // the specific metrics of the standard system font as closely as possible. + font = RCTDefaultFontWithFontProperties(fontProperties); + } else { + NSArray *fontNames = + [UIFont fontNamesForFamilyName:fontProperties.family]; + + if (fontNames.count == 0) { + // Gracefully handle being given a font name rather than font family, for + // example: "Helvetica Light Oblique" rather than just "Helvetica". + font = [UIFont fontWithName:fontProperties.family size:effectiveFontSize]; + + if (!font) { + // Failback to system font. + font = [UIFont systemFontOfSize:effectiveFontSize weight:fontProperties.weight]; + } + } else { + // Get the closest font that matches the given weight for the fontFamily + CGFloat closestWeight = INFINITY; + for (NSString *name in fontNames) { + UIFont *fontMatch = [UIFont fontWithName:name size:effectiveFontSize]; + + if (RCTGetFontStyle(fontMatch) != fontProperties.style) { + continue; + } + + CGFloat testWeight = RCTGetFontWeight(fontMatch); + if (ABS(testWeight - fontProperties.weight) < ABS(closestWeight - fontProperties.weight)) { + font = fontMatch; + closestWeight = testWeight; + } + } + + if (!font) { + // If we still don't have a match at least return the first font in the fontFamily + // This is to support built-in font Zapfino and other custom single font families like Impact + font = [UIFont fontWithName:fontNames[0] size:effectiveFontSize]; + } + } + } + + // Apply font variants to font object. + if (fontProperties.variant != RCTFontVariantDefault) { + NSArray *fontFeatures = RCTFontFeatures(fontProperties.variant); + UIFontDescriptor *fontDescriptor = + [font.fontDescriptor fontDescriptorByAddingAttributes:@{UIFontDescriptorFeatureSettingsAttribute: fontFeatures}]; + font = [UIFont fontWithDescriptor:fontDescriptor size:effectiveFontSize]; + } + + return font; +} diff --git a/ReactCommon/fabric/textlayoutmanager/RCTTextLayoutManager.h b/ReactCommon/fabric/textlayoutmanager/RCTTextLayoutManager.h new file mode 100644 index 00000000000000..8a745aa4a60b9b --- /dev/null +++ b/ReactCommon/fabric/textlayoutmanager/RCTTextLayoutManager.h @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * iOS-specific TextLayoutManager + */ +@interface RCTTextLayoutManager : NSObject + +- (facebook::react::Size)measureWithAttributedString:(facebook::react::AttributedString)attributedString + paragraphAttributes:(facebook::react::ParagraphAttributes)paragraphAttributes + layoutConstraints:(facebook::react::LayoutConstraints)layoutConstraints; + +- (void)drawAttributedString:(facebook::react::AttributedString)attributedString + paragraphAttributes:(facebook::react::ParagraphAttributes)paragraphAttributes + frame:(CGRect)frame; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ReactCommon/fabric/textlayoutmanager/RCTTextLayoutManager.mm b/ReactCommon/fabric/textlayoutmanager/RCTTextLayoutManager.mm new file mode 100644 index 00000000000000..f729c9c814c778 --- /dev/null +++ b/ReactCommon/fabric/textlayoutmanager/RCTTextLayoutManager.mm @@ -0,0 +1,97 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTTextLayoutManager.h" + +#import "NSTextStorage+FontScaling.h" +#import "RCTAttributedTextUtils.h" + +using namespace facebook::react; + +@implementation RCTTextLayoutManager + +static NSLineBreakMode RCTNSLineBreakModeFromWritingDirection(EllipsizeMode ellipsizeMode) { + switch (ellipsizeMode) { + case EllipsizeMode::Clip: return NSLineBreakByClipping; + case EllipsizeMode::Head: return NSLineBreakByTruncatingHead; + case EllipsizeMode::Tail: return NSLineBreakByTruncatingTail; + case EllipsizeMode::Middle: return NSLineBreakByTruncatingMiddle; + } +} + +- (facebook::react::Size)measureWithAttributedString:(AttributedString)attributedString + paragraphAttributes:(ParagraphAttributes)paragraphAttributes + layoutConstraints:(LayoutConstraints)layoutConstraints +{ + CGSize maximumSize = CGSize {layoutConstraints.maximumSize.width, layoutConstraints.maximumSize.height}; + NSTextStorage *textStorage = + [self _textStorageAndLayoutManagerWithAttributesString:RCTNSAttributedStringFromAttributedString(attributedString) + paragraphAttributes:paragraphAttributes + size:maximumSize]; + + NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject; + NSTextContainer *textContainer = layoutManager.textContainers.firstObject; + [layoutManager ensureLayoutForTextContainer:textContainer]; + + CGSize size = [layoutManager usedRectForTextContainer:textContainer].size; + + size = (CGSize){ + MIN(size.width, maximumSize.width), + MIN(size.height, maximumSize.height) + }; + + return facebook::react::Size {size.width, size.height}; +} + +- (void)drawAttributedString:(AttributedString)attributedString + paragraphAttributes:(ParagraphAttributes)paragraphAttributes + frame:(CGRect)frame +{ + NSTextStorage *textStorage = + [self _textStorageAndLayoutManagerWithAttributesString:RCTNSAttributedStringFromAttributedString(attributedString) + paragraphAttributes:paragraphAttributes + size:frame.size]; + NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject; + NSTextContainer *textContainer = layoutManager.textContainers.firstObject; + + NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer]; + [layoutManager drawBackgroundForGlyphRange:glyphRange atPoint:frame.origin]; + [layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:frame.origin]; +} + + +- (NSTextStorage *)_textStorageAndLayoutManagerWithAttributesString:(NSAttributedString *)attributedString + paragraphAttributes:(ParagraphAttributes)paragraphAttributes + size:(CGSize)size +{ + NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:size]; + + textContainer.lineFragmentPadding = 0.0; // Note, the default value is 5. + textContainer.lineBreakMode = + paragraphAttributes.maximumNumberOfLines > 0 ? RCTNSLineBreakModeFromWritingDirection(paragraphAttributes.ellipsizeMode) : NSLineBreakByClipping; + textContainer.maximumNumberOfLines = paragraphAttributes.maximumNumberOfLines; + + NSLayoutManager *layoutManager = [NSLayoutManager new]; + [layoutManager addTextContainer:textContainer]; + + NSTextStorage *textStorage = + [[NSTextStorage alloc] initWithAttributedString:attributedString]; + + [textStorage addLayoutManager:layoutManager]; + + if (paragraphAttributes.adjustsFontSizeToFit) { + CGFloat minimumFontSize = !isnan(paragraphAttributes.minimumFontSize) ? paragraphAttributes.minimumFontSize : 4.0; + CGFloat maximumFontSize = !isnan(paragraphAttributes.maximumFontSize) ? paragraphAttributes.maximumFontSize : 96.0; + [textStorage scaleFontSizeToFitSize:size + minimumFontSize:minimumFontSize + maximumFontSize:maximumFontSize]; + } + + return textStorage; +} + +@end diff --git a/ReactCommon/fabric/textlayoutmanager/RCTTextPrimitivesConversions.h b/ReactCommon/fabric/textlayoutmanager/RCTTextPrimitivesConversions.h new file mode 100644 index 00000000000000..354952d9c8335d --- /dev/null +++ b/ReactCommon/fabric/textlayoutmanager/RCTTextPrimitivesConversions.h @@ -0,0 +1,75 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#include +#include + +using namespace facebook::react; + +inline static NSTextAlignment RCTNSTextAlignmentFromTextAlignment(TextAlignment textAlignment) { + switch (textAlignment) { + case TextAlignment::Natural: return NSTextAlignmentNatural; + case TextAlignment::Left: return NSTextAlignmentLeft; + case TextAlignment::Right: return NSTextAlignmentRight; + case TextAlignment::Center: return NSTextAlignmentCenter; + case TextAlignment::Justified: return NSTextAlignmentJustified; + } +} + +inline static NSWritingDirection RCTNSWritingDirectionFromWritingDirection(WritingDirection writingDirection) { + switch (writingDirection) { + case WritingDirection::Natural: return NSWritingDirectionNatural; + case WritingDirection::LeftToRight: return NSWritingDirectionLeftToRight; + case WritingDirection::RightToLeft: return NSWritingDirectionRightToLeft; + } +} + +inline static RCTFontStyle RCTFontStyleFromFontStyle(FontStyle fontStyle) { + switch (fontStyle) { + case FontStyle::Normal: return RCTFontStyleNormal; + case FontStyle::Italic: return RCTFontStyleItalic; + case FontStyle::Oblique: return RCTFontStyleOblique; + } +} + +inline static RCTFontVariant RCTFontVariantFromFontVariant(FontVariant fontVariant) { + return (RCTFontVariant)fontVariant; +} + +inline static NSUnderlineStyle RCTNSUnderlineStyleFromStyleAndPattern(TextDecorationLineStyle textDecorationLineStyle, TextDecorationLinePattern textDecorationLinePattern) { + NSUnderlineStyle style = NSUnderlineStyleNone; + + switch (textDecorationLineStyle) { + case TextDecorationLineStyle::Single: + style = NSUnderlineStyle(style | NSUnderlineStyleSingle); break; + case TextDecorationLineStyle::Thick: + style = NSUnderlineStyle(style | NSUnderlineStyleThick); break; + case TextDecorationLineStyle::Double: + style = NSUnderlineStyle(style | NSUnderlineStyleDouble); break; + } + + switch (textDecorationLinePattern) { + case TextDecorationLinePattern::Solid: + style = NSUnderlineStyle(style | NSUnderlinePatternSolid); break; + case TextDecorationLinePattern::Dash: + style = NSUnderlineStyle(style | NSUnderlinePatternDash); break; + case TextDecorationLinePattern::Dot: + style = NSUnderlineStyle(style | NSUnderlinePatternDot); break; + case TextDecorationLinePattern::DashDot: + style = NSUnderlineStyle(style | NSUnderlinePatternDashDot); break; + case TextDecorationLinePattern::DashDotDot: + style = NSUnderlineStyle(style | NSUnderlinePatternDashDotDot); break; + } + + return style; +} + +inline static UIColor *RCTUIColorFromSharedColor(const SharedColor &color) { + return color ? [UIColor colorWithCGColor:color.get()] : nil; +} diff --git a/ReactCommon/fabric/textlayoutmanager/TextLayoutManager.h b/ReactCommon/fabric/textlayoutmanager/TextLayoutManager.h new file mode 100644 index 00000000000000..dd54980ffd737e --- /dev/null +++ b/ReactCommon/fabric/textlayoutmanager/TextLayoutManager.h @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 { + +class TextLayoutManager; + +using SharedTextLayoutManager = std::shared_ptr; + +/* + * Cross platform facade for iOS-specific RCTTTextLayoutManager. + */ +class TextLayoutManager { +public: + TextLayoutManager(); + ~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_; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/textlayoutmanager/TextLayoutManager.mm b/ReactCommon/fabric/textlayoutmanager/TextLayoutManager.mm new file mode 100644 index 00000000000000..f7658211522fb7 --- /dev/null +++ b/ReactCommon/fabric/textlayoutmanager/TextLayoutManager.mm @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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" + +#import "RCTTextLayoutManager.h" + +namespace facebook { +namespace react { + +TextLayoutManager::TextLayoutManager() { + self_ = (__bridge_retained void *)[RCTTextLayoutManager new]; +} + +TextLayoutManager::~TextLayoutManager() { + CFRelease(self_); + self_ = nullptr; +} + +void *TextLayoutManager::getNativeTextLayoutManager() const { + return self_; +} + +Size TextLayoutManager::measure( + AttributedString attributedString, + ParagraphAttributes paragraphAttributes, + LayoutConstraints layoutConstraints +) const { + RCTTextLayoutManager *textLayoutManager = (__bridge RCTTextLayoutManager *)self_; + return [textLayoutManager measureWithAttributedString:attributedString + paragraphAttributes:paragraphAttributes + layoutConstraints:layoutConstraints]; +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/textlayoutmanager/tests/TextLayoutManagerTest.cpp b/ReactCommon/fabric/textlayoutmanager/tests/TextLayoutManagerTest.cpp new file mode 100644 index 00000000000000..d873c6eed80e86 --- /dev/null +++ b/ReactCommon/fabric/textlayoutmanager/tests/TextLayoutManagerTest.cpp @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 + +using namespace facebook::react; + +TEST(TextLayoutManagerTest, testSomething) { + // TODO: +} From 02c3cd4c4e712dea004713c271f0ae0d5a03ac96 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Mon, 7 May 2018 21:49:19 -0700 Subject: [PATCH 0457/1109] Fabric/Text: text module, rawtext part Summary: component represents a purely regular string object in React. Reviewed By: mdvacca Differential Revision: D7751850 fbshipit-source-id: 54afe43e0c1ac063862f109ea07f0e7de3593573 --- React.podspec | 9 ++ ReactCommon/fabric/text/BUCK | 84 +++++++++++++++++++ .../text/rawtext/RawTextComponentDescriptor.h | 27 ++++++ .../fabric/text/rawtext/RawTextProps.cpp | 37 ++++++++ .../fabric/text/rawtext/RawTextProps.h | 43 ++++++++++ .../fabric/text/rawtext/RawTextShadowNode.cpp | 20 +++++ .../fabric/text/rawtext/RawTextShadowNode.h | 39 +++++++++ ReactCommon/fabric/text/tests/TextTest.cpp | 14 ++++ 8 files changed, 273 insertions(+) create mode 100644 ReactCommon/fabric/text/BUCK create mode 100644 ReactCommon/fabric/text/rawtext/RawTextComponentDescriptor.h create mode 100644 ReactCommon/fabric/text/rawtext/RawTextProps.cpp create mode 100644 ReactCommon/fabric/text/rawtext/RawTextProps.h create mode 100644 ReactCommon/fabric/text/rawtext/RawTextShadowNode.cpp create mode 100644 ReactCommon/fabric/text/rawtext/RawTextShadowNode.h create mode 100644 ReactCommon/fabric/text/tests/TextTest.cpp diff --git a/React.podspec b/React.podspec index 44d6ef7f5886ff..9305d94ea4842d 100644 --- a/React.podspec +++ b/React.podspec @@ -185,6 +185,15 @@ Pod::Spec.new do |s| sss.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/Folly\"" } end + ss.subspec "text" do |sss| + sss.dependency "Folly", folly_version + sss.compiler_flags = folly_compiler_flags + sss.source_files = "ReactCommon/fabric/text/**/*.{cpp,h}" + sss.exclude_files = "**/tests/*" + sss.header_dir = "fabric/text" + sss.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/Folly\"" } + end + ss.subspec "textlayoutmanager" do |sss| sss.dependency "Folly", folly_version sss.compiler_flags = folly_compiler_flags diff --git a/ReactCommon/fabric/text/BUCK b/ReactCommon/fabric/text/BUCK new file mode 100644 index 00000000000000..20a30de396639b --- /dev/null +++ b/ReactCommon/fabric/text/BUCK @@ -0,0 +1,84 @@ +load("//configurations/buck/apple:flag_defs.bzl", "get_debug_preprocessor_flags", "get_fbobjc_enable_exception_lang_compiler_flags") +load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "get_apple_inspector_flags", "APPLE") + +APPLE_COMPILER_FLAGS = [] + +if not IS_OSS_BUILD: + load("@xplat//configurations/buck/apple:flag_defs.bzl", "get_static_library_ios_flags", "flags") + APPLE_COMPILER_FLAGS = flags.get_flag_value(get_static_library_ios_flags(), 'compiler_flags') + +rn_xplat_cxx_library( + name = "text", + srcs = glob( + ["**/*.cpp"], + excludes = glob(["tests/**/*.cpp"]), + ), + headers = glob( + ["**/*.h"], + excludes = glob(["tests/**/*.h"]), + ), + header_namespace = "", + exported_headers = subdir_glob( + [ + ("", "*.h"), + ("paragraph", "*.h"), + ("text", "*.h"), + ("rawtext", "*.h"), + ], + prefix = "fabric/text", + ), + compiler_flags = [ + "-fexceptions", + "-frtti", + "-std=c++14", + "-Wall", + ], + fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, + fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), + fbobjc_tests = [ + ":tests", + ], + force_static = True, + macosx_tests_override = [], + preprocessor_flags = [ + "-DLOG_TAG=\"ReactNative\"", + "-DWITH_FBSYSTRACE=1", + ], + tests = [], + visibility = ["PUBLIC"], + deps = [ + "xplat//fbsystrace:fbsystrace", + "xplat//folly:headers_only", + "xplat//folly:memory", + "xplat//folly:molly", + "xplat//third-party/glog:glog", + react_native_xplat_target("fabric/attributedstring:attributedstring"), + react_native_xplat_target("fabric/core:core"), + react_native_xplat_target("fabric/debug:debug"), + react_native_xplat_target("fabric/graphics:graphics"), + react_native_xplat_target("fabric/textlayoutmanager:textlayoutmanager"), + react_native_xplat_target("fabric/view:view"), + ], +) + +if not IS_OSS_BUILD: + load("@xplat//build_defs:fb_xplat_cxx_test.bzl", "fb_xplat_cxx_test") + + fb_xplat_cxx_test( + name = "tests", + srcs = glob(["tests/**/*.cpp"]), + headers = glob(["tests/**/*.h"]), + contacts = ["oncall+react_native@xmail.facebook.com"], + compiler_flags = [ + "-fexceptions", + "-frtti", + "-std=c++14", + "-Wall", + ], + platforms = APPLE, + deps = [ + "xplat//folly:molly", + "xplat//third-party/gmock:gtest", + ":text", + ], + ) diff --git a/ReactCommon/fabric/text/rawtext/RawTextComponentDescriptor.h b/ReactCommon/fabric/text/rawtext/RawTextComponentDescriptor.h new file mode 100644 index 00000000000000..6f615fa3c620f1 --- /dev/null +++ b/ReactCommon/fabric/text/rawtext/RawTextComponentDescriptor.h @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 { + +/* + * Descriptor for component. + */ +class RawTextComponentDescriptor: public ConcreteComponentDescriptor { +public: + ComponentName getComponentName() const override { + return "RawText"; + } +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/text/rawtext/RawTextProps.cpp b/ReactCommon/fabric/text/rawtext/RawTextProps.cpp new file mode 100644 index 00000000000000..d985188c9dd87f --- /dev/null +++ b/ReactCommon/fabric/text/rawtext/RawTextProps.cpp @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "RawTextProps.h" + +#include +#include + +namespace facebook { +namespace react { + +void RawTextProps::apply(const RawProps &rawProps) { + Props::apply(rawProps); + + applyRawProp(rawProps, "text", text_); +} + +#pragma mark - Getters + +std::string RawTextProps::getText() const { + return text_; +} + +#pragma mark - DebugStringConvertible + +SharedDebugStringConvertibleList RawTextProps::getDebugProps() const { + SharedDebugStringConvertibleList list = {}; + list.push_back(std::make_shared("text", text_)); + return list; +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/text/rawtext/RawTextProps.h b/ReactCommon/fabric/text/rawtext/RawTextProps.h new file mode 100644 index 00000000000000..4dd84f8fba5a0d --- /dev/null +++ b/ReactCommon/fabric/text/rawtext/RawTextProps.h @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 + +namespace facebook { +namespace react { + +class RawTextProps; + +using SharedRawTextProps = std::shared_ptr; + +class RawTextProps: + public Props { + +public: + + void apply(const RawProps &rawProps) override; + +#pragma mark - Getters + + std::string getText() const; + +#pragma mark - DebugStringConvertible + + SharedDebugStringConvertibleList getDebugProps() const override; + +private: + + std::string text_ {""}; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/text/rawtext/RawTextShadowNode.cpp b/ReactCommon/fabric/text/rawtext/RawTextShadowNode.cpp new file mode 100644 index 00000000000000..730e4aabb26460 --- /dev/null +++ b/ReactCommon/fabric/text/rawtext/RawTextShadowNode.cpp @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "RawTextShadowNode.h" + +#include + +namespace facebook { +namespace react { + +ComponentName RawTextShadowNode::getComponentName() const { + return ComponentName("RawText"); +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/text/rawtext/RawTextShadowNode.h b/ReactCommon/fabric/text/rawtext/RawTextShadowNode.h new file mode 100644 index 00000000000000..f4a2e2ffcebaf8 --- /dev/null +++ b/ReactCommon/fabric/text/rawtext/RawTextShadowNode.h @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 { + +class RawTextShadowNode; + +using SharedRawTextShadowNode = std::shared_ptr; + +/* + * `ShadowNode` for component, represents a purely regular string + * object in React. In a code fragment `Hello!`, "Hello!" part + * is represented as ``. + * component must not have any children. + */ +class RawTextShadowNode: + public ConcreteShadowNode { + +public: + using ConcreteShadowNode::ConcreteShadowNode; + + ComponentName getComponentName() const override; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/text/tests/TextTest.cpp b/ReactCommon/fabric/text/tests/TextTest.cpp new file mode 100644 index 00000000000000..55ae97a50fad7e --- /dev/null +++ b/ReactCommon/fabric/text/tests/TextTest.cpp @@ -0,0 +1,14 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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(TextLayoutManagerTest, testSomething) { + // TODO: +} From dc7a87e7377ebb2a3e08cdf00c7ba8961fac453a Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Mon, 7 May 2018 21:49:21 -0700 Subject: [PATCH 0458/1109] Fabric/Text: text module, text part Summary: component is used to describe text attributes in React. Reviewed By: mdvacca Differential Revision: D7751851 fbshipit-source-id: f90a4367cad64283ee64828b0d5e24470ee3d9f7 --- ReactCommon/fabric/text/propsConversions.h | 29 +++++++ ReactCommon/fabric/text/tests/TextTest.cpp | 2 +- .../text/text/TextComponentDescriptor.h | 25 +++++++ ReactCommon/fabric/text/text/TextProps.cpp | 75 +++++++++++++++++++ ReactCommon/fabric/text/text/TextProps.h | 46 ++++++++++++ .../fabric/text/text/TextShadowNode.cpp | 59 +++++++++++++++ ReactCommon/fabric/text/text/TextShadowNode.h | 40 ++++++++++ 7 files changed, 275 insertions(+), 1 deletion(-) create mode 100644 ReactCommon/fabric/text/propsConversions.h create mode 100644 ReactCommon/fabric/text/text/TextComponentDescriptor.h create mode 100644 ReactCommon/fabric/text/text/TextProps.cpp create mode 100644 ReactCommon/fabric/text/text/TextProps.h create mode 100644 ReactCommon/fabric/text/text/TextShadowNode.cpp create mode 100644 ReactCommon/fabric/text/text/TextShadowNode.h diff --git a/ReactCommon/fabric/text/propsConversions.h b/ReactCommon/fabric/text/propsConversions.h new file mode 100644 index 00000000000000..1656e82af44f79 --- /dev/null +++ b/ReactCommon/fabric/text/propsConversions.h @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 { + +APPLY_RAW_PROP_TEMPLATE(EllipsizeMode, ellipsizeModeFromDynamic) +APPLY_RAW_PROP_TEMPLATE(FontWeight, fontWeightFromDynamic) +APPLY_RAW_PROP_TEMPLATE(FontStyle, fontStyleFromDynamic) +APPLY_RAW_PROP_TEMPLATE(FontVariant, fontVariantFromDynamic) +APPLY_RAW_PROP_TEMPLATE(WritingDirection, writingDirectionFromDynamic) +APPLY_RAW_PROP_TEMPLATE(TextAlignment, textAlignmentFromDynamic) +APPLY_RAW_PROP_TEMPLATE(TextDecorationLineType, textDecorationLineTypeFromDynamic) +APPLY_RAW_PROP_TEMPLATE(TextDecorationLineStyle, textDecorationLineStyleFromDynamic) +APPLY_RAW_PROP_TEMPLATE(TextDecorationLinePattern, textDecorationLinePatternFromDynamic) + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/text/tests/TextTest.cpp b/ReactCommon/fabric/text/tests/TextTest.cpp index 55ae97a50fad7e..6b995ae90d7b0f 100644 --- a/ReactCommon/fabric/text/tests/TextTest.cpp +++ b/ReactCommon/fabric/text/tests/TextTest.cpp @@ -9,6 +9,6 @@ #include -TEST(TextLayoutManagerTest, testSomething) { +TEST(TextTest, testSomething) { // TODO: } diff --git a/ReactCommon/fabric/text/text/TextComponentDescriptor.h b/ReactCommon/fabric/text/text/TextComponentDescriptor.h new file mode 100644 index 00000000000000..043492f21e91e6 --- /dev/null +++ b/ReactCommon/fabric/text/text/TextComponentDescriptor.h @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 + +namespace facebook { +namespace react { + +class TextComponentDescriptor: public ConcreteComponentDescriptor { +public: + ComponentName getComponentName() const override { + return "Text"; + } +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/text/text/TextProps.cpp b/ReactCommon/fabric/text/text/TextProps.cpp new file mode 100644 index 00000000000000..402d2ea67129ca --- /dev/null +++ b/ReactCommon/fabric/text/text/TextProps.cpp @@ -0,0 +1,75 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "TextProps.h" + +#include +#include +#include +#include +#include + +namespace facebook { +namespace react { + +void TextProps::apply(const RawProps &rawProps) { + Props::apply(rawProps); + + // Color + applyRawProp(rawProps, "color", textAttributes_.foregroundColor); + applyRawProp(rawProps, "backgroundColor", textAttributes_.backgroundColor); + applyRawProp(rawProps, "opacity", textAttributes_.opacity); + + // Font + applyRawProp(rawProps, "fontFamily", textAttributes_.fontFamily); + applyRawProp(rawProps, "fontSize", textAttributes_.fontSize); + applyRawProp(rawProps, "fontSizeMultiplier", textAttributes_.fontSizeMultiplier); + applyRawProp(rawProps, "fontWeight", textAttributes_.fontWeight); + applyRawProp(rawProps, "fontStyle", textAttributes_.fontStyle); + applyRawProp(rawProps, "fontVariant", textAttributes_.fontVariant); + applyRawProp(rawProps, "allowFontScaling", textAttributes_.allowFontScaling); + applyRawProp(rawProps, "letterSpacing", textAttributes_.letterSpacing); + + // Paragraph + applyRawProp(rawProps, "lineHeight", textAttributes_.lineHeight); + applyRawProp(rawProps, "alignment", textAttributes_.alignment); + applyRawProp(rawProps, "baseWritingDirection", textAttributes_.baseWritingDirection); + + // Decoration + applyRawProp(rawProps, "textDecorationColor", textAttributes_.textDecorationColor); + applyRawProp(rawProps, "textDecorationLineType", textAttributes_.textDecorationLineType); + applyRawProp(rawProps, "textDecorationLineStyle", textAttributes_.textDecorationLineStyle); + applyRawProp(rawProps, "textDecorationLinePattern", textAttributes_.textDecorationLinePattern); + + // Shadow + applyRawProp(rawProps, "textShadowOffset", textAttributes_.textShadowOffset); + applyRawProp(rawProps, "textShadowRadius", textAttributes_.textShadowRadius); + applyRawProp(rawProps, "textShadowColor", textAttributes_.textShadowColor); + + // Special + applyRawProp(rawProps, "isHighlighted", textAttributes_.isHighlighted); +} + +#pragma mark - Getters + +TextAttributes TextProps::getTextAttributes() const { + return textAttributes_; +} + +#pragma mark - DebugStringConvertible + +SharedDebugStringConvertibleList TextProps::getDebugProps() const { + SharedDebugStringConvertibleList list = {}; + + auto textAttributesPropsList = textAttributes_.getDebugProps(); + std::move(textAttributesPropsList.begin(), textAttributesPropsList.end(), std::back_inserter(list)); + + return list; +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/text/text/TextProps.h b/ReactCommon/fabric/text/text/TextProps.h new file mode 100644 index 00000000000000..1a96b5519fb8b1 --- /dev/null +++ b/ReactCommon/fabric/text/text/TextProps.h @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 { + +class TextProps; + +using SharedTextProps = std::shared_ptr; + +class TextProps: + public Props { + +public: + void apply(const RawProps &rawProps) override; + +#pragma mark - Getters + + TextAttributes getTextAttributes() const; + +private: + + /* + * Not all `TextAttributes` fields make sense and is used as TextProps values. + */ + TextAttributes textAttributes_; + +#pragma mark - DebugStringConvertible + + SharedDebugStringConvertibleList getDebugProps() const override; +}; + +} // namespace react +} // namespace facebook + diff --git a/ReactCommon/fabric/text/text/TextShadowNode.cpp b/ReactCommon/fabric/text/text/TextShadowNode.cpp new file mode 100644 index 00000000000000..5429c7ba606382 --- /dev/null +++ b/ReactCommon/fabric/text/text/TextShadowNode.cpp @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "TextShadowNode.h" + +#include + +#include "RawTextShadowNode.h" +#include "RawTextProps.h" + +namespace facebook { +namespace react { + +ComponentName TextShadowNode::getComponentName() const { + return ComponentName("Text"); +} + +AttributedString TextShadowNode::getAttributedString(const TextAttributes &baseTextAttributes) const { + // TODO: Implement caching. + + TextAttributes textAttributes = baseTextAttributes; + textAttributes.apply(getProps()->getTextAttributes()); + + AttributedString attributedString; + + for (auto &&childNode : *getChildren()) { + // RawShadowNode + SharedRawTextShadowNode rawTextShadowNode = std::dynamic_pointer_cast(childNode); + if (rawTextShadowNode) { + AttributedString::Fragment fragment; + fragment.string = rawTextShadowNode->getProps()->getText(); + fragment.textAttributes = textAttributes; + attributedString.appendFragment(fragment); + continue; + } + + // TextShadowNode + SharedTextShadowNode textShadowNode = std::dynamic_pointer_cast(childNode); + if (textShadowNode) { + attributedString.appendAttributedString(textShadowNode->getAttributedString(textAttributes)); + continue; + } + + // Any other kind of ShadowNode + AttributedString::Fragment fragment; + fragment.shadowNode = childNode; + fragment.textAttributes = textAttributes; + attributedString.appendFragment(fragment); + } + + return attributedString; +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/text/text/TextShadowNode.h b/ReactCommon/fabric/text/text/TextShadowNode.h new file mode 100644 index 00000000000000..0eb421a96630a8 --- /dev/null +++ b/ReactCommon/fabric/text/text/TextShadowNode.h @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 +#include + +namespace facebook { +namespace react { + +class TextShadowNode; + +using SharedTextShadowNode = std::shared_ptr; + +class TextShadowNode: + public ConcreteShadowNode { + +public: + + using ConcreteShadowNode::ConcreteShadowNode; + + ComponentName getComponentName() const override; + + /* + * Returns a `AttributedString` which represents text content of the node. + */ + AttributedString getAttributedString(const TextAttributes &baseTextAttributes) const; +}; + +} // namespace react +} // namespace facebook From b5a780608e7c48f370f6aabb5db4c6d6c6923848 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Mon, 7 May 2018 21:49:23 -0700 Subject: [PATCH 0459/1109] Fabric/Text: text module, paragraph part Summary: component represents -like component containing and displaying text. Reviewed By: mdvacca Differential Revision: D7751854 fbshipit-source-id: 1acdfebf6f96a5da068ce985e15288e958266855 --- ReactCommon/fabric/text/BUCK | 6 +- .../paragraph/ParagraphComponentDescriptor.h | 55 +++++++++++++ .../text/paragraph/ParagraphLocalData.cpp | 46 +++++++++++ .../text/paragraph/ParagraphLocalData.h | 56 +++++++++++++ .../fabric/text/paragraph/ParagraphProps.cpp | 59 ++++++++++++++ .../fabric/text/paragraph/ParagraphProps.h | 60 ++++++++++++++ .../text/paragraph/ParagraphShadowNode.cpp | 63 +++++++++++++++ .../text/paragraph/ParagraphShadowNode.h | 78 +++++++++++++++++++ 8 files changed, 421 insertions(+), 2 deletions(-) create mode 100644 ReactCommon/fabric/text/paragraph/ParagraphComponentDescriptor.h create mode 100644 ReactCommon/fabric/text/paragraph/ParagraphLocalData.cpp create mode 100644 ReactCommon/fabric/text/paragraph/ParagraphLocalData.h create mode 100644 ReactCommon/fabric/text/paragraph/ParagraphProps.cpp create mode 100644 ReactCommon/fabric/text/paragraph/ParagraphProps.h create mode 100644 ReactCommon/fabric/text/paragraph/ParagraphShadowNode.cpp create mode 100644 ReactCommon/fabric/text/paragraph/ParagraphShadowNode.h diff --git a/ReactCommon/fabric/text/BUCK b/ReactCommon/fabric/text/BUCK index 20a30de396639b..04fbad8d174971 100644 --- a/ReactCommon/fabric/text/BUCK +++ b/ReactCommon/fabric/text/BUCK @@ -1,5 +1,5 @@ -load("//configurations/buck/apple:flag_defs.bzl", "get_debug_preprocessor_flags", "get_fbobjc_enable_exception_lang_compiler_flags") -load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "get_apple_inspector_flags", "APPLE") +load("//configurations/buck/apple:flag_defs.bzl", "get_application_ios_flags", "get_debug_preprocessor_flags", "OBJC_ARC_PREPROCESSOR_FLAGS") +load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "rn_xplat_cxx_library", "get_apple_inspector_flags", "react_native_xplat_target", "ANDROID", "APPLE") APPLE_COMPILER_FLAGS = [] @@ -40,6 +40,7 @@ rn_xplat_cxx_library( ], force_static = True, macosx_tests_override = [], + platforms = (ANDROID, APPLE), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", @@ -52,6 +53,7 @@ rn_xplat_cxx_library( "xplat//folly:memory", "xplat//folly:molly", "xplat//third-party/glog:glog", + "xplat//yoga:yoga", react_native_xplat_target("fabric/attributedstring:attributedstring"), react_native_xplat_target("fabric/core:core"), react_native_xplat_target("fabric/debug:debug"), diff --git a/ReactCommon/fabric/text/paragraph/ParagraphComponentDescriptor.h b/ReactCommon/fabric/text/paragraph/ParagraphComponentDescriptor.h new file mode 100644 index 00000000000000..d776767830064e --- /dev/null +++ b/ReactCommon/fabric/text/paragraph/ParagraphComponentDescriptor.h @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 + +namespace facebook { +namespace react { + +/* + * Descriptor for component. + */ +class ParagraphComponentDescriptor: public ConcreteComponentDescriptor { +public: + + ParagraphComponentDescriptor(): + ConcreteComponentDescriptor() { + // Every single `ParagraphShadowNode` will have a reference to + // a shared `TextLayoutManager`. + textLayoutManager_ = std::make_shared(); + } + + ComponentName getComponentName() const override { + return "Paragraph"; + } + + void adopt(UnsharedShadowNode shadowNode) const override { + ConcreteComponentDescriptor::adopt(shadowNode); + + assert(std::dynamic_pointer_cast(shadowNode)); + auto paragraphShadowNode = std::static_pointer_cast(shadowNode); + + // `ParagraphShadowNode` uses `TextLayoutManager` to measure text content + // and communicate text rendering metrics to mounting layer. + paragraphShadowNode->setTextLayoutManager(textLayoutManager_); + + // All `ParagraphShadowNode`s must have leaf Yoga nodes with properly + // setup measure function. + paragraphShadowNode->enableMeasurement(); + } + +private: + + SharedTextLayoutManager textLayoutManager_; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/text/paragraph/ParagraphLocalData.cpp b/ReactCommon/fabric/text/paragraph/ParagraphLocalData.cpp new file mode 100644 index 00000000000000..0390313b689c34 --- /dev/null +++ b/ReactCommon/fabric/text/paragraph/ParagraphLocalData.cpp @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "ParagraphLocalData.h" + +#include + +namespace facebook { +namespace react { + +AttributedString ParagraphLocalData::getAttributedString() const { + return attributedString_; +} + +void ParagraphLocalData::setAttributedString(AttributedString attributedString) { + ensureUnsealed(); + attributedString_ = attributedString; +} + +SharedTextLayoutManager ParagraphLocalData::getTextLayoutManager() const { + return textLayoutManager_; +} + +void ParagraphLocalData::setTextLayoutManager(SharedTextLayoutManager textLayoutManager) { + ensureUnsealed(); + textLayoutManager_ = textLayoutManager; +} + +#pragma mark - DebugStringConvertible + +std::string ParagraphLocalData::getDebugName() const { + return "ParagraphLocalData"; +} + +SharedDebugStringConvertibleList ParagraphLocalData::getDebugProps() const { + SharedDebugStringConvertibleList list = {}; + list.push_back(std::make_shared("attributedString", attributedString_.getDebugDescription())); + return list; +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/text/paragraph/ParagraphLocalData.h b/ReactCommon/fabric/text/paragraph/ParagraphLocalData.h new file mode 100644 index 00000000000000..7f3ad4007a3399 --- /dev/null +++ b/ReactCommon/fabric/text/paragraph/ParagraphLocalData.h @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 + +namespace facebook { +namespace react { + +class ParagraphLocalData; + +using SharedParagraphLocalData = std::shared_ptr; + +/* + * LocalData for component. + * Represents what to render and how to render. + */ +class ParagraphLocalData: + public LocalData { + +public: + + /* + * All content of component represented as an `AttributedString`. + */ + AttributedString getAttributedString() const; + void setAttributedString(AttributedString attributedString); + + /* + * `TextLayoutManager` provides a connection to platform-specific + * text rendering infrastructure which is capable to render the + * `AttributedString`. + */ + SharedTextLayoutManager getTextLayoutManager() const; + void setTextLayoutManager(SharedTextLayoutManager textLayoutManager); + +#pragma mark - DebugStringConvertible + + std::string getDebugName() const override; + SharedDebugStringConvertibleList getDebugProps() const override; + +private: + + AttributedString attributedString_; + SharedTextLayoutManager textLayoutManager_; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/text/paragraph/ParagraphProps.cpp b/ReactCommon/fabric/text/paragraph/ParagraphProps.cpp new file mode 100644 index 00000000000000..89faa944565a04 --- /dev/null +++ b/ReactCommon/fabric/text/paragraph/ParagraphProps.cpp @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "ParagraphProps.h" + +#include +#include +#include +#include + +namespace facebook { +namespace react { + +void ParagraphProps::apply(const RawProps &rawProps) { + ViewProps::apply(rawProps); + + // Paragraph Attributes + applyRawProp(rawProps, "numberOfLines", paragraphAttributes_.maximumNumberOfLines); + applyRawProp(rawProps, "ellipsizeMode", paragraphAttributes_.ellipsizeMode); + applyRawProp(rawProps, "adjustsFontSizeToFit", paragraphAttributes_.adjustsFontSizeToFit); + applyRawProp(rawProps, "minimumFontSize", paragraphAttributes_.minimumFontSize); + applyRawProp(rawProps, "maximumFontSize", paragraphAttributes_.maximumFontSize); + + // Other Props + applyRawProp(rawProps, "selectable", isSelectable_); +} + +#pragma mark - Getters + +ParagraphAttributes ParagraphProps::getParagraphAttributes() const { + return paragraphAttributes_; +} + +bool ParagraphProps::getIsSelectable() const { + return isSelectable_; +} + +#pragma mark - DebugStringConvertible + +SharedDebugStringConvertibleList ParagraphProps::getDebugProps() const { + SharedDebugStringConvertibleList list = {}; + + // Paragraph Props + auto &¶graphAttributePropsList = paragraphAttributes_.getDebugProps(); + std::move(paragraphAttributePropsList.begin(), paragraphAttributePropsList.end(), std::back_inserter(list)); + + // View Props + auto &&viewPropsList = ViewProps::getDebugProps(); + std::move(viewPropsList.begin(), viewPropsList.end(), std::back_inserter(list)); + + return list; +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/text/paragraph/ParagraphProps.h b/ReactCommon/fabric/text/paragraph/ParagraphProps.h new file mode 100644 index 00000000000000..42d630f04d0f98 --- /dev/null +++ b/ReactCommon/fabric/text/paragraph/ParagraphProps.h @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 ParagraphProps; + +using SharedParagraphProps = std::shared_ptr; + +/* + * Props of component. + * Most of the props are directly stored in composed `ParagraphAttributes` + * object. + */ +class ParagraphProps: + public ViewProps { + +public: + + void apply(const RawProps &rawProps) override; + +#pragma mark - Getters + + /* + * Returns `ParagraphAttributes` object which has all prop values that affect + * visual representation of the paragraph. + */ + ParagraphAttributes getParagraphAttributes() const; + + /* + * Defines can the text be selected (and copied) or not. + */ + bool getIsSelectable() const; + +#pragma mark - DebugStringConvertible + + SharedDebugStringConvertibleList getDebugProps() const override; + +private: + + ParagraphAttributes paragraphAttributes_ {}; + bool isSelectable_ {false}; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/text/paragraph/ParagraphShadowNode.cpp b/ReactCommon/fabric/text/paragraph/ParagraphShadowNode.cpp new file mode 100644 index 00000000000000..76e90f9b9bcaca --- /dev/null +++ b/ReactCommon/fabric/text/paragraph/ParagraphShadowNode.cpp @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "ParagraphShadowNode.h" + +#include + +#import "ParagraphLocalData.h" + +namespace facebook { +namespace react { + +ComponentName ParagraphShadowNode::getComponentName() const { + return ComponentName("Paragraph"); +} + +SharedTextShadowNode ParagraphShadowNode::getTextChildNode() const { + // component must always have a single child component. + assert(getChildren()->size() == 1); + auto childNode = getChildren()->front(); + assert(std::dynamic_pointer_cast(childNode)); + return std::static_pointer_cast(childNode); +} + +AttributedString ParagraphShadowNode::getAttributedString() const { + return getTextChildNode()->getAttributedString(TextAttributes()); +} + +void ParagraphShadowNode::setTextLayoutManager(SharedTextLayoutManager textLayoutManager) { + ensureUnsealed(); + textLayoutManager_ = textLayoutManager; +} + +void ParagraphShadowNode::updateLocalData() { + ensureUnsealed(); + + auto localData = std::make_shared(); + localData->setAttributedString(getAttributedString()); + localData->setTextLayoutManager(textLayoutManager_); + setLocalData(localData); +} + +#pragma mark - LayoutableShadowNode + +Size ParagraphShadowNode::measure(LayoutConstraints layoutConstraints) const { + return textLayoutManager_->measure( + getAttributedString(), + getProps()->getParagraphAttributes(), + layoutConstraints + ); +} + +void ParagraphShadowNode::layout(LayoutContext layoutContext) { + updateLocalData(); + ConcreteViewShadowNode::layout(layoutContext); +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/text/paragraph/ParagraphShadowNode.h b/ReactCommon/fabric/text/paragraph/ParagraphShadowNode.h new file mode 100644 index 00000000000000..2348d84655d023 --- /dev/null +++ b/ReactCommon/fabric/text/paragraph/ParagraphShadowNode.h @@ -0,0 +1,78 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 +#include +#include + +namespace facebook { +namespace react { + +class ParagraphShadowNode; + +using SharedParagraphShadowNode = std::shared_ptr; + +/* + * `ShadowNode` for component, represents -like component + * containing and displaying text. Text content is represented as nested + * and components. + * Note some Hierarchical constraints: + * * component must have only one component. + * * component might have nested , , and -like + * components. + * * component must not have any children. + */ +class ParagraphShadowNode: + public ConcreteViewShadowNode { + +public: + + using ConcreteViewShadowNode::ConcreteViewShadowNode; + + ComponentName getComponentName() const override; + + /* + * Returns a single nested shadow node. + */ + SharedTextShadowNode getTextChildNode() const; + + /* + * Returns a `AttributedString` which represents text content of the node. + */ + AttributedString getAttributedString() const; + + /* + * Associates a shared TextLayoutManager with the node. + * `ParagraphShadowNode` uses the manager to measure text content + * and construct `ParagraphLocalData` objects. + */ + void setTextLayoutManager(SharedTextLayoutManager textLayoutManager); + +#pragma mark - LayoutableShadowNode + + void layout(LayoutContext layoutContext) override; + Size measure(LayoutConstraints layoutConstraints) const override; + +private: + + /* + * Creates a `LocalData` object (with `AttributedText` and + * `TextLayoutManager`) if needed. + */ + void updateLocalData(); + + SharedTextLayoutManager textLayoutManager_; +}; + +} // namespace react +} // namespace facebook From 7e97ed00bc5c7cd6a5b8bbc711ddf0e0730ccb8a Mon Sep 17 00:00:00 2001 From: Riley Dulin Date: Tue, 8 May 2018 17:57:51 -0700 Subject: [PATCH 0460/1109] Fix prepack warning in RN bridge code Reviewed By: yungsters Differential Revision: D7903364 fbshipit-source-id: 4ef888f4e7f773f9fbc5183db2470b0f7b368d8a --- Libraries/Interaction/FrameRateLogger.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Libraries/Interaction/FrameRateLogger.js b/Libraries/Interaction/FrameRateLogger.js index 252fc465a3d487..1653b85915a217 100644 --- a/Libraries/Interaction/FrameRateLogger.js +++ b/Libraries/Interaction/FrameRateLogger.js @@ -40,7 +40,18 @@ const FrameRateLogger = { 'Trying to debug FrameRateLogger without the native module!', ); } - NativeModules.FrameRateLogger && NativeModules.FrameRateLogger.setGlobalOptions(options); + if (NativeModules.FrameRateLogger) { + // Freeze the object to avoid the prepack warning (PP0017) about leaking + // unfrozen objects. + // Needs to clone the object first to avoid modifying the argument. + const optionsClone = { + debug: !!options.debug, + reportStackTraces: !!options.reportStackTraces, + }; + Object.freeze(optionsClone); + Object.seal(optionsClone); + NativeModules.FrameRateLogger.setGlobalOptions(optionsClone); + } }, /** From 9646c5cb3c40ef29be4bdbf39775ccfaddd8e489 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 8 May 2018 18:50:05 -0700 Subject: [PATCH 0461/1109] Fabric: RCTViewComponentView, storing just applied `layoutMetrics` Summary: This will be useful for this class and for subclasses soon. For instance, when we draw something in `drawRect:`, we need to know exact content frame for rendering. Reviewed By: mdvacca Differential Revision: D7751855 fbshipit-source-id: 5d688368edd7b4f3c8c19d54ca701a9cc361270b --- React/Fabric/Mounting/RCTViewComponentView.h | 6 +++++- React/Fabric/Mounting/RCTViewComponentView.mm | 8 ++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/React/Fabric/Mounting/RCTViewComponentView.h b/React/Fabric/Mounting/RCTViewComponentView.h index 046030a8faa371..8dc5fc2e12dfe2 100644 --- a/React/Fabric/Mounting/RCTViewComponentView.h +++ b/React/Fabric/Mounting/RCTViewComponentView.h @@ -9,13 +9,17 @@ #import #import +#import NS_ASSUME_NONNULL_BEGIN /** * UIView class for component. */ -@interface RCTViewComponentView : UIView +@interface RCTViewComponentView : UIView { +@protected + facebook::react::LayoutMetrics _layoutMetrics; +} @end diff --git a/React/Fabric/Mounting/RCTViewComponentView.mm b/React/Fabric/Mounting/RCTViewComponentView.mm index 24a98594901266..cc3c0772bd75fb 100644 --- a/React/Fabric/Mounting/RCTViewComponentView.mm +++ b/React/Fabric/Mounting/RCTViewComponentView.mm @@ -30,4 +30,12 @@ - (void)updateProps:(facebook::react::SharedProps)props // TODO: Implement all sutable non-layout props. } +- (void)updateLayoutMetrics:(LayoutMetrics)layoutMetrics + oldLayoutMetrics:(LayoutMetrics)oldLayoutMetrics +{ + [super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics]; + + _layoutMetrics = layoutMetrics; +} + @end From 81bdd36204f246938dbe2ee108d280525e5b8476 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 8 May 2018 18:50:10 -0700 Subject: [PATCH 0462/1109] Fabric/Text: RCTParagraphComponentView Summary: RCTParagraphComponentView is a UIView which can render text using TextLayoutManager. Reviewed By: mdvacca Differential Revision: D7751853 fbshipit-source-id: e6ee9a0f989cdf6e878390d37dbcf8a11ef90bf4 --- .../Mounting/RCTParagraphComponentView.h | 21 +++++ .../Mounting/RCTParagraphComponentView.mm | 80 +++++++++++++++++++ .../fabric/core/layout/LayoutMetrics.h | 7 ++ 3 files changed, 108 insertions(+) create mode 100644 React/Fabric/Mounting/RCTParagraphComponentView.h create mode 100644 React/Fabric/Mounting/RCTParagraphComponentView.mm diff --git a/React/Fabric/Mounting/RCTParagraphComponentView.h b/React/Fabric/Mounting/RCTParagraphComponentView.h new file mode 100644 index 00000000000000..92700da77d642c --- /dev/null +++ b/React/Fabric/Mounting/RCTParagraphComponentView.h @@ -0,0 +1,21 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * UIView class for component. + */ +@interface RCTParagraphComponentView : RCTViewComponentView + +@end + +NS_ASSUME_NONNULL_END diff --git a/React/Fabric/Mounting/RCTParagraphComponentView.mm b/React/Fabric/Mounting/RCTParagraphComponentView.mm new file mode 100644 index 00000000000000..6709bd2b222392 --- /dev/null +++ b/React/Fabric/Mounting/RCTParagraphComponentView.mm @@ -0,0 +1,80 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTParagraphComponentView.h" + +#import +#import +#import +#import +#import +#import + +using namespace facebook::react; + +@implementation RCTParagraphComponentView { + SharedParagraphLocalData _paragraphLocalData; + ParagraphAttributes _paragraphAttributes; +} + +- (instancetype)initWithFrame:(CGRect)frame +{ + if (self = [super initWithFrame:frame]) { + self.isAccessibilityElement = YES; + self.accessibilityTraits |= UIAccessibilityTraitStaticText; + self.opaque = NO; + self.contentMode = UIViewContentModeRedraw; + } + + return self; +} + +- (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps +{ + [super updateProps:props oldProps:oldProps]; + auto paragraphProps = std::static_pointer_cast(props); + assert(paragraphProps); + _paragraphAttributes = paragraphProps->getParagraphAttributes(); +} + +- (void)updateLocalData:(SharedLocalData)localData + oldLocalData:(SharedLocalData)oldLocalData +{ + _paragraphLocalData = std::static_pointer_cast(localData); + assert(_paragraphLocalData); + [self setNeedsDisplay]; +} + +- (void)drawRect:(CGRect)rect +{ + if (!_paragraphLocalData) { + return; + } + + SharedTextLayoutManager textLayoutManager = + _paragraphLocalData->getTextLayoutManager(); + RCTTextLayoutManager *nativeTextLayoutManager = + (__bridge RCTTextLayoutManager *)textLayoutManager->getNativeTextLayoutManager(); + + auto contentFrame = _layoutMetrics.getContentFrame(); + CGRect frame = { + .origin = { + .x = contentFrame.origin.x, + .y = contentFrame.origin.y + }, + .size = { + .width = contentFrame.size.width, + .height = contentFrame.size.height + } + }; + + [nativeTextLayoutManager drawAttributedString:_paragraphLocalData->getAttributedString() + paragraphAttributes:_paragraphAttributes + frame:frame]; +} + +@end diff --git a/ReactCommon/fabric/core/layout/LayoutMetrics.h b/ReactCommon/fabric/core/layout/LayoutMetrics.h index 22cff2d7cc1e6f..e1c74359e8e7fc 100644 --- a/ReactCommon/fabric/core/layout/LayoutMetrics.h +++ b/ReactCommon/fabric/core/layout/LayoutMetrics.h @@ -23,6 +23,13 @@ struct LayoutMetrics { DisplayType displayType {DisplayType::Flex}; LayoutDirection layoutDirection {LayoutDirection::Undefined}; + Rect getContentFrame() const { + return Rect { + Point {contentInsets.left, contentInsets.top}, + Size {frame.size.width - contentInsets.left - contentInsets.right, frame.size.height - contentInsets.top - contentInsets.bottom} + }; + } + bool operator ==(const LayoutMetrics& rhs) const { return std::tie(this->frame, this->contentInsets, this->borderWidth, this->displayType, this->layoutDirection) == From f3893aab3b069ec3dba04bd1181231704bec899b Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 8 May 2018 18:50:15 -0700 Subject: [PATCH 0463/1109] Fabric/Text: Connecting the dots Summary: This change registers the Text module. Reviewed By: mdvacca Differential Revision: D7784509 fbshipit-source-id: 0de3e432b8f975927547ba990586f99655e8322d --- .../textlayoutmanager/RCTTextLayoutManager.mm | 1 - ReactCommon/fabric/uimanager/BUCK | 1 + .../fabric/uimanager/FabricUIManager.cpp | 21 +++++++++++++++++++ ReactCommon/fabric/uimanager/Scheduler.cpp | 10 +++++++-- 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/ReactCommon/fabric/textlayoutmanager/RCTTextLayoutManager.mm b/ReactCommon/fabric/textlayoutmanager/RCTTextLayoutManager.mm index f729c9c814c778..33a2fdb702d85f 100644 --- a/ReactCommon/fabric/textlayoutmanager/RCTTextLayoutManager.mm +++ b/ReactCommon/fabric/textlayoutmanager/RCTTextLayoutManager.mm @@ -63,7 +63,6 @@ - (void)drawAttributedString:(AttributedString)attributedString [layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:frame.origin]; } - - (NSTextStorage *)_textStorageAndLayoutManagerWithAttributesString:(NSAttributedString *)attributedString paragraphAttributes:(ParagraphAttributes)paragraphAttributes size:(CGSize)size diff --git a/ReactCommon/fabric/uimanager/BUCK b/ReactCommon/fabric/uimanager/BUCK index 4a3eeae2ba5fc0..39004b1e121db2 100644 --- a/ReactCommon/fabric/uimanager/BUCK +++ b/ReactCommon/fabric/uimanager/BUCK @@ -52,6 +52,7 @@ rn_xplat_cxx_library( "xplat//third-party/glog:glog", react_native_xplat_target("fabric/core:core"), react_native_xplat_target("fabric/debug:debug"), + react_native_xplat_target("fabric/text:text"), react_native_xplat_target("fabric/view:view"), ], ) diff --git a/ReactCommon/fabric/uimanager/FabricUIManager.cpp b/ReactCommon/fabric/uimanager/FabricUIManager.cpp index 3b8786b29889ec..b9a5cd57fcb7e4 100644 --- a/ReactCommon/fabric/uimanager/FabricUIManager.cpp +++ b/ReactCommon/fabric/uimanager/FabricUIManager.cpp @@ -39,12 +39,33 @@ static const RawProps rawPropsFromDynamic(const folly::dynamic object) { } static const std::string componentNameByReactViewName(std::string viewName) { + // We need this function only for the transition period; + // eventually, all names will be unified. + std::string rctPrefix("RCT"); if (std::mismatch(rctPrefix.begin(), rctPrefix.end(), viewName.begin()).first == rctPrefix.end()) { // If `viewName` has "RCT" prefix, remove it. viewName.erase(0, 3); } + // Fabric uses slightly new names for Text components because of differences + // in semantic. + if (viewName == "Text") { + return "Paragraph"; + } + if (viewName == "VirtualText") { + return "Text"; + } + + // We need this temporarly for testing purposes until we have proper + // implementation of component. + if ( + viewName == "ScrollContentView" || + viewName == "ScrollView" + ) { + return "View"; + } + return viewName; } diff --git a/ReactCommon/fabric/uimanager/Scheduler.cpp b/ReactCommon/fabric/uimanager/Scheduler.cpp index b2571ebf6168d5..8b5038c31f7c95 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.cpp +++ b/ReactCommon/fabric/uimanager/Scheduler.cpp @@ -5,6 +5,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -16,8 +19,11 @@ namespace react { Scheduler::Scheduler() { auto componentDescriptorRegistry = std::make_shared(); - SharedComponentDescriptor viewComponentDescriptor = std::make_shared(); - componentDescriptorRegistry->registerComponentDescriptor(viewComponentDescriptor); + + componentDescriptorRegistry->registerComponentDescriptor(std::make_shared()); + componentDescriptorRegistry->registerComponentDescriptor(std::make_shared()); + componentDescriptorRegistry->registerComponentDescriptor(std::make_shared()); + componentDescriptorRegistry->registerComponentDescriptor(std::make_shared()); uiManager_ = std::make_shared(componentDescriptorRegistry); uiManager_->setDelegate(this); From 9ea7957958c3f7acdaec6309117af61072986818 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 8 May 2018 18:50:19 -0700 Subject: [PATCH 0464/1109] Fabric: Do not crash in attempt to mount layout-only components Summary: We do not have a clear strategy how to deal with layout-only (view-less) components. Even if this particular solution is not so fancy, it prevents crashing during text rendering. Reviewed By: mdvacca Differential Revision: D7785885 fbshipit-source-id: f3ed8988aa2b41349fd1693c2a7f8c9368daee43 --- React/Fabric/Mounting/MountItems/RCTDeleteMountItem.mm | 5 +++++ React/Fabric/Mounting/MountItems/RCTInsertMountItem.mm | 4 ++++ React/Fabric/Mounting/MountItems/RCTRemoveMountItem.mm | 4 ++++ 3 files changed, 13 insertions(+) diff --git a/React/Fabric/Mounting/MountItems/RCTDeleteMountItem.mm b/React/Fabric/Mounting/MountItems/RCTDeleteMountItem.mm index 99909f450cc245..ed4a884e411c0d 100644 --- a/React/Fabric/Mounting/MountItems/RCTDeleteMountItem.mm +++ b/React/Fabric/Mounting/MountItems/RCTDeleteMountItem.mm @@ -28,6 +28,11 @@ - (instancetype)initWithComponentName:(NSString *)componentName - (void)executeWithRegistry:(RCTComponentViewRegistry *)registry { UIView *componentView = [registry componentViewByTag:_tag]; + + if (componentView == nil) { + return; + } + [registry enqueueComponentViewWithName:_componentName tag:_tag componentView:componentView]; } diff --git a/React/Fabric/Mounting/MountItems/RCTInsertMountItem.mm b/React/Fabric/Mounting/MountItems/RCTInsertMountItem.mm index f714cb0a70db71..740718b963d532 100644 --- a/React/Fabric/Mounting/MountItems/RCTInsertMountItem.mm +++ b/React/Fabric/Mounting/MountItems/RCTInsertMountItem.mm @@ -33,6 +33,10 @@ - (void)executeWithRegistry:(RCTComponentViewRegistry *)registry UIView *childComponentView = [registry componentViewByTag:_childTag]; UIView *parentComponentView = [registry componentViewByTag:_parentTag]; + if (childComponentView == nil || parentComponentView == nil) { + return; + } + [parentComponentView mountChildComponentView:childComponentView index:_index]; } diff --git a/React/Fabric/Mounting/MountItems/RCTRemoveMountItem.mm b/React/Fabric/Mounting/MountItems/RCTRemoveMountItem.mm index d46b936dd04474..3279b939438f62 100644 --- a/React/Fabric/Mounting/MountItems/RCTRemoveMountItem.mm +++ b/React/Fabric/Mounting/MountItems/RCTRemoveMountItem.mm @@ -33,6 +33,10 @@ - (void)executeWithRegistry:(RCTComponentViewRegistry *)registry UIView *childComponentView = [registry componentViewByTag:_childTag]; UIView *parentComponentView = [registry componentViewByTag:_parentTag]; + if (childComponentView == nil || parentComponentView == nil) { + return; + } + [parentComponentView unmountChildComponentView:childComponentView index:_index]; } From d9ff1769aaff704ae612b4e0532fc2737a91c4ff Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 8 May 2018 18:50:25 -0700 Subject: [PATCH 0465/1109] Fabric/Text: is now supporting text attributes Summary: I was shamed by Sebastian's sebmarkbage concerns (totally unrelated to this topic) about introducing another level of indirection into the system and decided to change my original plan not to support text attributes for the component. So, now shares , and itself capabilities. That reduces the minimum amount of required components for trivial text fragment from three (Paragraph, Text, RawText) to two (Paragraph and RawText). Special thanks for C++ for supporting multiple inheritance. Reviewed By: mdvacca Differential Revision: D7785889 fbshipit-source-id: dd9f2e2650bfbfd76d7d4b538adaf409f9429df3 --- ReactCommon/fabric/attributedstring/BUCK | 5 +- ReactCommon/fabric/core/BUCK | 5 +- ReactCommon/fabric/debug/BUCK | 10 ++- ReactCommon/fabric/graphics/BUCK | 14 +++- ReactCommon/fabric/text/BUCK | 1 + .../fabric/text/basetext/BaseTextProps.cpp | 73 +++++++++++++++++++ .../fabric/text/basetext/BaseTextProps.h | 48 ++++++++++++ .../text/basetext/BaseTextShadowNode.cpp | 59 +++++++++++++++ .../fabric/text/basetext/BaseTextShadowNode.h | 33 +++++++++ .../fabric/text/paragraph/ParagraphProps.cpp | 11 ++- .../fabric/text/paragraph/ParagraphProps.h | 4 +- .../text/paragraph/ParagraphShadowNode.cpp | 10 +-- .../text/paragraph/ParagraphShadowNode.h | 13 +--- ReactCommon/fabric/text/text/TextProps.cpp | 48 +----------- ReactCommon/fabric/text/text/TextProps.h | 16 +--- .../fabric/text/text/TextShadowNode.cpp | 39 ---------- ReactCommon/fabric/text/text/TextShadowNode.h | 9 +-- ReactCommon/fabric/textlayoutmanager/BUCK | 13 ++-- ReactCommon/fabric/view/BUCK | 4 +- 19 files changed, 268 insertions(+), 147 deletions(-) create mode 100644 ReactCommon/fabric/text/basetext/BaseTextProps.cpp create mode 100644 ReactCommon/fabric/text/basetext/BaseTextProps.h create mode 100644 ReactCommon/fabric/text/basetext/BaseTextShadowNode.cpp create mode 100644 ReactCommon/fabric/text/basetext/BaseTextShadowNode.h diff --git a/ReactCommon/fabric/attributedstring/BUCK b/ReactCommon/fabric/attributedstring/BUCK index 625639db36efd2..e6aa5bab556716 100644 --- a/ReactCommon/fabric/attributedstring/BUCK +++ b/ReactCommon/fabric/attributedstring/BUCK @@ -1,5 +1,5 @@ -load("//configurations/buck/apple:flag_defs.bzl", "get_debug_preprocessor_flags") -load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "get_apple_inspector_flags", "APPLE") +load("//configurations/buck/apple:flag_defs.bzl", "get_application_ios_flags", "get_debug_preprocessor_flags", "OBJC_ARC_PREPROCESSOR_FLAGS") +load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "rn_xplat_cxx_library", "get_apple_inspector_flags", "react_native_xplat_target", "ANDROID", "APPLE") APPLE_COMPILER_FLAGS = [] @@ -37,6 +37,7 @@ rn_xplat_cxx_library( ], force_static = True, macosx_tests_override = [], + platforms = (ANDROID, APPLE), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", diff --git a/ReactCommon/fabric/core/BUCK b/ReactCommon/fabric/core/BUCK index 981dd874f40045..4c732efc470eb7 100644 --- a/ReactCommon/fabric/core/BUCK +++ b/ReactCommon/fabric/core/BUCK @@ -1,5 +1,5 @@ -load("//configurations/buck/apple:flag_defs.bzl", "get_debug_preprocessor_flags") -load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "get_apple_inspector_flags", "APPLE") +load("//configurations/buck/apple:flag_defs.bzl", "get_application_ios_flags", "get_debug_preprocessor_flags", "OBJC_ARC_PREPROCESSOR_FLAGS") +load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "rn_xplat_cxx_library", "get_apple_inspector_flags", "react_native_xplat_target", "ANDROID", "APPLE") APPLE_COMPILER_FLAGS = [] @@ -40,6 +40,7 @@ rn_xplat_cxx_library( ], force_static = True, macosx_tests_override = [], + platforms = (ANDROID, APPLE), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", diff --git a/ReactCommon/fabric/debug/BUCK b/ReactCommon/fabric/debug/BUCK index 782b7452253f47..41fe3bcc5c77ec 100644 --- a/ReactCommon/fabric/debug/BUCK +++ b/ReactCommon/fabric/debug/BUCK @@ -1,11 +1,11 @@ -load("@xplat//configurations/buck/apple:flag_defs.bzl", "get_debug_preprocessor_flags") -load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "get_apple_inspector_flags", "APPLE") +load("//configurations/buck/apple:flag_defs.bzl", "get_application_ios_flags", "get_debug_preprocessor_flags", "OBJC_ARC_PREPROCESSOR_FLAGS") +load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "rn_xplat_cxx_library", "get_apple_inspector_flags", "react_native_xplat_target", "ANDROID", "APPLE") APPLE_COMPILER_FLAGS = [] if not IS_OSS_BUILD: load("@xplat//configurations/buck/apple:flag_defs.bzl", "get_static_library_ios_flags", "flags") - APPLE_COMPILER_FLAGS = flags.get_flag_value(get_static_library_ios_flags(), "compiler_flags") + APPLE_COMPILER_FLAGS = flags.get_flag_value(get_static_library_ios_flags(), 'compiler_flags') rn_xplat_cxx_library( name = "debug", @@ -37,6 +37,7 @@ rn_xplat_cxx_library( ], force_static = True, macosx_tests_override = [], + platforms = (ANDROID, APPLE), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", @@ -44,7 +45,10 @@ rn_xplat_cxx_library( tests = [], visibility = ["PUBLIC"], deps = [ + "xplat//fbsystrace:fbsystrace", "xplat//folly:headers_only", + "xplat//folly:memory", + "xplat//folly:molly", ], ) diff --git a/ReactCommon/fabric/graphics/BUCK b/ReactCommon/fabric/graphics/BUCK index 52a42e39208fa5..2cd6abacfdf0d9 100644 --- a/ReactCommon/fabric/graphics/BUCK +++ b/ReactCommon/fabric/graphics/BUCK @@ -1,5 +1,5 @@ -load("//configurations/buck/apple:flag_defs.bzl", "get_debug_preprocessor_flags") -load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "get_apple_inspector_flags", "APPLE") +load("//configurations/buck/apple:flag_defs.bzl", "get_application_ios_flags", "get_debug_preprocessor_flags", "OBJC_ARC_PREPROCESSOR_FLAGS") +load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "rn_xplat_cxx_library", "get_apple_inspector_flags", "react_native_xplat_target", "ANDROID", "APPLE") APPLE_COMPILER_FLAGS = [] @@ -25,10 +25,10 @@ rn_xplat_cxx_library( prefix = "fabric/graphics", ), compiler_flags = [ - "-std=c++14", - "-Wall", "-fexceptions", "-frtti", + "-std=c++14", + "-Wall", ], fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), @@ -36,7 +36,13 @@ rn_xplat_cxx_library( ":tests", ], force_static = True, + frameworks = [ + "$SDKROOT/System/Library/Frameworks/CoreGraphics.framework", + "$SDKROOT/System/Library/Frameworks/Foundation.framework", + "$SDKROOT/System/Library/Frameworks/UIKit.framework", + ], macosx_tests_override = [], + platforms = (ANDROID, APPLE), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", diff --git a/ReactCommon/fabric/text/BUCK b/ReactCommon/fabric/text/BUCK index 04fbad8d174971..9ee6fca05f03f9 100644 --- a/ReactCommon/fabric/text/BUCK +++ b/ReactCommon/fabric/text/BUCK @@ -21,6 +21,7 @@ rn_xplat_cxx_library( exported_headers = subdir_glob( [ ("", "*.h"), + ("basetext", "*.h"), ("paragraph", "*.h"), ("text", "*.h"), ("rawtext", "*.h"), diff --git a/ReactCommon/fabric/text/basetext/BaseTextProps.cpp b/ReactCommon/fabric/text/basetext/BaseTextProps.cpp new file mode 100644 index 00000000000000..4b3e1a80e5ff00 --- /dev/null +++ b/ReactCommon/fabric/text/basetext/BaseTextProps.cpp @@ -0,0 +1,73 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "BaseTextProps.h" + +#include +#include +#include +#include +#include + +namespace facebook { +namespace react { + +void BaseTextProps::apply(const RawProps &rawProps) { + // Color + applyRawProp(rawProps, "color", textAttributes_.foregroundColor); + applyRawProp(rawProps, "backgroundColor", textAttributes_.backgroundColor); + applyRawProp(rawProps, "opacity", textAttributes_.opacity); + + // Font + applyRawProp(rawProps, "fontFamily", textAttributes_.fontFamily); + applyRawProp(rawProps, "fontSize", textAttributes_.fontSize); + applyRawProp(rawProps, "fontSizeMultiplier", textAttributes_.fontSizeMultiplier); + applyRawProp(rawProps, "fontWeight", textAttributes_.fontWeight); + applyRawProp(rawProps, "fontStyle", textAttributes_.fontStyle); + applyRawProp(rawProps, "fontVariant", textAttributes_.fontVariant); + applyRawProp(rawProps, "allowFontScaling", textAttributes_.allowFontScaling); + applyRawProp(rawProps, "letterSpacing", textAttributes_.letterSpacing); + + // Paragraph + applyRawProp(rawProps, "lineHeight", textAttributes_.lineHeight); + applyRawProp(rawProps, "alignment", textAttributes_.alignment); + applyRawProp(rawProps, "baseWritingDirection", textAttributes_.baseWritingDirection); + + // Decoration + applyRawProp(rawProps, "textDecorationColor", textAttributes_.textDecorationColor); + applyRawProp(rawProps, "textDecorationLineType", textAttributes_.textDecorationLineType); + applyRawProp(rawProps, "textDecorationLineStyle", textAttributes_.textDecorationLineStyle); + applyRawProp(rawProps, "textDecorationLinePattern", textAttributes_.textDecorationLinePattern); + + // Shadow + applyRawProp(rawProps, "textShadowOffset", textAttributes_.textShadowOffset); + applyRawProp(rawProps, "textShadowRadius", textAttributes_.textShadowRadius); + applyRawProp(rawProps, "textShadowColor", textAttributes_.textShadowColor); + + // Special + applyRawProp(rawProps, "isHighlighted", textAttributes_.isHighlighted); +} + +#pragma mark - Getters + +TextAttributes BaseTextProps::getTextAttributes() const { + return textAttributes_; +} + +#pragma mark - DebugStringConvertible + +SharedDebugStringConvertibleList BaseTextProps::getDebugProps() const { + SharedDebugStringConvertibleList list = {}; + + auto textAttributesPropsList = textAttributes_.getDebugProps(); + std::move(textAttributesPropsList.begin(), textAttributesPropsList.end(), std::back_inserter(list)); + + return list; +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/text/basetext/BaseTextProps.h b/ReactCommon/fabric/text/basetext/BaseTextProps.h new file mode 100644 index 00000000000000..9d3909a3b354b8 --- /dev/null +++ b/ReactCommon/fabric/text/basetext/BaseTextProps.h @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 { + +/* + * `Props`-like class which is used as a base class for all Props classes + * that can have text attributes (such as Text and Paragraph). + */ +class BaseTextProps { +public: + + /* + * Same semantic as `Props::apply(...)`. + */ + void apply(const RawProps &rawProps); + +#pragma mark - Getters + + /* + * Returns all props values as `TextAttributes` object. + */ + TextAttributes getTextAttributes() const; + +#pragma mark - DebugStringConvertible (partially) + + SharedDebugStringConvertibleList getDebugProps() const; + +private: + + TextAttributes textAttributes_; +}; + +} // namespace react +} // namespace facebook + diff --git a/ReactCommon/fabric/text/basetext/BaseTextShadowNode.cpp b/ReactCommon/fabric/text/basetext/BaseTextShadowNode.cpp new file mode 100644 index 00000000000000..f37f534b880d49 --- /dev/null +++ b/ReactCommon/fabric/text/basetext/BaseTextShadowNode.cpp @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "BaseTextShadowNode.h" + +#include + +#include "RawTextShadowNode.h" +#include "RawTextProps.h" +#include "TextShadowNode.h" +#include "TextProps.h" + +namespace facebook { +namespace react { + +AttributedString BaseTextShadowNode::getAttributedString( + const TextAttributes &textAttributes, + const SharedShadowNodeSharedList &childNodes +) const { + // TODO: Implement caching. + + AttributedString attributedString; + + for (auto &&childNode : *childNodes) { + // RawShadowNode + SharedRawTextShadowNode rawTextShadowNode = std::dynamic_pointer_cast(childNode); + if (rawTextShadowNode) { + AttributedString::Fragment fragment; + fragment.string = rawTextShadowNode->getProps()->getText(); + fragment.textAttributes = textAttributes; + attributedString.appendFragment(fragment); + continue; + } + + // TextShadowNode + SharedTextShadowNode textShadowNode = std::dynamic_pointer_cast(childNode); + if (textShadowNode) { + TextAttributes localTextAttributes = textAttributes; + localTextAttributes.apply(textShadowNode->getProps()->getTextAttributes()); + attributedString.appendAttributedString(textShadowNode->getAttributedString(localTextAttributes, textShadowNode->getChildren())); + continue; + } + + // Any other kind of ShadowNode + AttributedString::Fragment fragment; + fragment.shadowNode = childNode; + fragment.textAttributes = textAttributes; + attributedString.appendFragment(fragment); + } + + return attributedString; +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/text/basetext/BaseTextShadowNode.h b/ReactCommon/fabric/text/basetext/BaseTextShadowNode.h new file mode 100644 index 00000000000000..9d52b9c5ebe921 --- /dev/null +++ b/ReactCommon/fabric/text/basetext/BaseTextShadowNode.h @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 { + +/* + * Base class (one of) for shadow nodes that represents attributed text, + * such as Text and Paragraph (but not RawText). + */ +class BaseTextShadowNode { +public: + + /* + * Returns a `AttributedString` which represents text content of the node. + */ + AttributedString getAttributedString( + const TextAttributes &baseTextAttributes, + const SharedShadowNodeSharedList &childNodes + ) const; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/text/paragraph/ParagraphProps.cpp b/ReactCommon/fabric/text/paragraph/ParagraphProps.cpp index 89faa944565a04..95be162bb5a78d 100644 --- a/ReactCommon/fabric/text/paragraph/ParagraphProps.cpp +++ b/ReactCommon/fabric/text/paragraph/ParagraphProps.cpp @@ -17,6 +17,7 @@ namespace react { void ParagraphProps::apply(const RawProps &rawProps) { ViewProps::apply(rawProps); + BaseTextProps::apply(rawProps); // Paragraph Attributes applyRawProp(rawProps, "numberOfLines", paragraphAttributes_.maximumNumberOfLines); @@ -44,13 +45,17 @@ bool ParagraphProps::getIsSelectable() const { SharedDebugStringConvertibleList ParagraphProps::getDebugProps() const { SharedDebugStringConvertibleList list = {}; + // View Props + auto &&viewPropsList = ViewProps::getDebugProps(); + std::move(viewPropsList.begin(), viewPropsList.end(), std::back_inserter(list)); + // Paragraph Props auto &¶graphAttributePropsList = paragraphAttributes_.getDebugProps(); std::move(paragraphAttributePropsList.begin(), paragraphAttributePropsList.end(), std::back_inserter(list)); - // View Props - auto &&viewPropsList = ViewProps::getDebugProps(); - std::move(viewPropsList.begin(), viewPropsList.end(), std::back_inserter(list)); + // Base Text Props + auto &&baseTextPropsList = BaseTextProps::getDebugProps(); + std::move(baseTextPropsList.begin(), baseTextPropsList.end(), std::back_inserter(list)); return list; } diff --git a/ReactCommon/fabric/text/paragraph/ParagraphProps.h b/ReactCommon/fabric/text/paragraph/ParagraphProps.h index 42d630f04d0f98..4918f47b978727 100644 --- a/ReactCommon/fabric/text/paragraph/ParagraphProps.h +++ b/ReactCommon/fabric/text/paragraph/ParagraphProps.h @@ -12,6 +12,7 @@ #include #include +#include #include namespace facebook { @@ -27,7 +28,8 @@ using SharedParagraphProps = std::shared_ptr; * object. */ class ParagraphProps: - public ViewProps { + public ViewProps, + public BaseTextProps { public: diff --git a/ReactCommon/fabric/text/paragraph/ParagraphShadowNode.cpp b/ReactCommon/fabric/text/paragraph/ParagraphShadowNode.cpp index 76e90f9b9bcaca..57d13d7ed66f2c 100644 --- a/ReactCommon/fabric/text/paragraph/ParagraphShadowNode.cpp +++ b/ReactCommon/fabric/text/paragraph/ParagraphShadowNode.cpp @@ -17,17 +17,9 @@ namespace react { ComponentName ParagraphShadowNode::getComponentName() const { return ComponentName("Paragraph"); } - -SharedTextShadowNode ParagraphShadowNode::getTextChildNode() const { - // component must always have a single child component. - assert(getChildren()->size() == 1); - auto childNode = getChildren()->front(); - assert(std::dynamic_pointer_cast(childNode)); - return std::static_pointer_cast(childNode); -} AttributedString ParagraphShadowNode::getAttributedString() const { - return getTextChildNode()->getAttributedString(TextAttributes()); + return BaseTextShadowNode::getAttributedString(getProps()->getTextAttributes(), getChildren()); } void ParagraphShadowNode::setTextLayoutManager(SharedTextLayoutManager textLayoutManager) { diff --git a/ReactCommon/fabric/text/paragraph/ParagraphShadowNode.h b/ReactCommon/fabric/text/paragraph/ParagraphShadowNode.h index 2348d84655d023..df16aee1b797bd 100644 --- a/ReactCommon/fabric/text/paragraph/ParagraphShadowNode.h +++ b/ReactCommon/fabric/text/paragraph/ParagraphShadowNode.h @@ -26,14 +26,10 @@ using SharedParagraphShadowNode = std::shared_ptr; * `ShadowNode` for component, represents -like component * containing and displaying text. Text content is represented as nested * and components. - * Note some Hierarchical constraints: - * * component must have only one component. - * * component might have nested , , and -like - * components. - * * component must not have any children. */ class ParagraphShadowNode: - public ConcreteViewShadowNode { + public ConcreteViewShadowNode, + public BaseTextShadowNode { public: @@ -41,11 +37,6 @@ class ParagraphShadowNode: ComponentName getComponentName() const override; - /* - * Returns a single nested shadow node. - */ - SharedTextShadowNode getTextChildNode() const; - /* * Returns a `AttributedString` which represents text content of the node. */ diff --git a/ReactCommon/fabric/text/text/TextProps.cpp b/ReactCommon/fabric/text/text/TextProps.cpp index 402d2ea67129ca..c752a5f0ec01e0 100644 --- a/ReactCommon/fabric/text/text/TextProps.cpp +++ b/ReactCommon/fabric/text/text/TextProps.cpp @@ -18,57 +18,13 @@ namespace react { void TextProps::apply(const RawProps &rawProps) { Props::apply(rawProps); - - // Color - applyRawProp(rawProps, "color", textAttributes_.foregroundColor); - applyRawProp(rawProps, "backgroundColor", textAttributes_.backgroundColor); - applyRawProp(rawProps, "opacity", textAttributes_.opacity); - - // Font - applyRawProp(rawProps, "fontFamily", textAttributes_.fontFamily); - applyRawProp(rawProps, "fontSize", textAttributes_.fontSize); - applyRawProp(rawProps, "fontSizeMultiplier", textAttributes_.fontSizeMultiplier); - applyRawProp(rawProps, "fontWeight", textAttributes_.fontWeight); - applyRawProp(rawProps, "fontStyle", textAttributes_.fontStyle); - applyRawProp(rawProps, "fontVariant", textAttributes_.fontVariant); - applyRawProp(rawProps, "allowFontScaling", textAttributes_.allowFontScaling); - applyRawProp(rawProps, "letterSpacing", textAttributes_.letterSpacing); - - // Paragraph - applyRawProp(rawProps, "lineHeight", textAttributes_.lineHeight); - applyRawProp(rawProps, "alignment", textAttributes_.alignment); - applyRawProp(rawProps, "baseWritingDirection", textAttributes_.baseWritingDirection); - - // Decoration - applyRawProp(rawProps, "textDecorationColor", textAttributes_.textDecorationColor); - applyRawProp(rawProps, "textDecorationLineType", textAttributes_.textDecorationLineType); - applyRawProp(rawProps, "textDecorationLineStyle", textAttributes_.textDecorationLineStyle); - applyRawProp(rawProps, "textDecorationLinePattern", textAttributes_.textDecorationLinePattern); - - // Shadow - applyRawProp(rawProps, "textShadowOffset", textAttributes_.textShadowOffset); - applyRawProp(rawProps, "textShadowRadius", textAttributes_.textShadowRadius); - applyRawProp(rawProps, "textShadowColor", textAttributes_.textShadowColor); - - // Special - applyRawProp(rawProps, "isHighlighted", textAttributes_.isHighlighted); -} - -#pragma mark - Getters - -TextAttributes TextProps::getTextAttributes() const { - return textAttributes_; + BaseTextProps::apply(rawProps); } #pragma mark - DebugStringConvertible SharedDebugStringConvertibleList TextProps::getDebugProps() const { - SharedDebugStringConvertibleList list = {}; - - auto textAttributesPropsList = textAttributes_.getDebugProps(); - std::move(textAttributesPropsList.begin(), textAttributesPropsList.end(), std::back_inserter(list)); - - return list; + return BaseTextProps::getDebugProps(); } } // namespace react diff --git a/ReactCommon/fabric/text/text/TextProps.h b/ReactCommon/fabric/text/text/TextProps.h index 1a96b5519fb8b1..8762642bb02e95 100644 --- a/ReactCommon/fabric/text/text/TextProps.h +++ b/ReactCommon/fabric/text/text/TextProps.h @@ -11,6 +11,7 @@ #include #include #include +#include namespace facebook { namespace react { @@ -20,22 +21,12 @@ class TextProps; using SharedTextProps = std::shared_ptr; class TextProps: - public Props { + public Props, + public BaseTextProps { public: void apply(const RawProps &rawProps) override; -#pragma mark - Getters - - TextAttributes getTextAttributes() const; - -private: - - /* - * Not all `TextAttributes` fields make sense and is used as TextProps values. - */ - TextAttributes textAttributes_; - #pragma mark - DebugStringConvertible SharedDebugStringConvertibleList getDebugProps() const override; @@ -43,4 +34,3 @@ class TextProps: } // namespace react } // namespace facebook - diff --git a/ReactCommon/fabric/text/text/TextShadowNode.cpp b/ReactCommon/fabric/text/text/TextShadowNode.cpp index 5429c7ba606382..c49c8bfd243c18 100644 --- a/ReactCommon/fabric/text/text/TextShadowNode.cpp +++ b/ReactCommon/fabric/text/text/TextShadowNode.cpp @@ -9,9 +9,6 @@ #include -#include "RawTextShadowNode.h" -#include "RawTextProps.h" - namespace facebook { namespace react { @@ -19,41 +16,5 @@ ComponentName TextShadowNode::getComponentName() const { return ComponentName("Text"); } -AttributedString TextShadowNode::getAttributedString(const TextAttributes &baseTextAttributes) const { - // TODO: Implement caching. - - TextAttributes textAttributes = baseTextAttributes; - textAttributes.apply(getProps()->getTextAttributes()); - - AttributedString attributedString; - - for (auto &&childNode : *getChildren()) { - // RawShadowNode - SharedRawTextShadowNode rawTextShadowNode = std::dynamic_pointer_cast(childNode); - if (rawTextShadowNode) { - AttributedString::Fragment fragment; - fragment.string = rawTextShadowNode->getProps()->getText(); - fragment.textAttributes = textAttributes; - attributedString.appendFragment(fragment); - continue; - } - - // TextShadowNode - SharedTextShadowNode textShadowNode = std::dynamic_pointer_cast(childNode); - if (textShadowNode) { - attributedString.appendAttributedString(textShadowNode->getAttributedString(textAttributes)); - continue; - } - - // Any other kind of ShadowNode - AttributedString::Fragment fragment; - fragment.shadowNode = childNode; - fragment.textAttributes = textAttributes; - attributedString.appendFragment(fragment); - } - - return attributedString; -} - } // namespace react } // namespace facebook diff --git a/ReactCommon/fabric/text/text/TextShadowNode.h b/ReactCommon/fabric/text/text/TextShadowNode.h index 0eb421a96630a8..12c73e1a17e30c 100644 --- a/ReactCommon/fabric/text/text/TextShadowNode.h +++ b/ReactCommon/fabric/text/text/TextShadowNode.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -22,18 +23,14 @@ class TextShadowNode; using SharedTextShadowNode = std::shared_ptr; class TextShadowNode: - public ConcreteShadowNode { + public ConcreteShadowNode, + public BaseTextShadowNode { public: using ConcreteShadowNode::ConcreteShadowNode; ComponentName getComponentName() const override; - - /* - * Returns a `AttributedString` which represents text content of the node. - */ - AttributedString getAttributedString(const TextAttributes &baseTextAttributes) const; }; } // namespace react diff --git a/ReactCommon/fabric/textlayoutmanager/BUCK b/ReactCommon/fabric/textlayoutmanager/BUCK index c7bb2f92ec06d9..be8ed19c2885e7 100644 --- a/ReactCommon/fabric/textlayoutmanager/BUCK +++ b/ReactCommon/fabric/textlayoutmanager/BUCK @@ -1,5 +1,5 @@ -load("//configurations/buck/apple:flag_defs.bzl", "get_debug_preprocessor_flags", "get_fbobjc_enable_exception_lang_compiler_flags") -load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "get_apple_inspector_flags", "APPLE") +load("//configurations/buck/apple:flag_defs.bzl", "get_application_ios_flags", "get_debug_preprocessor_flags", "OBJC_ARC_PREPROCESSOR_FLAGS") +load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "rn_xplat_cxx_library", "get_apple_inspector_flags", "react_native_xplat_target", "ANDROID", "APPLE") APPLE_COMPILER_FLAGS = [] @@ -39,14 +39,14 @@ rn_xplat_cxx_library( ":tests", ], force_static = True, - macosx_tests_override = [], frameworks = [ + "$SDKROOT/System/Library/Frameworks/CoreGraphics.framework", "$SDKROOT/System/Library/Frameworks/Foundation.framework", - "$SDKROOT/System/Library/Frameworks/QuartzCore.framework", "$SDKROOT/System/Library/Frameworks/UIKit.framework", ], - lang_compiler_flags = get_fbobjc_enable_exception_lang_compiler_flags(), - preprocessor_flags = get_debug_preprocessor_flags() + [ + macosx_tests_override = [], + platforms = (ANDROID, APPLE), + preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", ], @@ -58,6 +58,7 @@ rn_xplat_cxx_library( "xplat//folly:memory", "xplat//folly:molly", "xplat//third-party/glog:glog", + "xplat//yoga:yoga", react_native_xplat_target("fabric/attributedstring:attributedstring"), react_native_xplat_target("fabric/core:core"), react_native_xplat_target("fabric/debug:debug"), diff --git a/ReactCommon/fabric/view/BUCK b/ReactCommon/fabric/view/BUCK index 20b7108c25c753..221ea2c1055537 100644 --- a/ReactCommon/fabric/view/BUCK +++ b/ReactCommon/fabric/view/BUCK @@ -53,15 +53,15 @@ rn_xplat_cxx_library( "xplat//folly:molly", "xplat//third-party/glog:glog", "xplat//yoga:yoga", - react_native_xplat_target("fabric/debug:debug"), react_native_xplat_target("fabric/core:core"), + react_native_xplat_target("fabric/debug:debug"), react_native_xplat_target("fabric/graphics:graphics"), ], ) if not IS_OSS_BUILD: load("@xplat//build_defs:fb_xplat_cxx_test.bzl", "fb_xplat_cxx_test") - + fb_xplat_cxx_test( name = "tests", srcs = glob(["tests/**/*.cpp"]), From 6e537b000bb4778759879dc922acf6bcb28c28df Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 8 May 2018 22:56:02 -0700 Subject: [PATCH 0466/1109] Fabric: New nice way to deal with DebugStringConvertible items Summary: No macros in product code. (Not all callsites are converted yet.) Reviewed By: mdvacca Differential Revision: D7797561 fbshipit-source-id: da899421bf99669a0e0a2b83df6004daf14355c2 --- .../attributedstring/ParagraphAttributes.cpp | 24 +++----- .../attributedstring/TextAttributes.cpp | 57 ++++++++++++------- .../debugStringConvertibleUtils.h | 21 +++++++ .../attributedstring/textValuesConversions.h | 12 ++++ .../fabric/debug/DebugStringConvertible.cpp | 8 +++ .../debug/debugStringConvertibleUtils.cpp | 25 ++++++++ .../debug/debugStringConvertibleUtils.h | 53 +++++++++++++++++ .../graphics/debugStringConvertibleUtils.h | 22 +++++++ .../fabric/text/basetext/BaseTextProps.cpp | 7 +-- .../text/paragraph/ParagraphLocalData.cpp | 8 +-- .../fabric/text/paragraph/ParagraphProps.cpp | 21 ++----- 11 files changed, 198 insertions(+), 60 deletions(-) create mode 100644 ReactCommon/fabric/attributedstring/debugStringConvertibleUtils.h create mode 100644 ReactCommon/fabric/debug/debugStringConvertibleUtils.cpp create mode 100644 ReactCommon/fabric/debug/debugStringConvertibleUtils.h create mode 100644 ReactCommon/fabric/graphics/debugStringConvertibleUtils.h diff --git a/ReactCommon/fabric/attributedstring/ParagraphAttributes.cpp b/ReactCommon/fabric/attributedstring/ParagraphAttributes.cpp index 3901c18cf38bd3..43d895e7608c54 100644 --- a/ReactCommon/fabric/attributedstring/ParagraphAttributes.cpp +++ b/ReactCommon/fabric/attributedstring/ParagraphAttributes.cpp @@ -10,27 +10,21 @@ #include #include +#include "debugStringConvertibleUtils.h" + namespace facebook { namespace react { #pragma mark - DebugStringConvertible SharedDebugStringConvertibleList ParagraphAttributes::getDebugProps() const { - ParagraphAttributes defaultParagraphAttributes = {}; - SharedDebugStringConvertibleList list = {}; - -#define PARAGRAPH_ATTRIBUTE(stringName, propertyName, accessor, convertor) \ - if (propertyName != defaultParagraphAttributes.propertyName) { \ - list.push_back(std::make_shared(#stringName, convertor(propertyName accessor))); \ - } - - PARAGRAPH_ATTRIBUTE(maximumNumberOfLines, maximumNumberOfLines, , std::to_string) - PARAGRAPH_ATTRIBUTE(ellipsizeMode, ellipsizeMode, , stringFromEllipsizeMode) - PARAGRAPH_ATTRIBUTE(adjustsFontSizeToFit, adjustsFontSizeToFit, , std::to_string) - PARAGRAPH_ATTRIBUTE(minimumFontSize, minimumFontSize, , std::to_string) - PARAGRAPH_ATTRIBUTE(maximumFontSize, maximumFontSize, , std::to_string) - - return list; + return { + debugStringConvertibleItem("maximumNumberOfLines", maximumNumberOfLines), + debugStringConvertibleItem("ellipsizeMode", ellipsizeMode), + debugStringConvertibleItem("adjustsFontSizeToFit", adjustsFontSizeToFit), + debugStringConvertibleItem("minimumFontSize", minimumFontSize), + debugStringConvertibleItem("maximumFontSize", maximumFontSize) + }; } } // namespace react diff --git a/ReactCommon/fabric/attributedstring/TextAttributes.cpp b/ReactCommon/fabric/attributedstring/TextAttributes.cpp index 984aba5d377f20..4f85297dc71313 100644 --- a/ReactCommon/fabric/attributedstring/TextAttributes.cpp +++ b/ReactCommon/fabric/attributedstring/TextAttributes.cpp @@ -7,8 +7,9 @@ #include "TextAttributes.h" -#include +#include #include +#include "debugStringConvertibleUtils.h" namespace facebook { namespace react { @@ -53,26 +54,44 @@ void TextAttributes::apply(TextAttributes textAttributes) { #pragma mark - DebugStringConvertible SharedDebugStringConvertibleList TextAttributes::getDebugProps() const { - TextAttributes defaultAttributes = {}; - - SharedDebugStringConvertibleList list = {}; - -#define PROPS_ADD_TO_SET(propertyName, accessor, convertor) \ - if (propertyName != defaultAttributes.propertyName) { \ - list.push_back(std::make_shared(#propertyName, convertor(propertyName accessor))); \ - } - - PROPS_ADD_TO_SET(backgroundColor, , colorNameFromColor) - PROPS_ADD_TO_SET(foregroundColor, , colorNameFromColor) - PROPS_ADD_TO_SET(opacity, , std::to_string) - - PROPS_ADD_TO_SET(fontFamily, , ) - PROPS_ADD_TO_SET(fontSize, , std::to_string) - PROPS_ADD_TO_SET(fontSizeMultiplier, , std::to_string) - // TODO: Implement all fields. - return list; + return { + // Color + debugStringConvertibleItem("backgroundColor", backgroundColor), + debugStringConvertibleItem("foregroundColor", foregroundColor), + debugStringConvertibleItem("opacity", opacity), + + // Font + debugStringConvertibleItem("fontFamily", fontFamily), + debugStringConvertibleItem("fontSize", fontSize), + debugStringConvertibleItem("fontSizeMultiplier", fontSizeMultiplier), + debugStringConvertibleItem("fontWeight", fontWeight), + debugStringConvertibleItem("fontStyle", fontStyle), + //debugStringConvertibleItem("fontVariant", fontVariant), + debugStringConvertibleItem("allowFontScaling", allowFontScaling), + debugStringConvertibleItem("letterSpacing", letterSpacing), + + // Paragraph Styles + debugStringConvertibleItem("lineHeight", lineHeight), + //debugStringConvertibleItem("alignment", alignment), + //debugStringConvertibleItem("baseWritingDirection", baseWritingDirection), + + // Decoration + debugStringConvertibleItem("textDecorationColor", textDecorationColor), + //debugStringConvertibleItem("textDecorationLineType", textDecorationLineType), + //debugStringConvertibleItem("textDecorationLineStyle", textDecorationLineStyle), + //debugStringConvertibleItem("textDecorationLinePattern", textDecorationLinePattern), + + // Shadow + debugStringConvertibleItem("textShadowOffset", textShadowOffset), + debugStringConvertibleItem("textShadowRadius", textShadowRadius), + debugStringConvertibleItem("textShadowColor", textShadowColor), + + // Special + debugStringConvertibleItem("isHighlighted", isHighlighted), + //debugStringConvertibleItem("layoutDirection", layoutDirection), + }; } } // namespace react diff --git a/ReactCommon/fabric/attributedstring/debugStringConvertibleUtils.h b/ReactCommon/fabric/attributedstring/debugStringConvertibleUtils.h new file mode 100644 index 00000000000000..617efb4c19cdf8 --- /dev/null +++ b/ReactCommon/fabric/attributedstring/debugStringConvertibleUtils.h @@ -0,0 +1,21 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 { + +DEBUG_STRING_CONVERTIBLE_TEMPLATE(EllipsizeMode, stringFromEllipsizeMode) +DEBUG_STRING_CONVERTIBLE_TEMPLATE(FontWeight, stringFromFontWeight) +DEBUG_STRING_CONVERTIBLE_TEMPLATE(FontStyle, stringFromFontStyle) + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/attributedstring/textValuesConversions.h b/ReactCommon/fabric/attributedstring/textValuesConversions.h index 88480b6ff2e578..deb5660e2f7681 100644 --- a/ReactCommon/fabric/attributedstring/textValuesConversions.h +++ b/ReactCommon/fabric/attributedstring/textValuesConversions.h @@ -49,6 +49,10 @@ inline FontWeight fontWeightFromDynamic(const folly::dynamic &value) { abort(); } +inline std::string stringFromFontWeight(const FontWeight &fontWeight) { + return std::to_string((int)fontWeight); +} + inline FontStyle fontStyleFromDynamic(const folly::dynamic &value) { auto string = value.asString(); if (string == "normal") { return FontStyle::Normal; } @@ -57,6 +61,14 @@ inline FontStyle fontStyleFromDynamic(const folly::dynamic &value) { abort(); } +inline std::string stringFromFontStyle(const FontStyle &fontStyle) { + switch (fontStyle) { + case FontStyle::Normal: return "normal"; + case FontStyle::Italic: return "italic"; + case FontStyle::Oblique: return "oblique"; + } +} + inline FontVariant fontVariantFromDynamic(const folly::dynamic &value) { assert(value.isArray()); FontVariant fontVariant = FontVariant::Default; diff --git a/ReactCommon/fabric/debug/DebugStringConvertible.cpp b/ReactCommon/fabric/debug/DebugStringConvertible.cpp index ce2c91611af9c4..08d885d9674687 100644 --- a/ReactCommon/fabric/debug/DebugStringConvertible.cpp +++ b/ReactCommon/fabric/debug/DebugStringConvertible.cpp @@ -18,6 +18,10 @@ std::string DebugStringConvertible::getDebugChildrenDescription(DebugStringConve std::string childrenString = ""; for (auto child : getDebugChildren()) { + if (!child) { + continue; + } + childrenString += child->getDebugDescription(options, depth + 1); } @@ -32,6 +36,10 @@ std::string DebugStringConvertible::getDebugPropsDescription(DebugStringConverti std::string propsString = ""; for (auto prop : getDebugProps()) { + if (!prop) { + continue; + } + auto name = prop->getDebugName(); auto value = prop->getDebugValue(); auto children = prop->getDebugPropsDescription(options, depth + 1); diff --git a/ReactCommon/fabric/debug/debugStringConvertibleUtils.cpp b/ReactCommon/fabric/debug/debugStringConvertibleUtils.cpp new file mode 100644 index 00000000000000..de9817d4999f44 --- /dev/null +++ b/ReactCommon/fabric/debug/debugStringConvertibleUtils.cpp @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "debugStringConvertibleUtils.h" + +namespace facebook { +namespace react { + +SharedDebugStringConvertibleList operator+(const SharedDebugStringConvertibleList &lhs, const SharedDebugStringConvertibleList &rhs) { + SharedDebugStringConvertibleList result = {}; + std::move(lhs.begin(), lhs.end(), std::back_inserter(result)); + std::move(rhs.begin(), rhs.end(), std::back_inserter(result)); + return result; +} + +SharedDebugStringConvertible debugStringConvertibleItem(std::string name, DebugStringConvertible value, std::string defaultValue) { + return debugStringConvertibleItem(name, value.getDebugDescription(), defaultValue); +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/debug/debugStringConvertibleUtils.h b/ReactCommon/fabric/debug/debugStringConvertibleUtils.h new file mode 100644 index 00000000000000..d6be81b3c6be36 --- /dev/null +++ b/ReactCommon/fabric/debug/debugStringConvertibleUtils.h @@ -0,0 +1,53 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 +#include +#include + +namespace facebook { +namespace react { + +SharedDebugStringConvertibleList operator+(const SharedDebugStringConvertibleList &lhs, const SharedDebugStringConvertibleList &rhs); +SharedDebugStringConvertible debugStringConvertibleItem(std::string name, DebugStringConvertible value, std::string defaultValue = ""); + +#define IS_EQUAL(a, b) ((a) == (b)) +#define IS_EQUAL_FLOAT(a, b) ((isnan(a) == isnan(b)) || ((a) == (b))) + +#define DEBUG_STRING_CONVERTIBLE_TEMPLATE(type, converter) \ +DEBUG_STRING_CONVERTIBLE_TEMPLATE_EX(type, converter, {}, IS_EQUAL) + +#define DEBUG_STRING_CONVERTIBLE_TEMPLATE_EX(type, converter, defaults, comparator) \ +inline SharedDebugStringConvertible debugStringConvertibleItem(std::string name, type value, type defaultValue = defaults) { \ + if (comparator(value, defaultValue)) { \ + return nullptr; \ + } \ + return std::make_shared(name, converter(value)); \ +} \ +\ +inline SharedDebugStringConvertible debugStringConvertibleItem(std::string name, folly::Optional value, type defaultValue = defaults) { \ + if (value.has_value()) { \ + return nullptr; \ + } \ + return debugStringConvertibleItem(name, value.value_or(defaultValue), defaultValue); \ +} + +DEBUG_STRING_CONVERTIBLE_TEMPLATE(std::string, ) +DEBUG_STRING_CONVERTIBLE_TEMPLATE(int, folly::to) +DEBUG_STRING_CONVERTIBLE_TEMPLATE(bool, folly::to) +DEBUG_STRING_CONVERTIBLE_TEMPLATE_EX(float, folly::to, std::numeric_limits::quiet_NaN(), IS_EQUAL_FLOAT) +DEBUG_STRING_CONVERTIBLE_TEMPLATE_EX(double, folly::to, std::numeric_limits::quiet_NaN(), IS_EQUAL_FLOAT) + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/graphics/debugStringConvertibleUtils.h b/ReactCommon/fabric/graphics/debugStringConvertibleUtils.h new file mode 100644 index 00000000000000..d67dd14cce13d0 --- /dev/null +++ b/ReactCommon/fabric/graphics/debugStringConvertibleUtils.h @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 { + +DEBUG_STRING_CONVERTIBLE_TEMPLATE(Point, stringFromPoint) +DEBUG_STRING_CONVERTIBLE_TEMPLATE(Size, stringFromSize) +DEBUG_STRING_CONVERTIBLE_TEMPLATE(Rect, stringFromRect) +DEBUG_STRING_CONVERTIBLE_TEMPLATE(SharedColor, colorNameFromColor) + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/text/basetext/BaseTextProps.cpp b/ReactCommon/fabric/text/basetext/BaseTextProps.cpp index 4b3e1a80e5ff00..5b03c924d5eb98 100644 --- a/ReactCommon/fabric/text/basetext/BaseTextProps.cpp +++ b/ReactCommon/fabric/text/basetext/BaseTextProps.cpp @@ -61,12 +61,7 @@ TextAttributes BaseTextProps::getTextAttributes() const { #pragma mark - DebugStringConvertible SharedDebugStringConvertibleList BaseTextProps::getDebugProps() const { - SharedDebugStringConvertibleList list = {}; - - auto textAttributesPropsList = textAttributes_.getDebugProps(); - std::move(textAttributesPropsList.begin(), textAttributesPropsList.end(), std::back_inserter(list)); - - return list; + return textAttributes_.getDebugProps(); } } // namespace react diff --git a/ReactCommon/fabric/text/paragraph/ParagraphLocalData.cpp b/ReactCommon/fabric/text/paragraph/ParagraphLocalData.cpp index 0390313b689c34..0064ee862e7fb0 100644 --- a/ReactCommon/fabric/text/paragraph/ParagraphLocalData.cpp +++ b/ReactCommon/fabric/text/paragraph/ParagraphLocalData.cpp @@ -7,7 +7,7 @@ #include "ParagraphLocalData.h" -#include +#include namespace facebook { namespace react { @@ -37,9 +37,9 @@ std::string ParagraphLocalData::getDebugName() const { } SharedDebugStringConvertibleList ParagraphLocalData::getDebugProps() const { - SharedDebugStringConvertibleList list = {}; - list.push_back(std::make_shared("attributedString", attributedString_.getDebugDescription())); - return list; + return { + debugStringConvertibleItem("attributedString", attributedString_) + }; } } // namespace react diff --git a/ReactCommon/fabric/text/paragraph/ParagraphProps.cpp b/ReactCommon/fabric/text/paragraph/ParagraphProps.cpp index 95be162bb5a78d..a4481e13836618 100644 --- a/ReactCommon/fabric/text/paragraph/ParagraphProps.cpp +++ b/ReactCommon/fabric/text/paragraph/ParagraphProps.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include namespace facebook { @@ -43,21 +43,10 @@ bool ParagraphProps::getIsSelectable() const { #pragma mark - DebugStringConvertible SharedDebugStringConvertibleList ParagraphProps::getDebugProps() const { - SharedDebugStringConvertibleList list = {}; - - // View Props - auto &&viewPropsList = ViewProps::getDebugProps(); - std::move(viewPropsList.begin(), viewPropsList.end(), std::back_inserter(list)); - - // Paragraph Props - auto &¶graphAttributePropsList = paragraphAttributes_.getDebugProps(); - std::move(paragraphAttributePropsList.begin(), paragraphAttributePropsList.end(), std::back_inserter(list)); - - // Base Text Props - auto &&baseTextPropsList = BaseTextProps::getDebugProps(); - std::move(baseTextPropsList.begin(), baseTextPropsList.end(), std::back_inserter(list)); - - return list; + return + ViewProps::getDebugProps() + + paragraphAttributes_.getDebugProps() + + BaseTextProps::getDebugProps(); } } // namespace react From 7cf7028092bcb4f3c0fc391893c2682523abc6e3 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 8 May 2018 22:56:04 -0700 Subject: [PATCH 0467/1109] Fabric: Support for view recycling in RCTComponentViewRegistry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Quite trivial but still very cool recycling of native view instances is finnally here, in React Native. � Reviewed By: mdvacca Differential Revision: D7804085 fbshipit-source-id: 644804da3185f9ed3fdea42d4d76c93e86934448 --- .../Mounting/RCTComponentViewRegistry.mm | 53 +++++++++++++++++-- React/Fabric/Mounting/RCTViewComponentView.h | 2 + React/Fabric/Mounting/RCTViewComponentView.mm | 3 +- 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/React/Fabric/Mounting/RCTComponentViewRegistry.mm b/React/Fabric/Mounting/RCTComponentViewRegistry.mm index c9d8224007e407..83b0afb85a9d9b 100644 --- a/React/Fabric/Mounting/RCTComponentViewRegistry.mm +++ b/React/Fabric/Mounting/RCTComponentViewRegistry.mm @@ -10,8 +10,11 @@ #import #import +const NSInteger RCTComponentViewRegistryRecyclePoolMaxSize = 256; + @implementation RCTComponentViewRegistry { NSMapTable *> *_registry; + NSMapTable *> *> *_recyclePool; } - (instancetype)init @@ -19,6 +22,8 @@ - (instancetype)init if (self = [super init]) { _registry = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsIntegerPersonality | NSPointerFunctionsOpaqueMemory valueOptions:NSPointerFunctionsObjectPersonality]; + _recyclePool = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsObjectPersonality + valueOptions:NSPointerFunctionsObjectPersonality]; } return self; @@ -28,9 +33,8 @@ - (instancetype)init tag:(ReactTag)tag { RCTAssertMainQueue(); - // This is temporary approach. - NSString *className = [NSString stringWithFormat:@"RCT%@ComponentView", componentName]; - UIView *componentView = [[NSClassFromString(className) alloc] init]; + UIView *componentView = + [self _dequeueComponentViewWithName:componentName]; componentView.tag = tag; [_registry setObject:componentView forKey:(__bridge id)(void *)tag]; return componentView; @@ -42,6 +46,8 @@ - (void)enqueueComponentViewWithName:(NSString *)componentName { RCTAssertMainQueue(); [_registry removeObjectForKey:(__bridge id)(void *)tag]; + componentView.tag = 0; + [self _enqueueComponentViewWithName:componentName componentView:componentView]; } - (UIView *)componentViewByTag:(ReactTag)tag @@ -56,4 +62,45 @@ - (ReactTag)tagByComponentView:(UIView *)componentView return componentView.tag; } +- (UIView *)_createComponentViewWithName:(NSString *)componentName +{ + RCTAssertMainQueue(); + // This is temporary approach. + NSString *className = [NSString stringWithFormat:@"RCT%@ComponentView", componentName]; + UIView *componentView = [[NSClassFromString(className) alloc] init]; + return componentView; +} + +- (nullable UIView *)_dequeueComponentViewWithName:(NSString *)componentName +{ + RCTAssertMainQueue(); + NSHashTable *> *componentViews = [_recyclePool objectForKey:componentName]; + if (!componentViews || componentViews.count == 0) { + return [self _createComponentViewWithName:componentName]; + } + + UIView *componentView = [componentViews anyObject]; + [componentViews removeObject:componentView]; + return componentView; +} + +- (void)_enqueueComponentViewWithName:(NSString *)componentName + componentView:(UIView *)componentView +{ + RCTAssertMainQueue(); + [componentView prepareForRecycle]; + + NSHashTable *> *componentViews = [_recyclePool objectForKey:componentName]; + if (!componentViews) { + componentViews = [NSHashTable hashTableWithOptions:NSPointerFunctionsObjectPersonality]; + [_recyclePool setObject:componentViews forKey:componentName]; + } + + if (componentViews.count >= RCTComponentViewRegistryRecyclePoolMaxSize) { + return; + } + + [componentViews addObject:componentView]; +} + @end diff --git a/React/Fabric/Mounting/RCTViewComponentView.h b/React/Fabric/Mounting/RCTViewComponentView.h index 8dc5fc2e12dfe2..8ae84d138f5036 100644 --- a/React/Fabric/Mounting/RCTViewComponentView.h +++ b/React/Fabric/Mounting/RCTViewComponentView.h @@ -10,6 +10,7 @@ #import #import #import +#import NS_ASSUME_NONNULL_BEGIN @@ -19,6 +20,7 @@ NS_ASSUME_NONNULL_BEGIN @interface RCTViewComponentView : UIView { @protected facebook::react::LayoutMetrics _layoutMetrics; + facebook::react::SharedProps _props; } @end diff --git a/React/Fabric/Mounting/RCTViewComponentView.mm b/React/Fabric/Mounting/RCTViewComponentView.mm index cc3c0772bd75fb..26fff3a50a62e6 100644 --- a/React/Fabric/Mounting/RCTViewComponentView.mm +++ b/React/Fabric/Mounting/RCTViewComponentView.mm @@ -17,8 +17,9 @@ - (void)updateProps:(facebook::react::SharedProps)props oldProps:(facebook::react::SharedProps)oldProps { if (!oldProps) { - oldProps = std::make_shared(); + oldProps = _props ?: std::make_shared(); } + _props = props; auto oldViewProps = *std::dynamic_pointer_cast(oldProps); auto newViewProps = *std::dynamic_pointer_cast(props); From e028631513e535898834dc4e5e6d089bb37fda79 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 8 May 2018 22:56:07 -0700 Subject: [PATCH 0468/1109] Fabric: Implementation of `yogaStyleValueFromFloat` Summary: Quite obvious. Reviewed By: mdvacca Differential Revision: D7857047 fbshipit-source-id: 876664b3ab5c19b7c66a38579664f18a38a1a371 --- ReactCommon/fabric/view/yoga/YogaStylableProps.h | 4 ++-- .../fabric/view/yoga/yogaValuesConversions.cpp | 13 ++++++++++--- .../fabric/view/yoga/yogaValuesConversions.h | 2 ++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/ReactCommon/fabric/view/yoga/YogaStylableProps.h b/ReactCommon/fabric/view/yoga/YogaStylableProps.h index 61d935a22f27a5..14f721c0594bf6 100644 --- a/ReactCommon/fabric/view/yoga/YogaStylableProps.h +++ b/ReactCommon/fabric/view/yoga/YogaStylableProps.h @@ -20,8 +20,8 @@ class YogaStylableProps; typedef std::shared_ptr SharedYogaStylableProps; class YogaStylableProps: - public virtual DebugStringConvertible -{ + public virtual DebugStringConvertible { + public: const YGStyle &getYogaStyle() const; diff --git a/ReactCommon/fabric/view/yoga/yogaValuesConversions.cpp b/ReactCommon/fabric/view/yoga/yogaValuesConversions.cpp index f13744de757722..328ea9f183324a 100644 --- a/ReactCommon/fabric/view/yoga/yogaValuesConversions.cpp +++ b/ReactCommon/fabric/view/yoga/yogaValuesConversions.cpp @@ -46,6 +46,14 @@ YGFloatOptional yogaOptionalFloatFromFabricFloat(Float value) { return YGFloatOptional(yogaFloatFromFabricFloat(value)); } +YGValue yogaStyleValueFromFloat(const Float &value) { + if (isnan(value) || value == kFloatUndefined) { + return YGValueUndefined; + } + + return {(float)value, YGUnitPoint}; +} + LayoutMetrics layoutMetricsFromYogaNode(YGNode &yogaNode) { LayoutMetrics layoutMetrics; @@ -182,12 +190,11 @@ YGDisplay yogaStyleDisplayFromDynamic(const folly::dynamic &value) { YGValue yogaStyleValueFromDynamic(const folly::dynamic &value) { if (value.isNumber()) { - float x = value.asDouble(); - return { x, YGUnitPoint }; + return yogaStyleValueFromFloat(value.asDouble()); } else if (value.isString()) { const auto stringValue = value.asString(); if (stringValue == "auto") { - return { YGUndefined, YGUnitAuto }; + return YGValueUndefined; } else { if (stringValue.back() == '%') { return { folly::to(stringValue.substr(stringValue.length() - 1)), YGUnitPercent }; diff --git a/ReactCommon/fabric/view/yoga/yogaValuesConversions.h b/ReactCommon/fabric/view/yoga/yogaValuesConversions.h index 6c51565983007e..6837f9e10b326e 100644 --- a/ReactCommon/fabric/view/yoga/yogaValuesConversions.h +++ b/ReactCommon/fabric/view/yoga/yogaValuesConversions.h @@ -24,6 +24,8 @@ float yogaFloatFromFabricFloat(Float value); Float fabricFloatFromYogaOptionalFloat(YGFloatOptional value); YGFloatOptional yogaOptionalFloatFromFabricFloat(Float value); +YGValue yogaStyleValueFromFloat(const Float &value); + LayoutMetrics layoutMetricsFromYogaNode(YGNode &yogaNode); YGDirection yogaStyleDirectionFromDynamic(const folly::dynamic &value); From cb48fa4d494e7352e11d23cf60fcf23884345564 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 8 May 2018 22:56:10 -0700 Subject: [PATCH 0469/1109] Fabric: `LayoutContext::affectedShadowNodes` was removed Summary: Apparently, we don't need this functionality in Fabric because we compute mutation instactions during diffing anyways. But we still need (will need) `LayoutContext` for sure. Reviewed By: mdvacca Differential Revision: D7857045 fbshipit-source-id: 4be2744d9abea473ead847f35f698104f94af33d --- ReactCommon/fabric/core/layout/LayoutContext.h | 6 ------ ReactCommon/fabric/uimanager/Scheduler.cpp | 1 - ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp | 5 +---- 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/ReactCommon/fabric/core/layout/LayoutContext.h b/ReactCommon/fabric/core/layout/LayoutContext.h index 6f8d49ff4a18bb..1046fd00147fdd 100644 --- a/ReactCommon/fabric/core/layout/LayoutContext.h +++ b/ReactCommon/fabric/core/layout/LayoutContext.h @@ -24,12 +24,6 @@ struct LayoutContext { * Compound absolute position of the node relative to the root node. */ Point absolutePosition {0, 0}; - - /* - * Collection of shadow nodes which were chanded during the layout pass, - * and which associated views might need to be updated. - */ - std::shared_ptr> affectedShadowNodes {nullptr}; }; } // namespace react diff --git a/ReactCommon/fabric/uimanager/Scheduler.cpp b/ReactCommon/fabric/uimanager/Scheduler.cpp index 8b5038c31f7c95..6ad2f45f0080c2 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.cpp +++ b/ReactCommon/fabric/uimanager/Scheduler.cpp @@ -65,7 +65,6 @@ void Scheduler::uiManagerDidFinishTransaction(Tag rootTag, const SharedShadowNod auto nonConstNewRootShadowNode = std::const_pointer_cast(newRootShadowNode); LayoutContext layoutContext = LayoutContext(); - layoutContext.affectedShadowNodes = std::make_shared>(); LOG(INFO) << "Old Shadow Tree: \n" << oldRootShadowNode->getDebugDescription(); LOG(INFO) << "New Shadow Tree *before* layout: \n" << newRootShadowNode->getDebugDescription(); diff --git a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp index d91def613c2d67..bce88ce68adaf0 100644 --- a/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp +++ b/ReactCommon/fabric/view/yoga/YogaLayoutableShadowNode.cpp @@ -130,10 +130,7 @@ void YogaLayoutableShadowNode::layoutChildren(LayoutContext layoutContext) { auto nonConstYogaLayoutableChild = std::const_pointer_cast(yogaLayoutableChild); LayoutMetrics childLayoutMetrics = layoutMetricsFromYogaNode(*nonConstYogaLayoutableChild->yogaNode_); - bool isAffected = nonConstYogaLayoutableChild->setLayoutMetrics(childLayoutMetrics); - if (isAffected) { - layoutContext.affectedShadowNodes->insert(child); - } + nonConstYogaLayoutableChild->setLayoutMetrics(childLayoutMetrics); } } From 2bb41031baaec7ca9fe97e8574407209db2c229e Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 8 May 2018 22:56:14 -0700 Subject: [PATCH 0470/1109] Fabric: Introducing `RootShadowNode` Summary: `RootShadowNode` is a dedicated class for managing the root node. Reviewed By: mdvacca Differential Revision: D7857050 fbshipit-source-id: f15f4b177f03cea4c0fd5a60d761ee2745319d77 --- .../core/shadownode/ConcreteShadowNode.h | 1 - ReactCommon/fabric/uimanager/Scheduler.h | 7 +-- ReactCommon/fabric/view/BUCK | 1 + ReactCommon/fabric/view/root/RootProps.cpp | 45 +++++++++++++++++ ReactCommon/fabric/view/root/RootProps.h | 44 ++++++++++++++++ .../fabric/view/root/RootShadowNode.cpp | 23 +++++++++ ReactCommon/fabric/view/root/RootShadowNode.h | 50 +++++++++++++++++++ 7 files changed, 164 insertions(+), 7 deletions(-) create mode 100644 ReactCommon/fabric/view/root/RootProps.cpp create mode 100644 ReactCommon/fabric/view/root/RootProps.h create mode 100644 ReactCommon/fabric/view/root/RootShadowNode.cpp create mode 100644 ReactCommon/fabric/view/root/RootShadowNode.h diff --git a/ReactCommon/fabric/core/shadownode/ConcreteShadowNode.h b/ReactCommon/fabric/core/shadownode/ConcreteShadowNode.h index aca5fc32bea853..06a1afa7c98927 100644 --- a/ReactCommon/fabric/core/shadownode/ConcreteShadowNode.h +++ b/ReactCommon/fabric/core/shadownode/ConcreteShadowNode.h @@ -81,7 +81,6 @@ class ConcreteShadowNode: public ShadowNode { const SharedConcreteProps getProps() const { assert(std::dynamic_pointer_cast(props_)); - return std::static_pointer_cast(props_); } diff --git a/ReactCommon/fabric/uimanager/Scheduler.h b/ReactCommon/fabric/uimanager/Scheduler.h index b48d6e848af4c7..5082f9bb60953b 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.h +++ b/ReactCommon/fabric/uimanager/Scheduler.h @@ -9,16 +9,11 @@ #include #include #include +#include namespace facebook { namespace react { -/* - * We expect having a dedicated subclass for root shadow node. - */ -using SharedRootShadowNode = SharedViewShadowNode; -using RootShadowNode = ViewShadowNode; - class FabricUIManager; /* diff --git a/ReactCommon/fabric/view/BUCK b/ReactCommon/fabric/view/BUCK index 221ea2c1055537..5665baed32ee76 100644 --- a/ReactCommon/fabric/view/BUCK +++ b/ReactCommon/fabric/view/BUCK @@ -22,6 +22,7 @@ rn_xplat_cxx_library( [ ("", "*.h"), ("accessibility", "*.h"), + ("root", "*.h"), ("yoga", "*.h"), ], prefix = "fabric/view", diff --git a/ReactCommon/fabric/view/root/RootProps.cpp b/ReactCommon/fabric/view/root/RootProps.cpp new file mode 100644 index 00000000000000..e8f0becede9778 --- /dev/null +++ b/ReactCommon/fabric/view/root/RootProps.cpp @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "RootProps.h" + +#include "yogaValuesConversions.h" + +namespace facebook { +namespace react { + +void RootProps::applyLayoutConstraints(const LayoutConstraints &layoutConstraints) { + ensureUnsealed(); + + layoutConstraints_ = layoutConstraints; + + yogaStyle_.minDimensions[YGDimensionWidth] = + yogaStyleValueFromFloat(layoutConstraints.minimumSize.width); + yogaStyle_.minDimensions[YGDimensionHeight] = + yogaStyleValueFromFloat(layoutConstraints.minimumSize.height); + + yogaStyle_.maxDimensions[YGDimensionWidth] = + yogaStyleValueFromFloat(layoutConstraints.maximumSize.width); + yogaStyle_.maxDimensions[YGDimensionHeight] = + yogaStyleValueFromFloat(layoutConstraints.maximumSize.height); +} + +void RootProps::applyLayoutContext(const LayoutContext &layoutContext) { + ensureUnsealed(); + layoutContext_ = layoutContext; +} + +LayoutConstraints RootProps::getLayoutConstraints() const { + return layoutConstraints_; +} + +LayoutContext RootProps::getLayoutContext() const { + return layoutContext_; +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/view/root/RootProps.h b/ReactCommon/fabric/view/root/RootProps.h new file mode 100644 index 00000000000000..f8c40f361914d3 --- /dev/null +++ b/ReactCommon/fabric/view/root/RootProps.h @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 { + +class RootProps; + +using SharedRootProps = std::shared_ptr; + +class RootProps final: + public ViewProps { + +public: + + /* + * Same semantic as `apply()` but LayoutConstraints & LayoutContext specific. + */ + void applyLayoutConstraints(const LayoutConstraints &layoutConstraints); + void applyLayoutContext(const LayoutContext &layoutContext); + + LayoutConstraints getLayoutConstraints() const; + LayoutContext getLayoutContext() const; + +private: + + LayoutConstraints layoutConstraints_; + LayoutContext layoutContext_; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/view/root/RootShadowNode.cpp b/ReactCommon/fabric/view/root/RootShadowNode.cpp new file mode 100644 index 00000000000000..97dc7dd011e5ad --- /dev/null +++ b/ReactCommon/fabric/view/root/RootShadowNode.cpp @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "RootShadowNode.h" + +namespace facebook { +namespace react { + +ComponentName RootShadowNode::getComponentName() const { + return ComponentName("RootView"); +} + +void RootShadowNode::layout() { + ensureUnsealed(); + layout(getProps()->getLayoutContext()); +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/view/root/RootShadowNode.h b/ReactCommon/fabric/view/root/RootShadowNode.h new file mode 100644 index 00000000000000..6508fa5872181d --- /dev/null +++ b/ReactCommon/fabric/view/root/RootShadowNode.h @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 { + +class RootShadowNode; + +using SharedRootShadowNode = std::shared_ptr; +using UnsharedRootShadowNode = std::shared_ptr; + +/* + * `ShadowNode` for the root component. + * Besides all functionality of the `View` component, `RootShadowNode` contains + * props which represent external layout constraints and context of the + * shadow tree. + */ +class RootShadowNode final: + public ConcreteViewShadowNode { + +public: + + using ConcreteViewShadowNode::ConcreteViewShadowNode; + + ComponentName getComponentName() const override; + + /* + * Layouts the shadow tree. + */ + void layout(); + +private: + + using YogaLayoutableShadowNode::layout; +}; + +} // namespace react +} // namespace facebook From a879842033385dc342970692a987cdf08d407e2a Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 8 May 2018 22:56:16 -0700 Subject: [PATCH 0471/1109] Fabric: Introducing `ShadowTree` Summary: ShadowTree is an abstraction around (commited) root shadow node and managing its lifecycle. Reviewed By: mdvacca Differential Revision: D7857049 fbshipit-source-id: 8d530e0366fc703e4aef4ec88dd8ea990dafaaf1 --- ReactCommon/fabric/uimanager/Scheduler.cpp | 78 ++++++------- ReactCommon/fabric/uimanager/Scheduler.h | 26 +++-- ReactCommon/fabric/uimanager/ShadowTree.cpp | 107 ++++++++++++++++++ ReactCommon/fabric/uimanager/ShadowTree.h | 87 ++++++++++++++ .../fabric/uimanager/ShadowTreeDelegate.h | 25 ++++ 5 files changed, 268 insertions(+), 55 deletions(-) create mode 100644 ReactCommon/fabric/uimanager/ShadowTree.cpp create mode 100644 ReactCommon/fabric/uimanager/ShadowTree.h create mode 100644 ReactCommon/fabric/uimanager/ShadowTreeDelegate.h diff --git a/ReactCommon/fabric/uimanager/Scheduler.cpp b/ReactCommon/fabric/uimanager/Scheduler.cpp index 6ad2f45f0080c2..f4ffe53a3b114f 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.cpp +++ b/ReactCommon/fabric/uimanager/Scheduler.cpp @@ -19,7 +19,6 @@ namespace react { Scheduler::Scheduler() { auto componentDescriptorRegistry = std::make_shared(); - componentDescriptorRegistry->registerComponentDescriptor(std::make_shared()); componentDescriptorRegistry->registerComponentDescriptor(std::make_shared()); componentDescriptorRegistry->registerComponentDescriptor(std::make_shared()); @@ -34,12 +33,29 @@ Scheduler::~Scheduler() { } void Scheduler::registerRootTag(Tag rootTag) { - auto rootShadowNode = std::make_shared(rootTag, rootTag, nullptr); - rootNodeRegistry_.insert({rootTag, rootShadowNode}); + auto &&shadowTree = std::make_shared(rootTag); + shadowTree->setDelegate(this); + shadowTreeRegistry_.insert({rootTag, shadowTree}); } void Scheduler::unregisterRootTag(Tag rootTag) { - rootNodeRegistry_.erase(rootTag); + auto &&iterator = shadowTreeRegistry_.find(rootTag); + auto &&shadowTree = iterator->second; + assert(shadowTree); + shadowTree->setDelegate(nullptr); + shadowTreeRegistry_.erase(iterator); +} + +Size Scheduler::measure(const Tag &rootTag, const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const { + auto &&shadowTree = shadowTreeRegistry_.at(rootTag); + assert(shadowTree); + return shadowTree->measure(layoutConstraints, layoutContext); +} + +void Scheduler::constraintLayout(const Tag &rootTag, const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) { + auto &&shadowTree = shadowTreeRegistry_.at(rootTag); + assert(shadowTree); + return shadowTree->constraintLayout(layoutConstraints, layoutContext); } #pragma mark - Delegate @@ -48,55 +64,27 @@ void Scheduler::setDelegate(SchedulerDelegate *delegate) { delegate_ = delegate; } -SchedulerDelegate *Scheduler::getDelegate() { +SchedulerDelegate *Scheduler::getDelegate() const { return delegate_; } -#pragma mark - UIManagerDelegate - -void Scheduler::uiManagerDidFinishTransaction(Tag rootTag, const SharedShadowNodeUnsharedList &rootChildNodes) { - SharedRootShadowNode oldRootShadowNode = rootNodeRegistry_[rootTag]; - assert(oldRootShadowNode); - - SharedRootShadowNode newRootShadowNode = - std::make_shared(oldRootShadowNode, nullptr, SharedShadowNodeSharedList(rootChildNodes)); - - auto nonConstOldRootShadowNode = std::const_pointer_cast(oldRootShadowNode); - auto nonConstNewRootShadowNode = std::const_pointer_cast(newRootShadowNode); - - LayoutContext layoutContext = LayoutContext(); - - LOG(INFO) << "Old Shadow Tree: \n" << oldRootShadowNode->getDebugDescription(); - LOG(INFO) << "New Shadow Tree *before* layout: \n" << newRootShadowNode->getDebugDescription(); - - nonConstNewRootShadowNode->layout(layoutContext); - - nonConstNewRootShadowNode->sealRecursive(); - - LOG(INFO) << "New Shadow Tree *after* layout: \n" << nonConstNewRootShadowNode->getDebugDescription(); - - TreeMutationInstructionList instructions = TreeMutationInstructionList(); - - calculateMutationInstructions( - instructions, - oldRootShadowNode, - oldRootShadowNode->ShadowNode::getChildren(), - newRootShadowNode->ShadowNode::getChildren() - ); - - LOG(INFO) << "TreeMutationInstructionList:"; - - for (auto instruction : instructions) { - LOG(INFO) << "Instruction: " << instruction.getDebugDescription(); - } - - rootNodeRegistry_[rootTag] = newRootShadowNode; +#pragma mark - ShadowTreeDelegate +void Scheduler::shadowTreeDidCommit(const SharedShadowTree &shadowTree, const TreeMutationInstructionList &instructions) { if (delegate_) { - delegate_->schedulerDidComputeMutationInstructions(rootTag, instructions); + delegate_->schedulerDidComputeMutationInstructions(shadowTree->getRootTag(), instructions); } } +#pragma mark - UIManagerDelegate + +void Scheduler::uiManagerDidFinishTransaction(Tag rootTag, const SharedShadowNodeUnsharedList &rootChildNodes) { + auto &&iterator = shadowTreeRegistry_.find(rootTag); + auto &&shadowTree = iterator->second; + assert(shadowTree); + return shadowTree->complete(rootChildNodes); +} + void Scheduler::uiManagerDidCreateShadowNode(const SharedShadowNode &shadowNode) { if (delegate_) { delegate_->schedulerDidRequestPreliminaryViewAllocation(shadowNode->getComponentName()); diff --git a/ReactCommon/fabric/uimanager/Scheduler.h b/ReactCommon/fabric/uimanager/Scheduler.h index 5082f9bb60953b..cadbc4caa2edae 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.h +++ b/ReactCommon/fabric/uimanager/Scheduler.h @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include @@ -20,18 +22,21 @@ class FabricUIManager; * Scheduler coordinates Shadow Tree updates and event flows. */ class Scheduler: - public UIManagerDelegate { + public UIManagerDelegate, + public ShadowTreeDelegate { public: + Scheduler(); - virtual ~Scheduler(); + ~Scheduler(); -#pragma mark - Root Nodes Managerment +#pragma mark - Shadow Tree Management void registerRootTag(Tag rootTag); void unregisterRootTag(Tag rootTag); - void setLayoutConstraints(Tag rootTag, LayoutConstraints layoutConstraints); + Size measure(const Tag &rootTag, const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const; + void constraintLayout(const Tag &rootTag, const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext); #pragma mark - Delegate @@ -41,13 +46,17 @@ class Scheduler: * the pointer before being destroyed. */ void setDelegate(SchedulerDelegate *delegate); - SchedulerDelegate *getDelegate(); + SchedulerDelegate *getDelegate() const; #pragma mark - UIManagerDelegate void uiManagerDidFinishTransaction(Tag rootTag, const SharedShadowNodeUnsharedList &rootChildNodes) override; void uiManagerDidCreateShadowNode(const SharedShadowNode &shadowNode) override; +#pragma mark - ShadowTreeDelegate + + void shadowTreeDidCommit(const SharedShadowTree &shadowTree, const TreeMutationInstructionList &instructions) override; + #pragma mark - Deprecated /* @@ -56,13 +65,10 @@ class Scheduler: std::shared_ptr getUIManager_DO_NOT_USE(); private: + SchedulerDelegate *delegate_; std::shared_ptr uiManager_; - - /* - * All commited `RootShadowNode` instances to differentiate against. - */ - std::unordered_map rootNodeRegistry_; + std::unordered_map shadowTreeRegistry_; }; } // namespace react diff --git a/ReactCommon/fabric/uimanager/ShadowTree.cpp b/ReactCommon/fabric/uimanager/ShadowTree.cpp new file mode 100644 index 00000000000000..66d2e23068c8e8 --- /dev/null +++ b/ReactCommon/fabric/uimanager/ShadowTree.cpp @@ -0,0 +1,107 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include "ShadowTree.h" + +#include +#include + +#include "ShadowTreeDelegate.h" +#include "Differentiator.h" +#include "TreeMutationInstruction.h" + +namespace facebook { +namespace react { + +ShadowTree::ShadowTree(Tag rootTag): + rootTag_(rootTag) { + + rootShadowNode_ = std::make_shared( + rootTag, + rootTag, + nullptr, + RootShadowNode::defaultSharedProps() + ); +} + +Tag ShadowTree::getRootTag() const { + return rootTag_; +} + +#pragma mark - Layout + +Size ShadowTree::measure(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const { + auto newRootShadowNode = cloneRootShadowNode(layoutConstraints, layoutContext); + newRootShadowNode->layout(); + return newRootShadowNode->getLayoutMetrics().frame.size; +} + +void ShadowTree::constraintLayout(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) { + auto newRootShadowNode = cloneRootShadowNode(layoutConstraints, layoutContext); + complete(newRootShadowNode); +} + +#pragma mark - Commiting + +UnsharedRootShadowNode ShadowTree::cloneRootShadowNode(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const { + auto oldRootShadowNode = rootShadowNode_; + auto &&props = std::make_shared(*oldRootShadowNode->getProps()); + props->applyLayoutConstraints(layoutConstraints); + props->applyLayoutContext(layoutContext); + auto newRootShadowNode = std::make_shared(oldRootShadowNode, props, nullptr); + return newRootShadowNode; +} + +void ShadowTree::complete(const SharedShadowNodeUnsharedList &rootChildNodes) { + auto oldRootShadowNode = rootShadowNode_; + auto newRootShadowNode = + std::make_shared(oldRootShadowNode, nullptr, SharedShadowNodeSharedList(rootChildNodes)); + + complete(newRootShadowNode); +} + +void ShadowTree::complete(UnsharedRootShadowNode newRootShadowNode) { + SharedRootShadowNode oldRootShadowNode = rootShadowNode_; + + newRootShadowNode->layout(); + + newRootShadowNode->sealRecursive(); + + TreeMutationInstructionList instructions = TreeMutationInstructionList(); + + calculateMutationInstructions( + instructions, + oldRootShadowNode, + oldRootShadowNode->ShadowNode::getChildren(), + newRootShadowNode->ShadowNode::getChildren() + ); + + if (commit(newRootShadowNode)) { + if (delegate_) { + delegate_->shadowTreeDidCommit(shared_from_this(), instructions); + } + } +} + +bool ShadowTree::commit(const SharedRootShadowNode &newRootShadowNode) { + std::lock_guard lock(commitMutex_); + + if (newRootShadowNode->getSourceNode() != rootShadowNode_) { + return false; + } + + rootShadowNode_ = newRootShadowNode; + return true; +} + +#pragma mark - Delegate + +void ShadowTree::setDelegate(ShadowTreeDelegate *delegate) { + delegate_ = delegate; +} + +ShadowTreeDelegate *ShadowTree::getDelegate() const { + return delegate_; +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/uimanager/ShadowTree.h b/ReactCommon/fabric/uimanager/ShadowTree.h new file mode 100644 index 00000000000000..e2abea7a37cc08 --- /dev/null +++ b/ReactCommon/fabric/uimanager/ShadowTree.h @@ -0,0 +1,87 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace facebook { +namespace react { + +class ShadowTree; + +using SharedShadowTree = std::shared_ptr; + +/* + * Represents the shadow tree and its lifecycle. + */ +class ShadowTree final: + public std::enable_shared_from_this { + +public: + + /* + * Creates a new shadow tree instance with given `rootTag`. + */ + ShadowTree(Tag rootTag); + + /* + * Returns the rootTag associated with the shadow tree (the tag of the + * root shadow node). + */ + Tag getRootTag() const; + +#pragma mark - Layout + + /* + * Measures the shadow tree with given `layoutConstraints` and `layoutContext`. + * Can be called from any thread, side-effect-less. + */ + Size measure(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const; + + /* + * Applies given `layoutConstraints` and `layoutContext` and commit + * the new shadow tree. + * Can be called from any thread. + */ + void constraintLayout(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext); + +#pragma mark - Application + + /* + * Create a new shadow tree with given `rootChildNodes` and commit. + * Can be called from any thread. + */ + void complete(const SharedShadowNodeUnsharedList &rootChildNodes); + +#pragma mark - Delegate + + /* + * Sets and gets the delegate. + * The delegate is stored as a raw pointer, so the owner must null + * the pointer before being destroyed. + */ + void setDelegate(ShadowTreeDelegate *delegate); + ShadowTreeDelegate *getDelegate() const; + +private: + + UnsharedRootShadowNode cloneRootShadowNode(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const; + void complete(UnsharedRootShadowNode newRootShadowNode); + bool commit(const SharedRootShadowNode &newRootShadowNode); + + const Tag rootTag_; + SharedRootShadowNode rootShadowNode_; + ShadowTreeDelegate *delegate_; + mutable std::mutex commitMutex_ {}; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/uimanager/ShadowTreeDelegate.h b/ReactCommon/fabric/uimanager/ShadowTreeDelegate.h new file mode 100644 index 00000000000000..59ca85f46be519 --- /dev/null +++ b/ReactCommon/fabric/uimanager/ShadowTreeDelegate.h @@ -0,0 +1,25 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include + +namespace facebook { +namespace react { + +class ShadowTree; + +/* + * Abstract class for ShadowTree's delegate. + */ +class ShadowTreeDelegate { +public: + + /* + * Called right after Shadow Tree commit a new state of the the tree. + */ + virtual void shadowTreeDidCommit(const std::shared_ptr &shadowTree, const TreeMutationInstructionList &instructions) = 0; +}; + +} // namespace react +} // namespace facebook From e052685ffc633a5b42f9658833d4ec3bc9d64710 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 8 May 2018 22:56:19 -0700 Subject: [PATCH 0472/1109] Fabric: Resonable default values for LayoutConstraints members Summary: Trivial. Reviewed By: mdvacca Differential Revision: D7857046 fbshipit-source-id: 88400f1831bf66ccd3d880ddf1de3df27287b5be --- ReactCommon/fabric/core/layout/LayoutConstraints.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ReactCommon/fabric/core/layout/LayoutConstraints.h b/ReactCommon/fabric/core/layout/LayoutConstraints.h index 432a8aad324dc4..8f92cc22c1cc07 100644 --- a/ReactCommon/fabric/core/layout/LayoutConstraints.h +++ b/ReactCommon/fabric/core/layout/LayoutConstraints.h @@ -17,8 +17,8 @@ namespace react { * Unified layout constraints for measuring. */ struct LayoutConstraints { - Size minimumSize; - Size maximumSize; + Size minimumSize {0, 0}; + Size maximumSize {kFloatUndefined, kFloatUndefined}; LayoutDirection layoutDirection; }; From 25664cc48c042319067ee26c87608fa6a1bed821 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 8 May 2018 22:56:21 -0700 Subject: [PATCH 0473/1109] Fabric: RCTConversions unified way to covert primitives between Fabric and UIKit Summary: Quite obvious. Reviewed By: mdvacca Differential Revision: D7857051 fbshipit-source-id: 85aa6a9c064e5aebe65486acd011d445efaf0ce8 --- .../Mounting/RCTParagraphComponentView.mm | 13 ++----- .../Mounting/UIView+ComponentViewProtocol.mm | 12 ++----- React/Fabric/RCTConversions.h | 34 +++++++++++++++++++ 3 files changed, 38 insertions(+), 21 deletions(-) create mode 100644 React/Fabric/RCTConversions.h diff --git a/React/Fabric/Mounting/RCTParagraphComponentView.mm b/React/Fabric/Mounting/RCTParagraphComponentView.mm index 6709bd2b222392..29175e9f535e1a 100644 --- a/React/Fabric/Mounting/RCTParagraphComponentView.mm +++ b/React/Fabric/Mounting/RCTParagraphComponentView.mm @@ -13,6 +13,7 @@ #import #import #import +#import "RCTConversions.h" using namespace facebook::react; @@ -60,17 +61,7 @@ - (void)drawRect:(CGRect)rect RCTTextLayoutManager *nativeTextLayoutManager = (__bridge RCTTextLayoutManager *)textLayoutManager->getNativeTextLayoutManager(); - auto contentFrame = _layoutMetrics.getContentFrame(); - CGRect frame = { - .origin = { - .x = contentFrame.origin.x, - .y = contentFrame.origin.y - }, - .size = { - .width = contentFrame.size.width, - .height = contentFrame.size.height - } - }; + CGRect frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame()); [nativeTextLayoutManager drawAttributedString:_paragraphLocalData->getAttributedString() paragraphAttributes:_paragraphAttributes diff --git a/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm b/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm index 1a4136cfd5117e..5627a699d252cd 100644 --- a/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm +++ b/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm @@ -8,6 +8,7 @@ #import "UIView+ComponentViewProtocol.h" #import +#import "RCTConversions.h" @implementation UIView (ComponentViewProtocol) @@ -40,16 +41,7 @@ - (void)updateLayoutMetrics:(facebook::react::LayoutMetrics)layoutMetrics oldLayoutMetrics:(facebook::react::LayoutMetrics)oldLayoutMetrics { if (layoutMetrics.frame != oldLayoutMetrics.frame) { - self.frame = { - .origin = { - .x = layoutMetrics.frame.origin.x, - .y = layoutMetrics.frame.origin.y - }, - .size = { - .width = layoutMetrics.frame.size.width, - .height = layoutMetrics.frame.size.height - } - }; + self.frame = RCTCGRectFromRect(layoutMetrics.frame); } // TODO: Apply another layout metrics here. diff --git a/React/Fabric/RCTConversions.h b/React/Fabric/RCTConversions.h new file mode 100644 index 00000000000000..9e4184651da421 --- /dev/null +++ b/React/Fabric/RCTConversions.h @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import + +inline CGPoint RCTCGPointFromPoint(facebook::react::Point point) { + return {point.x, point.y}; +} + +inline CGSize RCTCGSizeFromSize(facebook::react::Size size) { + return {size.width, size.height}; +} + +inline CGRect RCTCGRectFromRect(facebook::react::Rect rect) { + return {RCTCGPointFromPoint(rect.origin), RCTCGSizeFromSize(rect.size)}; +} + +inline facebook::react::Point RCTPointFromCGPoint(CGPoint point) { + return {point.x, point.y}; +} + +inline facebook::react::Size RCTSizeFromCGSize(CGSize size) { + return {size.width, size.height}; +} + +inline facebook::react::Rect RCTRectFromCGRect(CGRect rect) { + return {RCTPointFromCGPoint(rect.origin), RCTSizeFromCGSize(rect.size)}; +} From 20e88e9ac4b1e162cf9ac514c82b663212bb9dda Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 8 May 2018 22:56:24 -0700 Subject: [PATCH 0474/1109] Fabric: Deprecating `-[RCTSurface rootViewTag]` Summary: This diff deprecates `-[RCTSurface rootViewTag]` in favour of `-[RCTSurface rootTag]` which returns same value but represented as `ReactTag` (`long`) instead of `NSNumber *`. Reviewed By: mdvacca Differential Revision: D7857044 fbshipit-source-id: f5427c30d3de2d3563e830f2caac70b7dc9631f9 --- React/Fabric/Surface/RCTFabricSurface.h | 12 +++++++++++- React/Fabric/Surface/RCTFabricSurface.mm | 1 - 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/React/Fabric/Surface/RCTFabricSurface.h b/React/Fabric/Surface/RCTFabricSurface.h index 498fe1807c8964..c0a88c0729a375 100644 --- a/React/Fabric/Surface/RCTFabricSurface.h +++ b/React/Fabric/Surface/RCTFabricSurface.h @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +#import #import NS_ASSUME_NONNULL_BEGIN @@ -37,7 +38,7 @@ NS_ASSUME_NONNULL_BEGIN @property (atomic, readonly) RCTSurfaceStage stage; @property (atomic, readonly) RCTBridge *bridge; @property (atomic, readonly) NSString *moduleName; -@property (atomic, readonly) NSNumber *rootViewTag; +@property (atomic, readonly) ReactTag rootTag; @property (atomic, readwrite, weak, nullable) id delegate; @@ -124,4 +125,13 @@ NS_ASSUME_NONNULL_BEGIN @end +@interface RCTFabricSurface (Deprecated) + +/** + * Deprecated. Use `rootTag` instead. + */ +@property (atomic, readonly) NSNumber *rootViewTag; + +@end + NS_ASSUME_NONNULL_END diff --git a/React/Fabric/Surface/RCTFabricSurface.mm b/React/Fabric/Surface/RCTFabricSurface.mm index babdc28c7c3d40..060d05675d6524 100644 --- a/React/Fabric/Surface/RCTFabricSurface.mm +++ b/React/Fabric/Surface/RCTFabricSurface.mm @@ -28,7 +28,6 @@ @implementation RCTFabricSurface { // Immutable RCTSurfacePresenter *_surfacePresenter; NSString *_moduleName; - ReactTag _rootTag; // Protected by the `_mutex` std::mutex _mutex; From 67dbcbd57e8e69a397faaab8daffd61f27b90db4 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 8 May 2018 22:56:27 -0700 Subject: [PATCH 0475/1109] Fabric: Wiring layout pipeline between Surface and ShadowTree Summary: The layout pipeline is quite long: UIKit <-> Surface <-> SurfacePresenter <-> [RCTScheduler <|-|> Scheduler] <-> ShadowTree <-> RootShadowNode <-> YogaNode. Reviewed By: mdvacca Differential Revision: D7857048 fbshipit-source-id: 06c92ef1639465d17e2489667f99d0114b80dcff --- React/Fabric/RCTScheduler.h | 10 +++++++ React/Fabric/RCTScheduler.mm | 16 +++++++++++ React/Fabric/RCTSurfacePresenter.h | 15 +++++++++- React/Fabric/RCTSurfacePresenter.mm | 36 ++++++++++++++++++++++-- React/Fabric/Surface/RCTFabricSurface.mm | 9 ++++-- 5 files changed, 79 insertions(+), 7 deletions(-) diff --git a/React/Fabric/RCTScheduler.h b/React/Fabric/RCTScheduler.h index 1f1e367060f506..e6a730b788caec 100644 --- a/React/Fabric/RCTScheduler.h +++ b/React/Fabric/RCTScheduler.h @@ -9,6 +9,8 @@ #import #import +#import +#import #import #import @@ -38,6 +40,14 @@ NS_ASSUME_NONNULL_BEGIN - (void)unregisterRootTag:(ReactTag)tag; +- (CGSize)measureWithLayoutConstraints:(facebook::react::LayoutConstraints)layoutConstraints + layoutContext:(facebook::react::LayoutContext)layoutContext + rootTag:(ReactTag)rootTag; + +- (void)constraintLayoutWithLayoutConstraints:(facebook::react::LayoutConstraints)layoutConstraints + layoutContext:(facebook::react::LayoutContext)layoutContext + rootTag:(ReactTag)rootTag; + @end @interface RCTScheduler (Deprecated) diff --git a/React/Fabric/RCTScheduler.mm b/React/Fabric/RCTScheduler.mm index 0fe06175ee4dbc..fcd1a9d8b86d85 100644 --- a/React/Fabric/RCTScheduler.mm +++ b/React/Fabric/RCTScheduler.mm @@ -10,6 +10,8 @@ #import #import +#import "RCTConversions.h" + using namespace facebook::react; class SchedulerDelegateProxy: public SchedulerDelegate { @@ -61,6 +63,20 @@ - (void)unregisterRootTag:(ReactTag)tag _scheduler->unregisterRootTag(tag); } +- (CGSize)measureWithLayoutConstraints:(LayoutConstraints)layoutConstraints + layoutContext:(LayoutContext)layoutContext + rootTag:(ReactTag)rootTag +{ + return RCTCGSizeFromSize(_scheduler->measure(rootTag, layoutConstraints, layoutContext)); +} + +- (void)constraintLayoutWithLayoutConstraints:(LayoutConstraints)layoutConstraints + layoutContext:(LayoutContext)layoutContext + rootTag:(ReactTag)rootTag +{ + _scheduler->constraintLayout(rootTag, layoutConstraints, layoutContext); +} + @end @implementation RCTScheduler (Deprecated) diff --git a/React/Fabric/RCTSurfacePresenter.h b/React/Fabric/RCTSurfacePresenter.h index d99133d59a91c8..65456cbf53e669 100644 --- a/React/Fabric/RCTSurfacePresenter.h +++ b/React/Fabric/RCTSurfacePresenter.h @@ -29,7 +29,7 @@ NS_ASSUME_NONNULL_BEGIN @end -@interface RCTSurfacePresenter (Internal) +@interface RCTSurfacePresenter (Surface) /** * Surface uses those methods to register itself in the Presenter. @@ -38,6 +38,19 @@ NS_ASSUME_NONNULL_BEGIN - (void)registerSurface:(RCTFabricSurface *)surface; - (void)unregisterSurface:(RCTFabricSurface *)surface; +/** + * Measures the Surface with given constraints. + */ +- (CGSize)sizeThatFitsMinimumSize:(CGSize)minimumSize + maximumSize:(CGSize)maximumSize + surface:(RCTFabricSurface *)surface; + +/** + * Sets `minimumSize` and `maximumSize` layout constraints for the Surface. + */ +- (void)setMinimumSize:(CGSize)minimumSize + maximumSize:(CGSize)maximumSize + surface:(RCTFabricSurface *)surface; @end @interface RCTSurfacePresenter (Deprecated) diff --git a/React/Fabric/RCTSurfacePresenter.mm b/React/Fabric/RCTSurfacePresenter.mm index 8e88548c8d78df..1e0164f2b9fd14 100644 --- a/React/Fabric/RCTSurfacePresenter.mm +++ b/React/Fabric/RCTSurfacePresenter.mm @@ -19,6 +19,11 @@ #import #import +#import +#import + +#import "RCTConversions.h" + using namespace facebook::react; @interface RCTSurfacePresenter () @@ -87,6 +92,34 @@ - (void)unregisterSurface:(RCTFabricSurface *)surface [_surfaceRegistry unregisterSurface:surface]; } +- (CGSize)sizeThatFitsMinimumSize:(CGSize)minimumSize + maximumSize:(CGSize)maximumSize + surface:(RCTFabricSurface *)surface +{ + LayoutContext layoutContext; + LayoutConstraints layoutConstraints = {}; + layoutConstraints.minimumSize = RCTSizeFromCGSize(minimumSize); + layoutConstraints.maximumSize = RCTSizeFromCGSize(maximumSize); + + return [_scheduler measureWithLayoutConstraints:layoutConstraints + layoutContext:layoutContext + rootTag:surface.rootTag]; +} + +- (void)setMinimumSize:(CGSize)minimumSize + maximumSize:(CGSize)maximumSize + surface:(RCTFabricSurface *)surface +{ + LayoutContext layoutContext; + LayoutConstraints layoutConstraints = {}; + layoutConstraints.minimumSize = RCTSizeFromCGSize(minimumSize); + layoutConstraints.maximumSize = RCTSizeFromCGSize(maximumSize); + + [_scheduler constraintLayoutWithLayoutConstraints:layoutConstraints + layoutContext:layoutContext + rootTag:surface.rootTag]; +} + - (void)runSurface:(RCTFabricSurface *)surface { NSDictionary *applicationParameters = @{ @@ -122,9 +155,6 @@ - (void)mountingManager:(RCTMountingManager *)mountingManager didMountComponents UIView *rootComponentView = [_mountingManager.componentViewRegistry componentViewByTag:rootTag]; - // FIXME: Remove this. - rootComponentView.frame = CGRectMake(0, 0, 400, 400); - surface.view.rootView = (RCTSurfaceRootView *)rootComponentView; } diff --git a/React/Fabric/Surface/RCTFabricSurface.mm b/React/Fabric/Surface/RCTFabricSurface.mm index 060d05675d6524..3028a204e97e53 100644 --- a/React/Fabric/Surface/RCTFabricSurface.mm +++ b/React/Fabric/Surface/RCTFabricSurface.mm @@ -188,8 +188,9 @@ - (void)_stop - (CGSize)sizeThatFitsMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximumSize { - // TODO: Not supported yet. - return CGSizeZero; + return [_surfacePresenter sizeThatFitsMinimumSize:minimumSize + maximumSize:maximumSize + surface:self]; } #pragma mark - Size Constraints @@ -213,7 +214,9 @@ - (void)setMinimumSize:(CGSize)minimumSize _minimumSize = minimumSize; } - // TODO: Not supported yet. + return [_surfacePresenter setMinimumSize:minimumSize + maximumSize:maximumSize + surface:self]; } - (CGSize)minimumSize From 5d4c542c58d84bbe05f76bf01d9efdd9d438572c Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Wed, 9 May 2018 00:47:45 -0700 Subject: [PATCH 0476/1109] RN: Refactor `MockNativeMethods` in Jest Reviewed By: sahrens Differential Revision: D7917498 fbshipit-source-id: 97636080588bf2641a56256688cb0f2ec81ae463 --- jest/MockNativeMethods.js | 38 ++++++++++++++++++++++++++++++++++++++ jest/setup.js | 29 +++-------------------------- 2 files changed, 41 insertions(+), 26 deletions(-) create mode 100644 jest/MockNativeMethods.js diff --git a/jest/MockNativeMethods.js b/jest/MockNativeMethods.js new file mode 100644 index 00000000000000..9b44fc45fec62e --- /dev/null +++ b/jest/MockNativeMethods.js @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2013-present, Facebook, Inc. + * + * 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 mockNativeFunction = methodName => { + let warned = false; + return function() { + if (warned) { + return; + } + warned = true; + console.warn( + 'Calling .' + + methodName + + '() in the test renderer environment is not supported. Instead, mock ' + + 'out your components that use findNodeHandle with replacements that ' + + "don't rely on the native environment.", + ); + }; +}; + +const MockNativeMethods = { + measure: mockNativeFunction('measure'), + measureInWindow: mockNativeFunction('measureInWindow'), + measureLayout: mockNativeFunction('measureLayout'), + setNativeProps: mockNativeFunction('setNativeProps'), + focus: mockNativeFunction('focus'), + blur: mockNativeFunction('blur'), +}; + +module.exports = MockNativeMethods; diff --git a/jest/setup.js b/jest/setup.js index 25fed46877e9d4..b40bcebae25d6a 100644 --- a/jest/setup.js +++ b/jest/setup.js @@ -6,6 +6,7 @@ */ 'use strict'; +const MockNativeMethods = require.requireActual('./MockNativeMethods'); const mockComponent = require.requireActual('./mockComponent'); require.requireActual('../Libraries/polyfills/babelHelpers.js'); @@ -81,33 +82,9 @@ jest const NativeMethodsMixin = ReactNative.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.NativeMethodsMixin; - const mockFunction = (key) => { - let warned = false; - return function() { - if (warned) { - return; - } - warned = true; - console.warn( - 'Calling .' + key + '() in the test renderer environment is not ' + - 'supported. Instead, mock out your components that use ' + - 'findNodeHandle with replacements that don\'t rely on the ' + - 'native environment.', - ); - }; - }; + Object.assign(NativeMethodsMixin, MockNativeMethods); + Object.assign(ReactNative.NativeComponent.prototype, MockNativeMethods); - [ - 'measure', - 'measureInWindow', - 'measureLayout', - 'setNativeProps', - 'focus', - 'blur', - ].forEach((key) => { - NativeMethodsMixin[key] = mockFunction(key); - ReactNative.NativeComponent.prototype[key] = mockFunction(key); - }); return ReactNative; }) .mock('ensureComponentIsNative', () => () => true); From e1339bc18303ca5394cd0c9dc97cededb2261581 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Wed, 9 May 2018 00:47:46 -0700 Subject: [PATCH 0477/1109] RN: Replace `context.isInAParentText` w/ React.createContext Reviewed By: sahrens Differential Revision: D7895382 fbshipit-source-id: 4affcecd147b8e8c506e0d94f223bac3e6dfdf66 --- Libraries/Components/TextInput/TextInput.js | 21 ++--- Libraries/Components/View/View.js | 38 +++++----- Libraries/Image/Image.android.js | 76 +++++++++---------- Libraries/Text/Text.js | 29 ++++--- .../ViewContext.js => Text/TextAncestor.js} | 16 ++-- 5 files changed, 85 insertions(+), 95 deletions(-) rename Libraries/{Components/View/ViewContext.js => Text/TextAncestor.js} (53%) diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js index f0cf5b955e9612..754af17e1bcb56 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -20,6 +20,7 @@ const PropTypes = require('prop-types'); const ReactNative = require('ReactNative'); const StyleSheet = require('StyleSheet'); const Text = require('Text'); +const TextAncestor = require('TextAncestor'); const TextInputState = require('TextInputState'); /* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error * found when Flow v0.54 was deployed. To see the error delete this comment and @@ -28,7 +29,6 @@ const TimerMixin = require('react-timer-mixin'); const TouchableWithoutFeedback = require('TouchableWithoutFeedback'); const UIManager = require('UIManager'); const ViewPropTypes = require('ViewPropTypes'); -const {ViewContextTypes} = require('ViewContext'); const emptyFunction = require('fbjs/lib/emptyFunction'); const invariant = require('fbjs/lib/invariant'); @@ -47,8 +47,6 @@ const onlyMultiline = { children: true, }; -import type {ViewChildContext} from 'ViewContext'; - if (Platform.OS === 'android') { AndroidTextInput = requireNativeComponent('AndroidTextInput', null); } else if (Platform.OS === 'ios') { @@ -701,16 +699,7 @@ const TextInput = createReactClass({ } }, - getChildContext(): ViewChildContext { - return { - isInAParentText: true, - }; - }, - - childContextTypes: ViewContextTypes, - contextTypes: { - ...ViewContextTypes, onFocusRequested: PropTypes.func, focusEmitter: PropTypes.instanceOf(EventEmitter), }, @@ -723,13 +712,17 @@ const TextInput = createReactClass({ }, render: function() { + let textInput; if (Platform.OS === 'ios') { - return UIManager.RCTVirtualText + textInput = UIManager.RCTVirtualText ? this._renderIOS() : this._renderIOSLegacy(); } else if (Platform.OS === 'android') { - return this._renderAndroid(); + textInput = this._renderAndroid(); } + return ( + {textInput} + ); }, _getText: function(): ?string { diff --git a/Libraries/Components/View/View.js b/Libraries/Components/View/View.js index 558f40a5d4087c..1e79f88a5483d4 100644 --- a/Libraries/Components/View/View.js +++ b/Libraries/Components/View/View.js @@ -7,6 +7,7 @@ * @flow * @format */ + 'use strict'; const Platform = require('Platform'); @@ -14,13 +15,13 @@ const React = require('React'); const ReactNative = require('ReactNative'); const ReactNativeStyleAttributes = require('ReactNativeStyleAttributes'); const ReactNativeViewAttributes = require('ReactNativeViewAttributes'); +const TextAncestor = require('TextAncestor'); const ViewPropTypes = require('ViewPropTypes'); -const {ViewContextTypes} = require('ViewContext'); + const invariant = require('fbjs/lib/invariant'); const requireNativeComponent = require('requireNativeComponent'); import type {ViewProps} from 'ViewPropTypes'; -import type {ViewChildContext} from 'ViewContext'; export type Props = ViewProps; @@ -33,30 +34,31 @@ export type Props = ViewProps; */ class View extends ReactNative.NativeComponent { static propTypes = ViewPropTypes; - static childContextTypes = ViewContextTypes; viewConfig = { uiViewClassName: 'RCTView', validAttributes: ReactNativeViewAttributes.RCTView, }; - getChildContext(): ViewChildContext { - return { - isInAParentText: false, - }; - } - + /** + * WARNING: This method will not be used in production mode as in that mode we + * replace wrapper component View with generated native wrapper RCTView. Avoid + * adding functionality this component that you'd want to be available in both + * dev and prod modes. + */ render() { - invariant( - !(this.context.isInAParentText && Platform.OS === 'android'), - 'Nesting of within is not supported on Android.', + return ( + + {hasTextAncestor => { + // TODO: Change iOS to behave the same as Android. + invariant( + !hasTextAncestor || Platform.OS !== 'android', + 'Nesting of within is not supported on Android.', + ); + return ; + }} + ); - - // WARNING: This method will not be used in production mode as in that mode we - // replace wrapper component View with generated native wrapper RCTView. Avoid - // adding functionality this component that you'd want to be available in both - // dev and prod modes. - return ; } } diff --git a/Libraries/Image/Image.android.js b/Libraries/Image/Image.android.js index 7b0ec83a8738ec..d9702700be5930 100644 --- a/Libraries/Image/Image.android.js +++ b/Libraries/Image/Image.android.js @@ -7,6 +7,7 @@ * @flow * @format */ + 'use strict'; var ImageResizeMode = require('ImageResizeMode'); @@ -18,6 +19,7 @@ var PropTypes = require('prop-types'); var ReactNativeViewAttributes = require('ReactNativeViewAttributes'); var StyleSheet = require('StyleSheet'); var StyleSheetPropType = require('StyleSheetPropType'); +const TextAncestor = require('TextAncestor'); var ViewPropTypes = require('ViewPropTypes'); var createReactClass = require('create-react-class'); @@ -26,8 +28,6 @@ var merge = require('merge'); var requireNativeComponent = require('requireNativeComponent'); var resolveAssetSource = require('resolveAssetSource'); -const {ViewContextTypes} = require('ViewContext'); - var {ImageLoader} = NativeModules; let _requestId = 1; @@ -202,8 +202,6 @@ var Image = createReactClass({ validAttributes: ReactNativeViewAttributes.RCTView, }, - contextTypes: ViewContextTypes, - render: function() { const source = resolveAssetSource(this.props.source); const defaultSource = resolveAssetSource(this.props.defaultSource); @@ -236,42 +234,44 @@ var Image = createReactClass({ ); } - if (source && (source.uri || Array.isArray(source))) { - let style; - let sources; - if (source.uri) { - const {width, height} = source; - style = flattenStyle([{width, height}, styles.base, this.props.style]); - sources = [{uri: source.uri}]; - } else { - style = flattenStyle([styles.base, this.props.style]); - sources = source; - } - - const {onLoadStart, onLoad, onLoadEnd, onError} = this.props; - const nativeProps = merge(this.props, { - style, - shouldNotifyLoadEvents: !!( - onLoadStart || - onLoad || - onLoadEnd || - onError - ), - src: sources, - headers: source.headers, - defaultSrc: defaultSource ? defaultSource.uri : null, - loadingIndicatorSrc: loadingIndicatorSource - ? loadingIndicatorSource.uri - : null, - }); + if (!source || (!source.uri && !Array.isArray(source))) { + return null; + } - if (this.context.isInAParentText) { - return ; - } else { - return ; - } + let style; + let sources; + if (source.uri) { + const {width, height} = source; + style = flattenStyle([{width, height}, styles.base, this.props.style]); + sources = [{uri: source.uri}]; + } else { + style = flattenStyle([styles.base, this.props.style]); + sources = source; } - return null; + + const {onLoadStart, onLoad, onLoadEnd, onError} = this.props; + const nativeProps = merge(this.props, { + style, + shouldNotifyLoadEvents: !!(onLoadStart || onLoad || onLoadEnd || onError), + src: sources, + headers: source.headers, + defaultSrc: defaultSource ? defaultSource.uri : null, + loadingIndicatorSrc: loadingIndicatorSource + ? loadingIndicatorSource.uri + : null, + }); + + return ( + + {hasTextAncestor => + hasTextAncestor ? ( + + ) : ( + + ) + } + + ); }, }); diff --git a/Libraries/Text/Text.js b/Libraries/Text/Text.js index d6fd56fcc62e40..d983638ac5f101 100644 --- a/Libraries/Text/Text.js +++ b/Libraries/Text/Text.js @@ -12,6 +12,7 @@ const React = require('React'); const ReactNative = require('ReactNative'); const ReactNativeViewAttributes = require('ReactNativeViewAttributes'); +const TextAncestor = require('TextAncestor'); const TextPropTypes = require('TextPropTypes'); const Touchable = require('Touchable'); const UIManager = require('UIManager'); @@ -19,11 +20,9 @@ const UIManager = require('UIManager'); const createReactNativeComponentClass = require('createReactNativeComponentClass'); const mergeFast = require('mergeFast'); const processColor = require('processColor'); -const {ViewContextTypes} = require('ViewContext'); import type {PressEvent} from 'CoreEventTypes'; import type {TextProps} from 'TextProps'; -import type {ViewChildContext} from 'ViewContext'; type State = { isHighlighted: boolean, @@ -61,8 +60,6 @@ const viewConfig = { */ class Text extends ReactNative.NativeComponent { static propTypes = TextPropTypes; - static childContextTypes = ViewContextTypes; - static contextTypes = ViewContextTypes; static defaultProps = { accessible: true, @@ -76,12 +73,6 @@ class Text extends ReactNative.NativeComponent { viewConfig = viewConfig; - getChildContext(): ViewChildContext { - return { - isInAParentText: true, - }; - } - _handlers: ?Object; _hasPressHandler(): boolean { @@ -215,11 +206,19 @@ class Text extends ReactNative.NativeComponent { style: [this.props.style, {color: 'magenta'}], }; } - if (this.context.isInAParentText) { - return ; - } else { - return ; - } + return ( + + {hasTextAncestor => + hasTextAncestor ? ( + + ) : ( + + + + ) + } + + ); } } diff --git a/Libraries/Components/View/ViewContext.js b/Libraries/Text/TextAncestor.js similarity index 53% rename from Libraries/Components/View/ViewContext.js rename to Libraries/Text/TextAncestor.js index 81879aa35ecfa1..147d9763b2d6d4 100644 --- a/Libraries/Components/View/ViewContext.js +++ b/Libraries/Text/TextAncestor.js @@ -7,16 +7,12 @@ * @flow * @format */ -'use strict'; -const PropTypes = require('prop-types'); +'use strict'; -export type ViewChildContext = {| - +isInAParentText: boolean, -|}; +const React = require('React'); -module.exports = { - ViewContextTypes: { - isInAParentText: PropTypes.bool, - }, -}; +/** + * Whether the current element is the descendant of a element. + */ +module.exports = React.createContext(false); From 3e534b9aab5156adac67762877b2457408fe8934 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Wed, 9 May 2018 00:47:48 -0700 Subject: [PATCH 0478/1109] RN: Switch `View` to `React.forwardRef` Reviewed By: bvaughn, sophiebits Differential Revision: D7896711 fbshipit-source-id: c10c8a14a00ac2d67605e6e4fe1a341b4688fdd8 --- .../Animated/src/createAnimatedComponent.js | 2 +- Libraries/Components/View/View.js | 72 ++++++++----------- jest/mockComponent.js | 17 ++++- jest/setup.js | 2 +- 4 files changed, 45 insertions(+), 48 deletions(-) diff --git a/Libraries/Animated/src/createAnimatedComponent.js b/Libraries/Animated/src/createAnimatedComponent.js index d876af645c4e0c..a4177d65be0e40 100644 --- a/Libraries/Animated/src/createAnimatedComponent.js +++ b/Libraries/Animated/src/createAnimatedComponent.js @@ -18,7 +18,7 @@ const invariant = require('fbjs/lib/invariant'); function createAnimatedComponent(Component: any): any { invariant( - typeof Component === 'string' || + typeof Component !== 'function' || (Component.prototype && Component.prototype.isReactComponent), '`createAnimatedComponent` does not support stateless functional components; ' + 'use a class component instead.', diff --git a/Libraries/Components/View/View.js b/Libraries/Components/View/View.js index 1e79f88a5483d4..337f77d1aae558 100644 --- a/Libraries/Components/View/View.js +++ b/Libraries/Components/View/View.js @@ -4,23 +4,22 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @flow * @format + * @flow */ 'use strict'; const Platform = require('Platform'); const React = require('React'); -const ReactNative = require('ReactNative'); const ReactNativeStyleAttributes = require('ReactNativeStyleAttributes'); -const ReactNativeViewAttributes = require('ReactNativeViewAttributes'); const TextAncestor = require('TextAncestor'); const ViewPropTypes = require('ViewPropTypes'); const invariant = require('fbjs/lib/invariant'); const requireNativeComponent = require('requireNativeComponent'); +import type {NativeComponent} from 'ReactNative'; import type {ViewProps} from 'ViewPropTypes'; export type Props = ViewProps; @@ -32,50 +31,25 @@ export type Props = ViewProps; * * @see http://facebook.github.io/react-native/docs/view.html */ -class View extends ReactNative.NativeComponent { - static propTypes = ViewPropTypes; - - viewConfig = { - uiViewClassName: 'RCTView', - validAttributes: ReactNativeViewAttributes.RCTView, - }; - - /** - * WARNING: This method will not be used in production mode as in that mode we - * replace wrapper component View with generated native wrapper RCTView. Avoid - * adding functionality this component that you'd want to be available in both - * dev and prod modes. - */ - render() { - return ( - - {hasTextAncestor => { - // TODO: Change iOS to behave the same as Android. - invariant( - !hasTextAncestor || Platform.OS !== 'android', - 'Nesting of within is not supported on Android.', - ); - return ; - }} - - ); - } -} - -const RCTView = requireNativeComponent('RCTView', View, { - nativeOnly: { - nativeBackgroundAndroid: true, - nativeForegroundAndroid: true, +const RCTView = requireNativeComponent( + 'RCTView', + { + propTypes: ViewPropTypes, + }, + { + nativeOnly: { + nativeBackgroundAndroid: true, + nativeForegroundAndroid: true, + }, }, -}); +); if (__DEV__) { const UIManager = require('UIManager'); const viewConfig = (UIManager.viewConfigs && UIManager.viewConfigs.RCTView) || {}; for (const prop in viewConfig.nativeProps) { - const viewAny: any = View; // Appease flow - if (!viewAny.propTypes[prop] && !ReactNativeStyleAttributes[prop]) { + if (!ViewPropTypes[prop] && !ReactNativeStyleAttributes[prop]) { throw new Error( 'View is missing propType for native prop `' + prop + '`', ); @@ -85,8 +59,20 @@ if (__DEV__) { let ViewToExport = RCTView; if (__DEV__) { - ViewToExport = View; + // $FlowFixMe - TODO T29156721 `React.forwardRef` is not defined in Flow, yet. + ViewToExport = React.forwardRef((props, ref) => ( + + {hasTextAncestor => { + // TODO: Change iOS to behave the same as Android. + invariant( + !hasTextAncestor || Platform.OS !== 'android', + 'Nesting of within is not supported on Android.', + ); + return ; + }} + + )); + ViewToExport.displayName = 'View'; } -// No one should depend on the DEV-mode createClass View wrapper. -module.exports = ((ViewToExport: any): typeof View); +module.exports = ((ViewToExport: any): Class>); diff --git a/jest/mockComponent.js b/jest/mockComponent.js index 84c162d867f4f4..bdc16d805dcbcc 100644 --- a/jest/mockComponent.js +++ b/jest/mockComponent.js @@ -3,23 +3,34 @@ * * 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 = moduleName => { +module.exports = (moduleName, instanceMethods) => { const RealComponent = require.requireActual(moduleName); const React = require('react'); - const Component = class extends RealComponent { + const SuperClass = + typeof RealComponent === 'function' ? RealComponent : React.Component; + + const Component = class extends SuperClass { render() { const name = RealComponent.displayName || RealComponent.name; return React.createElement( - name.replace(/^(RCT|RK)/,''), + name.replace(/^(RCT|RK)/, ''), this.props, this.props.children, ); } }; + + if (instanceMethods != null) { + Object.assign(Component.prototype, instanceMethods); + } + return Component; }; diff --git a/jest/setup.js b/jest/setup.js index b40bcebae25d6a..2aef9f1b39fe58 100644 --- a/jest/setup.js +++ b/jest/setup.js @@ -38,7 +38,7 @@ jest .mock('Text', () => mockComponent('Text')) .mock('TextInput', () => mockComponent('TextInput')) .mock('Modal', () => mockComponent('Modal')) - .mock('View', () => mockComponent('View')) + .mock('View', () => mockComponent('View', MockNativeMethods)) .mock('RefreshControl', () => require.requireMock('RefreshControlMock')) .mock('ScrollView', () => require.requireMock('ScrollViewMock')) .mock( From 6a1b41643a5f5035c61a96263220d11d3462e8f2 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Wed, 9 May 2018 00:47:50 -0700 Subject: [PATCH 0479/1109] RN: Consistently Throw for Reviewed By: sahrens Differential Revision: D7898238 fbshipit-source-id: a2b74e691a116b1beae3c6bb266252a722aacbb1 --- Libraries/Components/View/View.js | 5 ++--- RNTester/js/TextInputExample.ios.js | 8 -------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/Libraries/Components/View/View.js b/Libraries/Components/View/View.js index 337f77d1aae558..9694a2fb39a234 100644 --- a/Libraries/Components/View/View.js +++ b/Libraries/Components/View/View.js @@ -63,10 +63,9 @@ if (__DEV__) { ViewToExport = React.forwardRef((props, ref) => ( {hasTextAncestor => { - // TODO: Change iOS to behave the same as Android. invariant( - !hasTextAncestor || Platform.OS !== 'android', - 'Nesting of within is not supported on Android.', + !hasTextAncestor, + 'Nesting of within is not currently supported.', ); return ; }} diff --git a/RNTester/js/TextInputExample.ios.js b/RNTester/js/TextInputExample.ios.js index fdcddc1f793dda..704278796f0630 100644 --- a/RNTester/js/TextInputExample.ios.js +++ b/RNTester/js/TextInputExample.ios.js @@ -872,14 +872,6 @@ exports.examples = [ style={styles.multiline} dataDetectorTypes="phoneNumber" /> - - - ); } From a1f2076aae13dd973932b0ecb90529402ab3f09f Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Wed, 9 May 2018 00:47:54 -0700 Subject: [PATCH 0480/1109] RN: Delete `mergeFast` from `Text` Reviewed By: sahrens, TheSavior Differential Revision: D7899406 fbshipit-source-id: 35fb14c5af3d01404896342a47af9fa280226c7f --- Libraries/Text/Text.js | 35 ++++++++++++++++---------------- Libraries/Text/TextProps.js | 4 ++-- Libraries/Utilities/mergeFast.js | 31 ---------------------------- 3 files changed, 19 insertions(+), 51 deletions(-) delete mode 100644 Libraries/Utilities/mergeFast.js diff --git a/Libraries/Text/Text.js b/Libraries/Text/Text.js index d983638ac5f101..1727e8f2684243 100644 --- a/Libraries/Text/Text.js +++ b/Libraries/Text/Text.js @@ -18,27 +18,24 @@ const Touchable = require('Touchable'); const UIManager = require('UIManager'); const createReactNativeComponentClass = require('createReactNativeComponentClass'); -const mergeFast = require('mergeFast'); const processColor = require('processColor'); import type {PressEvent} from 'CoreEventTypes'; -import type {TextProps} from 'TextProps'; +import type {PressRetentionOffset, TextProps} from 'TextProps'; -type State = { +type State = {| + touchable: {| + touchState: ?string, + responderID: ?number, + |}, isHighlighted: boolean, -}; - -type RectOffset = { - top: number, - left: number, - right: number, - bottom: number, -}; +|}; const PRESS_RECT_OFFSET = {top: 20, left: 20, right: 20, bottom: 30}; const viewConfig = { - validAttributes: mergeFast(ReactNativeViewAttributes.UIView, { + validAttributes: { + ...ReactNativeViewAttributes.UIView, isHighlighted: true, numberOfLines: true, ellipsizeMode: true, @@ -49,7 +46,7 @@ const viewConfig = { adjustsFontSizeToFit: true, minimumFontScale: true, textBreakStrategy: true, - }), + }, uiViewClassName: 'RCTText', }; @@ -67,9 +64,10 @@ class Text extends ReactNative.NativeComponent { ellipsizeMode: 'tail', }; - state = mergeFast(Touchable.Mixin.touchableGetInitialState(), { + state = { + ...Touchable.Mixin.touchableGetInitialState(), isHighlighted: false, - }); + }; viewConfig = viewConfig; @@ -143,7 +141,7 @@ class Text extends ReactNative.NativeComponent { this.props.onLongPress && this.props.onLongPress(e); }; - this.touchableGetPressRectOffset = function(): RectOffset { + this.touchableGetPressRectOffset = function(): PressRetentionOffset { return this.props.pressRetentionOffset || PRESS_RECT_OFFSET; }; } @@ -230,9 +228,10 @@ var RCTVirtualText = RCTText; if (UIManager.RCTVirtualText) { RCTVirtualText = createReactNativeComponentClass('RCTVirtualText', () => ({ - validAttributes: mergeFast(ReactNativeViewAttributes.UIView, { + validAttributes: { + ...ReactNativeViewAttributes.UIView, isHighlighted: true, - }), + }, uiViewClassName: 'RCTVirtualText', })); } diff --git a/Libraries/Text/TextProps.js b/Libraries/Text/TextProps.js index 56229632a01bac..474c8fef802bb5 100644 --- a/Libraries/Text/TextProps.js +++ b/Libraries/Text/TextProps.js @@ -17,12 +17,12 @@ import type {Node} from 'react'; import type {LayoutEvent, PressEvent} from 'CoreEventTypes'; import type {DangerouslyImpreciseStyleProp} from 'StyleSheet'; -type PressRetentionOffset = { +export type PressRetentionOffset = $ReadOnly<{| top: number, left: number, bottom: number, right: number, -}; +|}>; /** * @see https://facebook.github.io/react-native/docs/text.html#reference diff --git a/Libraries/Utilities/mergeFast.js b/Libraries/Utilities/mergeFast.js deleted file mode 100644 index 42e357e5dbda59..00000000000000 --- a/Libraries/Utilities/mergeFast.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * - * 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'; - -/** - * Faster version of `merge` that doesn't check its arguments and - * also merges prototype inherited properties. - * - * @param {object} one Any non-null object. - * @param {object} two Any non-null object. - * @return {object} Merging of two objects, including prototype - * inherited properties. - */ -var mergeFast = function(one: Object, two: Object): Object { - var ret = {}; - for (var keyOne in one) { - ret[keyOne] = one[keyOne]; - } - for (var keyTwo in two) { - ret[keyTwo] = two[keyTwo]; - } - return ret; -}; - -module.exports = mergeFast; From 06c05e744d8af9582bde348210f254d76dae48b9 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Wed, 9 May 2018 00:47:55 -0700 Subject: [PATCH 0481/1109] RN: Cleanup `Text` Implementation Reviewed By: sahrens, TheSavior Differential Revision: D7901531 fbshipit-source-id: dfaba402c1c26e34e9d2df01f2bbb8c26dfcd17e --- Libraries/Text/Text.js | 308 ++++++++++++++++++++++------------------- 1 file changed, 166 insertions(+), 142 deletions(-) diff --git a/Libraries/Text/Text.js b/Libraries/Text/Text.js index 1727e8f2684243..adde971751b74b 100644 --- a/Libraries/Text/Text.js +++ b/Libraries/Text/Text.js @@ -7,6 +7,7 @@ * @flow * @format */ + 'use strict'; const React = require('React'); @@ -18,17 +19,31 @@ const Touchable = require('Touchable'); const UIManager = require('UIManager'); const createReactNativeComponentClass = require('createReactNativeComponentClass'); +const nullthrows = require('fbjs/lib/nullthrows'); const processColor = require('processColor'); import type {PressEvent} from 'CoreEventTypes'; import type {PressRetentionOffset, TextProps} from 'TextProps'; +type ResponseHandlers = $ReadOnly<{| + onStartShouldSetResponder: () => boolean, + onResponderGrant: (event: SyntheticEvent<>, dispatchID: string) => void, + onResponderMove: (event: SyntheticEvent<>) => void, + onResponderRelease: (event: SyntheticEvent<>) => void, + onResponderTerminate: (event: SyntheticEvent<>) => void, + onResponderTerminationRequest: () => boolean, +|}>; + +type Props = TextProps; + type State = {| touchable: {| touchState: ?string, responderID: ?number, |}, isHighlighted: boolean, + createResponderHandlers: () => ResponseHandlers, + responseHandlers: ?ResponseHandlers, |}; const PRESS_RECT_OFFSET = {top: 20, left: 20, right: 20, bottom: 30}; @@ -55,7 +70,7 @@ const viewConfig = { * * See https://facebook.github.io/react-native/docs/text.html */ -class Text extends ReactNative.NativeComponent { +class Text extends ReactNative.NativeComponent { static propTypes = TextPropTypes; static defaultProps = { @@ -64,176 +79,185 @@ class Text extends ReactNative.NativeComponent { ellipsizeMode: 'tail', }; + touchableGetPressRectOffset: ?() => PressRetentionOffset; + touchableHandleActivePressIn: ?() => void; + touchableHandleActivePressOut: ?() => void; + touchableHandleLongPress: ?(event: PressEvent) => void; + touchableHandlePress: ?(event: PressEvent) => void; + touchableHandleResponderGrant: ?( + event: SyntheticEvent<>, + dispatchID: string, + ) => void; + touchableHandleResponderMove: ?(event: SyntheticEvent<>) => void; + touchableHandleResponderRelease: ?(event: SyntheticEvent<>) => void; + touchableHandleResponderTerminate: ?(event: SyntheticEvent<>) => void; + touchableHandleResponderTerminationRequest: ?() => boolean; + state = { ...Touchable.Mixin.touchableGetInitialState(), isHighlighted: false, + createResponderHandlers: this._createResponseHandlers.bind(this), + responseHandlers: null, }; - viewConfig = viewConfig; + static getDerivedStateFromProps(nextProps: Props, prevState: State): ?State { + return prevState.responseHandlers == null && isTouchable(nextProps) + ? { + ...prevState, + responseHandlers: prevState.createResponderHandlers(), + } + : null; + } - _handlers: ?Object; + static viewConfig = viewConfig; - _hasPressHandler(): boolean { - return !!this.props.onPress || !!this.props.onLongPress; - } - /** - * These are assigned lazily the first time the responder is set to make plain - * text nodes as cheap as possible. - */ - touchableHandleActivePressIn: ?Function; - touchableHandleActivePressOut: ?Function; - touchableHandlePress: ?Function; - touchableHandleLongPress: ?Function; - touchableHandleResponderGrant: ?Function; - touchableHandleResponderMove: ?Function; - touchableHandleResponderRelease: ?Function; - touchableHandleResponderTerminate: ?Function; - touchableHandleResponderTerminationRequest: ?Function; - touchableGetPressRectOffset: ?Function; - - render(): React.Element { - let newProps = this.props; - if (this.props.onStartShouldSetResponder || this._hasPressHandler()) { - if (!this._handlers) { - this._handlers = { - onStartShouldSetResponder: (): boolean => { - const shouldSetFromProps = - this.props.onStartShouldSetResponder && - this.props.onStartShouldSetResponder(); - const setResponder = shouldSetFromProps || this._hasPressHandler(); - if (setResponder && !this.touchableHandleActivePressIn) { - // Attach and bind all the other handlers only the first time a touch - // actually happens. - for (const key in Touchable.Mixin) { - if (typeof Touchable.Mixin[key] === 'function') { - (this: any)[key] = Touchable.Mixin[key].bind(this); - } - } - this.touchableHandleActivePressIn = () => { - if ( - this.props.suppressHighlighting || - !this._hasPressHandler() - ) { - return; - } - this.setState({ - isHighlighted: true, - }); - }; - - this.touchableHandleActivePressOut = () => { - if ( - this.props.suppressHighlighting || - !this._hasPressHandler() - ) { - return; - } - this.setState({ - isHighlighted: false, - }); - }; - - this.touchableHandlePress = (e: PressEvent) => { - this.props.onPress && this.props.onPress(e); - }; - - this.touchableHandleLongPress = (e: PressEvent) => { - this.props.onLongPress && this.props.onLongPress(e); - }; - - this.touchableGetPressRectOffset = function(): PressRetentionOffset { - return this.props.pressRetentionOffset || PRESS_RECT_OFFSET; - }; - } - return setResponder; - }, - onResponderGrant: function(e: SyntheticEvent<>, dispatchID: string) { - // $FlowFixMe TouchableMixin handlers couldn't actually be null - this.touchableHandleResponderGrant(e, dispatchID); - this.props.onResponderGrant && - this.props.onResponderGrant.apply(this, arguments); - }.bind(this), - onResponderMove: function(e: SyntheticEvent<>) { - // $FlowFixMe TouchableMixin handlers couldn't actually be null - this.touchableHandleResponderMove(e); - this.props.onResponderMove && - this.props.onResponderMove.apply(this, arguments); - }.bind(this), - onResponderRelease: function(e: SyntheticEvent<>) { - // $FlowFixMe TouchableMixin handlers couldn't actually be null - this.touchableHandleResponderRelease(e); - this.props.onResponderRelease && - this.props.onResponderRelease.apply(this, arguments); - }.bind(this), - onResponderTerminate: function(e: SyntheticEvent<>) { - // $FlowFixMe TouchableMixin handlers couldn't actually be null - this.touchableHandleResponderTerminate(e); - this.props.onResponderTerminate && - this.props.onResponderTerminate.apply(this, arguments); - }.bind(this), - onResponderTerminationRequest: function(): boolean { - // Allow touchable or props.onResponderTerminationRequest to deny - // the request - // $FlowFixMe TouchableMixin handlers couldn't actually be null - var allowTermination = this.touchableHandleResponderTerminationRequest(); - if (allowTermination && this.props.onResponderTerminationRequest) { - allowTermination = this.props.onResponderTerminationRequest.apply( - this, - arguments, - ); - } - return allowTermination; - }.bind(this), - }; - } - newProps = { - ...this.props, - ...this._handlers, + render(): React.Node { + let props = this.props; + if (isTouchable(props)) { + props = { + ...props, + ...this.state.responseHandlers, isHighlighted: this.state.isHighlighted, }; } - if (newProps.selectionColor != null) { - newProps = { - ...newProps, - selectionColor: processColor(newProps.selectionColor), + if (props.selectionColor != null) { + props = { + ...props, + selectionColor: processColor(props.selectionColor), }; } - if (Touchable.TOUCH_TARGET_DEBUG && newProps.onPress) { - newProps = { - ...newProps, - style: [this.props.style, {color: 'magenta'}], - }; + if (__DEV__) { + if (Touchable.TOUCH_TARGET_DEBUG && props.onPress != null) { + props = { + ...props, + style: [props.style, {color: 'magenta'}], + }; + } } return ( {hasTextAncestor => hasTextAncestor ? ( - + ) : ( - + ) } ); } + + _createResponseHandlers(): ResponseHandlers { + return { + onStartShouldSetResponder: (): boolean => { + const {onStartShouldSetResponder} = this.props; + const shouldSetResponder = + (onStartShouldSetResponder == null + ? false + : onStartShouldSetResponder()) || isTouchable(this.props); + + if (shouldSetResponder) { + this._attachTouchHandlers(); + } + return shouldSetResponder; + }, + onResponderGrant: (event: SyntheticEvent<>, dispatchID: string): void => { + nullthrows(this.touchableHandleResponderGrant)(event, dispatchID); + if (this.props.onResponderGrant != null) { + this.props.onResponderGrant.apply(this, arguments); + } + }, + onResponderMove: (event: SyntheticEvent<>): void => { + nullthrows(this.touchableHandleResponderMove)(event); + if (this.props.onResponderMove != null) { + this.props.onResponderMove.apply(this, arguments); + } + }, + onResponderRelease: (event: SyntheticEvent<>): void => { + nullthrows(this.touchableHandleResponderRelease)(event); + if (this.props.onResponderRelease != null) { + this.props.onResponderRelease.apply(this, arguments); + } + }, + onResponderTerminate: (event: SyntheticEvent<>): void => { + nullthrows(this.touchableHandleResponderTerminate)(event); + if (this.props.onResponderTerminate != null) { + this.props.onResponderTerminate.apply(this, arguments); + } + }, + onResponderTerminationRequest: (): boolean => { + const {onResponderTerminationRequest} = this.props; + if (!nullthrows(this.touchableHandleResponderTerminationRequest)()) { + return false; + } + if (onResponderTerminationRequest == null) { + return true; + } + return onResponderTerminationRequest(); + }, + }; + } + + /** + * Lazily attaches Touchable.Mixin handlers. + */ + _attachTouchHandlers(): void { + if (this.touchableGetPressRectOffset != null) { + return; + } + for (const key in Touchable.Mixin) { + if (typeof Touchable.Mixin[key] === 'function') { + (this: any)[key] = Touchable.Mixin[key].bind(this); + } + } + this.touchableHandleActivePressIn = (): void => { + if (!this.props.suppressHighlighting && isTouchable(this.props)) { + this.setState({isHighlighted: true}); + } + }; + this.touchableHandleActivePressOut = (): void => { + if (!this.props.suppressHighlighting && isTouchable(this.props)) { + this.setState({isHighlighted: false}); + } + }; + this.touchableHandlePress = (event: PressEvent): void => { + if (this.props.onPress != null) { + this.props.onPress(event); + } + }; + this.touchableHandleLongPress = (event: PressEvent): void => { + if (this.props.onLongPress != null) { + this.props.onLongPress(event); + } + }; + this.touchableGetPressRectOffset = (): PressRetentionOffset => + this.props.pressRetentionOffset == null + ? PRESS_RECT_OFFSET + : this.props.pressRetentionOffset; + } } -var RCTText = createReactNativeComponentClass( +const isTouchable = (props: Props): boolean => + props.onPress != null || + props.onLongPress != null || + props.onStartShouldSetResponder != null; + +const RCTText = createReactNativeComponentClass( viewConfig.uiViewClassName, () => viewConfig, ); -var RCTVirtualText = RCTText; - -if (UIManager.RCTVirtualText) { - RCTVirtualText = createReactNativeComponentClass('RCTVirtualText', () => ({ - validAttributes: { - ...ReactNativeViewAttributes.UIView, - isHighlighted: true, - }, - uiViewClassName: 'RCTVirtualText', - })); -} + +const RCTVirtualText = + UIManager.RCTVirtualText == null + ? RCTText + : createReactNativeComponentClass('RCTVirtualText', () => ({ + validAttributes: { + ...ReactNativeViewAttributes.UIView, + isHighlighted: true, + }, + uiViewClassName: 'RCTVirtualText', + })); module.exports = Text; From e708010d18f938e2d6b6424cfc9485d8e5dd2800 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Wed, 9 May 2018 00:47:57 -0700 Subject: [PATCH 0482/1109] RN: Switch `Text` to `React.forwardRef` Reviewed By: sahrens Differential Revision: D7902262 fbshipit-source-id: 218f95cde6d77f21d9362a2f2bd47c5f83d5ee15 --- .../TouchableHighlight-test.js.snap | 3 --- Libraries/Text/Text.js | 26 +++++++++++++------ jest/mockComponent.js | 4 +++ jest/setup.js | 2 +- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/Libraries/Components/Touchable/__tests__/__snapshots__/TouchableHighlight-test.js.snap b/Libraries/Components/Touchable/__tests__/__snapshots__/TouchableHighlight-test.js.snap index 4596f0307d0e8d..6028d74aaa8a21 100644 --- a/Libraries/Components/Touchable/__tests__/__snapshots__/TouchableHighlight-test.js.snap +++ b/Libraries/Components/Touchable/__tests__/__snapshots__/TouchableHighlight-test.js.snap @@ -22,9 +22,6 @@ exports[`TouchableHighlight renders correctly 1`] = ` tvParallaxProperties={undefined} > Touchable diff --git a/Libraries/Text/Text.js b/Libraries/Text/Text.js index adde971751b74b..1dcac7c1a759dc 100644 --- a/Libraries/Text/Text.js +++ b/Libraries/Text/Text.js @@ -11,7 +11,6 @@ 'use strict'; const React = require('React'); -const ReactNative = require('ReactNative'); const ReactNativeViewAttributes = require('ReactNativeViewAttributes'); const TextAncestor = require('TextAncestor'); const TextPropTypes = require('TextPropTypes'); @@ -23,6 +22,7 @@ const nullthrows = require('fbjs/lib/nullthrows'); const processColor = require('processColor'); import type {PressEvent} from 'CoreEventTypes'; +import type {NativeComponent} from 'ReactNative'; import type {PressRetentionOffset, TextProps} from 'TextProps'; type ResponseHandlers = $ReadOnly<{| @@ -34,7 +34,10 @@ type ResponseHandlers = $ReadOnly<{| onResponderTerminationRequest: () => boolean, |}>; -type Props = TextProps; +type Props = $ReadOnly<{ + ...TextProps, + forwardedRef: ?React.Ref>, +}>; type State = {| touchable: {| @@ -70,9 +73,7 @@ const viewConfig = { * * See https://facebook.github.io/react-native/docs/text.html */ -class Text extends ReactNative.NativeComponent { - static propTypes = TextPropTypes; - +class TouchableText extends React.Component { static defaultProps = { accessible: true, allowFontScaling: true, @@ -138,10 +139,10 @@ class Text extends ReactNative.NativeComponent { {hasTextAncestor => hasTextAncestor ? ( - + ) : ( - + ) } @@ -260,4 +261,13 @@ const RCTVirtualText = uiViewClassName: 'RCTVirtualText', })); -module.exports = Text; +// $FlowFixMe - TODO T29156721 `React.forwardRef` is not defined in Flow, yet. +const Text = React.forwardRef((props, ref) => ( + +)); +Text.displayName = 'Text'; + +// TODO: Deprecate this. +Text.propTypes = TextPropTypes; + +module.exports = ((Text: any): NativeComponent); diff --git a/jest/mockComponent.js b/jest/mockComponent.js index bdc16d805dcbcc..e22c34ccaa4391 100644 --- a/jest/mockComponent.js +++ b/jest/mockComponent.js @@ -28,6 +28,10 @@ module.exports = (moduleName, instanceMethods) => { } }; + if (RealComponent.propTypes != null) { + Component.propTypes = RealComponent.propTypes; + } + if (instanceMethods != null) { Object.assign(Component.prototype, instanceMethods); } diff --git a/jest/setup.js b/jest/setup.js index 2aef9f1b39fe58..18cb7dfbddd7f6 100644 --- a/jest/setup.js +++ b/jest/setup.js @@ -35,7 +35,7 @@ jest.setMock('ErrorUtils', require('ErrorUtils')); jest .mock('InitializeCore', () => {}) .mock('Image', () => mockComponent('Image')) - .mock('Text', () => mockComponent('Text')) + .mock('Text', () => mockComponent('Text', MockNativeMethods)) .mock('TextInput', () => mockComponent('TextInput')) .mock('Modal', () => mockComponent('Modal')) .mock('View', () => mockComponent('View', MockNativeMethods)) From c18cf5bd4a130534e1019722453443c5e610a406 Mon Sep 17 00:00:00 2001 From: Payton Yao Date: Wed, 9 May 2018 10:26:06 -0700 Subject: [PATCH 0483/1109] Prevent unintended VirtualizedList high priority rendering Summary: VirtualizedList sets high priority rendering when scrolled to the top of a list even if the bottom of the rendered list is still far away and there's nothing further to render above. This causes severe non-responsiveness while dozens of items are waiting to be rendered and user inputs can't get through. The fix is simply to not consider it high priority to render more items when we reach the top and the first item has already been rendered, or when we reach the bottom and the last item has been rendered. The code change just splits the two cases (hitting the top and bottom) instead of combining them into one. I wrote a small application that switches between two FlatLists. Demo of the original VirtualizedList I'm clicking pretty often on the button, but you can see that it only switches lists a split second after the rendering is all done because the javascript thread was being blocked. Demo of the fixed VirtualizedList You can see this one is significantly more responsive than the previous one. The source code for the demo application is available [here](https://gist.github.com/jabbawookiees/ba93a4e7b4f9b8f3acbc157e4fd04877) [ GENERAL ] [ ENHANCEMENT ] [ Libraries/Lists/VirtualizedList.js ] - Prevent high priority rendering at the top or bottom of a list. Closes https://github.com/facebook/react-native/pull/19081 Differential Revision: D7933994 Pulled By: sahrens fbshipit-source-id: 13c9f73baeb3487620b720854a753287ac0aa1fa --- Libraries/Lists/VirtualizedList.js | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/Libraries/Lists/VirtualizedList.js b/Libraries/Lists/VirtualizedList.js index ca6d9fc7fe56e4..7c54eba55c397b 100644 --- a/Libraries/Lists/VirtualizedList.js +++ b/Libraries/Lists/VirtualizedList.js @@ -1344,19 +1344,23 @@ class VirtualizedList extends React.PureComponent { const {offset, visibleLength, velocity} = this._scrollMetrics; const itemCount = this.props.getItemCount(this.props.data); let hiPri = false; - if (first > 0 || last < itemCount - 1) { + const scrollingThreshold = + /* $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. */ + this.props.onEndReachedThreshold * visibleLength / 2; + // Mark as high priority if we're close to the start of the first item + // But only if there are items before the first rendered item + if (first > 0) { const distTop = offset - this._getFrameMetricsApprox(first).offset; + hiPri = hiPri || distTop < 0 || (velocity < -2 && distTop < scrollingThreshold); + } + // Mark as high priority if we're close to the end of the last item + // But only if there are items after the last rendered item + if (last < itemCount - 1) { const distBottom = this._getFrameMetricsApprox(last).offset - (offset + visibleLength); - const scrollingThreshold = - /* $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. */ - this.props.onEndReachedThreshold * visibleLength / 2; - hiPri = - Math.min(distTop, distBottom) < 0 || - (velocity < -2 && distTop < scrollingThreshold) || - (velocity > 2 && distBottom < scrollingThreshold); + hiPri = hiPri || distBottom < 0 || (velocity > 2 && distBottom < scrollingThreshold); } // Only trigger high-priority updates if we've actually rendered cells, // and with that size estimate, accurately compute how many cells we should render. From 16b955bd1f6b321cbe88cc628c5e8bdd1ba57cc2 Mon Sep 17 00:00:00 2001 From: Andrew Jack Date: Wed, 9 May 2018 13:04:40 -0700 Subject: [PATCH 0484/1109] Fix Android modal crash: android.view.WindowManager$BadTokenException Summary: Fixes a crash with the Android Dialog. This occurs when the Activity is finishing or has been removed and React Native requests the modal to be shown. Stacktrace here: ``` Caused by android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@f125ea3 is not valid; is your activity running? at android.view.ViewRootImpl.setView(ViewRootImpl.java:683) at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:319) at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:85) at android.app.Dialog.show(Dialog.java:326) at com.facebook.react.views.modal.ReactModalHostView.showOrUpdate(ReactModalHostView.java:256) at com.facebook.react.views.modal.ReactModalHostManager.onAfterUpdateTransaction(ReactModalHostManager.java:107) at com.facebook.react.views.modal.ReactModalHostManager.onAfterUpdateTransaction(ReactModalHostManager.java:28) at com.facebook.react.uimanager.ViewManager.updateProperties(ViewManager.java:35) at com.facebook.react.uimanager.NativeViewHierarchyManager.createView(NativeViewHierarchyManager.java:233) at com.facebook.react.uimanager.UIViewOperationQueue$CreateViewOperation.execute(UIViewOperationQueue.java:153) at com.facebook.react.uimanager.UIViewOperationQueue$1.run(UIViewOperationQueue.java:816) at com.facebook.react.uimanager.UIViewOperationQueue.flushPendingBatches(UIViewOperationQueue.java:929) at com.facebook.react.uimanager.UIViewOperationQueue.access$2100(UIViewOperationQueue.java:47) at com.facebook.react.uimanager.UIViewOperationQueue$2.runGuarded(UIViewOperationQueue.java:887) at com.facebook.react.bridge.GuardedRunnable.run(GuardedRunnable.java:21) at android.os.Handler.handleCallback(Handler.java:815) at android.os.Handler.dispatchMessage(Handler.java:104) at android.os.Looper.loop(Looper.java:207) at android.app.ActivityThread.main(ActivityThread.java:5728) at java.lang.reflect.Method.invoke(Method.java) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:679) ``` Related issues: #18570 & #18634 mdvacca added to this file in https://github.com/facebook/react-native/commit/e5c2a66897b9c562c549e63adcf70783ea34c418 Doesn't look like the issue was introduced in the above change, but it masks the issue. The wrapping if block should not allow a null activity to display a dialog. Run sample app on Android and display dialog when app is about to close. [ANDROID] [BUGFIX] [Modal] - Fix Android BadTokenException crash Closes https://github.com/facebook/react-native/pull/18996 Differential Revision: D7938147 Pulled By: hramos fbshipit-source-id: f4ffd1746304d6184d727339072a7e926ffdaf39 --- .../java/com/facebook/react/views/modal/ReactModalHostView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java index 00eac510ab8f35..ab0491fe4619fd 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java @@ -250,7 +250,7 @@ public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { if (mHardwareAccelerated) { mDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); } - if (currentActivity == null || !currentActivity.isFinishing()) { + if (currentActivity != null && !currentActivity.isFinishing()) { mDialog.show(); } } From 8799047dd0bc8dd93f05fa97d4b9a59f7dfeb324 Mon Sep 17 00:00:00 2001 From: Spencer Ahrens Date: Wed, 9 May 2018 13:09:44 -0700 Subject: [PATCH 0485/1109] Fix Modal + FlatList scrolling Summary: `FlatList` (actually `VirtualizedList`) allows recursive nesting of itself for easy and complex composition of lists such that it can support seemless virtualization and VPV events. It does this by only rendering a `ScrollView` for the outermost `VirtualizedList` and simply stacking `View`s for all the internal ones. However, if a `Modal` is in a `FlatList` and also hosts a `FlatList`, e.g.: ``` } /> ``` Then React context will propogate through to the inner `FlatList` and cause it to render as a plain `View`. Because the `Modal` actually portals the views into a different native hierarchy, one without a `ScrollView`, the `FlatList` won't scroll as expected. The fix is to wipe out the context - not sure if there is a better way, but this doesn't seem terrible. Differential Revision: D7863625 fbshipit-source-id: 38f41d72ed32b9f0eb1c9c82893f21d83a83f9ad --- Libraries/Modal/Modal.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Libraries/Modal/Modal.js b/Libraries/Modal/Modal.js index b1cc4a1cb7bb80..52ed8c7a2b9e87 100644 --- a/Libraries/Modal/Modal.js +++ b/Libraries/Modal/Modal.js @@ -129,6 +129,18 @@ class Modal extends React.Component { this._identifier = uniqueModalIdentifier++; } + static childContextTypes = { + virtualizedList: PropTypes.object, + }; + + getChildContext() { + // Reset the context so VirtualizedList doesn't get confused by nesting + // in the React tree that doesn't reflect the native component heirarchy. + return { + virtualizedList: null, + }; + } + componentDidMount() { if (ModalEventEmitter) { this._eventSubscription = ModalEventEmitter.addListener( From 11cc7be821683e258b3adf5d09f46e0b54fb10b7 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Wed, 9 May 2018 15:18:18 -0700 Subject: [PATCH 0486/1109] RN: Switch `ProgressBarAndroid` to `React.forwardRef` Reviewed By: sahrens Differential Revision: D7904339 fbshipit-source-id: a4fe54acee7af12f1bc9b7c0d5e02a690f57ca0d --- .../ProgressBarAndroid.android.js | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js b/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js index db20d579db0a5f..9ee432f56bd5a2 100644 --- a/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js +++ b/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js @@ -4,7 +4,9 @@ * 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 ColorPropType = require('ColorPropType'); @@ -30,7 +32,9 @@ const indeterminateType = function(props, propName, componentName, ...rest) { const indeterminate = props[propName]; const styleAttr = props.styleAttr; if (!indeterminate && styleAttr !== 'Horizontal') { - return new Error('indeterminate=false is only valid for styleAttr=Horizontal'); + return new Error( + 'indeterminate=false is only valid for styleAttr=Horizontal', + ); } }; @@ -38,8 +42,8 @@ const indeterminateType = function(props, propName, componentName, ...rest) { }; /** - * React component that wraps the Android-only `ProgressBar`. This component is used to indicate - * that the app is loading or there is some activity in the app. + * React component that wraps the Android-only `ProgressBar`. This component is + * used to indicate that the app is loading or there is activity in the app. * * Example: * @@ -60,7 +64,7 @@ const indeterminateType = function(props, propName, componentName, ...rest) { * }, * ``` */ -class ProgressBarAndroid extends ReactNative.NativeComponent { +class ProgressBarAndroid extends React.Component { static propTypes = { ...ViewPropTypes, @@ -106,7 +110,8 @@ class ProgressBarAndroid extends ReactNative.NativeComponent { }; render() { - return ; + const {forwardedRef, ...props} = this.props; + return ; } } @@ -117,7 +122,9 @@ const AndroidProgressBar = requireNativeComponent( nativeOnly: { animating: true, }, - } + }, ); -module.exports = ProgressBarAndroid; +module.exports = React.forwardRef((props, ref) => ( + +)); From 522640cf3aebc30580dd492d8c4eb863dac3d8b4 Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Wed, 9 May 2018 15:51:30 -0700 Subject: [PATCH 0487/1109] OSS exclude Xcode artifacts in ReactCommon subdir Summary: ReactCommon subdir is supposed to be focused on C++, so Xcode projects shouldn't creep in. Reviewed By: PeteTheHeat Differential Revision: D7939858 fbshipit-source-id: 2e90491bdaec92829485aded071f74d004b24b21 --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 6b290712dbd6d4..1b46fc1ee1ba3d 100644 --- a/.gitignore +++ b/.gitignore @@ -66,3 +66,7 @@ package-lock.json /coverage /third-party + +# ReactCommon subdir shouldn't have Xcode project +/ReactCommon/**/*.xcodeproj + From d11fdcfb9305a57d0256aad045624a5a06c0077c Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Wed, 9 May 2018 20:16:30 -0700 Subject: [PATCH 0488/1109] Prevent console logging on iOS 11.3+ within WebSocket Summary: Fixes Xcode console output for web socket connections. Apple uses OSLog for logging within libnetworking starting 11.3+. The old way we hook into logging to prevent it will not work anymore. Let's hook into `__nwlog_pack` that is exclusively used by libnetworking and prevent the logging in there. Closes https://github.com/facebook/react-native/pull/18948 Reviewed By: fkgozali Differential Revision: D7940969 Pulled By: mmmulani fbshipit-source-id: a61beea34377044bfad7e3c446b2ec1138d6d1f5 --- .../WebSocket/RCTReconnectingWebSocket.m | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Libraries/WebSocket/RCTReconnectingWebSocket.m b/Libraries/WebSocket/RCTReconnectingWebSocket.m index 04e5dee57b67e7..55ed86f7b22922 100644 --- a/Libraries/WebSocket/RCTReconnectingWebSocket.m +++ b/Libraries/WebSocket/RCTReconnectingWebSocket.m @@ -19,6 +19,29 @@ #if RCT_DEV // Only supported in dev mode +#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 100300 /* __IPHONE_10_3 */ + +// From https://github.com/apple/swift/blob/ad40c770bfe372f879b530443a3d94761fe258a6/stdlib/public/SDK/os/os_log.m +typedef struct os_log_pack_s { + uint64_t olp_continuous_time; + struct timespec olp_wall_time; + const void *olp_mh; + const void *olp_pc; + const char *olp_format; + uint8_t olp_data[0]; +} os_log_pack_s, *os_log_pack_t; + +static void (*orig__nwlog_pack)(os_log_pack_t pack, os_log_type_t logType); + +static void my__nwlog_pack(os_log_pack_t pack, os_log_type_t logType) +{ + if (logType == OS_LOG_TYPE_ERROR && strstr(pack->olp_format, "Connection has no connected handler") == NULL) { + orig__nwlog_pack(pack, logType); + } +} + +#endif /* __IPHONE_10_3 */ + static void (*orig_nwlog_legacy_v)(int, char*, va_list); static void my_nwlog_legacy_v(int level, char *format, va_list args) { @@ -63,6 +86,11 @@ + (void)load rebind_symbols((struct rebinding[1]){ {"nwlog_legacy_v", my_nwlog_legacy_v, (void *)&orig_nwlog_legacy_v} }, 1); +#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 100300 /* __IPHONE_10_3 */ + rebind_symbols((struct rebinding[1]){ + {"__nwlog_pack", my__nwlog_pack, (void *)&orig__nwlog_pack} + }, 1); +#endif /* __IPHONE_10_3 */ #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */ rebind_symbols((struct rebinding[1]){ {"_os_log_error_impl", my_os_log_error_impl, (void *)&orig_os_log_error_impl} From ef258b0106652e9cd60f41058d610865251559fa Mon Sep 17 00:00:00 2001 From: Marc Horowitz Date: Wed, 9 May 2018 22:01:34 -0700 Subject: [PATCH 0489/1109] Remove unnecessary #includes to reduce dependencies Reviewed By: davidaurelio Differential Revision: D7803909 fbshipit-source-id: 2ccafdbfcb786c4c5f703714fb0c92cda1026cef --- ReactAndroid/src/main/jni/react/jni/JInspector.cpp | 1 - ReactAndroid/src/main/jni/react/jni/OnLoad.cpp | 5 ----- ReactCommon/cxxreact/JSModulesUnbundle.h | 7 +++++-- ReactCommon/cxxreact/RAMBundleRegistry.h | 3 +-- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/ReactAndroid/src/main/jni/react/jni/JInspector.cpp b/ReactAndroid/src/main/jni/react/jni/JInspector.cpp index 47000279487ed7..1d326e3e7337de 100644 --- a/ReactAndroid/src/main/jni/react/jni/JInspector.cpp +++ b/ReactAndroid/src/main/jni/react/jni/JInspector.cpp @@ -1,7 +1,6 @@ // Copyright 2004-present Facebook. All Rights Reserved. #include "JInspector.h" -#include #ifdef WITH_INSPECTOR diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp index 81cc8f33419641..7e7184e7112488 100644 --- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp +++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp @@ -2,14 +2,9 @@ #include -#include -#include -#include #include #include #include -#include -#include #include "AndroidJSCFactory.h" #include "CatalystInstanceImpl.h" diff --git a/ReactCommon/cxxreact/JSModulesUnbundle.h b/ReactCommon/cxxreact/JSModulesUnbundle.h index bbf3a6c8d8c020..83a997f5495d49 100644 --- a/ReactCommon/cxxreact/JSModulesUnbundle.h +++ b/ReactCommon/cxxreact/JSModulesUnbundle.h @@ -7,12 +7,11 @@ #include #include -#include namespace facebook { namespace react { -class JSModulesUnbundle : noncopyable { +class JSModulesUnbundle { /** * Represents the set of JavaScript modules that the application consists of. * The source code of each module can be retrieved by module ID. @@ -31,8 +30,12 @@ class JSModulesUnbundle : noncopyable { std::string name; std::string code; }; + JSModulesUnbundle() {} virtual ~JSModulesUnbundle() {} virtual Module getModule(uint32_t moduleId) const = 0; + +private: + JSModulesUnbundle(const JSModulesUnbundle&) = delete; }; } diff --git a/ReactCommon/cxxreact/RAMBundleRegistry.h b/ReactCommon/cxxreact/RAMBundleRegistry.h index 9fb546066bed36..6314dce036edf8 100644 --- a/ReactCommon/cxxreact/RAMBundleRegistry.h +++ b/ReactCommon/cxxreact/RAMBundleRegistry.h @@ -9,7 +9,6 @@ #include #include -#include #ifndef RN_EXPORT #define RN_EXPORT __attribute__((visibility("default"))) @@ -18,7 +17,7 @@ namespace facebook { namespace react { -class RN_EXPORT RAMBundleRegistry : noncopyable { +class RN_EXPORT RAMBundleRegistry { public: constexpr static uint32_t MAIN_BUNDLE_ID = 0; From d1d09c208acb623b3759d604a1e90d9faca28eb1 Mon Sep 17 00:00:00 2001 From: Marc Horowitz Date: Wed, 9 May 2018 22:01:36 -0700 Subject: [PATCH 0490/1109] Remove unused JS Sampling Profiler code Reviewed By: cwdick Differential Revision: D7803915 fbshipit-source-id: 3edb42d449ff7b272f7d25ac8f16a646839f8c20 --- .../react/devsupport/DevServerHelper.java | 7 --- .../devsupport/DevSupportManagerImpl.java | 23 -------- .../facebook/react/packagerconnection/BUCK | 3 +- .../SamplingProfilerPackagerMethod.java | 53 ------------------- .../main/jni/packagerconnection/Android.mk | 29 ---------- .../src/main/jni/packagerconnection/BUCK | 35 ------------ .../JSPackagerClientResponder.cpp | 32 ----------- .../JSPackagerClientResponder.h | 22 -------- .../main/jni/packagerconnection/OnLoad.cpp | 17 ------ .../SamplingProfilerJniMethod.cpp | 53 ------------------- .../SamplingProfilerJniMethod.h | 33 ------------ 11 files changed, 1 insertion(+), 306 deletions(-) delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/packagerconnection/SamplingProfilerPackagerMethod.java delete mode 100644 ReactAndroid/src/main/jni/packagerconnection/Android.mk delete mode 100644 ReactAndroid/src/main/jni/packagerconnection/BUCK delete mode 100644 ReactAndroid/src/main/jni/packagerconnection/JSPackagerClientResponder.cpp delete mode 100644 ReactAndroid/src/main/jni/packagerconnection/JSPackagerClientResponder.h delete mode 100644 ReactAndroid/src/main/jni/packagerconnection/OnLoad.cpp delete mode 100644 ReactAndroid/src/main/jni/packagerconnection/SamplingProfilerJniMethod.cpp delete mode 100644 ReactAndroid/src/main/jni/packagerconnection/SamplingProfilerJniMethod.h 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 f0638b0b41c2ac..3fb603f9c519ee 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java @@ -81,7 +81,6 @@ public interface PackagerCommandListener { void onPackagerReloadCommand(); void onPackagerDevMenuCommand(); void onCaptureHeapCommand(final Responder responder); - void onPokeSamplingProfilerCommand(final Responder responder); } public interface SymbolicationListener { @@ -163,12 +162,6 @@ public void onRequest(@Nullable Object params, Responder responder) { commandListener.onCaptureHeapCommand(responder); } }); - handlers.put("pokeSamplingProfiler", new RequestOnlyHandler() { - @Override - public void onRequest(@Nullable Object params, Responder responder) { - commandListener.onPokeSamplingProfilerCommand(responder); - } - }); handlers.putAll(new FileIoHandler().handlers()); ConnectionCallback onPackagerConnectedCallback = 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 241bd0dbf1ddb3..b951ef2ff22213 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java @@ -841,29 +841,6 @@ public void run() { }); } - @Override - public void onPokeSamplingProfilerCommand(final Responder responder) { - UiThreadUtil.runOnUiThread(new Runnable() { - @Override - public void run() { - if (mCurrentContext == null) { - responder.error("JSCContext is missing, unable to profile"); - return; - } - try { - JavaScriptContextHolder jsContext = mCurrentContext.getJavaScriptContextHolder(); - synchronized (jsContext) { - Class clazz = Class.forName("com.facebook.react.packagerconnection.SamplingProfilerPackagerMethod"); - RequestHandler handler = (RequestHandler)clazz.getConstructor(long.class).newInstance(jsContext.get()); - handler.onRequest(null, responder); - } - } catch (Exception e) { - // Module not present - } - } - }); - } - private void handleCaptureHeap(final Responder responder) { if (mCurrentContext == null) { return; diff --git a/ReactAndroid/src/main/java/com/facebook/react/packagerconnection/BUCK b/ReactAndroid/src/main/java/com/facebook/react/packagerconnection/BUCK index 540e9b3496c43f..3b27ea6f362622 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/packagerconnection/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/packagerconnection/BUCK @@ -4,7 +4,6 @@ rn_android_library( name = "packagerconnection", srcs = glob( ["**/*.java"], - excludes = ["SamplingProfilerPackagerMethod.java"] if IS_OSS_BUILD else [], ), visibility = [ "PUBLIC", @@ -19,5 +18,5 @@ rn_android_library( react_native_dep("third-party/java/okhttp:okhttp3"), react_native_dep("third-party/java/okio:okio"), react_native_target("java/com/facebook/react/modules/systeminfo:systeminfo-moduleless"), - ] + ([react_native_target("jni/packagerconnection:jni")] if not IS_OSS_BUILD else []), + ], ) diff --git a/ReactAndroid/src/main/java/com/facebook/react/packagerconnection/SamplingProfilerPackagerMethod.java b/ReactAndroid/src/main/java/com/facebook/react/packagerconnection/SamplingProfilerPackagerMethod.java deleted file mode 100644 index f1de5e198efe87..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/packagerconnection/SamplingProfilerPackagerMethod.java +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * - * 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.packagerconnection; - -import javax.annotation.Nullable; - -import android.os.Looper; - -import com.facebook.jni.HybridData; -import com.facebook.proguard.annotations.DoNotStrip; -import com.facebook.soloader.SoLoader; - -public class SamplingProfilerPackagerMethod extends RequestOnlyHandler { - static { - SoLoader.loadLibrary("packagerconnectionjnifb"); - } - - final private static class SamplingProfilerJniMethod { - - @DoNotStrip - private final HybridData mHybridData; - - public SamplingProfilerJniMethod(long javaScriptContext) { - if (Looper.myLooper() == null) { - Looper.prepare(); - } - - mHybridData = initHybrid(javaScriptContext); - } - - @DoNotStrip - private native void poke(Responder responder); - - @DoNotStrip - private static native HybridData initHybrid(long javaScriptContext); - } - - private SamplingProfilerJniMethod mJniMethod; - - public SamplingProfilerPackagerMethod(long javaScriptContext) { - mJniMethod = new SamplingProfilerJniMethod(javaScriptContext); - } - - @Override - public void onRequest(@Nullable Object params, Responder responder) { - mJniMethod.poke(responder); - } -} diff --git a/ReactAndroid/src/main/jni/packagerconnection/Android.mk b/ReactAndroid/src/main/jni/packagerconnection/Android.mk deleted file mode 100644 index ba09a7e689d447..00000000000000 --- a/ReactAndroid/src/main/jni/packagerconnection/Android.mk +++ /dev/null @@ -1,29 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := packagerconnectionjnifb - -LOCAL_SRC_FILES := \ - JSPackagerClientResponder.h \ - SamplingProfilerPackagerMethod.cpp \ - -LOCAL_C_INCLUDES := $(LOCAL_PATH) -LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../ - -LOCAL_CFLAGS += -Wall -Werror -fvisibility=hidden -fexceptions -frtti -CXX11_FLAGS := -std=c++11 -LOCAL_CFLAGS += $(CXX11_FLAGS) -LOCAL_EXPORT_CPPFLAGS := $(CXX11_FLAGS) - -LOCAL_LDLIBS += -landroid -LOCAL_SHARED_LIBRARIES := libfolly_json libfbjni libjsc libglog_init - -include $(BUILD_SHARED_LIBRARY) - -$(call import-module,fb) -$(call import-module,jsc) -$(call import-module,folly) -$(call import-module,fbgloginit) -$(call import-module,jni) -$(call import-module,jscwrapper) diff --git a/ReactAndroid/src/main/jni/packagerconnection/BUCK b/ReactAndroid/src/main/jni/packagerconnection/BUCK deleted file mode 100644 index caede999292be2..00000000000000 --- a/ReactAndroid/src/main/jni/packagerconnection/BUCK +++ /dev/null @@ -1,35 +0,0 @@ -load("//ReactNative:DEFS.bzl", "rn_xplat_cxx_library", "FBJNI_TARGET", "ANDROID_JSC_DEPS", "APPLE_JSC_DEPS", "ANDROID", "IS_OSS_BUILD", "react_native_xplat_target") - -rn_xplat_cxx_library( - name = "jni", - srcs = glob(["*.cpp"]), - headers = glob( - ["*.h"], - ), - header_namespace = "", - compiler_flags = [ - "-Wall", - "-Werror", - "-fexceptions", - "-std=c++1y", - "-frtti", - ], - fbandroid_deps = ANDROID_JSC_DEPS, - fbobjc_deps = APPLE_JSC_DEPS, - platforms = ANDROID, - preprocessor_flags = [ - "-DLOG_TAG=\"PackagerConnectionJNI\"", - "-DWITH_FBSYSTRACE=1", - "-DWITH_INSPECTOR=1", - ], - soname = "libpackagerconnectionjnifb.$(ext)", - visibility = [ - "PUBLIC", - ], - deps = ([ - FBJNI_TARGET, - "xplat//folly:molly", - react_native_xplat_target("jschelpers:jschelpers"), - react_native_xplat_target("jsinspector:jsinspector"), - ]) if not IS_OSS_BUILD else [], -) diff --git a/ReactAndroid/src/main/jni/packagerconnection/JSPackagerClientResponder.cpp b/ReactAndroid/src/main/jni/packagerconnection/JSPackagerClientResponder.cpp deleted file mode 100644 index 786af299cc751a..00000000000000 --- a/ReactAndroid/src/main/jni/packagerconnection/JSPackagerClientResponder.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#include "JSPackagerClientResponder.h" - -#include - -using namespace facebook::jni; - -namespace facebook { -namespace react { - -void JSPackagerClientResponder::respond(alias_ref result) { - static auto method = - javaClassStatic()->getMethod)>("respond"); - method(self(), result); -} - -void JSPackagerClientResponder::respond(const std::string &result) { - respond(LocalString(result).string()); -} - -void JSPackagerClientResponder::error(alias_ref result) { - static auto method = - javaClassStatic()->getMethod)>("error"); - method(self(), result); -} - -void JSPackagerClientResponder::error(const std::string &result) { - error(LocalString(result).string()); -} -} -} diff --git a/ReactAndroid/src/main/jni/packagerconnection/JSPackagerClientResponder.h b/ReactAndroid/src/main/jni/packagerconnection/JSPackagerClientResponder.h deleted file mode 100644 index 243a409c78c0c1..00000000000000 --- a/ReactAndroid/src/main/jni/packagerconnection/JSPackagerClientResponder.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#include - -namespace facebook { -namespace react { - -class JSPackagerClientResponder - : public jni::JavaClass { -public: - static constexpr auto kJavaDescriptor = - "Lcom/facebook/react/packagerconnection/Responder;"; - - void respond(jni::alias_ref result); - void respond(const std::string& result); - - void error(jni::alias_ref result); - void error(const std::string& result); -}; - -} -} diff --git a/ReactAndroid/src/main/jni/packagerconnection/OnLoad.cpp b/ReactAndroid/src/main/jni/packagerconnection/OnLoad.cpp deleted file mode 100644 index d9b6b8cad443ce..00000000000000 --- a/ReactAndroid/src/main/jni/packagerconnection/OnLoad.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#include -#include - -#include "SamplingProfilerJniMethod.h" - -using namespace facebook::jni; - -namespace facebook { -namespace react { - -extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { - return initialize(vm, [] { SamplingProfilerJniMethod::registerNatives(); }); -} -} -} diff --git a/ReactAndroid/src/main/jni/packagerconnection/SamplingProfilerJniMethod.cpp b/ReactAndroid/src/main/jni/packagerconnection/SamplingProfilerJniMethod.cpp deleted file mode 100644 index 738d3e4fafefd4..00000000000000 --- a/ReactAndroid/src/main/jni/packagerconnection/SamplingProfilerJniMethod.cpp +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#include "SamplingProfilerJniMethod.h" - -#include - -#include -#include -#include - -using namespace facebook::jni; - -namespace facebook { -namespace react { - -/* static */ jni::local_ref -SamplingProfilerJniMethod::initHybrid(jni::alias_ref, - jlong javaScriptContext) { - return makeCxxInstance(javaScriptContext); -} - -/* static */ void SamplingProfilerJniMethod::registerNatives() { - registerHybrid( - {makeNativeMethod("initHybrid", SamplingProfilerJniMethod::initHybrid), - makeNativeMethod("poke", SamplingProfilerJniMethod::poke)}); -} - -SamplingProfilerJniMethod::SamplingProfilerJniMethod(jlong javaScriptContext) { - context_ = reinterpret_cast(javaScriptContext); -} - -void SamplingProfilerJniMethod::poke( - jni::alias_ref responder) { - if (!JSC_JSSamplingProfilerEnabled(context_)) { - responder->error("The JSSamplingProfiler is disabled. See this " - "https://fburl.com/u4lw7xeq for some help"); - return; - } - - JSValueRef jsResult = JSC_JSPokeSamplingProfiler(context_); - if (JSC_JSValueGetType(context_, jsResult) == kJSTypeNull) { - responder->respond("started"); - } else { - JSStringRef resultStrRef = JSValueToStringCopy(context_, jsResult, nullptr); - size_t length = JSStringGetLength(resultStrRef); - char buffer[length + 1]; - JSStringGetUTF8CString(resultStrRef, buffer, length + 1); - JSStringRelease(resultStrRef); - responder->respond(buffer); - } -} -} -} diff --git a/ReactAndroid/src/main/jni/packagerconnection/SamplingProfilerJniMethod.h b/ReactAndroid/src/main/jni/packagerconnection/SamplingProfilerJniMethod.h deleted file mode 100644 index da83ec4cf5a7b2..00000000000000 --- a/ReactAndroid/src/main/jni/packagerconnection/SamplingProfilerJniMethod.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#include -#include - -#include "JSPackagerClientResponder.h" - -namespace facebook { -namespace react { - -class SamplingProfilerJniMethod - : public jni::HybridClass { -public: - static constexpr auto kJavaDescriptor = - "Lcom/facebook/react/packagerconnection/" - "SamplingProfilerPackagerMethod$SamplingProfilerJniMethod;"; - - static jni::local_ref initHybrid(jni::alias_ref jthis, - jlong javaScriptContext); - - static void registerNatives(); - -private: - friend HybridBase; - - explicit SamplingProfilerJniMethod(jlong javaScriptContext); - - void poke(jni::alias_ref responder); - - JSGlobalContextRef context_; -}; -} -} From 09f3d7ab492409a0d60f92c09a80e7f9b90d664a Mon Sep 17 00:00:00 2001 From: Marc Horowitz Date: Wed, 9 May 2018 22:01:48 -0700 Subject: [PATCH 0491/1109] reformat JSCExecutor.cpp Reviewed By: fromcelticpark Differential Revision: D7803913 fbshipit-source-id: fc4637d0f9ab8c01f2f257e34e435c9573ecf948 --- ReactCommon/cxxreact/JSCExecutor.cpp | 1275 ++++++++++++++------------ 1 file changed, 676 insertions(+), 599 deletions(-) diff --git a/ReactCommon/cxxreact/JSCExecutor.cpp b/ReactCommon/cxxreact/JSCExecutor.cpp index 01a68fb4d5a7dc..c88da5f5b7a318 100644 --- a/ReactCommon/cxxreact/JSCExecutor.cpp +++ b/ReactCommon/cxxreact/JSCExecutor.cpp @@ -2,22 +2,22 @@ #include "JSCExecutor.h" +#include +#include +#include #include #include -#include #include #include #include -#include -#include #include #include #include #include -#include #include #include +#include #include #include #include @@ -44,682 +44,759 @@ #endif namespace facebook { - namespace react { - - namespace { - - template - inline JSObjectCallAsFunctionCallback exceptionWrapMethod() { - struct funcWrapper { - static JSValueRef call( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef *exception) { - try { - auto executor = Object::getGlobalObject(ctx).getPrivate(); - if (executor && executor->getJavaScriptContext()) { // Executor not invalidated - return (executor->*method)(argumentCount, arguments); - } - } catch (...) { - *exception = translatePendingCppExceptionToJSError(ctx, function); - } - return Value::makeUndefined(ctx); - } - }; - - return &funcWrapper::call; - } - - template - inline JSObjectGetPropertyCallback exceptionWrapMethod() { - struct funcWrapper { - static JSValueRef call( - JSContextRef ctx, - JSObjectRef object, - JSStringRef propertyName, - JSValueRef *exception) { - try { - auto executor = Object::getGlobalObject(ctx).getPrivate(); - if (executor && executor->getJavaScriptContext()) { // Executor not invalidated - return (executor->*method)(object, propertyName); - } - } catch (...) { - *exception = translatePendingCppExceptionToJSError(ctx, object); - } - return Value::makeUndefined(ctx); - } - }; - - return &funcWrapper::call; +namespace react { + +namespace { + +template +inline JSObjectCallAsFunctionCallback exceptionWrapMethod() { + struct funcWrapper { + static JSValueRef call( + JSContextRef ctx, + JSObjectRef function, + JSObjectRef thisObject, + size_t argumentCount, + const JSValueRef arguments[], + JSValueRef* exception) { + try { + auto executor = Object::getGlobalObject(ctx).getPrivate(); + if (executor && + executor->getJavaScriptContext()) { // Executor not invalidated + return (executor->*method)(argumentCount, arguments); + } + } catch (...) { + *exception = translatePendingCppExceptionToJSError(ctx, function); } - - } - -#if DEBUG - static JSValueRef nativeInjectHMRUpdate( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef *exception) { - String execJSString = Value(ctx, arguments[0]).toString(); - String jsURL = Value(ctx, arguments[1]).toString(); - evaluateScript(ctx, execJSString, jsURL); return Value::makeUndefined(ctx); } -#endif + }; - std::unique_ptr JSCExecutorFactory::createJSExecutor( - std::shared_ptr delegate, std::shared_ptr jsQueue) { - return folly::make_unique(delegate, jsQueue, m_jscConfig, m_nativeExtensionsProvider); - } + return &funcWrapper::call; +} - JSCExecutor::JSCExecutor(std::shared_ptr delegate, - std::shared_ptr messageQueueThread, - const folly::dynamic& jscConfig, - NativeExtensionsProvider nativeExtensionsProvider) throw(JSException) : - m_delegate(delegate), - m_messageQueueThread(messageQueueThread), - m_nativeModules(delegate ? delegate->getModuleRegistry() : nullptr), - m_jscConfig(jscConfig), - m_nativeExtensionsProvider(nativeExtensionsProvider) { - initOnJSVMThread(); - - { - SystraceSection s("nativeModuleProxy object"); - installGlobalProxy(m_context, "nativeModuleProxy", - exceptionWrapMethod<&JSCExecutor::getNativeModule>()); - } - if (nativeExtensionsProvider) { - installGlobalProxy(m_context, "nativeExtensions", - exceptionWrapMethod<&JSCExecutor::getNativeExtension>()); +template +inline JSObjectGetPropertyCallback exceptionWrapMethod() { + struct funcWrapper { + static JSValueRef call( + JSContextRef ctx, + JSObjectRef object, + JSStringRef propertyName, + JSValueRef* exception) { + try { + auto executor = Object::getGlobalObject(ctx).getPrivate(); + if (executor && + executor->getJavaScriptContext()) { // Executor not invalidated + return (executor->*method)(object, propertyName); + } + } catch (...) { + *exception = translatePendingCppExceptionToJSError(ctx, object); } + return Value::makeUndefined(ctx); } + }; - JSCExecutor::~JSCExecutor() { - CHECK(*m_isDestroyed) << "JSCExecutor::destroy() must be called before its destructor!"; - } + return &funcWrapper::call; +} - void JSCExecutor::destroy() { - *m_isDestroyed = true; - if (m_messageQueueThread.get()) { - m_messageQueueThread->runOnQueueSync([this] () { - terminateOnJSVMThread(); - }); - } else { - terminateOnJSVMThread(); - } - } +} // namespace - void JSCExecutor::setContextName(const std::string& name) { - String jsName = String(m_context, name.c_str()); - JSC_JSGlobalContextSetName(m_context, jsName); - } +#if DEBUG +static JSValueRef nativeInjectHMRUpdate( + JSContextRef ctx, + JSObjectRef function, + JSObjectRef thisObject, + size_t argumentCount, + const JSValueRef arguments[], + JSValueRef* exception) { + String execJSString = Value(ctx, arguments[0]).toString(); + String jsURL = Value(ctx, arguments[1]).toString(); + evaluateScript(ctx, execJSString, jsURL); + return Value::makeUndefined(ctx); +} +#endif - static bool canUseInspector(JSContextRef context) { +std::unique_ptr JSCExecutorFactory::createJSExecutor( + std::shared_ptr delegate, + std::shared_ptr jsQueue) { + return folly::make_unique( + delegate, jsQueue, m_jscConfig, m_nativeExtensionsProvider); +} + +JSCExecutor::JSCExecutor( + std::shared_ptr delegate, + std::shared_ptr messageQueueThread, + const folly::dynamic& jscConfig, + NativeExtensionsProvider nativeExtensionsProvider) throw(JSException) + : m_delegate(delegate), + m_messageQueueThread(messageQueueThread), + m_nativeModules(delegate ? delegate->getModuleRegistry() : nullptr), + m_jscConfig(jscConfig), + m_nativeExtensionsProvider(nativeExtensionsProvider) { + initOnJSVMThread(); + + { + SystraceSection s("nativeModuleProxy object"); + installGlobalProxy( + m_context, + "nativeModuleProxy", + exceptionWrapMethod<&JSCExecutor::getNativeModule>()); + } + if (nativeExtensionsProvider) { + installGlobalProxy( + m_context, + "nativeExtensions", + exceptionWrapMethod<&JSCExecutor::getNativeExtension>()); + } +} + +JSCExecutor::~JSCExecutor() { + CHECK(*m_isDestroyed) + << "JSCExecutor::destroy() must be called before its destructor!"; +} + +void JSCExecutor::destroy() { + *m_isDestroyed = true; + if (m_messageQueueThread.get()) { + m_messageQueueThread->runOnQueueSync([this]() { terminateOnJSVMThread(); }); + } else { + terminateOnJSVMThread(); + } +} + +void JSCExecutor::setContextName(const std::string& name) { + String jsName = String(m_context, name.c_str()); + JSC_JSGlobalContextSetName(m_context, jsName); +} + +static bool canUseInspector(JSContextRef context) { #ifdef WITH_INSPECTOR #if defined(__APPLE__) - return isCustomJSCPtr(context); // WITH_INSPECTOR && Apple + return isCustomJSCPtr(context); // WITH_INSPECTOR && Apple #else - return true; // WITH_INSPECTOR && Android + return true; // WITH_INSPECTOR && Android #endif #else - return false; // !WITH_INSPECTOR + return false; // !WITH_INSPECTOR #endif - } +} - static bool canUseSamplingProfiler(JSContextRef context) { +static bool canUseSamplingProfiler(JSContextRef context) { #if defined(__APPLE__) || defined(WITH_JSC_EXTRA_TRACING) - return JSC_JSSamplingProfilerEnabled(context); + return JSC_JSSamplingProfilerEnabled(context); #else - return false; + return false; #endif - } +} - void JSCExecutor::initOnJSVMThread() throw(JSException) { - SystraceSection s("JSCExecutor::initOnJSVMThread"); +void JSCExecutor::initOnJSVMThread() throw(JSException) { + SystraceSection s("JSCExecutor::initOnJSVMThread"); #if defined(__APPLE__) - const bool useCustomJSC = m_jscConfig.getDefault("UseCustomJSC", false).getBool(); - if (useCustomJSC) { - JSC_configureJSCForIOS(true, toJson(m_jscConfig)); - } + const bool useCustomJSC = + m_jscConfig.getDefault("UseCustomJSC", false).getBool(); + if (useCustomJSC) { + JSC_configureJSCForIOS(true, toJson(m_jscConfig)); + } #else - const bool useCustomJSC = false; + const bool useCustomJSC = false; #endif #if defined(WITH_FB_JSC_TUNING) && defined(__ANDROID__) - configureJSCForAndroid(m_jscConfig); + configureJSCForAndroid(m_jscConfig); #endif - // Create a custom global class, so we can store data in it later using JSObjectSetPrivate - JSClassRef globalClass = nullptr; - { - SystraceSection s_("JSClassCreate"); - JSClassDefinition definition = kJSClassDefinitionEmpty; - definition.attributes |= kJSClassAttributeNoAutomaticPrototype; - globalClass = JSC_JSClassCreate(useCustomJSC, &definition); - } - { - SystraceSection s_("JSGlobalContextCreateInGroup"); - m_context = JSC_JSGlobalContextCreateInGroup(useCustomJSC, nullptr, globalClass); - } - JSC_JSClassRelease(useCustomJSC, globalClass); - - // Add a pointer to ourselves so we can retrieve it later in our hooks - Object::getGlobalObject(m_context).setPrivate(this); - - if (canUseInspector(m_context)) { - const std::string ownerId = m_jscConfig.getDefault("OwnerIdentity", "unknown").getString(); - const std::string appId = m_jscConfig.getDefault("AppIdentity", "unknown").getString(); - const std::string deviceId = m_jscConfig.getDefault("DeviceIdentity", "unknown").getString(); - auto checkIsInspectedRemote = [ownerId, appId, deviceId]() { - return isNetworkInspected(ownerId, appId, deviceId); - }; - - auto& globalInspector = facebook::react::getInspectorInstance(); - JSC_JSGlobalContextEnableDebugger(m_context, globalInspector, ownerId.c_str(), checkIsInspectedRemote); - } - - installNativeHook<&JSCExecutor::nativeFlushQueueImmediate>("nativeFlushQueueImmediate"); - installNativeHook<&JSCExecutor::nativeCallSyncHook>("nativeCallSyncHook"); - - installGlobalFunction(m_context, "nativeLoggingHook", JSCNativeHooks::loggingHook); - installGlobalFunction(m_context, "nativePerformanceNow", JSCNativeHooks::nowHook); + // Create a custom global class, so we can store data in it later using + // JSObjectSetPrivate + JSClassRef globalClass = nullptr; + { + SystraceSection s_("JSClassCreate"); + JSClassDefinition definition = kJSClassDefinitionEmpty; + definition.attributes |= kJSClassAttributeNoAutomaticPrototype; + globalClass = JSC_JSClassCreate(useCustomJSC, &definition); + } + { + SystraceSection s_("JSGlobalContextCreateInGroup"); + m_context = + JSC_JSGlobalContextCreateInGroup(useCustomJSC, nullptr, globalClass); + } + JSC_JSClassRelease(useCustomJSC, globalClass); + + // Add a pointer to ourselves so we can retrieve it later in our hooks + Object::getGlobalObject(m_context).setPrivate(this); + + if (canUseInspector(m_context)) { + const std::string ownerId = + m_jscConfig.getDefault("OwnerIdentity", "unknown").getString(); + const std::string appId = + m_jscConfig.getDefault("AppIdentity", "unknown").getString(); + const std::string deviceId = + m_jscConfig.getDefault("DeviceIdentity", "unknown").getString(); + auto checkIsInspectedRemote = [ownerId, appId, deviceId]() { + return isNetworkInspected(ownerId, appId, deviceId); + }; + + auto& globalInspector = facebook::react::getInspectorInstance(); + JSC_JSGlobalContextEnableDebugger( + m_context, globalInspector, ownerId.c_str(), checkIsInspectedRemote); + } + + installNativeHook<&JSCExecutor::nativeFlushQueueImmediate>( + "nativeFlushQueueImmediate"); + installNativeHook<&JSCExecutor::nativeCallSyncHook>("nativeCallSyncHook"); + + installGlobalFunction( + m_context, "nativeLoggingHook", JSCNativeHooks::loggingHook); + installGlobalFunction( + m_context, "nativePerformanceNow", JSCNativeHooks::nowHook); #if DEBUG - installGlobalFunction(m_context, "nativeInjectHMRUpdate", nativeInjectHMRUpdate); + installGlobalFunction( + m_context, "nativeInjectHMRUpdate", nativeInjectHMRUpdate); #endif - addNativeTracingHooks(m_context); - addNativeTracingLegacyHooks(m_context); - addJSCMemoryHooks(m_context); - addJSCPerfStatsHooks(m_context); + addNativeTracingHooks(m_context); + addNativeTracingLegacyHooks(m_context); + addJSCMemoryHooks(m_context); + addJSCPerfStatsHooks(m_context); - JSCNativeHooks::installPerfHooks(m_context); + JSCNativeHooks::installPerfHooks(m_context); - if (canUseSamplingProfiler(m_context)) { - initSamplingProfilerOnMainJSCThread(m_context); - } - } + if (canUseSamplingProfiler(m_context)) { + initSamplingProfilerOnMainJSCThread(m_context); + } +} - bool JSCExecutor::isNetworkInspected(const std::string &owner, const std::string &app, const std::string &device) { +bool JSCExecutor::isNetworkInspected( + const std::string& owner, + const std::string& app, + const std::string& device) { #ifdef WITH_FB_DBG_ATTACH_BEFORE_EXEC - auto connect_socket = [](int socket_desc, std::string address, int port) { - if (socket_desc < 0) { - ::close(socket_desc); - return false; - } - - struct timeval tv; - tv.tv_sec = 1; - tv.tv_usec = 0; - auto sock_opt_rcv_resp = setsockopt(socket_desc, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(struct timeval)); - if (sock_opt_rcv_resp < 0) { - ::close(socket_desc); - return false; - } - - auto sock_opt_snd_resp = setsockopt(socket_desc, SOL_SOCKET, SO_SNDTIMEO, (const char*)&tv, sizeof(struct timeval)); - if (sock_opt_snd_resp < 0) { - ::close(socket_desc); - return false; - } - - struct sockaddr_in server; - server.sin_addr.s_addr = inet_addr(address.c_str()); - server.sin_family = AF_INET; - server.sin_port = htons(port); - auto connect_resp = ::connect(socket_desc, (struct sockaddr *)&server, sizeof(server)); - if (connect_resp < 0) { - ::close(socket_desc); - return false; - } - - return true; - }; - - int socket_desc = socket(AF_INET, SOCK_STREAM, 0); - - if (!connect_socket(socket_desc, "127.0.0.1", 8082)) { -#if defined(__ANDROID__) - socket_desc = socket(AF_INET, SOCK_STREAM, 0); - if (!connect_socket(socket_desc, "10.0.2.2", 8082) /* emulator */) { - socket_desc = socket(AF_INET, SOCK_STREAM, 0); - if (!connect_socket(socket_desc, "10.0.3.2", 8082) /* genymotion */) { - return false; - } - } -#else //!defined(__ANDROID__) - return false; -#endif //defined(__ANDROID__) - } + auto connect_socket = [](int socket_desc, std::string address, int port) { + if (socket_desc < 0) { + ::close(socket_desc); + return false; + } - std::string escapedOwner = folly::uriEscape(owner, folly::UriEscapeMode::QUERY); - std::string escapedApp = folly::uriEscape(app, folly::UriEscapeMode::QUERY); - std::string escapedDevice = folly::uriEscape(device, folly::UriEscapeMode::QUERY); - std::string msg = folly::to( - "GET /autoattach?title=", escapedOwner, - "&app=" , escapedApp, - "&device=" , escapedDevice, - " HTTP/1.1\r\n\r\n"); - auto send_resp = ::send(socket_desc, msg.c_str(), msg.length(), 0); - if (send_resp < 0) { - ::close(socket_desc); - return false; - } + struct timeval tv; + tv.tv_sec = 1; + tv.tv_usec = 0; + auto sock_opt_rcv_resp = setsockopt( + socket_desc, + SOL_SOCKET, + SO_RCVTIMEO, + (const char*)&tv, + sizeof(struct timeval)); + if (sock_opt_rcv_resp < 0) { + ::close(socket_desc); + return false; + } - char server_reply[200]; - server_reply[199] = '\0'; - auto recv_resp = ::recv(socket_desc, server_reply, - sizeof(server_reply) - 1, 0); - if (recv_resp < 0) { - ::close(socket_desc); - return false; - } + auto sock_opt_snd_resp = setsockopt( + socket_desc, + SOL_SOCKET, + SO_SNDTIMEO, + (const char*)&tv, + sizeof(struct timeval)); + if (sock_opt_snd_resp < 0) { + ::close(socket_desc); + return false; + } - std::string response(server_reply); - if (response.size() < 25) { - ::close(socket_desc); - return false; - } - auto responseCandidate = response.substr(response.size() - 25); - auto found = responseCandidate.find("{\"autoattach\":true}") != std::string::npos; + struct sockaddr_in server; + server.sin_addr.s_addr = inet_addr(address.c_str()); + server.sin_family = AF_INET; + server.sin_port = htons(port); + auto connect_resp = + ::connect(socket_desc, (struct sockaddr*)&server, sizeof(server)); + if (connect_resp < 0) { ::close(socket_desc); - return found; -#else //!WITH_FB_DBG_ATTACH_BEFORE_EXEC return false; -#endif //WITH_FB_DBG_ATTACH_BEFORE_EXEC } - void JSCExecutor::terminateOnJSVMThread() { - JSGlobalContextRef context = m_context; - m_context = nullptr; - Object::getGlobalObject(context).setPrivate(nullptr); - m_nativeModules.reset(); + return true; + }; - if (canUseInspector(context)) { - auto &globalInspector = facebook::react::getInspectorInstance(); - JSC_JSGlobalContextDisableDebugger(context, globalInspector); - } + int socket_desc = socket(AF_INET, SOCK_STREAM, 0); - JSC_JSGlobalContextRelease(context); + if (!connect_socket(socket_desc, "127.0.0.1", 8082)) { +#if defined(__ANDROID__) + socket_desc = socket(AF_INET, SOCK_STREAM, 0); + if (!connect_socket(socket_desc, "10.0.2.2", 8082) /* emulator */) { + socket_desc = socket(AF_INET, SOCK_STREAM, 0); + if (!connect_socket(socket_desc, "10.0.3.2", 8082) /* genymotion */) { + return false; + } } +#else //! defined(__ANDROID__) + return false; +#endif // defined(__ANDROID__) + } + + std::string escapedOwner = + folly::uriEscape(owner, folly::UriEscapeMode::QUERY); + std::string escapedApp = + folly::uriEscape(app, folly::UriEscapeMode::QUERY); + std::string escapedDevice = + folly::uriEscape(device, folly::UriEscapeMode::QUERY); + std::string msg = folly::to( + "GET /autoattach?title=", + escapedOwner, + "&app=", + escapedApp, + "&device=", + escapedDevice, + " HTTP/1.1\r\n\r\n"); + auto send_resp = ::send(socket_desc, msg.c_str(), msg.length(), 0); + if (send_resp < 0) { + ::close(socket_desc); + return false; + } + + char server_reply[200]; + server_reply[199] = '\0'; + auto recv_resp = + ::recv(socket_desc, server_reply, sizeof(server_reply) - 1, 0); + if (recv_resp < 0) { + ::close(socket_desc); + return false; + } + + std::string response(server_reply); + if (response.size() < 25) { + ::close(socket_desc); + return false; + } + auto responseCandidate = response.substr(response.size() - 25); + auto found = + responseCandidate.find("{\"autoattach\":true}") != std::string::npos; + ::close(socket_desc); + return found; +#else //! WITH_FB_DBG_ATTACH_BEFORE_EXEC + return false; +#endif // WITH_FB_DBG_ATTACH_BEFORE_EXEC +} + +void JSCExecutor::terminateOnJSVMThread() { + JSGlobalContextRef context = m_context; + m_context = nullptr; + Object::getGlobalObject(context).setPrivate(nullptr); + m_nativeModules.reset(); + + if (canUseInspector(context)) { + auto& globalInspector = facebook::react::getInspectorInstance(); + JSC_JSGlobalContextDisableDebugger(context, globalInspector); + } + + JSC_JSGlobalContextRelease(context); +} #ifdef WITH_FBJSCEXTENSIONS - static const char* explainLoadSourceStatus(JSLoadSourceStatus status) { - switch (status) { - case JSLoadSourceIsCompiled: - return "No error encountered during source load"; +static const char* explainLoadSourceStatus(JSLoadSourceStatus status) { + switch (status) { + case JSLoadSourceIsCompiled: + return "No error encountered during source load"; - case JSLoadSourceErrorOnRead: - return "Error reading source"; + case JSLoadSourceErrorOnRead: + return "Error reading source"; - case JSLoadSourceIsNotCompiled: - return "Source is not compiled"; + case JSLoadSourceIsNotCompiled: + return "Source is not compiled"; - case JSLoadSourceErrorVersionMismatch: - return "Source version not supported"; + case JSLoadSourceErrorVersionMismatch: + return "Source version not supported"; - default: - return "Bad error code"; - } - } + default: + return "Bad error code"; + } +} #endif - // basename_r isn't in all iOS SDKs, so use this simple version instead. - static std::string simpleBasename(const std::string &path) { - size_t pos = path.rfind("/"); - return (pos != std::string::npos) ? path.substr(pos) : path; - } +// basename_r isn't in all iOS SDKs, so use this simple version instead. +static std::string simpleBasename(const std::string& path) { + size_t pos = path.rfind("/"); + return (pos != std::string::npos) ? path.substr(pos) : path; +} - void JSCExecutor::loadApplicationScript(std::unique_ptr script, std::string sourceURL) { - SystraceSection s("JSCExecutor::loadApplicationScript", - "sourceURL", sourceURL); +void JSCExecutor::loadApplicationScript( + std::unique_ptr script, + std::string sourceURL) { + SystraceSection s( + "JSCExecutor::loadApplicationScript", "sourceURL", sourceURL); - std::string scriptName = simpleBasename(sourceURL); - ReactMarker::logTaggedMarker(ReactMarker::RUN_JS_BUNDLE_START, scriptName.c_str()); - String jsSourceURL(m_context, sourceURL.c_str()); + std::string scriptName = simpleBasename(sourceURL); + ReactMarker::logTaggedMarker( + ReactMarker::RUN_JS_BUNDLE_START, scriptName.c_str()); + String jsSourceURL(m_context, sourceURL.c_str()); - // TODO t15069155: reduce the number of overrides here +// TODO t15069155: reduce the number of overrides here #ifdef WITH_FBJSCEXTENSIONS - if (auto fileStr = dynamic_cast(script.get())) { - JSContextLock lock(m_context); - JSLoadSourceStatus jsStatus; - auto bcSourceCode = JSCreateSourceCodeFromFile(fileStr->fd(), jsSourceURL, nullptr, &jsStatus); - - switch (jsStatus) { - case JSLoadSourceIsCompiled: - if (!bcSourceCode) { - throw std::runtime_error("Unexpected error opening compiled bundle"); - } - evaluateSourceCode(m_context, bcSourceCode, jsSourceURL); - - flush(); - - ReactMarker::logMarker(ReactMarker::CREATE_REACT_CONTEXT_STOP); - ReactMarker::logTaggedMarker(ReactMarker::RUN_JS_BUNDLE_STOP, scriptName.c_str()); - return; - - case JSLoadSourceErrorVersionMismatch: - throw RecoverableError(explainLoadSourceStatus(jsStatus)); - - case JSLoadSourceErrorOnRead: - case JSLoadSourceIsNotCompiled: - // Not bytecode, fall through. - break; + if (auto fileStr = dynamic_cast(script.get())) { + JSContextLock lock(m_context); + JSLoadSourceStatus jsStatus; + auto bcSourceCode = JSCreateSourceCodeFromFile( + fileStr->fd(), jsSourceURL, nullptr, &jsStatus); + + switch (jsStatus) { + case JSLoadSourceIsCompiled: + if (!bcSourceCode) { + throw std::runtime_error("Unexpected error opening compiled bundle"); } - } -#elif defined(__APPLE__) - BundleHeader header; - memcpy(&header, script->c_str(), std::min(script->size(), sizeof(BundleHeader))); - auto scriptTag = parseTypeFromHeader(header); - - if (scriptTag == ScriptTag::BCBundle) { - using file_ptr = std::unique_ptr; - file_ptr source(fopen(sourceURL.c_str(), "r"), fclose); - int sourceFD = fileno(source.get()); - - JSValueRef jsError; - JSValueRef result = JSC_JSEvaluateBytecodeBundle(m_context, NULL, sourceFD, jsSourceURL, &jsError); - if (result == nullptr) { - throw JSException(m_context, jsError, jsSourceURL); - } - } else -#endif - { - String jsScript; - JSContextLock lock(m_context); - { - SystraceSection s_("JSCExecutor::loadApplicationScript-createExpectingAscii"); - ReactMarker::logMarker(ReactMarker::JS_BUNDLE_STRING_CONVERT_START); - jsScript = adoptString(std::move(script)); - ReactMarker::logMarker(ReactMarker::JS_BUNDLE_STRING_CONVERT_STOP); - } - - SystraceSection s_("JSCExecutor::loadApplicationScript-evaluateScript"); - evaluateScript(m_context, jsScript, jsSourceURL); - } - - flush(); - - ReactMarker::logMarker(ReactMarker::CREATE_REACT_CONTEXT_STOP); - ReactMarker::logTaggedMarker(ReactMarker::RUN_JS_BUNDLE_STOP, scriptName.c_str()); - } + evaluateSourceCode(m_context, bcSourceCode, jsSourceURL); - void JSCExecutor::setBundleRegistry(std::unique_ptr bundleRegistry) { - if (!m_bundleRegistry) { - installNativeHook<&JSCExecutor::nativeRequire>("nativeRequire"); - } - m_bundleRegistry = std::move(bundleRegistry); - } - - void JSCExecutor::registerBundle( - uint32_t bundleId, - const std::string& bundlePath) { - if (m_bundleRegistry) { - m_bundleRegistry->registerBundle(bundleId, bundlePath); - } else { - auto stPath = JSCExecutor::getSyntheticBundlePath(bundleId, bundlePath); - auto sourceUrlStr = String(m_context, stPath.c_str()); - auto source = adoptString(JSBigFileString::fromPath(bundlePath)); - evaluateScript(m_context, source, sourceUrlStr); - } - } + flush(); - void JSCExecutor::bindBridge() throw(JSException) { - SystraceSection s("JSCExecutor::bindBridge"); - std::call_once(m_bindFlag, [this] { - auto global = Object::getGlobalObject(m_context); - auto batchedBridgeValue = global.getProperty("__fbBatchedBridge"); - if (batchedBridgeValue.isUndefined()) { - auto requireBatchedBridge = global.getProperty("__fbRequireBatchedBridge"); - if (!requireBatchedBridge.isUndefined()) { - batchedBridgeValue = requireBatchedBridge.asObject().callAsFunction({}); - } - if (batchedBridgeValue.isUndefined()) { - throw JSException("Could not get BatchedBridge, make sure your bundle is packaged correctly"); - } - } + ReactMarker::logMarker(ReactMarker::CREATE_REACT_CONTEXT_STOP); + ReactMarker::logTaggedMarker( + ReactMarker::RUN_JS_BUNDLE_STOP, scriptName.c_str()); + return; - auto batchedBridge = batchedBridgeValue.asObject(); - m_callFunctionReturnFlushedQueueJS = batchedBridge.getProperty("callFunctionReturnFlushedQueue").asObject(); - m_invokeCallbackAndReturnFlushedQueueJS = batchedBridge.getProperty("invokeCallbackAndReturnFlushedQueue").asObject(); - m_flushedQueueJS = batchedBridge.getProperty("flushedQueue").asObject(); - m_callFunctionReturnResultAndFlushedQueueJS = batchedBridge.getProperty("callFunctionReturnResultAndFlushedQueue").asObject(); - }); - } + case JSLoadSourceErrorVersionMismatch: + throw RecoverableError(explainLoadSourceStatus(jsStatus)); - void JSCExecutor::callNativeModules(Value&& value) { - SystraceSection s("JSCExecutor::callNativeModules"); - // If this fails, you need to pass a fully functional delegate with a - // module registry to the factory/ctor. - CHECK(m_delegate) << "Attempting to use native modules without a delegate"; - try { - auto calls = value.toJSONString(); - m_delegate->callNativeModules(*this, folly::parseJson(calls), true); - } catch (...) { - std::string message = "Error in callNativeModules()"; - try { - message += ":" + value.toString().str(); - } catch (...) { - // ignored - } - std::throw_with_nested(std::runtime_error(message)); - } + case JSLoadSourceErrorOnRead: + case JSLoadSourceIsNotCompiled: + // Not bytecode, fall through. + break; } - - void JSCExecutor::flush() { - SystraceSection s("JSCExecutor::flush"); - - if (m_flushedQueueJS) { - callNativeModules(m_flushedQueueJS->callAsFunction({})); - return; - } - - // When a native module is called from JS, BatchedBridge.enqueueNativeCall() - // is invoked. For that to work, require('BatchedBridge') has to be called, - // and when that happens, __fbBatchedBridge is set as a side effect. - auto global = Object::getGlobalObject(m_context); - auto batchedBridgeValue = global.getProperty("__fbBatchedBridge"); - // So here, if __fbBatchedBridge doesn't exist, then we know no native calls - // have happened, and we were able to determine this without forcing - // BatchedBridge to be loaded as a side effect. - if (!batchedBridgeValue.isUndefined()) { - // If calls were made, we bind to the JS bridge methods, and use them to - // get the pending queue of native calls. + } +#elif defined(__APPLE__) + BundleHeader header; + memcpy( + &header, script->c_str(), std::min(script->size(), sizeof(BundleHeader))); + auto scriptTag = parseTypeFromHeader(header); + + if (scriptTag == ScriptTag::BCBundle) { + using file_ptr = std::unique_ptr; + file_ptr source(fopen(sourceURL.c_str(), "r"), fclose); + int sourceFD = fileno(source.get()); + + JSValueRef jsError; + JSValueRef result = JSC_JSEvaluateBytecodeBundle( + m_context, NULL, sourceFD, jsSourceURL, &jsError); + if (result == nullptr) { + throw JSException(m_context, jsError, jsSourceURL); + } + } else +#endif + { + String jsScript; + JSContextLock lock(m_context); + { + SystraceSection s_( + "JSCExecutor::loadApplicationScript-createExpectingAscii"); + ReactMarker::logMarker(ReactMarker::JS_BUNDLE_STRING_CONVERT_START); + jsScript = adoptString(std::move(script)); + ReactMarker::logMarker(ReactMarker::JS_BUNDLE_STRING_CONVERT_STOP); + } + + SystraceSection s_("JSCExecutor::loadApplicationScript-evaluateScript"); + evaluateScript(m_context, jsScript, jsSourceURL); + } + + flush(); + + ReactMarker::logMarker(ReactMarker::CREATE_REACT_CONTEXT_STOP); + ReactMarker::logTaggedMarker( + ReactMarker::RUN_JS_BUNDLE_STOP, scriptName.c_str()); +} + +void JSCExecutor::setBundleRegistry( + std::unique_ptr bundleRegistry) { + if (!m_bundleRegistry) { + installNativeHook<&JSCExecutor::nativeRequire>("nativeRequire"); + } + m_bundleRegistry = std::move(bundleRegistry); +} + +void JSCExecutor::registerBundle( + uint32_t bundleId, + const std::string& bundlePath) { + if (m_bundleRegistry) { + m_bundleRegistry->registerBundle(bundleId, bundlePath); + } else { + auto stPath = JSCExecutor::getSyntheticBundlePath(bundleId, bundlePath); + auto sourceUrlStr = String(m_context, stPath.c_str()); + auto source = adoptString(JSBigFileString::fromPath(bundlePath)); + evaluateScript(m_context, source, sourceUrlStr); + } +} + +void JSCExecutor::bindBridge() throw(JSException) { + SystraceSection s("JSCExecutor::bindBridge"); + std::call_once(m_bindFlag, [this] { + auto global = Object::getGlobalObject(m_context); + auto batchedBridgeValue = global.getProperty("__fbBatchedBridge"); + if (batchedBridgeValue.isUndefined()) { + auto requireBatchedBridge = + global.getProperty("__fbRequireBatchedBridge"); + if (!requireBatchedBridge.isUndefined()) { + batchedBridgeValue = requireBatchedBridge.asObject().callAsFunction({}); + } + if (batchedBridgeValue.isUndefined()) { + throw JSException( + "Could not get BatchedBridge, make sure your bundle is packaged correctly"); + } + } + + auto batchedBridge = batchedBridgeValue.asObject(); + m_callFunctionReturnFlushedQueueJS = + batchedBridge.getProperty("callFunctionReturnFlushedQueue").asObject(); + m_invokeCallbackAndReturnFlushedQueueJS = + batchedBridge.getProperty("invokeCallbackAndReturnFlushedQueue") + .asObject(); + m_flushedQueueJS = batchedBridge.getProperty("flushedQueue").asObject(); + m_callFunctionReturnResultAndFlushedQueueJS = + batchedBridge.getProperty("callFunctionReturnResultAndFlushedQueue") + .asObject(); + }); +} + +void JSCExecutor::callNativeModules(Value&& value) { + SystraceSection s("JSCExecutor::callNativeModules"); + // If this fails, you need to pass a fully functional delegate with a + // module registry to the factory/ctor. + CHECK(m_delegate) << "Attempting to use native modules without a delegate"; + try { + auto calls = value.toJSONString(); + m_delegate->callNativeModules(*this, folly::parseJson(calls), true); + } catch (...) { + std::string message = "Error in callNativeModules()"; + try { + message += ":" + value.toString().str(); + } catch (...) { + // ignored + } + std::throw_with_nested(std::runtime_error(message)); + } +} + +void JSCExecutor::flush() { + SystraceSection s("JSCExecutor::flush"); + + if (m_flushedQueueJS) { + callNativeModules(m_flushedQueueJS->callAsFunction({})); + return; + } + + // When a native module is called from JS, BatchedBridge.enqueueNativeCall() + // is invoked. For that to work, require('BatchedBridge') has to be called, + // and when that happens, __fbBatchedBridge is set as a side effect. + auto global = Object::getGlobalObject(m_context); + auto batchedBridgeValue = global.getProperty("__fbBatchedBridge"); + // So here, if __fbBatchedBridge doesn't exist, then we know no native calls + // have happened, and we were able to determine this without forcing + // BatchedBridge to be loaded as a side effect. + if (!batchedBridgeValue.isUndefined()) { + // If calls were made, we bind to the JS bridge methods, and use them to + // get the pending queue of native calls. + bindBridge(); + callNativeModules(m_flushedQueueJS->callAsFunction({})); + } else if (m_delegate) { + // If we have a delegate, we need to call it; we pass a null list to + // callNativeModules, since we know there are no native calls, without + // calling into JS again. If no calls were made and there's no delegate, + // nothing happens, which is correct. + callNativeModules(Value::makeNull(m_context)); + } +} + +void JSCExecutor::callFunction( + const std::string& moduleId, + const std::string& methodId, + const folly::dynamic& arguments) { + SystraceSection s("JSCExecutor::callFunction"); + // This weird pattern is because Value is not default constructible. + // The lambda is inlined, so there's no overhead. + auto result = [&] { + JSContextLock lock(m_context); + try { + if (!m_callFunctionReturnResultAndFlushedQueueJS) { bindBridge(); - callNativeModules(m_flushedQueueJS->callAsFunction({})); - } else if (m_delegate) { - // If we have a delegate, we need to call it; we pass a null list to - // callNativeModules, since we know there are no native calls, without - // calling into JS again. If no calls were made and there's no delegate, - // nothing happens, which is correct. - callNativeModules(Value::makeNull(m_context)); } - } - - void JSCExecutor::callFunction(const std::string& moduleId, const std::string& methodId, const folly::dynamic& arguments) { - SystraceSection s("JSCExecutor::callFunction"); - // This weird pattern is because Value is not default constructible. - // The lambda is inlined, so there's no overhead. - auto result = [&] { - JSContextLock lock(m_context); - try { - if (!m_callFunctionReturnResultAndFlushedQueueJS) { - bindBridge(); - } - return m_callFunctionReturnFlushedQueueJS->callAsFunction({ - Value(m_context, String::createExpectingAscii(m_context, moduleId)), - Value(m_context, String::createExpectingAscii(m_context, methodId)), - Value::fromDynamic(m_context, std::move(arguments)) - }); - } catch (...) { - std::throw_with_nested( - std::runtime_error("Error calling " + moduleId + "." + methodId)); - } - }(); - callNativeModules(std::move(result)); - } - - void JSCExecutor::invokeCallback(const double callbackId, const folly::dynamic& arguments) { - SystraceSection s("JSCExecutor::invokeCallback"); - auto result = [&] { - JSContextLock lock(m_context); - try { - if (!m_invokeCallbackAndReturnFlushedQueueJS) { - bindBridge(); - } - return m_invokeCallbackAndReturnFlushedQueueJS->callAsFunction({ - Value::makeNumber(m_context, callbackId), - Value::fromDynamic(m_context, std::move(arguments)) - }); - } catch (...) { - std::throw_with_nested( - std::runtime_error(folly::to("Error invoking callback ", callbackId))); - } - }(); - callNativeModules(std::move(result)); - } - - void JSCExecutor::setGlobalVariable(std::string propName, std::unique_ptr jsonValue) { - try { - SystraceSection s("JSCExecutor::setGlobalVariable", "propName", propName); - auto valueToInject = Value::fromJSON(adoptString(std::move(jsonValue))); - Object::getGlobalObject(m_context).setProperty(propName.c_str(), valueToInject); - } catch (...) { - std::throw_with_nested(std::runtime_error("Error setting global variable: " + propName)); + return m_callFunctionReturnFlushedQueueJS->callAsFunction( + {Value(m_context, String::createExpectingAscii(m_context, moduleId)), + Value(m_context, String::createExpectingAscii(m_context, methodId)), + Value::fromDynamic(m_context, std::move(arguments))}); + } catch (...) { + std::throw_with_nested( + std::runtime_error("Error calling " + moduleId + "." + methodId)); + } + }(); + callNativeModules(std::move(result)); +} + +void JSCExecutor::invokeCallback( + const double callbackId, + const folly::dynamic& arguments) { + SystraceSection s("JSCExecutor::invokeCallback"); + auto result = [&] { + JSContextLock lock(m_context); + try { + if (!m_invokeCallbackAndReturnFlushedQueueJS) { + bindBridge(); } - } - - std::string JSCExecutor::getDescription() { + return m_invokeCallbackAndReturnFlushedQueueJS->callAsFunction( + {Value::makeNumber(m_context, callbackId), + Value::fromDynamic(m_context, std::move(arguments))}); + } catch (...) { + std::throw_with_nested(std::runtime_error( + folly::to("Error invoking callback ", callbackId))); + } + }(); + callNativeModules(std::move(result)); +} + +void JSCExecutor::setGlobalVariable( + std::string propName, + std::unique_ptr jsonValue) { + try { + SystraceSection s("JSCExecutor::setGlobalVariable", "propName", propName); + auto valueToInject = Value::fromJSON(adoptString(std::move(jsonValue))); + Object::getGlobalObject(m_context).setProperty( + propName.c_str(), valueToInject); + } catch (...) { + std::throw_with_nested( + std::runtime_error("Error setting global variable: " + propName)); + } +} + +std::string JSCExecutor::getDescription() { #if defined(__APPLE__) - if (isCustomJSCPtr(m_context)) { - return "Custom JSC"; - } else { - return "System JSC"; - } + if (isCustomJSCPtr(m_context)) { + return "Custom JSC"; + } else { + return "System JSC"; + } #else - return "JSC"; + return "JSC"; #endif - } +} - String JSCExecutor::adoptString(std::unique_ptr script) { +String JSCExecutor::adoptString(std::unique_ptr script) { #if defined(WITH_FBJSCEXTENSIONS) - const JSBigString* string = script.release(); - auto jsString = JSStringCreateAdoptingExternal(string->c_str(), string->size(), (void*)string, [](void* s) { + const JSBigString* string = script.release(); + auto jsString = JSStringCreateAdoptingExternal( + string->c_str(), string->size(), (void*)string, [](void* s) { delete static_cast(s); }); - return String::adopt(m_context, jsString); + return String::adopt(m_context, jsString); #else - return script->isAscii() - ? String::createExpectingAscii(m_context, script->c_str(), script->size()) - : String(m_context, script->c_str()); + return script->isAscii() + ? String::createExpectingAscii(m_context, script->c_str(), script->size()) + : String(m_context, script->c_str()); #endif - } +} - void* JSCExecutor::getJavaScriptContext() { - return m_context; - } +void* JSCExecutor::getJavaScriptContext() { + return m_context; +} - bool JSCExecutor::isInspectable() { - return canUseInspector(m_context); - } +bool JSCExecutor::isInspectable() { + return canUseInspector(m_context); +} #ifdef WITH_JSC_MEMORY_PRESSURE - void JSCExecutor::handleMemoryPressure(int pressureLevel) { - JSHandleMemoryPressure(this, m_context, static_cast(pressureLevel)); - } +void JSCExecutor::handleMemoryPressure(int pressureLevel) { + JSHandleMemoryPressure( + this, m_context, static_cast(pressureLevel)); +} #endif - void JSCExecutor::flushQueueImmediate(Value&& queue) { - auto queueStr = queue.toJSONString(); - m_delegate->callNativeModules(*this, folly::parseJson(queueStr), false); - } - - void JSCExecutor::loadModule(uint32_t bundleId, uint32_t moduleId) { - auto module = m_bundleRegistry->getModule(bundleId, moduleId); - auto sourceUrl = String::createExpectingAscii(m_context, module.name); - auto source = adoptString(std::unique_ptr(new JSBigStdString(module.code))); - evaluateScript(m_context, source, sourceUrl); - } - - // Native JS hooks - template - void JSCExecutor::installNativeHook(const char* name) { - installGlobalFunction(m_context, name, exceptionWrapMethod()); - } - - JSValueRef JSCExecutor::getNativeModule(JSObjectRef object, JSStringRef propertyName) { - if (JSC_JSStringIsEqualToUTF8CString(m_context, propertyName, "name")) { - return Value(m_context, String(m_context, "NativeModules")); - } - - return m_nativeModules.getModule(m_context, propertyName); - } - - JSValueRef JSCExecutor::getNativeExtension(JSObjectRef object, JSStringRef propertyName) { - if (m_nativeExtensionsProvider) { - folly::dynamic value = m_nativeExtensionsProvider(String::ref(m_context, propertyName).str()); - return Value::fromDynamic(m_context, std::move(value)); - } - return JSC_JSValueMakeUndefined(m_context); - } - - JSValueRef JSCExecutor::nativeRequire(size_t count, const JSValueRef arguments[]) { - if (count > 2 || count == 0) { - throw std::invalid_argument("Got wrong number of args"); - } - - uint32_t moduleId = folly::to(Value(m_context, arguments[0]).getNumberOrThrow()); - uint32_t bundleId = count == 2 ? folly::to(Value(m_context, arguments[1]).getNumberOrThrow()) : 0; - - ReactMarker::logMarker(ReactMarker::NATIVE_REQUIRE_START); - loadModule(bundleId, moduleId); - ReactMarker::logMarker(ReactMarker::NATIVE_REQUIRE_STOP); - return Value::makeUndefined(m_context); - } - - JSValueRef JSCExecutor::nativeFlushQueueImmediate( - size_t argumentCount, - const JSValueRef arguments[]) { - if (argumentCount != 1) { - throw std::invalid_argument("Got wrong number of args"); - } - - flushQueueImmediate(Value(m_context, arguments[0])); - return Value::makeUndefined(m_context); - } - - JSValueRef JSCExecutor::nativeCallSyncHook( - size_t argumentCount, - const JSValueRef arguments[]) { - if (argumentCount != 3) { - throw std::invalid_argument("Got wrong number of args"); - } - - unsigned int moduleId = Value(m_context, arguments[0]).asUnsignedInteger(); - unsigned int methodId = Value(m_context, arguments[1]).asUnsignedInteger(); - folly::dynamic args = folly::parseJson(Value(m_context, arguments[2]).toJSONString()); - - if (!args.isArray()) { - throw std::invalid_argument( - folly::to("method parameters should be array, but are ", args.typeName())); - } - - MethodCallResult result = m_delegate->callSerializableNativeHook( - *this, - moduleId, - methodId, - std::move(args)); - if (!result.hasValue()) { - return Value::makeUndefined(m_context); - } - return Value::fromDynamic(m_context, result.value()); - } - - } } +void JSCExecutor::flushQueueImmediate(Value&& queue) { + auto queueStr = queue.toJSONString(); + m_delegate->callNativeModules(*this, folly::parseJson(queueStr), false); +} + +void JSCExecutor::loadModule(uint32_t bundleId, uint32_t moduleId) { + auto module = m_bundleRegistry->getModule(bundleId, moduleId); + auto sourceUrl = String::createExpectingAscii(m_context, module.name); + auto source = adoptString( + std::unique_ptr(new JSBigStdString(module.code))); + evaluateScript(m_context, source, sourceUrl); +} + +// Native JS hooks +template +void JSCExecutor::installNativeHook(const char* name) { + installGlobalFunction(m_context, name, exceptionWrapMethod()); +} + +JSValueRef JSCExecutor::getNativeModule( + JSObjectRef object, + JSStringRef propertyName) { + if (JSC_JSStringIsEqualToUTF8CString(m_context, propertyName, "name")) { + return Value(m_context, String(m_context, "NativeModules")); + } + + return m_nativeModules.getModule(m_context, propertyName); +} + +JSValueRef JSCExecutor::getNativeExtension( + JSObjectRef object, + JSStringRef propertyName) { + if (m_nativeExtensionsProvider) { + folly::dynamic value = + m_nativeExtensionsProvider(String::ref(m_context, propertyName).str()); + return Value::fromDynamic(m_context, std::move(value)); + } + return JSC_JSValueMakeUndefined(m_context); +} + +JSValueRef JSCExecutor::nativeRequire( + size_t count, + const JSValueRef arguments[]) { + if (count > 2 || count == 0) { + throw std::invalid_argument("Got wrong number of args"); + } + + uint32_t moduleId = + folly::to(Value(m_context, arguments[0]).getNumberOrThrow()); + uint32_t bundleId = count == 2 + ? folly::to(Value(m_context, arguments[1]).getNumberOrThrow()) + : 0; + + ReactMarker::logMarker(ReactMarker::NATIVE_REQUIRE_START); + loadModule(bundleId, moduleId); + ReactMarker::logMarker(ReactMarker::NATIVE_REQUIRE_STOP); + return Value::makeUndefined(m_context); +} + +JSValueRef JSCExecutor::nativeFlushQueueImmediate( + size_t argumentCount, + const JSValueRef arguments[]) { + if (argumentCount != 1) { + throw std::invalid_argument("Got wrong number of args"); + } + + flushQueueImmediate(Value(m_context, arguments[0])); + return Value::makeUndefined(m_context); +} + +JSValueRef JSCExecutor::nativeCallSyncHook( + size_t argumentCount, + const JSValueRef arguments[]) { + if (argumentCount != 3) { + throw std::invalid_argument("Got wrong number of args"); + } + + unsigned int moduleId = Value(m_context, arguments[0]).asUnsignedInteger(); + unsigned int methodId = Value(m_context, arguments[1]).asUnsignedInteger(); + folly::dynamic args = + folly::parseJson(Value(m_context, arguments[2]).toJSONString()); + + if (!args.isArray()) { + throw std::invalid_argument(folly::to( + "method parameters should be array, but are ", args.typeName())); + } + + MethodCallResult result = m_delegate->callSerializableNativeHook( + *this, moduleId, methodId, std::move(args)); + if (!result.hasValue()) { + return Value::makeUndefined(m_context); + } + return Value::fromDynamic(m_context, result.value()); +} + +} // namespace react +} // namespace facebook From 042449f24adbf1b36036fbe6bf1c8a869021010e Mon Sep 17 00:00:00 2001 From: Marc Horowitz Date: Wed, 9 May 2018 22:01:50 -0700 Subject: [PATCH 0492/1109] simplify handleMemoryPressure conditionalization, delete some dead code Reviewed By: javache Differential Revision: D7803912 fbshipit-source-id: 0bab4be07fc006a208caa75f94b5716c99b5d265 --- ReactAndroid/src/main/jni/react/jni/BUCK | 1 - ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp | 2 -- ReactCommon/cxxreact/Instance.cpp | 2 -- ReactCommon/cxxreact/Instance.h | 3 --- ReactCommon/cxxreact/JSCExecutor.cpp | 4 ++-- ReactCommon/cxxreact/JSCExecutor.h | 2 -- ReactCommon/cxxreact/NativeToJsBridge.cpp | 3 +-- ReactCommon/cxxreact/NativeToJsBridge.h | 3 --- 8 files changed, 3 insertions(+), 17 deletions(-) diff --git a/ReactAndroid/src/main/jni/react/jni/BUCK b/ReactAndroid/src/main/jni/react/jni/BUCK index dc0f2a76d55cf0..e79a63dbde7118 100644 --- a/ReactAndroid/src/main/jni/react/jni/BUCK +++ b/ReactAndroid/src/main/jni/react/jni/BUCK @@ -47,7 +47,6 @@ rn_xplat_cxx_library( "-DLOG_TAG=\"ReactNativeJNI\"", "-DWITH_FBSYSTRACE=1", "-DWITH_INSPECTOR=1", - "-DWITH_JSC_MEMORY_PRESSURE=1", ], soname = "libreactnativejni.$(ext)", visibility = [ diff --git a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp index aeb4cc55e1099b..0c5cf5c8f68e3c 100644 --- a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp +++ b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp @@ -259,9 +259,7 @@ jlong CatalystInstanceImpl::getJavaScriptContext() { } void CatalystInstanceImpl::handleMemoryPressure(int pressureLevel) { - #ifdef WITH_JSC_MEMORY_PRESSURE instance_->handleMemoryPressure(pressureLevel); - #endif } }} diff --git a/ReactCommon/cxxreact/Instance.cpp b/ReactCommon/cxxreact/Instance.cpp index c3fd8cf607dd27..534f4b981cd84f 100644 --- a/ReactCommon/cxxreact/Instance.cpp +++ b/ReactCommon/cxxreact/Instance.cpp @@ -170,11 +170,9 @@ const ModuleRegistry &Instance::getModuleRegistry() const { ModuleRegistry &Instance::getModuleRegistry() { return *moduleRegistry_; } -#ifdef WITH_JSC_MEMORY_PRESSURE void Instance::handleMemoryPressure(int pressureLevel) { nativeToJsBridge_->handleMemoryPressure(pressureLevel); } -#endif } // namespace react } // namespace facebook diff --git a/ReactCommon/cxxreact/Instance.h b/ReactCommon/cxxreact/Instance.h index e35ce4bbe2ac3e..dffbe72465dd7d 100644 --- a/ReactCommon/cxxreact/Instance.h +++ b/ReactCommon/cxxreact/Instance.h @@ -6,7 +6,6 @@ #include #include -#include #ifndef RN_EXPORT #define RN_EXPORT __attribute__((visibility("default"))) @@ -66,9 +65,7 @@ class RN_EXPORT Instance { const ModuleRegistry &getModuleRegistry() const; ModuleRegistry &getModuleRegistry(); -#ifdef WITH_JSC_MEMORY_PRESSURE void handleMemoryPressure(int pressureLevel); -#endif private: void callNativeModules(folly::dynamic &&calls, bool isEndOfBatch); diff --git a/ReactCommon/cxxreact/JSCExecutor.cpp b/ReactCommon/cxxreact/JSCExecutor.cpp index c88da5f5b7a318..d20c97a154242c 100644 --- a/ReactCommon/cxxreact/JSCExecutor.cpp +++ b/ReactCommon/cxxreact/JSCExecutor.cpp @@ -696,12 +696,12 @@ bool JSCExecutor::isInspectable() { return canUseInspector(m_context); } -#ifdef WITH_JSC_MEMORY_PRESSURE void JSCExecutor::handleMemoryPressure(int pressureLevel) { +#ifdef WITH_JSC_MEMORY_PRESSURE JSHandleMemoryPressure( this, m_context, static_cast(pressureLevel)); -} #endif +} void JSCExecutor::flushQueueImmediate(Value&& queue) { auto queueStr = queue.toJSONString(); diff --git a/ReactCommon/cxxreact/JSCExecutor.h b/ReactCommon/cxxreact/JSCExecutor.h index 44b13aa94b2a20..b85e590d713607 100644 --- a/ReactCommon/cxxreact/JSCExecutor.h +++ b/ReactCommon/cxxreact/JSCExecutor.h @@ -89,9 +89,7 @@ class RN_EXPORT JSCExecutor : public JSExecutor, public PrivateDataBase { virtual bool isInspectable() override; -#ifdef WITH_JSC_MEMORY_PRESSURE virtual void handleMemoryPressure(int pressureLevel) override; -#endif virtual void destroy() override; diff --git a/ReactCommon/cxxreact/NativeToJsBridge.cpp b/ReactCommon/cxxreact/NativeToJsBridge.cpp index f8ae2856e602de..3cf374f068df61 100644 --- a/ReactCommon/cxxreact/NativeToJsBridge.cpp +++ b/ReactCommon/cxxreact/NativeToJsBridge.cpp @@ -11,6 +11,7 @@ #include "SystraceSection.h" #include "MethodCall.h" #include "MessageQueueThread.h" +#include "ModuleRegistry.h" #include "RAMBundleRegistry.h" #ifdef WITH_FBSYSTRACE @@ -194,13 +195,11 @@ bool NativeToJsBridge::isInspectable() { return m_executor->isInspectable(); } -#ifdef WITH_JSC_MEMORY_PRESSURE void NativeToJsBridge::handleMemoryPressure(int pressureLevel) { runOnExecutorQueue([=] (JSExecutor* executor) { executor->handleMemoryPressure(pressureLevel); }); } -#endif void NativeToJsBridge::destroy() { // All calls made through runOnExecutorQueue have an early exit if diff --git a/ReactCommon/cxxreact/NativeToJsBridge.h b/ReactCommon/cxxreact/NativeToJsBridge.h index 78d960a08a4529..7e7aaf77ee2179 100644 --- a/ReactCommon/cxxreact/NativeToJsBridge.h +++ b/ReactCommon/cxxreact/NativeToJsBridge.h @@ -7,7 +7,6 @@ #include #include -#include #include namespace folly { @@ -74,9 +73,7 @@ class NativeToJsBridge { void* getJavaScriptContext(); bool isInspectable(); - #ifdef WITH_JSC_MEMORY_PRESSURE void handleMemoryPressure(int pressureLevel); - #endif /** * Synchronously tears down the bridge and the main executor. From a363a7b501dece8fcc9ba8c95689d2177e8862a3 Mon Sep 17 00:00:00 2001 From: Marc Horowitz Date: Wed, 9 May 2018 22:01:53 -0700 Subject: [PATCH 0493/1109] Refactor ReactMarker out of Platform Reviewed By: fromcelticpark Differential Revision: D7803908 fbshipit-source-id: 957e80519c209732b163ece2bccb7c8c36ff8107 --- React/CxxBridge/RCTCxxBridge.mm | 1 + React/React.xcodeproj/project.pbxproj | 14 +++++++ .../src/main/jni/react/jni/Android.mk | 2 +- .../main/jni/react/jni/AndroidJSCFactory.cpp | 2 +- ReactAndroid/src/main/jni/react/jni/BUCK | 2 +- .../jni/{ReactMarker.cpp => JReactMarker.cpp} | 5 +-- .../jni/{ReactMarker.h => JReactMarker.h} | 3 +- ReactCommon/cxxreact/Android.mk | 3 +- ReactCommon/cxxreact/BUCK | 1 + ReactCommon/cxxreact/JSCExecutor.cpp | 2 +- ReactCommon/cxxreact/JSCNativeModules.cpp | 3 +- ReactCommon/cxxreact/JSCNativeModules.h | 3 +- ReactCommon/cxxreact/Platform.cpp | 9 ---- ReactCommon/cxxreact/Platform.h | 28 +------------ ReactCommon/cxxreact/ReactMarker.cpp | 26 ++++++++++++ ReactCommon/cxxreact/ReactMarker.h | 41 +++++++++++++++++++ 16 files changed, 98 insertions(+), 47 deletions(-) rename ReactAndroid/src/main/jni/react/jni/{ReactMarker.cpp => JReactMarker.cpp} (95%) rename ReactAndroid/src/main/jni/react/jni/{ReactMarker.h => JReactMarker.h} (94%) create mode 100644 ReactCommon/cxxreact/ReactMarker.cpp create mode 100644 ReactCommon/cxxreact/ReactMarker.h diff --git a/React/CxxBridge/RCTCxxBridge.mm b/React/CxxBridge/RCTCxxBridge.mm index 2517e29491925f..6fa0813996e92b 100644 --- a/React/CxxBridge/RCTCxxBridge.mm +++ b/React/CxxBridge/RCTCxxBridge.mm @@ -33,6 +33,7 @@ #import #import #import +#import #import #import #import diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj index ab260bb49534c9..1f6f9f2eef6978 100644 --- a/React/React.xcodeproj/project.pbxproj +++ b/React/React.xcodeproj/project.pbxproj @@ -51,6 +51,7 @@ 133957881DF76D3500EC27BE /* YGEnums.h in Headers */ = {isa = PBXBuildFile; fileRef = 130A77031DF767AF001F9587 /* YGEnums.h */; }; 133957891DF76D3500EC27BE /* YGMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = 130A77041DF767AF001F9587 /* YGMacros.h */; }; 1339578B1DF76D3500EC27BE /* Yoga.h in Headers */ = {isa = PBXBuildFile; fileRef = 130A77081DF767AF001F9587 /* Yoga.h */; }; + 133EA4E52098F6E30035B1D8 /* ReactMarker.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 13DA8A2F2097A90A00276ED4 /* ReactMarker.h */; }; 13456E931ADAD2DE009F94A7 /* RCTConvert+CoreLocation.m in Sources */ = {isa = PBXBuildFile; fileRef = 13456E921ADAD2DE009F94A7 /* RCTConvert+CoreLocation.m */; }; 134D63C31F1FEC4B008872B5 /* RCTCxxBridgeDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 134D63C21F1FEC4B008872B5 /* RCTCxxBridgeDelegate.h */; }; 134D63C41F1FEC65008872B5 /* RCTCxxBridgeDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 134D63C21F1FEC4B008872B5 /* RCTCxxBridgeDelegate.h */; }; @@ -127,6 +128,10 @@ 13D033631C1837FE0021DC29 /* RCTClipboard.m in Sources */ = {isa = PBXBuildFile; fileRef = 13D033621C1837FE0021DC29 /* RCTClipboard.m */; }; 13D9FEEB1CDCCECF00158BD7 /* RCTEventEmitter.m in Sources */ = {isa = PBXBuildFile; fileRef = 13D9FEEA1CDCCECF00158BD7 /* RCTEventEmitter.m */; }; 13D9FEEE1CDCD93000158BD7 /* RCTKeyboardObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 13D9FEED1CDCD93000158BD7 /* RCTKeyboardObserver.m */; }; + 13DA8A312097A90B00276ED4 /* ReactMarker.h in Headers */ = {isa = PBXBuildFile; fileRef = 13DA8A2F2097A90A00276ED4 /* ReactMarker.h */; }; + 13DA8A322097A90B00276ED4 /* ReactMarker.h in Headers */ = {isa = PBXBuildFile; fileRef = 13DA8A2F2097A90A00276ED4 /* ReactMarker.h */; }; + 13DA8A332097A90B00276ED4 /* ReactMarker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 13DA8A302097A90B00276ED4 /* ReactMarker.cpp */; }; + 13DA8A342097A90B00276ED4 /* ReactMarker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 13DA8A302097A90B00276ED4 /* ReactMarker.cpp */; }; 13E0674A1A70F434002CDEE1 /* RCTUIManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E067491A70F434002CDEE1 /* RCTUIManager.m */; }; 13E067561A70F44B002CDEE1 /* RCTViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E0674E1A70F44B002CDEE1 /* RCTViewManager.m */; }; 13E067571A70F44B002CDEE1 /* RCTView.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E067501A70F44B002CDEE1 /* RCTView.m */; }; @@ -1756,6 +1761,7 @@ dstPath = include/cxxreact; dstSubfolderSpec = 16; files = ( + 133EA4E52098F6E30035B1D8 /* ReactMarker.h in Copy Headers */, C669D8981F72E3DE006748EB /* RAMBundleRegistry.h in Copy Headers */, 3DA981A01E5B0E34004F2374 /* CxxModule.h in Copy Headers */, 3DA981A11E5B0E34004F2374 /* CxxNativeModule.h in Copy Headers */, @@ -2017,6 +2023,8 @@ 13D9FEEA1CDCCECF00158BD7 /* RCTEventEmitter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTEventEmitter.m; sourceTree = ""; }; 13D9FEEC1CDCD93000158BD7 /* RCTKeyboardObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTKeyboardObserver.h; sourceTree = ""; }; 13D9FEED1CDCD93000158BD7 /* RCTKeyboardObserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTKeyboardObserver.m; sourceTree = ""; }; + 13DA8A2F2097A90A00276ED4 /* ReactMarker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReactMarker.h; sourceTree = ""; }; + 13DA8A302097A90B00276ED4 /* ReactMarker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ReactMarker.cpp; sourceTree = ""; }; 13E067481A70F434002CDEE1 /* RCTUIManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTUIManager.h; sourceTree = ""; }; 13E067491A70F434002CDEE1 /* RCTUIManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTUIManager.m; sourceTree = ""; }; 13E0674B1A70F44B002CDEE1 /* RCTShadowView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTShadowView.h; sourceTree = ""; }; @@ -3041,6 +3049,8 @@ AC70D2EA1DE489FC002E6351 /* cxxreact */ = { isa = PBXGroup; children = ( + 13DA8A302097A90B00276ED4 /* ReactMarker.cpp */, + 13DA8A2F2097A90A00276ED4 /* ReactMarker.h */, E223624320875A8000108244 /* JSExecutor.cpp */, 3D92B0A71E03699D0018521A /* CxxModule.h */, 3D92B0A81E03699D0018521A /* CxxNativeModule.cpp */, @@ -3329,6 +3339,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 13DA8A322097A90B00276ED4 /* ReactMarker.h in Headers */, 3D74547E1E54759A00E74ADD /* JSModulesUnbundle.h in Headers */, C6D3801B1F71D76200621378 /* RAMBundleRegistry.h in Headers */, 27595AD51E575C7800CCE2B1 /* NativeToJsBridge.h in Headers */, @@ -3423,6 +3434,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 13DA8A312097A90B00276ED4 /* ReactMarker.h in Headers */, 3D74547F1E54759E00E74ADD /* JSModulesUnbundle.h in Headers */, C6D3801A1F71D76100621378 /* RAMBundleRegistry.h in Headers */, 27595ABA1E575C7800CCE2B1 /* NativeToJsBridge.h in Headers */, @@ -4405,6 +4417,7 @@ 13F8876E1E29726200C3C7A1 /* CxxNativeModule.cpp in Sources */, 13F887721E29726200C3C7A1 /* JSCExecutor.cpp in Sources */, 13F887741E29726200C3C7A1 /* JSCLegacyTracing.cpp in Sources */, + 13DA8A332097A90B00276ED4 /* ReactMarker.cpp in Sources */, 13F887771E29726200C3C7A1 /* JSCPerfStats.cpp in Sources */, 13F887711E29726200C3C7A1 /* JSBundleType.cpp in Sources */, 13F887791E29726200C3C7A1 /* JSCUtils.cpp in Sources */, @@ -4430,6 +4443,7 @@ 13F887851E29726300C3C7A1 /* JSCExecutor.cpp in Sources */, 13F887871E29726300C3C7A1 /* JSCLegacyTracing.cpp in Sources */, 13F8878A1E29726300C3C7A1 /* JSCPerfStats.cpp in Sources */, + 13DA8A342097A90B00276ED4 /* ReactMarker.cpp in Sources */, 13F887841E29726300C3C7A1 /* Instance.cpp in Sources */, 13F8878C1E29726300C3C7A1 /* JSCUtils.cpp in Sources */, 13F8878B1E29726300C3C7A1 /* JSCSamplingProfiler.cpp in Sources */, diff --git a/ReactAndroid/src/main/jni/react/jni/Android.mk b/ReactAndroid/src/main/jni/react/jni/Android.mk index 313950674e13d9..8fe31894cdff3d 100644 --- a/ReactAndroid/src/main/jni/react/jni/Android.mk +++ b/ReactAndroid/src/main/jni/react/jni/Android.mk @@ -9,6 +9,7 @@ LOCAL_SRC_FILES := \ CatalystInstanceImpl.cpp \ CxxModuleWrapper.cpp \ JavaModuleWrapper.cpp \ + JReactMarker.cpp \ JMessageQueueThread.cpp \ JSCPerfLogging.cpp \ JSLoader.cpp \ @@ -22,7 +23,6 @@ LOCAL_SRC_FILES := \ NativeMap.cpp \ OnLoad.cpp \ ProxyExecutor.cpp \ - ReactMarker.cpp \ ReadableNativeArray.cpp \ ReadableNativeMap.cpp \ WritableNativeArray.cpp \ diff --git a/ReactAndroid/src/main/jni/react/jni/AndroidJSCFactory.cpp b/ReactAndroid/src/main/jni/react/jni/AndroidJSCFactory.cpp index 73d774e7d5d8f1..88b80bd47d6b0a 100644 --- a/ReactAndroid/src/main/jni/react/jni/AndroidJSCFactory.cpp +++ b/ReactAndroid/src/main/jni/react/jni/AndroidJSCFactory.cpp @@ -13,7 +13,7 @@ #include "JSCPerfLogging.h" #include "JSLogging.h" -#include "ReactMarker.h" +#include "JReactMarker.h" using namespace facebook::jni; diff --git a/ReactAndroid/src/main/jni/react/jni/BUCK b/ReactAndroid/src/main/jni/react/jni/BUCK index e79a63dbde7118..1272b44f4abdd0 100644 --- a/ReactAndroid/src/main/jni/react/jni/BUCK +++ b/ReactAndroid/src/main/jni/react/jni/BUCK @@ -7,6 +7,7 @@ EXPORTED_HEADERS = [ "CxxSharedModuleWrapper.h", "JavaModuleWrapper.h", "JavaScriptExecutorHolder.h", + "JReactMarker.h", "JSLoader.h", "JSLogging.h", "MethodInvoker.h", @@ -14,7 +15,6 @@ EXPORTED_HEADERS = [ "NativeArray.h", "NativeCommon.h", "NativeMap.h", - "ReactMarker.h", "ReadableNativeArray.h", "ReadableNativeMap.h", "WritableNativeArray.h", diff --git a/ReactAndroid/src/main/jni/react/jni/ReactMarker.cpp b/ReactAndroid/src/main/jni/react/jni/JReactMarker.cpp similarity index 95% rename from ReactAndroid/src/main/jni/react/jni/ReactMarker.cpp rename to ReactAndroid/src/main/jni/react/jni/JReactMarker.cpp index c4680eedff2495..e210aedca7fb7e 100644 --- a/ReactAndroid/src/main/jni/react/jni/ReactMarker.cpp +++ b/ReactAndroid/src/main/jni/react/jni/JReactMarker.cpp @@ -1,9 +1,8 @@ // Copyright 2004-present Facebook. All Rights Reserved. -#include "ReactMarker.h" +#include "JReactMarker.h" #include -#include -#include +#include #include namespace facebook { diff --git a/ReactAndroid/src/main/jni/react/jni/ReactMarker.h b/ReactAndroid/src/main/jni/react/jni/JReactMarker.h similarity index 94% rename from ReactAndroid/src/main/jni/react/jni/ReactMarker.h rename to ReactAndroid/src/main/jni/react/jni/JReactMarker.h index 7f918c77cbcf1d..6a46d083c40e89 100644 --- a/ReactAndroid/src/main/jni/react/jni/ReactMarker.h +++ b/ReactAndroid/src/main/jni/react/jni/JReactMarker.h @@ -4,7 +4,8 @@ #include #include -#include + +#include namespace facebook { namespace react { diff --git a/ReactCommon/cxxreact/Android.mk b/ReactCommon/cxxreact/Android.mk index 8efb42a3a15018..d4b294fc17fef8 100644 --- a/ReactCommon/cxxreact/Android.mk +++ b/ReactCommon/cxxreact/Android.mk @@ -24,7 +24,8 @@ LOCAL_SRC_FILES := \ ModuleRegistry.cpp \ NativeToJsBridge.cpp \ Platform.cpp \ - RAMBundleRegistry.cpp \ + RAMBundleRegistry.cpp \ + ReactMarker.cpp \ LOCAL_C_INCLUDES := $(LOCAL_PATH)/.. LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES) diff --git a/ReactCommon/cxxreact/BUCK b/ReactCommon/cxxreact/BUCK index c5b958918f7b35..4a30b0e11c28f9 100644 --- a/ReactCommon/cxxreact/BUCK +++ b/ReactCommon/cxxreact/BUCK @@ -102,6 +102,7 @@ CXXREACT_PUBLIC_HEADERS = [ "NativeToJsBridge.h", "Platform.h", "RAMBundleRegistry.h", + "ReactMarker.h", "RecoverableError.h", "SharedProxyCxxModule.h", "SystraceSection.h", diff --git a/ReactCommon/cxxreact/JSCExecutor.cpp b/ReactCommon/cxxreact/JSCExecutor.cpp index d20c97a154242c..2f1f24fd967688 100644 --- a/ReactCommon/cxxreact/JSCExecutor.cpp +++ b/ReactCommon/cxxreact/JSCExecutor.cpp @@ -27,12 +27,12 @@ #include "JSBundleType.h" #include "JSCLegacyTracing.h" #include "JSCMemory.h" -#include "JSCNativeModules.h" #include "JSCPerfStats.h" #include "JSCSamplingProfiler.h" #include "JSCTracing.h" #include "JSCUtils.h" #include "JSModulesUnbundle.h" +#include "MessageQueueThread.h" #include "ModuleRegistry.h" #include "Platform.h" #include "RAMBundleRegistry.h" diff --git a/ReactCommon/cxxreact/JSCNativeModules.cpp b/ReactCommon/cxxreact/JSCNativeModules.cpp index 63380dfa68066a..1a440086c4862a 100644 --- a/ReactCommon/cxxreact/JSCNativeModules.cpp +++ b/ReactCommon/cxxreact/JSCNativeModules.cpp @@ -4,7 +4,8 @@ #include -#include "Platform.h" +#include "ModuleRegistry.h" +#include "ReactMarker.h" namespace facebook { namespace react { diff --git a/ReactCommon/cxxreact/JSCNativeModules.h b/ReactCommon/cxxreact/JSCNativeModules.h index 38b2c1d30d9036..e81e98d2a79527 100644 --- a/ReactCommon/cxxreact/JSCNativeModules.h +++ b/ReactCommon/cxxreact/JSCNativeModules.h @@ -5,13 +5,14 @@ #include #include -#include #include #include namespace facebook { namespace react { +class ModuleRegistry; + /** * Holds and creates JS representations of the modules in ModuleRegistry */ diff --git a/ReactCommon/cxxreact/Platform.cpp b/ReactCommon/cxxreact/Platform.cpp index b1a069d489c257..c4aeb2e0e700ef 100644 --- a/ReactCommon/cxxreact/Platform.cpp +++ b/ReactCommon/cxxreact/Platform.cpp @@ -10,15 +10,6 @@ namespace react { #pragma clang diagnostic ignored "-Wglobal-constructors" #endif -namespace ReactMarker { - -LogTaggedMarker logTaggedMarker = nullptr; -void logMarker(const ReactMarkerId markerId) { - logTaggedMarker(markerId, nullptr); -} - -} - namespace JSCNativeHooks { Hook loggingHook = nullptr; diff --git a/ReactCommon/cxxreact/Platform.h b/ReactCommon/cxxreact/Platform.h index c8a63c746bca99..be9c1737ec155a 100644 --- a/ReactCommon/cxxreact/Platform.h +++ b/ReactCommon/cxxreact/Platform.h @@ -6,8 +6,7 @@ #include #include -#include -#include +#include #include #ifndef RN_EXPORT @@ -17,31 +16,6 @@ namespace facebook { namespace react { -namespace ReactMarker { - -enum ReactMarkerId { - NATIVE_REQUIRE_START, - NATIVE_REQUIRE_STOP, - RUN_JS_BUNDLE_START, - RUN_JS_BUNDLE_STOP, - CREATE_REACT_CONTEXT_STOP, - JS_BUNDLE_STRING_CONVERT_START, - JS_BUNDLE_STRING_CONVERT_STOP, - NATIVE_MODULE_SETUP_START, - NATIVE_MODULE_SETUP_STOP, -}; - -#ifdef __APPLE__ -using LogTaggedMarker = std::function; -#else -typedef void(*LogTaggedMarker)(const ReactMarkerId, const char* tag); -#endif -extern RN_EXPORT LogTaggedMarker logTaggedMarker; - -extern void logMarker(const ReactMarkerId markerId); - -} - namespace JSCNativeHooks { using Hook = JSValueRef(*)( diff --git a/ReactCommon/cxxreact/ReactMarker.cpp b/ReactCommon/cxxreact/ReactMarker.cpp new file mode 100644 index 00000000000000..f2c28c404b3793 --- /dev/null +++ b/ReactCommon/cxxreact/ReactMarker.cpp @@ -0,0 +1,26 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include "ReactMarker.h" + +namespace facebook { +namespace react { +namespace ReactMarker { + +#if __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wglobal-constructors" +#endif + +LogTaggedMarker logTaggedMarker = nullptr; + +#if __clang__ +#pragma clang diagnostic pop +#endif + +void logMarker(const ReactMarkerId markerId) { + logTaggedMarker(markerId, nullptr); +} + +} +} +} diff --git a/ReactCommon/cxxreact/ReactMarker.h b/ReactCommon/cxxreact/ReactMarker.h new file mode 100644 index 00000000000000..26f84ea35e7328 --- /dev/null +++ b/ReactCommon/cxxreact/ReactMarker.h @@ -0,0 +1,41 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#ifdef __APPLE__ +#include +#endif + +namespace facebook { +namespace react { +namespace ReactMarker { + +enum ReactMarkerId { + NATIVE_REQUIRE_START, + NATIVE_REQUIRE_STOP, + RUN_JS_BUNDLE_START, + RUN_JS_BUNDLE_STOP, + CREATE_REACT_CONTEXT_STOP, + JS_BUNDLE_STRING_CONVERT_START, + JS_BUNDLE_STRING_CONVERT_STOP, + NATIVE_MODULE_SETUP_START, + NATIVE_MODULE_SETUP_STOP, +}; + +#ifdef __APPLE__ +using LogTaggedMarker = std::function; +#else +typedef void(*LogTaggedMarker)(const ReactMarkerId, const char* tag); +#endif + +#ifndef RN_EXPORT +#define RN_EXPORT __attribute__((visibility("default"))) +#endif + +extern RN_EXPORT LogTaggedMarker logTaggedMarker; + +extern void logMarker(const ReactMarkerId markerId); + +} +} +} From a810e6875fc5b6d1e1545c34910a109450b5aacd Mon Sep 17 00:00:00 2001 From: Marc Horowitz Date: Wed, 9 May 2018 22:01:58 -0700 Subject: [PATCH 0494/1109] move nativeLoggingHook into AndroidJSCFactory Reviewed By: fromcelticpark Differential Revision: D7803905 fbshipit-source-id: 797f5250a4a129a8dff3fb447c01837d68bea452 --- .../main/jni/react/jni/AndroidJSCFactory.cpp | 23 ++++++++++++++++ .../src/main/jni/react/jni/JSLogging.cpp | 26 ------------------- .../src/main/jni/react/jni/JSLogging.h | 10 ------- 3 files changed, 23 insertions(+), 36 deletions(-) diff --git a/ReactAndroid/src/main/jni/react/jni/AndroidJSCFactory.cpp b/ReactAndroid/src/main/jni/react/jni/AndroidJSCFactory.cpp index 88b80bd47d6b0a..5208152f54a9c0 100644 --- a/ReactAndroid/src/main/jni/react/jni/AndroidJSCFactory.cpp +++ b/ReactAndroid/src/main/jni/react/jni/AndroidJSCFactory.cpp @@ -74,6 +74,29 @@ JSValueRef nativePerformanceNow( return Value::makeNumber(ctx, (nano / (double)NANOSECONDS_IN_MILLISECOND)); } +JSValueRef nativeLoggingHook( + JSContextRef ctx, + JSObjectRef function, + JSObjectRef thisObject, + size_t argumentCount, + const JSValueRef arguments[], + JSValueRef* exception) { + android_LogPriority logLevel = ANDROID_LOG_DEBUG; + if (argumentCount > 1) { + int level = (int)Value(ctx, arguments[1]).asNumber(); + // The lowest log level we get from JS is 0. We shift and cap it to be + // in the range the Android logging method expects. + logLevel = std::min( + static_cast(level + ANDROID_LOG_DEBUG), + ANDROID_LOG_FATAL); + } + if (argumentCount > 0) { + String message = Value(ctx, arguments[0]).toString(); + reactAndroidLoggingHook(message.str(), logLevel); + } + return Value::makeUndefined(ctx); +} + } namespace detail { diff --git a/ReactAndroid/src/main/jni/react/jni/JSLogging.cpp b/ReactAndroid/src/main/jni/react/jni/JSLogging.cpp index e178542157e07f..02cd21ddd755b5 100644 --- a/ReactAndroid/src/main/jni/react/jni/JSLogging.cpp +++ b/ReactAndroid/src/main/jni/react/jni/JSLogging.cpp @@ -3,36 +3,10 @@ #include "JSLogging.h" #include -#include - -#include namespace facebook { namespace react { -JSValueRef nativeLoggingHook( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef* exception) { - android_LogPriority logLevel = ANDROID_LOG_DEBUG; - if (argumentCount > 1) { - int level = (int)Value(ctx, arguments[1]).asNumber(); - // The lowest log level we get from JS is 0. We shift and cap it to be - // in the range the Android logging method expects. - logLevel = std::min( - static_cast(level + ANDROID_LOG_DEBUG), - ANDROID_LOG_FATAL); - } - if (argumentCount > 0) { - String message = Value(ctx, arguments[0]).toString(); - reactAndroidLoggingHook(message.str(), logLevel); - } - return Value::makeUndefined(ctx); -} - void reactAndroidLoggingHook( const std::string& message, android_LogPriority logLevel) { diff --git a/ReactAndroid/src/main/jni/react/jni/JSLogging.h b/ReactAndroid/src/main/jni/react/jni/JSLogging.h index 5e4e99143a2991..aaf5718ccf158f 100644 --- a/ReactAndroid/src/main/jni/react/jni/JSLogging.h +++ b/ReactAndroid/src/main/jni/react/jni/JSLogging.h @@ -5,19 +5,9 @@ #include #include -#include - namespace facebook { namespace react { -JSValueRef nativeLoggingHook( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef* exception); - void reactAndroidLoggingHook( const std::string& message, android_LogPriority logLevel); From 9d0b7d8f31c7045d6b68ec03d48e617c4c0f07bb Mon Sep 17 00:00:00 2001 From: Marc Horowitz Date: Wed, 9 May 2018 22:02:01 -0700 Subject: [PATCH 0495/1109] Fix BUCK bugs which were breaking tests after refactoring Reviewed By: johnislarry Differential Revision: D7874275 fbshipit-source-id: 7f9c8648571bc7f41649ec4ef547e7c34b479221 --- ReactCommon/cxxreact/BUCK | 1 + ReactCommon/cxxreact/tests/BUCK | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ReactCommon/cxxreact/BUCK b/ReactCommon/cxxreact/BUCK index 4a30b0e11c28f9..9fa2e3aa404325 100644 --- a/ReactCommon/cxxreact/BUCK +++ b/ReactCommon/cxxreact/BUCK @@ -141,6 +141,7 @@ rn_xplat_cxx_library( ], fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, fbobjc_deps = APPLE_JSC_DEPS, + fbobjc_force_static = True, fbobjc_frameworks = [ "$SDKROOT/System/Library/Frameworks/JavaScriptCore.framework", ], diff --git a/ReactCommon/cxxreact/tests/BUCK b/ReactCommon/cxxreact/tests/BUCK index e78b7692b1d7fb..67160139c88269 100644 --- a/ReactCommon/cxxreact/tests/BUCK +++ b/ReactCommon/cxxreact/tests/BUCK @@ -1,4 +1,4 @@ -load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target") +load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "APPLE_JSC_DEPS", "ANDROID_JSC_DEPS") TEST_SRCS = [ "RecoverableErrorTest.cpp", @@ -28,7 +28,7 @@ if not IS_OSS_BUILD: 'xplat//third-party/linker_lib:android', 'xplat//third-party/gmock:gtest', react_native_xplat_target('cxxreact:bridge'), - ], + ] + ANDROID_JSC_DEPS, visibility = [ 'fbandroid//instrumentation_tests/...' ], @@ -47,7 +47,7 @@ if not IS_OSS_BUILD: 'xplat//third-party/gmock:gtest', react_native_xplat_target('cxxreact:bridge'), react_native_xplat_target('jschelpers:jschelpers'), - ], + ] + APPLE_JSC_DEPS, visibility = [ react_native_xplat_target('cxxreact/...'), ], From 3bc2696d652184fc4676f2fbba1d56e604428d03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Wed, 9 May 2018 23:26:39 -0700 Subject: [PATCH 0496/1109] Update Android docker images Summary: Quick update to switch to a new React Native CI org on Docker Hub. Note that the images are not yet automatically generated on CI. We could do this on Circle CI in certain scenarios: - Base image needs to be updated whenever the Android development environment has changed (e.g. switch to a new SDK version, build tools, etc) - Tests image should ideally be updated on each commit This PR should be safe to land as Circle CI is not yet using these images. Closes https://github.com/facebook/react-native/pull/19192 Differential Revision: D7939209 Pulled By: hramos fbshipit-source-id: 0f845a8fffbf8f5b9cecef4fa0ba802bc755f7aa --- ContainerShip/Dockerfile.android | 10 +++++++++- ContainerShip/Dockerfile.android-base | 15 +++++++++++++++ package.json | 6 +++--- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/ContainerShip/Dockerfile.android b/ContainerShip/Dockerfile.android index f7a207aea3e557..a72a4b64403e84 100644 --- a/ContainerShip/Dockerfile.android +++ b/ContainerShip/Dockerfile.android @@ -1,4 +1,12 @@ -FROM hramos/android-base:latest +# React Native Android Unit Tests +# +# This image builds upon the React Native Base Android Development Environment +# image. Ideally, this image would be rebuilt with any new commit to the master +# branch. Doing so will catch issues such as BUCK failing to fetch dependencies +# or run tests, as well as unit test failures. +FROM reactnativeci/android-base:latest + +LABEL Description="This image prepares and runs React Native's Android tests." maintainer "Héctor Ramos " # set default environment variables ENV GRADLE_OPTS="-Dorg.gradle.daemon=false -Dorg.gradle.jvmargs=\"-Xmx512m -XX:+HeapDumpOnOutOfMemoryError\"" diff --git a/ContainerShip/Dockerfile.android-base b/ContainerShip/Dockerfile.android-base index 93a1aafa811787..083903341e07ab 100644 --- a/ContainerShip/Dockerfile.android-base +++ b/ContainerShip/Dockerfile.android-base @@ -1,5 +1,20 @@ +# React Native Base Android Development Environment +# +# This image provides a base Android development environment for React Native, +# including, but not limited to, the Android SDK, Android NDK, Node, and BUCK. +# These are required in order to run React Native's Android unit and integration +# tests. +# +# This image is not currently built automatically as part of React Native's CI +# infrastructure. It should not be necessary to rebuild this image while the +# Android dependencies (Android SDK version, build tools version, etc) remain +# equal. The operations performed to build this image are those that tend to +# remain stable across commits in any given React Native release. + FROM library/ubuntu:16.04 +LABEL Description="This image provides a base Android development environment for React Native, and may be used to run tests." maintainer "Héctor Ramos " + # set default build arguments ARG ANDROID_TOOLS_VERSION=25.2.5 ARG BUCK_VERSION=v2018.02.16.01 diff --git a/package.json b/package.json index 02d8deb8c636d4..f345d390953122 100644 --- a/package.json +++ b/package.json @@ -128,9 +128,9 @@ "lint": "eslint .", "prettier": "find . -name node_modules -prune -or -name '*.js' -print | xargs prettier --write", "start": "/usr/bin/env bash -c './scripts/packager.sh \"$@\" || true' --", - "docker-setup-android": "docker pull hramos/android-base:latest", - "docker-build-android-base": "docker build -t hramos/android-base -f ContainerShip/Dockerfile.android-base .", - "docker-build-android": "docker build -t react/android -f ContainerShip/Dockerfile.android .", + "docker-setup-android": "docker pull reactnativeci/android-base:latest", + "docker-build-android-base": "docker build -t reactnativeci/android-base -f ContainerShip/Dockerfile.android-base .", + "docker-build-android": "docker build -t reactnativeci/android -f ContainerShip/Dockerfile.android .", "test-android-run-instrumentation": "docker run --cap-add=SYS_ADMIN -it react/android bash ContainerShip/scripts/run-android-docker-instrumentation-tests.sh", "test-android-run-unit": "docker run --cap-add=SYS_ADMIN -it react/android bash ContainerShip/scripts/run-android-docker-unit-tests.sh", "test-android-run-e2e": "docker run --privileged -it react/android bash ContainerShip/scripts/run-ci-e2e-tests.sh --android --js", From c2c352024f3cc5c3f26cc4cc75b6672b53d4982a Mon Sep 17 00:00:00 2001 From: Andrey Mishanin Date: Thu, 10 May 2018 01:43:01 -0700 Subject: [PATCH 0497/1109] Back out "[react-native][PR] Prevent console logging on iOS 11.3+ within WebSocket" Differential Revision: D7947829 Ninja: master broken fbshipit-source-id: 282c574897684ce48e9e7461067805a3ec5c1de1 --- .../WebSocket/RCTReconnectingWebSocket.m | 28 ------------------- 1 file changed, 28 deletions(-) diff --git a/Libraries/WebSocket/RCTReconnectingWebSocket.m b/Libraries/WebSocket/RCTReconnectingWebSocket.m index 55ed86f7b22922..04e5dee57b67e7 100644 --- a/Libraries/WebSocket/RCTReconnectingWebSocket.m +++ b/Libraries/WebSocket/RCTReconnectingWebSocket.m @@ -19,29 +19,6 @@ #if RCT_DEV // Only supported in dev mode -#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 100300 /* __IPHONE_10_3 */ - -// From https://github.com/apple/swift/blob/ad40c770bfe372f879b530443a3d94761fe258a6/stdlib/public/SDK/os/os_log.m -typedef struct os_log_pack_s { - uint64_t olp_continuous_time; - struct timespec olp_wall_time; - const void *olp_mh; - const void *olp_pc; - const char *olp_format; - uint8_t olp_data[0]; -} os_log_pack_s, *os_log_pack_t; - -static void (*orig__nwlog_pack)(os_log_pack_t pack, os_log_type_t logType); - -static void my__nwlog_pack(os_log_pack_t pack, os_log_type_t logType) -{ - if (logType == OS_LOG_TYPE_ERROR && strstr(pack->olp_format, "Connection has no connected handler") == NULL) { - orig__nwlog_pack(pack, logType); - } -} - -#endif /* __IPHONE_10_3 */ - static void (*orig_nwlog_legacy_v)(int, char*, va_list); static void my_nwlog_legacy_v(int level, char *format, va_list args) { @@ -86,11 +63,6 @@ + (void)load rebind_symbols((struct rebinding[1]){ {"nwlog_legacy_v", my_nwlog_legacy_v, (void *)&orig_nwlog_legacy_v} }, 1); -#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 100300 /* __IPHONE_10_3 */ - rebind_symbols((struct rebinding[1]){ - {"__nwlog_pack", my__nwlog_pack, (void *)&orig__nwlog_pack} - }, 1); -#endif /* __IPHONE_10_3 */ #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */ rebind_symbols((struct rebinding[1]){ {"_os_log_error_impl", my_os_log_error_impl, (void *)&orig_os_log_error_impl} From d4d515cdc34858ba2c41353184ed83f7922033c0 Mon Sep 17 00:00:00 2001 From: Riley Dulin Date: Thu, 10 May 2018 10:45:36 -0700 Subject: [PATCH 0498/1109] MessageQueue not initializing inCall Reviewed By: yungsters Differential Revision: D7898700 fbshipit-source-id: c2b4d6e75e7f5871cd40b00bd173e6f1a929b26a --- Libraries/BatchedBridge/MessageQueue.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Libraries/BatchedBridge/MessageQueue.js b/Libraries/BatchedBridge/MessageQueue.js index 93a759154cb0f5..a5208d81b70d56 100644 --- a/Libraries/BatchedBridge/MessageQueue.js +++ b/Libraries/BatchedBridge/MessageQueue.js @@ -46,7 +46,6 @@ class MessageQueue { _successCallbacks: {[key: number]: ?Function}; _failureCallbacks: {[key: number]: ?Function}; _callID: number; - _inCall: number; _lastFlush: number; _eventLoopStartTime: number; @@ -248,8 +247,7 @@ class MessageQueue { const now = new Date().getTime(); if ( global.nativeFlushQueueImmediate && - (now - this._lastFlush >= MIN_TIME_BETWEEN_FLUSHES_MS || - this._inCall === 0) + now - this._lastFlush >= MIN_TIME_BETWEEN_FLUSHES_MS ) { var queue = this._queue; this._queue = [[], [], [], this._callID]; @@ -286,7 +284,6 @@ class MessageQueue { */ __guard(fn: () => void) { - this._inCall++; if (this.__shouldPauseOnThrow()) { fn(); } else { @@ -296,7 +293,6 @@ class MessageQueue { ErrorUtils.reportFatalError(error); } } - this._inCall--; } // MessageQueue installs a global handler to catch all exceptions where JS users can register their own behavior From 266016c521f9f5c0effe56ade85036b300eaa684 Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Thu, 10 May 2018 15:00:30 -0700 Subject: [PATCH 0499/1109] iOS: Mark Scheduler class as final Summary: This fixes some build flavor: ``` error: destructor called on non-final 'facebook::react::Scheduler' that has virtual functions but non-virtual destructor [-Werror,-Wdelete-non-virtual-dtor] ``` Reviewed By: shergin Differential Revision: D7958022 fbshipit-source-id: 6ff64bdaa221b5c6430a98244d40d6d3789ba937 --- ReactCommon/fabric/uimanager/Scheduler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactCommon/fabric/uimanager/Scheduler.h b/ReactCommon/fabric/uimanager/Scheduler.h index cadbc4caa2edae..c3730a03346fd8 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.h +++ b/ReactCommon/fabric/uimanager/Scheduler.h @@ -21,7 +21,7 @@ class FabricUIManager; /* * Scheduler coordinates Shadow Tree updates and event flows. */ -class Scheduler: +class Scheduler final: public UIManagerDelegate, public ShadowTreeDelegate { From 8f5ebe5952d0675b463137103a82f3fb0c26ae0d Mon Sep 17 00:00:00 2001 From: Eli White Date: Thu, 10 May 2018 15:44:52 -0700 Subject: [PATCH 0500/1109] Convert react-native-github/Libraries to let/const Reviewed By: sahrens Differential Revision: D7956042 fbshipit-source-id: 221851aa311f3cdd6326497352b366048db0a1bb --- Libraries/ART/ARTSerializablePath.js | 16 +- Libraries/ART/ReactNativeART.js | 158 ++++++------- Libraries/Alert/Alert.js | 10 +- Libraries/Alert/AlertIOS.js | 16 +- Libraries/Alert/RCTAlertManager.android.js | 2 +- Libraries/Alert/RCTAlertManager.ios.js | 2 +- Libraries/Animated/src/AnimatedWeb.js | 2 +- .../Animated/src/NativeAnimatedHelper.js | 4 +- Libraries/Animated/src/SpringConfig.js | 8 +- .../Animated/src/__tests__/Animated-test.js | 210 +++++++++--------- .../Animated/src/__tests__/Easing-test.js | 42 ++-- .../src/__tests__/Interpolation-test.js | 42 ++-- .../Animated/src/__tests__/bezier-test.js | 49 ++-- Libraries/Animated/src/bezier.js | 38 ++-- .../__mocks__/MessageQueueTestConfig.js | 4 +- .../__mocks__/MessageQueueTestModule.js | 2 +- Libraries/Blob/__tests__/Blob-test.js | 2 +- Libraries/Blob/__tests__/BlobManager-test.js | 4 +- Libraries/Blob/__tests__/FileReader-test.js | 4 +- Libraries/BugReporting/getReactData.js | 36 +-- Libraries/CameraRoll/ImagePickerIOS.js | 4 +- Libraries/Color/normalizeColor.js | 36 +-- .../__tests__/parseErrorStack-test.js | 10 +- Libraries/Core/__mocks__/ErrorUtils.js | 2 +- Libraries/Experimental/IncrementalExample.js | 2 +- Libraries/Geolocation/Geolocation.js | 22 +- Libraries/Image/AssetRegistry.js | 2 +- Libraries/Image/AssetSourceResolver.js | 14 +- Libraries/Image/Image.android.js | 42 ++-- Libraries/Image/ImageResizeMode.js | 4 +- Libraries/Image/ImageStylePropTypes.js | 14 +- Libraries/Image/RelativeImageStub.js | 2 +- .../__tests__/resolveAssetSource-test.js | 14 +- Libraries/Image/resolveAssetSource.js | 2 +- Libraries/Inspector/BorderBox.js | 8 +- Libraries/Inspector/BoxInspector.js | 24 +- Libraries/Inspector/ElementBox.js | 24 +- Libraries/Inspector/InspectorOverlay.js | 20 +- Libraries/Inspector/PerformanceOverlay.js | 20 +- Libraries/Inspector/StyleInspector.js | 14 +- Libraries/Inspector/resolveBoxStyle.js | 8 +- Libraries/Interaction/InteractionManager.js | 8 +- Libraries/Interaction/InteractionMixin.js | 6 +- .../__tests__/InteractionMixin-test.js | 12 +- Libraries/Lists/ListView/ListView.js | 138 ++++++------ .../Lists/ListView/ListViewDataSource.js | 60 ++--- Libraries/Modal/Modal.js | 2 +- Libraries/Network/FormData.js | 4 +- Libraries/Network/XHRInterceptor.js | 12 +- Libraries/Network/XMLHttpRequest.js | 6 +- .../PushNotificationIOS.js | 8 +- Libraries/RCTTest/SnapshotViewIOS.ios.js | 20 +- Libraries/ReactNative/UIManagerStatTracker.js | 16 +- Libraries/ReactNative/YellowBox.js | 2 +- Libraries/ReactNative/queryLayoutByID.js | 4 +- Libraries/Sample/Sample.android.js | 4 +- Libraries/Sample/Sample.ios.js | 4 +- Libraries/Settings/Settings.android.js | 2 +- Libraries/Settings/Settings.ios.js | 16 +- Libraries/Storage/AsyncStorage.js | 24 +- Libraries/StyleSheet/ColorPropType.js | 8 +- Libraries/StyleSheet/LayoutPropTypes.js | 4 +- Libraries/StyleSheet/PointPropType.js | 6 +- Libraries/StyleSheet/StyleSheetPropType.js | 8 +- Libraries/StyleSheet/StyleSheetValidation.js | 22 +- Libraries/StyleSheet/TransformPropTypes.js | 10 +- .../StyleSheet/__tests__/flattenStyle-test.js | 24 +- .../__tests__/normalizeColor-test.js | 2 +- .../StyleSheet/__tests__/processColor-test.js | 36 +-- .../__tests__/setNormalizedColorAlpha-test.js | 6 +- Libraries/StyleSheet/flattenStyle.js | 8 +- Libraries/StyleSheet/processTransform.js | 28 +-- Libraries/Text/TextUpdateTest.js | 16 +- Libraries/Utilities/BackAndroid.js | 6 +- Libraries/Utilities/BackHandler.android.js | 16 +- Libraries/Utilities/BackHandler.ios.js | 8 +- Libraries/Utilities/Dimensions.js | 14 +- Libraries/Utilities/HMRLoadingView.android.js | 2 +- Libraries/Utilities/HeapCapture.js | 4 +- Libraries/Utilities/MatrixMath.js | 111 +++++---- Libraries/Utilities/PixelRatio.js | 4 +- .../Utilities/__tests__/MatrixMath-test.js | 8 +- .../Utilities/__tests__/Platform-test.js | 4 +- .../__tests__/buildStyleInterpolator-test.js | 68 +++--- .../deepFreezeAndThrowOnMutationInDev-test.js | 20 +- .../Utilities/__tests__/groupByEveryN-test.js | 2 +- .../Utilities/__tests__/truncate-test.js | 2 +- Libraries/Utilities/buildStyleInterpolator.js | 86 +++---- .../Utilities/createStrictShapeTypeChecker.js | 18 +- .../deepFreezeAndThrowOnMutationInDev.js | 2 +- .../differ/__tests__/deepDiffer-test.js | 4 +- Libraries/Utilities/differ/deepDiffer.js | 10 +- Libraries/Utilities/differ/insetsDiffer.js | 4 +- Libraries/Utilities/differ/matricesDiffer.js | 2 +- Libraries/Utilities/differ/pointsDiffer.js | 4 +- Libraries/Utilities/differ/sizesDiffer.js | 4 +- Libraries/Utilities/dismissKeyboard.js | 2 +- Libraries/Utilities/groupByEveryN.js | 6 +- Libraries/Utilities/logError.js | 4 +- Libraries/Utilities/mergeIntoFast.js | 4 +- Libraries/Utilities/stringifySafe.js | 4 +- Libraries/Utilities/truncate.js | 4 +- Libraries/Vibration/Vibration.js | 10 +- Libraries/Vibration/VibrationIOS.android.js | 4 +- Libraries/Vibration/VibrationIOS.ios.js | 6 +- .../WebSocket/__tests__/WebSocket-test.js | 2 +- Libraries/vendor/core/Map.js | 72 +++--- Libraries/vendor/core/Set.js | 18 +- .../core/_shouldPolyfillES6Collection.js | 4 +- Libraries/vendor/core/getObjectValues.js | 4 +- Libraries/vendor/core/isEmpty.js | 2 +- Libraries/vendor/core/mergeHelpers.js | 8 +- Libraries/vendor/core/toIterator.js | 30 +-- .../selection/DocumentSelectionState.js | 2 +- 114 files changed, 1018 insertions(+), 1036 deletions(-) diff --git a/Libraries/ART/ARTSerializablePath.js b/Libraries/ART/ARTSerializablePath.js index 08c4530222dff3..de02f9498d069c 100644 --- a/Libraries/ART/ARTSerializablePath.js +++ b/Libraries/ART/ARTSerializablePath.js @@ -9,16 +9,16 @@ // TODO: Move this into an ART mode called "serialized" or something -var Class = require('art/core/class.js'); -var Path = require('art/core/path.js'); +const Class = require('art/core/class.js'); +const Path = require('art/core/path.js'); -var MOVE_TO = 0; -var CLOSE = 1; -var LINE_TO = 2; -var CURVE_TO = 3; -var ARC = 4; +const MOVE_TO = 0; +const CLOSE = 1; +const LINE_TO = 2; +const CURVE_TO = 3; +const ARC = 4; -var SerializablePath = Class(Path, { +const SerializablePath = Class(Path, { initialize: function(path) { this.reset(); diff --git a/Libraries/ART/ReactNativeART.js b/Libraries/ART/ReactNativeART.js index 9b0a725cd140ec..0f32fa2dae2a85 100644 --- a/Libraries/ART/ReactNativeART.js +++ b/Libraries/ART/ReactNativeART.js @@ -7,17 +7,17 @@ */ 'use strict'; -var Color = require('art/core/color'); -var Path = require('ARTSerializablePath'); -var Transform = require('art/core/transform'); +const Color = require('art/core/color'); +const Path = require('ARTSerializablePath'); +const Transform = require('art/core/transform'); -var React = require('React'); -var PropTypes = require('prop-types'); -var ReactNativeViewAttributes = require('ReactNativeViewAttributes'); +const React = require('React'); +const PropTypes = require('prop-types'); +const ReactNativeViewAttributes = require('ReactNativeViewAttributes'); -var createReactNativeComponentClass = require('createReactNativeComponentClass'); -var merge = require('merge'); -var invariant = require('fbjs/lib/invariant'); +const createReactNativeComponentClass = require('createReactNativeComponentClass'); +const merge = require('merge'); +const invariant = require('fbjs/lib/invariant'); // Diff Helpers @@ -28,7 +28,7 @@ function arrayDiffer(a, b) { if (a.length !== b.length) { return true; } - for (var i = 0; i < a.length; i++) { + for (let i = 0; i < a.length; i++) { if (a[i] !== b[i]) { return true; } @@ -62,22 +62,22 @@ function fontAndLinesDiffer(a, b) { // Native Attributes -var SurfaceViewAttributes = merge(ReactNativeViewAttributes.UIView, { +const SurfaceViewAttributes = merge(ReactNativeViewAttributes.UIView, { // This should contain pixel information such as width, height and // resolution to know what kind of buffer needs to be allocated. // Currently we rely on UIViews and style to figure that out. }); -var NodeAttributes = { +const NodeAttributes = { transform: { diff: arrayDiffer }, opacity: true, }; -var GroupAttributes = merge(NodeAttributes, { +const GroupAttributes = merge(NodeAttributes, { clipping: { diff: arrayDiffer } }); -var RenderableAttributes = merge(NodeAttributes, { +const RenderableAttributes = merge(NodeAttributes, { fill: { diff: arrayDiffer }, stroke: { diff: arrayDiffer }, strokeWidth: true, @@ -86,11 +86,11 @@ var RenderableAttributes = merge(NodeAttributes, { strokeDash: { diff: arrayDiffer }, }); -var ShapeAttributes = merge(RenderableAttributes, { +const ShapeAttributes = merge(RenderableAttributes, { d: { diff: arrayDiffer }, }); -var TextAttributes = merge(RenderableAttributes, { +const TextAttributes = merge(RenderableAttributes, { alignment: true, frame: { diff: fontAndLinesDiffer }, path: { diff: arrayDiffer } @@ -98,25 +98,25 @@ var TextAttributes = merge(RenderableAttributes, { // Native Components -var NativeSurfaceView = createReactNativeComponentClass('ARTSurfaceView', +const NativeSurfaceView = createReactNativeComponentClass('ARTSurfaceView', () => ({ validAttributes: SurfaceViewAttributes, uiViewClassName: 'ARTSurfaceView', })); -var NativeGroup = createReactNativeComponentClass('ARTGroup', +const NativeGroup = createReactNativeComponentClass('ARTGroup', () => ({ validAttributes: GroupAttributes, uiViewClassName: 'ARTGroup', })); -var NativeShape = createReactNativeComponentClass('ARTShape', +const NativeShape = createReactNativeComponentClass('ARTShape', () => ({ validAttributes: ShapeAttributes, uiViewClassName: 'ARTShape', })); -var NativeText = createReactNativeComponentClass('ARTText', +const NativeText = createReactNativeComponentClass('ARTText', () => ({ validAttributes: TextAttributes, uiViewClassName: 'ARTText', @@ -149,9 +149,9 @@ class Surface extends React.Component { } render() { - var props = this.props; - var w = extractNumber(props.width, 0); - var h = extractNumber(props.height, 0); + const props = this.props; + const w = extractNumber(props.width, 0); + const h = extractNumber(props.height, 0); return ( {this.props.children} @@ -172,12 +172,12 @@ function extractNumber(value, defaultValue) { return +value; } -var pooledTransform = new Transform(); +const pooledTransform = new Transform(); function extractTransform(props) { - var scaleX = props.scaleX != null ? props.scaleX : + const scaleX = props.scaleX != null ? props.scaleX : props.scale != null ? props.scale : 1; - var scaleY = props.scaleY != null ? props.scaleY : + const scaleY = props.scaleY != null ? props.scaleY : props.scale != null ? props.scale : 1; pooledTransform @@ -219,7 +219,7 @@ class Group extends React.Component { }; render() { - var props = this.props; + const props = this.props; invariant( this.context.isInSurface, 'ART: must be a child of a ' @@ -236,14 +236,14 @@ class Group extends React.Component { class ClippingRectangle extends React.Component { render() { - var props = this.props; - var x = extractNumber(props.x, 0); - var y = extractNumber(props.y, 0); - var w = extractNumber(props.width, 0); - var h = extractNumber(props.height, 0); - var clipping = [x, y, w, h]; + const props = this.props; + const x = extractNumber(props.x, 0); + const y = extractNumber(props.y, 0); + const w = extractNumber(props.width, 0); + const h = extractNumber(props.height, 0); + const clipping = [x, y, w, h]; // The current clipping API requires x and y to be ignored in the transform - var propsExcludingXAndY = merge(props); + const propsExcludingXAndY = merge(props); delete propsExcludingXAndY.x; delete propsExcludingXAndY.y; return ( @@ -259,13 +259,13 @@ class ClippingRectangle extends React.Component { // Renderables -var SOLID_COLOR = 0; -var LINEAR_GRADIENT = 1; -var RADIAL_GRADIENT = 2; -var PATTERN = 3; +const SOLID_COLOR = 0; +const LINEAR_GRADIENT = 1; +const RADIAL_GRADIENT = 2; +const PATTERN = 3; function insertColorIntoArray(color, targetArray, atIndex) { - var c = new Color(color); + const c = new Color(color); targetArray[atIndex + 0] = c.red / 255; targetArray[atIndex + 1] = c.green / 255; targetArray[atIndex + 2] = c.blue / 255; @@ -273,14 +273,14 @@ function insertColorIntoArray(color, targetArray, atIndex) { } function insertColorsIntoArray(stops, targetArray, atIndex) { - var i = 0; + let i = 0; if ('length' in stops) { while (i < stops.length) { insertColorIntoArray(stops[i], targetArray, atIndex + i * 4); i++; } } else { - for (var offset in stops) { + for (const offset in stops) { insertColorIntoArray(stops[offset], targetArray, atIndex + i * 4); i++; } @@ -289,8 +289,8 @@ function insertColorsIntoArray(stops, targetArray, atIndex) { } function insertOffsetsIntoArray(stops, targetArray, atIndex, multi, reverse) { - var offsetNumber; - var i = 0; + let offsetNumber; + let i = 0; if ('length' in stops) { while (i < stops.length) { offsetNumber = i / (stops.length - 1) * multi; @@ -298,7 +298,7 @@ function insertOffsetsIntoArray(stops, targetArray, atIndex, multi, reverse) { i++; } } else { - for (var offsetString in stops) { + for (const offsetString in stops) { offsetNumber = (+offsetString) * multi; targetArray[atIndex + i] = reverse ? 1 - offsetNumber : offsetNumber; i++; @@ -308,21 +308,21 @@ function insertOffsetsIntoArray(stops, targetArray, atIndex, multi, reverse) { } function insertColorStopsIntoArray(stops, targetArray, atIndex) { - var lastIndex = insertColorsIntoArray(stops, targetArray, atIndex); + const lastIndex = insertColorsIntoArray(stops, targetArray, atIndex); insertOffsetsIntoArray(stops, targetArray, lastIndex, 1, false); } function insertDoubleColorStopsIntoArray(stops, targetArray, atIndex) { - var lastIndex = insertColorsIntoArray(stops, targetArray, atIndex); + let lastIndex = insertColorsIntoArray(stops, targetArray, atIndex); lastIndex = insertColorsIntoArray(stops, targetArray, lastIndex); lastIndex = insertOffsetsIntoArray(stops, targetArray, lastIndex, 0.5, false); insertOffsetsIntoArray(stops, targetArray, lastIndex, 0.5, true); } function applyBoundingBoxToBrushData(brushData, props) { - var type = brushData[0]; - var width = +props.width; - var height = +props.height; + const type = brushData[0]; + const width = +props.width; + const height = +props.height; if (type === LINEAR_GRADIENT) { brushData[1] *= width; brushData[2] *= height; @@ -356,7 +356,7 @@ function extractBrush(colorOrBrush, props) { } return colorOrBrush._brush; } - var c = new Color(colorOrBrush); + const c = new Color(colorOrBrush); return [SOLID_COLOR, c.red / 255, c.green / 255, c.blue / 255, c.alpha]; } @@ -364,7 +364,7 @@ function extractColor(color) { if (color == null) { return null; } - var c = new Color(color); + const c = new Color(color); return [c.red / 255, c.green / 255, c.blue / 255, c.alpha]; } @@ -391,9 +391,9 @@ function extractStrokeJoin(strokeJoin) { class Shape extends React.Component { render() { - var props = this.props; - var path = props.d || childrenAsString(props.children); - var d = (path instanceof Path ? path : new Path(path)).toJSON(); + const props = this.props; + const path = props.d || childrenAsString(props.children); + const d = (path instanceof Path ? path : new Path(path)).toJSON(); return ( { - var cb = callbacks[id]; + const cb = callbacks[id]; cb && cb(value); }); } diff --git a/Libraries/Alert/RCTAlertManager.android.js b/Libraries/Alert/RCTAlertManager.android.js index 25297171c4ce46..57bd4740e8fc74 100644 --- a/Libraries/Alert/RCTAlertManager.android.js +++ b/Libraries/Alert/RCTAlertManager.android.js @@ -7,7 +7,7 @@ */ 'use strict'; -var NativeModules = require('NativeModules'); +const NativeModules = require('NativeModules'); function emptyCallback() {} diff --git a/Libraries/Alert/RCTAlertManager.ios.js b/Libraries/Alert/RCTAlertManager.ios.js index 220b72c3d91ded..d64bce5b4f12be 100644 --- a/Libraries/Alert/RCTAlertManager.ios.js +++ b/Libraries/Alert/RCTAlertManager.ios.js @@ -8,6 +8,6 @@ */ 'use strict'; -var RCTAlertManager = require('NativeModules').AlertManager; +const RCTAlertManager = require('NativeModules').AlertManager; module.exports = RCTAlertManager; diff --git a/Libraries/Animated/src/AnimatedWeb.js b/Libraries/Animated/src/AnimatedWeb.js index a22bd075ec51ce..5538eb9b64c383 100644 --- a/Libraries/Animated/src/AnimatedWeb.js +++ b/Libraries/Animated/src/AnimatedWeb.js @@ -8,7 +8,7 @@ */ 'use strict'; -var AnimatedImplementation = require('AnimatedImplementation'); +const AnimatedImplementation = require('AnimatedImplementation'); module.exports = { ...AnimatedImplementation, diff --git a/Libraries/Animated/src/NativeAnimatedHelper.js b/Libraries/Animated/src/NativeAnimatedHelper.js index 61b2bde64a4d75..3142ea24c084d1 100644 --- a/Libraries/Animated/src/NativeAnimatedHelper.js +++ b/Libraries/Animated/src/NativeAnimatedHelper.js @@ -208,7 +208,7 @@ function validateTransform(configs: Array): void { } function validateStyles(styles: Object): void { - for (var key in styles) { + for (const key in styles) { if (!STYLES_WHITELIST.hasOwnProperty(key)) { throw new Error( `Style property '${key}' is not supported by native animated module`, @@ -218,7 +218,7 @@ function validateStyles(styles: Object): void { } function validateInterpolation(config: Object): void { - for (var key in config) { + for (const key in config) { if (!SUPPORTED_INTERPOLATION_PARAMS.hasOwnProperty(key)) { throw new Error( `Interpolation property '${key}' is not supported by native animated module`, diff --git a/Libraries/Animated/src/SpringConfig.js b/Libraries/Animated/src/SpringConfig.js index 6227c28301b4e3..b71fda2eacce74 100644 --- a/Libraries/Animated/src/SpringConfig.js +++ b/Libraries/Animated/src/SpringConfig.js @@ -77,11 +77,11 @@ function fromBouncinessAndSpeed( } } - var b = normalize(bounciness / 1.7, 0, 20); + let b = normalize(bounciness / 1.7, 0, 20); b = projectNormal(b, 0, 0.8); - var s = normalize(speed / 1.7, 0, 20); - var bouncyTension = projectNormal(s, 0.5, 200); - var bouncyFriction = quadraticOutInterpolation( + const s = normalize(speed / 1.7, 0, 20); + const bouncyTension = projectNormal(s, 0.5, 200); + const bouncyFriction = quadraticOutInterpolation( b, b3Nobounce(bouncyTension), 0.01 diff --git a/Libraries/Animated/src/__tests__/Animated-test.js b/Libraries/Animated/src/__tests__/Animated-test.js index d6409d7f8a9224..36b4d2a40a5042 100644 --- a/Libraries/Animated/src/__tests__/Animated-test.js +++ b/Libraries/Animated/src/__tests__/Animated-test.js @@ -8,7 +8,7 @@ */ 'use strict'; -var Animated = require('Animated'); +let Animated = require('Animated'); describe('Animated tests', () => { beforeEach(() => { jest.resetModules(); @@ -17,11 +17,11 @@ describe('Animated tests', () => { describe('Animated', () => { it('works end to end', () => { - var anim = new Animated.Value(0); + const anim = new Animated.Value(0); - var callback = jest.fn(); + const callback = jest.fn(); - var node = new Animated.__PropsOnlyForTests({ + const node = new Animated.__PropsOnlyForTests({ style: { backgroundColor: 'red', opacity: anim, @@ -83,10 +83,10 @@ describe('Animated tests', () => { }); it('does not detach on updates', () => { - var anim = new Animated.Value(0); + const anim = new Animated.Value(0); anim.__detach = jest.fn(); - var c = new Animated.View(); + const c = new Animated.View(); c.props = { style: { opacity: anim, @@ -109,10 +109,10 @@ describe('Animated tests', () => { it('stops animation when detached', () => { - var anim = new Animated.Value(0); - var callback = jest.fn(); + const anim = new Animated.Value(0); + const callback = jest.fn(); - var c = new Animated.View(); + const c = new Animated.View(); c.props = { style: { opacity: anim, @@ -129,31 +129,31 @@ describe('Animated tests', () => { }); it('triggers callback when spring is at rest', () => { - var anim = new Animated.Value(0); - var callback = jest.fn(); + const anim = new Animated.Value(0); + const callback = jest.fn(); Animated.spring(anim, {toValue: 0, velocity: 0}).start(callback); expect(callback).toBeCalled(); }); it('send toValue when an underdamped spring stops', () => { - var anim = new Animated.Value(0); - var listener = jest.fn(); + const anim = new Animated.Value(0); + const listener = jest.fn(); anim.addListener(listener); Animated.spring(anim, {toValue: 15}).start(); jest.runAllTimers(); - var lastValue = listener.mock.calls[listener.mock.calls.length - 2][0].value; + const lastValue = listener.mock.calls[listener.mock.calls.length - 2][0].value; expect(lastValue).not.toBe(15); expect(lastValue).toBeCloseTo(15); expect(anim.__getValue()).toBe(15); }); it('send toValue when a critically damped spring stops', () => { - var anim = new Animated.Value(0); - var listener = jest.fn(); + const anim = new Animated.Value(0); + const listener = jest.fn(); anim.addListener(listener); Animated.spring(anim, {stiffness: 8000, damping: 2000, toValue: 15}).start(); jest.runAllTimers(); - var lastValue = listener.mock.calls[listener.mock.calls.length - 2][0].value; + const lastValue = listener.mock.calls[listener.mock.calls.length - 2][0].value; expect(lastValue).not.toBe(15); expect(lastValue).toBeCloseTo(15); expect(anim.__getValue()).toBe(15); @@ -168,17 +168,17 @@ describe('Animated tests', () => { describe('Animated Sequence', () => { it('works with an empty sequence', () => { - var cb = jest.fn(); + const cb = jest.fn(); Animated.sequence([]).start(cb); expect(cb).toBeCalledWith({finished: true}); }); it('sequences well', () => { - var anim1 = {start: jest.fn()}; - var anim2 = {start: jest.fn()}; - var cb = jest.fn(); + const anim1 = {start: jest.fn()}; + const anim2 = {start: jest.fn()}; + const cb = jest.fn(); - var seq = Animated.sequence([anim1, anim2]); + const seq = Animated.sequence([anim1, anim2]); expect(anim1.start).not.toBeCalled(); expect(anim2.start).not.toBeCalled(); @@ -199,9 +199,9 @@ describe('Animated tests', () => { }); it('supports interrupting sequence', () => { - var anim1 = {start: jest.fn()}; - var anim2 = {start: jest.fn()}; - var cb = jest.fn(); + const anim1 = {start: jest.fn()}; + const anim2 = {start: jest.fn()}; + const cb = jest.fn(); Animated.sequence([anim1, anim2]).start(cb); @@ -213,11 +213,11 @@ describe('Animated tests', () => { }); it('supports stopping sequence', () => { - var anim1 = {start: jest.fn(), stop: jest.fn()}; - var anim2 = {start: jest.fn(), stop: jest.fn()}; - var cb = jest.fn(); + const anim1 = {start: jest.fn(), stop: jest.fn()}; + const anim2 = {start: jest.fn(), stop: jest.fn()}; + const cb = jest.fn(); - var seq = Animated.sequence([anim1, anim2]); + const seq = Animated.sequence([anim1, anim2]); seq.start(cb); seq.stop(); @@ -234,10 +234,10 @@ describe('Animated tests', () => { describe('Animated Loop', () => { it('loops indefinitely if config not specified', () => { - var animation = {start: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; - var cb = jest.fn(); + const animation = {start: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; + const cb = jest.fn(); - var loop = Animated.loop(animation); + const loop = Animated.loop(animation); expect(animation.start).not.toBeCalled(); @@ -261,10 +261,10 @@ describe('Animated tests', () => { }); it('loops indefinitely if iterations is -1', () => { - var animation = {start: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; - var cb = jest.fn(); + const animation = {start: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; + const cb = jest.fn(); - var loop = Animated.loop(animation, { iterations: -1 }); + const loop = Animated.loop(animation, { iterations: -1 }); expect(animation.start).not.toBeCalled(); @@ -288,10 +288,10 @@ describe('Animated tests', () => { }); it('loops indefinitely if iterations not specified', () => { - var animation = {start: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; - var cb = jest.fn(); + const animation = {start: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; + const cb = jest.fn(); - var loop = Animated.loop(animation, { anotherKey: 'value' }); + const loop = Animated.loop(animation, { anotherKey: 'value' }); expect(animation.start).not.toBeCalled(); @@ -315,10 +315,10 @@ describe('Animated tests', () => { }); it('loops three times if iterations is 3', () => { - var animation = {start: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; - var cb = jest.fn(); + const animation = {start: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; + const cb = jest.fn(); - var loop = Animated.loop(animation, { iterations: 3 }); + const loop = Animated.loop(animation, { iterations: 3 }); expect(animation.start).not.toBeCalled(); @@ -342,10 +342,10 @@ describe('Animated tests', () => { }); it('does not loop if iterations is 1', () => { - var animation = {start: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; - var cb = jest.fn(); + const animation = {start: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; + const cb = jest.fn(); - var loop = Animated.loop(animation, { iterations: 1 }); + const loop = Animated.loop(animation, { iterations: 1 }); expect(animation.start).not.toBeCalled(); @@ -359,10 +359,10 @@ describe('Animated tests', () => { }); it('does not animate if iterations is 0', () => { - var animation = {start: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; - var cb = jest.fn(); + const animation = {start: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; + const cb = jest.fn(); - var loop = Animated.loop(animation, { iterations: 0 }); + const loop = Animated.loop(animation, { iterations: 0 }); expect(animation.start).not.toBeCalled(); @@ -373,8 +373,8 @@ describe('Animated tests', () => { }); it('supports interrupting an indefinite loop', () => { - var animation = {start: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; - var cb = jest.fn(); + const animation = {start: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; + const cb = jest.fn(); Animated.loop(animation).start(cb); expect(animation.start).toBeCalled(); @@ -391,10 +391,10 @@ describe('Animated tests', () => { }); it('supports stopping loop', () => { - var animation = {start: jest.fn(), stop: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; - var cb = jest.fn(); + const animation = {start: jest.fn(), stop: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; + const cb = jest.fn(); - var loop = Animated.loop(animation); + const loop = Animated.loop(animation); loop.start(cb); loop.stop(); @@ -411,14 +411,14 @@ describe('Animated tests', () => { describe('Animated Parallel', () => { it('works with an empty parallel', () => { - var cb = jest.fn(); + const cb = jest.fn(); Animated.parallel([]).start(cb); expect(cb).toBeCalledWith({finished: true}); }); it('works with an empty element in array', () => { - var anim1 = {start: jest.fn()}; - var cb = jest.fn(); + const anim1 = {start: jest.fn()}; + const cb = jest.fn(); Animated.parallel([null, anim1]).start(cb); expect(anim1.start).toBeCalled(); @@ -428,11 +428,11 @@ describe('Animated tests', () => { }); it('parellelizes well', () => { - var anim1 = {start: jest.fn()}; - var anim2 = {start: jest.fn()}; - var cb = jest.fn(); + const anim1 = {start: jest.fn()}; + const anim2 = {start: jest.fn()}; + const cb = jest.fn(); - var par = Animated.parallel([anim1, anim2]); + const par = Animated.parallel([anim1, anim2]); expect(anim1.start).not.toBeCalled(); expect(anim2.start).not.toBeCalled(); @@ -451,11 +451,11 @@ describe('Animated tests', () => { }); it('supports stopping parallel', () => { - var anim1 = {start: jest.fn(), stop: jest.fn()}; - var anim2 = {start: jest.fn(), stop: jest.fn()}; - var cb = jest.fn(); + const anim1 = {start: jest.fn(), stop: jest.fn()}; + const anim2 = {start: jest.fn(), stop: jest.fn()}; + const cb = jest.fn(); - var seq = Animated.parallel([anim1, anim2]); + const seq = Animated.parallel([anim1, anim2]); seq.start(cb); seq.stop(); @@ -472,12 +472,12 @@ describe('Animated tests', () => { it('does not call stop more than once when stopping', () => { - var anim1 = {start: jest.fn(), stop: jest.fn()}; - var anim2 = {start: jest.fn(), stop: jest.fn()}; - var anim3 = {start: jest.fn(), stop: jest.fn()}; - var cb = jest.fn(); + const anim1 = {start: jest.fn(), stop: jest.fn()}; + const anim2 = {start: jest.fn(), stop: jest.fn()}; + const anim3 = {start: jest.fn(), stop: jest.fn()}; + const cb = jest.fn(); - var seq = Animated.parallel([anim1, anim2, anim3]); + const seq = Animated.parallel([anim1, anim2, anim3]); seq.start(cb); anim1.start.mock.calls[0][0]({finished: false}); @@ -502,8 +502,8 @@ describe('Animated tests', () => { describe('Animated delays', () => { it('should call anim after delay in sequence', () => { - var anim = {start: jest.fn(), stop: jest.fn()}; - var cb = jest.fn(); + const anim = {start: jest.fn(), stop: jest.fn()}; + const cb = jest.fn(); Animated.sequence([ Animated.delay(1000), anim, @@ -515,7 +515,7 @@ describe('Animated tests', () => { expect(cb).toBeCalledWith({finished: true}); }); it('should run stagger to end', () => { - var cb = jest.fn(); + const cb = jest.fn(); Animated.stagger(1000, [ Animated.delay(1000), Animated.delay(1000), @@ -528,17 +528,17 @@ describe('Animated tests', () => { describe('Animated Events', () => { it('should map events', () => { - var value = new Animated.Value(0); - var handler = Animated.event( + const value = new Animated.Value(0); + const handler = Animated.event( [null, {state: {foo: value}}], ); handler({bar: 'ignoreBar'}, {state: {baz: 'ignoreBaz', foo: 42}}); expect(value.__getValue()).toBe(42); }); it('should call listeners', () => { - var value = new Animated.Value(0); - var listener = jest.fn(); - var handler = Animated.event( + const value = new Animated.Value(0); + const listener = jest.fn(); + const handler = Animated.event( [{foo: value}], {listener}, ); @@ -548,14 +548,14 @@ describe('Animated tests', () => { expect(listener).toBeCalledWith({foo: 42}); }); it('should call forked event listeners', () => { - var value = new Animated.Value(0); - var listener = jest.fn(); - var handler = Animated.event( + const value = new Animated.Value(0); + const listener = jest.fn(); + const handler = Animated.event( [{foo: value}], {listener}, ); - var listener2 = jest.fn(); - var forkedHandler = Animated.forkEvent(handler, listener2); + const listener2 = jest.fn(); + const forkedHandler = Animated.forkEvent(handler, listener2); forkedHandler({foo: 42}); expect(value.__getValue()).toBe(42); expect(listener.mock.calls.length).toBe(1); @@ -567,9 +567,9 @@ describe('Animated tests', () => { describe('Animated Interactions', () => { /*eslint-disable no-shadow*/ - var Animated; + let Animated; /*eslint-enable*/ - var InteractionManager; + let InteractionManager; beforeEach(() => { jest.mock('InteractionManager'); @@ -584,8 +584,8 @@ describe('Animated tests', () => { it('registers an interaction by default', () => { InteractionManager.createInteractionHandle.mockReturnValue(777); - var value = new Animated.Value(0); - var callback = jest.fn(); + const value = new Animated.Value(0); + const callback = jest.fn(); Animated.timing(value, { toValue: 100, duration: 100, @@ -598,8 +598,8 @@ describe('Animated tests', () => { }); it('does not register an interaction when specified', () => { - var value = new Animated.Value(0); - var callback = jest.fn(); + const value = new Animated.Value(0); + const callback = jest.fn(); Animated.timing(value, { toValue: 100, duration: 100, @@ -615,8 +615,8 @@ describe('Animated tests', () => { describe('Animated Tracking', () => { it('should track values', () => { - var value1 = new Animated.Value(0); - var value2 = new Animated.Value(0); + const value1 = new Animated.Value(0); + const value2 = new Animated.Value(0); Animated.timing(value2, { toValue: value1, duration: 0, @@ -628,8 +628,8 @@ describe('Animated tests', () => { }); it('should track interpolated values', () => { - var value1 = new Animated.Value(0); - var value2 = new Animated.Value(0); + const value1 = new Animated.Value(0); + const value2 = new Animated.Value(0); Animated.timing(value2, { toValue: value1.interpolate({ inputRange: [0, 2], @@ -642,8 +642,8 @@ describe('Animated tests', () => { }); it('should stop tracking when animated', () => { - var value1 = new Animated.Value(0); - var value2 = new Animated.Value(0); + const value1 = new Animated.Value(0); + const value2 = new Animated.Value(0); Animated.timing(value2, { toValue: value1, duration: 0, @@ -661,11 +661,11 @@ describe('Animated tests', () => { describe('Animated Vectors', () => { it('should animate vectors', () => { - var vec = new Animated.ValueXY(); + const vec = new Animated.ValueXY(); - var callback = jest.fn(); + const callback = jest.fn(); - var node = new Animated.__PropsOnlyForTests({ + const node = new Animated.__PropsOnlyForTests({ style: { opacity: vec.x.interpolate({ inputRange: [0, 42], @@ -711,8 +711,8 @@ describe('Animated tests', () => { }); it('should track vectors', () => { - var value1 = new Animated.ValueXY(); - var value2 = new Animated.ValueXY(); + const value1 = new Animated.ValueXY(); + const value2 = new Animated.ValueXY(); Animated.timing(value2, { toValue: value1, duration: 0, @@ -727,8 +727,8 @@ describe('Animated tests', () => { }); it('should track with springs', () => { - var value1 = new Animated.ValueXY(); - var value2 = new Animated.ValueXY(); + const value1 = new Animated.ValueXY(); + const value2 = new Animated.ValueXY(); Animated.spring(value2, { toValue: value1, tension: 3000, // faster spring for faster test @@ -747,9 +747,9 @@ describe('Animated tests', () => { describe('Animated Listeners', () => { it('should get updates', () => { - var value1 = new Animated.Value(0); - var listener = jest.fn(); - var id = value1.addListener(listener); + const value1 = new Animated.Value(0); + const listener = jest.fn(); + const id = value1.addListener(listener); value1.setValue(42); expect(listener.mock.calls.length).toBe(1); expect(listener).toBeCalledWith({value: 42}); @@ -765,8 +765,8 @@ describe('Animated tests', () => { }); it('should removeAll', () => { - var value1 = new Animated.Value(0); - var listener = jest.fn(); + const value1 = new Animated.Value(0); + const listener = jest.fn(); [1,2,3,4].forEach(() => value1.addListener(listener)); value1.setValue(42); expect(listener.mock.calls.length).toBe(4); diff --git a/Libraries/Animated/src/__tests__/Easing-test.js b/Libraries/Animated/src/__tests__/Easing-test.js index 14f18aacd628e0..ae6cd336868292 100644 --- a/Libraries/Animated/src/__tests__/Easing-test.js +++ b/Libraries/Animated/src/__tests__/Easing-test.js @@ -8,10 +8,10 @@ */ 'use strict'; -var Easing = require('Easing'); +const Easing = require('Easing'); describe('Easing', () => { it('should work with linear', () => { - var easing = Easing.linear; + const easing = Easing.linear; expect(easing(0)).toBe(0); expect(easing(0.5)).toBe(0.5); @@ -20,7 +20,7 @@ describe('Easing', () => { }); it('should work with ease in linear', () => { - var easing = Easing.in(Easing.linear); + const easing = Easing.in(Easing.linear); expect(easing(0)).toBe(0); expect(easing(0.5)).toBe(0.5); expect(easing(0.8)).toBe(0.8); @@ -28,7 +28,7 @@ describe('Easing', () => { }); it('should work with easy out linear', () => { - var easing = Easing.out(Easing.linear); + const easing = Easing.out(Easing.linear); expect(easing(0)).toBe(0); expect(easing(0.5)).toBe(0.5); expect(easing(0.6)).toBe(0.6); @@ -39,8 +39,8 @@ describe('Easing', () => { function easeInQuad(t) { return t * t; } - var easing = Easing.in(Easing.quad); - for (var t = -0.5; t < 1.5; t += 0.1) { + const easing = Easing.in(Easing.quad); + for (let t = -0.5; t < 1.5; t += 0.1) { expect(easing(t)).toBe(easeInQuad(t)); } }); @@ -49,8 +49,8 @@ describe('Easing', () => { function easeOutQuad(t) { return -t * (t - 2); } - var easing = Easing.out(Easing.quad); - for (var t = 0; t <= 1; t += 0.1) { + const easing = Easing.out(Easing.quad); + for (let t = 0; t <= 1; t += 0.1) { expect(easing(1)).toBe(easeOutQuad(1)); } }); @@ -63,31 +63,31 @@ describe('Easing', () => { } return -((t - 1) * (t - 3) - 1) / 2; } - var easing = Easing.inOut(Easing.quad); - for (var t = -0.5; t < 1.5; t += 0.1) { + const easing = Easing.inOut(Easing.quad); + for (let t = -0.5; t < 1.5; t += 0.1) { expect(easing(t)).toBeCloseTo(easeInOutQuad(t), 4); } }); it('should satisfy boundary conditions with elastic', () => { - for (var b = 0; b < 4; b += 0.3) { - var easing = Easing.elastic(b); + for (let b = 0; b < 4; b += 0.3) { + const easing = Easing.elastic(b); expect(easing(0)).toBe(0); expect(easing(1)).toBe(1); } }); function sampleEasingFunction(easing) { - var DURATION = 300; - var tickCount = Math.round(DURATION * 60 / 1000); - var samples = []; - for (var i = 0; i <= tickCount; i++) { + const DURATION = 300; + const tickCount = Math.round(DURATION * 60 / 1000); + const samples = []; + for (let i = 0; i <= tickCount; i++) { samples.push(easing(i / tickCount)); } return samples; } - var Samples = { + const Samples = { in_quad: [0,0.0030864197530864196,0.012345679012345678,0.027777777777777776,0.04938271604938271,0.0771604938271605,0.1111111111111111,0.15123456790123457,0.19753086419753085,0.25,0.308641975308642,0.37345679012345684,0.4444444444444444,0.5216049382716049,0.6049382716049383,0.6944444444444445,0.7901234567901234,0.8919753086419753,1], out_quad: [0,0.10802469135802469,0.20987654320987653,0.3055555555555555,0.3950617283950617,0.47839506172839513,0.5555555555555556,0.6265432098765432,0.691358024691358,0.75,0.8024691358024691,0.8487654320987654,0.888888888888889,0.9228395061728394,0.9506172839506174,0.9722222222222221,0.9876543209876543,0.9969135802469136,1], inOut_quad: [0,0.006172839506172839,0.024691358024691357,0.05555555555555555,0.09876543209876543,0.154320987654321,0.2222222222222222,0.30246913580246915,0.3950617283950617,0.5,0.6049382716049383,0.697530864197531,0.7777777777777777,0.845679012345679,0.9012345679012346,0.9444444444444444,0.9753086419753086,0.9938271604938271,1], @@ -109,13 +109,13 @@ describe('Easing', () => { Object.keys(Samples).forEach(function(type) { it('should ease ' + type, function() { - var [modeName, easingName, isFunction] = type.split('_'); - var easing = Easing[easingName]; + const [modeName, easingName, isFunction] = type.split('_'); + let easing = Easing[easingName]; if (isFunction !== undefined) { easing = easing(); } - var computed = sampleEasingFunction(Easing[modeName](easing)); - var samples = Samples[type]; + const computed = sampleEasingFunction(Easing[modeName](easing)); + const samples = Samples[type]; computed.forEach((value, key) => { expect(value).toBeCloseTo(samples[key], 2); diff --git a/Libraries/Animated/src/__tests__/Interpolation-test.js b/Libraries/Animated/src/__tests__/Interpolation-test.js index 27f4438ab1568d..c2b832bcf5cf7b 100644 --- a/Libraries/Animated/src/__tests__/Interpolation-test.js +++ b/Libraries/Animated/src/__tests__/Interpolation-test.js @@ -8,12 +8,12 @@ */ 'use strict'; -var AnimatedInterpolation = require('../nodes/AnimatedInterpolation'); -var Easing = require('Easing'); +const AnimatedInterpolation = require('../nodes/AnimatedInterpolation'); +const Easing = require('Easing'); describe('Interpolation', () => { it('should work with defaults', () => { - var interpolation = AnimatedInterpolation.__createInterpolation({ + const interpolation = AnimatedInterpolation.__createInterpolation({ inputRange: [0, 1], outputRange: [0, 1], }); @@ -25,7 +25,7 @@ describe('Interpolation', () => { }); it('should work with output range', () => { - var interpolation = AnimatedInterpolation.__createInterpolation({ + const interpolation = AnimatedInterpolation.__createInterpolation({ inputRange: [0, 1], outputRange: [100, 200], }); @@ -37,7 +37,7 @@ describe('Interpolation', () => { }); it('should work with input range', () => { - var interpolation = AnimatedInterpolation.__createInterpolation({ + const interpolation = AnimatedInterpolation.__createInterpolation({ inputRange: [100, 200], outputRange: [0, 1], }); @@ -65,7 +65,7 @@ describe('Interpolation', () => { }); it('should work with empty input range', () => { - var interpolation = AnimatedInterpolation.__createInterpolation({ + const interpolation = AnimatedInterpolation.__createInterpolation({ inputRange: [0, 10, 10], outputRange: [1, 2, 3], extrapolate: 'extend', @@ -79,7 +79,7 @@ describe('Interpolation', () => { }); it('should work with empty output range', () => { - var interpolation = AnimatedInterpolation.__createInterpolation({ + const interpolation = AnimatedInterpolation.__createInterpolation({ inputRange: [1, 2, 3], outputRange: [0, 10, 10], extrapolate: 'extend', @@ -94,7 +94,7 @@ describe('Interpolation', () => { }); it('should work with easing', () => { - var interpolation = AnimatedInterpolation.__createInterpolation({ + const interpolation = AnimatedInterpolation.__createInterpolation({ inputRange: [0, 1], outputRange: [0, 1], easing: Easing.quad, @@ -107,7 +107,7 @@ describe('Interpolation', () => { }); it('should work with extrapolate', () => { - var interpolation = AnimatedInterpolation.__createInterpolation({ + let interpolation = AnimatedInterpolation.__createInterpolation({ inputRange: [0, 1], outputRange: [0, 1], extrapolate: 'extend', @@ -139,7 +139,7 @@ describe('Interpolation', () => { }); it('should work with keyframes with extrapolate', () => { - var interpolation = AnimatedInterpolation.__createInterpolation({ + const interpolation = AnimatedInterpolation.__createInterpolation({ inputRange: [0, 10, 100, 1000], outputRange: [0, 5, 50, 500], extrapolate: true, @@ -157,7 +157,7 @@ describe('Interpolation', () => { }); it('should work with keyframes without extrapolate', () => { - var interpolation = AnimatedInterpolation.__createInterpolation({ + const interpolation = AnimatedInterpolation.__createInterpolation({ inputRange: [0, 1, 2], outputRange: [0.2, 1, 0.2], extrapolate: 'clamp', @@ -183,7 +183,7 @@ describe('Interpolation', () => { }); it('should work with negative infinite', () => { - var interpolation = AnimatedInterpolation.__createInterpolation({ + const interpolation = AnimatedInterpolation.__createInterpolation({ inputRange: [-Infinity, 0], outputRange: [-Infinity, 0], easing: Easing.quad, @@ -199,7 +199,7 @@ describe('Interpolation', () => { }); it('should work with positive infinite', () => { - var interpolation = AnimatedInterpolation.__createInterpolation({ + const interpolation = AnimatedInterpolation.__createInterpolation({ inputRange: [5, Infinity], outputRange: [5, Infinity], easing: Easing.quad, @@ -217,7 +217,7 @@ describe('Interpolation', () => { }); it('should work with output ranges as string', () => { - var interpolation = AnimatedInterpolation.__createInterpolation({ + const interpolation = AnimatedInterpolation.__createInterpolation({ inputRange: [0, 1], outputRange: ['rgba(0, 100, 200, 0)', 'rgba(50, 150, 250, 0.4)'], }); @@ -228,7 +228,7 @@ describe('Interpolation', () => { }); it('should work with output ranges as short hex string', () => { - var interpolation = AnimatedInterpolation.__createInterpolation({ + const interpolation = AnimatedInterpolation.__createInterpolation({ inputRange: [0, 1], outputRange: ['#024', '#9BF'], }); @@ -239,7 +239,7 @@ describe('Interpolation', () => { }); it('should work with output ranges as long hex string', () => { - var interpolation = AnimatedInterpolation.__createInterpolation({ + const interpolation = AnimatedInterpolation.__createInterpolation({ inputRange: [0, 1], outputRange: ['#FF9500', '#87FC70'], }); @@ -250,7 +250,7 @@ describe('Interpolation', () => { }); it('should work with output ranges with mixed hex and rgba strings', () => { - var interpolation = AnimatedInterpolation.__createInterpolation({ + const interpolation = AnimatedInterpolation.__createInterpolation({ inputRange: [0, 1], outputRange: ['rgba(100, 120, 140, .4)', '#87FC70'], }); @@ -261,7 +261,7 @@ describe('Interpolation', () => { }); it('should work with negative and decimal values in string ranges', () => { - var interpolation = AnimatedInterpolation.__createInterpolation({ + const interpolation = AnimatedInterpolation.__createInterpolation({ inputRange: [0, 1], outputRange: ['-100.5deg', '100deg'], }); @@ -272,7 +272,7 @@ describe('Interpolation', () => { }); it('should crash when chaining an interpolation that returns a string', () => { - var interpolation = AnimatedInterpolation.__createInterpolation({ + const interpolation = AnimatedInterpolation.__createInterpolation({ inputRange: [0, 1], outputRange: [0, 1], }); @@ -282,7 +282,7 @@ describe('Interpolation', () => { }); it('should support a mix of color patterns', () => { - var interpolation = AnimatedInterpolation.__createInterpolation({ + const interpolation = AnimatedInterpolation.__createInterpolation({ inputRange: [0, 1, 2], outputRange: ['rgba(0, 100, 200, 0)', 'rgb(50, 150, 250)', 'red'], }); @@ -303,7 +303,7 @@ describe('Interpolation', () => { }); it('should round the alpha channel of a color to the nearest thousandth', () => { - var interpolation = AnimatedInterpolation.__createInterpolation({ + const interpolation = AnimatedInterpolation.__createInterpolation({ inputRange: [0, 1], outputRange: ['rgba(0, 0, 0, 0)', 'rgba(0, 0, 0, 1)'], }); diff --git a/Libraries/Animated/src/__tests__/bezier-test.js b/Libraries/Animated/src/__tests__/bezier-test.js index 3f1070a48fd71e..16b7acc0f1930a 100644 --- a/Libraries/Animated/src/__tests__/bezier-test.js +++ b/Libraries/Animated/src/__tests__/bezier-test.js @@ -10,9 +10,9 @@ 'use strict'; -var bezier = require('bezier'); +const bezier = require('bezier'); -var identity = function(x) { +const identity = function(x) { return x; }; @@ -30,15 +30,15 @@ function allEquals(be1, be2, samples, assertion) { if (!assertion) { assertion = assertClose; } - for (var i = 0; i <= samples; ++i) { - var x = i / samples; + for (let i = 0; i <= samples; ++i) { + const x = i / samples; assertion(be1(x), be2(x)); } } function repeat(n) { return function(f) { - for (var i = 0; i < n; ++i) { + for (let i = 0; i < n; ++i) { f(i); } }; @@ -74,11 +74,8 @@ describe('bezier', function() { describe('common properties', function() { it('should be the right value at extremes', function() { repeat(10)(function() { - var a = Math.random(), - b = 2 * Math.random() - 0.5, - c = Math.random(), - d = 2 * Math.random() - 0.5; - var easing = bezier(a, b, c, d); + const a = Math.random(), b = 2 * Math.random() - 0.5, c = Math.random(), d = 2 * Math.random() - 0.5; + const easing = bezier(a, b, c, d); expect(easing(0)).toBe(0); expect(easing(1)).toBe(1); }); @@ -86,13 +83,10 @@ describe('bezier', function() { it('should approach the projected value of its x=y projected curve', function() { repeat(10)(function() { - var a = Math.random(), - b = Math.random(), - c = Math.random(), - d = Math.random(); - var easing = bezier(a, b, c, d); - var projected = bezier(b, a, d, c); - var composed = function(x) { + const a = Math.random(), b = Math.random(), c = Math.random(), d = Math.random(); + const easing = bezier(a, b, c, d); + const projected = bezier(b, a, d, c); + const composed = function(x) { return projected(easing(x)); }; allEquals(identity, composed, 100, makeAssertCloseWithPrecision(2)); @@ -102,10 +96,7 @@ describe('bezier', function() { describe('two same instances', function() { it('should be strictly equals', function() { repeat(10)(function() { - var a = Math.random(), - b = 2 * Math.random() - 0.5, - c = Math.random(), - d = 2 * Math.random() - 0.5; + const a = Math.random(), b = 2 * Math.random() - 0.5, c = Math.random(), d = 2 * Math.random() - 0.5; allEquals(bezier(a, b, c, d), bezier(a, b, c, d), 100, 0); }); }); @@ -113,22 +104,16 @@ describe('bezier', function() { describe('symetric curves', function() { it('should have a central value y~=0.5 at x=0.5', function() { repeat(10)(function() { - var a = Math.random(), - b = 2 * Math.random() - 0.5, - c = 1 - a, - d = 1 - b; - var easing = bezier(a, b, c, d); + const a = Math.random(), b = 2 * Math.random() - 0.5, c = 1 - a, d = 1 - b; + const easing = bezier(a, b, c, d); assertClose(easing(0.5), 0.5, 2); }); }); it('should be symmetrical', function() { repeat(10)(function() { - var a = Math.random(), - b = 2 * Math.random() - 0.5, - c = 1 - a, - d = 1 - b; - var easing = bezier(a, b, c, d); - var sym = function(x) { + const a = Math.random(), b = 2 * Math.random() - 0.5, c = 1 - a, d = 1 - b; + const easing = bezier(a, b, c, d); + const sym = function(x) { return 1 - easing(1 - x); }; allEquals(easing, sym, 100, makeAssertCloseWithPrecision(2)); diff --git a/Libraries/Animated/src/bezier.js b/Libraries/Animated/src/bezier.js index 9aa777a124931a..f38ecef8c451ed 100644 --- a/Libraries/Animated/src/bezier.js +++ b/Libraries/Animated/src/bezier.js @@ -8,15 +8,15 @@ 'use strict'; // These values are established by empiricism with tests (tradeoff: performance VS precision) - var NEWTON_ITERATIONS = 4; - var NEWTON_MIN_SLOPE = 0.001; - var SUBDIVISION_PRECISION = 0.0000001; - var SUBDIVISION_MAX_ITERATIONS = 10; + const NEWTON_ITERATIONS = 4; + const NEWTON_MIN_SLOPE = 0.001; + const SUBDIVISION_PRECISION = 0.0000001; + const SUBDIVISION_MAX_ITERATIONS = 10; - var kSplineTableSize = 11; - var kSampleStepSize = 1.0 / (kSplineTableSize - 1.0); + const kSplineTableSize = 11; + const kSampleStepSize = 1.0 / (kSplineTableSize - 1.0); - var float32ArraySupported = typeof Float32Array === 'function'; + const float32ArraySupported = typeof Float32Array === 'function'; function A (aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; } function B (aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; } @@ -29,7 +29,7 @@ function getSlope (aT, aA1, aA2) { return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1); } function binarySubdivide (aX, aA, aB, mX1, mX2) { - var currentX, currentT, i = 0; + let currentX, currentT, i = 0; do { currentT = aA + (aB - aA) / 2.0; currentX = calcBezier(currentT, mX1, mX2) - aX; @@ -43,12 +43,12 @@ } function newtonRaphsonIterate (aX, aGuessT, mX1, mX2) { - for (var i = 0; i < NEWTON_ITERATIONS; ++i) { - var currentSlope = getSlope(aGuessT, mX1, mX2); + for (let i = 0; i < NEWTON_ITERATIONS; ++i) { + const currentSlope = getSlope(aGuessT, mX1, mX2); if (currentSlope === 0.0) { return aGuessT; } - var currentX = calcBezier(aGuessT, mX1, mX2) - aX; + const currentX = calcBezier(aGuessT, mX1, mX2) - aX; aGuessT -= currentX / currentSlope; } return aGuessT; @@ -60,17 +60,17 @@ } // Precompute samples table - var sampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : new Array(kSplineTableSize); + const sampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : new Array(kSplineTableSize); if (mX1 !== mY1 || mX2 !== mY2) { - for (var i = 0; i < kSplineTableSize; ++i) { + for (let i = 0; i < kSplineTableSize; ++i) { sampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2); } } function getTForX (aX) { - var intervalStart = 0.0; - var currentSample = 1; - var lastSample = kSplineTableSize - 1; + let intervalStart = 0.0; + let currentSample = 1; + const lastSample = kSplineTableSize - 1; for (; currentSample !== lastSample && sampleValues[currentSample] <= aX; ++currentSample) { intervalStart += kSampleStepSize; @@ -78,10 +78,10 @@ --currentSample; // Interpolate to provide an initial guess for t - var dist = (aX - sampleValues[currentSample]) / (sampleValues[currentSample + 1] - sampleValues[currentSample]); - var guessForT = intervalStart + dist * kSampleStepSize; + const dist = (aX - sampleValues[currentSample]) / (sampleValues[currentSample + 1] - sampleValues[currentSample]); + const guessForT = intervalStart + dist * kSampleStepSize; - var initialSlope = getSlope(guessForT, mX1, mX2); + const initialSlope = getSlope(guessForT, mX1, mX2); if (initialSlope >= NEWTON_MIN_SLOPE) { return newtonRaphsonIterate(aX, guessForT, mX1, mX2); } else if (initialSlope === 0.0) { diff --git a/Libraries/BatchedBridge/__mocks__/MessageQueueTestConfig.js b/Libraries/BatchedBridge/__mocks__/MessageQueueTestConfig.js index 40ad81f5f5cb5f..2fa722fb39e89a 100644 --- a/Libraries/BatchedBridge/__mocks__/MessageQueueTestConfig.js +++ b/Libraries/BatchedBridge/__mocks__/MessageQueueTestConfig.js @@ -7,12 +7,12 @@ * These don't actually exist anywhere in the code. */ 'use strict'; -var remoteModulesConfig = [ +const remoteModulesConfig = [ ['RemoteModule1',null,['remoteMethod','promiseMethod'],[]], ['RemoteModule2',null,['remoteMethod','promiseMethod'],[]], ]; -var MessageQueueTestConfig = { +const MessageQueueTestConfig = { remoteModuleConfig: remoteModulesConfig, }; diff --git a/Libraries/BatchedBridge/__mocks__/MessageQueueTestModule.js b/Libraries/BatchedBridge/__mocks__/MessageQueueTestModule.js index 8c4f7d3c03063f..7d4f5f1a565a7d 100644 --- a/Libraries/BatchedBridge/__mocks__/MessageQueueTestModule.js +++ b/Libraries/BatchedBridge/__mocks__/MessageQueueTestModule.js @@ -12,7 +12,7 @@ * correctly dispatches to commonJS modules. The `testHook` is overriden by test * cases. */ -var MessageQueueTestModule = { +const MessageQueueTestModule = { testHook1: function() { }, testHook2: function() { diff --git a/Libraries/Blob/__tests__/Blob-test.js b/Libraries/Blob/__tests__/Blob-test.js index 8d37915720c9b3..47bf5fee7c1361 100644 --- a/Libraries/Blob/__tests__/Blob-test.js +++ b/Libraries/Blob/__tests__/Blob-test.js @@ -13,7 +13,7 @@ jest.setMock('NativeModules', { BlobModule: require('../__mocks__/BlobModule'), }); -var Blob = require('Blob'); +const Blob = require('Blob'); describe('Blob', function() { it('should create empty blob', () => { diff --git a/Libraries/Blob/__tests__/BlobManager-test.js b/Libraries/Blob/__tests__/BlobManager-test.js index 2ed118b446be1c..c141d42f16334c 100644 --- a/Libraries/Blob/__tests__/BlobManager-test.js +++ b/Libraries/Blob/__tests__/BlobManager-test.js @@ -13,8 +13,8 @@ jest.setMock('NativeModules', { BlobModule: require('../__mocks__/BlobModule'), }); -var Blob = require('Blob'); -var BlobManager = require('BlobManager'); +const Blob = require('Blob'); +const BlobManager = require('BlobManager'); describe('BlobManager', function() { it('should create blob from parts', () => { diff --git a/Libraries/Blob/__tests__/FileReader-test.js b/Libraries/Blob/__tests__/FileReader-test.js index a278a4918a9d10..b2237550bf7184 100644 --- a/Libraries/Blob/__tests__/FileReader-test.js +++ b/Libraries/Blob/__tests__/FileReader-test.js @@ -14,8 +14,8 @@ jest.unmock('event-target-shim').setMock('NativeModules', { FileReaderModule: require('../__mocks__/FileReaderModule'), }); -var Blob = require('Blob'); -var FileReader = require('FileReader'); +const Blob = require('Blob'); +const FileReader = require('FileReader'); describe('FileReader', function() { it('should read blob as text', async () => { diff --git a/Libraries/BugReporting/getReactData.js b/Libraries/BugReporting/getReactData.js index 3f7a1a903d6675..f995e8f41967c4 100644 --- a/Libraries/BugReporting/getReactData.js +++ b/Libraries/BugReporting/getReactData.js @@ -15,16 +15,16 @@ * https://github.com/facebook/react-devtools/blob/master/backend/getData.js */ function getData(element: Object): Object { - var children = null; - var props = null; - var state = null; - var context = null; - var updater = null; - var name = null; - var type = null; - var text = null; - var publicInstance = null; - var nodeType = 'Native'; + let children = null; + let props = null; + let state = null; + let context = null; + let updater = null; + let name = null; + let type = null; + let text = null; + let publicInstance = null; + let nodeType = 'Native'; // If the parent is a native node without rendered children, but with // multiple string children, then the `element` that gets passed in here is // a plain value -- a string or number. @@ -80,7 +80,7 @@ function getData(element: Object): Object { } if (element._instance) { - var inst = element._instance; + const inst = element._instance; updater = { setState: inst.setState && inst.setState.bind(inst), forceUpdate: inst.forceUpdate && inst.forceUpdate.bind(inst), @@ -113,7 +113,7 @@ function getData(element: Object): Object { } function setInProps(internalInst, path: Array, value: any) { - var element = internalInst._currentElement; + const element = internalInst._currentElement; internalInst._currentElement = { ...element, props: copyWithSet(element.props, path, value), @@ -132,16 +132,16 @@ function setInContext(inst, path: Array, value: any) { } function setIn(obj: Object, path: Array, value: any) { - var last = path.pop(); - var parent = path.reduce((obj_, attr) => obj_ ? obj_[attr] : null, obj); + const last = path.pop(); + const parent = path.reduce((obj_, attr) => obj_ ? obj_[attr] : null, obj); if (parent) { parent[last] = value; } } function childrenList(children) { - var res = []; - for (var name in children) { + const res = []; + for (const name in children) { res.push(children[name]); } return res; @@ -151,8 +151,8 @@ function copyWithSetImpl(obj, path, idx, value) { if (idx >= path.length) { return value; } - var key = path[idx]; - var updated = Array.isArray(obj) ? obj.slice() : {...obj}; + const key = path[idx]; + const updated = Array.isArray(obj) ? obj.slice() : {...obj}; // $FlowFixMe number or string is fine here updated[key] = copyWithSetImpl(obj[key], path, idx + 1, value); return updated; diff --git a/Libraries/CameraRoll/ImagePickerIOS.js b/Libraries/CameraRoll/ImagePickerIOS.js index fe50825da14222..b653c11090e2de 100644 --- a/Libraries/CameraRoll/ImagePickerIOS.js +++ b/Libraries/CameraRoll/ImagePickerIOS.js @@ -8,9 +8,9 @@ */ 'use strict'; -var RCTImagePicker = require('NativeModules').ImagePickerIOS; +const RCTImagePicker = require('NativeModules').ImagePickerIOS; -var ImagePickerIOS = { +const ImagePickerIOS = { canRecordVideos: function(callback: Function) { return RCTImagePicker.canRecordVideos(callback); }, diff --git a/Libraries/Color/normalizeColor.js b/Libraries/Color/normalizeColor.js index de62e68dad0a06..59b3eb33ba5d0e 100755 --- a/Libraries/Color/normalizeColor.js +++ b/Libraries/Color/normalizeColor.js @@ -10,7 +10,7 @@ 'use strict'; function normalizeColor(color: string | number): ?number { - var match; + let match; if (typeof color === 'number') { if (color >>> 0 === color && color >= 0 && color <= 0xffffffff) { @@ -31,18 +31,18 @@ function normalizeColor(color: string | number): ?number { if ((match = matchers.rgb.exec(color))) { return ( (// b - parse255(match[1]) << 24 | // r + (parse255(match[1]) << 24 | // r parse255(match[2]) << 16 | // g - parse255(match[3]) << 8 | 0x000000ff) // a + parse255(match[3]) << 8 | 0x000000ff)) // a ) >>> 0; } if ((match = matchers.rgba.exec(color))) { return ( (// b - parse255(match[1]) << 24 | // r + (parse255(match[1]) << 24 | // r parse255(match[2]) << 16 | // g - parse255(match[3]) << 8 | parse1(match[4])) // a + parse255(match[3]) << 8 | parse1(match[4]))) // a ) >>> 0; } @@ -114,11 +114,11 @@ function hue2rgb(p: number, q: number, t: number): number { } function hslToRgb(h: number, s: number, l: number): number { - var q = l < 0.5 ? l * (1 + s) : l + s - l * s; - var p = 2 * l - q; - var r = hue2rgb(p, q, h + 1 / 3); - var g = hue2rgb(p, q, h); - var b = hue2rgb(p, q, h - 1 / 3); + const q = l < 0.5 ? l * (1 + s) : l + s - l * s; + const p = 2 * l - q; + const r = hue2rgb(p, q, h + 1 / 3); + const g = hue2rgb(p, q, h); + const b = hue2rgb(p, q, h - 1 / 3); return ( Math.round(r * 255) << 24 | @@ -128,14 +128,14 @@ function hslToRgb(h: number, s: number, l: number): number { } // var INTEGER = '[-+]?\\d+'; -var NUMBER = '[-+]?\\d*\\.?\\d+'; -var PERCENTAGE = NUMBER + '%'; +const NUMBER = '[-+]?\\d*\\.?\\d+'; +const PERCENTAGE = NUMBER + '%'; function call(...args) { return '\\(\\s*(' + args.join(')\\s*,\\s*(') + ')\\s*\\)'; } -var matchers = { +const matchers = { rgb: new RegExp('rgb' + call(NUMBER, NUMBER, NUMBER)), rgba: new RegExp('rgba' + call(NUMBER, NUMBER, NUMBER, NUMBER)), hsl: new RegExp('hsl' + call(NUMBER, PERCENTAGE, PERCENTAGE)), @@ -147,7 +147,7 @@ var matchers = { }; function parse255(str: string): number { - var int = parseInt(str, 10); + const int = parseInt(str, 10); if (int < 0) { return 0; } @@ -158,12 +158,12 @@ function parse255(str: string): number { } function parse360(str: string): number { - var int = parseFloat(str); + const int = parseFloat(str); return (((int % 360) + 360) % 360) / 360; } function parse1(str: string): number { - var num = parseFloat(str); + const num = parseFloat(str); if (num < 0) { return 0; } @@ -175,7 +175,7 @@ function parse1(str: string): number { function parsePercentage(str: string): number { // parseFloat conveniently ignores the final % - var int = parseFloat(str); + const int = parseFloat(str); if (int < 0) { return 0; } @@ -185,7 +185,7 @@ function parsePercentage(str: string): number { return int / 100; } -var names = { +const names = { transparent: 0x00000000, // http://www.w3.org/TR/css3-color/#svg-color diff --git a/Libraries/Core/Devtools/__tests__/parseErrorStack-test.js b/Libraries/Core/Devtools/__tests__/parseErrorStack-test.js index beaa629d765d77..7726a6117b9b83 100644 --- a/Libraries/Core/Devtools/__tests__/parseErrorStack-test.js +++ b/Libraries/Core/Devtools/__tests__/parseErrorStack-test.js @@ -9,7 +9,7 @@ 'use strict'; -var parseErrorStack = require('parseErrorStack'); +const parseErrorStack = require('parseErrorStack'); function getFakeError() { return new Error('Happy Cat'); @@ -18,24 +18,24 @@ function getFakeError() { describe('parseErrorStack', function() { it('parses error stack', function() { - var stack = parseErrorStack(getFakeError()); + const stack = parseErrorStack(getFakeError()); expect(stack.length).toBeGreaterThan(0); - var firstFrame = stack[0]; + const firstFrame = stack[0]; expect(firstFrame.methodName).toEqual('getFakeError'); expect(firstFrame.file).toMatch(/parseErrorStack-test\.js$/); }); it('supports framesToPop', function() { function getWrappedError() { - var error = getFakeError(); + const error = getFakeError(); error.framesToPop = 1; return error; } // Make sure framesToPop == 1 causes it to ignore getFakeError // stack frame - var stack = parseErrorStack(getWrappedError()); + const stack = parseErrorStack(getWrappedError()); expect(stack[0].methodName).toEqual('getWrappedError'); }); diff --git a/Libraries/Core/__mocks__/ErrorUtils.js b/Libraries/Core/__mocks__/ErrorUtils.js index 2ab128040cffca..6b2282672de439 100644 --- a/Libraries/Core/__mocks__/ErrorUtils.js +++ b/Libraries/Core/__mocks__/ErrorUtils.js @@ -19,7 +19,7 @@ function reportError(error) { throw error; } -var ErrorUtils = { +const ErrorUtils = { apply: jest.fn(execute), applyWithGuard: jest.fn(execute), guard: jest.fn(callback => callback), diff --git a/Libraries/Experimental/IncrementalExample.js b/Libraries/Experimental/IncrementalExample.js index e46510b5e4e9d4..7f006d38b6a7b4 100644 --- a/Libraries/Experimental/IncrementalExample.js +++ b/Libraries/Experimental/IncrementalExample.js @@ -153,7 +153,7 @@ function burnCPU(milliseconds) { while (performanceNow() < (start + milliseconds)) {} } -var styles = StyleSheet.create({ +const styles = StyleSheet.create({ scrollView: { margin: 10, backgroundColor: 'white', diff --git a/Libraries/Geolocation/Geolocation.js b/Libraries/Geolocation/Geolocation.js index 29bb0aa13a9932..8bdc212636beff 100644 --- a/Libraries/Geolocation/Geolocation.js +++ b/Libraries/Geolocation/Geolocation.js @@ -23,8 +23,8 @@ const LocationEventEmitter = new NativeEventEmitter(RCTLocationObserver); const Platform = require('Platform'); const PermissionsAndroid = require('PermissionsAndroid'); -var subscriptions = []; -var updatesEnabled = false; +let subscriptions = []; +let updatesEnabled = false; type GeoConfiguration = { skipPermissionRequests: bool; @@ -44,7 +44,7 @@ type GeoOptions = { * * See https://facebook.github.io/react-native/docs/geolocation.html */ -var Geolocation = { +const Geolocation = { /* * Sets configuration options that will be used in all location requests. @@ -116,7 +116,7 @@ var Geolocation = { RCTLocationObserver.startObserving(options || {}); updatesEnabled = true; } - var watchID = subscriptions.length; + const watchID = subscriptions.length; subscriptions.push([ LocationEventEmitter.addListener( 'geolocationDidChange', @@ -131,7 +131,7 @@ var Geolocation = { }, clearWatch: function(watchID: number) { - var sub = subscriptions[watchID]; + const sub = subscriptions[watchID]; if (!sub) { // Silently exit when the watchID is invalid or already cleared // This is consistent with timers @@ -140,10 +140,10 @@ var Geolocation = { sub[0].remove(); // array element refinements not yet enabled in Flow - var sub1 = sub[1]; sub1 && sub1.remove(); + const sub1 = sub[1]; sub1 && sub1.remove(); subscriptions[watchID] = undefined; - var noWatchers = true; - for (var ii = 0; ii < subscriptions.length; ii++) { + let noWatchers = true; + for (let ii = 0; ii < subscriptions.length; ii++) { if (subscriptions[ii]) { noWatchers = false; // still valid subscriptions } @@ -157,13 +157,13 @@ var Geolocation = { if (updatesEnabled) { RCTLocationObserver.stopObserving(); updatesEnabled = false; - for (var ii = 0; ii < subscriptions.length; ii++) { - var sub = subscriptions[ii]; + for (let ii = 0; ii < subscriptions.length; ii++) { + const sub = subscriptions[ii]; if (sub) { warning(false, 'Called stopObserving with existing subscriptions.'); sub[0].remove(); // array element refinements not yet enabled in Flow - var sub1 = sub[1]; sub1 && sub1.remove(); + const sub1 = sub[1]; sub1 && sub1.remove(); } } subscriptions = []; diff --git a/Libraries/Image/AssetRegistry.js b/Libraries/Image/AssetRegistry.js index 5f5f0980f432be..ad1b495af42894 100644 --- a/Libraries/Image/AssetRegistry.js +++ b/Libraries/Image/AssetRegistry.js @@ -21,7 +21,7 @@ export type PackagerAsset = { +type: string, }; -var assets: Array = []; +const assets: Array = []; function registerAsset(asset: PackagerAsset): number { // `push` returns new array length, so the first asset will diff --git a/Libraries/Image/AssetSourceResolver.js b/Libraries/Image/AssetSourceResolver.js index d7b583ebcb8d63..6ae1a7801d09c5 100644 --- a/Libraries/Image/AssetSourceResolver.js +++ b/Libraries/Image/AssetSourceResolver.js @@ -29,9 +29,9 @@ const invariant = require('fbjs/lib/invariant'); * Returns a path like 'assets/AwesomeModule/icon@2x.png' */ function getScaledAssetPath(asset): string { - var scale = AssetSourceResolver.pickScale(asset.scales, PixelRatio.get()); - var scaleSuffix = scale === 1 ? '' : '@' + scale + 'x'; - var assetDir = assetPathUtils.getBasePath(asset); + const scale = AssetSourceResolver.pickScale(asset.scales, PixelRatio.get()); + const scaleSuffix = scale === 1 ? '' : '@' + scale + 'x'; + const assetDir = assetPathUtils.getBasePath(asset); return assetDir + '/' + asset.name + scaleSuffix + '.' + asset.type; } @@ -39,9 +39,9 @@ function getScaledAssetPath(asset): string { * Returns a path like 'drawable-mdpi/icon.png' */ function getAssetPathInDrawableFolder(asset): string { - var scale = AssetSourceResolver.pickScale(asset.scales, PixelRatio.get()); - var drawbleFolder = assetPathUtils.getAndroidResourceFolderName(asset, scale); - var fileName = assetPathUtils.getAndroidResourceIdentifier(asset); + const scale = AssetSourceResolver.pickScale(asset.scales, PixelRatio.get()); + const drawbleFolder = assetPathUtils.getAndroidResourceFolderName(asset, scale); + const fileName = assetPathUtils.getAndroidResourceIdentifier(asset); return drawbleFolder + '/' + fileName + '.' + asset.type; } @@ -151,7 +151,7 @@ class AssetSourceResolver { static pickScale(scales: Array, deviceScale: number): number { // Packager guarantees that `scales` array is sorted - for (var i = 0; i < scales.length; i++) { + for (let i = 0; i < scales.length; i++) { if (scales[i] >= deviceScale) { return scales[i]; } diff --git a/Libraries/Image/Image.android.js b/Libraries/Image/Image.android.js index d9702700be5930..b54d624118b173 100644 --- a/Libraries/Image/Image.android.js +++ b/Libraries/Image/Image.android.js @@ -10,25 +10,25 @@ 'use strict'; -var ImageResizeMode = require('ImageResizeMode'); -var ImageStylePropTypes = require('ImageStylePropTypes'); -var NativeMethodsMixin = require('NativeMethodsMixin'); -var NativeModules = require('NativeModules'); -var React = require('React'); -var PropTypes = require('prop-types'); -var ReactNativeViewAttributes = require('ReactNativeViewAttributes'); -var StyleSheet = require('StyleSheet'); -var StyleSheetPropType = require('StyleSheetPropType'); +const ImageResizeMode = require('ImageResizeMode'); +const ImageStylePropTypes = require('ImageStylePropTypes'); +const NativeMethodsMixin = require('NativeMethodsMixin'); +const NativeModules = require('NativeModules'); +const React = require('React'); +const PropTypes = require('prop-types'); +const ReactNativeViewAttributes = require('ReactNativeViewAttributes'); +const StyleSheet = require('StyleSheet'); +const StyleSheetPropType = require('StyleSheetPropType'); const TextAncestor = require('TextAncestor'); -var ViewPropTypes = require('ViewPropTypes'); +const ViewPropTypes = require('ViewPropTypes'); -var createReactClass = require('create-react-class'); -var flattenStyle = require('flattenStyle'); -var merge = require('merge'); -var requireNativeComponent = require('requireNativeComponent'); -var resolveAssetSource = require('resolveAssetSource'); +const createReactClass = require('create-react-class'); +const flattenStyle = require('flattenStyle'); +const merge = require('merge'); +const requireNativeComponent = require('requireNativeComponent'); +const resolveAssetSource = require('resolveAssetSource'); -var {ImageLoader} = NativeModules; +const {ImageLoader} = NativeModules; let _requestId = 1; function generateRequestId() { @@ -42,7 +42,7 @@ function generateRequestId() { * * See https://facebook.github.io/react-native/docs/image.html */ -var Image = createReactClass({ +const Image = createReactClass({ displayName: 'Image', propTypes: { ...ViewPropTypes, @@ -275,13 +275,13 @@ var Image = createReactClass({ }, }); -var styles = StyleSheet.create({ +const styles = StyleSheet.create({ base: { overflow: 'hidden', }, }); -var cfg = { +const cfg = { nativeOnly: { src: true, headers: true, @@ -290,8 +290,8 @@ var cfg = { shouldNotifyLoadEvents: true, }, }; -var RKImage = requireNativeComponent('RCTImageView', Image, cfg); -var RCTTextInlineImage = requireNativeComponent( +const RKImage = requireNativeComponent('RCTImageView', Image, cfg); +const RCTTextInlineImage = requireNativeComponent( 'RCTTextInlineImage', Image, cfg, diff --git a/Libraries/Image/ImageResizeMode.js b/Libraries/Image/ImageResizeMode.js index 89e74bcc502ee6..48779e383f3119 100644 --- a/Libraries/Image/ImageResizeMode.js +++ b/Libraries/Image/ImageResizeMode.js @@ -12,13 +12,13 @@ /* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error * found when Flow v0.54 was deployed. To see the error delete this comment and * run Flow. */ -var keyMirror = require('fbjs/lib/keyMirror'); +const keyMirror = require('fbjs/lib/keyMirror'); /** * ImageResizeMode - Enum for different image resizing modes, set via * `resizeMode` style property on `` components. */ -var ImageResizeMode = keyMirror({ +const ImageResizeMode = keyMirror({ /** * contain - The image will be resized such that it will be completely * visible, contained within the frame of the View. diff --git a/Libraries/Image/ImageStylePropTypes.js b/Libraries/Image/ImageStylePropTypes.js index c88c19ea3cec29..54e500994227db 100644 --- a/Libraries/Image/ImageStylePropTypes.js +++ b/Libraries/Image/ImageStylePropTypes.js @@ -9,14 +9,14 @@ */ 'use strict'; -var ColorPropType = require('ColorPropType'); -var ImageResizeMode = require('ImageResizeMode'); -var LayoutPropTypes = require('LayoutPropTypes'); -var ReactPropTypes = require('prop-types'); -var ShadowPropTypesIOS = require('ShadowPropTypesIOS'); -var TransformPropTypes = require('TransformPropTypes'); +const ColorPropType = require('ColorPropType'); +const ImageResizeMode = require('ImageResizeMode'); +const LayoutPropTypes = require('LayoutPropTypes'); +const ReactPropTypes = require('prop-types'); +const ShadowPropTypesIOS = require('ShadowPropTypesIOS'); +const TransformPropTypes = require('TransformPropTypes'); -var ImageStylePropTypes = { +const ImageStylePropTypes = { ...LayoutPropTypes, ...ShadowPropTypesIOS, ...TransformPropTypes, diff --git a/Libraries/Image/RelativeImageStub.js b/Libraries/Image/RelativeImageStub.js index 866488eecc83c3..1a74c36cb1bd98 100644 --- a/Libraries/Image/RelativeImageStub.js +++ b/Libraries/Image/RelativeImageStub.js @@ -11,7 +11,7 @@ // This is a stub for flow to make it understand require('./icon.png') // See metro/src/Bundler/index.js -var AssetRegistry = require('AssetRegistry'); +const AssetRegistry = require('AssetRegistry'); module.exports = AssetRegistry.registerAsset({ __packager_asset: true, diff --git a/Libraries/Image/__tests__/resolveAssetSource-test.js b/Libraries/Image/__tests__/resolveAssetSource-test.js index 50a666a5b54897..db1a0a853d9937 100644 --- a/Libraries/Image/__tests__/resolveAssetSource-test.js +++ b/Libraries/Image/__tests__/resolveAssetSource-test.js @@ -8,13 +8,13 @@ */ 'use strict'; -var AssetRegistry = require('AssetRegistry'); -var Platform = require('Platform'); -var NativeModules = require('NativeModules'); -var resolveAssetSource = require('../resolveAssetSource'); +const AssetRegistry = require('AssetRegistry'); +const Platform = require('Platform'); +const NativeModules = require('NativeModules'); +const resolveAssetSource = require('../resolveAssetSource'); function expectResolvesAsset(input, expectedSource) { - var assetId = AssetRegistry.registerAsset(input); + const assetId = AssetRegistry.registerAsset(input); expect(resolveAssetSource(assetId)).toEqual(expectedSource); } @@ -24,10 +24,10 @@ describe('resolveAssetSource', () => { }); it('returns same source for simple static and network images', () => { - var source1 = {uri: 'https://www.facebook.com/logo'}; + const source1 = {uri: 'https://www.facebook.com/logo'}; expect(resolveAssetSource(source1)).toBe(source1); - var source2 = {uri: 'logo'}; + const source2 = {uri: 'logo'}; expect(resolveAssetSource(source2)).toBe(source2); }); diff --git a/Libraries/Image/resolveAssetSource.js b/Libraries/Image/resolveAssetSource.js index fefb28ff5f7b32..fe483beff59427 100644 --- a/Libraries/Image/resolveAssetSource.js +++ b/Libraries/Image/resolveAssetSource.js @@ -85,7 +85,7 @@ function resolveAssetSource(source: any): ?ResolvedAssetSource { return source; } - var asset = AssetRegistry.getAssetByID(source); + const asset = AssetRegistry.getAssetByID(source); if (!asset) { return null; } diff --git a/Libraries/Inspector/BorderBox.js b/Libraries/Inspector/BorderBox.js index 7ed32e73ae49a0..21ace69d9c90fa 100644 --- a/Libraries/Inspector/BorderBox.js +++ b/Libraries/Inspector/BorderBox.js @@ -8,16 +8,16 @@ */ 'use strict'; -var React = require('React'); -var View = require('View'); +const React = require('React'); +const View = require('View'); class BorderBox extends React.Component<$FlowFixMeProps> { render() { - var box = this.props.box; + const box = this.props.box; if (!box) { return this.props.children; } - var style = { + const style = { borderTopWidth: box.top, borderBottomWidth: box.bottom, borderLeftWidth: box.left, diff --git a/Libraries/Inspector/BoxInspector.js b/Libraries/Inspector/BoxInspector.js index 6009e78ea44186..11fe9c8c980787 100644 --- a/Libraries/Inspector/BoxInspector.js +++ b/Libraries/Inspector/BoxInspector.js @@ -8,13 +8,13 @@ */ 'use strict'; -var React = require('React'); -var StyleSheet = require('StyleSheet'); -var Text = require('Text'); -var View = require('View'); -var resolveBoxStyle = require('resolveBoxStyle'); +const React = require('React'); +const StyleSheet = require('StyleSheet'); +const Text = require('Text'); +const View = require('View'); +const resolveBoxStyle = require('resolveBoxStyle'); -var blank = { +const blank = { top: 0, left: 0, right: 0, @@ -23,10 +23,10 @@ var blank = { class BoxInspector extends React.Component<$FlowFixMeProps> { render() { - var frame = this.props.frame; - var style = this.props.style; - var margin = style && resolveBoxStyle('margin', style) || blank; - var padding = style && resolveBoxStyle('padding', style) || blank; + const frame = this.props.frame; + const style = this.props.style; + const margin = style && resolveBoxStyle('margin', style) || blank; + const padding = style && resolveBoxStyle('padding', style) || blank; return ( @@ -46,7 +46,7 @@ class BoxInspector extends React.Component<$FlowFixMeProps> { class BoxContainer extends React.Component<$FlowFixMeProps> { render() { - var box = this.props.box; + const box = this.props.box; return ( @@ -66,7 +66,7 @@ class BoxContainer extends React.Component<$FlowFixMeProps> { } } -var styles = StyleSheet.create({ +const styles = StyleSheet.create({ row: { flexDirection: 'row', alignItems: 'center', diff --git a/Libraries/Inspector/ElementBox.js b/Libraries/Inspector/ElementBox.js index 7eebb22f337af6..17b2c8920e8e5f 100644 --- a/Libraries/Inspector/ElementBox.js +++ b/Libraries/Inspector/ElementBox.js @@ -8,20 +8,20 @@ */ 'use strict'; -var React = require('React'); -var View = require('View'); -var StyleSheet = require('StyleSheet'); -var BorderBox = require('BorderBox'); -var resolveBoxStyle = require('resolveBoxStyle'); +const React = require('React'); +const View = require('View'); +const StyleSheet = require('StyleSheet'); +const BorderBox = require('BorderBox'); +const resolveBoxStyle = require('resolveBoxStyle'); -var flattenStyle = require('flattenStyle'); +const flattenStyle = require('flattenStyle'); class ElementBox extends React.Component<$FlowFixMeProps> { render() { - var style = flattenStyle(this.props.style) || {}; - var margin = resolveBoxStyle('margin', style); - var padding = resolveBoxStyle('padding', style); - var frameStyle = this.props.frame; + const style = flattenStyle(this.props.style) || {}; + const margin = resolveBoxStyle('margin', style); + const padding = resolveBoxStyle('padding', style); + let frameStyle = this.props.frame; if (margin) { frameStyle = { top: frameStyle.top - margin.top, @@ -30,7 +30,7 @@ class ElementBox extends React.Component<$FlowFixMeProps> { width: frameStyle.width + margin.left + margin.right, }; } - var contentStyle = { + let contentStyle = { width: this.props.frame.width, height: this.props.frame.height, }; @@ -52,7 +52,7 @@ class ElementBox extends React.Component<$FlowFixMeProps> { } } -var styles = StyleSheet.create({ +const styles = StyleSheet.create({ frame: { position: 'absolute', }, diff --git a/Libraries/Inspector/InspectorOverlay.js b/Libraries/Inspector/InspectorOverlay.js index 3ef8ae60f3501b..a2dda0b316c251 100644 --- a/Libraries/Inspector/InspectorOverlay.js +++ b/Libraries/Inspector/InspectorOverlay.js @@ -8,13 +8,13 @@ */ 'use strict'; -var Dimensions = require('Dimensions'); -var ElementBox = require('ElementBox'); -var PropTypes = require('prop-types'); -var React = require('React'); -var StyleSheet = require('StyleSheet'); -var UIManager = require('UIManager'); -var View = require('View'); +const Dimensions = require('Dimensions'); +const ElementBox = require('ElementBox'); +const PropTypes = require('prop-types'); +const React = require('React'); +const StyleSheet = require('StyleSheet'); +const UIManager = require('UIManager'); +const View = require('View'); type EventLike = { nativeEvent: Object, @@ -38,7 +38,7 @@ class InspectorOverlay extends React.Component<{ }; findViewForTouchEvent = (e: EventLike) => { - var {locationX, locationY} = e.nativeEvent.touches[0]; + const {locationX, locationY} = e.nativeEvent.touches[0]; UIManager.findSubviewIn( this.props.inspectedViewTag, [locationX, locationY], @@ -54,7 +54,7 @@ class InspectorOverlay extends React.Component<{ }; render() { - var content = null; + let content = null; if (this.props.inspected) { content = ; } @@ -70,7 +70,7 @@ class InspectorOverlay extends React.Component<{ } } -var styles = StyleSheet.create({ +const styles = StyleSheet.create({ inspector: { backgroundColor: 'transparent', position: 'absolute', diff --git a/Libraries/Inspector/PerformanceOverlay.js b/Libraries/Inspector/PerformanceOverlay.js index d414ea2db298da..b75c8f1b38bc8b 100644 --- a/Libraries/Inspector/PerformanceOverlay.js +++ b/Libraries/Inspector/PerformanceOverlay.js @@ -8,20 +8,20 @@ */ 'use strict'; -var PerformanceLogger = require('PerformanceLogger'); -var React = require('React'); -var StyleSheet = require('StyleSheet'); -var Text = require('Text'); -var View = require('View'); +const PerformanceLogger = require('PerformanceLogger'); +const React = require('React'); +const StyleSheet = require('StyleSheet'); +const Text = require('Text'); +const View = require('View'); class PerformanceOverlay extends React.Component<{}> { render() { - var perfLogs = PerformanceLogger.getTimespans(); - var items = []; + const perfLogs = PerformanceLogger.getTimespans(); + const items = []; - for (var key in perfLogs) { + for (const key in perfLogs) { if (perfLogs[key].totalTime) { - var unit = (key === 'BundleSize') ? 'b' : 'ms'; + const unit = (key === 'BundleSize') ? 'b' : 'ms'; items.push( {key} @@ -41,7 +41,7 @@ class PerformanceOverlay extends React.Component<{}> { } } -var styles = StyleSheet.create({ +const styles = StyleSheet.create({ container: { height: 100, paddingTop: 10, diff --git a/Libraries/Inspector/StyleInspector.js b/Libraries/Inspector/StyleInspector.js index a65e027996521c..df32a6688de4d8 100644 --- a/Libraries/Inspector/StyleInspector.js +++ b/Libraries/Inspector/StyleInspector.js @@ -8,17 +8,17 @@ */ 'use strict'; -var React = require('React'); -var StyleSheet = require('StyleSheet'); -var Text = require('Text'); -var View = require('View'); +const React = require('React'); +const StyleSheet = require('StyleSheet'); +const Text = require('Text'); +const View = require('View'); class StyleInspector extends React.Component<$FlowFixMeProps> { render() { if (!this.props.style) { return No style; } - var names = Object.keys(this.props.style); + const names = Object.keys(this.props.style); return ( @@ -27,7 +27,7 @@ class StyleInspector extends React.Component<$FlowFixMeProps> { {names.map(name => { - var value = typeof this.props.style[name] === 'object' ? JSON.stringify(this.props.style[name]) : this.props.style[name]; + const value = typeof this.props.style[name] === 'object' ? JSON.stringify(this.props.style[name]) : this.props.style[name]; return {value}; } ) } @@ -36,7 +36,7 @@ class StyleInspector extends React.Component<$FlowFixMeProps> { } } -var styles = StyleSheet.create({ +const styles = StyleSheet.create({ container: { flexDirection: 'row', }, diff --git a/Libraries/Inspector/resolveBoxStyle.js b/Libraries/Inspector/resolveBoxStyle.js index 43026ada8f763e..27c89de9b6d8a9 100644 --- a/Libraries/Inspector/resolveBoxStyle.js +++ b/Libraries/Inspector/resolveBoxStyle.js @@ -18,9 +18,9 @@ * If none are set, returns false. */ function resolveBoxStyle(prefix: string, style: Object): ?Object { - var res = {}; - var subs = ['top', 'left', 'bottom', 'right']; - var set = false; + const res = {}; + const subs = ['top', 'left', 'bottom', 'right']; + let set = false; subs.forEach(sub => { res[sub] = style[prefix] || 0; }); @@ -36,7 +36,7 @@ function resolveBoxStyle(prefix: string, style: Object): ?Object { set = true; } subs.forEach(sub => { - var val = style[prefix + capFirst(sub)]; + const val = style[prefix + capFirst(sub)]; if (val) { res[sub] = val; set = true; diff --git a/Libraries/Interaction/InteractionManager.js b/Libraries/Interaction/InteractionManager.js index 7373575a0cae8d..3d2f2fa46e0b14 100644 --- a/Libraries/Interaction/InteractionManager.js +++ b/Libraries/Interaction/InteractionManager.js @@ -77,7 +77,7 @@ const DEBUG = false; * allowing events such as touches to start interactions and block queued tasks * from executing, making apps more responsive. */ -var InteractionManager = { +const InteractionManager = { Events: keyMirror({ interactionStart: true, interactionComplete: true, @@ -118,7 +118,7 @@ var InteractionManager = { createInteractionHandle(): Handle { DEBUG && infoLog('create interaction handle'); _scheduleUpdate(); - var handle = ++_inc; + const handle = ++_inc; _addInteractionSet.add(handle); return handle; }, @@ -181,14 +181,14 @@ function _scheduleUpdate() { function _processUpdate() { _nextUpdateHandle = 0; - var interactionCount = _interactionSet.size; + const interactionCount = _interactionSet.size; _addInteractionSet.forEach(handle => _interactionSet.add(handle) ); _deleteInteractionSet.forEach(handle => _interactionSet.delete(handle) ); - var nextInteractionCount = _interactionSet.size; + const nextInteractionCount = _interactionSet.size; if (interactionCount !== 0 && nextInteractionCount === 0) { // transition from 1+ --> 0 interactions diff --git a/Libraries/Interaction/InteractionMixin.js b/Libraries/Interaction/InteractionMixin.js index e4310ad91d86ec..018ca1bd16d6a1 100644 --- a/Libraries/Interaction/InteractionMixin.js +++ b/Libraries/Interaction/InteractionMixin.js @@ -8,14 +8,14 @@ */ 'use strict'; -var InteractionManager = require('InteractionManager'); +const InteractionManager = require('InteractionManager'); /** * This mixin provides safe versions of InteractionManager start/end methods * that ensures `clearInteractionHandle` is always called * once per start, even if the component is unmounted. */ -var InteractionMixin = { +const InteractionMixin = { componentWillUnmount: function() { while (this._interactionMixinHandles.length) { InteractionManager.clearInteractionHandle( @@ -27,7 +27,7 @@ var InteractionMixin = { _interactionMixinHandles: ([]: Array), createInteractionHandle: function() { - var handle = InteractionManager.createInteractionHandle(); + const handle = InteractionManager.createInteractionHandle(); this._interactionMixinHandles.push(handle); return handle; }, diff --git a/Libraries/Interaction/__tests__/InteractionMixin-test.js b/Libraries/Interaction/__tests__/InteractionMixin-test.js index 08f33d759f5016..7a3675b13f0b49 100644 --- a/Libraries/Interaction/__tests__/InteractionMixin-test.js +++ b/Libraries/Interaction/__tests__/InteractionMixin-test.js @@ -11,9 +11,9 @@ jest.enableAutomock().unmock('InteractionMixin'); describe('InteractionMixin', () => { - var InteractionManager; - var InteractionMixin; - var component; + let InteractionManager; + let InteractionMixin; + let component; beforeEach(() => { jest.resetModules(); @@ -29,19 +29,19 @@ describe('InteractionMixin', () => { }); it('should end interactions', () => { - var handle = {}; + const handle = {}; component.clearInteractionHandle(handle); expect(InteractionManager.clearInteractionHandle).toBeCalledWith(handle); }); it('should schedule tasks', () => { - var task = jest.fn(); + const task = jest.fn(); component.runAfterInteractions(task); expect(InteractionManager.runAfterInteractions).toBeCalledWith(task); }); it('should end unfinished interactions in componentWillUnmount', () => { - var handle = component.createInteractionHandle(); + const handle = component.createInteractionHandle(); component.componentWillUnmount(); expect(InteractionManager.clearInteractionHandle).toBeCalledWith(handle); }); diff --git a/Libraries/Lists/ListView/ListView.js b/Libraries/Lists/ListView/ListView.js index b36150510e2c62..cd168bc656cd0d 100644 --- a/Libraries/Lists/ListView/ListView.js +++ b/Libraries/Lists/ListView/ListView.js @@ -9,34 +9,34 @@ */ 'use strict'; -var ListViewDataSource = require('ListViewDataSource'); -var Platform = require('Platform'); -var React = require('React'); -var PropTypes = require('prop-types'); -var ReactNative = require('ReactNative'); -var RCTScrollViewManager = require('NativeModules').ScrollViewManager; -var ScrollView = require('ScrollView'); -var ScrollResponder = require('ScrollResponder'); -var StaticRenderer = require('StaticRenderer'); +const ListViewDataSource = require('ListViewDataSource'); +const Platform = require('Platform'); +const React = require('React'); +const PropTypes = require('prop-types'); +const ReactNative = require('ReactNative'); +const RCTScrollViewManager = require('NativeModules').ScrollViewManager; +const ScrollView = require('ScrollView'); +const ScrollResponder = require('ScrollResponder'); +const StaticRenderer = require('StaticRenderer'); /* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error * found when Flow v0.54 was deployed. To see the error delete this comment and * run Flow. */ -var TimerMixin = require('react-timer-mixin'); -var View = require('View'); +const TimerMixin = require('react-timer-mixin'); +const View = require('View'); /* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error * found when Flow v0.54 was deployed. To see the error delete this comment and * run Flow. */ -var cloneReferencedElement = require('react-clone-referenced-element'); -var createReactClass = require('create-react-class'); -var isEmpty = require('isEmpty'); -var merge = require('merge'); +const cloneReferencedElement = require('react-clone-referenced-element'); +const createReactClass = require('create-react-class'); +const isEmpty = require('isEmpty'); +const merge = require('merge'); -var DEFAULT_PAGE_SIZE = 1; -var DEFAULT_INITIAL_ROWS = 10; -var DEFAULT_SCROLL_RENDER_AHEAD = 1000; -var DEFAULT_END_REACHED_THRESHOLD = 1000; -var DEFAULT_SCROLL_CALLBACK_THROTTLE = 50; +const DEFAULT_PAGE_SIZE = 1; +const DEFAULT_INITIAL_ROWS = 10; +const DEFAULT_SCROLL_RENDER_AHEAD = 1000; +const DEFAULT_END_REACHED_THRESHOLD = 1000; +const DEFAULT_SCROLL_CALLBACK_THROTTLE = 50; /** * DEPRECATED - use one of the new list components, such as [`FlatList`](docs/flatlist.html) @@ -95,7 +95,7 @@ var DEFAULT_SCROLL_CALLBACK_THROTTLE = 50; * rendering rows. */ -var ListView = createReactClass({ +const ListView = createReactClass({ displayName: 'ListView', _childFrames: ([]: Array), _sentEndForContentLength: (null: ?number), @@ -405,28 +405,28 @@ var ListView = createReactClass({ }, render: function() { - var bodyComponents = []; + const bodyComponents = []; - var dataSource = this.props.dataSource; - var allRowIDs = dataSource.rowIdentities; - var rowCount = 0; - var stickySectionHeaderIndices = []; + const dataSource = this.props.dataSource; + const allRowIDs = dataSource.rowIdentities; + let rowCount = 0; + const stickySectionHeaderIndices = []; const {renderSectionHeader} = this.props; - var header = this.props.renderHeader && this.props.renderHeader(); - var footer = this.props.renderFooter && this.props.renderFooter(); - var totalIndex = header ? 1 : 0; + const header = this.props.renderHeader && this.props.renderHeader(); + const footer = this.props.renderFooter && this.props.renderFooter(); + let totalIndex = header ? 1 : 0; - for (var sectionIdx = 0; sectionIdx < allRowIDs.length; sectionIdx++) { - var sectionID = dataSource.sectionIdentities[sectionIdx]; - var rowIDs = allRowIDs[sectionIdx]; + for (let sectionIdx = 0; sectionIdx < allRowIDs.length; sectionIdx++) { + const sectionID = dataSource.sectionIdentities[sectionIdx]; + const rowIDs = allRowIDs[sectionIdx]; if (rowIDs.length === 0) { if (this.props.enableEmptySections === undefined) { /* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses * an error found when Flow v0.54 was deployed. To see the error * delete this comment and run Flow. */ - var warning = require('fbjs/lib/warning'); + const warning = require('fbjs/lib/warning'); warning( false, 'In next release empty section headers will be rendered.' + @@ -434,7 +434,7 @@ var ListView = createReactClass({ ); continue; } else { - var invariant = require('fbjs/lib/invariant'); + const invariant = require('fbjs/lib/invariant'); invariant( this.props.enableEmptySections, "In next release 'enableEmptySections' flag will be deprecated, empty section headers will always be rendered." + @@ -460,13 +460,13 @@ var ListView = createReactClass({ } } - for (var rowIdx = 0; rowIdx < rowIDs.length; rowIdx++) { - var rowID = rowIDs[rowIdx]; - var comboID = sectionID + '_' + rowID; - var shouldUpdateRow = + for (let rowIdx = 0; rowIdx < rowIDs.length; rowIdx++) { + const rowID = rowIDs[rowIdx]; + const comboID = sectionID + '_' + rowID; + const shouldUpdateRow = rowCount >= this._prevRenderedRowsCount && dataSource.rowShouldUpdate(sectionIdx, rowIdx); - var row = ( + const row = ( { - var rowsToRender = Math.min( + const rowsToRender = Math.min( state.curRenderedRowsCount + props.pageSize, props.enableEmptySections ? props.dataSource.getRowAndSectionCount() @@ -666,32 +666,32 @@ var ListView = createReactClass({ this._childFrames[newFrame.index] = merge(newFrame); }); } - var isVertical = !this.props.horizontal; - var dataSource = this.props.dataSource; - var visibleMin = this.scrollProperties.offset; - var visibleMax = visibleMin + this.scrollProperties.visibleLength; - var allRowIDs = dataSource.rowIdentities; - - var header = this.props.renderHeader && this.props.renderHeader(); - var totalIndex = header ? 1 : 0; - var visibilityChanged = false; - var changedRows = {}; - for (var sectionIdx = 0; sectionIdx < allRowIDs.length; sectionIdx++) { - var rowIDs = allRowIDs[sectionIdx]; + const isVertical = !this.props.horizontal; + const dataSource = this.props.dataSource; + const visibleMin = this.scrollProperties.offset; + const visibleMax = visibleMin + this.scrollProperties.visibleLength; + const allRowIDs = dataSource.rowIdentities; + + const header = this.props.renderHeader && this.props.renderHeader(); + let totalIndex = header ? 1 : 0; + let visibilityChanged = false; + const changedRows = {}; + for (let sectionIdx = 0; sectionIdx < allRowIDs.length; sectionIdx++) { + const rowIDs = allRowIDs[sectionIdx]; if (rowIDs.length === 0) { continue; } - var sectionID = dataSource.sectionIdentities[sectionIdx]; + const sectionID = dataSource.sectionIdentities[sectionIdx]; if (this.props.renderSectionHeader) { totalIndex++; } - var visibleSection = this._visibleRows[sectionID]; + let visibleSection = this._visibleRows[sectionID]; if (!visibleSection) { visibleSection = {}; } - for (var rowIdx = 0; rowIdx < rowIDs.length; rowIdx++) { - var rowID = rowIDs[rowIdx]; - var frame = this._childFrames[totalIndex]; + for (let rowIdx = 0; rowIdx < rowIDs.length; rowIdx++) { + const rowID = rowIDs[rowIdx]; + const frame = this._childFrames[totalIndex]; totalIndex++; if ( this.props.renderSeparator && @@ -702,9 +702,9 @@ var ListView = createReactClass({ if (!frame) { break; } - var rowVisible = visibleSection[rowID]; - var min = isVertical ? frame.y : frame.x; - var max = min + (isVertical ? frame.height : frame.width); + const rowVisible = visibleSection[rowID]; + const min = isVertical ? frame.y : frame.x; + const max = min + (isVertical ? frame.height : frame.width); if ((!min && !max) || min === max) { break; } @@ -737,7 +737,7 @@ var ListView = createReactClass({ }, _onScroll: function(e: Object) { - var isVertical = !this.props.horizontal; + const isVertical = !this.props.horizontal; this.scrollProperties.visibleLength = e.nativeEvent.layoutMeasurement[isVertical ? 'height' : 'width']; this.scrollProperties.contentLength = diff --git a/Libraries/Lists/ListView/ListViewDataSource.js b/Libraries/Lists/ListView/ListViewDataSource.js index dda74b50cb8381..b046a58bfd2af1 100644 --- a/Libraries/Lists/ListView/ListViewDataSource.js +++ b/Libraries/Lists/ListView/ListViewDataSource.js @@ -9,12 +9,12 @@ */ 'use strict'; -var invariant = require('fbjs/lib/invariant'); -var isEmpty = require('isEmpty'); +const invariant = require('fbjs/lib/invariant'); +const isEmpty = require('isEmpty'); /* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error * found when Flow v0.54 was deployed. To see the error delete this comment and * run Flow. */ -var warning = require('fbjs/lib/warning'); +const warning = require('fbjs/lib/warning'); function defaultGetRowData( dataBlob: any, @@ -142,7 +142,7 @@ class ListViewDataSource { dataBlob: $ReadOnlyArray | {+[key: string]: any}, rowIdentities: ?$ReadOnlyArray, ): ListViewDataSource { - var rowIds = rowIdentities ? [[...rowIdentities]] : null; + const rowIds = rowIdentities ? [[...rowIdentities]] : null; if (!this._sectionHeaderHasChanged) { this._sectionHeaderHasChanged = () => false; } @@ -184,7 +184,7 @@ class ListViewDataSource { 'row and section ids lengths must be the same', ); - var newSource = new ListViewDataSource({ + const newSource = new ListViewDataSource({ getRowData: this._getRowData, getSectionHeaderData: this._getSectionHeaderData, rowHasChanged: this._rowHasChanged, @@ -237,7 +237,7 @@ class ListViewDataSource { * Returns if the row is dirtied and needs to be rerendered */ rowShouldUpdate(sectionIndex: number, rowIndex: number): boolean { - var needsUpdate = this._dirtyRows[sectionIndex][rowIndex]; + const needsUpdate = this._dirtyRows[sectionIndex][rowIndex]; warning( needsUpdate !== undefined, 'missing dirtyBit for section, row: ' + sectionIndex + ', ' + rowIndex, @@ -249,8 +249,8 @@ class ListViewDataSource { * Gets the data required to render the row. */ getRowData(sectionIndex: number, rowIndex: number): any { - var sectionID = this.sectionIdentities[sectionIndex]; - var rowID = this.rowIdentities[sectionIndex][rowIndex]; + const sectionID = this.sectionIdentities[sectionIndex]; + const rowID = this.rowIdentities[sectionIndex][rowIndex]; warning( sectionID !== undefined && rowID !== undefined, 'rendering invalid section, row: ' + sectionIndex + ', ' + rowIndex, @@ -263,8 +263,8 @@ class ListViewDataSource { * or null of out of range indexes. */ getRowIDForFlatIndex(index: number): ?string { - var accessIndex = index; - for (var ii = 0; ii < this.sectionIdentities.length; ii++) { + let accessIndex = index; + for (let ii = 0; ii < this.sectionIdentities.length; ii++) { if (accessIndex >= this.rowIdentities[ii].length) { accessIndex -= this.rowIdentities[ii].length; } else { @@ -279,8 +279,8 @@ class ListViewDataSource { * or null for out of range indexes. */ getSectionIDForFlatIndex(index: number): ?string { - var accessIndex = index; - for (var ii = 0; ii < this.sectionIdentities.length; ii++) { + let accessIndex = index; + for (let ii = 0; ii < this.sectionIdentities.length; ii++) { if (accessIndex >= this.rowIdentities[ii].length) { accessIndex -= this.rowIdentities[ii].length; } else { @@ -294,8 +294,8 @@ class ListViewDataSource { * Returns an array containing the number of rows in each section */ getSectionLengths(): Array { - var results = []; - for (var ii = 0; ii < this.sectionIdentities.length; ii++) { + const results = []; + for (let ii = 0; ii < this.sectionIdentities.length; ii++) { results.push(this.rowIdentities[ii].length); } return results; @@ -305,7 +305,7 @@ class ListViewDataSource { * Returns if the section header is dirtied and needs to be rerendered */ sectionHeaderShouldUpdate(sectionIndex: number): boolean { - var needsUpdate = this._dirtySections[sectionIndex]; + const needsUpdate = this._dirtySections[sectionIndex]; warning( needsUpdate !== undefined, 'missing dirtyBit for section: ' + sectionIndex, @@ -320,7 +320,7 @@ class ListViewDataSource { if (!this._getSectionHeaderData) { return null; } - var sectionID = this.sectionIdentities[sectionIndex]; + const sectionID = this.sectionIdentities[sectionIndex]; warning( sectionID !== undefined, 'renderSection called on invalid section: ' + sectionIndex, @@ -353,9 +353,9 @@ class ListViewDataSource { prevRowIDs: Array>, ): void { // construct a hashmap of the existing (old) id arrays - var prevSectionsHash = keyedDictionaryFromArray(prevSectionIDs); - var prevRowsHash = {}; - for (var ii = 0; ii < prevRowIDs.length; ii++) { + const prevSectionsHash = keyedDictionaryFromArray(prevSectionIDs); + const prevRowsHash = {}; + for (let ii = 0; ii < prevRowIDs.length; ii++) { var sectionID = prevSectionIDs[ii]; warning( !prevRowsHash[sectionID], @@ -368,12 +368,12 @@ class ListViewDataSource { this._dirtySections = []; this._dirtyRows = []; - var dirty; - for (var sIndex = 0; sIndex < this.sectionIdentities.length; sIndex++) { + let dirty; + for (let sIndex = 0; sIndex < this.sectionIdentities.length; sIndex++) { var sectionID = this.sectionIdentities[sIndex]; // dirty if the sectionHeader is new or _sectionHasChanged is true dirty = !prevSectionsHash[sectionID]; - var sectionHeaderHasChanged = this._sectionHeaderHasChanged; + const sectionHeaderHasChanged = this._sectionHeaderHasChanged; if (!dirty && sectionHeaderHasChanged) { dirty = sectionHeaderHasChanged( this._getSectionHeaderData(prevDataBlob, sectionID), @@ -384,11 +384,11 @@ class ListViewDataSource { this._dirtyRows[sIndex] = []; for ( - var rIndex = 0; + let rIndex = 0; rIndex < this.rowIdentities[sIndex].length; rIndex++ ) { - var rowID = this.rowIdentities[sIndex][rIndex]; + const rowID = this.rowIdentities[sIndex][rIndex]; // dirty if the section is new, row is new or _rowHasChanged is true dirty = !prevSectionsHash[sectionID] || @@ -404,9 +404,9 @@ class ListViewDataSource { } function countRows(allRowIDs) { - var totalRows = 0; - for (var sectionIdx = 0; sectionIdx < allRowIDs.length; sectionIdx++) { - var rowIDs = allRowIDs[sectionIdx]; + let totalRows = 0; + for (let sectionIdx = 0; sectionIdx < allRowIDs.length; sectionIdx++) { + const rowIDs = allRowIDs[sectionIdx]; totalRows += rowIDs.length; } return totalRows; @@ -416,9 +416,9 @@ function keyedDictionaryFromArray(arr) { if (isEmpty(arr)) { return {}; } - var result = {}; - for (var ii = 0; ii < arr.length; ii++) { - var key = arr[ii]; + const result = {}; + for (let ii = 0; ii < arr.length; ii++) { + const key = arr[ii]; warning(!result[key], 'Value appears more than once in array: ' + key); result[key] = true; } diff --git a/Libraries/Modal/Modal.js b/Libraries/Modal/Modal.js index 52ed8c7a2b9e87..77f50cf273d788 100644 --- a/Libraries/Modal/Modal.js +++ b/Libraries/Modal/Modal.js @@ -36,7 +36,7 @@ import type EmitterSubscription from 'EmitterSubscription'; // on screen. There can be different ones, either nested or as siblings. // We cannot pass the onDismiss callback to native as the view will be // destroyed before the callback is fired. -var uniqueModalIdentifier = 0; +let uniqueModalIdentifier = 0; class Modal extends React.Component { static propTypes = { diff --git a/Libraries/Network/FormData.js b/Libraries/Network/FormData.js index 6028a06bf87657..40f351c5a5ee78 100644 --- a/Libraries/Network/FormData.js +++ b/Libraries/Network/FormData.js @@ -60,9 +60,9 @@ class FormData { getParts(): Array { return this._parts.map(([name, value]) => { - var contentDisposition = 'form-data; name="' + name + '"'; + const contentDisposition = 'form-data; name="' + name + '"'; - var headers: Headers = {'content-disposition': contentDisposition}; + const headers: Headers = {'content-disposition': contentDisposition}; // The body part is a "blob", which in React Native just means // an object with a `uri` attribute. Optionally, it can also diff --git a/Libraries/Network/XHRInterceptor.js b/Libraries/Network/XHRInterceptor.js index 22c6cf853fe0a8..f3dd1e03e08403 100644 --- a/Libraries/Network/XHRInterceptor.js +++ b/Libraries/Network/XHRInterceptor.js @@ -12,13 +12,13 @@ const originalXHROpen = XMLHttpRequest.prototype.open; const originalXHRSend = XMLHttpRequest.prototype.send; const originalXHRSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader; -var openCallback; -var sendCallback; -var requestHeaderCallback; -var headerReceivedCallback; -var responseCallback; +let openCallback; +let sendCallback; +let requestHeaderCallback; +let headerReceivedCallback; +let responseCallback; -var isInterceptorEnabled = false; +let isInterceptorEnabled = false; /** * A network interceptor which monkey-patches XMLHttpRequest methods diff --git a/Libraries/Network/XMLHttpRequest.js b/Libraries/Network/XMLHttpRequest.js index dd43fa40c86cd2..afbfc7db68df26 100644 --- a/Libraries/Network/XMLHttpRequest.js +++ b/Libraries/Network/XMLHttpRequest.js @@ -421,14 +421,14 @@ class XMLHttpRequest extends EventTarget(...XHR_EVENTS) { // according to the spec, return null if no response has been received return null; } - var headers = this.responseHeaders || {}; + const headers = this.responseHeaders || {}; return Object.keys(headers).map((headerName) => { return headerName + ': ' + headers[headerName]; }).join('\r\n'); } getResponseHeader(header: string): ?string { - var value = this._lowerCaseResponseHeaders[header.toLowerCase()]; + const value = this._lowerCaseResponseHeaders[header.toLowerCase()]; return value !== undefined ? value : null; } @@ -545,7 +545,7 @@ class XMLHttpRequest extends EventTarget(...XHR_EVENTS) { setResponseHeaders(responseHeaders: ?Object): void { this.responseHeaders = responseHeaders || null; - var headers = responseHeaders || {}; + const headers = responseHeaders || {}; this._lowerCaseResponseHeaders = Object.keys(headers).reduce((lcaseHeaders, headerName) => { lcaseHeaders[headerName.toLowerCase()] = headers[headerName]; diff --git a/Libraries/PushNotificationIOS/PushNotificationIOS.js b/Libraries/PushNotificationIOS/PushNotificationIOS.js index 9f013436c991ae..fc3db58f2974e9 100644 --- a/Libraries/PushNotificationIOS/PushNotificationIOS.js +++ b/Libraries/PushNotificationIOS/PushNotificationIOS.js @@ -182,7 +182,7 @@ class PushNotificationIOS { type === 'notification' || type === 'register' || type === 'registrationError' || type === 'localNotification', 'PushNotificationIOS only supports `notification`, `register`, `registrationError`, and `localNotification` events' ); - var listener; + let listener; if (type === 'notification') { listener = PushNotificationEmitter.addListener( DEVICE_NOTIF_EVENT, @@ -226,7 +226,7 @@ class PushNotificationIOS { type === 'notification' || type === 'register' || type === 'registrationError' || type === 'localNotification', 'PushNotificationIOS only supports `notification`, `register`, `registrationError`, and `localNotification` events' ); - var listener = _notifHandlers.get(type); + const listener = _notifHandlers.get(type); if (!listener) { return; } @@ -251,7 +251,7 @@ class PushNotificationIOS { badge: boolean, sound: boolean }> { - var requestedPermissions = {}; + let requestedPermissions = {}; if (permissions) { requestedPermissions = { alert: !!permissions.alert, @@ -321,7 +321,7 @@ class PushNotificationIOS { // Extract data from Apple's `aps` dict as defined: // https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ApplePushService.html Object.keys(nativeNotif).forEach((notifKey) => { - var notifVal = nativeNotif[notifKey]; + const notifVal = nativeNotif[notifKey]; if (notifKey === 'aps') { this._alert = notifVal.alert; this._sound = notifVal.sound; diff --git a/Libraries/RCTTest/SnapshotViewIOS.ios.js b/Libraries/RCTTest/SnapshotViewIOS.ios.js index 050ec5d633dd63..0a2877a9d64233 100644 --- a/Libraries/RCTTest/SnapshotViewIOS.ios.js +++ b/Libraries/RCTTest/SnapshotViewIOS.ios.js @@ -8,16 +8,16 @@ */ 'use strict'; -var React = require('React'); +const React = require('React'); const PropTypes = require('prop-types'); -var StyleSheet = require('StyleSheet'); -var { TestModule } = require('NativeModules'); -var UIManager = require('UIManager'); -var View = require('View'); +const StyleSheet = require('StyleSheet'); +const { TestModule } = require('NativeModules'); +const UIManager = require('UIManager'); +const View = require('View'); const ViewPropTypes = require('ViewPropTypes'); -var requireNativeComponent = require('requireNativeComponent'); +const requireNativeComponent = require('requireNativeComponent'); class SnapshotViewIOS extends React.Component<{ onSnapshotReady?: Function, @@ -37,8 +37,8 @@ class SnapshotViewIOS extends React.Component<{ }; render() { - var testIdentifier = this.props.testIdentifier || 'test'; - var onSnapshotReady = this.props.onSnapshotReady || this.onDefaultAction; + const testIdentifier = this.props.testIdentifier || 'test'; + const onSnapshotReady = this.props.onSnapshotReady || this.onDefaultAction; return ( void; * @param {function} onError `func(error)` * @param {function} onSuccess `func(left, top, width, height, pageX, pageY)` */ -var queryLayoutByID = function( +const queryLayoutByID = function( tag: ?number, onError: OnErrorCallback, onSuccess: OnSuccessCallback, diff --git a/Libraries/Sample/Sample.android.js b/Libraries/Sample/Sample.android.js index dbb43949f6f61c..61b3948415b884 100644 --- a/Libraries/Sample/Sample.android.js +++ b/Libraries/Sample/Sample.android.js @@ -5,9 +5,9 @@ */ 'use strict'; -var warning = require('fbjs/lib/warning'); +const warning = require('fbjs/lib/warning'); -var Sample = { +const Sample = { test: function() { warning('Not yet implemented for Android.'); } diff --git a/Libraries/Sample/Sample.ios.js b/Libraries/Sample/Sample.ios.js index ae51247cc63524..0e459eb90ae304 100644 --- a/Libraries/Sample/Sample.ios.js +++ b/Libraries/Sample/Sample.ios.js @@ -3,13 +3,13 @@ */ 'use strict'; -var NativeSample = require('NativeModules').Sample; +const NativeSample = require('NativeModules').Sample; /** * High-level docs for the Sample iOS API can be written here. */ -var Sample = { +const Sample = { test: function() { NativeSample.test(); } diff --git a/Libraries/Settings/Settings.android.js b/Libraries/Settings/Settings.android.js index 220c04e8b15961..c87accba58344f 100644 --- a/Libraries/Settings/Settings.android.js +++ b/Libraries/Settings/Settings.android.js @@ -8,7 +8,7 @@ */ 'use strict'; -var Settings = { +const Settings = { get(key: string): mixed { console.warn('Settings is not yet supported on Android'); return null; diff --git a/Libraries/Settings/Settings.ios.js b/Libraries/Settings/Settings.ios.js index 46f0a8bebdd7c9..d0c893ddfb6dd9 100644 --- a/Libraries/Settings/Settings.ios.js +++ b/Libraries/Settings/Settings.ios.js @@ -8,14 +8,14 @@ */ 'use strict'; -var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter'); -var RCTSettingsManager = require('NativeModules').SettingsManager; +const RCTDeviceEventEmitter = require('RCTDeviceEventEmitter'); +const RCTSettingsManager = require('NativeModules').SettingsManager; -var invariant = require('fbjs/lib/invariant'); +const invariant = require('fbjs/lib/invariant'); -var subscriptions: Array<{keys: Array, callback: ?Function}> = []; +const subscriptions: Array<{keys: Array, callback: ?Function}> = []; -var Settings = { +const Settings = { _settings: RCTSettingsManager && RCTSettingsManager.settings, get(key: string): mixed { @@ -37,7 +37,7 @@ var Settings = { 'keys should be a string or array of strings' ); - var sid = subscriptions.length; + const sid = subscriptions.length; subscriptions.push({keys: keys, callback: callback}); return sid; }, @@ -50,8 +50,8 @@ var Settings = { _sendObservations(body: Object) { Object.keys(body).forEach((key) => { - var newValue = body[key]; - var didChange = this._settings[key] !== newValue; + const newValue = body[key]; + const didChange = this._settings[key] !== newValue; this._settings[key] = newValue; if (didChange) { diff --git a/Libraries/Storage/AsyncStorage.js b/Libraries/Storage/AsyncStorage.js index f953aecbce26b0..ed5042edd934bb 100644 --- a/Libraries/Storage/AsyncStorage.js +++ b/Libraries/Storage/AsyncStorage.js @@ -24,7 +24,7 @@ const RCTAsyncStorage = NativeModules.AsyncRocksDBStorage || * * See http://facebook.github.io/react-native/docs/asyncstorage.html */ -var AsyncStorage = { +const AsyncStorage = { _getRequests: ([]: Array), _getKeys: ([]: Array), _immediate: (null: ?number), @@ -41,8 +41,8 @@ var AsyncStorage = { return new Promise((resolve, reject) => { RCTAsyncStorage.multiGet([key], function(errors, result) { // Unpack result to get value from [[key,value]] - var value = (result && result[0] && result[0][1]) ? result[0][1] : null; - var errs = convertErrors(errors); + const value = (result && result[0] && result[0][1]) ? result[0][1] : null; + const errs = convertErrors(errors); callback && callback(errs && errs[0], value); if (errs) { reject(errs[0]); @@ -65,7 +65,7 @@ var AsyncStorage = { ): Promise { return new Promise((resolve, reject) => { RCTAsyncStorage.multiSet([[key,value]], function(errors) { - var errs = convertErrors(errors); + const errs = convertErrors(errors); callback && callback(errs && errs[0]); if (errs) { reject(errs[0]); @@ -87,7 +87,7 @@ var AsyncStorage = { ): Promise { return new Promise((resolve, reject) => { RCTAsyncStorage.multiRemove([key], function(errors) { - var errs = convertErrors(errors); + const errs = convertErrors(errors); callback && callback(errs && errs[0]); if (errs) { reject(errs[0]); @@ -113,7 +113,7 @@ var AsyncStorage = { ): Promise { return new Promise((resolve, reject) => { RCTAsyncStorage.multiMerge([[key,value]], function(errors) { - var errs = convertErrors(errors); + const errs = convertErrors(errors); callback && callback(errs && errs[0]); if (errs) { reject(errs[0]); @@ -222,7 +222,7 @@ var AsyncStorage = { }); } - var getRequest = { + const getRequest = { keys: keys, callback: callback, // do we need this? @@ -231,7 +231,7 @@ var AsyncStorage = { reject: null, }; - var promiseResult = new Promise((resolve, reject) => { + const promiseResult = new Promise((resolve, reject) => { getRequest.resolve = resolve; getRequest.reject = reject; }); @@ -259,7 +259,7 @@ var AsyncStorage = { ): Promise { return new Promise((resolve, reject) => { RCTAsyncStorage.multiSet(keyValuePairs, function(errors) { - var error = convertErrors(errors); + const error = convertErrors(errors); callback && callback(error); if (error) { reject(error); @@ -281,7 +281,7 @@ var AsyncStorage = { ): Promise { return new Promise((resolve, reject) => { RCTAsyncStorage.multiRemove(keys, function(errors) { - var error = convertErrors(errors); + const error = convertErrors(errors); callback && callback(error); if (error) { reject(error); @@ -306,7 +306,7 @@ var AsyncStorage = { ): Promise { return new Promise((resolve, reject) => { RCTAsyncStorage.multiMerge(keyValuePairs, function(errors) { - var error = convertErrors(errors); + const error = convertErrors(errors); callback && callback(error); if (error) { reject(error); @@ -335,7 +335,7 @@ function convertError(error) { if (!error) { return null; } - var out = new Error(error.message); + const out = new Error(error.message); out.key = error.key; // flow doesn't like this :( return out; } diff --git a/Libraries/StyleSheet/ColorPropType.js b/Libraries/StyleSheet/ColorPropType.js index 28bc93f45fa9ef..562d3ad89ff8fd 100644 --- a/Libraries/StyleSheet/ColorPropType.js +++ b/Libraries/StyleSheet/ColorPropType.js @@ -7,10 +7,10 @@ */ 'use strict'; -var normalizeColor = require('normalizeColor'); +const normalizeColor = require('normalizeColor'); -var colorPropType = function(isRequired, props, propName, componentName, location, propFullName) { - var color = props[propName]; +const colorPropType = function(isRequired, props, propName, componentName, location, propFullName) { + const color = props[propName]; if (color === undefined || color === null) { if (isRequired) { return new Error( @@ -48,7 +48,7 @@ var colorPropType = function(isRequired, props, propName, componentName, locatio } }; -var ColorPropType = colorPropType.bind(null, false /* isRequired */); +const ColorPropType = colorPropType.bind(null, false /* isRequired */); ColorPropType.isRequired = colorPropType.bind(null, true /* isRequired */); module.exports = ColorPropType; diff --git a/Libraries/StyleSheet/LayoutPropTypes.js b/Libraries/StyleSheet/LayoutPropTypes.js index 6ff1844c7facd8..aa755aa4473dbb 100644 --- a/Libraries/StyleSheet/LayoutPropTypes.js +++ b/Libraries/StyleSheet/LayoutPropTypes.js @@ -8,7 +8,7 @@ */ 'use strict'; -var ReactPropTypes = require('prop-types'); +const ReactPropTypes = require('prop-types'); /** * React Native's layout system is based on Flexbox and is powered both @@ -23,7 +23,7 @@ var ReactPropTypes = require('prop-types'); * These properties are a subset of our styles that are consumed by the layout * algorithm and affect the positioning and sizing of views. */ -var LayoutPropTypes = { +const LayoutPropTypes = { /** `display` sets the display type of this component. * * It works similarly to `display` in CSS, but only support 'flex' and 'none'. diff --git a/Libraries/StyleSheet/PointPropType.js b/Libraries/StyleSheet/PointPropType.js index 44efc2d5fc400c..8a93b6c5464202 100644 --- a/Libraries/StyleSheet/PointPropType.js +++ b/Libraries/StyleSheet/PointPropType.js @@ -8,11 +8,11 @@ */ 'use strict'; -var PropTypes = require('prop-types'); +const PropTypes = require('prop-types'); -var createStrictShapeTypeChecker = require('createStrictShapeTypeChecker'); +const createStrictShapeTypeChecker = require('createStrictShapeTypeChecker'); -var PointPropType = createStrictShapeTypeChecker({ +const PointPropType = createStrictShapeTypeChecker({ x: PropTypes.number, y: PropTypes.number, }); diff --git a/Libraries/StyleSheet/StyleSheetPropType.js b/Libraries/StyleSheet/StyleSheetPropType.js index 9fed3d207a6303..e024c9374fea29 100644 --- a/Libraries/StyleSheet/StyleSheetPropType.js +++ b/Libraries/StyleSheet/StyleSheetPropType.js @@ -8,15 +8,15 @@ */ 'use strict'; -var createStrictShapeTypeChecker = require('createStrictShapeTypeChecker'); -var flattenStyle = require('flattenStyle'); +const createStrictShapeTypeChecker = require('createStrictShapeTypeChecker'); +const flattenStyle = require('flattenStyle'); function StyleSheetPropType( shape: {[key: string]: ReactPropsCheckType} ): ReactPropsCheckType { - var shapePropType = createStrictShapeTypeChecker(shape); + const shapePropType = createStrictShapeTypeChecker(shape); return function(props, propName, componentName, location?, ...rest) { - var newProps = props; + let newProps = props; if (props[propName]) { // Just make a dummy prop object with only the flattened style newProps = {}; diff --git a/Libraries/StyleSheet/StyleSheetValidation.js b/Libraries/StyleSheet/StyleSheetValidation.js index ae6c843de4f7ee..c7686dcb9e9305 100644 --- a/Libraries/StyleSheet/StyleSheetValidation.js +++ b/Libraries/StyleSheet/StyleSheetValidation.js @@ -8,11 +8,11 @@ */ 'use strict'; -var ImageStylePropTypes = require('ImageStylePropTypes'); -var TextStylePropTypes = require('TextStylePropTypes'); -var ViewStylePropTypes = require('ViewStylePropTypes'); +const ImageStylePropTypes = require('ImageStylePropTypes'); +const TextStylePropTypes = require('TextStylePropTypes'); +const ViewStylePropTypes = require('ViewStylePropTypes'); -var invariant = require('fbjs/lib/invariant'); +const invariant = require('fbjs/lib/invariant'); // Hardcoded because this is a legit case but we don't want to load it from // a private API. We might likely want to unify style sheet creation with how it @@ -26,12 +26,12 @@ class StyleSheetValidation { return; } if (allStylePropTypes[prop] === undefined) { - var message1 = '"' + prop + '" is not a valid style property.'; - var message2 = '\nValid style props: ' + + const message1 = '"' + prop + '" is not a valid style property.'; + const message2 = '\nValid style props: ' + JSON.stringify(Object.keys(allStylePropTypes).sort(), null, ' '); styleError(message1, style, caller, message2); } - var error = allStylePropTypes[prop]( + const error = allStylePropTypes[prop]( style, prop, caller, @@ -48,19 +48,19 @@ class StyleSheetValidation { if (!__DEV__) { return; } - for (var prop in styles[name]) { + for (const prop in styles[name]) { StyleSheetValidation.validateStyleProp(prop, styles[name], 'StyleSheet ' + name); } } static addValidStylePropTypes(stylePropTypes) { - for (var key in stylePropTypes) { + for (const key in stylePropTypes) { allStylePropTypes[key] = stylePropTypes[key]; } } } -var styleError = function(message1, style, caller?, message2?) { +const styleError = function(message1, style, caller?, message2?) { invariant( false, message1 + '\n' + (caller || '<>') + ': ' + @@ -68,7 +68,7 @@ var styleError = function(message1, style, caller?, message2?) { ); }; -var allStylePropTypes = {}; +const allStylePropTypes = {}; StyleSheetValidation.addValidStylePropTypes(ImageStylePropTypes); StyleSheetValidation.addValidStylePropTypes(TextStylePropTypes); diff --git a/Libraries/StyleSheet/TransformPropTypes.js b/Libraries/StyleSheet/TransformPropTypes.js index 13a58fdd7ff8ca..2f9037abf0ad94 100644 --- a/Libraries/StyleSheet/TransformPropTypes.js +++ b/Libraries/StyleSheet/TransformPropTypes.js @@ -8,11 +8,11 @@ */ 'use strict'; -var ReactPropTypes = require('prop-types'); +const ReactPropTypes = require('prop-types'); -var deprecatedPropType = require('deprecatedPropType'); +const deprecatedPropType = require('deprecatedPropType'); -var TransformMatrixPropType = function( +const TransformMatrixPropType = function( props : Object, propName : string, componentName : string @@ -25,7 +25,7 @@ var TransformMatrixPropType = function( } }; -var DecomposedMatrixPropType = function( +const DecomposedMatrixPropType = function( props : Object, propName : string, componentName : string @@ -38,7 +38,7 @@ var DecomposedMatrixPropType = function( } }; -var TransformPropTypes = { +const TransformPropTypes = { /** * `transform` accepts an array of transformation objects. Each object specifies * the property that will be transformed as the key, and the value to use in the diff --git a/Libraries/StyleSheet/__tests__/flattenStyle-test.js b/Libraries/StyleSheet/__tests__/flattenStyle-test.js index 76ce2822d900f2..0db505ff29b0a5 100644 --- a/Libraries/StyleSheet/__tests__/flattenStyle-test.js +++ b/Libraries/StyleSheet/__tests__/flattenStyle-test.js @@ -83,8 +83,8 @@ describe('flattenStyle', () => { it('should not allocate an object when there is a single class', () => { const fixture = getFixture(); - var singleStyle = flattenStyle(fixture.elementA); - var singleStyleAgain = flattenStyle(fixture.elementA); + const singleStyle = flattenStyle(fixture.elementA); + const singleStyleAgain = flattenStyle(fixture.elementA); expect(singleStyle).toBe(singleStyleAgain); expect(singleStyle).toEqual({ @@ -95,8 +95,8 @@ describe('flattenStyle', () => { it('should merge single class and style properly', () => { const fixture = getFixture(); - var style = {styleA: 'overrideA', styleC: 'overrideC'}; - var arrayStyle = flattenStyle([fixture.elementA, style]); + const style = {styleA: 'overrideA', styleC: 'overrideC'}; + const arrayStyle = flattenStyle([fixture.elementA, style]); expect(arrayStyle).toEqual({ styleA: 'overrideA', @@ -107,8 +107,8 @@ describe('flattenStyle', () => { it('should merge multiple classes', () => { const fixture = getFixture(); - var AthenB = flattenStyle([fixture.elementA, fixture.elementB]); - var BthenA = flattenStyle([fixture.elementB, fixture.elementA]); + const AthenB = flattenStyle([fixture.elementA, fixture.elementB]); + const BthenA = flattenStyle([fixture.elementB, fixture.elementA]); expect(AthenB).toEqual({ styleA: 'moduleA/elementA/styleA', @@ -122,9 +122,9 @@ describe('flattenStyle', () => { it('should merge multiple classes with style', () => { const fixture = getFixture(); - var style = {styleA: 'overrideA'}; - var AthenB = flattenStyle([fixture.elementA, fixture.elementB, style]); - var BthenA = flattenStyle([fixture.elementB, fixture.elementA, style]); + const style = {styleA: 'overrideA'}; + const AthenB = flattenStyle([fixture.elementA, fixture.elementB, style]); + const BthenA = flattenStyle([fixture.elementB, fixture.elementA, style]); expect(AthenB).toEqual({ styleA: 'overrideA', @@ -138,8 +138,8 @@ describe('flattenStyle', () => { it('should flatten recursively', () => { const fixture = getFixture(); - var style = [{styleA: 'newA', styleB: 'newB'}, {styleA: 'newA2'}]; - var AthenB = flattenStyle([fixture.elementA, fixture.elementB, style]); + const style = [{styleA: 'newA', styleB: 'newB'}, {styleA: 'newA2'}]; + const AthenB = flattenStyle([fixture.elementA, fixture.elementB, style]); expect(AthenB).toEqual({ styleA: 'newA2', @@ -148,7 +148,7 @@ describe('flattenStyle', () => { }); it('should ignore invalid class names', () => { - var invalid = flattenStyle(1234, null); + const invalid = flattenStyle(1234, null); expect(invalid).toEqual(undefined); // Invalid class name 1234 skipping ... diff --git a/Libraries/StyleSheet/__tests__/normalizeColor-test.js b/Libraries/StyleSheet/__tests__/normalizeColor-test.js index d7482a9c55bd55..7edfdb4ac9052f 100644 --- a/Libraries/StyleSheet/__tests__/normalizeColor-test.js +++ b/Libraries/StyleSheet/__tests__/normalizeColor-test.js @@ -8,7 +8,7 @@ */ 'use strict'; -var normalizeColor = require('normalizeColor'); +const normalizeColor = require('normalizeColor'); describe('normalizeColor', function() { it('should accept only spec compliant colors', function() { diff --git a/Libraries/StyleSheet/__tests__/processColor-test.js b/Libraries/StyleSheet/__tests__/processColor-test.js index 2af0baa108a742..a353a52a6be9c0 100644 --- a/Libraries/StyleSheet/__tests__/processColor-test.js +++ b/Libraries/StyleSheet/__tests__/processColor-test.js @@ -20,26 +20,26 @@ describe('processColor', () => { describe('predefined color names', () => { it('should convert red', () => { - var colorFromString = processColor('red'); - var expectedInt = 0xFFFF0000; + const colorFromString = processColor('red'); + const expectedInt = 0xFFFF0000; expect(colorFromString).toEqual(platformSpecific(expectedInt)); }); it('should convert white', () => { - var colorFromString = processColor('white'); - var expectedInt = 0xFFFFFFFF; + const colorFromString = processColor('white'); + const expectedInt = 0xFFFFFFFF; expect(colorFromString).toEqual(platformSpecific(expectedInt)); }); it('should convert black', () => { - var colorFromString = processColor('black'); - var expectedInt = 0xFF000000; + const colorFromString = processColor('black'); + const expectedInt = 0xFF000000; expect(colorFromString).toEqual(platformSpecific(expectedInt)); }); it('should convert transparent', () => { - var colorFromString = processColor('transparent'); - var expectedInt = 0x00000000; + const colorFromString = processColor('transparent'); + const expectedInt = 0x00000000; expect(colorFromString).toEqual(platformSpecific(expectedInt)); }); }); @@ -47,8 +47,8 @@ describe('processColor', () => { describe('RGB strings', () => { it('should convert rgb(x, y, z)', () => { - var colorFromString = processColor('rgb(10, 20, 30)'); - var expectedInt = 0xFF0A141E; + const colorFromString = processColor('rgb(10, 20, 30)'); + const expectedInt = 0xFF0A141E; expect(colorFromString).toEqual(platformSpecific(expectedInt)); }); @@ -57,8 +57,8 @@ describe('processColor', () => { describe('RGBA strings', () => { it('should convert rgba(x, y, z, a)', () => { - var colorFromString = processColor('rgba(10, 20, 30, 0.4)'); - var expectedInt = 0x660A141E; + const colorFromString = processColor('rgba(10, 20, 30, 0.4)'); + const expectedInt = 0x660A141E; expect(colorFromString).toEqual(platformSpecific(expectedInt)); }); @@ -67,8 +67,8 @@ describe('processColor', () => { describe('HSL strings', () => { it('should convert hsl(x, y%, z%)', () => { - var colorFromString = processColor('hsl(318, 69%, 55%)'); - var expectedInt = 0xFFDB3DAC; + const colorFromString = processColor('hsl(318, 69%, 55%)'); + const expectedInt = 0xFFDB3DAC; expect(colorFromString).toEqual(platformSpecific(expectedInt)); }); @@ -77,8 +77,8 @@ describe('processColor', () => { describe('HSLA strings', () => { it('should convert hsla(x, y%, z%, a)', () => { - var colorFromString = processColor('hsla(318, 69%, 55%, 0.25)'); - var expectedInt = 0x40DB3DAC; + const colorFromString = processColor('hsla(318, 69%, 55%, 0.25)'); + const expectedInt = 0x40DB3DAC; expect(colorFromString).toEqual(platformSpecific(expectedInt)); }); @@ -87,8 +87,8 @@ describe('processColor', () => { describe('hex strings', () => { it('should convert #xxxxxx', () => { - var colorFromString = processColor('#1e83c9'); - var expectedInt = 0xFF1E83C9; + const colorFromString = processColor('#1e83c9'); + const expectedInt = 0xFF1E83C9; expect(colorFromString).toEqual(platformSpecific(expectedInt)); }); diff --git a/Libraries/StyleSheet/__tests__/setNormalizedColorAlpha-test.js b/Libraries/StyleSheet/__tests__/setNormalizedColorAlpha-test.js index 13e47aff565726..5fd4a9f735e24a 100644 --- a/Libraries/StyleSheet/__tests__/setNormalizedColorAlpha-test.js +++ b/Libraries/StyleSheet/__tests__/setNormalizedColorAlpha-test.js @@ -8,8 +8,8 @@ */ 'use strict'; -var setNormalizedColorAlpha = require('setNormalizedColorAlpha'); -var normalizeColor = require('normalizeColor'); +const setNormalizedColorAlpha = require('setNormalizedColorAlpha'); +const normalizeColor = require('normalizeColor'); describe('setNormalizedColorAlpha', function() { it('should adjust the alpha of the color passed in', function() { @@ -27,7 +27,7 @@ describe('setNormalizedColorAlpha', function() { }); it('should return the original color when alpha is unchanged', function() { - var originalColor = normalizeColor('blue'); + const originalColor = normalizeColor('blue'); expect(setNormalizedColorAlpha(originalColor, 1)).toBe(originalColor); }); }); diff --git a/Libraries/StyleSheet/flattenStyle.js b/Libraries/StyleSheet/flattenStyle.js index f62e35ea70f4f4..cb5f6ebc96e71f 100644 --- a/Libraries/StyleSheet/flattenStyle.js +++ b/Libraries/StyleSheet/flattenStyle.js @@ -25,11 +25,11 @@ function flattenStyle( return style; } - var result = {}; - for (var i = 0, styleLength = style.length; i < styleLength; ++i) { - var computedStyle = flattenStyle(style[i]); + const result = {}; + for (let i = 0, styleLength = style.length; i < styleLength; ++i) { + const computedStyle = flattenStyle(style[i]); if (computedStyle) { - for (var key in computedStyle) { + for (const key in computedStyle) { result[key] = computedStyle[key]; } } diff --git a/Libraries/StyleSheet/processTransform.js b/Libraries/StyleSheet/processTransform.js index 3c8d30ea0e0ed6..fb4ed3445e8c9e 100644 --- a/Libraries/StyleSheet/processTransform.js +++ b/Libraries/StyleSheet/processTransform.js @@ -8,11 +8,11 @@ */ 'use strict'; -var MatrixMath = require('MatrixMath'); -var Platform = require('Platform'); +const MatrixMath = require('MatrixMath'); +const Platform = require('Platform'); -var invariant = require('fbjs/lib/invariant'); -var stringifySafe = require('stringifySafe'); +const invariant = require('fbjs/lib/invariant'); +const stringifySafe = require('stringifySafe'); /** * Generate a transform matrix based on the provided transforms, and use that @@ -34,11 +34,11 @@ function processTransform(transform: Array): Array | Array { - var key = Object.keys(transformation)[0]; - var value = transformation[key]; + const key = Object.keys(transformation)[0]; + const value = transformation[key]; switch (key) { case 'matrix': @@ -97,8 +97,8 @@ function _multiplyTransform( matrixMathFunction: Function, args: Array ): void { - var matrixToApply = MatrixMath.createIdentityMatrix(); - var argsWithIdentity = [matrixToApply].concat(args); + const matrixToApply = MatrixMath.createIdentityMatrix(); + const argsWithIdentity = [matrixToApply].concat(args); matrixMathFunction.apply(this, argsWithIdentity); MatrixMath.multiplyInto(result, result, matrixToApply); } @@ -108,20 +108,20 @@ function _multiplyTransform( * Note that validation on the string is done in `_validateTransform()`. */ function _convertToRadians(value: string): number { - var floatValue = parseFloat(value); + const floatValue = parseFloat(value); return value.indexOf('rad') > -1 ? floatValue : floatValue * Math.PI / 180; } function _validateTransforms(transform: Array): void { transform.forEach(transformation => { - var keys = Object.keys(transformation); + const keys = Object.keys(transformation); invariant( keys.length === 1, 'You must specify exactly one property per transform object. Passed properties: %s', stringifySafe(transformation), ); - var key = keys[0]; - var value = transformation[key]; + const key = keys[0]; + const value = transformation[key]; _validateTransform(key, value, transformation); }); } @@ -134,7 +134,7 @@ function _validateTransform(key, value, transformation) { 'replace by .' ); - var multivalueTransforms = [ + const multivalueTransforms = [ 'matrix', 'translate', ]; diff --git a/Libraries/Text/TextUpdateTest.js b/Libraries/Text/TextUpdateTest.js index 18a3ac5084b7af..b3dc0949aeed61 100644 --- a/Libraries/Text/TextUpdateTest.js +++ b/Libraries/Text/TextUpdateTest.js @@ -8,22 +8,22 @@ */ 'use strict'; -var React = require('react'); -var createReactClass = require('create-react-class'); -var ReactNative = require('react-native'); +const React = require('react'); +const createReactClass = require('create-react-class'); +const ReactNative = require('react-native'); /* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error * found when Flow v0.54 was deployed. To see the error delete this comment and * run Flow. */ -var TimerMixin = require('react-timer-mixin'); -var { +const TimerMixin = require('react-timer-mixin'); +const { NativeModules, StyleSheet, Text, } = ReactNative; -var TestManager = NativeModules.TestManager || NativeModules.SnapshotTestManager; +const TestManager = NativeModules.TestManager || NativeModules.SnapshotTestManager; -var TextUpdateTest = createReactClass({ +const TextUpdateTest = createReactClass({ displayName: 'TextUpdateTest', mixins: [TimerMixin], getInitialState: function() { @@ -48,7 +48,7 @@ var TextUpdateTest = createReactClass({ }, }); -var styles = StyleSheet.create({ +const styles = StyleSheet.create({ container: { margin: 10, marginTop: 100, diff --git a/Libraries/Utilities/BackAndroid.js b/Libraries/Utilities/BackAndroid.js index 51a68a7671f8e4..57e2d8d77a3acd 100644 --- a/Libraries/Utilities/BackAndroid.js +++ b/Libraries/Utilities/BackAndroid.js @@ -11,14 +11,14 @@ 'use strict'; -var BackHandler = require('BackHandler'); +const BackHandler = require('BackHandler'); -var warning = require('fbjs/lib/warning'); +const warning = require('fbjs/lib/warning'); /** * Deprecated. Use BackHandler instead. */ -var BackAndroid = { +const BackAndroid = { exitApp: function() { warning(false, 'BackAndroid is deprecated. Please use BackHandler instead.'); diff --git a/Libraries/Utilities/BackHandler.android.js b/Libraries/Utilities/BackHandler.android.js index b2e3a74bc44864..0db35d872098c1 100644 --- a/Libraries/Utilities/BackHandler.android.js +++ b/Libraries/Utilities/BackHandler.android.js @@ -8,22 +8,22 @@ 'use strict'; -var DeviceEventManager = require('NativeModules').DeviceEventManager; -var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter'); +const DeviceEventManager = require('NativeModules').DeviceEventManager; +const RCTDeviceEventEmitter = require('RCTDeviceEventEmitter'); -var DEVICE_BACK_EVENT = 'hardwareBackPress'; +const DEVICE_BACK_EVENT = 'hardwareBackPress'; type BackPressEventName = $Enum<{ backPress: string, }>; -var _backPressSubscriptions = new Set(); +const _backPressSubscriptions = new Set(); RCTDeviceEventEmitter.addListener(DEVICE_BACK_EVENT, function() { - var invokeDefault = true; - var subscriptions = Array.from(_backPressSubscriptions.values()).reverse(); + let invokeDefault = true; + const subscriptions = Array.from(_backPressSubscriptions.values()).reverse(); - for (var i = 0; i < subscriptions.length; ++i) { + for (let i = 0; i < subscriptions.length; ++i) { if (subscriptions[i]()) { invokeDefault = false; break; @@ -65,7 +65,7 @@ RCTDeviceEventEmitter.addListener(DEVICE_BACK_EVENT, function() { * }); * ``` */ -var BackHandler = { +const BackHandler = { exitApp: function() { DeviceEventManager.invokeDefaultBackPressHandler(); diff --git a/Libraries/Utilities/BackHandler.ios.js b/Libraries/Utilities/BackHandler.ios.js index 0c0d7d437870df..4112d6197f0738 100644 --- a/Libraries/Utilities/BackHandler.ios.js +++ b/Libraries/Utilities/BackHandler.ios.js @@ -54,14 +54,14 @@ let BackHandler; if (Platform.isTVOS) { const _tvEventHandler = new TVEventHandler(); - var _backPressSubscriptions = new Set(); + const _backPressSubscriptions = new Set(); _tvEventHandler.enable(this, function(cmp, evt) { if (evt && evt.eventType === 'menu') { - var invokeDefault = true; - var subscriptions = Array.from(_backPressSubscriptions.values()).reverse(); + let invokeDefault = true; + const subscriptions = Array.from(_backPressSubscriptions.values()).reverse(); - for (var i = 0; i < subscriptions.length; ++i) { + for (let i = 0; i < subscriptions.length; ++i) { if (subscriptions[i]()) { invokeDefault = false; break; diff --git a/Libraries/Utilities/Dimensions.js b/Libraries/Utilities/Dimensions.js index f27ecc0976b823..76bde024355cdb 100644 --- a/Libraries/Utilities/Dimensions.js +++ b/Libraries/Utilities/Dimensions.js @@ -8,15 +8,15 @@ */ 'use strict'; -var EventEmitter = require('EventEmitter'); -var Platform = require('Platform'); -var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter'); +const EventEmitter = require('EventEmitter'); +const Platform = require('Platform'); +const RCTDeviceEventEmitter = require('RCTDeviceEventEmitter'); -var invariant = require('fbjs/lib/invariant'); +const invariant = require('fbjs/lib/invariant'); -var eventEmitter = new EventEmitter(); -var dimensionsInitialized = false; -var dimensions = {}; +const eventEmitter = new EventEmitter(); +let dimensionsInitialized = false; +const dimensions = {}; class Dimensions { /** * This should only be called from native code by sending the diff --git a/Libraries/Utilities/HMRLoadingView.android.js b/Libraries/Utilities/HMRLoadingView.android.js index f4c0c5c731222d..61bc75c7e5171e 100644 --- a/Libraries/Utilities/HMRLoadingView.android.js +++ b/Libraries/Utilities/HMRLoadingView.android.js @@ -9,7 +9,7 @@ 'use strict'; -var ToastAndroid = require('ToastAndroid'); +const ToastAndroid = require('ToastAndroid'); const TOAST_SHORT_DELAY = 2000; diff --git a/Libraries/Utilities/HeapCapture.js b/Libraries/Utilities/HeapCapture.js index 519a2e94370b8c..91df130ed934a2 100644 --- a/Libraries/Utilities/HeapCapture.js +++ b/Libraries/Utilities/HeapCapture.js @@ -8,9 +8,9 @@ */ 'use strict'; -var HeapCapture = { +const HeapCapture = { captureHeap: function (path: string) { - var error = null; + let error = null; try { global.nativeCaptureHeap(path); console.log('HeapCapture.captureHeap succeeded: ' + path); diff --git a/Libraries/Utilities/MatrixMath.js b/Libraries/Utilities/MatrixMath.js index be329c2e645d5d..40f934cc88ac34 100755 --- a/Libraries/Utilities/MatrixMath.js +++ b/Libraries/Utilities/MatrixMath.js @@ -9,13 +9,13 @@ /* eslint-disable space-infix-ops */ 'use strict'; -var invariant = require('fbjs/lib/invariant'); +const invariant = require('fbjs/lib/invariant'); /** * Memory conservative (mutative) matrix math utilities. Uses "command" * matrices, which are reusable. */ -var MatrixMath = { +const MatrixMath = { createIdentityMatrix: function() { return [ 1,0,0,0, @@ -35,13 +35,13 @@ var MatrixMath = { }, createOrthographic: function(left, right, bottom, top, near, far) { - var a = 2 / (right - left); - var b = 2 / (top - bottom); - var c = -2 / (far - near); + const a = 2 / (right - left); + const b = 2 / (top - bottom); + const c = -2 / (far - near); - var tx = -(right + left) / (right - left); - var ty = -(top + bottom) / (top - bottom); - var tz = -(far + near) / (far - near); + const tx = -(right + left) / (right - left); + const ty = -(top + bottom) / (top - bottom); + const tz = -(far + near) / (far - near); return [ a, 0, 0, 0, @@ -52,15 +52,15 @@ var MatrixMath = { }, createFrustum: function(left, right, bottom, top, near, far) { - var r_width = 1 / (right - left); - var r_height = 1 / (top - bottom); - var r_depth = 1 / (near - far); - var x = 2 * (near * r_width); - var y = 2 * (near * r_height); - var A = (right + left) * r_width; - var B = (top + bottom) * r_height; - var C = (far + near) * r_depth; - var D = 2 * (far * near * r_depth); + const r_width = 1 / (right - left); + const r_height = 1 / (top - bottom); + const r_depth = 1 / (near - far); + const x = 2 * (near * r_width); + const y = 2 * (near * r_height); + const A = (right + left) * r_width; + const B = (top + bottom) * r_height; + const C = (far + near) * r_depth; + const D = 2 * (far * near * r_depth); return [ x, 0, 0, 0, 0, y, 0, 0, @@ -76,10 +76,10 @@ var MatrixMath = { * @param fovInRadians - field of view in randians */ createPerspective: function(fovInRadians, aspect, near, far) { - var h = 1 / Math.tan(fovInRadians / 2); - var r_depth = 1 / (near - far); - var C = (far + near) * r_depth; - var D = 2 * (far * near * r_depth); + const h = 1 / Math.tan(fovInRadians / 2); + const r_depth = 1 / (near - far); + const C = (far + near) * r_depth; + const D = 2 * (far * near * r_depth); return [ h/aspect, 0, 0, 0, 0, h, 0, 0, @@ -89,7 +89,7 @@ var MatrixMath = { }, createTranslate2d: function(x, y) { - var mat = MatrixMath.createIdentityMatrix(); + const mat = MatrixMath.createIdentityMatrix(); MatrixMath.reuseTranslate2dCommand(mat, x, y); return mat; }, @@ -106,7 +106,7 @@ var MatrixMath = { }, createScale: function(factor) { - var mat = MatrixMath.createIdentityMatrix(); + const mat = MatrixMath.createIdentityMatrix(); MatrixMath.reuseScaleCommand(mat, factor); return mat; }, @@ -161,7 +161,7 @@ var MatrixMath = { }, createRotateZ: function(radians) { - var mat = MatrixMath.createIdentityMatrix(); + const mat = MatrixMath.createIdentityMatrix(); MatrixMath.reuseRotateZCommand(mat, radians); return mat; }, @@ -175,12 +175,9 @@ var MatrixMath = { }, multiplyInto: function(out, a, b) { - var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], - a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], - a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], - a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; + const a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; - var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; + let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; @@ -206,7 +203,7 @@ var MatrixMath = { }, determinant(matrix: Array): number { - var [ + const [ m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, @@ -236,11 +233,11 @@ var MatrixMath = { * http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm */ inverse(matrix: Array): Array { - var det = MatrixMath.determinant(matrix); + const det = MatrixMath.determinant(matrix); if (!det) { return matrix; } - var [ + const [ m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, @@ -285,7 +282,7 @@ var MatrixMath = { v: Array, m: Array ): Array { - var [vx, vy, vz, vw] = v; + const [vx, vy, vz, vw] = v; return [ vx * m[0] + vy * m[4] + vz * m[8] + vw * m[12], vx * m[1] + vy * m[5] + vz * m[9] + vw * m[13], @@ -308,7 +305,7 @@ var MatrixMath = { vector: Array, v3Length: number ): Array { - var im = 1 / (v3Length || MatrixMath.v3Length(vector)); + const im = 1 / (v3Length || MatrixMath.v3Length(vector)); return [ vector[0] * im, vector[1] * im, @@ -372,14 +369,14 @@ var MatrixMath = { * roll === bank === x-axis */ quaternionToDegreesXYZ(q: Array, matrix, row): Array { - var [qx, qy, qz, qw] = q; - var qw2 = qw * qw; - var qx2 = qx * qx; - var qy2 = qy * qy; - var qz2 = qz * qz; - var test = qx * qy + qz * qw; - var unit = qw2 + qx2 + qy2 + qz2; - var conv = 180 / Math.PI; + const [qx, qy, qz, qw] = q; + const qw2 = qw * qw; + const qx2 = qx * qx; + const qy2 = qy * qy; + const qz2 = qz * qz; + const test = qx * qy + qz * qw; + const unit = qw2 + qx2 + qy2 + qz2; + const conv = 180 / Math.PI; if (test > 0.49999 * unit) { return [0, 2 * Math.atan2(qx, qw) * conv, 90]; @@ -406,7 +403,7 @@ var MatrixMath = { * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round */ roundTo3Places(n: number): number { - var arr = n.toString().split('e'); + const arr = n.toString().split('e'); return Math.round(arr[0] + 'e' + (arr[1] ? (+arr[1] - 3) : 3)) * 0.001; }, @@ -431,22 +428,22 @@ var MatrixMath = { // output values var perspective = []; - var quaternion = []; - var scale = []; - var skew = []; - var translation = []; + const quaternion = []; + const scale = []; + const skew = []; + const translation = []; // create normalized, 2d array matrix // and normalized 1d array perspectiveMatrix with redefined 4th column if (!transformMatrix[15]) { return; } - var matrix = []; - var perspectiveMatrix = []; + const matrix = []; + const perspectiveMatrix = []; for (var i = 0; i < 4; i++) { matrix.push([]); - for (var j = 0; j < 4; j++) { - var value = transformMatrix[(i * 4) + j] / transformMatrix[15]; + for (let j = 0; j < 4; j++) { + const value = transformMatrix[(i * 4) + j] / transformMatrix[15]; matrix[i].push(value); perspectiveMatrix.push(j === 3 ? 0 : value); } @@ -462,7 +459,7 @@ var MatrixMath = { if (matrix[0][3] !== 0 || matrix[1][3] !== 0 || matrix[2][3] !== 0) { // rightHandSide is the right hand side of the equation. // rightHandSide is a vector, or point in 3d space relative to the origin. - var rightHandSide = [ + const rightHandSide = [ matrix[0][3], matrix[1][3], matrix[2][3], @@ -471,10 +468,10 @@ var MatrixMath = { // Solve the equation by inverting perspectiveMatrix and multiplying // rightHandSide by the inverse. - var inversePerspectiveMatrix = MatrixMath.inverse( + const inversePerspectiveMatrix = MatrixMath.inverse( perspectiveMatrix ); - var transposedInversePerspectiveMatrix = MatrixMath.transpose( + const transposedInversePerspectiveMatrix = MatrixMath.transpose( inversePerspectiveMatrix ); var perspective = MatrixMath.multiplyVectorByMatrix( @@ -494,7 +491,7 @@ var MatrixMath = { // Now get scale and shear. // 'row' is a 3 element array of 3 component vectors - var row = []; + const row = []; for (i = 0; i < 3; i++) { row[i] = [ matrix[i][0], @@ -535,7 +532,7 @@ var MatrixMath = { // At this point, the matrix (in rows) is orthonormal. // Check for a coordinate system flip. If the determinant // is -1, then negate the matrix and the scaling factors. - var pdum3 = MatrixMath.v3Cross(row[1], row[2]); + const pdum3 = MatrixMath.v3Cross(row[1], row[2]); if (MatrixMath.v3Dot(row[0], pdum3) < 0) { for (i = 0; i < 3; i++) { scale[i] *= -1; @@ -566,7 +563,7 @@ var MatrixMath = { } // correct for occasional, weird Euler synonyms for 2d rotation - var rotationDegrees; + let rotationDegrees; if ( quaternion[0] < 0.001 && quaternion[0] >= 0 && quaternion[1] < 0.001 && quaternion[1] >= 0 diff --git a/Libraries/Utilities/PixelRatio.js b/Libraries/Utilities/PixelRatio.js index 5f52bdc0f5b838..58b2b02241fed4 100644 --- a/Libraries/Utilities/PixelRatio.js +++ b/Libraries/Utilities/PixelRatio.js @@ -8,7 +8,7 @@ */ 'use strict'; -var Dimensions = require('Dimensions'); +const Dimensions = require('Dimensions'); /** * PixelRatio class gives access to the device pixel density. @@ -108,7 +108,7 @@ class PixelRatio { * exactly (8.33 * 3) = 25 pixels. */ static roundToNearestPixel(layoutSize: number): number { - var ratio = PixelRatio.get(); + const ratio = PixelRatio.get(); return Math.round(layoutSize * ratio) / ratio; } diff --git a/Libraries/Utilities/__tests__/MatrixMath-test.js b/Libraries/Utilities/__tests__/MatrixMath-test.js index 2eb14cb5ba3c7b..f8491cec0fd76a 100644 --- a/Libraries/Utilities/__tests__/MatrixMath-test.js +++ b/Libraries/Utilities/__tests__/MatrixMath-test.js @@ -8,7 +8,7 @@ */ 'use strict'; -var MatrixMath = require('MatrixMath'); +const MatrixMath = require('MatrixMath'); function degreesToRadians(degrees) { return degrees * Math.PI / 180; @@ -26,7 +26,7 @@ describe('MatrixMath', () => { ]).rotationDegrees).toEqual([0, 0, 0]); [30, 45, 60, 75, 90, 100, 115, 120, 133, 167].forEach(angle => { - var mat = MatrixMath.createRotateZ(degreesToRadians(angle)); + let mat = MatrixMath.createRotateZ(degreesToRadians(angle)); expect(convertZeroes(MatrixMath.decomposeMatrix(mat).rotationDegrees)) .toEqual([0, 0, angle]); @@ -80,7 +80,7 @@ describe('MatrixMath', () => { }); it('decomposes a 4x4 matrix to produce accurate Y-axis angles', () => { - var mat; + let mat; [30, 45, 60, 75, 90, 100, 110, 120, 133, 167].forEach(angle => { mat = MatrixMath.createIdentityMatrix(); MatrixMath.reuseRotateYCommand(mat, degreesToRadians(angle)); @@ -112,7 +112,7 @@ describe('MatrixMath', () => { }); it('decomposes a 4x4 matrix to produce accurate X-axis angles', () => { - var mat; + let mat; [30, 45, 60, 75, 90, 100, 110, 120, 133, 167].forEach(angle => { mat = MatrixMath.createIdentityMatrix(); MatrixMath.reuseRotateXCommand(mat, degreesToRadians(angle)); diff --git a/Libraries/Utilities/__tests__/Platform-test.js b/Libraries/Utilities/__tests__/Platform-test.js index 1fdfaaa1a75ca3..72dafb4329c7dd 100644 --- a/Libraries/Utilities/__tests__/Platform-test.js +++ b/Libraries/Utilities/__tests__/Platform-test.js @@ -8,8 +8,8 @@ */ 'use strict'; -var PlatformIOS = require('../Platform.ios'); -var PlatformAndroid = require('../Platform.android'); +const PlatformIOS = require('../Platform.ios'); +const PlatformAndroid = require('../Platform.android'); describe('Platform', () => { diff --git a/Libraries/Utilities/__tests__/buildStyleInterpolator-test.js b/Libraries/Utilities/__tests__/buildStyleInterpolator-test.js index ccb5f7edfb31c5..78440b640010a7 100644 --- a/Libraries/Utilities/__tests__/buildStyleInterpolator-test.js +++ b/Libraries/Utilities/__tests__/buildStyleInterpolator-test.js @@ -8,11 +8,11 @@ */ 'use strict'; -var buildStyleInterpolator = require('buildStyleInterpolator'); +const buildStyleInterpolator = require('buildStyleInterpolator'); -var validateEmpty = function(interpolator, value, validator) { - var emptyObject = {}; - var changed = interpolator(emptyObject, value); +const validateEmpty = function(interpolator, value, validator) { + const emptyObject = {}; + let changed = interpolator(emptyObject, value); validator(emptyObject); expect(changed).toBe(true); changed = interpolator(emptyObject, value); @@ -20,7 +20,7 @@ var validateEmpty = function(interpolator, value, validator) { }; describe('buildStyleInterpolator', function() { it('should linearly interpolate without extrapolating', function() { - var testAnim = { + const testAnim = { opacity: { from: 100, to: 200, @@ -42,7 +42,7 @@ describe('buildStyleInterpolator', function() { value: 23.5, }, }; - var interpolator = buildStyleInterpolator(testAnim); + const interpolator = buildStyleInterpolator(testAnim); validateEmpty(interpolator, 0, function(res) { expect(res).toEqual({ opacity: 100, @@ -80,7 +80,7 @@ describe('buildStyleInterpolator', function() { }); }); it('should linearly interpolate with extrapolating', function() { - var testAnim = { + const testAnim = { opacity: { from: 100, to: 200, @@ -104,7 +104,7 @@ describe('buildStyleInterpolator', function() { value: 23.5, }, }; - var interpolator = buildStyleInterpolator(testAnim); + const interpolator = buildStyleInterpolator(testAnim); validateEmpty(interpolator, 0, function(res) { expect(res).toEqual({ opacity: 100, @@ -142,7 +142,7 @@ describe('buildStyleInterpolator', function() { }); }); it('should round accordingly', function() { - var testAnim = { + const testAnim = { opacity: { from: 0, to: 1, @@ -153,7 +153,7 @@ describe('buildStyleInterpolator', function() { extrapolate: true, }, }; - var interpolator = buildStyleInterpolator(testAnim); + const interpolator = buildStyleInterpolator(testAnim); validateEmpty(interpolator, 0, function(res) { expect(res).toEqual({ opacity: 0, @@ -186,7 +186,7 @@ describe('buildStyleInterpolator', function() { }); }); it('should detect chnages correctly', function() { - var testAnim = { + const testAnim = { opacity: { from: 0, to: 1, @@ -197,9 +197,9 @@ describe('buildStyleInterpolator', function() { extrapolate: false, }, }; - var interpolator = buildStyleInterpolator(testAnim); - var obj = {}; - var res = interpolator(obj, 0); + const interpolator = buildStyleInterpolator(testAnim); + const obj = {}; + let res = interpolator(obj, 0); expect(obj).toEqual({ opacity: 0, }); @@ -227,14 +227,14 @@ describe('buildStyleInterpolator', function() { expect(res).toBe(false); }); it('should handle identity', function() { - var testAnim = { + const testAnim = { opacity: { type: 'identity', }, }; - var interpolator = buildStyleInterpolator(testAnim); - var obj = {}; - var res = interpolator(obj, 0.5); + const interpolator = buildStyleInterpolator(testAnim); + const obj = {}; + let res = interpolator(obj, 0.5); expect(obj).toEqual({ opacity: 0.5, }); @@ -248,7 +248,7 @@ describe('buildStyleInterpolator', function() { expect(res).toBe(false); }); it('should translate', function() { - var testAnim = { + const testAnim = { transformTranslate: { from: {x: 1, y: 10, z: 100}, to: {x: 5, y: 50, z: 500}, @@ -257,9 +257,9 @@ describe('buildStyleInterpolator', function() { type: 'linear', }, }; - var interpolator = buildStyleInterpolator(testAnim); - var obj = {}; - var res = interpolator(obj, 1); + const interpolator = buildStyleInterpolator(testAnim); + const obj = {}; + const res = interpolator(obj, 1); expect(obj).toEqual({ transform: [{matrix: [1, 0, 0, 0, 0, 1, 0, 0, @@ -269,7 +269,7 @@ describe('buildStyleInterpolator', function() { expect(res).toBe(true); }); it('should scale', function() { - var testAnim = { + const testAnim = { transformScale: { from: {x: 1, y: 10, z: 100}, to: {x: 5, y: 50, z: 500}, @@ -278,9 +278,9 @@ describe('buildStyleInterpolator', function() { type: 'linear', }, }; - var interpolator = buildStyleInterpolator(testAnim); - var obj = {}; - var res = interpolator(obj, 1); + const interpolator = buildStyleInterpolator(testAnim); + const obj = {}; + const res = interpolator(obj, 1); expect(obj).toEqual({ transform: [{matrix: [2, 0, 0, 0, 0, 20, 0, 0, @@ -290,7 +290,7 @@ describe('buildStyleInterpolator', function() { expect(res).toBe(true); }); it('should combine scale and translate', function() { - var testAnim = { + const testAnim = { transformScale: { from: {x: 1, y: 10, z: 100}, to: {x: 5, y: 50, z: 500}, @@ -306,9 +306,9 @@ describe('buildStyleInterpolator', function() { type: 'linear', }, }; - var interpolator = buildStyleInterpolator(testAnim); - var obj = {}; - var res = interpolator(obj, 1); + const interpolator = buildStyleInterpolator(testAnim); + const obj = {}; + const res = interpolator(obj, 1); expect(obj).toEqual({ transform: [{matrix: [2, 0, 0, 0, 0, 20, 0, 0, @@ -318,7 +318,7 @@ describe('buildStyleInterpolator', function() { expect(res).toBe(true); }); it('should step', function() { - var testAnim = { + const testAnim = { opacity: { threshold: 13, from: 10, @@ -326,9 +326,9 @@ describe('buildStyleInterpolator', function() { type: 'step', }, }; - var interpolator = buildStyleInterpolator(testAnim); - var obj = {}; - var res = interpolator(obj, 0); + const interpolator = buildStyleInterpolator(testAnim); + const obj = {}; + let res = interpolator(obj, 0); expect(obj).toEqual({ opacity: 10, }); diff --git a/Libraries/Utilities/__tests__/deepFreezeAndThrowOnMutationInDev-test.js b/Libraries/Utilities/__tests__/deepFreezeAndThrowOnMutationInDev-test.js index cc307eedac0ee8..f00b974d95e9a5 100644 --- a/Libraries/Utilities/__tests__/deepFreezeAndThrowOnMutationInDev-test.js +++ b/Libraries/Utilities/__tests__/deepFreezeAndThrowOnMutationInDev-test.js @@ -6,7 +6,7 @@ * * @emails oncall+react_native */ -var deepFreezeAndThrowOnMutationInDev = require('deepFreezeAndThrowOnMutationInDev'); +const deepFreezeAndThrowOnMutationInDev = require('deepFreezeAndThrowOnMutationInDev'); describe('deepFreezeAndThrowOnMutationInDev', function() { @@ -28,7 +28,7 @@ describe('deepFreezeAndThrowOnMutationInDev', function() { it('should throw on mutation in dev with strict', () => { 'use strict'; __DEV__ = true; - var o = {key: 'oldValue'}; + const o = {key: 'oldValue'}; deepFreezeAndThrowOnMutationInDev(o); expect(() => { o.key = 'newValue'; }).toThrowError( 'You attempted to set the key `key` with the value `"newValue"` ' + @@ -39,7 +39,7 @@ describe('deepFreezeAndThrowOnMutationInDev', function() { it('should throw on mutation in dev without strict', () => { __DEV__ = true; - var o = {key: 'oldValue'}; + const o = {key: 'oldValue'}; deepFreezeAndThrowOnMutationInDev(o); expect(() => { o.key = 'newValue'; }).toThrowError( 'You attempted to set the key `key` with the value `"newValue"` ' + @@ -51,7 +51,7 @@ describe('deepFreezeAndThrowOnMutationInDev', function() { it('should throw on nested mutation in dev with strict', () => { 'use strict'; __DEV__ = true; - var o = {key1: {key2: {key3: 'oldValue'}}}; + const o = {key1: {key2: {key3: 'oldValue'}}}; deepFreezeAndThrowOnMutationInDev(o); expect(() => { o.key1.key2.key3 = 'newValue'; }).toThrowError( 'You attempted to set the key `key3` with the value `"newValue"` ' + @@ -62,7 +62,7 @@ describe('deepFreezeAndThrowOnMutationInDev', function() { it('should throw on nested mutation in dev without strict', () => { __DEV__ = true; - var o = {key1: {key2: {key3: 'oldValue'}}}; + const o = {key1: {key2: {key3: 'oldValue'}}}; deepFreezeAndThrowOnMutationInDev(o); expect(() => { o.key1.key2.key3 = 'newValue'; }).toThrowError( 'You attempted to set the key `key3` with the value `"newValue"` ' + @@ -74,7 +74,7 @@ describe('deepFreezeAndThrowOnMutationInDev', function() { it('should throw on insertion in dev with strict', () => { 'use strict'; __DEV__ = true; - var o = {oldKey: 'value'}; + const o = {oldKey: 'value'}; deepFreezeAndThrowOnMutationInDev(o); expect(() => { o.newKey = 'value'; }) .toThrowError( @@ -85,7 +85,7 @@ describe('deepFreezeAndThrowOnMutationInDev', function() { it('should not throw on insertion in dev without strict', () => { __DEV__ = true; - var o = {oldKey: 'value'}; + const o = {oldKey: 'value'}; deepFreezeAndThrowOnMutationInDev(o); expect(() => { o.newKey = 'value'; }).not.toThrow(); expect(o.newKey).toBe(undefined); @@ -94,7 +94,7 @@ describe('deepFreezeAndThrowOnMutationInDev', function() { it('should mutate and not throw on mutation in prod', () => { 'use strict'; __DEV__ = false; - var o = {key: 'oldValue'}; + const o = {key: 'oldValue'}; deepFreezeAndThrowOnMutationInDev(o); expect(() => { o.key = 'newValue'; }).not.toThrow(); expect(o.key).toBe('newValue'); @@ -104,7 +104,7 @@ describe('deepFreezeAndThrowOnMutationInDev', function() { it('should not deep freeze already frozen objects', () => { 'use strict'; __DEV__ = true; - var o = {key1: {key2: 'oldValue'}}; + const o = {key1: {key2: 'oldValue'}}; Object.freeze(o); deepFreezeAndThrowOnMutationInDev(o); expect(() => { o.key1.key2 = 'newValue'; }).not.toThrow(); @@ -113,7 +113,7 @@ describe('deepFreezeAndThrowOnMutationInDev', function() { it("shouldn't recurse infinitely", () => { __DEV__ = true; - var o = {}; + const o = {}; o.circular = o; deepFreezeAndThrowOnMutationInDev(o); }); diff --git a/Libraries/Utilities/__tests__/groupByEveryN-test.js b/Libraries/Utilities/__tests__/groupByEveryN-test.js index 5fe34833549e2f..56baa9b0ac6256 100644 --- a/Libraries/Utilities/__tests__/groupByEveryN-test.js +++ b/Libraries/Utilities/__tests__/groupByEveryN-test.js @@ -9,7 +9,7 @@ 'use strict'; describe('groupByEveryN', () => { - var groupByEveryN = require('groupByEveryN'); + const groupByEveryN = require('groupByEveryN'); it('should group by with different n', () => { expect(groupByEveryN([1, 2, 3, 4, 5, 6, 7, 8, 9], 1)) diff --git a/Libraries/Utilities/__tests__/truncate-test.js b/Libraries/Utilities/__tests__/truncate-test.js index 9c38d1e1e701c9..47b2a3ae9803f8 100644 --- a/Libraries/Utilities/__tests__/truncate-test.js +++ b/Libraries/Utilities/__tests__/truncate-test.js @@ -10,7 +10,7 @@ describe('truncate', () => { - var truncate = require('truncate'); + const truncate = require('truncate'); it('should truncate', () => { expect(truncate('Hello, world.', 5)) diff --git a/Libraries/Utilities/buildStyleInterpolator.js b/Libraries/Utilities/buildStyleInterpolator.js index a22526e45cf31e..2ffed265f1df8f 100644 --- a/Libraries/Utilities/buildStyleInterpolator.js +++ b/Libraries/Utilities/buildStyleInterpolator.js @@ -8,18 +8,18 @@ 'use strict'; -var keyOf = require('fbjs/lib/keyOf'); +const keyOf = require('fbjs/lib/keyOf'); -var X_DIM = keyOf({x: null}); -var Y_DIM = keyOf({y: null}); -var Z_DIM = keyOf({z: null}); +const X_DIM = keyOf({x: null}); +const Y_DIM = keyOf({y: null}); +const Z_DIM = keyOf({z: null}); -var InitialOperationField = { +const InitialOperationField = { transformTranslate: [0, 0, 0], transformScale: [1, 1, 1], }; -var InterpolateMatrix = { +const InterpolateMatrix = { transformScale: function(mat, x, y, z) { mat[0] = mat[0] * x; mat[1] = mat[1] * x; @@ -42,27 +42,27 @@ var InterpolateMatrix = { } }; -var computeNextValLinear = function(anim, from, to, value) { - var hasRoundRatio = 'round' in anim; - var roundRatio = anim.round; - var ratio = (value - anim.min) / (anim.max - anim.min); +const computeNextValLinear = function(anim, from, to, value) { + const hasRoundRatio = 'round' in anim; + const roundRatio = anim.round; + let ratio = (value - anim.min) / (anim.max - anim.min); if (!anim.extrapolate) { ratio = ratio > 1 ? 1 : (ratio < 0 ? 0 : ratio); } - var nextVal = from * (1 - ratio) + to * ratio; + let nextVal = from * (1 - ratio) + to * ratio; if (hasRoundRatio) { nextVal = Math.round(roundRatio * nextVal) / roundRatio; } return nextVal; }; -var computeNextValLinearScalar = function(anim, value) { +const computeNextValLinearScalar = function(anim, value) { return computeNextValLinear(anim, anim.from, anim.to, value); }; -var setNextValAndDetectChange = function(result, name, nextVal, didChange) { +const setNextValAndDetectChange = function(result, name, nextVal, didChange) { if (!didChange) { - var prevVal = result[name]; + const prevVal = result[name]; result[name] = nextVal; didChange = didChange || (nextVal !== prevVal); } else { @@ -71,7 +71,7 @@ var setNextValAndDetectChange = function(result, name, nextVal, didChange) { return didChange; }; -var initIdentity = function(mat) { +const initIdentity = function(mat) { mat[0] = 1; mat[1] = 0; mat[2] = 0; @@ -90,7 +90,7 @@ var initIdentity = function(mat) { mat[15] = 1; }; -var computeNextMatrixOperationField = function(anim, name, dim, index, value) { +const computeNextMatrixOperationField = function(anim, name, dim, index, value) { if (anim.from[dim] !== undefined && anim.to[dim] !== undefined) { return computeNextValLinear(anim, anim.from[dim], anim.to[dim], value); } else { @@ -98,33 +98,33 @@ var computeNextMatrixOperationField = function(anim, name, dim, index, value) { } }; -var computeTransform = function(anim, name, value, result, +const computeTransform = function(anim, name, value, result, didChange, didMatrix) { - var transform = result.transform !== undefined ? + const transform = result.transform !== undefined ? result.transform : (result.transform = [{ matrix: [] }]); - var mat = transform[0].matrix; - var m0 = mat[0]; - var m1 = mat[1]; - var m2 = mat[2]; - var m3 = mat[3]; - var m4 = mat[4]; - var m5 = mat[5]; - var m6 = mat[6]; - var m7 = mat[7]; - var m8 = mat[8]; - var m9 = mat[9]; - var m10 = mat[10]; - var m11 = mat[11]; - var m12 = mat[12]; - var m13 = mat[13]; - var m14 = mat[14]; - var m15 = mat[15]; + const mat = transform[0].matrix; + const m0 = mat[0]; + const m1 = mat[1]; + const m2 = mat[2]; + const m3 = mat[3]; + const m4 = mat[4]; + const m5 = mat[5]; + const m6 = mat[6]; + const m7 = mat[7]; + const m8 = mat[8]; + const m9 = mat[9]; + const m10 = mat[10]; + const m11 = mat[11]; + const m12 = mat[12]; + const m13 = mat[13]; + const m14 = mat[14]; + const m15 = mat[15]; if (!didMatrix) { initIdentity(mat); // This will be the first transform. } - var x = computeNextMatrixOperationField(anim, name, X_DIM, 0, value); - var y = computeNextMatrixOperationField(anim, name, Y_DIM, 1, value); - var z = computeNextMatrixOperationField(anim, name, Z_DIM, 2, value); + const x = computeNextMatrixOperationField(anim, name, X_DIM, 0, value); + const y = computeNextMatrixOperationField(anim, name, Y_DIM, 1, value); + const z = computeNextMatrixOperationField(anim, name, Z_DIM, 2, value); InterpolateMatrix[name](mat, x, y, z); if (!didChange) { didChange = m0 !== mat[0] || m1 !== mat[1] || @@ -144,12 +144,12 @@ var computeTransform = function(anim, name, value, result, * @return {function} Function accepting style object, that mutates that style * object and returns a boolean describing if any update was actually applied. */ -var buildStyleInterpolator = function(anims) { +const buildStyleInterpolator = function(anims) { function styleInterpolator(result, value) { - var didChange = false; - var didMatrix = false; - for (var name in anims) { - var anim = anims[name]; + let didChange = false; + let didMatrix = false; + for (const name in anims) { + const anim = anims[name]; if (anim.type === 'linear') { if (name in InterpolateMatrix) { didChange = computeTransform(anim, name, value, result, diff --git a/Libraries/Utilities/createStrictShapeTypeChecker.js b/Libraries/Utilities/createStrictShapeTypeChecker.js index 5cde7eb5315768..558119f6ae04cf 100644 --- a/Libraries/Utilities/createStrictShapeTypeChecker.js +++ b/Libraries/Utilities/createStrictShapeTypeChecker.js @@ -8,8 +8,8 @@ */ 'use strict'; -var invariant = require('fbjs/lib/invariant'); -var merge = require('merge'); +const invariant = require('fbjs/lib/invariant'); +const merge = require('merge'); function createStrictShapeTypeChecker( shapeTypes: {[key: string]: ReactPropsCheckType} @@ -25,9 +25,9 @@ function createStrictShapeTypeChecker( } return; } - var propValue = props[propName]; - var propType = typeof propValue; - var locationName = location || '(unknown)'; + const propValue = props[propName]; + const propType = typeof propValue; + const locationName = location || '(unknown)'; if (propType !== 'object') { invariant( false, @@ -37,9 +37,9 @@ function createStrictShapeTypeChecker( } // We need to check all keys in case some are required but missing from // props. - var allKeys = merge(props[propName], shapeTypes); - for (var key in allKeys) { - var checker = shapeTypes[key]; + const allKeys = merge(props[propName], shapeTypes); + for (const key in allKeys) { + const checker = shapeTypes[key]; if (!checker) { invariant( false, @@ -48,7 +48,7 @@ function createStrictShapeTypeChecker( '\nValid keys: ' + JSON.stringify(Object.keys(shapeTypes), null, ' ') ); } - var error = checker(propValue, key, componentName, location, ...rest); + const error = checker(propValue, key, componentName, location, ...rest); if (error) { invariant( false, diff --git a/Libraries/Utilities/deepFreezeAndThrowOnMutationInDev.js b/Libraries/Utilities/deepFreezeAndThrowOnMutationInDev.js index 041691a67f7abe..9e21a2aae63c6f 100644 --- a/Libraries/Utilities/deepFreezeAndThrowOnMutationInDev.js +++ b/Libraries/Utilities/deepFreezeAndThrowOnMutationInDev.js @@ -35,7 +35,7 @@ function deepFreezeAndThrowOnMutationInDev(object: T): T { return object; } - var keys = Object.keys(object); + const keys = Object.keys(object); for (var i = 0; i < keys.length; i++) { var key = keys[i]; diff --git a/Libraries/Utilities/differ/__tests__/deepDiffer-test.js b/Libraries/Utilities/differ/__tests__/deepDiffer-test.js index 4fb31ee05fb39b..cb39370dc5c4d0 100644 --- a/Libraries/Utilities/differ/__tests__/deepDiffer-test.js +++ b/Libraries/Utilities/differ/__tests__/deepDiffer-test.js @@ -8,7 +8,7 @@ */ 'use strict'; -var deepDiffer = require('deepDiffer'); +const deepDiffer = require('deepDiffer'); describe('deepDiffer', function() { it('should diff primitives of the same type', () => { @@ -95,7 +95,7 @@ describe('deepDiffer', function() { expect(deepDiffer(['a', 'b'], {length: 2, 0: 'a', 1: 'b'})).toBe(true); }); it('should diff same object', () => { - var obj = [1,[2,3]]; + const obj = [1,[2,3]]; expect(deepDiffer(obj, obj)).toBe(false); }); it('should respect maxDepth arg', () => { diff --git a/Libraries/Utilities/differ/deepDiffer.js b/Libraries/Utilities/differ/deepDiffer.js index f3f826fe91169a..94dc0cd71dc20f 100644 --- a/Libraries/Utilities/differ/deepDiffer.js +++ b/Libraries/Utilities/differ/deepDiffer.js @@ -11,7 +11,7 @@ /* * @returns {bool} true if different, false if equal */ -var deepDiffer = function(one: any, two: any, maxDepth: number = -1): bool { +const deepDiffer = function(one: any, two: any, maxDepth: number = -1): bool { if (maxDepth === 0) { return true; } @@ -37,22 +37,22 @@ var deepDiffer = function(one: any, two: any, maxDepth: number = -1): bool { } if (Array.isArray(one)) { // We know two is also an array because the constructors are equal - var len = one.length; + const len = one.length; if (two.length !== len) { return true; } - for (var ii = 0; ii < len; ii++) { + for (let ii = 0; ii < len; ii++) { if (deepDiffer(one[ii], two[ii], maxDepth - 1)) { return true; } } } else { - for (var key in one) { + for (const key in one) { if (deepDiffer(one[key], two[key], maxDepth - 1)) { return true; } } - for (var twoKey in two) { + for (const twoKey in two) { // The only case we haven't checked yet is keys that are in two but aren't // in one, which means they are different. if (one[twoKey] === undefined && two[twoKey] !== undefined) { diff --git a/Libraries/Utilities/differ/insetsDiffer.js b/Libraries/Utilities/differ/insetsDiffer.js index 7214ab6d763895..c86f6d17b4e1ee 100644 --- a/Libraries/Utilities/differ/insetsDiffer.js +++ b/Libraries/Utilities/differ/insetsDiffer.js @@ -15,14 +15,14 @@ type Inset = { bottom: ?number, } -var dummyInsets = { +const dummyInsets = { top: undefined, left: undefined, right: undefined, bottom: undefined, }; -var insetsDiffer = function( +const insetsDiffer = function( one: ?Inset, two: ?Inset ): bool { diff --git a/Libraries/Utilities/differ/matricesDiffer.js b/Libraries/Utilities/differ/matricesDiffer.js index 177a7a110ac43a..883081fa0ab832 100644 --- a/Libraries/Utilities/differ/matricesDiffer.js +++ b/Libraries/Utilities/differ/matricesDiffer.js @@ -16,7 +16,7 @@ * @param {MatrixMath.Matrix} two Second matrix. * @return {boolean} Whether or not the two matrices differ. */ -var matricesDiffer = function(one, two) { +const matricesDiffer = function(one, two) { if (one === two) { return false; } diff --git a/Libraries/Utilities/differ/pointsDiffer.js b/Libraries/Utilities/differ/pointsDiffer.js index e019124e76d1d8..b9d239c7907f13 100644 --- a/Libraries/Utilities/differ/pointsDiffer.js +++ b/Libraries/Utilities/differ/pointsDiffer.js @@ -13,9 +13,9 @@ type Point = { y: ?number, } -var dummyPoint = {x: undefined, y: undefined}; +const dummyPoint = {x: undefined, y: undefined}; -var pointsDiffer = function(one: ?Point, two: ?Point): bool { +const pointsDiffer = function(one: ?Point, two: ?Point): bool { one = one || dummyPoint; two = two || dummyPoint; return one !== two && ( diff --git a/Libraries/Utilities/differ/sizesDiffer.js b/Libraries/Utilities/differ/sizesDiffer.js index c4e104a1439b79..ad2939cc71ef1e 100644 --- a/Libraries/Utilities/differ/sizesDiffer.js +++ b/Libraries/Utilities/differ/sizesDiffer.js @@ -7,9 +7,9 @@ */ 'use strict'; -var dummySize = {width: undefined, height: undefined}; +const dummySize = {width: undefined, height: undefined}; -var sizesDiffer = function(one, two) { +const sizesDiffer = function(one, two) { one = one || dummySize; two = two || dummySize; return one !== two && ( diff --git a/Libraries/Utilities/dismissKeyboard.js b/Libraries/Utilities/dismissKeyboard.js index a5b9e2f00dd987..64f7368a35dacb 100644 --- a/Libraries/Utilities/dismissKeyboard.js +++ b/Libraries/Utilities/dismissKeyboard.js @@ -9,7 +9,7 @@ */ 'use strict'; -var TextInputState = require('TextInputState'); +const TextInputState = require('TextInputState'); function dismissKeyboard() { TextInputState.blurTextInput(TextInputState.currentlyFocusedField()); diff --git a/Libraries/Utilities/groupByEveryN.js b/Libraries/Utilities/groupByEveryN.js index 2cda280be6f15f..bdf13b226936c3 100644 --- a/Libraries/Utilities/groupByEveryN.js +++ b/Libraries/Utilities/groupByEveryN.js @@ -25,10 +25,10 @@ 'use strict'; function groupByEveryN(array: Array, n: number): Array> { - var result = []; - var temp = []; + const result = []; + let temp = []; - for (var i = 0; i < array.length; ++i) { + for (let i = 0; i < array.length; ++i) { if (i > 0 && i % n === 0) { result.push(temp); temp = []; diff --git a/Libraries/Utilities/logError.js b/Libraries/Utilities/logError.js index 5482448ae20b54..e79b340563cec4 100644 --- a/Libraries/Utilities/logError.js +++ b/Libraries/Utilities/logError.js @@ -13,9 +13,9 @@ * `console.error` as a failure callback - it's not properly bound. If passes an * `Error` object, it will print the message and stack. */ -var logError = function(...args: $ReadOnlyArray) { +const logError = function(...args: $ReadOnlyArray) { if (args.length === 1 && args[0] instanceof Error) { - var err = args[0]; + const err = args[0]; console.error('Error: "' + err.message + '". Stack:\n' + err.stack); } else { console.error.apply(console, args); diff --git a/Libraries/Utilities/mergeIntoFast.js b/Libraries/Utilities/mergeIntoFast.js index e657de7c3d9dbb..cfbc879239876c 100644 --- a/Libraries/Utilities/mergeIntoFast.js +++ b/Libraries/Utilities/mergeIntoFast.js @@ -15,8 +15,8 @@ * @param {object} one Object to assign to. * @param {object} two Object to assign from. */ -var mergeIntoFast = function(one: Object, two: Object): void { - for (var keyTwo in two) { +const mergeIntoFast = function(one: Object, two: Object): void { + for (const keyTwo in two) { one[keyTwo] = two[keyTwo]; } }; diff --git a/Libraries/Utilities/stringifySafe.js b/Libraries/Utilities/stringifySafe.js index f8f7ab8f0e4013..4536b8f668becf 100644 --- a/Libraries/Utilities/stringifySafe.js +++ b/Libraries/Utilities/stringifySafe.js @@ -13,8 +13,8 @@ * (e.g. from circular objects) and always returns a string and never throws. */ function stringifySafe(arg: any): string { - var ret; - var type = typeof arg; + let ret; + const type = typeof arg; if (arg === undefined) { ret = 'undefined'; } else if (arg === null) { diff --git a/Libraries/Utilities/truncate.js b/Libraries/Utilities/truncate.js index 5b89e8ff200741..017a524912c016 100644 --- a/Libraries/Utilities/truncate.js +++ b/Libraries/Utilities/truncate.js @@ -30,12 +30,12 @@ const truncate = function( if (str && str.length && str.length - options.minDelta + options.elipsis.length >= maxChars) { // If the slice is happening in the middle of a wide char, add one more char - var extraChar = str.charCodeAt(maxChars - options.elipsis.length) > 255 + const extraChar = str.charCodeAt(maxChars - options.elipsis.length) > 255 ? 1 : 0; str = str.slice(0, maxChars - options.elipsis.length + 1 + extraChar); if (options.breakOnWords) { - var ii = Math.max(str.lastIndexOf(' '), str.lastIndexOf('\n')); + const ii = Math.max(str.lastIndexOf(' '), str.lastIndexOf('\n')); str = str.slice(0, ii); } str = str.trim() + options.elipsis; diff --git a/Libraries/Vibration/Vibration.js b/Libraries/Vibration/Vibration.js index c0ee75203fcd57..182ca26d9c50e9 100644 --- a/Libraries/Vibration/Vibration.js +++ b/Libraries/Vibration/Vibration.js @@ -9,8 +9,8 @@ */ 'use strict'; -var RCTVibration = require('NativeModules').Vibration; -var Platform = require('Platform'); +const RCTVibration = require('NativeModules').Vibration; +const Platform = require('Platform'); /** * Vibration API @@ -18,8 +18,8 @@ var Platform = require('Platform'); * See https://facebook.github.io/react-native/docs/vibration.html */ -var _vibrating: boolean = false; -var _id: number = 0; // _id is necessary to prevent race condition. +let _vibrating: boolean = false; +let _id: number = 0; // _id is necessary to prevent race condition. function vibrateByPattern(pattern: Array, repeat: boolean = false) { if (_vibrating) { @@ -53,7 +53,7 @@ function vibrateScheduler(id, pattern: Array, repeat: boolean, nextIndex setTimeout(() => vibrateScheduler(id, pattern, repeat, nextIndex + 1), pattern[nextIndex]); } -var Vibration = { +const Vibration = { /** * Trigger a vibration with specified `pattern`. * diff --git a/Libraries/Vibration/VibrationIOS.android.js b/Libraries/Vibration/VibrationIOS.android.js index b57279a73844df..93a1aab1af8369 100644 --- a/Libraries/Vibration/VibrationIOS.android.js +++ b/Libraries/Vibration/VibrationIOS.android.js @@ -9,9 +9,9 @@ */ 'use strict'; -var warning = require('fbjs/lib/warning'); +const warning = require('fbjs/lib/warning'); -var VibrationIOS = { +const VibrationIOS = { vibrate: function() { warning('VibrationIOS is not supported on this platform!'); } diff --git a/Libraries/Vibration/VibrationIOS.ios.js b/Libraries/Vibration/VibrationIOS.ios.js index 5ce5f4019bb5a6..29cc3eee02a47d 100644 --- a/Libraries/Vibration/VibrationIOS.ios.js +++ b/Libraries/Vibration/VibrationIOS.ios.js @@ -8,9 +8,9 @@ */ 'use strict'; -var RCTVibration = require('NativeModules').Vibration; +const RCTVibration = require('NativeModules').Vibration; -var invariant = require('fbjs/lib/invariant'); +const invariant = require('fbjs/lib/invariant'); /** * NOTE: `VibrationIOS` is being deprecated. Use `Vibration` instead. @@ -25,7 +25,7 @@ var invariant = require('fbjs/lib/invariant'); * Vibration patterns are currently unsupported. */ -var VibrationIOS = { +const VibrationIOS = { /** * @deprecated */ diff --git a/Libraries/WebSocket/__tests__/WebSocket-test.js b/Libraries/WebSocket/__tests__/WebSocket-test.js index c6e04bf0a6d998..a263caf3ee224c 100644 --- a/Libraries/WebSocket/__tests__/WebSocket-test.js +++ b/Libraries/WebSocket/__tests__/WebSocket-test.js @@ -15,7 +15,7 @@ jest.setMock('NativeModules', { } }); -var WebSocket = require('WebSocket'); +const WebSocket = require('WebSocket'); describe('WebSocket', function() { diff --git a/Libraries/vendor/core/Map.js b/Libraries/vendor/core/Map.js index 115e2f855eafab..575a6b1d57c063 100644 --- a/Libraries/vendor/core/Map.js +++ b/Libraries/vendor/core/Map.js @@ -12,10 +12,10 @@ 'use strict'; -var _shouldPolyfillES6Collection = require('_shouldPolyfillES6Collection'); -var guid = require('guid'); -var isNode = require('fbjs/lib/isNode'); -var toIterator = require('toIterator'); +const _shouldPolyfillES6Collection = require('_shouldPolyfillES6Collection'); +const guid = require('guid'); +const isNode = require('fbjs/lib/isNode'); +const toIterator = require('toIterator'); module.exports = (function(global, undefined) { // Since our implementation is spec-compliant for the most part we can safely @@ -81,23 +81,23 @@ module.exports = (function(global, undefined) { */ // Kinds of map iterations 23.1.5.3 - var KIND_KEY = 'key'; - var KIND_VALUE = 'value'; - var KIND_KEY_VALUE = 'key+value'; + 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. - var KEY_PREFIX = '$map_'; + 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. - var SECRET_SIZE_PROP; + let SECRET_SIZE_PROP; if (__DEV__) { SECRET_SIZE_PROP = '$size' + guid(); } // In oldIE we use the DOM Node `uniqueID` property to get create the hash. - var OLD_IE_HASH_PREFIX = 'IE_HASH_'; + const OLD_IE_HASH_PREFIX = 'IE_HASH_'; class Map { @@ -118,8 +118,8 @@ module.exports = (function(global, undefined) { initMap(this); if (iterable != null) { - var it = toIterator(iterable); - var next; + 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.'); @@ -145,7 +145,7 @@ module.exports = (function(global, undefined) { * @return {boolean} */ has(key) { - var index = getIndex(this, key); + const index = getIndex(this, key); return !!(index != null && this._mapData[index]); } @@ -158,7 +158,7 @@ module.exports = (function(global, undefined) { * @return {map} */ set(key, value) { - var index = getIndex(this, key); + let index = getIndex(this, key); if (index != null && this._mapData[index]) { this._mapData[index][1] = value; @@ -186,7 +186,7 @@ module.exports = (function(global, undefined) { * @return {*} */ get(key) { - var index = getIndex(this, key); + const index = getIndex(this, key); if (index == null) { return undefined; } else { @@ -203,7 +203,7 @@ module.exports = (function(global, undefined) { * @return {boolean} Whether the key was found and deleted. */ delete(key) { - var index = getIndex(this, key); + const index = getIndex(this, key); if (index != null && this._mapData[index]) { setIndex(this, key, undefined); this._mapData[index] = undefined; @@ -263,14 +263,14 @@ module.exports = (function(global, undefined) { throw new TypeError('Callback must be callable.'); } - var boundCallback = callback.bind(thisArg || undefined); - var mapData = this._mapData; + 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 (var i = 0; i < mapData.length; i++) { - var entry = mapData[i]; + for (let i = 0; i < mapData.length; i++) { + const entry = mapData[i]; if (entry != null) { boundCallback(entry[1], entry[0], this); } @@ -316,18 +316,18 @@ module.exports = (function(global, undefined) { throw new TypeError('Expected to be called on a MapIterator.'); } - var map = this._map; - var index = this._nextIndex; - var kind = this._kind; + const map = this._map; + let index = this._nextIndex; + const kind = this._kind; if (map == null) { return createIterResultObject(undefined, true); } - var entries = map._mapData; + const entries = map._mapData; while (index < entries.length) { - var record = entries[index]; + const record = entries[index]; index += 1; this._nextIndex = index; @@ -369,10 +369,10 @@ module.exports = (function(global, undefined) { */ function getIndex(map, key) { if (isObject(key)) { - var hash = getHash(key); + const hash = getHash(key); return map._objectIndex[hash]; } else { - var prefixedKey = KEY_PREFIX + key; + const prefixedKey = KEY_PREFIX + key; if (typeof key === 'string') { return map._stringIndex[prefixedKey]; } else { @@ -388,17 +388,17 @@ module.exports = (function(global, undefined) { * @param {*} key */ function setIndex(map, key, index) { - var shouldDelete = index == null; + const shouldDelete = index == null; if (isObject(key)) { - var hash = getHash(key); + const hash = getHash(key); if (shouldDelete) { delete map._objectIndex[hash]; } else { map._objectIndex[hash] = index; } } else { - var prefixedKey = KEY_PREFIX + key; + const prefixedKey = KEY_PREFIX + key; if (typeof key === 'string') { if (shouldDelete) { delete map._stringIndex[prefixedKey]; @@ -505,7 +505,7 @@ module.exports = (function(global, undefined) { } // Are we in a legit ES5 environment. Spoiler alert: that doesn't include IE8. - var isES5 = (function() { + const isES5 = (function() { try { Object.defineProperty({}, 'x', {}); return true; @@ -537,7 +537,7 @@ module.exports = (function(global, undefined) { * @return {?string} */ function getIENodeHash(node) { - var uniqueID; + let uniqueID; switch (node.nodeType) { case 1: // Element uniqueID = node.uniqueID; @@ -556,10 +556,10 @@ module.exports = (function(global, undefined) { } } - var getHash = (function() { - var propIsEnumerable = Object.prototype.propertyIsEnumerable; - var hashProperty = guid(); - var hashCounter = 0; + const getHash = (function() { + const propIsEnumerable = Object.prototype.propertyIsEnumerable; + const hashProperty = guid(); + let hashCounter = 0; /** * Get the "hash" associated with an object. diff --git a/Libraries/vendor/core/Set.js b/Libraries/vendor/core/Set.js index 16e3cecae21fb1..3ba61c26a99360 100644 --- a/Libraries/vendor/core/Set.js +++ b/Libraries/vendor/core/Set.js @@ -12,10 +12,10 @@ 'use strict'; -var Map = require('Map'); +const Map = require('Map'); -var _shouldPolyfillES6Collection = require('_shouldPolyfillES6Collection'); -var toIterator = require('toIterator'); +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 @@ -88,8 +88,8 @@ module.exports = (function(global) { initSet(this); if (iterable != null) { - var it = toIterator(iterable); - var next; + const it = toIterator(iterable); + let next; while (!(next = it.next()).done) { this.add(next.value); } @@ -129,7 +129,7 @@ module.exports = (function(global) { * @return {boolean} */ delete(value) { - var ret = this._map.delete(value); + const ret = this._map.delete(value); this.size = this._map.size; return ret; } @@ -151,9 +151,9 @@ module.exports = (function(global) { * @param {function} callback */ forEach(callback) { - var thisArg = arguments[1]; - var it = this._map.keys(); - var next; + const thisArg = arguments[1]; + const it = this._map.keys(); + let next; while (!(next = it.next()).done) { callback.call(thisArg, next.value, next.value, this); } diff --git a/Libraries/vendor/core/_shouldPolyfillES6Collection.js b/Libraries/vendor/core/_shouldPolyfillES6Collection.js index 84ed51ded55e18..576d1eb671035c 100644 --- a/Libraries/vendor/core/_shouldPolyfillES6Collection.js +++ b/Libraries/vendor/core/_shouldPolyfillES6Collection.js @@ -14,7 +14,7 @@ * that is safe to be used. */ function _shouldActuallyPolyfillES6Collection(collectionName: string): boolean { - var Collection = global[collectionName]; + const Collection = global[collectionName]; if (Collection == null) { return true; } @@ -27,7 +27,7 @@ function _shouldActuallyPolyfillES6Collection(collectionName: string): boolean { return true; } - var proto = Collection.prototype; + const proto = Collection.prototype; // These checks are adapted from es6-shim: https://fburl.com/34437854 // NOTE: `isCallableWithoutNew` and `!supportsSubclassing` are not checked diff --git a/Libraries/vendor/core/getObjectValues.js b/Libraries/vendor/core/getObjectValues.js index 398788c1e02f96..0a020af5169c18 100644 --- a/Libraries/vendor/core/getObjectValues.js +++ b/Libraries/vendor/core/getObjectValues.js @@ -18,8 +18,8 @@ * @return {array} The object's values. */ function getObjectValues(obj) { - var values = []; - for (var key in obj) { + const values = []; + for (const key in obj) { values.push(obj[key]); } return values; diff --git a/Libraries/vendor/core/isEmpty.js b/Libraries/vendor/core/isEmpty.js index 6d451729c7c8e2..c7747c980a56ae 100644 --- a/Libraries/vendor/core/isEmpty.js +++ b/Libraries/vendor/core/isEmpty.js @@ -14,7 +14,7 @@ function isEmpty(obj) { if (Array.isArray(obj)) { return obj.length === 0; } else if (typeof obj === 'object') { - for (var i in obj) { + for (const i in obj) { return false; } return true; diff --git a/Libraries/vendor/core/mergeHelpers.js b/Libraries/vendor/core/mergeHelpers.js index e24559ddb50c2f..10072ed46335bb 100644 --- a/Libraries/vendor/core/mergeHelpers.js +++ b/Libraries/vendor/core/mergeHelpers.js @@ -10,13 +10,13 @@ 'use strict'; -var invariant = require('fbjs/lib/invariant'); +const invariant = require('fbjs/lib/invariant'); /** * Maximum number of levels to traverse. Will catch circular structures. * @const */ -var MAX_MERGE_DEPTH = 36; +const MAX_MERGE_DEPTH = 36; /** * We won't worry about edge cases like new String('x') or new Boolean(true). @@ -24,11 +24,11 @@ var MAX_MERGE_DEPTH = 36; * @param {*} o The item/object/value to test. * @return {boolean} true iff the argument is a terminal. */ -var isTerminal = function(o) { +const isTerminal = function(o) { return typeof o !== 'object' || o instanceof Date || o === null; }; -var mergeHelpers = { +const mergeHelpers = { MAX_MERGE_DEPTH: MAX_MERGE_DEPTH, diff --git a/Libraries/vendor/core/toIterator.js b/Libraries/vendor/core/toIterator.js index cabd1e2b066786..728b68c7bda97d 100644 --- a/Libraries/vendor/core/toIterator.js +++ b/Libraries/vendor/core/toIterator.js @@ -17,15 +17,15 @@ * Constants */ -var KIND_KEY = 'key'; -var KIND_VALUE = 'value'; -var KIND_KEY_VAL = 'key+value'; +const KIND_KEY = 'key'; +const KIND_VALUE = 'value'; +const KIND_KEY_VAL = 'key+value'; /*global Symbol: true*/ -var ITERATOR_SYMBOL = (typeof Symbol === 'function') +const ITERATOR_SYMBOL = (typeof Symbol === 'function') ? Symbol.iterator : '@@iterator'; -var toIterator = (function() { +const toIterator = (function() { if (!(Array.prototype[ITERATOR_SYMBOL] && String.prototype[ITERATOR_SYMBOL])) { // IIFE to avoid creating classes for no reason because of hoisting. @@ -51,10 +51,10 @@ var toIterator = (function() { return createIterResultObject(undefined, true); } - var array = this._iteratedObject; - var len = this._iteratedObject.length; - var index = this._nextIndex; - var kind = this._kind; + const array = this._iteratedObject; + const len = this._iteratedObject.length; + const index = this._nextIndex; + const kind = this._kind; if (index >= len) { this._iteratedObject = undefined; @@ -98,22 +98,22 @@ var toIterator = (function() { return createIterResultObject(undefined, true); } - var index = this._nextIndex; - var s = this._iteratedString; - var len = s.length; + const index = this._nextIndex; + const s = this._iteratedString; + const len = s.length; if (index >= len) { this._iteratedString = undefined; return createIterResultObject(undefined, true); } - var ret; - var first = s.charCodeAt(index); + let ret; + const first = s.charCodeAt(index); if (first < 0xD800 || first > 0xDBFF || index + 1 === len) { ret = s[index]; } else { - var second = s.charCodeAt(index + 1); + const second = s.charCodeAt(index + 1); if (second < 0xDC00 || second > 0xDFFF) { ret = s[index]; } else { diff --git a/Libraries/vendor/document/selection/DocumentSelectionState.js b/Libraries/vendor/document/selection/DocumentSelectionState.js index 28b93e34390609..350732776f722d 100644 --- a/Libraries/vendor/document/selection/DocumentSelectionState.js +++ b/Libraries/vendor/document/selection/DocumentSelectionState.js @@ -9,7 +9,7 @@ 'use strict'; -var mixInEventEmitter = require('mixInEventEmitter'); +const mixInEventEmitter = require('mixInEventEmitter'); /** * DocumentSelectionState is responsible for maintaining selection information From 86b6f5d39ecc571260dee891aa422f8d3cc807e8 Mon Sep 17 00:00:00 2001 From: Eli White Date: Thu, 10 May 2018 15:44:53 -0700 Subject: [PATCH 0501/1109] Add Prettier to some files Reviewed By: sahrens Differential Revision: D7958196 fbshipit-source-id: 05a04380a4a1f3abd4cc3a9034fc70deaa4a444b --- babel-preset/configs/hmr.js | 22 +++++++++++++--------- babel-preset/configs/main.js | 4 +++- flow-github/metro.js | 1 + flow/Map.js | 12 +++++++++--- flow/Position.js | 7 ++++--- flow/Promise.js | 27 ++++++++++++++------------- flow/Set.js | 8 ++++++-- flow/console.js | 19 ++++++++++--------- flow/fbjs.js | 8 +++++++- flow/prop-types.js | 7 ++++--- 10 files changed, 71 insertions(+), 44 deletions(-) diff --git a/babel-preset/configs/hmr.js b/babel-preset/configs/hmr.js index e2b4a0f3dec0e0..05b305c09e6cc8 100644 --- a/babel-preset/configs/hmr.js +++ b/babel-preset/configs/hmr.js @@ -3,6 +3,8 @@ * * 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'; @@ -13,8 +15,8 @@ var transformPath = require.resolve(hmrTransform); module.exports = function(options, filename) { var transform = filename - ? './' + path.relative(path.dirname(filename), transformPath) // packager can't handle absolute paths - : hmrTransform; + ? './' + path.relative(path.dirname(filename), transformPath) // packager can't handle absolute paths + : hmrTransform; // Fix the module path to use '/' on Windows. if (path.sep === '\\') { @@ -26,13 +28,15 @@ module.exports = function(options, filename) { [ require('metro-babel7-plugin-react-transform'), { - transforms: [{ - transform: transform, - imports: ['react'], - locals: ['module'], - }] + transforms: [ + { + transform: transform, + imports: ['react'], + locals: ['module'], + }, + ], }, - ] - ] + ], + ], }; }; diff --git a/babel-preset/configs/main.js b/babel-preset/configs/main.js index e6aeeec39865ba..526d6f7f909ddd 100644 --- a/babel-preset/configs/main.js +++ b/babel-preset/configs/main.js @@ -3,6 +3,8 @@ * * 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'; @@ -31,7 +33,7 @@ const defaultPlugins = [ require('@babel/plugin-transform-modules-commonjs'), { strict: false, - strictMode : false, // prevent "use strict" injections + strictMode: false, // prevent "use strict" injections allowTopLevelThis: true, // dont rewrite global `this` -> `undefined` }, ], diff --git a/flow-github/metro.js b/flow-github/metro.js index ff06b427774628..db5dbdc28c7a5e 100644 --- a/flow-github/metro.js +++ b/flow-github/metro.js @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. * * @flow + * @format */ declare module 'metro' { diff --git a/flow/Map.js b/flow/Map.js index f2021affd67a63..0723ea4266ec62 100644 --- a/flow/Map.js +++ b/flow/Map.js @@ -5,23 +5,29 @@ * LICENSE file in the root directory of this source tree. * * @flow + * @format */ // These annotations are copy/pasted from the built-in Flow definitions for // Native Map. -declare module "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; + 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; + forEach( + callbackfn: (value: V, index: K, map: MapPolyfill) => mixed, + thisArg?: any, + ): void; get(key: K): V | void; has(key: K): boolean; keys(): Iterator; diff --git a/flow/Position.js b/flow/Position.js index 58e3330b0b926a..5bd2717c0e742a 100644 --- a/flow/Position.js +++ b/flow/Position.js @@ -6,10 +6,11 @@ * * @flow * @nolint + * @format */ declare class Position { - coords: Coordinates, - timestamp: number, - mocked: boolean, + coords: Coordinates; + timestamp: number; + mocked: boolean; } diff --git a/flow/Promise.js b/flow/Promise.js index d69944eb4b47e2..64350cabc0b5c5 100644 --- a/flow/Promise.js +++ b/flow/Promise.js @@ -5,41 +5,42 @@ * LICENSE file in the root directory of this source tree. * * @flow + * @format */ // These annotations are copy/pasted from the built-in Flow definitions for // Native Promises with some non-standard APIs added in declare class Promise<+R> { - constructor(callback: ( - resolve: (result?: Promise | R) => void, - reject: (error?: any) => void - ) => mixed): void; + constructor( + callback: ( + resolve: (result?: Promise | R) => void, + reject: (error?: any) => void, + ) => mixed, + ): void; then( onFulfill?: ?(value: R) => Promise | ?U, - onReject?: ?(error: any) => Promise | ?U + onReject?: ?(error: any) => Promise | ?U, ): Promise; - catch( - onReject?: (error: any) => ?Promise | U - ): Promise; + catch(onReject?: (error: any) => ?Promise | U): Promise; static resolve(object?: Promise | T): Promise; static reject(error?: any): Promise; - static all>(promises: T): Promise<$TupleMap>; + static all>( + promises: T, + ): Promise<$TupleMap>; static race(promises: Array>): Promise; // Non-standard APIs // See https://github.com/facebook/fbjs/blob/master/packages/fbjs/src/__forks__/Promise.native.js#L21 - finally( - onFinally?: ?(value: any) => Promise | U - ): Promise; + finally(onFinally?: ?(value: any) => Promise | U): Promise; done( onFulfill?: ?(value: R) => mixed, - onReject?: ?(error: any) => mixed + onReject?: ?(error: any) => mixed, ): void; static cast(object?: T): Promise; diff --git a/flow/Set.js b/flow/Set.js index 54b997a68a6f44..ea3b1533b830b6 100644 --- a/flow/Set.js +++ b/flow/Set.js @@ -6,12 +6,13 @@ * * @flow * @nolint + * @format */ // These annotations are copy/pasted from the built-in Flow definitions for // Native Set. -declare module "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 { @@ -21,7 +22,10 @@ declare module "Set" { clear(): void; delete(value: T): boolean; entries(): Iterator<[T, T]>; - forEach(callbackfn: (value: T, index: T, set: SetPolyfill) => mixed, thisArg?: any): void; + forEach( + callbackfn: (value: T, index: T, set: SetPolyfill) => mixed, + thisArg?: any, + ): void; has(value: T): boolean; keys(): Iterator; size: number; diff --git a/flow/console.js b/flow/console.js index 4e57ba953715c3..a5d0d31bf36742 100644 --- a/flow/console.js +++ b/flow/console.js @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. * * @flow + * @format */ declare module 'console' { @@ -22,17 +23,17 @@ declare module 'console' { declare function warn(...data: any): void; declare class Console { constructor(stdout: stream$Writable, stdin?: stream$Writable): void; - assert(value: any, ...message: any): void, + assert(value: any, ...message: any): void; dir( obj: Object, options: {showHidden: boolean, depth: number, colors: boolean}, - ): void, - error(...data: any): void, - info(...data: any): void, - log(...data: any): void, - time(label: any): void, - timeEnd(label: any): void, - trace(first: any, ...rest: any): void, - warn(...data: any): void, + ): void; + error(...data: any): void; + info(...data: any): void; + log(...data: any): void; + time(label: any): void; + timeEnd(label: any): void; + trace(first: any, ...rest: any): void; + warn(...data: any): void; } } diff --git a/flow/fbjs.js b/flow/fbjs.js index f7b41b5a6a3ad8..9106e436da85d8 100644 --- a/flow/fbjs.js +++ b/flow/fbjs.js @@ -3,10 +3,16 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. + * + * @format */ declare module 'fbjs/lib/invariant' { - declare module.exports: (condition: any, message: string, ...args: Array) => void; + declare module.exports: ( + condition: any, + message: string, + ...args: Array + ) => void; } declare module 'fbjs/lib/nullthrows' { diff --git a/flow/prop-types.js b/flow/prop-types.js index c79dab62ba9345..be239f5bdfb385 100644 --- a/flow/prop-types.js +++ b/flow/prop-types.js @@ -6,6 +6,7 @@ * * @flow * @nolint + * @format */ // TODO (bvaughn) Remove this file once flowtype/flow-typed/pull/773 is merged @@ -14,7 +15,7 @@ type $npm$propTypes$ReactPropsCheckType = ( props: any, propName: string, componentName: string, - href?: string + href?: string, ) => ?Error; declare module 'prop-types' { @@ -39,6 +40,6 @@ declare module 'prop-types' { values: V, location: string, componentName: string, - getStack: ?(() => ?string) - ) : void; + getStack: ?() => ?string, + ): void; } From dca21c8f234803a32a74a2080b7bc9c8493e7c45 Mon Sep 17 00:00:00 2001 From: Eli White Date: Thu, 10 May 2018 15:44:55 -0700 Subject: [PATCH 0502/1109] Prettier IntegrationTests Reviewed By: sahrens Differential Revision: D7958195 fbshipit-source-id: 253c0eec593228e7b6bc66606584877161c6bfc2 --- IntegrationTests/AccessibilityManagerTest.js | 34 +++---- IntegrationTests/AppEventsTest.js | 19 ++-- IntegrationTests/AsyncStorageTest.js | 98 ++++++++++--------- IntegrationTests/ImageCachePolicyTest.js | 70 +++++++------ IntegrationTests/ImageSnapshotTest.js | 14 +-- .../IntegrationTestHarnessTest.js | 25 ++--- IntegrationTests/IntegrationTestsApp.js | 14 +-- IntegrationTests/LayoutEventsTest.js | 37 +++---- IntegrationTests/LoggingTestModule.js | 11 +-- IntegrationTests/PromiseTest.js | 32 +++--- IntegrationTests/PropertiesUpdateTest.js | 13 ++- .../RCTRootViewIntegrationTestApp.js | 21 ++-- .../ReactContentSizeUpdateTest.js | 28 +++--- IntegrationTests/SimpleSnapshotTest.js | 11 +-- IntegrationTests/SizeFlexibilityUpdateTest.js | 36 ++++--- IntegrationTests/SyncMethodTest.js | 14 +-- IntegrationTests/TimersTest.js | 44 +++++---- IntegrationTests/WebSocketTest.js | 63 ++++++------ IntegrationTests/WebViewTest.js | 52 ++++++---- 19 files changed, 342 insertions(+), 294 deletions(-) diff --git a/IntegrationTests/AccessibilityManagerTest.js b/IntegrationTests/AccessibilityManagerTest.js index 4287094d375905..41710be91e14c0 100644 --- a/IntegrationTests/AccessibilityManagerTest.js +++ b/IntegrationTests/AccessibilityManagerTest.js @@ -4,35 +4,33 @@ * 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 { View } = ReactNative; +const {View} = ReactNative; const RCTDeviceEventEmitter = require('RCTDeviceEventEmitter'); -const { - TestModule, - AccessibilityManager, -} = ReactNative.NativeModules; - +const {TestModule, AccessibilityManager} = ReactNative.NativeModules; class AccessibilityManagerTest extends React.Component<{}> { componentDidMount() { AccessibilityManager.setAccessibilityContentSizeMultipliers({ - 'extraSmall': 1.0, - 'small': 2.0, - 'medium': 3.0, - 'large': 4.0, - 'extraLarge': 5.0, - 'extraExtraLarge': 6.0, - 'extraExtraExtraLarge': 7.0, - 'accessibilityMedium': 8.0, - 'accessibilityLarge': 9.0, - 'accessibilityExtraLarge': 10.0, - 'accessibilityExtraExtraLarge': 11.0, - 'accessibilityExtraExtraExtraLarge': 12.0, + extraSmall: 1.0, + small: 2.0, + medium: 3.0, + large: 4.0, + extraLarge: 5.0, + extraExtraLarge: 6.0, + extraExtraExtraLarge: 7.0, + accessibilityMedium: 8.0, + accessibilityLarge: 9.0, + accessibilityExtraLarge: 10.0, + accessibilityExtraExtraLarge: 11.0, + accessibilityExtraExtraExtraLarge: 12.0, }); RCTDeviceEventEmitter.addListener('didUpdateDimensions', update => { TestModule.markTestPassed(update.window.fontScale === 4.0); diff --git a/IntegrationTests/AppEventsTest.js b/IntegrationTests/AppEventsTest.js index af04819b38fd67..9df430fea983ad 100644 --- a/IntegrationTests/AppEventsTest.js +++ b/IntegrationTests/AppEventsTest.js @@ -4,25 +4,22 @@ * 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'; var React = require('react'); var ReactNative = require('react-native'); -var { - NativeAppEventEmitter, - StyleSheet, - Text, - View, -} = ReactNative; -var { TestModule } = ReactNative.NativeModules; +var {NativeAppEventEmitter, StyleSheet, Text, View} = ReactNative; +var {TestModule} = ReactNative.NativeModules; var deepDiffer = require('deepDiffer'); var TEST_PAYLOAD = {foo: 'bar'}; -type AppEvent = { data: Object, ts: number, }; +type AppEvent = {data: Object, ts: number}; type State = { sent: 'none' | AppEvent, received: 'none' | AppEvent, @@ -43,7 +40,7 @@ class AppEventsTest extends React.Component<{}, State> { if (deepDiffer(event.data, TEST_PAYLOAD)) { throw new Error('Received wrong event: ' + JSON.stringify(event)); } - var elapsed = (Date.now() - event.ts) + 'ms'; + var elapsed = Date.now() - event.ts + 'ms'; this.setState({received: event, elapsed}, () => { TestModule.markTestCompleted(); }); @@ -52,9 +49,7 @@ class AppEventsTest extends React.Component<{}, State> { render() { return ( - - {JSON.stringify(this.state, null, ' ')} - + {JSON.stringify(this.state, null, ' ')} ); } diff --git a/IntegrationTests/AsyncStorageTest.js b/IntegrationTests/AsyncStorageTest.js index 2d951dab3984c5..9245854e2e0108 100644 --- a/IntegrationTests/AsyncStorageTest.js +++ b/IntegrationTests/AsyncStorageTest.js @@ -4,18 +4,16 @@ * 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'; var React = require('react'); var ReactNative = require('react-native'); -var { - AsyncStorage, - Text, - View, -} = ReactNative; -var { TestModule } = ReactNative.NativeModules; +var {AsyncStorage, Text, View} = ReactNative; +var {TestModule} = ReactNative.NativeModules; var deepDiffer = require('deepDiffer'); @@ -26,31 +24,34 @@ var VAL_1 = 'val_1'; var KEY_2 = 'key_2'; var VAL_2 = 'val_2'; var KEY_MERGE = 'key_merge'; -var VAL_MERGE_1 = {'foo': 1, 'bar': {'hoo': 1, 'boo': 1}, 'moo': {'a': 3}}; -var VAL_MERGE_2 = {'bar': {'hoo': 2}, 'baz': 2, 'moo': {'a': 3}}; -var VAL_MERGE_EXPECT = - {'foo': 1, 'bar': {'hoo': 2, 'boo': 1}, 'baz': 2, 'moo': {'a': 3}}; +var VAL_MERGE_1 = {foo: 1, bar: {hoo: 1, boo: 1}, moo: {a: 3}}; +var VAL_MERGE_2 = {bar: {hoo: 2}, baz: 2, moo: {a: 3}}; +var VAL_MERGE_EXPECT = {foo: 1, bar: {hoo: 2, boo: 1}, baz: 2, moo: {a: 3}}; // setup in componentDidMount -var done = (result : ?boolean) => {}; -var updateMessage = (message : string ) => {}; +var done = (result: ?boolean) => {}; +var updateMessage = (message: string) => {}; -function runTestCase(description : string, fn) { +function runTestCase(description: string, fn) { updateMessage(description); fn(); } -function expectTrue(condition : boolean, message : string) { +function expectTrue(condition: boolean, message: string) { if (!condition) { throw new Error(message); } } -function expectEqual(lhs, rhs, testname : string) { +function expectEqual(lhs, rhs, testname: string) { expectTrue( !deepDiffer(lhs, rhs), - 'Error in test ' + testname + ': expected\n' + JSON.stringify(rhs) + - '\ngot\n' + JSON.stringify(lhs) + 'Error in test ' + + testname + + ': expected\n' + + JSON.stringify(rhs) + + '\ngot\n' + + JSON.stringify(lhs), ); } @@ -58,11 +59,14 @@ function expectAsyncNoError(place, err) { if (err instanceof Error) { err = err.message; } - expectTrue(err === null, 'Unexpected error in ' + place + ': ' + JSON.stringify(err)); + expectTrue( + err === null, + 'Unexpected error in ' + place + ': ' + JSON.stringify(err), + ); } function testSetAndGet() { - AsyncStorage.setItem(KEY_1, VAL_1, (err1) => { + AsyncStorage.setItem(KEY_1, VAL_1, err1 => { expectAsyncNoError('testSetAndGet/setItem', err1); AsyncStorage.getItem(KEY_1, (err2, result) => { expectAsyncNoError('testSetAndGet/getItem', err2); @@ -83,8 +87,8 @@ function testMissingGet() { } function testSetTwice() { - AsyncStorage.setItem(KEY_1, VAL_1, ()=>{ - AsyncStorage.setItem(KEY_1, VAL_1, ()=>{ + AsyncStorage.setItem(KEY_1, VAL_1, () => { + AsyncStorage.setItem(KEY_1, VAL_1, () => { AsyncStorage.getItem(KEY_1, (err, result) => { expectAsyncNoError('testSetTwice/setItem', err); expectEqual(result, VAL_1, 'testSetTwice'); @@ -96,16 +100,16 @@ function testSetTwice() { } function testRemoveItem() { - AsyncStorage.setItem(KEY_1, VAL_1, ()=>{ - AsyncStorage.setItem(KEY_2, VAL_2, ()=>{ + AsyncStorage.setItem(KEY_1, VAL_1, () => { + AsyncStorage.setItem(KEY_2, VAL_2, () => { AsyncStorage.getAllKeys((err, result) => { expectAsyncNoError('testRemoveItem/getAllKeys', err); expectTrue( result.indexOf(KEY_1) >= 0 && result.indexOf(KEY_2) >= 0, - 'Missing KEY_1 or KEY_2 in ' + '(' + result + ')' + 'Missing KEY_1 or KEY_2 in ' + '(' + result + ')', ); updateMessage('testRemoveItem - add two items'); - AsyncStorage.removeItem(KEY_1, (err2) => { + AsyncStorage.removeItem(KEY_1, err2 => { expectAsyncNoError('testRemoveItem/removeItem', err2); updateMessage('delete successful '); AsyncStorage.getItem(KEY_1, (err3, result2) => { @@ -113,17 +117,17 @@ function testRemoveItem() { expectEqual( result2, null, - 'testRemoveItem: key_1 present after delete' + 'testRemoveItem: key_1 present after delete', ); updateMessage('key properly removed '); AsyncStorage.getAllKeys((err4, result3) => { - expectAsyncNoError('testRemoveItem/getAllKeys', err4); - expectTrue( - result3.indexOf(KEY_1) === -1, - 'Unexpected: KEY_1 present in ' + result3 - ); - updateMessage('proper length returned.'); - runTestCase('should merge values', testMerge); + expectAsyncNoError('testRemoveItem/getAllKeys', err4); + expectTrue( + result3.indexOf(KEY_1) === -1, + 'Unexpected: KEY_1 present in ' + result3, + ); + updateMessage('proper length returned.'); + runTestCase('should merge values', testMerge); }); }); }); @@ -133,9 +137,9 @@ function testRemoveItem() { } function testMerge() { - AsyncStorage.setItem(KEY_MERGE, JSON.stringify(VAL_MERGE_1), (err1) => { + AsyncStorage.setItem(KEY_MERGE, JSON.stringify(VAL_MERGE_1), err1 => { expectAsyncNoError('testMerge/setItem', err1); - AsyncStorage.mergeItem(KEY_MERGE, JSON.stringify(VAL_MERGE_2), (err2) => { + AsyncStorage.mergeItem(KEY_MERGE, JSON.stringify(VAL_MERGE_2), err2 => { expectAsyncNoError('testMerge/mergeItem', err2); AsyncStorage.getItem(KEY_MERGE, (err3, result) => { expectAsyncNoError('testMerge/setItem', err3); @@ -150,21 +154,23 @@ function testMerge() { function testOptimizedMultiGet() { let batch = [[KEY_1, VAL_1], [KEY_2, VAL_2]]; let keys = batch.map(([key, value]) => key); - AsyncStorage.multiSet(batch, (err1) => { + AsyncStorage.multiSet(batch, err1 => { // yes, twice on purpose - [1, 2].forEach((i) => { + [1, 2].forEach(i => { expectAsyncNoError(`${i} testOptimizedMultiGet/multiSet`, err1); AsyncStorage.multiGet(keys, (err2, result) => { expectAsyncNoError(`${i} testOptimizedMultiGet/multiGet`, err2); expectEqual(result, batch, `${i} testOptimizedMultiGet multiGet`); - updateMessage('multiGet([key_1, key_2]) correctly returned ' + JSON.stringify(result)); + updateMessage( + 'multiGet([key_1, key_2]) correctly returned ' + + JSON.stringify(result), + ); done(); }); }); }); } - class AsyncStorageTest extends React.Component<{}, $FlowFixMeState> { state = { messages: 'Initializing...', @@ -172,10 +178,11 @@ class AsyncStorageTest extends React.Component<{}, $FlowFixMeState> { }; componentDidMount() { - done = () => this.setState({done: true}, () => { - TestModule.markTestCompleted(); - }); - updateMessage = (msg) => { + done = () => + this.setState({done: true}, () => { + TestModule.markTestCompleted(); + }); + updateMessage = msg => { this.setState({messages: this.state.messages.concat('\n' + msg)}); DEBUG && console.log(msg); }; @@ -186,11 +193,10 @@ class AsyncStorageTest extends React.Component<{}, $FlowFixMeState> { return ( - { - /* $FlowFixMe(>=0.54.0 site=react_native_fb,react_native_oss) This + {/* $FlowFixMe(>=0.54.0 site=react_native_fb,react_native_oss) This * comment suppresses an error found when Flow v0.54 was deployed. * To see the error delete this comment and run Flow. */ - this.constructor.displayName + ': '} + this.constructor.displayName + ': '} {this.state.done ? 'Done' : 'Testing...'} {'\n\n' + this.state.messages} diff --git a/IntegrationTests/ImageCachePolicyTest.js b/IntegrationTests/ImageCachePolicyTest.js index a095b4ec99128a..1c4429389cbbb0 100644 --- a/IntegrationTests/ImageCachePolicyTest.js +++ b/IntegrationTests/ImageCachePolicyTest.js @@ -4,19 +4,16 @@ * 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'; var React = require('react'); var ReactNative = require('react-native'); -var { - Image, - View, - Text, - StyleSheet, -} = ReactNative; -var { TestModule } = ReactNative.NativeModules; +var {Image, View, Text, StyleSheet} = ReactNative; +var {TestModule} = ReactNative.NativeModules; /* * The reload and force-cache tests don't actually verify that the complete functionality. @@ -30,22 +27,25 @@ var { TestModule } = ReactNative.NativeModules; const TESTS = ['only-if-cached', 'default', 'reload', 'force-cache']; -type Props = {} +type Props = {}; type State = { 'only-if-cached'?: boolean, - 'default'?: boolean, - 'reload'?: boolean, + default?: boolean, + reload?: boolean, 'force-cache'?: boolean, -} +}; class ImageCachePolicyTest extends React.Component { - state = {} + state = {}; shouldComponentUpdate(nextProps: Props, nextState: State) { const results: Array = TESTS.map(x => nextState[x]); if (!results.includes(undefined)) { - const result: boolean = results.reduce((x,y) => x === y === true, true); + const result: boolean = results.reduce( + (x, y) => (x === y) === true, + true, + ); TestModule.markTestPassed(result); } @@ -60,38 +60,46 @@ class ImageCachePolicyTest extends React.Component { return ( Hello - this.testComplete('only-if-cached', false)} - onError={() => this.testComplete('only-if-cached', true)} - style={styles.base} - /> this.testComplete('only-if-cached', false)} + onError={() => this.testComplete('only-if-cached', true)} + style={styles.base} + /> + this.testComplete('default', true)} onError={() => this.testComplete('default', false)} style={styles.base} /> this.testComplete('reload', true)} onError={() => this.testComplete('reload', false)} style={styles.base} /> this.testComplete('force-cache', true)} onError={() => this.testComplete('force-cache', false)} style={styles.base} diff --git a/IntegrationTests/ImageSnapshotTest.js b/IntegrationTests/ImageSnapshotTest.js index 3d024d569da669..5c74433a9d40f5 100644 --- a/IntegrationTests/ImageSnapshotTest.js +++ b/IntegrationTests/ImageSnapshotTest.js @@ -4,17 +4,16 @@ * 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'; var React = require('react'); var ReactNative = require('react-native'); -var { - Image, - View, -} = ReactNative; -var { TestModule } = ReactNative.NativeModules; +var {Image, View} = ReactNative; +var {TestModule} = ReactNative.NativeModules; class ImageSnapshotTest extends React.Component<{}> { componentDidMount() { @@ -23,7 +22,7 @@ class ImageSnapshotTest extends React.Component<{}> { } } - done = (success : boolean) => { + done = (success: boolean) => { TestModule.markTestPassed(success); }; @@ -32,7 +31,8 @@ class ImageSnapshotTest extends React.Component<{}> { TestModule.verifySnapshot(this.done)} /> + onLoad={() => TestModule.verifySnapshot(this.done)} + /> ); } } diff --git a/IntegrationTests/IntegrationTestHarnessTest.js b/IntegrationTests/IntegrationTestHarnessTest.js index 9b34065b8fd6d4..2a596d068b676c 100644 --- a/IntegrationTests/IntegrationTestHarnessTest.js +++ b/IntegrationTests/IntegrationTestHarnessTest.js @@ -4,8 +4,10 @@ * 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'; /* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error @@ -15,16 +17,16 @@ var requestAnimationFrame = require('fbjs/lib/requestAnimationFrame'); var React = require('react'); var PropTypes = require('prop-types'); var ReactNative = require('react-native'); -var { - Text, - View, -} = ReactNative; -var { TestModule } = ReactNative.NativeModules; +var {Text, View} = ReactNative; +var {TestModule} = ReactNative.NativeModules; -class IntegrationTestHarnessTest extends React.Component<{ - shouldThrow?: boolean, - waitOneFrame?: boolean, -}, $FlowFixMeState> { +class IntegrationTestHarnessTest extends React.Component< + { + shouldThrow?: boolean, + waitOneFrame?: boolean, + }, + $FlowFixMeState, +> { static propTypes = { shouldThrow: PropTypes.bool, waitOneFrame: PropTypes.bool, @@ -60,11 +62,10 @@ class IntegrationTestHarnessTest extends React.Component<{ return ( - { - /* $FlowFixMe(>=0.54.0 site=react_native_fb,react_native_oss) This + {/* $FlowFixMe(>=0.54.0 site=react_native_fb,react_native_oss) This * comment suppresses an error found when Flow v0.54 was deployed. * To see the error delete this comment and run Flow. */ - this.constructor.displayName + ': '} + this.constructor.displayName + ': '} {this.state.done ? 'Done' : 'Testing...'} diff --git a/IntegrationTests/IntegrationTestsApp.js b/IntegrationTests/IntegrationTestsApp.js index 62f6fa83057b3c..c59f15b3d73a46 100644 --- a/IntegrationTests/IntegrationTestsApp.js +++ b/IntegrationTests/IntegrationTestsApp.js @@ -4,8 +4,10 @@ * 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'; var React = require('react'); @@ -40,7 +42,7 @@ TESTS.forEach( /* $FlowFixMe(>=0.54.0 site=react_native_fb,react_native_oss) This comment * suppresses an error found when Flow v0.54 was deployed. To see the error * delete this comment and run Flow. */ - (test) => AppRegistry.registerComponent(test.displayName, () => test) + test => AppRegistry.registerComponent(test.displayName, () => test), ); // Modules required for integration tests @@ -68,20 +70,18 @@ class IntegrationTestsApp extends React.Component<{}, $FlowFixMeState> { Click on a test to run it in this shell for easier debugging and - development. Run all tests in the testing environment with cmd+U in + development. Run all tests in the testing environment with cmd+U in Xcode. - {TESTS.map((test) => [ + {TESTS.map(test => [ this.setState({test})} style={styles.row}> - - {test.displayName} - + {test.displayName} , - + , ])} diff --git a/IntegrationTests/LayoutEventsTest.js b/IntegrationTests/LayoutEventsTest.js index 31dd1839c86cfc..b9183a34e92eb0 100644 --- a/IntegrationTests/LayoutEventsTest.js +++ b/IntegrationTests/LayoutEventsTest.js @@ -4,21 +4,17 @@ * 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'; var React = require('react'); var createReactClass = require('create-react-class'); var ReactNative = require('react-native'); -var { - Image, - LayoutAnimation, - StyleSheet, - Text, - View, -} = ReactNative; -var { TestModule } = ReactNative.NativeModules; +var {Image, LayoutAnimation, StyleSheet, Text, View} = ReactNative; +var {TestModule} = ReactNative.NativeModules; var deepDiffer = require('deepDiffer'); @@ -55,27 +51,23 @@ var LayoutEventsTest = createReactClass({ }, animateViewLayout: function() { debug('animateViewLayout invoked'); - LayoutAnimation.configureNext( - LayoutAnimation.Presets.spring, - () => { - debug('animateViewLayout done'); - this.checkLayout(this.addWrapText); - } - ); + LayoutAnimation.configureNext(LayoutAnimation.Presets.spring, () => { + debug('animateViewLayout done'); + this.checkLayout(this.addWrapText); + }); this.setState({viewStyle: {margin: 60}}); }, addWrapText: function() { debug('addWrapText invoked'); this.setState( {extraText: ' And a bunch more text to wrap around a few lines.'}, - () => this.checkLayout(this.changeContainer) + () => this.checkLayout(this.changeContainer), ); }, changeContainer: function() { debug('changeContainer invoked'); - this.setState( - {containerStyle: {width: 280}}, - () => this.checkLayout(TestModule.markTestCompleted) + this.setState({containerStyle: {width: 280}}, () => + this.checkLayout(TestModule.markTestCompleted), ); }, checkLayout: function(next?: ?Function) { @@ -103,8 +95,9 @@ var LayoutEventsTest = createReactClass({ if (deepDiffer(measured, onLayout)) { var data = {measured, onLayout}; throw new Error( - node + ' onLayout mismatch with measure ' + - JSON.stringify(data, null, ' ') + node + + ' onLayout mismatch with measure ' + + JSON.stringify(data, null, ' '), ); } }, @@ -145,7 +138,7 @@ var LayoutEventsTest = createReactClass({ ); - } + }, }); var styles = StyleSheet.create({ diff --git a/IntegrationTests/LoggingTestModule.js b/IntegrationTests/LoggingTestModule.js index df2b0e59b52414..76a4fbccd71256 100644 --- a/IntegrationTests/LoggingTestModule.js +++ b/IntegrationTests/LoggingTestModule.js @@ -4,7 +4,9 @@ * 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'; var BatchedBridge = require('BatchedBridge'); @@ -16,7 +18,7 @@ var LoggingTestModule = { logToConsole: function(str) { console.log(str); }, - logToConsoleAfterWait: function(str,timeout_ms) { + logToConsoleAfterWait: function(str, timeout_ms) { setTimeout(function() { console.log(str); }, timeout_ms); @@ -32,12 +34,9 @@ var LoggingTestModule = { }, throwError: function(str) { throw new Error(str); - } + }, }; -BatchedBridge.registerCallableModule( - 'LoggingTestModule', - LoggingTestModule -); +BatchedBridge.registerCallableModule('LoggingTestModule', LoggingTestModule); module.exports = LoggingTestModule; diff --git a/IntegrationTests/PromiseTest.js b/IntegrationTests/PromiseTest.js index 21005576d678d0..3e919a86712be4 100644 --- a/IntegrationTests/PromiseTest.js +++ b/IntegrationTests/PromiseTest.js @@ -4,14 +4,16 @@ * 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'; var React = require('react'); var ReactNative = require('react-native'); -var { View } = ReactNative; -var { TestModule } = ReactNative.NativeModules; +var {View} = ReactNative; +var {TestModule} = ReactNative.NativeModules; class PromiseTest extends React.Component<{}> { shouldResolve = false; @@ -25,24 +27,26 @@ class PromiseTest extends React.Component<{}> { this.testShouldReject(), this.testShouldSucceedAsync(), this.testShouldThrowAsync(), - ]).then(() => TestModule.markTestPassed( - this.shouldResolve && this.shouldReject && - this.shouldSucceedAsync && this.shouldThrowAsync - )); + ]).then(() => + TestModule.markTestPassed( + this.shouldResolve && + this.shouldReject && + this.shouldSucceedAsync && + this.shouldThrowAsync, + ), + ); } testShouldResolve = () => { - return TestModule - .shouldResolve() - .then(() => this.shouldResolve = true) - .catch(() => this.shouldResolve = false); + return TestModule.shouldResolve() + .then(() => (this.shouldResolve = true)) + .catch(() => (this.shouldResolve = false)); }; testShouldReject = () => { - return TestModule - .shouldReject() - .then(() => this.shouldReject = false) - .catch(() => this.shouldReject = true); + return TestModule.shouldReject() + .then(() => (this.shouldReject = false)) + .catch(() => (this.shouldReject = true)); }; testShouldSucceedAsync = async (): Promise => { diff --git a/IntegrationTests/PropertiesUpdateTest.js b/IntegrationTests/PropertiesUpdateTest.js index 3d93d9d0ac238f..e2c16f3a6325e5 100644 --- a/IntegrationTests/PropertiesUpdateTest.js +++ b/IntegrationTests/PropertiesUpdateTest.js @@ -3,25 +3,24 @@ * * 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'; var React = require('react'); var ReactNative = require('react-native'); -var { - View, -} = ReactNative; +var {View} = ReactNative; -var { TestModule } = ReactNative.NativeModules; +var {TestModule} = ReactNative.NativeModules; class PropertiesUpdateTest extends React.Component { render() { if (this.props.markTestPassed) { TestModule.markTestPassed(true); } - return ( - - ); + return ; } } diff --git a/IntegrationTests/RCTRootViewIntegrationTestApp.js b/IntegrationTests/RCTRootViewIntegrationTestApp.js index aef56f97599220..8cb499f3677f82 100644 --- a/IntegrationTests/RCTRootViewIntegrationTestApp.js +++ b/IntegrationTests/RCTRootViewIntegrationTestApp.js @@ -4,7 +4,9 @@ * 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'; require('regenerator-runtime/runtime'); @@ -28,8 +30,8 @@ var TESTS = [ require('./SizeFlexibilityUpdateTest'), ]; -TESTS.forEach( - (test) => AppRegistry.registerComponent(test.displayName, () => test) +TESTS.forEach(test => + AppRegistry.registerComponent(test.displayName, () => test), ); class RCTRootViewIntegrationTestApp extends React.Component { @@ -49,20 +51,18 @@ class RCTRootViewIntegrationTestApp extends React.Component { Click on a test to run it in this shell for easier debugging and - development. Run all tests in the testing environment with cmd+U in + development. Run all tests in the testing environment with cmd+U in Xcode. - {TESTS.map((test) => [ + {TESTS.map(test => [ this.setState({test})} style={styles.row}> - - {test.displayName} - + {test.displayName} , - + , ])} @@ -88,4 +88,7 @@ var styles = StyleSheet.create({ }, }); -AppRegistry.registerComponent('RCTRootViewIntegrationTestApp', () => RCTRootViewIntegrationTestApp); +AppRegistry.registerComponent( + 'RCTRootViewIntegrationTestApp', + () => RCTRootViewIntegrationTestApp, +); diff --git a/IntegrationTests/ReactContentSizeUpdateTest.js b/IntegrationTests/ReactContentSizeUpdateTest.js index dda42b4df9c875..1306f8d7aa9811 100644 --- a/IntegrationTests/ReactContentSizeUpdateTest.js +++ b/IntegrationTests/ReactContentSizeUpdateTest.js @@ -3,7 +3,10 @@ * * 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'; var React = require('react'); @@ -13,9 +16,9 @@ var RCTNativeAppEventEmitter = require('RCTNativeAppEventEmitter'); var Subscribable = require('Subscribable'); var TimerMixin = require('react-timer-mixin'); -var { View } = ReactNative; +var {View} = ReactNative; -var { TestModule } = ReactNative.NativeModules; +var {TestModule} = ReactNative.NativeModules; var reactViewWidth = 101; var reactViewHeight = 102; @@ -24,14 +27,13 @@ var newReactViewHeight = 202; var ReactContentSizeUpdateTest = createReactClass({ displayName: 'ReactContentSizeUpdateTest', - mixins: [Subscribable.Mixin, - TimerMixin], + mixins: [Subscribable.Mixin, TimerMixin], UNSAFE_componentWillMount: function() { this.addListenerOn( RCTNativeAppEventEmitter, 'rootViewDidChangeIntrinsicSize', - this.rootViewDidChangeIntrinsicSize + this.rootViewDidChangeIntrinsicSize, ); }, @@ -50,23 +52,25 @@ var ReactContentSizeUpdateTest = createReactClass({ }, componentDidMount: function() { - this.setTimeout( - () => { this.updateViewSize(); }, - 1000 - ); + this.setTimeout(() => { + this.updateViewSize(); + }, 1000); }, rootViewDidChangeIntrinsicSize: function(intrinsicSize) { - if (intrinsicSize.height === newReactViewHeight && intrinsicSize.width === newReactViewWidth) { + if ( + intrinsicSize.height === newReactViewHeight && + intrinsicSize.width === newReactViewWidth + ) { TestModule.markTestPassed(true); } }, render() { return ( - + ); - } + }, }); ReactContentSizeUpdateTest.displayName = 'ReactContentSizeUpdateTest'; diff --git a/IntegrationTests/SimpleSnapshotTest.js b/IntegrationTests/SimpleSnapshotTest.js index dd8bf9ac8731e7..ea32c4a9a912f1 100644 --- a/IntegrationTests/SimpleSnapshotTest.js +++ b/IntegrationTests/SimpleSnapshotTest.js @@ -4,8 +4,10 @@ * 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'; var React = require('react'); @@ -15,11 +17,8 @@ var ReactNative = require('react-native'); * run Flow. */ var requestAnimationFrame = require('fbjs/lib/requestAnimationFrame'); -var { - StyleSheet, - View, -} = ReactNative; -var { TestModule } = ReactNative.NativeModules; +var {StyleSheet, View} = ReactNative; +var {TestModule} = ReactNative.NativeModules; class SimpleSnapshotTest extends React.Component<{}> { componentDidMount() { @@ -29,7 +28,7 @@ class SimpleSnapshotTest extends React.Component<{}> { requestAnimationFrame(() => TestModule.verifySnapshot(this.done)); } - done = (success : boolean) => { + done = (success: boolean) => { TestModule.markTestPassed(success); }; diff --git a/IntegrationTests/SizeFlexibilityUpdateTest.js b/IntegrationTests/SizeFlexibilityUpdateTest.js index ce0be9e6e2229d..5f885ddb7bd712 100644 --- a/IntegrationTests/SizeFlexibilityUpdateTest.js +++ b/IntegrationTests/SizeFlexibilityUpdateTest.js @@ -3,7 +3,10 @@ * * 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'; var React = require('react'); @@ -11,9 +14,9 @@ var createReactClass = require('create-react-class'); var ReactNative = require('react-native'); var RCTNativeAppEventEmitter = require('RCTNativeAppEventEmitter'); var Subscribable = require('Subscribable'); -var { View } = ReactNative; +var {View} = ReactNative; -var { TestModule } = ReactNative.NativeModules; +var {TestModule} = ReactNative.NativeModules; var reactViewWidth = 111; var reactViewHeight = 222; @@ -28,7 +31,7 @@ var SizeFlexibilityUpdateTest = createReactClass({ this.addListenerOn( RCTNativeAppEventEmitter, 'rootViewDidChangeIntrinsicSize', - this.rootViewDidChangeIntrinsicSize + this.rootViewDidChangeIntrinsicSize, ); }, @@ -38,7 +41,6 @@ var SizeFlexibilityUpdateTest = createReactClass({ }, rootViewDidChangeIntrinsicSize: function(intrinsicSize) { - if (finalState) { // If a test reaches its final state, it is not expected to do anything more TestModule.markTestPassed(false); @@ -46,25 +48,37 @@ var SizeFlexibilityUpdateTest = createReactClass({ } if (this.props.both) { - if (intrinsicSize.width === reactViewWidth && intrinsicSize.height === reactViewHeight) { + if ( + intrinsicSize.width === reactViewWidth && + intrinsicSize.height === reactViewHeight + ) { this.markPassed(); return; } } if (this.props.height) { - if (intrinsicSize.width !== reactViewWidth && intrinsicSize.height === reactViewHeight) { + if ( + intrinsicSize.width !== reactViewWidth && + intrinsicSize.height === reactViewHeight + ) { this.markPassed(); return; } } if (this.props.width) { - if (intrinsicSize.width === reactViewWidth && intrinsicSize.height !== reactViewHeight) { + if ( + intrinsicSize.width === reactViewWidth && + intrinsicSize.height !== reactViewHeight + ) { this.markPassed(); return; } } if (this.props.none) { - if (intrinsicSize.width !== reactViewWidth && intrinsicSize.height !== reactViewHeight) { + if ( + intrinsicSize.width !== reactViewWidth && + intrinsicSize.height !== reactViewHeight + ) { this.markPassed(); return; } @@ -72,10 +86,8 @@ var SizeFlexibilityUpdateTest = createReactClass({ }, render() { - return ( - - ); - } + return ; + }, }); SizeFlexibilityUpdateTest.displayName = 'SizeFlexibilityUpdateTest'; diff --git a/IntegrationTests/SyncMethodTest.js b/IntegrationTests/SyncMethodTest.js index f61f52b3610600..eca1df986ba334 100644 --- a/IntegrationTests/SyncMethodTest.js +++ b/IntegrationTests/SyncMethodTest.js @@ -4,23 +4,23 @@ * 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'; var React = require('react'); var ReactNative = require('react-native'); -var { View } = ReactNative; - -const { - TestModule, - RNTesterTestModule, -} = ReactNative.NativeModules; +var {View} = ReactNative; +const {TestModule, RNTesterTestModule} = ReactNative.NativeModules; class SyncMethodTest extends React.Component<{}> { componentDidMount() { - if (RNTesterTestModule.echoString('test string value') !== 'test string value') { + if ( + RNTesterTestModule.echoString('test string value') !== 'test string value' + ) { throw new Error('Something wrong with sync method export'); } if (RNTesterTestModule.methodThatReturnsNil() != null) { diff --git a/IntegrationTests/TimersTest.js b/IntegrationTests/TimersTest.js index f40742c9a8b008..86e1a962175c6b 100644 --- a/IntegrationTests/TimersTest.js +++ b/IntegrationTests/TimersTest.js @@ -4,8 +4,10 @@ * 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'; var React = require('react'); @@ -16,12 +18,8 @@ var ReactNative = require('react-native'); * run Flow. */ var TimerMixin = require('react-timer-mixin'); -var { - StyleSheet, - Text, - View, -} = ReactNative; -var { TestModule } = ReactNative.NativeModules; +var {StyleSheet, Text, View} = ReactNative; +var {TestModule} = ReactNative.NativeModules; var TimersTest = createReactClass({ displayName: 'TimersTest', @@ -91,7 +89,7 @@ var TimersTest = createReactClass({ fails.push(this.setTimeout(() => this._fail('testClearMulti-4'), 0)); fails.push(this.setTimeout(() => this._fail('testClearMulti-5'), 10)); - fails.forEach((timeout) => this.clearTimeout(timeout)); + fails.forEach(timeout => this.clearTimeout(timeout)); this.setTimeout(() => this.clearTimeout(delayClear), 20); this.setTimeout(this.testOrdering, 50); @@ -102,22 +100,32 @@ var TimersTest = createReactClass({ var fail0; this.setImmediate(() => this.clearTimeout(fail0)); fail0 = this.setTimeout( - () => this._fail('testOrdering-t0, setImmediate should happen before ' + - 'setTimeout 0'), - 0 + () => + this._fail( + 'testOrdering-t0, setImmediate should happen before ' + + 'setTimeout 0', + ), + 0, ); var failAnim; // This should fail without the t=0 fastpath feature. this.setTimeout(() => this.cancelAnimationFrame(failAnim), 0); - failAnim = this.requestAnimationFrame( - () => this._fail('testOrdering-Anim, setTimeout 0 should happen before ' + - 'requestAnimationFrame') + failAnim = this.requestAnimationFrame(() => + this._fail( + 'testOrdering-Anim, setTimeout 0 should happen before ' + + 'requestAnimationFrame', + ), ); var fail25; - this.setTimeout(() => { this.clearTimeout(fail25); }, 20); + this.setTimeout(() => { + this.clearTimeout(fail25); + }, 20); fail25 = this.setTimeout( - () => this._fail('testOrdering-t25, setTimeout 20 should happen before ' + - 'setTimeout 25'), - 25 + () => + this._fail( + 'testOrdering-t25, setTimeout 20 should happen before ' + + 'setTimeout 25', + ), + 25, ); this.setTimeout(this.done, 50); }, @@ -152,7 +160,7 @@ var TimersTest = createReactClass({ this.setState({count: this.state.count + 1}); }, - _fail(caller : string) : void { + _fail(caller: string): void { throw new Error('_fail called by ' + caller); }, }); diff --git a/IntegrationTests/WebSocketTest.js b/IntegrationTests/WebSocketTest.js index de8428f79e6acb..33d6b2500c5d3a 100644 --- a/IntegrationTests/WebSocketTest.js +++ b/IntegrationTests/WebSocketTest.js @@ -4,23 +4,20 @@ * 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'; var React = require('react'); var ReactNative = require('react-native'); -var { View } = ReactNative; -var { TestModule } = ReactNative.NativeModules; +var {View} = ReactNative; +var {TestModule} = ReactNative.NativeModules; const DEFAULT_WS_URL = 'ws://localhost:5555/'; -const WS_EVENTS = [ - 'close', - 'error', - 'message', - 'open', -]; +const WS_EVENTS = ['close', 'error', 'message', 'open']; const WS_STATES = [ /* 0 */ 'CONNECTING', /* 1 */ 'OPEN', @@ -29,14 +26,14 @@ const WS_STATES = [ ]; type State = { - url: string; - fetchStatus: ?string; - socket: ?WebSocket; - socketState: ?number; - lastSocketEvent: ?string; - lastMessage: ?string | ?ArrayBuffer; - testMessage: string; - testExpectedResponse: string; + url: string, + fetchStatus: ?string, + socket: ?WebSocket, + socketState: ?number, + lastSocketEvent: ?string, + lastMessage: ?string | ?ArrayBuffer, + testMessage: string, + testExpectedResponse: string, }; class WebSocketTest extends React.Component<{}, State> { @@ -48,13 +45,13 @@ class WebSocketTest extends React.Component<{}, State> { lastSocketEvent: null, lastMessage: null, testMessage: 'testMessage', - testExpectedResponse: 'testMessage_response' + testExpectedResponse: 'testMessage_response', }; _waitFor = (condition: any, timeout: any, callback: any) => { var remaining = timeout; var t; - var timeoutFunction = function() { + var timeoutFunction = function() { if (condition()) { callback(true); return; @@ -63,11 +60,11 @@ class WebSocketTest extends React.Component<{}, State> { if (remaining === 0) { callback(false); } else { - t = setTimeout(timeoutFunction,1000); + t = setTimeout(timeoutFunction, 1000); } }; - t = setTimeout(timeoutFunction,1000); - } + t = setTimeout(timeoutFunction, 1000); + }; _connect = () => { const socket = new WebSocket(this.state.url); @@ -80,11 +77,11 @@ class WebSocketTest extends React.Component<{}, State> { _socketIsConnected = () => { return this.state.socketState === 1; //'OPEN' - } + }; _socketIsDisconnected = () => { return this.state.socketState === 3; //'CLOSED' - } + }; _disconnect = () => { if (!this.state.socket) { @@ -116,7 +113,7 @@ class WebSocketTest extends React.Component<{}, State> { }; _receivedTestExpectedResponse = () => { - return (this.state.lastMessage === this.state.testExpectedResponse); + return this.state.lastMessage === this.state.testExpectedResponse; }; componentDidMount() { @@ -126,34 +123,40 @@ class WebSocketTest extends React.Component<{}, State> { testConnect = () => { var component = this; component._connect(); - component._waitFor(component._socketIsConnected, 5, function(connectSucceeded) { + component._waitFor(component._socketIsConnected, 5, function( + connectSucceeded, + ) { if (!connectSucceeded) { TestModule.markTestPassed(false); return; } component.testSendAndReceive(); }); - } + }; testSendAndReceive = () => { var component = this; component._sendTestMessage(); - component._waitFor(component._receivedTestExpectedResponse, 5, function(messageReceived) { + component._waitFor(component._receivedTestExpectedResponse, 5, function( + messageReceived, + ) { if (!messageReceived) { TestModule.markTestPassed(false); return; } component.testDisconnect(); }); - } + }; testDisconnect = () => { var component = this; component._disconnect(); - component._waitFor(component._socketIsDisconnected, 5, function(disconnectSucceeded) { + component._waitFor(component._socketIsDisconnected, 5, function( + disconnectSucceeded, + ) { TestModule.markTestPassed(disconnectSucceeded); }); - } + }; render(): React.Node { return ; diff --git a/IntegrationTests/WebViewTest.js b/IntegrationTests/WebViewTest.js index 818b4e980216f0..47b4544cda8845 100644 --- a/IntegrationTests/WebViewTest.js +++ b/IntegrationTests/WebViewTest.js @@ -4,52 +4,68 @@ * 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'; var React = require('react'); var ReactNative = require('react-native'); -var { - WebView, -} = ReactNative; +var {WebView} = ReactNative; -var { TestModule } = ReactNative.NativeModules; +var {TestModule} = ReactNative.NativeModules; class WebViewTest extends React.Component { - render() { var firstMessageReceived = false; var secondMessageReceived = false; function processMessage(e) { var message = e.nativeEvent.data; - if (message === 'First') {firstMessageReceived = true;} - if (message === 'Second') {secondMessageReceived = true;} + if (message === 'First') { + firstMessageReceived = true; + } + if (message === 'Second') { + secondMessageReceived = true; + } // got both messages - if (firstMessageReceived && secondMessageReceived) {TestModule.markTestPassed(true);} + if (firstMessageReceived && secondMessageReceived) { + TestModule.markTestPassed(true); + } // wait for next message - else if (firstMessageReceived && !secondMessageReceived) {return;} + else if (firstMessageReceived && !secondMessageReceived) { + return; + } // first message got lost - else if (!firstMessageReceived && secondMessageReceived) {throw new Error('First message got lost');} + else if (!firstMessageReceived && secondMessageReceived) { + throw new Error('First message got lost'); + } } - var html = 'Hello world' - + ''; + var html = + 'Hello world' + + ''; // fail if messages didn't get through; - window.setTimeout(function() { throw new Error(firstMessageReceived ? 'Both messages got lost' : 'Second message got lost');}, 10000); + window.setTimeout(function() { + throw new Error( + firstMessageReceived + ? 'Both messages got lost' + : 'Second message got lost', + ); + }, 10000); var source = { html: html, - }; + }; return ( + /> ); } } From cd7c91f35d4b0d7e2a25dc0677bf064b7477d9ac Mon Sep 17 00:00:00 2001 From: Eli White Date: Thu, 10 May 2018 19:06:39 -0700 Subject: [PATCH 0503/1109] Convert react-native-github/Libraries to let/const Reviewed By: sahrens Differential Revision: D7961763 fbshipit-source-id: ff7dd1d2c7101c8019e0b4f844d8c377b4d13a13 --- Libraries/BatchedBridge/MessageQueue.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/BatchedBridge/MessageQueue.js b/Libraries/BatchedBridge/MessageQueue.js index a5208d81b70d56..2d22b90a44c376 100644 --- a/Libraries/BatchedBridge/MessageQueue.js +++ b/Libraries/BatchedBridge/MessageQueue.js @@ -249,7 +249,7 @@ class MessageQueue { global.nativeFlushQueueImmediate && now - this._lastFlush >= MIN_TIME_BETWEEN_FLUSHES_MS ) { - var queue = this._queue; + const queue = this._queue; this._queue = [[], [], [], this._callID]; this._lastFlush = now; global.nativeFlushQueueImmediate(queue); From 1e2de712907e5fe0d17648f0ff5c81d4384ca85b Mon Sep 17 00:00:00 2001 From: Eli White Date: Thu, 10 May 2018 19:06:41 -0700 Subject: [PATCH 0504/1109] Allow trailing commas Summary: This was previously set to disallow trailing commas on function arguments which prettier would add. Since we are dropping support for node < 8, we can now change this setting to require trailing commas everywhere and be consistent with the prettier config at Facebook. Reviewed By: hramos Differential Revision: D7961098 fbshipit-source-id: fbe49513183a8c8e027bb05467a767235dbfb15b --- .eslintrc | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/.eslintrc b/.eslintrc index 9887d1c6d8dbe0..395f7d8243492b 100644 --- a/.eslintrc +++ b/.eslintrc @@ -57,18 +57,7 @@ "rules": { // General - - // This must be disallowed in this repo because the minimum supported - // version of node is 4 which doesn't support trailing commas. - // Once the minimum supported version is 8 or greater this can be changed - "comma-dangle": [2, { // disallow trailing commas in object literals - "arrays": "ignore", - "objects": "ignore", - "imports": "ignore", - "exports": "ignore", - "functions": "never" - }], - + "comma-dangle": [1, "always-multiline"], // allow or disallow trailing commas "no-cond-assign": 1, // disallow assignment in conditional expressions "no-console": 0, // disallow use of console (off by default in the node environment) "no-const-assign": 2, // disallow assignment to const-declared variables @@ -267,27 +256,11 @@ }, "overrides": [ - { - "files": [ - "Libraries/**/*.js", - "RNTester/**/*.js", - "jest/**/*.js", - ], - "rules": { - // These folders currently run through babel and don't need to be - // compatible with node 4 - "comma-dangle": 0, - }, - }, { "files": [ "local-cli/**/*.js", ], "rules": { - // This folder currently runs through babel and doesn't need to be - // compatible with node 4 - "comma-dangle": 0, - "lint/extra-arrow-initializer": 0, "no-alert": 0, "no-console-disallow": 0, From d01ab66b47a173a62eef6261e2415f0619fefcbb Mon Sep 17 00:00:00 2001 From: Eli White Date: Thu, 10 May 2018 19:06:46 -0700 Subject: [PATCH 0505/1109] Prettier React Native Libraries Reviewed By: sahrens Differential Revision: D7961488 fbshipit-source-id: 05f9b8b0b91ae77f9040a5321ccc18f7c3c1ce9a --- Libraries/ART/ARTSerializablePath.js | 19 +- Libraries/ART/ReactNativeART.js | 119 ++--- Libraries/Alert/Alert.js | 32 +- Libraries/Alert/AlertIOS.js | 76 +-- Libraries/Alert/RCTAlertManager.android.js | 11 +- Libraries/Alert/RCTAlertManager.ios.js | 2 + Libraries/Animated/release/gulpfile.js | 84 ++-- Libraries/Animated/src/AnimatedWeb.js | 2 + Libraries/Animated/src/Easing.js | 24 +- Libraries/Animated/src/SpringConfig.js | 19 +- .../Animated/src/__tests__/Animated-test.js | 185 ++++---- .../src/__tests__/AnimatedNative-test.js | 414 ++++++++++------ .../Animated/src/__tests__/Easing-test.js | 376 ++++++++++++++- .../src/__tests__/Interpolation-test.js | 2 + .../Animated/src/__tests__/bezier-test.js | 25 +- Libraries/Animated/src/bezier.js | 210 ++++---- .../src/polyfills/InteractionManager.js | 4 +- Libraries/Animated/src/polyfills/Set.js | 2 + .../Animated/src/polyfills/flattenStyle.js | 3 + Libraries/AppState/AppState.js | 67 ++- Libraries/BatchedBridge/BatchedBridge.js | 2 + Libraries/BatchedBridge/NativeModules.js | 145 +++--- .../__mocks__/MessageQueueTestConfig.js | 7 +- .../__mocks__/MessageQueueTestModule.js | 8 +- .../__tests__/NativeModules-test.js | 19 +- Libraries/BugReporting/BugReporting.js | 52 +- Libraries/BugReporting/dumpReactTree.js | 4 +- Libraries/BugReporting/getReactData.js | 21 +- Libraries/CameraRoll/ImagePickerIOS.js | 26 +- Libraries/Color/normalizeColor.js | 89 ++-- .../AccessibilityInfo.android.js | 22 +- .../AccessibilityInfo.ios.js | 38 +- .../ActivityIndicator/ActivityIndicator.js | 10 +- .../Components/AppleTV/TVEventHandler.js | 18 +- .../Components/AppleTV/TVViewPropTypes.js | 103 ++-- Libraries/Components/Button.js | 16 +- Libraries/Components/Clipboard/Clipboard.js | 4 +- .../DatePicker/DatePickerIOS.android.js | 7 +- .../DatePicker/DatePickerIOS.ios.js | 26 +- .../DatePickerAndroid.android.js | 10 +- .../DatePickerAndroid.ios.js | 4 +- .../DrawerLayoutAndroid.android.js | 98 ++-- .../DrawerAndroid/DrawerLayoutAndroid.ios.js | 2 + Libraries/Components/Keyboard/Keyboard.js | 2 + .../Keyboard/KeyboardAvoidingView.js | 50 +- Libraries/Components/LazyRenderer.js | 6 +- .../MaskedView/MaskedViewIOS.android.js | 2 + .../MaskedView/MaskedViewIOS.ios.js | 7 +- .../Navigation/NavigatorIOS.android.js | 2 + .../Components/Navigation/NavigatorIOS.ios.js | 65 ++- Libraries/Components/Picker/Picker.js | 209 ++++---- .../Picker/PickerAndroid.android.js | 50 +- .../Components/Picker/PickerAndroid.ios.js | 2 + .../Components/Picker/PickerIOS.android.js | 3 + Libraries/Components/Picker/PickerIOS.ios.js | 41 +- .../ProgressBarAndroid.ios.js | 2 + .../ProgressViewIOS.android.js | 4 +- .../ProgressViewIOS/ProgressViewIOS.ios.js | 6 +- .../RefreshControl/RefreshControl.js | 19 +- .../__mocks__/RefreshControlMock.js | 2 + .../SafeAreaView/SafeAreaView.android.js | 2 + Libraries/Components/ScrollResponder.js | 165 +++++-- Libraries/Components/ScrollView/ScrollView.js | 270 ++++++----- .../ScrollView/__mocks__/ScrollViewMock.js | 5 +- .../ScrollView/processDecelerationRate.js | 2 + .../SegmentedControlIOS.android.js | 4 +- .../SegmentedControlIOS.ios.js | 13 +- Libraries/Components/Slider/Slider.js | 58 ++- Libraries/Components/StaticContainer.react.js | 6 +- Libraries/Components/StaticRenderer.js | 4 +- Libraries/Components/StatusBar/StatusBar.js | 26 +- .../StatusBar/StatusBarIOS.android.js | 2 + .../Components/StatusBar/StatusBarIOS.ios.js | 4 +- Libraries/Components/Subscribable.js | 16 +- Libraries/Components/Switch/Switch.js | 27 +- .../Components/TabBarIOS/TabBarIOS.android.js | 3 +- .../Components/TabBarIOS/TabBarIOS.ios.js | 28 +- .../TabBarIOS/TabBarItemIOS.android.js | 7 +- .../Components/TabBarIOS/TabBarItemIOS.ios.js | 20 +- .../Components/TextInput/TextInputState.js | 11 +- .../TimePickerAndroid.android.js | 11 +- .../TimePickerAndroid.ios.js | 4 +- .../ToastAndroid/ToastAndroid.android.js | 19 +- .../ToastAndroid/ToastAndroid.ios.js | 9 +- .../ToolbarAndroid/ToolbarAndroid.android.js | 20 +- .../ToolbarAndroid/ToolbarAndroid.ios.js | 2 + .../Touchable/BoundingDimensions.js | 3 +- Libraries/Components/Touchable/PooledClass.js | 1 + Libraries/Components/Touchable/Position.js | 1 + Libraries/Components/Touchable/Touchable.js | 179 ++++--- .../TouchableNativeFeedback.android.js | 59 ++- .../Touchable/TouchableNativeFeedback.ios.js | 7 +- .../Components/Touchable/TouchableOpacity.js | 42 +- .../Touchable/TouchableWithoutFeedback.js | 50 +- .../__mocks__/ensureComponentIsNative.js | 3 + .../__tests__/TouchableHighlight-test.js | 4 +- .../Touchable/ensureComponentIsNative.js | 4 +- .../Touchable/ensurePositiveDelayProps.js | 11 +- .../Components/View/PlatformViewPropTypes.js | 1 + .../View/ReactNativeStyleAttributes.js | 7 +- .../View/ReactNativeViewAttributes.js | 2 + .../Components/View/ViewAccessibility.js | 44 +- Libraries/Components/View/ViewPropTypes.js | 42 +- .../Components/View/ViewStylePropTypes.js | 2 + .../ViewPager/ViewPagerAndroid.android.js | 51 +- .../ViewPager/ViewPagerAndroid.ios.js | 2 + .../Components/WebView/WebView.android.js | 115 +++-- Libraries/Components/WebView/WebView.ios.js | 126 ++--- Libraries/Components/WebView/WebViewShared.js | 2 + .../WebView/__tests__/WebViewShared-test.js | 43 +- .../__tests__/parseErrorStack-test.js | 5 +- Libraries/Core/Devtools/getDevServer.js | 7 +- Libraries/Core/Devtools/openFileInEditor.js | 2 + Libraries/Core/Devtools/parseErrorStack.js | 6 +- Libraries/Core/Devtools/setupDevtools.js | 4 +- .../Core/Devtools/symbolicateStackTrace.js | 6 +- Libraries/Core/ExceptionsManager.js | 38 +- Libraries/Core/InitializeCore.js | 53 ++- Libraries/Core/ReactNativeVersion.js | 4 +- Libraries/Core/__mocks__/ErrorUtils.js | 2 + .../MissingNativeEventEmitterShim.js | 10 +- Libraries/EventEmitter/NativeEventEmitter.js | 2 + .../EventEmitter/RCTDeviceEventEmitter.js | 28 +- Libraries/EventEmitter/RCTEventEmitter.js | 9 +- .../EventEmitter/RCTNativeAppEventEmitter.js | 2 + .../__mocks__/NativeEventEmitter.js | 2 + Libraries/Experimental/Incremental.js | 68 +-- Libraries/Experimental/IncrementalExample.js | 60 ++- Libraries/Experimental/IncrementalGroup.js | 11 +- .../Experimental/IncrementalPresenter.js | 24 +- .../SwipeableRow/SwipeableListView.js | 61 ++- .../SwipeableListViewDataSource.js | 20 +- .../SwipeableQuickActionButton.js | 6 +- .../SwipeableRow/SwipeableQuickActions.js | 14 +- .../Experimental/SwipeableRow/SwipeableRow.js | 71 +-- Libraries/Experimental/WindowedListView.js | 262 ++++++---- Libraries/Geolocation/Geolocation.js | 47 +- Libraries/Image/AssetSourceResolver.js | 5 +- Libraries/Image/RelativeImageStub.js | 2 + .../__tests__/assetRelativePathInSnapshot.js | 16 +- .../__tests__/resolveAssetSource-test.js | 329 +++++++------ Libraries/Image/resolveAssetSource.js | 13 +- Libraries/Inspector/BorderBox.js | 9 +- Libraries/Inspector/BoxInspector.js | 16 +- Libraries/Inspector/ElementBox.js | 3 +- Libraries/Inspector/ElementProperties.js | 15 +- Libraries/Inspector/Inspector.js | 92 ++-- Libraries/Inspector/InspectorOverlay.js | 19 +- Libraries/Inspector/InspectorPanel.js | 36 +- Libraries/Inspector/NetworkOverlay.js | 133 +++--- Libraries/Inspector/PerformanceOverlay.js | 12 +- Libraries/Inspector/StyleInspector.js | 22 +- Libraries/Inspector/resolveBoxStyle.js | 3 +- Libraries/Interaction/Batchinator.js | 2 + .../Interaction/BridgeSpyStallHandler.js | 16 +- Libraries/Interaction/FrameRateLogger.js | 13 +- Libraries/Interaction/InteractionManager.js | 34 +- Libraries/Interaction/InteractionMixin.js | 6 +- .../Interaction/InteractionStallDebugger.js | 2 + Libraries/Interaction/JSEventLoopWatchdog.js | 9 +- Libraries/Interaction/PanResponder.js | 147 ++++-- .../Interaction/ReactPerfStallHandler.js | 2 + Libraries/Interaction/TaskQueue.js | 53 ++- Libraries/Interaction/TouchHistoryMath.js | 2 + .../Interaction/__tests__/Batchinator-test.js | 5 +- .../__tests__/InteractionManager-test.js | 24 +- .../__tests__/InteractionMixin-test.js | 2 + .../Interaction/__tests__/TaskQueue-test.js | 2 +- Libraries/JSInspector/InspectorAgent.js | 2 + Libraries/JSInspector/JSInspector.js | 6 +- Libraries/JSInspector/NetworkAgent.js | 92 ++-- Libraries/Linking/Linking.js | 18 +- Libraries/Lists/VirtualizedList.js | 8 +- Libraries/Modal/Modal.js | 67 ++- Libraries/Network/FormData.js | 22 +- Libraries/Network/NetInfo.js | 63 ++- Libraries/Network/RCTNetworking.android.js | 9 +- Libraries/Network/RCTNetworking.ios.js | 30 +- Libraries/Network/XHRInterceptor.js | 75 +-- Libraries/Network/XMLHttpRequest.js | 200 ++++---- Libraries/Network/__tests__/FormData-test.js | 11 +- .../Network/__tests__/XMLHttpRequest-test.js | 41 +- Libraries/Network/fetch.js | 4 +- .../Performance/QuickPerformanceLogger.js | 2 +- Libraries/Performance/SamplingProfiler.js | 7 +- .../PermissionsAndroid/PermissionsAndroid.js | 49 +- Libraries/Promise.js | 4 +- .../PushNotificationIOS.js | 84 ++-- Libraries/RCTTest/SnapshotViewIOS.android.js | 2 + Libraries/RCTTest/SnapshotViewIOS.ios.js | 14 +- Libraries/ReactNative/UIManager.js | 21 +- Libraries/Sample/Sample.android.js | 4 +- Libraries/Sample/Sample.ios.js | 4 +- Libraries/Settings/Settings.android.js | 2 + Libraries/Settings/Settings.ios.js | 10 +- Libraries/Share/Share.js | 41 +- Libraries/Storage/AsyncStorage.js | 41 +- Libraries/StyleSheet/ColorPropType.js | 36 +- Libraries/StyleSheet/EdgeInsetsPropType.js | 2 + Libraries/StyleSheet/LayoutPropTypes.js | 50 +- Libraries/StyleSheet/PointPropType.js | 2 + Libraries/StyleSheet/StyleSheetPropType.js | 8 +- Libraries/StyleSheet/StyleSheetValidation.js | 19 +- Libraries/StyleSheet/TransformPropTypes.js | 51 +- .../StyleSheet/__tests__/flattenStyle-test.js | 2 + .../__tests__/normalizeColor-test.js | 4 +- .../StyleSheet/__tests__/processColor-test.js | 38 +- .../__tests__/processTransform-test.js | 62 ++- .../__tests__/setNormalizedColorAlpha-test.js | 4 +- Libraries/StyleSheet/processColor.js | 4 +- Libraries/StyleSheet/processTransform.js | 60 ++- .../StyleSheet/setNormalizedColorAlpha.js | 2 + Libraries/Text/TextStylePropTypes.js | 78 ++- Libraries/Text/TextUpdateTest.js | 17 +- Libraries/Utilities/BackAndroid.js | 24 +- Libraries/Utilities/BackHandler.android.js | 9 +- Libraries/Utilities/BackHandler.ios.js | 15 +- Libraries/Utilities/DeviceInfo.js | 2 + Libraries/Utilities/Dimensions.js | 32 +- Libraries/Utilities/HMRLoadingView.android.js | 1 + Libraries/Utilities/HMRLoadingView.ios.js | 3 +- Libraries/Utilities/HeapCapture.js | 4 +- Libraries/Utilities/JSDevSupportModule.js | 12 +- Libraries/Utilities/MatrixMath.js | 447 ++++++++++++------ Libraries/Utilities/PixelRatio.js | 2 + Libraries/Utilities/Platform.android.js | 3 +- Libraries/Utilities/Platform.ios.js | 3 +- Libraries/Utilities/PlatformOS.android.js | 3 +- Libraries/Utilities/PlatformOS.ios.js | 3 +- Libraries/Utilities/RCTLog.js | 8 +- Libraries/Utilities/SceneTracker.js | 9 +- Libraries/Utilities/__mocks__/BackHandler.js | 8 +- Libraries/Utilities/__mocks__/PixelRatio.js | 6 +- .../Utilities/__tests__/MatrixMath-test.js | 182 ++++--- .../Utilities/__tests__/Platform-test.js | 6 +- .../Utilities/__tests__/SceneTracker-test.js | 7 +- .../__tests__/buildStyleInterpolator-test.js | 37 +- .../deepFreezeAndThrowOnMutationInDev-test.js | 49 +- .../Utilities/__tests__/groupByEveryN-test.js | 53 ++- .../__tests__/mapWithSeparator-test.js | 8 +- .../Utilities/__tests__/truncate-test.js | 54 +-- Libraries/Utilities/binaryToBase64.js | 2 + Libraries/Utilities/buildStyleInterpolator.js | 68 ++- Libraries/Utilities/clamp.js | 2 + .../Utilities/createStrictShapeTypeChecker.js | 30 +- .../deepFreezeAndThrowOnMutationInDev.js | 20 +- .../Utilities/defineLazyObjectProperty.js | 1 + Libraries/Utilities/deprecatedPropType.js | 15 +- .../differ/__tests__/deepDiffer-test.js | 88 ++-- Libraries/Utilities/differ/deepDiffer.js | 14 +- Libraries/Utilities/differ/insetsDiffer.js | 28 +- Libraries/Utilities/differ/matricesDiffer.js | 9 +- Libraries/Utilities/differ/pointsDiffer.js | 11 +- Libraries/Utilities/differ/sizesDiffer.js | 7 +- Libraries/Utilities/dismissKeyboard.js | 3 + Libraries/Utilities/groupByEveryN.js | 1 + Libraries/Utilities/infoLog.js | 2 + Libraries/Utilities/logError.js | 2 + Libraries/Utilities/mapWithSeparator.js | 2 + Libraries/Utilities/mergeIntoFast.js | 2 + Libraries/Utilities/stringifySafe.js | 2 + Libraries/Utilities/truncate.js | 18 +- Libraries/Vibration/Vibration.js | 21 +- Libraries/Vibration/VibrationIOS.android.js | 4 +- Libraries/Vibration/VibrationIOS.ios.js | 9 +- Libraries/WebSocket/WebSocket.js | 86 ++-- Libraries/WebSocket/WebSocketEvent.js | 1 + Libraries/WebSocket/WebSocketInterceptor.js | 21 +- .../WebSocket/__mocks__/event-target-shim.js | 2 + .../WebSocket/__tests__/WebSocket-test.js | 8 +- Libraries/polyfills/Array.es6.js | 14 +- Libraries/polyfills/Array.prototype.es6.js | 21 +- Libraries/polyfills/Number.es6.js | 1 + Libraries/polyfills/Object.es6.js | 14 +- Libraries/polyfills/Object.es7.js | 2 +- Libraries/polyfills/String.prototype.es6.js | 7 +- .../polyfills/__tests__/Object.es7-test.js | 63 ++- Libraries/polyfills/babelHelpers.js | 157 +++--- Libraries/polyfills/error-guard.js | 15 +- Libraries/promiseRejectionIsError.js | 2 + Libraries/react-native/React.js | 1 + .../react-native-implementation.js | 398 ++++++++++++---- .../react-native/react-native-interface.js | 2 + Libraries/vendor/core/ErrorUtils.js | 1 + Libraries/vendor/core/Map.js | 36 +- Libraries/vendor/core/Set.js | 8 +- .../core/_shouldPolyfillES6Collection.js | 36 +- Libraries/vendor/core/getObjectValues.js | 2 + Libraries/vendor/core/guid.js | 1 + Libraries/vendor/core/isEmpty.js | 2 + Libraries/vendor/core/mergeHelpers.js | 14 +- Libraries/vendor/core/toIterator.js | 18 +- .../selection/DocumentSelectionState.js | 24 +- .../vendor/emitter/EmitterSubscription.js | 5 +- Libraries/vendor/emitter/EventEmitter.js | 42 +- .../vendor/emitter/EventEmitterWithHolding.js | 14 +- Libraries/vendor/emitter/EventHolder.js | 11 +- Libraries/vendor/emitter/EventSubscription.js | 3 +- .../vendor/emitter/EventSubscriptionVendor.js | 12 +- Libraries/vendor/emitter/EventValidator.js | 35 +- Libraries/vendor/emitter/mixInEventEmitter.js | 8 +- 301 files changed, 6287 insertions(+), 3809 deletions(-) diff --git a/Libraries/ART/ARTSerializablePath.js b/Libraries/ART/ARTSerializablePath.js index de02f9498d069c..9c2d98e033fcc3 100644 --- a/Libraries/ART/ARTSerializablePath.js +++ b/Libraries/ART/ARTSerializablePath.js @@ -4,7 +4,9 @@ * 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'; // TODO: Move this into an ART mode called "serialized" or something @@ -19,7 +21,6 @@ const CURVE_TO = 3; const ARC = 4; const SerializablePath = Class(Path, { - initialize: function(path) { this.reset(); if (path instanceof SerializablePath) { @@ -54,7 +55,18 @@ const SerializablePath = Class(Path, { onArc: function(sx, sy, ex, ey, cx, cy, rx, ry, sa, ea, ccw, rotation) { if (rx !== ry || rotation) { return this._arcToBezier( - sx, sy, ex, ey, cx, cy, rx, ry, sa, ea, ccw, rotation + sx, + sy, + ex, + ey, + cx, + cy, + rx, + ry, + sa, + ea, + ccw, + rotation, ); } this.path.push(ARC, cx, cy, rx, sa, ea, ccw ? 0 : 1); @@ -66,8 +78,7 @@ const SerializablePath = Class(Path, { toJSON: function() { return this.path; - } - + }, }); module.exports = SerializablePath; diff --git a/Libraries/ART/ReactNativeART.js b/Libraries/ART/ReactNativeART.js index 0f32fa2dae2a85..465ddc6b13f21b 100644 --- a/Libraries/ART/ReactNativeART.js +++ b/Libraries/ART/ReactNativeART.js @@ -4,7 +4,9 @@ * 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 Color = require('art/core/color'); @@ -69,58 +71,57 @@ const SurfaceViewAttributes = merge(ReactNativeViewAttributes.UIView, { }); const NodeAttributes = { - transform: { diff: arrayDiffer }, + transform: {diff: arrayDiffer}, opacity: true, }; const GroupAttributes = merge(NodeAttributes, { - clipping: { diff: arrayDiffer } + clipping: {diff: arrayDiffer}, }); const RenderableAttributes = merge(NodeAttributes, { - fill: { diff: arrayDiffer }, - stroke: { diff: arrayDiffer }, + fill: {diff: arrayDiffer}, + stroke: {diff: arrayDiffer}, strokeWidth: true, strokeCap: true, strokeJoin: true, - strokeDash: { diff: arrayDiffer }, + strokeDash: {diff: arrayDiffer}, }); const ShapeAttributes = merge(RenderableAttributes, { - d: { diff: arrayDiffer }, + d: {diff: arrayDiffer}, }); const TextAttributes = merge(RenderableAttributes, { alignment: true, - frame: { diff: fontAndLinesDiffer }, - path: { diff: arrayDiffer } + frame: {diff: fontAndLinesDiffer}, + path: {diff: arrayDiffer}, }); // Native Components -const NativeSurfaceView = createReactNativeComponentClass('ARTSurfaceView', +const NativeSurfaceView = createReactNativeComponentClass( + 'ARTSurfaceView', () => ({ validAttributes: SurfaceViewAttributes, uiViewClassName: 'ARTSurfaceView', - })); + }), +); -const NativeGroup = createReactNativeComponentClass('ARTGroup', - () => ({ - validAttributes: GroupAttributes, - uiViewClassName: 'ARTGroup', - })); +const NativeGroup = createReactNativeComponentClass('ARTGroup', () => ({ + validAttributes: GroupAttributes, + uiViewClassName: 'ARTGroup', +})); -const NativeShape = createReactNativeComponentClass('ARTShape', - () => ({ - validAttributes: ShapeAttributes, - uiViewClassName: 'ARTShape', - })); +const NativeShape = createReactNativeComponentClass('ARTShape', () => ({ + validAttributes: ShapeAttributes, + uiViewClassName: 'ARTShape', +})); -const NativeText = createReactNativeComponentClass('ARTText', - () => ({ - validAttributes: TextAttributes, - uiViewClassName: 'ARTText', - })); +const NativeText = createReactNativeComponentClass('ARTText', () => ({ + validAttributes: TextAttributes, + uiViewClassName: 'ARTText', +})); // Utilities @@ -145,7 +146,7 @@ class Surface extends React.Component { }; getChildContext() { - return { isInSurface: true }; + return {isInSurface: true}; } render() { @@ -153,7 +154,7 @@ class Surface extends React.Component { const w = extractNumber(props.width, 0); const h = extractNumber(props.height, 0); return ( - + {this.props.children} ); @@ -175,10 +176,10 @@ function extractNumber(value, defaultValue) { const pooledTransform = new Transform(); function extractTransform(props) { - const scaleX = props.scaleX != null ? props.scaleX : - props.scale != null ? props.scale : 1; - const scaleY = props.scaleY != null ? props.scaleY : - props.scale != null ? props.scale : 1; + const scaleX = + props.scaleX != null ? props.scaleX : props.scale != null ? props.scale : 1; + const scaleY = + props.scaleY != null ? props.scaleY : props.scale != null ? props.scale : 1; pooledTransform .transformTo(1, 0, 0, 1, 0, 0) @@ -191,9 +192,12 @@ function extractTransform(props) { } return [ - pooledTransform.xx, pooledTransform.yx, - pooledTransform.xy, pooledTransform.yy, - pooledTransform.x, pooledTransform.y, + pooledTransform.xx, + pooledTransform.yx, + pooledTransform.xy, + pooledTransform.yy, + pooledTransform.x, + pooledTransform.y, ]; } @@ -222,7 +226,7 @@ class Group extends React.Component { const props = this.props; invariant( this.context.isInSurface, - 'ART: must be a child of a ' + 'ART: must be a child of a ', ); return ( ); @@ -422,9 +431,10 @@ function extractSingleFontFamily(fontFamilyString) { // ART on the web allows for multiple font-families to be specified. // For compatibility, we extract the first font-family, hoping // we'll get a match. - return fontFamilyString.split(',')[0] - .replace(fontFamilyPrefix, '') - .replace(fontFamilySuffix, ''); + return fontFamilyString + .split(',')[0] + .replace(fontFamilyPrefix, '') + .replace(fontFamilySuffix, ''); } function parseFontString(font) { @@ -458,7 +468,8 @@ function extractFont(font) { } const fontFamily = extractSingleFontFamily(font.fontFamily); const fontSize = +font.fontSize || 12; - const fontWeight = font.fontWeight != null ? font.fontWeight.toString() : '400'; + const fontWeight = + font.fontWeight != null ? font.fontWeight.toString() : '400'; return { // Normalize fontFamily: fontFamily, @@ -470,7 +481,7 @@ function extractFont(font) { const newLine = /\n/g; function extractFontAndLines(font, text) { - return { font: extractFont(font), lines: text.split(newLine) }; + return {font: extractFont(font), lines: text.split(newLine)}; } function extractAlignment(alignment) { @@ -488,10 +499,12 @@ class Text extends React.Component { render() { const props = this.props; const path = props.path; - const textPath = path ? (path instanceof Path ? path : new Path(path)).toJSON() : null; + const textPath = path + ? (path instanceof Path ? path : new Path(path)).toJSON() + : null; const textFrame = extractFontAndLines( props.font, - childrenAsString(props.children) + childrenAsString(props.children), ); return ( console.warn(errorMessage), + errorMessage => console.warn(errorMessage), (action, buttonKey) => { if (action === NativeModules.DialogManagerAndroid.buttonClicked) { if (buttonKey === NativeModules.DialogManagerAndroid.buttonNeutral) { buttonNeutral.onPress && buttonNeutral.onPress(); - } else if (buttonKey === NativeModules.DialogManagerAndroid.buttonNegative) { + } else if ( + buttonKey === NativeModules.DialogManagerAndroid.buttonNegative + ) { buttonNegative.onPress && buttonNegative.onPress(); - } else if (buttonKey === NativeModules.DialogManagerAndroid.buttonPositive) { + } else if ( + buttonKey === NativeModules.DialogManagerAndroid.buttonPositive + ) { buttonPositive.onPress && buttonPositive.onPress(); } } else if (action === NativeModules.DialogManagerAndroid.dismissed) { options && options.onDismiss && options.onDismiss(); } - } + }, ); } } diff --git a/Libraries/Alert/AlertIOS.js b/Libraries/Alert/AlertIOS.js index 082e3779da88e2..1998865b2d597c 100644 --- a/Libraries/Alert/AlertIOS.js +++ b/Libraries/Alert/AlertIOS.js @@ -4,9 +4,11 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * + * @format * @flow * @jsdoc */ + 'use strict'; const RCTAlertManager = require('NativeModules').AlertManager; @@ -18,7 +20,7 @@ export type AlertType = $Enum<{ /** * Default alert with no inputs */ - 'default': string, + default: string, /** * Plain text input alert */ @@ -40,15 +42,15 @@ export type AlertButtonStyle = $Enum<{ /** * Default button style */ - 'default': string, + default: string, /** * Cancel button style */ - 'cancel': string, + cancel: string, /** * Destructive button style */ - 'destructive': string, + destructive: string, }>; /** @@ -87,11 +89,13 @@ class AlertIOS { static alert( title: ?string, message?: ?string, - callbackOrButtons?: ?(() => void) | ButtonsArray, + callbackOrButtons?: ?((() => void) | ButtonsArray), type?: AlertType, ): void { if (typeof type !== 'undefined') { - console.warn('AlertIOS.alert() with a 4th "type" parameter is deprecated and will be removed. Use AlertIOS.prompt() instead.'); + console.warn( + 'AlertIOS.alert() with a 4th "type" parameter is deprecated and will be removed. Use AlertIOS.prompt() instead.', + ); this.prompt(title, message, callbackOrButtons, type); return; } @@ -106,26 +110,30 @@ class AlertIOS { static prompt( title: ?string, message?: ?string, - callbackOrButtons?: ?((text: string) => void) | ButtonsArray, + callbackOrButtons?: ?(((text: string) => void) | ButtonsArray), type?: ?AlertType = 'plain-text', defaultValue?: string, - keyboardType?: string + keyboardType?: string, ): void { if (typeof type === 'function') { console.warn( 'You passed a callback function as the "type" argument to AlertIOS.prompt(). React Native is ' + - 'assuming you want to use the deprecated AlertIOS.prompt(title, defaultValue, buttons, callback) ' + - 'signature. The current signature is AlertIOS.prompt(title, message, callbackOrButtons, type, defaultValue, ' + - 'keyboardType) and the old syntax will be removed in a future version.'); + 'assuming you want to use the deprecated AlertIOS.prompt(title, defaultValue, buttons, callback) ' + + 'signature. The current signature is AlertIOS.prompt(title, message, callbackOrButtons, type, defaultValue, ' + + 'keyboardType) and the old syntax will be removed in a future version.', + ); const callback = type; - RCTAlertManager.alertWithArgs({ - title: title || '', - type: 'plain-text', - defaultValue: message, - }, (id, value) => { - callback(value); - }); + RCTAlertManager.alertWithArgs( + { + title: title || '', + type: 'plain-text', + defaultValue: message, + }, + (id, value) => { + callback(value); + }, + ); return; } @@ -135,8 +143,7 @@ class AlertIOS { let destructiveButtonKey; if (typeof callbackOrButtons === 'function') { callbacks = [callbackOrButtons]; - } - else if (callbackOrButtons instanceof Array) { + } else if (callbackOrButtons instanceof Array) { callbackOrButtons.forEach((btn, index) => { callbacks[index] = btn.onPress; if (btn.style === 'cancel') { @@ -152,19 +159,22 @@ class AlertIOS { }); } - RCTAlertManager.alertWithArgs({ - title: title || '', - message: message || undefined, - buttons, - type: type || undefined, - defaultValue, - cancelButtonKey, - destructiveButtonKey, - keyboardType, - }, (id, value) => { - const cb = callbacks[id]; - cb && cb(value); - }); + RCTAlertManager.alertWithArgs( + { + title: title || '', + message: message || undefined, + buttons, + type: type || undefined, + defaultValue, + cancelButtonKey, + destructiveButtonKey, + keyboardType, + }, + (id, value) => { + const cb = callbacks[id]; + cb && cb(value); + }, + ); } } diff --git a/Libraries/Alert/RCTAlertManager.android.js b/Libraries/Alert/RCTAlertManager.android.js index 57bd4740e8fc74..2e510add8ddaca 100644 --- a/Libraries/Alert/RCTAlertManager.android.js +++ b/Libraries/Alert/RCTAlertManager.android.js @@ -4,7 +4,9 @@ * 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 NativeModules = require('NativeModules'); @@ -15,8 +17,9 @@ module.exports = { alertWithArgs: function(args, callback) { // TODO(5998984): Polyfill it correctly with DialogManagerAndroid NativeModules.DialogManagerAndroid.showAlert( - args, - emptyCallback, - callback || emptyCallback); + args, + emptyCallback, + callback || emptyCallback, + ); }, }; diff --git a/Libraries/Alert/RCTAlertManager.ios.js b/Libraries/Alert/RCTAlertManager.ios.js index d64bce5b4f12be..529bb5da0e55f2 100644 --- a/Libraries/Alert/RCTAlertManager.ios.js +++ b/Libraries/Alert/RCTAlertManager.ios.js @@ -4,8 +4,10 @@ * 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 RCTAlertManager = require('NativeModules').AlertManager; diff --git a/Libraries/Animated/release/gulpfile.js b/Libraries/Animated/release/gulpfile.js index f5e87b4c998709..b5599e9365fef3 100644 --- a/Libraries/Animated/release/gulpfile.js +++ b/Libraries/Animated/release/gulpfile.js @@ -3,6 +3,8 @@ * * 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'; @@ -20,58 +22,52 @@ var objectAssign = require('object-assign'); var runSequence = require('run-sequence'); var webpackStream = require('webpack-stream'); -var DEVELOPMENT_HEADER = [ - '/**', - ' * Animated v<%= version %>', - ' */' -].join('\n') + '\n'; -var PRODUCTION_HEADER = [ - '/**', - ' * Animated v<%= version %>', - ' *', - ' * Copyright (c) 2013-present, Facebook, Inc.', - ' *', - ' * This source code is licensed under the MIT license found in the', - ' * LICENSE file in the root directory of this source tree.', - ' */' -].join('\n') + '\n'; +var DEVELOPMENT_HEADER = + ['/**', ' * Animated v<%= version %>', ' */'].join('\n') + '\n'; +var PRODUCTION_HEADER = + [ + '/**', + ' * Animated v<%= version %>', + ' *', + ' * Copyright (c) 2013-present, Facebook, Inc.', + ' *', + ' * This source code is licensed under the MIT license found in the', + ' * LICENSE file in the root directory of this source tree.', + ' */', + ].join('\n') + '\n'; var babelOpts = { nonStandard: true, - loose: [ - 'es6.classes' - ], + loose: ['es6.classes'], stage: 1, plugins: [babelPluginDEV, babelPluginModules], _moduleMap: objectAssign({}, require('fbjs/module-map'), { - 'React': 'react', - }) + React: 'react', + }), }; var buildDist = function(opts) { var webpackOpts = { debug: opts.debug, externals: { - 'react': 'React', + react: 'React', }, module: { - loaders: [ - {test: /\.js$/, loader: 'babel'} - ], + loaders: [{test: /\.js$/, loader: 'babel'}], }, output: { filename: opts.output, - library: 'Animated' + library: 'Animated', }, plugins: [ new webpackStream.webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify( - opts.debug ? 'development' : 'production' + opts.debug ? 'development' : 'production', ), }), new webpackStream.webpack.optimize.OccurenceOrderPlugin(), - new webpackStream.webpack.optimize.DedupePlugin() - ] + new webpackStream.webpack.optimize.DedupePlugin(), + ], }; if (!opts.debug) { webpackOpts.plugins.push( @@ -79,9 +75,9 @@ var buildDist = function(opts) { compress: { hoist_vars: true, screw_ie8: true, - warnings: false - } - }) + warnings: false, + }, + }), ); } return webpackStream(webpackOpts, null, function(err, stats) { @@ -101,7 +97,7 @@ var paths = { src: [ '*src/**/*.js', '!src/**/__tests__/**/*.js', - '!src/**/__mocks__/**/*.js' + '!src/**/__mocks__/**/*.js', ], }; @@ -117,32 +113,36 @@ gulp.task('modules', function() { .pipe(gulp.dest(paths.lib)); }); -gulp.task('dist', ['modules'], function () { +gulp.task('dist', ['modules'], function() { var distOpts = { debug: true, - output: 'animated.js' + output: 'animated.js', }; return gulp .src(paths.entry) .pipe(buildDist(distOpts)) .pipe(derequire()) - .pipe(header(DEVELOPMENT_HEADER, { - version: process.env.npm_package_version - })) + .pipe( + header(DEVELOPMENT_HEADER, { + version: process.env.npm_package_version, + }), + ) .pipe(gulp.dest(paths.dist)); }); -gulp.task('dist:min', ['modules'], function () { +gulp.task('dist:min', ['modules'], function() { var distOpts = { debug: false, - output: 'animated.min.js' + output: 'animated.min.js', }; return gulp .src(paths.entry) .pipe(buildDist(distOpts)) - .pipe(header(PRODUCTION_HEADER, { - version: process.env.npm_package_version - })) + .pipe( + header(PRODUCTION_HEADER, { + version: process.env.npm_package_version, + }), + ) .pipe(gulp.dest(paths.dist)); }); diff --git a/Libraries/Animated/src/AnimatedWeb.js b/Libraries/Animated/src/AnimatedWeb.js index 5538eb9b64c383..e80023d73687a4 100644 --- a/Libraries/Animated/src/AnimatedWeb.js +++ b/Libraries/Animated/src/AnimatedWeb.js @@ -4,8 +4,10 @@ * 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 AnimatedImplementation = require('AnimatedImplementation'); diff --git a/Libraries/Animated/src/Easing.js b/Libraries/Animated/src/Easing.js index 5fb4478eef63f7..c5e54b24723ee9 100644 --- a/Libraries/Animated/src/Easing.js +++ b/Libraries/Animated/src/Easing.js @@ -4,8 +4,10 @@ * 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'; let ease; @@ -162,7 +164,7 @@ class Easing { */ static elastic(bounciness: number = 1): (t: number) => number { const p = bounciness * Math.PI; - return (t) => 1 - Math.pow(Math.cos(t * Math.PI / 2), 3) * Math.cos(t * p); + return t => 1 - Math.pow(Math.cos(t * Math.PI / 2), 3) * Math.cos(t * p); } /** @@ -177,7 +179,7 @@ class Easing { if (s === undefined) { s = 1.70158; } - return (t) => t * t * ((s + 1) * t - s); + return t => t * t * ((s + 1) * t - s); } /** @@ -215,7 +217,7 @@ class Easing { x1: number, y1: number, x2: number, - y2: number + y2: number, ): (t: number) => number { const _bezier = require('bezier'); return _bezier(x1, y1, x2, y2); @@ -224,19 +226,15 @@ class Easing { /** * Runs an easing function forwards. */ - static in( - easing: (t: number) => number, - ): (t: number) => number { + static in(easing: (t: number) => number): (t: number) => number { return easing; } /** * Runs an easing function backwards. */ - static out( - easing: (t: number) => number, - ): (t: number) => number { - return (t) => 1 - easing(1 - t); + static out(easing: (t: number) => number): (t: number) => number { + return t => 1 - easing(1 - t); } /** @@ -244,10 +242,8 @@ class Easing { * forwards for half of the duration, then backwards for the rest of the * duration. */ - static inOut( - easing: (t: number) => number, - ): (t: number) => number { - return (t) => { + static inOut(easing: (t: number) => number): (t: number) => number { + return t => { if (t < 0.5) { return easing(t * 2) / 2; } diff --git a/Libraries/Animated/src/SpringConfig.js b/Libraries/Animated/src/SpringConfig.js index b71fda2eacce74..ca25a115cb0917 100644 --- a/Libraries/Animated/src/SpringConfig.js +++ b/Libraries/Animated/src/SpringConfig.js @@ -4,6 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * + * @format * @flow */ @@ -41,7 +42,7 @@ function fromBouncinessAndSpeed( } function projectNormal(n, start, end) { - return start + (n * (end - start)); + return start + n * (end - start); } function linearInterpolation(t, start, end) { @@ -53,18 +54,20 @@ function fromBouncinessAndSpeed( } function b3Friction1(x) { - return (0.0007 * Math.pow(x, 3)) - - (0.031 * Math.pow(x, 2)) + 0.64 * x + 1.28; + return 0.0007 * Math.pow(x, 3) - 0.031 * Math.pow(x, 2) + 0.64 * x + 1.28; } function b3Friction2(x) { - return (0.000044 * Math.pow(x, 3)) - - (0.006 * Math.pow(x, 2)) + 0.36 * x + 2; + return 0.000044 * Math.pow(x, 3) - 0.006 * Math.pow(x, 2) + 0.36 * x + 2; } function b3Friction3(x) { - return (0.00000045 * Math.pow(x, 3)) - - (0.000332 * Math.pow(x, 2)) + 0.1078 * x + 5.84; + return ( + 0.00000045 * Math.pow(x, 3) - + 0.000332 * Math.pow(x, 2) + + 0.1078 * x + + 5.84 + ); } function b3Nobounce(tension) { @@ -84,7 +87,7 @@ function fromBouncinessAndSpeed( const bouncyFriction = quadraticOutInterpolation( b, b3Nobounce(bouncyTension), - 0.01 + 0.01, ); return { diff --git a/Libraries/Animated/src/__tests__/Animated-test.js b/Libraries/Animated/src/__tests__/Animated-test.js index 36b4d2a40a5042..1c2066bfdc5e56 100644 --- a/Libraries/Animated/src/__tests__/Animated-test.js +++ b/Libraries/Animated/src/__tests__/Animated-test.js @@ -4,8 +4,10 @@ * 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'; let Animated = require('Animated'); @@ -15,29 +17,33 @@ describe('Animated tests', () => { }); describe('Animated', () => { - it('works end to end', () => { const anim = new Animated.Value(0); const callback = jest.fn(); - const node = new Animated.__PropsOnlyForTests({ - style: { - backgroundColor: 'red', - opacity: anim, - transform: [ - {translateX: anim.interpolate({ - inputRange: [0, 1], - outputRange: [100, 200], - })}, - {scale: anim}, - ], - shadowOffset: { - width: anim, - height: anim, + const node = new Animated.__PropsOnlyForTests( + { + style: { + backgroundColor: 'red', + opacity: anim, + transform: [ + { + translateX: anim.interpolate({ + inputRange: [0, 1], + outputRange: [100, 200], + }), + }, + {scale: anim}, + ], + shadowOffset: { + width: anim, + height: anim, + }, }, - } - }, callback); + }, + callback, + ); expect(anim.__getChildren().length).toBe(3); @@ -45,10 +51,7 @@ describe('Animated tests', () => { style: { backgroundColor: 'red', opacity: 0, - transform: [ - {translateX: 100}, - {scale: 0}, - ], + transform: [{translateX: 100}, {scale: 0}], shadowOffset: { width: 0, height: 0, @@ -64,10 +67,7 @@ describe('Animated tests', () => { style: { backgroundColor: 'red', opacity: 0.5, - transform: [ - {translateX: 150}, - {scale: 0.5}, - ], + transform: [{translateX: 150}, {scale: 0.5}], shadowOffset: { width: 0.5, height: 0.5, @@ -107,7 +107,6 @@ describe('Animated tests', () => { expect(anim.__detach).toBeCalled(); }); - it('stops animation when detached', () => { const anim = new Animated.Value(0); const callback = jest.fn(); @@ -141,7 +140,8 @@ describe('Animated tests', () => { anim.addListener(listener); Animated.spring(anim, {toValue: 15}).start(); jest.runAllTimers(); - const lastValue = listener.mock.calls[listener.mock.calls.length - 2][0].value; + const lastValue = + listener.mock.calls[listener.mock.calls.length - 2][0].value; expect(lastValue).not.toBe(15); expect(lastValue).toBeCloseTo(15); expect(anim.__getValue()).toBe(15); @@ -151,9 +151,14 @@ describe('Animated tests', () => { const anim = new Animated.Value(0); const listener = jest.fn(); anim.addListener(listener); - Animated.spring(anim, {stiffness: 8000, damping: 2000, toValue: 15}).start(); + Animated.spring(anim, { + stiffness: 8000, + damping: 2000, + toValue: 15, + }).start(); jest.runAllTimers(); - const lastValue = listener.mock.calls[listener.mock.calls.length - 2][0].value; + const lastValue = + listener.mock.calls[listener.mock.calls.length - 2][0].value; expect(lastValue).not.toBe(15); expect(lastValue).toBeCloseTo(15); expect(anim.__getValue()).toBe(15); @@ -164,9 +169,7 @@ describe('Animated tests', () => { }); }); - describe('Animated Sequence', () => { - it('works with an empty sequence', () => { const cb = jest.fn(); Animated.sequence([]).start(cb); @@ -232,9 +235,12 @@ describe('Animated tests', () => { }); describe('Animated Loop', () => { - it('loops indefinitely if config not specified', () => { - const animation = {start: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; + const animation = { + start: jest.fn(), + reset: jest.fn(), + _isUsingNativeDriver: () => false, + }; const cb = jest.fn(); const loop = Animated.loop(animation); @@ -261,10 +267,14 @@ describe('Animated tests', () => { }); it('loops indefinitely if iterations is -1', () => { - const animation = {start: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; + const animation = { + start: jest.fn(), + reset: jest.fn(), + _isUsingNativeDriver: () => false, + }; const cb = jest.fn(); - const loop = Animated.loop(animation, { iterations: -1 }); + const loop = Animated.loop(animation, {iterations: -1}); expect(animation.start).not.toBeCalled(); @@ -288,10 +298,14 @@ describe('Animated tests', () => { }); it('loops indefinitely if iterations not specified', () => { - const animation = {start: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; + const animation = { + start: jest.fn(), + reset: jest.fn(), + _isUsingNativeDriver: () => false, + }; const cb = jest.fn(); - const loop = Animated.loop(animation, { anotherKey: 'value' }); + const loop = Animated.loop(animation, {anotherKey: 'value'}); expect(animation.start).not.toBeCalled(); @@ -315,10 +329,14 @@ describe('Animated tests', () => { }); it('loops three times if iterations is 3', () => { - const animation = {start: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; + const animation = { + start: jest.fn(), + reset: jest.fn(), + _isUsingNativeDriver: () => false, + }; const cb = jest.fn(); - const loop = Animated.loop(animation, { iterations: 3 }); + const loop = Animated.loop(animation, {iterations: 3}); expect(animation.start).not.toBeCalled(); @@ -342,10 +360,14 @@ describe('Animated tests', () => { }); it('does not loop if iterations is 1', () => { - const animation = {start: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; + const animation = { + start: jest.fn(), + reset: jest.fn(), + _isUsingNativeDriver: () => false, + }; const cb = jest.fn(); - const loop = Animated.loop(animation, { iterations: 1 }); + const loop = Animated.loop(animation, {iterations: 1}); expect(animation.start).not.toBeCalled(); @@ -359,10 +381,14 @@ describe('Animated tests', () => { }); it('does not animate if iterations is 0', () => { - const animation = {start: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; + const animation = { + start: jest.fn(), + reset: jest.fn(), + _isUsingNativeDriver: () => false, + }; const cb = jest.fn(); - const loop = Animated.loop(animation, { iterations: 0 }); + const loop = Animated.loop(animation, {iterations: 0}); expect(animation.start).not.toBeCalled(); @@ -373,7 +399,11 @@ describe('Animated tests', () => { }); it('supports interrupting an indefinite loop', () => { - const animation = {start: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; + const animation = { + start: jest.fn(), + reset: jest.fn(), + _isUsingNativeDriver: () => false, + }; const cb = jest.fn(); Animated.loop(animation).start(cb); @@ -391,7 +421,12 @@ describe('Animated tests', () => { }); it('supports stopping loop', () => { - const animation = {start: jest.fn(), stop: jest.fn(), reset: jest.fn(), _isUsingNativeDriver: () => false}; + const animation = { + start: jest.fn(), + stop: jest.fn(), + reset: jest.fn(), + _isUsingNativeDriver: () => false, + }; const cb = jest.fn(); const loop = Animated.loop(animation); @@ -409,7 +444,6 @@ describe('Animated tests', () => { }); describe('Animated Parallel', () => { - it('works with an empty parallel', () => { const cb = jest.fn(); Animated.parallel([]).start(cb); @@ -470,7 +504,6 @@ describe('Animated tests', () => { expect(cb).toBeCalledWith({finished: false}); }); - it('does not call stop more than once when stopping', () => { const anim1 = {start: jest.fn(), stop: jest.fn()}; const anim2 = {start: jest.fn(), stop: jest.fn()}; @@ -504,10 +537,7 @@ describe('Animated tests', () => { it('should call anim after delay in sequence', () => { const anim = {start: jest.fn(), stop: jest.fn()}; const cb = jest.fn(); - Animated.sequence([ - Animated.delay(1000), - anim, - ]).start(cb); + Animated.sequence([Animated.delay(1000), anim]).start(cb); jest.runAllTimers(); expect(anim.start.mock.calls.length).toBe(1); expect(cb).not.toBeCalled(); @@ -529,19 +559,14 @@ describe('Animated tests', () => { describe('Animated Events', () => { it('should map events', () => { const value = new Animated.Value(0); - const handler = Animated.event( - [null, {state: {foo: value}}], - ); + const handler = Animated.event([null, {state: {foo: value}}]); handler({bar: 'ignoreBar'}, {state: {baz: 'ignoreBaz', foo: 42}}); expect(value.__getValue()).toBe(42); }); it('should call listeners', () => { const value = new Animated.Value(0); const listener = jest.fn(); - const handler = Animated.event( - [{foo: value}], - {listener}, - ); + const handler = Animated.event([{foo: value}], {listener}); handler({foo: 42}); expect(value.__getValue()).toBe(42); expect(listener.mock.calls.length).toBe(1); @@ -550,10 +575,7 @@ describe('Animated tests', () => { it('should call forked event listeners', () => { const value = new Animated.Value(0); const listener = jest.fn(); - const handler = Animated.event( - [{foo: value}], - {listener}, - ); + const handler = Animated.event([{foo: value}], {listener}); const listener2 = jest.fn(); const forkedHandler = Animated.forkEvent(handler, listener2); forkedHandler({foo: 42}); @@ -577,7 +599,7 @@ describe('Animated tests', () => { InteractionManager = require('InteractionManager'); }); - afterEach(()=> { + afterEach(() => { jest.unmock('InteractionManager'); }); @@ -633,7 +655,7 @@ describe('Animated tests', () => { Animated.timing(value2, { toValue: value1.interpolate({ inputRange: [0, 2], - outputRange: [0, 1] + outputRange: [0, 1], }), duration: 0, }).start(); @@ -665,24 +687,24 @@ describe('Animated tests', () => { const callback = jest.fn(); - const node = new Animated.__PropsOnlyForTests({ - style: { - opacity: vec.x.interpolate({ - inputRange: [0, 42], - outputRange: [0.2, 0.8], - }), - transform: vec.getTranslateTransform(), - ...vec.getLayout(), - } - }, callback); + const node = new Animated.__PropsOnlyForTests( + { + style: { + opacity: vec.x.interpolate({ + inputRange: [0, 42], + outputRange: [0.2, 0.8], + }), + transform: vec.getTranslateTransform(), + ...vec.getLayout(), + }, + }, + callback, + ); expect(node.__getValue()).toEqual({ style: { opacity: 0.2, - transform: [ - {translateX: 0}, - {translateY: 0}, - ], + transform: [{translateX: 0}, {translateY: 0}], left: 0, top: 0, }, @@ -695,10 +717,7 @@ describe('Animated tests', () => { expect(node.__getValue()).toEqual({ style: { opacity: 0.8, - transform: [ - {translateX: 42}, - {translateY: 1492}, - ], + transform: [{translateX: 42}, {translateY: 1492}], left: 42, top: 1492, }, @@ -767,7 +786,7 @@ describe('Animated tests', () => { it('should removeAll', () => { const value1 = new Animated.Value(0); const listener = jest.fn(); - [1,2,3,4].forEach(() => value1.addListener(listener)); + [1, 2, 3, 4].forEach(() => value1.addListener(listener)); value1.setValue(42); expect(listener.mock.calls.length).toBe(4); expect(listener).toBeCalledWith({value: 42}); diff --git a/Libraries/Animated/src/__tests__/AnimatedNative-test.js b/Libraries/Animated/src/__tests__/AnimatedNative-test.js index f04d5afb1429a3..8f59d33c57cbb0 100644 --- a/Libraries/Animated/src/__tests__/AnimatedNative-test.js +++ b/Libraries/Animated/src/__tests__/AnimatedNative-test.js @@ -4,8 +4,10 @@ * 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 ClassComponentMock = class {}; @@ -39,7 +41,6 @@ function createAndMountComponent(ComponentClass, props) { } describe('Native Animated', () => { - const nativeAnimatedModule = require('NativeModules').NativeAnimatedModule; beforeEach(() => { @@ -64,7 +65,11 @@ describe('Native Animated', () => { describe('Animated Value', () => { it('proxies `setValue` correctly', () => { const anim = new Animated.Value(0); - Animated.timing(anim, {toValue: 10, duration: 1000, useNativeDriver: true}).start(); + Animated.timing(anim, { + toValue: 10, + duration: 1000, + useNativeDriver: true, + }).start(); const c = createAndMountComponent(Animated.View, { style: { @@ -82,7 +87,10 @@ describe('Native Animated', () => { anim.setValue(0.5); - expect(nativeAnimatedModule.setAnimatedNodeValue).toBeCalledWith(expect.any(Number), 0.5); + expect(nativeAnimatedModule.setAnimatedNodeValue).toBeCalledWith( + expect.any(Number), + 0.5, + ); expect(c.refs.node.setNativeProps).not.toHaveBeenCalled(); }); @@ -101,8 +109,10 @@ describe('Native Animated', () => { {type: 'value', value: 0, offset: 10}, ); anim.setOffset(20); - expect(nativeAnimatedModule.setAnimatedNodeOffset) - .toBeCalledWith(expect.any(Number), 20); + expect(nativeAnimatedModule.setAnimatedNodeOffset).toBeCalledWith( + expect.any(Number), + 20, + ); }); it('should flatten offset', () => { @@ -119,8 +129,9 @@ describe('Native Animated', () => { {type: 'value', value: 0, offset: 0}, ); anim.flattenOffset(); - expect(nativeAnimatedModule.flattenAnimatedNodeOffset) - .toBeCalledWith(expect.any(Number)); + expect(nativeAnimatedModule.flattenAnimatedNodeOffset).toBeCalledWith( + expect.any(Number), + ); }); it('should extract offset', () => { @@ -137,8 +148,9 @@ describe('Native Animated', () => { {type: 'value', value: 0, offset: 0}, ); anim.extractOffset(); - expect(nativeAnimatedModule.extractAnimatedNodeOffset) - .toBeCalledWith(expect.any(Number)); + expect(nativeAnimatedModule.extractAnimatedNodeOffset).toBeCalledWith( + expect.any(Number), + ); }); }); @@ -148,33 +160,35 @@ describe('Native Animated', () => { value1.__makeNative(); const listener = jest.fn(); const id = value1.addListener(listener); - expect(nativeAnimatedModule.startListeningToAnimatedNodeValue) - .toHaveBeenCalledWith(value1.__getNativeTag()); + expect( + nativeAnimatedModule.startListeningToAnimatedNodeValue, + ).toHaveBeenCalledWith(value1.__getNativeTag()); - NativeAnimatedHelper.nativeEventEmitter.emit( - 'onAnimatedValueUpdate', - {value: 42, tag: value1.__getNativeTag()}, - ); + NativeAnimatedHelper.nativeEventEmitter.emit('onAnimatedValueUpdate', { + value: 42, + tag: value1.__getNativeTag(), + }); expect(listener).toHaveBeenCalledTimes(1); expect(listener).toBeCalledWith({value: 42}); expect(value1.__getValue()).toBe(42); - NativeAnimatedHelper.nativeEventEmitter.emit( - 'onAnimatedValueUpdate', - {value: 7, tag: value1.__getNativeTag()}, - ); + NativeAnimatedHelper.nativeEventEmitter.emit('onAnimatedValueUpdate', { + value: 7, + tag: value1.__getNativeTag(), + }); expect(listener).toHaveBeenCalledTimes(2); expect(listener).toBeCalledWith({value: 7}); expect(value1.__getValue()).toBe(7); value1.removeListener(id); - expect(nativeAnimatedModule.stopListeningToAnimatedNodeValue) - .toHaveBeenCalledWith(value1.__getNativeTag()); + expect( + nativeAnimatedModule.stopListeningToAnimatedNodeValue, + ).toHaveBeenCalledWith(value1.__getNativeTag()); - NativeAnimatedHelper.nativeEventEmitter.emit( - 'onAnimatedValueUpdate', - {value: 1492, tag: value1.__getNativeTag()}, - ); + NativeAnimatedHelper.nativeEventEmitter.emit('onAnimatedValueUpdate', { + value: 1492, + tag: value1.__getNativeTag(), + }); expect(listener).toHaveBeenCalledTimes(2); expect(value1.__getValue()).toBe(7); }); @@ -183,25 +197,27 @@ describe('Native Animated', () => { const value1 = new Animated.Value(0); value1.__makeNative(); const listener = jest.fn(); - [1,2,3,4].forEach(() => value1.addListener(listener)); - expect(nativeAnimatedModule.startListeningToAnimatedNodeValue) - .toHaveBeenCalledWith(value1.__getNativeTag()); - - NativeAnimatedHelper.nativeEventEmitter.emit( - 'onAnimatedValueUpdate', - {value: 42, tag: value1.__getNativeTag()}, - ); + [1, 2, 3, 4].forEach(() => value1.addListener(listener)); + expect( + nativeAnimatedModule.startListeningToAnimatedNodeValue, + ).toHaveBeenCalledWith(value1.__getNativeTag()); + + NativeAnimatedHelper.nativeEventEmitter.emit('onAnimatedValueUpdate', { + value: 42, + tag: value1.__getNativeTag(), + }); expect(listener).toHaveBeenCalledTimes(4); expect(listener).toBeCalledWith({value: 42}); value1.removeAllListeners(); - expect(nativeAnimatedModule.stopListeningToAnimatedNodeValue) - .toHaveBeenCalledWith(value1.__getNativeTag()); + expect( + nativeAnimatedModule.stopListeningToAnimatedNodeValue, + ).toHaveBeenCalledWith(value1.__getNativeTag()); - NativeAnimatedHelper.nativeEventEmitter.emit( - 'onAnimatedValueUpdate', - {value: 7, tag: value1.__getNativeTag()}, - ); + NativeAnimatedHelper.nativeEventEmitter.emit('onAnimatedValueUpdate', { + value: 7, + tag: value1.__getNativeTag(), + }); expect(listener).toHaveBeenCalledTimes(4); }); }); @@ -210,15 +226,17 @@ describe('Native Animated', () => { it('should map events', () => { const value = new Animated.Value(0); value.__makeNative(); - const event = Animated.event( - [{nativeEvent: {state: {foo: value}}}], - {useNativeDriver: true}, - ); + const event = Animated.event([{nativeEvent: {state: {foo: value}}}], { + useNativeDriver: true, + }); const c = createAndMountComponent(Animated.View, {onTouchMove: event}); expect(nativeAnimatedModule.addAnimatedEventToView).toBeCalledWith( expect.any(Number), 'onTouchMove', - {nativeEventPath: ['state', 'foo'], animatedValueTag: value.__getNativeTag()}, + { + nativeEventPath: ['state', 'foo'], + animatedValueTag: value.__getNativeTag(), + }, ); c.componentWillUnmount(); @@ -232,12 +250,12 @@ describe('Native Animated', () => { it('should throw on invalid event path', () => { const value = new Animated.Value(0); value.__makeNative(); - const event = Animated.event( - [{notNativeEvent: {foo: value}}], - {useNativeDriver: true}, - ); - expect(() => createAndMountComponent(Animated.View, {onTouchMove: event})) - .toThrowError(/nativeEvent/); + const event = Animated.event([{notNativeEvent: {foo: value}}], { + useNativeDriver: true, + }); + expect(() => + createAndMountComponent(Animated.View, {onTouchMove: event}), + ).toThrowError(/nativeEvent/); expect(nativeAnimatedModule.addAnimatedEventToView).not.toBeCalled(); }); @@ -245,10 +263,10 @@ describe('Native Animated', () => { const value = new Animated.Value(0); value.__makeNative(); const listener = jest.fn(); - const event = Animated.event( - [{nativeEvent: {foo: value}}], - {useNativeDriver: true, listener}, - ); + const event = Animated.event([{nativeEvent: {foo: value}}], { + useNativeDriver: true, + listener, + }); const handler = event.__getHandler(); handler({foo: 42}); expect(listener).toHaveBeenCalledTimes(1); @@ -265,21 +283,34 @@ describe('Native Animated', () => { }, }); - Animated.timing(anim, {toValue: 10, duration: 1000, useNativeDriver: true}).start(); + Animated.timing(anim, { + toValue: 10, + duration: 1000, + useNativeDriver: true, + }).start(); c.componentWillUnmount(); expect(nativeAnimatedModule.createAnimatedNode).toHaveBeenCalledTimes(3); - expect(nativeAnimatedModule.connectAnimatedNodes).toHaveBeenCalledTimes(2); + expect(nativeAnimatedModule.connectAnimatedNodes).toHaveBeenCalledTimes( + 2, + ); expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith( expect.any(Number), expect.any(Number), - {type: 'frames', frames: expect.any(Array), toValue: expect.any(Number), iterations: 1}, - expect.any(Function) + { + type: 'frames', + frames: expect.any(Array), + toValue: expect.any(Number), + iterations: 1, + }, + expect.any(Function), ); - expect(nativeAnimatedModule.disconnectAnimatedNodes).toHaveBeenCalledTimes(2); + expect( + nativeAnimatedModule.disconnectAnimatedNodes, + ).toHaveBeenCalledTimes(2); expect(nativeAnimatedModule.dropAnimatedNode).toHaveBeenCalledTimes(3); }); @@ -291,14 +322,24 @@ describe('Native Animated', () => { }, }); - Animated.timing(anim, {toValue: 10, duration: 1000, useNativeDriver: true}).start(); + Animated.timing(anim, { + toValue: 10, + duration: 1000, + useNativeDriver: true, + }).start(); - expect(nativeAnimatedModule.createAnimatedNode) - .toBeCalledWith(expect.any(Number), {type: 'value', value: 0, offset: 0}); - expect(nativeAnimatedModule.createAnimatedNode) - .toBeCalledWith(expect.any(Number), {type: 'style', style: {opacity: expect.any(Number)}}); - expect(nativeAnimatedModule.createAnimatedNode) - .toBeCalledWith(expect.any(Number), {type: 'props', props: {style: expect.any(Number)}}); + expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith( + expect.any(Number), + {type: 'value', value: 0, offset: 0}, + ); + expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith( + expect.any(Number), + {type: 'style', style: {opacity: expect.any(Number)}}, + ); + expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith( + expect.any(Number), + {type: 'props', props: {style: expect.any(Number)}}, + ); }); it('sends a valid graph description for Animated.add nodes', () => { @@ -318,19 +359,23 @@ describe('Native Animated', () => { {type: 'addition', input: expect.any(Array)}, ); const additionCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter( - (call) => call[1].type === 'addition' + call => call[1].type === 'addition', ); expect(additionCalls.length).toBe(1); const additionCall = additionCalls[0]; const additionNodeTag = additionCall[0]; const additionConnectionCalls = nativeAnimatedModule.connectAnimatedNodes.mock.calls.filter( - (call) => call[1] === additionNodeTag + call => call[1] === additionNodeTag, ); expect(additionConnectionCalls.length).toBe(2); - expect(nativeAnimatedModule.createAnimatedNode) - .toBeCalledWith(additionCall[1].input[0], {type: 'value', value: 1, offset: 0}); - expect(nativeAnimatedModule.createAnimatedNode) - .toBeCalledWith(additionCall[1].input[1], {type: 'value', value: 2, offset: 0}); + expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith( + additionCall[1].input[0], + {type: 'value', value: 1, offset: 0}, + ); + expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith( + additionCall[1].input[1], + {type: 'value', value: 2, offset: 0}, + ); }); it('sends a valid graph description for Animated.subtract nodes', () => { @@ -350,19 +395,23 @@ describe('Native Animated', () => { {type: 'subtraction', input: expect.any(Array)}, ); const subtractionCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter( - (call) => call[1].type === 'subtraction' + call => call[1].type === 'subtraction', ); expect(subtractionCalls.length).toBe(1); const subtractionCall = subtractionCalls[0]; const subtractionNodeTag = subtractionCall[0]; const subtractionConnectionCalls = nativeAnimatedModule.connectAnimatedNodes.mock.calls.filter( - (call) => call[1] === subtractionNodeTag + call => call[1] === subtractionNodeTag, ); expect(subtractionConnectionCalls.length).toBe(2); - expect(nativeAnimatedModule.createAnimatedNode) - .toBeCalledWith(subtractionCall[1].input[0], {type: 'value', value: 2, offset: 0}); - expect(nativeAnimatedModule.createAnimatedNode) - .toBeCalledWith(subtractionCall[1].input[1], {type: 'value', value: 1, offset: 0}); + expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith( + subtractionCall[1].input[0], + {type: 'value', value: 2, offset: 0}, + ); + expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith( + subtractionCall[1].input[1], + {type: 'value', value: 1, offset: 0}, + ); }); it('sends a valid graph description for Animated.multiply nodes', () => { @@ -382,19 +431,23 @@ describe('Native Animated', () => { {type: 'multiplication', input: expect.any(Array)}, ); const multiplicationCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter( - (call) => call[1].type === 'multiplication' + call => call[1].type === 'multiplication', ); expect(multiplicationCalls.length).toBe(1); const multiplicationCall = multiplicationCalls[0]; const multiplicationNodeTag = multiplicationCall[0]; const multiplicationConnectionCalls = nativeAnimatedModule.connectAnimatedNodes.mock.calls.filter( - (call) => call[1] === multiplicationNodeTag + call => call[1] === multiplicationNodeTag, ); expect(multiplicationConnectionCalls.length).toBe(2); - expect(nativeAnimatedModule.createAnimatedNode) - .toBeCalledWith(multiplicationCall[1].input[0], {type: 'value', value: 2, offset: 0}); - expect(nativeAnimatedModule.createAnimatedNode) - .toBeCalledWith(multiplicationCall[1].input[1], {type: 'value', value: 1, offset: 0}); + expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith( + multiplicationCall[1].input[0], + {type: 'value', value: 2, offset: 0}, + ); + expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith( + multiplicationCall[1].input[1], + {type: 'value', value: 1, offset: 0}, + ); }); it('sends a valid graph description for Animated.divide nodes', () => { @@ -409,22 +462,28 @@ describe('Native Animated', () => { }, }); - expect(nativeAnimatedModule.createAnimatedNode) - .toBeCalledWith(expect.any(Number), {type: 'division', input: expect.any(Array)}); + expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith( + expect.any(Number), + {type: 'division', input: expect.any(Array)}, + ); const divisionCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter( - (call) => call[1].type === 'division' + call => call[1].type === 'division', ); expect(divisionCalls.length).toBe(1); const divisionCall = divisionCalls[0]; const divisionNodeTag = divisionCall[0]; const divisionConnectionCalls = nativeAnimatedModule.connectAnimatedNodes.mock.calls.filter( - (call) => call[1] === divisionNodeTag + call => call[1] === divisionNodeTag, ); expect(divisionConnectionCalls.length).toBe(2); - expect(nativeAnimatedModule.createAnimatedNode) - .toBeCalledWith(divisionCall[1].input[0], {type: 'value', value: 4, offset: 0}); - expect(nativeAnimatedModule.createAnimatedNode) - .toBeCalledWith(divisionCall[1].input[1], {type: 'value', value: 2, offset: 0}); + expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith( + divisionCall[1].input[0], + {type: 'value', value: 4, offset: 0}, + ); + expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith( + divisionCall[1].input[1], + {type: 'value', value: 2, offset: 0}, + ); }); it('sends a valid graph description for Animated.modulo nodes', () => { @@ -442,17 +501,19 @@ describe('Native Animated', () => { {type: 'modulus', modulus: 4, input: expect.any(Number)}, ); const moduloCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter( - (call) => call[1].type === 'modulus' + call => call[1].type === 'modulus', ); expect(moduloCalls.length).toBe(1); const moduloCall = moduloCalls[0]; const moduloNodeTag = moduloCall[0]; const moduloConnectionCalls = nativeAnimatedModule.connectAnimatedNodes.mock.calls.filter( - (call) => call[1] === moduloNodeTag + call => call[1] === moduloNodeTag, ); expect(moduloConnectionCalls.length).toBe(1); - expect(nativeAnimatedModule.createAnimatedNode) - .toBeCalledWith(moduloCall[1].input, {type: 'value', value: 4, offset: 0}); + expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith( + moduloCall[1].input, + {type: 'value', value: 4, offset: 0}, + ); }); it('sends a valid graph description for interpolate() nodes', () => { @@ -470,23 +531,28 @@ describe('Native Animated', () => { expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith( expect.any(Number), - {type: 'value', value: 10, offset: 0} + {type: 'value', value: 10, offset: 0}, ); - expect(nativeAnimatedModule.createAnimatedNode) - .toBeCalledWith(expect.any(Number), { + expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith( + expect.any(Number), + { type: 'interpolation', inputRange: [10, 20], outputRange: [0, 1], extrapolateLeft: 'extend', extrapolateRight: 'extend', - }); + }, + ); const interpolationNodeTag = nativeAnimatedModule.createAnimatedNode.mock.calls.find( - (call) => call[1].type === 'interpolation' + call => call[1].type === 'interpolation', )[0]; const valueNodeTag = nativeAnimatedModule.createAnimatedNode.mock.calls.find( - (call) => call[1].type === 'value' + call => call[1].type === 'value', )[0]; - expect(nativeAnimatedModule.connectAnimatedNodes).toBeCalledWith(valueNodeTag, interpolationNodeTag); + expect(nativeAnimatedModule.connectAnimatedNodes).toBeCalledWith( + valueNodeTag, + interpolationNodeTag, + ); }); it('sends a valid graph description for transform nodes', () => { @@ -503,15 +569,18 @@ describe('Native Animated', () => { expect.any(Number), { type: 'transform', - transforms: [{ - nodeTag: expect.any(Number), - property: 'translateX', - type: 'animated', - }, { - value: 2, - property: 'scale', - type: 'static', - }], + transforms: [ + { + nodeTag: expect.any(Number), + property: 'translateX', + type: 'animated', + }, + { + value: 2, + property: 'scale', + type: 'static', + }, + ], }, ); }); @@ -531,20 +600,22 @@ describe('Native Animated', () => { {type: 'diffclamp', input: expect.any(Number), max: 20, min: 0}, ); const diffClampCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter( - (call) => call[1].type === 'diffclamp' + call => call[1].type === 'diffclamp', ); expect(diffClampCalls.length).toBe(1); const diffClampCall = diffClampCalls[0]; const diffClampNodeTag = diffClampCall[0]; const diffClampConnectionCalls = nativeAnimatedModule.connectAnimatedNodes.mock.calls.filter( - (call) => call[1] === diffClampNodeTag + call => call[1] === diffClampNodeTag, ); expect(diffClampConnectionCalls.length).toBe(1); - expect(nativeAnimatedModule.createAnimatedNode) - .toBeCalledWith(diffClampCall[1].input, {type: 'value', value: 2, offset: 0}); + expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith( + diffClampCall[1].input, + {type: 'value', value: 2, offset: 0}, + ); }); - it('doesn\'t call into native API if useNativeDriver is set to false', () => { + it("doesn't call into native API if useNativeDriver is set to false", () => { const anim = new Animated.Value(0); const c = createAndMountComponent(Animated.View, { @@ -553,7 +624,11 @@ describe('Native Animated', () => { }, }); - Animated.timing(anim, {toValue: 10, duration: 1000, useNativeDriver: false}).start(); + Animated.timing(anim, { + toValue: 10, + duration: 1000, + useNativeDriver: false, + }).start(); c.componentWillUnmount(); @@ -569,10 +644,18 @@ describe('Native Animated', () => { }, }); - Animated.timing(anim, {toValue: 10, duration: 50, useNativeDriver: true}).start(); + Animated.timing(anim, { + toValue: 10, + duration: 50, + useNativeDriver: true, + }).start(); jest.runAllTimers(); - Animated.timing(anim, {toValue: 4, duration: 500, useNativeDriver: false}).start(); + Animated.timing(anim, { + toValue: 4, + duration: 500, + useNativeDriver: false, + }).start(); expect(jest.runAllTimers).toThrow(); }); @@ -585,7 +668,11 @@ describe('Native Animated', () => { }, }); - const animation = Animated.timing(anim, {toValue: 10, duration: 50, useNativeDriver: true}); + const animation = Animated.timing(anim, { + toValue: 10, + duration: 50, + useNativeDriver: true, + }); expect(animation.start).toThrowError(/left/); }); @@ -603,29 +690,47 @@ describe('Native Animated', () => { removeClippedSubviews: true, }); - expect(nativeAnimatedModule.createAnimatedNode) - .toBeCalledWith(expect.any(Number), { type: 'style', style: { opacity: expect.any(Number) }}); - expect(nativeAnimatedModule.createAnimatedNode) - .toBeCalledWith(expect.any(Number), { type: 'props', props: { style: expect.any(Number) }}); + expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith( + expect.any(Number), + {type: 'style', style: {opacity: expect.any(Number)}}, + ); + expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith( + expect.any(Number), + {type: 'props', props: {style: expect.any(Number)}}, + ); }); }); describe('Animations', () => { it('sends a valid timing animation description', () => { const anim = new Animated.Value(0); - Animated.timing(anim, {toValue: 10, duration: 1000, useNativeDriver: true}).start(); + Animated.timing(anim, { + toValue: 10, + duration: 1000, + useNativeDriver: true, + }).start(); expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith( expect.any(Number), expect.any(Number), - {type: 'frames', frames: expect.any(Array), toValue: expect.any(Number), iterations: 1}, - expect.any(Function) + { + type: 'frames', + frames: expect.any(Array), + toValue: expect.any(Number), + iterations: 1, + }, + expect.any(Function), ); }); it('sends a valid spring animation description', () => { const anim = new Animated.Value(0); - Animated.spring(anim, {toValue: 10, friction: 5, tension: 164, useNativeDriver: true}).start(); + Animated.spring(anim, { + toValue: 10, + friction: 5, + tension: 164, + useNativeDriver: true, + }).start(); expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith( expect.any(Number), expect.any(Number), @@ -641,7 +746,7 @@ describe('Native Animated', () => { toValue: 10, iterations: 1, }, - expect.any(Function) + expect.any(Function), ); Animated.spring(anim, { @@ -649,7 +754,7 @@ describe('Native Animated', () => { stiffness: 1000, damping: 500, mass: 3, - useNativeDriver: true + useNativeDriver: true, }).start(); expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith( expect.any(Number), @@ -666,10 +771,15 @@ describe('Native Animated', () => { toValue: 10, iterations: 1, }, - expect.any(Function) + expect.any(Function), ); - Animated.spring(anim, {toValue: 10, bounciness: 8, speed: 10, useNativeDriver: true}).start(); + Animated.spring(anim, { + toValue: 10, + bounciness: 8, + speed: 10, + useNativeDriver: true, + }).start(); expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith( expect.any(Number), expect.any(Number), @@ -685,49 +795,67 @@ describe('Native Animated', () => { toValue: 10, iterations: 1, }, - expect.any(Function) + expect.any(Function), ); }); it('sends a valid decay animation description', () => { const anim = new Animated.Value(0); - Animated.decay(anim, {velocity: 10, deceleration: 0.1, useNativeDriver: true}).start(); + Animated.decay(anim, { + velocity: 10, + deceleration: 0.1, + useNativeDriver: true, + }).start(); expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith( expect.any(Number), expect.any(Number), {type: 'decay', deceleration: 0.1, velocity: 10, iterations: 1}, - expect.any(Function) + expect.any(Function), ); }); it('works with Animated.loop', () => { const anim = new Animated.Value(0); Animated.loop( - Animated.decay(anim, {velocity: 10, deceleration: 0.1, useNativeDriver: true}), - { iterations: 10 }, + Animated.decay(anim, { + velocity: 10, + deceleration: 0.1, + useNativeDriver: true, + }), + {iterations: 10}, ).start(); expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith( expect.any(Number), expect.any(Number), {type: 'decay', deceleration: 0.1, velocity: 10, iterations: 10}, - expect.any(Function) + expect.any(Function), ); }); it('sends stopAnimation command to native', () => { const value = new Animated.Value(0); - const animation = Animated.timing(value, {toValue: 10, duration: 50, useNativeDriver: true}); + const animation = Animated.timing(value, { + toValue: 10, + duration: 50, + useNativeDriver: true, + }); animation.start(); expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith( expect.any(Number), expect.any(Number), - {type: 'frames', frames: expect.any(Array), toValue: expect.any(Number), iterations: 1}, - expect.any(Function) + { + type: 'frames', + frames: expect.any(Array), + toValue: expect.any(Number), + iterations: 1, + }, + expect.any(Function), ); - const animationId = nativeAnimatedModule.startAnimatingNode.mock.calls[0][0]; + const animationId = + nativeAnimatedModule.startAnimatingNode.mock.calls[0][0]; animation.stop(); expect(nativeAnimatedModule.stopAnimation).toBeCalledWith(animationId); diff --git a/Libraries/Animated/src/__tests__/Easing-test.js b/Libraries/Animated/src/__tests__/Easing-test.js index ae6cd336868292..1e2a3a2f4a7ce6 100644 --- a/Libraries/Animated/src/__tests__/Easing-test.js +++ b/Libraries/Animated/src/__tests__/Easing-test.js @@ -4,8 +4,10 @@ * 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 Easing = require('Easing'); @@ -88,23 +90,363 @@ describe('Easing', () => { } const Samples = { - in_quad: [0,0.0030864197530864196,0.012345679012345678,0.027777777777777776,0.04938271604938271,0.0771604938271605,0.1111111111111111,0.15123456790123457,0.19753086419753085,0.25,0.308641975308642,0.37345679012345684,0.4444444444444444,0.5216049382716049,0.6049382716049383,0.6944444444444445,0.7901234567901234,0.8919753086419753,1], - out_quad: [0,0.10802469135802469,0.20987654320987653,0.3055555555555555,0.3950617283950617,0.47839506172839513,0.5555555555555556,0.6265432098765432,0.691358024691358,0.75,0.8024691358024691,0.8487654320987654,0.888888888888889,0.9228395061728394,0.9506172839506174,0.9722222222222221,0.9876543209876543,0.9969135802469136,1], - inOut_quad: [0,0.006172839506172839,0.024691358024691357,0.05555555555555555,0.09876543209876543,0.154320987654321,0.2222222222222222,0.30246913580246915,0.3950617283950617,0.5,0.6049382716049383,0.697530864197531,0.7777777777777777,0.845679012345679,0.9012345679012346,0.9444444444444444,0.9753086419753086,0.9938271604938271,1], - in_cubic: [0,0.00017146776406035664,0.0013717421124828531,0.004629629629629629,0.010973936899862825,0.021433470507544586,0.037037037037037035,0.05881344307270234,0.0877914951989026,0.125,0.1714677640603567,0.22822359396433475,0.2962962962962963,0.37671467764060357,0.4705075445816187,0.5787037037037038,0.7023319615912208,0.8424211248285322,1], - out_cubic: [0,0.15757887517146785,0.2976680384087792,0.42129629629629617,0.5294924554183813,0.6232853223593964,0.7037037037037036,0.7717764060356652,0.8285322359396433,0.875,0.9122085048010974,0.9411865569272977,0.9629629629629629,0.9785665294924554,0.9890260631001372,0.9953703703703703,0.9986282578875172,0.9998285322359396,1], - inOut_cubic: [0,0.0006858710562414266,0.0054869684499314125,0.018518518518518517,0.0438957475994513,0.08573388203017834,0.14814814814814814,0.23525377229080935,0.3511659807956104,0.5,0.6488340192043895,0.7647462277091908,0.8518518518518519,0.9142661179698217,0.9561042524005487,0.9814814814814815,0.9945130315500685,0.9993141289437586,1], - in_sin: [0,0.003805301908254455,0.01519224698779198,0.03407417371093169,0.06030737921409157,0.09369221296335006,0.1339745962155613,0.1808479557110082,0.233955556881022,0.2928932188134524,0.35721239031346064,0.42642356364895384,0.4999999999999999,0.5773817382593005,0.6579798566743311,0.7411809548974793,0.8263518223330696,0.9128442572523416,0.9999999999999999], - out_sin: [0,0.08715574274765817,0.17364817766693033,0.25881904510252074,0.3420201433256687,0.42261826174069944,0.49999999999999994,0.573576436351046,0.6427876096865393,0.7071067811865475,0.766044443118978,0.8191520442889918,0.8660254037844386,0.9063077870366499,0.9396926207859083,0.9659258262890683,0.984807753012208,0.9961946980917455,1], - inOut_sin: [0,0.00759612349389599,0.030153689607045786,0.06698729810778065,0.116977778440511,0.17860619515673032,0.24999999999999994,0.32898992833716556,0.4131759111665348,0.49999999999999994,0.5868240888334652,0.6710100716628343,0.7499999999999999,0.8213938048432696,0.883022221559489,0.9330127018922194,0.9698463103929542,0.9924038765061041,1], - in_exp: [0,0.0014352875901128893,0.002109491677524035,0.0031003926796253885,0.004556754060844206,0.006697218616039631,0.009843133202303688,0.014466792379488908,0.021262343752724643,0.03125,0.045929202883612456,0.06750373368076916,0.09921256574801243,0.1458161299470146,0.2143109957132682,0.31498026247371835,0.46293735614364506,0.6803950000871883,1], - out_exp: [0,0.31960499991281155,0.5370626438563548,0.6850197375262816,0.7856890042867318,0.8541838700529854,0.9007874342519875,0.9324962663192309,0.9540707971163875,0.96875,0.9787376562472754,0.9855332076205111,0.9901568667976963,0.9933027813839603,0.9954432459391558,0.9968996073203746,0.9978905083224759,0.9985647124098871,1], - inOut_exp: [0,0.0010547458387620175,0.002278377030422103,0.004921566601151844,0.010631171876362321,0.022964601441806228,0.049606282874006216,0.1071554978566341,0.23146867807182253,0.5,0.7685313219281775,0.892844502143366,0.9503937171259937,0.9770353985581938,0.9893688281236377,0.9950784333988482,0.9977216229695779,0.998945254161238,1], - in_circle: [0,0.0015444024660317135,0.006192010000093506,0.013986702816730645,0.025003956956430873,0.03935464078941209,0.057190958417936644,0.07871533601238889,0.10419358352238339,0.1339745962155614,0.1685205807169019,0.20845517506805522,0.2546440075000701,0.3083389112228482,0.37146063894529113,0.4472292016074334,0.5418771527091488,0.6713289009389102,1], - out_circle: [0,0.3286710990610898,0.45812284729085123,0.5527707983925666,0.6285393610547089,0.6916610887771518,0.7453559924999298,0.7915448249319448,0.8314794192830981,0.8660254037844386,0.8958064164776166,0.9212846639876111,0.9428090415820634,0.9606453592105879,0.9749960430435691,0.9860132971832694,0.9938079899999065,0.9984555975339683,1], - inOut_circle: [0,0.003096005000046753,0.012501978478215436,0.028595479208968322,0.052096791761191696,0.08426029035845095,0.12732200375003505,0.18573031947264557,0.2709385763545744,0.5,0.7290614236454256,0.8142696805273546,0.8726779962499649,0.915739709641549,0.9479032082388084,0.9714045207910317,0.9874980215217846,0.9969039949999532,1], - in_back_: [0,-0.004788556241426612,-0.017301289437585736,-0.0347587962962963,-0.05438167352537723,-0.07339051783264748,-0.08900592592592595,-0.09844849451303156,-0.0989388203017833,-0.08769750000000004,-0.06194513031550073,-0.018902307956104283,0.044210370370370254,0.13017230795610413,0.2417629080932785,0.3817615740740742,0.5529477091906719,0.7581007167352535,0.9999999999999998], - out_back_: [2.220446049250313e-16,0.24189928326474652,0.44705229080932807,0.6182384259259258,0.7582370919067215,0.8698276920438959,0.9557896296296297,1.0189023079561044,1.0619451303155008,1.0876975,1.0989388203017834,1.0984484945130315,1.089005925925926,1.0733905178326475,1.0543816735253773,1.0347587962962963,1.0173012894375857,1.0047885562414267,1], + in_quad: [ + 0, + 0.0030864197530864196, + 0.012345679012345678, + 0.027777777777777776, + 0.04938271604938271, + 0.0771604938271605, + 0.1111111111111111, + 0.15123456790123457, + 0.19753086419753085, + 0.25, + 0.308641975308642, + 0.37345679012345684, + 0.4444444444444444, + 0.5216049382716049, + 0.6049382716049383, + 0.6944444444444445, + 0.7901234567901234, + 0.8919753086419753, + 1, + ], + out_quad: [ + 0, + 0.10802469135802469, + 0.20987654320987653, + 0.3055555555555555, + 0.3950617283950617, + 0.47839506172839513, + 0.5555555555555556, + 0.6265432098765432, + 0.691358024691358, + 0.75, + 0.8024691358024691, + 0.8487654320987654, + 0.888888888888889, + 0.9228395061728394, + 0.9506172839506174, + 0.9722222222222221, + 0.9876543209876543, + 0.9969135802469136, + 1, + ], + inOut_quad: [ + 0, + 0.006172839506172839, + 0.024691358024691357, + 0.05555555555555555, + 0.09876543209876543, + 0.154320987654321, + 0.2222222222222222, + 0.30246913580246915, + 0.3950617283950617, + 0.5, + 0.6049382716049383, + 0.697530864197531, + 0.7777777777777777, + 0.845679012345679, + 0.9012345679012346, + 0.9444444444444444, + 0.9753086419753086, + 0.9938271604938271, + 1, + ], + in_cubic: [ + 0, + 0.00017146776406035664, + 0.0013717421124828531, + 0.004629629629629629, + 0.010973936899862825, + 0.021433470507544586, + 0.037037037037037035, + 0.05881344307270234, + 0.0877914951989026, + 0.125, + 0.1714677640603567, + 0.22822359396433475, + 0.2962962962962963, + 0.37671467764060357, + 0.4705075445816187, + 0.5787037037037038, + 0.7023319615912208, + 0.8424211248285322, + 1, + ], + out_cubic: [ + 0, + 0.15757887517146785, + 0.2976680384087792, + 0.42129629629629617, + 0.5294924554183813, + 0.6232853223593964, + 0.7037037037037036, + 0.7717764060356652, + 0.8285322359396433, + 0.875, + 0.9122085048010974, + 0.9411865569272977, + 0.9629629629629629, + 0.9785665294924554, + 0.9890260631001372, + 0.9953703703703703, + 0.9986282578875172, + 0.9998285322359396, + 1, + ], + inOut_cubic: [ + 0, + 0.0006858710562414266, + 0.0054869684499314125, + 0.018518518518518517, + 0.0438957475994513, + 0.08573388203017834, + 0.14814814814814814, + 0.23525377229080935, + 0.3511659807956104, + 0.5, + 0.6488340192043895, + 0.7647462277091908, + 0.8518518518518519, + 0.9142661179698217, + 0.9561042524005487, + 0.9814814814814815, + 0.9945130315500685, + 0.9993141289437586, + 1, + ], + in_sin: [ + 0, + 0.003805301908254455, + 0.01519224698779198, + 0.03407417371093169, + 0.06030737921409157, + 0.09369221296335006, + 0.1339745962155613, + 0.1808479557110082, + 0.233955556881022, + 0.2928932188134524, + 0.35721239031346064, + 0.42642356364895384, + 0.4999999999999999, + 0.5773817382593005, + 0.6579798566743311, + 0.7411809548974793, + 0.8263518223330696, + 0.9128442572523416, + 0.9999999999999999, + ], + out_sin: [ + 0, + 0.08715574274765817, + 0.17364817766693033, + 0.25881904510252074, + 0.3420201433256687, + 0.42261826174069944, + 0.49999999999999994, + 0.573576436351046, + 0.6427876096865393, + 0.7071067811865475, + 0.766044443118978, + 0.8191520442889918, + 0.8660254037844386, + 0.9063077870366499, + 0.9396926207859083, + 0.9659258262890683, + 0.984807753012208, + 0.9961946980917455, + 1, + ], + inOut_sin: [ + 0, + 0.00759612349389599, + 0.030153689607045786, + 0.06698729810778065, + 0.116977778440511, + 0.17860619515673032, + 0.24999999999999994, + 0.32898992833716556, + 0.4131759111665348, + 0.49999999999999994, + 0.5868240888334652, + 0.6710100716628343, + 0.7499999999999999, + 0.8213938048432696, + 0.883022221559489, + 0.9330127018922194, + 0.9698463103929542, + 0.9924038765061041, + 1, + ], + in_exp: [ + 0, + 0.0014352875901128893, + 0.002109491677524035, + 0.0031003926796253885, + 0.004556754060844206, + 0.006697218616039631, + 0.009843133202303688, + 0.014466792379488908, + 0.021262343752724643, + 0.03125, + 0.045929202883612456, + 0.06750373368076916, + 0.09921256574801243, + 0.1458161299470146, + 0.2143109957132682, + 0.31498026247371835, + 0.46293735614364506, + 0.6803950000871883, + 1, + ], + out_exp: [ + 0, + 0.31960499991281155, + 0.5370626438563548, + 0.6850197375262816, + 0.7856890042867318, + 0.8541838700529854, + 0.9007874342519875, + 0.9324962663192309, + 0.9540707971163875, + 0.96875, + 0.9787376562472754, + 0.9855332076205111, + 0.9901568667976963, + 0.9933027813839603, + 0.9954432459391558, + 0.9968996073203746, + 0.9978905083224759, + 0.9985647124098871, + 1, + ], + inOut_exp: [ + 0, + 0.0010547458387620175, + 0.002278377030422103, + 0.004921566601151844, + 0.010631171876362321, + 0.022964601441806228, + 0.049606282874006216, + 0.1071554978566341, + 0.23146867807182253, + 0.5, + 0.7685313219281775, + 0.892844502143366, + 0.9503937171259937, + 0.9770353985581938, + 0.9893688281236377, + 0.9950784333988482, + 0.9977216229695779, + 0.998945254161238, + 1, + ], + in_circle: [ + 0, + 0.0015444024660317135, + 0.006192010000093506, + 0.013986702816730645, + 0.025003956956430873, + 0.03935464078941209, + 0.057190958417936644, + 0.07871533601238889, + 0.10419358352238339, + 0.1339745962155614, + 0.1685205807169019, + 0.20845517506805522, + 0.2546440075000701, + 0.3083389112228482, + 0.37146063894529113, + 0.4472292016074334, + 0.5418771527091488, + 0.6713289009389102, + 1, + ], + out_circle: [ + 0, + 0.3286710990610898, + 0.45812284729085123, + 0.5527707983925666, + 0.6285393610547089, + 0.6916610887771518, + 0.7453559924999298, + 0.7915448249319448, + 0.8314794192830981, + 0.8660254037844386, + 0.8958064164776166, + 0.9212846639876111, + 0.9428090415820634, + 0.9606453592105879, + 0.9749960430435691, + 0.9860132971832694, + 0.9938079899999065, + 0.9984555975339683, + 1, + ], + inOut_circle: [ + 0, + 0.003096005000046753, + 0.012501978478215436, + 0.028595479208968322, + 0.052096791761191696, + 0.08426029035845095, + 0.12732200375003505, + 0.18573031947264557, + 0.2709385763545744, + 0.5, + 0.7290614236454256, + 0.8142696805273546, + 0.8726779962499649, + 0.915739709641549, + 0.9479032082388084, + 0.9714045207910317, + 0.9874980215217846, + 0.9969039949999532, + 1, + ], + in_back_: [ + 0, + -0.004788556241426612, + -0.017301289437585736, + -0.0347587962962963, + -0.05438167352537723, + -0.07339051783264748, + -0.08900592592592595, + -0.09844849451303156, + -0.0989388203017833, + -0.08769750000000004, + -0.06194513031550073, + -0.018902307956104283, + 0.044210370370370254, + 0.13017230795610413, + 0.2417629080932785, + 0.3817615740740742, + 0.5529477091906719, + 0.7581007167352535, + 0.9999999999999998, + ], + out_back_: [ + 2.220446049250313e-16, + 0.24189928326474652, + 0.44705229080932807, + 0.6182384259259258, + 0.7582370919067215, + 0.8698276920438959, + 0.9557896296296297, + 1.0189023079561044, + 1.0619451303155008, + 1.0876975, + 1.0989388203017834, + 1.0984484945130315, + 1.089005925925926, + 1.0733905178326475, + 1.0543816735253773, + 1.0347587962962963, + 1.0173012894375857, + 1.0047885562414267, + 1, + ], }; Object.keys(Samples).forEach(function(type) { diff --git a/Libraries/Animated/src/__tests__/Interpolation-test.js b/Libraries/Animated/src/__tests__/Interpolation-test.js index c2b832bcf5cf7b..5515f09bacd0bc 100644 --- a/Libraries/Animated/src/__tests__/Interpolation-test.js +++ b/Libraries/Animated/src/__tests__/Interpolation-test.js @@ -4,8 +4,10 @@ * 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 AnimatedInterpolation = require('../nodes/AnimatedInterpolation'); diff --git a/Libraries/Animated/src/__tests__/bezier-test.js b/Libraries/Animated/src/__tests__/bezier-test.js index 16b7acc0f1930a..46c7f043b331e2 100644 --- a/Libraries/Animated/src/__tests__/bezier-test.js +++ b/Libraries/Animated/src/__tests__/bezier-test.js @@ -74,7 +74,10 @@ describe('bezier', function() { describe('common properties', function() { it('should be the right value at extremes', function() { repeat(10)(function() { - const a = Math.random(), b = 2 * Math.random() - 0.5, c = Math.random(), d = 2 * Math.random() - 0.5; + const a = Math.random(), + b = 2 * Math.random() - 0.5, + c = Math.random(), + d = 2 * Math.random() - 0.5; const easing = bezier(a, b, c, d); expect(easing(0)).toBe(0); expect(easing(1)).toBe(1); @@ -83,7 +86,10 @@ describe('bezier', function() { it('should approach the projected value of its x=y projected curve', function() { repeat(10)(function() { - const a = Math.random(), b = Math.random(), c = Math.random(), d = Math.random(); + const a = Math.random(), + b = Math.random(), + c = Math.random(), + d = Math.random(); const easing = bezier(a, b, c, d); const projected = bezier(b, a, d, c); const composed = function(x) { @@ -96,7 +102,10 @@ describe('bezier', function() { describe('two same instances', function() { it('should be strictly equals', function() { repeat(10)(function() { - const a = Math.random(), b = 2 * Math.random() - 0.5, c = Math.random(), d = 2 * Math.random() - 0.5; + const a = Math.random(), + b = 2 * Math.random() - 0.5, + c = Math.random(), + d = 2 * Math.random() - 0.5; allEquals(bezier(a, b, c, d), bezier(a, b, c, d), 100, 0); }); }); @@ -104,14 +113,20 @@ describe('bezier', function() { describe('symetric curves', function() { it('should have a central value y~=0.5 at x=0.5', function() { repeat(10)(function() { - const a = Math.random(), b = 2 * Math.random() - 0.5, c = 1 - a, d = 1 - b; + const a = Math.random(), + b = 2 * Math.random() - 0.5, + c = 1 - a, + d = 1 - b; const easing = bezier(a, b, c, d); assertClose(easing(0.5), 0.5, 2); }); }); it('should be symmetrical', function() { repeat(10)(function() { - const a = Math.random(), b = 2 * Math.random() - 0.5, c = 1 - a, d = 1 - b; + const a = Math.random(), + b = 2 * Math.random() - 0.5, + c = 1 - a, + d = 1 - b; const easing = bezier(a, b, c, d); const sym = function(x) { return 1 - easing(1 - x); diff --git a/Libraries/Animated/src/bezier.js b/Libraries/Animated/src/bezier.js index f38ecef8c451ed..41a83b545f7254 100644 --- a/Libraries/Animated/src/bezier.js +++ b/Libraries/Animated/src/bezier.js @@ -2,47 +2,64 @@ * BezierEasing - use bezier curve for transition easing function * https://github.com/gre/bezier-easing * + * @format * @copyright 2014-2015 Gaëtan Renaudeau. MIT License. * @noflow */ + 'use strict'; - // These values are established by empiricism with tests (tradeoff: performance VS precision) - const NEWTON_ITERATIONS = 4; - const NEWTON_MIN_SLOPE = 0.001; - const SUBDIVISION_PRECISION = 0.0000001; - const SUBDIVISION_MAX_ITERATIONS = 10; - - const kSplineTableSize = 11; - const kSampleStepSize = 1.0 / (kSplineTableSize - 1.0); - - const float32ArraySupported = typeof Float32Array === 'function'; - - function A (aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; } - function B (aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; } - function C (aA1) { return 3.0 * aA1; } - - // Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2. - function calcBezier (aT, aA1, aA2) { return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT; } - - // Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2. - function getSlope (aT, aA1, aA2) { return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1); } - - function binarySubdivide (aX, aA, aB, mX1, mX2) { - let currentX, currentT, i = 0; - do { - currentT = aA + (aB - aA) / 2.0; - currentX = calcBezier(currentT, mX1, mX2) - aX; - if (currentX > 0.0) { - aB = currentT; - } else { - aA = currentT; - } - } while (Math.abs(currentX) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS); - return currentT; - } - - function newtonRaphsonIterate (aX, aGuessT, mX1, mX2) { +// These values are established by empiricism with tests (tradeoff: performance VS precision) +const NEWTON_ITERATIONS = 4; +const NEWTON_MIN_SLOPE = 0.001; +const SUBDIVISION_PRECISION = 0.0000001; +const SUBDIVISION_MAX_ITERATIONS = 10; + +const kSplineTableSize = 11; +const kSampleStepSize = 1.0 / (kSplineTableSize - 1.0); + +const float32ArraySupported = typeof Float32Array === 'function'; + +function A(aA1, aA2) { + return 1.0 - 3.0 * aA2 + 3.0 * aA1; +} +function B(aA1, aA2) { + return 3.0 * aA2 - 6.0 * aA1; +} +function C(aA1) { + return 3.0 * aA1; +} + +// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2. +function calcBezier(aT, aA1, aA2) { + return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT; +} + +// Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2. +function getSlope(aT, aA1, aA2) { + return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1); +} + +function binarySubdivide(aX, aA, aB, mX1, mX2) { + let currentX, + currentT, + i = 0; + do { + currentT = aA + (aB - aA) / 2.0; + currentX = calcBezier(currentT, mX1, mX2) - aX; + if (currentX > 0.0) { + aB = currentT; + } else { + aA = currentT; + } + } while ( + Math.abs(currentX) > SUBDIVISION_PRECISION && + ++i < SUBDIVISION_MAX_ITERATIONS + ); + return currentT; +} + +function newtonRaphsonIterate(aX, aGuessT, mX1, mX2) { for (let i = 0; i < NEWTON_ITERATIONS; ++i) { const currentSlope = getSlope(aGuessT, mX1, mX2); if (currentSlope === 0.0) { @@ -52,56 +69,71 @@ aGuessT -= currentX / currentSlope; } return aGuessT; - } - - module.exports = function bezier (mX1, mY1, mX2, mY2) { - if (!(0 <= mX1 && mX1 <= 1 && 0 <= mX2 && mX2 <= 1)) { // eslint-disable-line yoda - throw new Error('bezier x values must be in [0, 1] range'); - } - - // Precompute samples table - const sampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : new Array(kSplineTableSize); - if (mX1 !== mY1 || mX2 !== mY2) { - for (let i = 0; i < kSplineTableSize; ++i) { - sampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2); - } - } - - function getTForX (aX) { - let intervalStart = 0.0; - let currentSample = 1; - const lastSample = kSplineTableSize - 1; - - for (; currentSample !== lastSample && sampleValues[currentSample] <= aX; ++currentSample) { - intervalStart += kSampleStepSize; - } - --currentSample; - - // Interpolate to provide an initial guess for t - const dist = (aX - sampleValues[currentSample]) / (sampleValues[currentSample + 1] - sampleValues[currentSample]); - const guessForT = intervalStart + dist * kSampleStepSize; - - const initialSlope = getSlope(guessForT, mX1, mX2); - if (initialSlope >= NEWTON_MIN_SLOPE) { - return newtonRaphsonIterate(aX, guessForT, mX1, mX2); - } else if (initialSlope === 0.0) { - return guessForT; - } else { - return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize, mX1, mX2); - } - } - - return function BezierEasing (x) { - if (mX1 === mY1 && mX2 === mY2) { - return x; // linear - } - // Because JavaScript number are imprecise, we should guarantee the extremes are right. - if (x === 0) { - return 0; - } - if (x === 1) { - return 1; - } - return calcBezier(getTForX(x), mY1, mY2); - }; - }; +} + +module.exports = function bezier(mX1, mY1, mX2, mY2) { + if (!(0 <= mX1 && mX1 <= 1 && 0 <= mX2 && mX2 <= 1)) { + // eslint-disable-line yoda + throw new Error('bezier x values must be in [0, 1] range'); + } + + // Precompute samples table + const sampleValues = float32ArraySupported + ? new Float32Array(kSplineTableSize) + : new Array(kSplineTableSize); + if (mX1 !== mY1 || mX2 !== mY2) { + for (let i = 0; i < kSplineTableSize; ++i) { + sampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2); + } + } + + function getTForX(aX) { + let intervalStart = 0.0; + let currentSample = 1; + const lastSample = kSplineTableSize - 1; + + for ( + ; + currentSample !== lastSample && sampleValues[currentSample] <= aX; + ++currentSample + ) { + intervalStart += kSampleStepSize; + } + --currentSample; + + // Interpolate to provide an initial guess for t + const dist = + (aX - sampleValues[currentSample]) / + (sampleValues[currentSample + 1] - sampleValues[currentSample]); + const guessForT = intervalStart + dist * kSampleStepSize; + + const initialSlope = getSlope(guessForT, mX1, mX2); + if (initialSlope >= NEWTON_MIN_SLOPE) { + return newtonRaphsonIterate(aX, guessForT, mX1, mX2); + } else if (initialSlope === 0.0) { + return guessForT; + } else { + return binarySubdivide( + aX, + intervalStart, + intervalStart + kSampleStepSize, + mX1, + mX2, + ); + } + } + + return function BezierEasing(x) { + if (mX1 === mY1 && mX2 === mY2) { + return x; // linear + } + // Because JavaScript number are imprecise, we should guarantee the extremes are right. + if (x === 0) { + return 0; + } + if (x === 1) { + return 1; + } + return calcBezier(getTForX(x), mY1, mY2); + }; +}; diff --git a/Libraries/Animated/src/polyfills/InteractionManager.js b/Libraries/Animated/src/polyfills/InteractionManager.js index c063e9234b3df1..5e82aaaa544cdb 100644 --- a/Libraries/Animated/src/polyfills/InteractionManager.js +++ b/Libraries/Animated/src/polyfills/InteractionManager.js @@ -3,11 +3,13 @@ * * 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 = { createInteractionHandle: function() {}, - clearInteractionHandle: function() {} + clearInteractionHandle: function() {}, }; diff --git a/Libraries/Animated/src/polyfills/Set.js b/Libraries/Animated/src/polyfills/Set.js index fd071410d42395..c88278bda1cb38 100644 --- a/Libraries/Animated/src/polyfills/Set.js +++ b/Libraries/Animated/src/polyfills/Set.js @@ -3,6 +3,8 @@ * * 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'; diff --git a/Libraries/Animated/src/polyfills/flattenStyle.js b/Libraries/Animated/src/polyfills/flattenStyle.js index 2e4c8a1d36b476..21907b235f97f5 100644 --- a/Libraries/Animated/src/polyfills/flattenStyle.js +++ b/Libraries/Animated/src/polyfills/flattenStyle.js @@ -3,7 +3,10 @@ * * 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 = function(style) { return style; diff --git a/Libraries/AppState/AppState.js b/Libraries/AppState/AppState.js index 904bf2b0e65843..554689f11ad680 100644 --- a/Libraries/AppState/AppState.js +++ b/Libraries/AppState/AppState.js @@ -4,8 +4,10 @@ * 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 MissingNativeEventEmitterShim = require('MissingNativeEventEmitterShim'); @@ -23,7 +25,6 @@ const invariant = require('fbjs/lib/invariant'); * See http://facebook.github.io/react-native/docs/appstate.html */ class AppState extends NativeEventEmitter { - _eventHandlers: Object; currentState: ?string; isAvailable: boolean = true; @@ -47,27 +48,21 @@ class AppState extends NativeEventEmitter { // prop is up to date, we have to register an observer that updates it // whenever the state changes, even if nobody cares. We should just // deprecate the `currentState` property and get rid of this. - this.addListener( - 'appStateDidChange', - (appStateData) => { - eventUpdated = true; - this.currentState = appStateData.app_state; - } - ); + this.addListener('appStateDidChange', appStateData => { + eventUpdated = true; + this.currentState = appStateData.app_state; + }); // TODO: see above - this request just populates the value of `currentState` // when the module is first initialized. Would be better to get rid of the // prop and expose `getCurrentAppState` method directly. - RCTAppState.getCurrentAppState( - (appStateData) => { - // It's possible that the state will have changed here & listeners need to be notified - if (!eventUpdated && this.currentState !== appStateData.app_state) { - this.currentState = appStateData.app_state; - this.emit('appStateDidChange', appStateData); - } - }, - logError - ); + RCTAppState.getCurrentAppState(appStateData => { + // It's possible that the state will have changed here & listeners need to be notified + if (!eventUpdated && this.currentState !== appStateData.app_state) { + this.currentState = appStateData.app_state; + this.emit('appStateDidChange', appStateData); + } + }, logError); } // TODO: now that AppState is a subclass of NativeEventEmitter, we could @@ -75,32 +70,30 @@ class AppState extends NativeEventEmitter { // addListener` and `listener.remove()` directly. That will be a breaking // change though, as both the method and event names are different // (addListener events are currently required to be globally unique). - /** + /** * Add a handler to AppState changes by listening to the `change` event type * and providing the handler. * * See http://facebook.github.io/react-native/docs/appstate.html#addeventlistener */ - addEventListener( - type: string, - handler: Function - ) { + addEventListener(type: string, handler: Function) { invariant( ['change', 'memoryWarning'].indexOf(type) !== -1, - 'Trying to subscribe to unknown event: "%s"', type + 'Trying to subscribe to unknown event: "%s"', + type, ); if (type === 'change') { - this._eventHandlers[type].set(handler, this.addListener( - 'appStateDidChange', - (appStateData) => { + 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 - )); + this._eventHandlers[type].set( + handler, + this.addListener('memoryWarning', handler), + ); } } @@ -109,13 +102,11 @@ class AppState extends NativeEventEmitter { * * See http://facebook.github.io/react-native/docs/appstate.html#removeeventlistener */ - removeEventListener( - type: string, - handler: Function - ) { + removeEventListener(type: string, handler: Function) { invariant( ['change', 'memoryWarning'].indexOf(type) !== -1, - 'Trying to remove listener for unknown event: "%s"', type + 'Trying to remove listener for unknown event: "%s"', + type, ); if (!this._eventHandlers[type].has(handler)) { return; diff --git a/Libraries/BatchedBridge/BatchedBridge.js b/Libraries/BatchedBridge/BatchedBridge.js index bc66ae32f9f4c6..0b1aae766493e6 100644 --- a/Libraries/BatchedBridge/BatchedBridge.js +++ b/Libraries/BatchedBridge/BatchedBridge.js @@ -4,8 +4,10 @@ * 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 MessageQueue = require('MessageQueue'); diff --git a/Libraries/BatchedBridge/NativeModules.js b/Libraries/BatchedBridge/NativeModules.js index a5f9911499956e..bfee59abb4b784 100644 --- a/Libraries/BatchedBridge/NativeModules.js +++ b/Libraries/BatchedBridge/NativeModules.js @@ -4,8 +4,10 @@ * 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 BatchedBridge = require('BatchedBridge'); @@ -15,53 +17,66 @@ const invariant = require('fbjs/lib/invariant'); import type {ExtendedError} from 'parseErrorStack'; type ModuleConfig = [ - string, /* name */ - ?Object, /* constants */ - Array, /* functions */ - Array, /* promise method IDs */ - Array, /* sync method IDs */ + string /* name */, + ?Object /* constants */, + Array /* functions */, + Array /* promise method IDs */, + Array /* sync method IDs */, ]; export type MethodType = 'async' | 'promise' | 'sync'; -function genModule(config: ?ModuleConfig, moduleID: number): ?{name: string, module?: Object} { +function genModule( + config: ?ModuleConfig, + moduleID: number, +): ?{name: string, module?: Object} { if (!config) { return null; } const [moduleName, constants, methods, promiseMethods, syncMethods] = config; - invariant(!moduleName.startsWith('RCT') && !moduleName.startsWith('RK'), - 'Module name prefixes should\'ve been stripped by the native side ' + - 'but wasn\'t for ' + moduleName); + invariant( + !moduleName.startsWith('RCT') && !moduleName.startsWith('RK'), + "Module name prefixes should've been stripped by the native side " + + "but wasn't for " + + moduleName, + ); if (!constants && !methods) { // Module contents will be filled in lazily later - return { name: moduleName }; + return {name: moduleName}; } const module = {}; - methods && methods.forEach((methodName, methodID) => { - const isPromise = promiseMethods && arrayContains(promiseMethods, methodID); - const isSync = syncMethods && arrayContains(syncMethods, methodID); - invariant(!isPromise || !isSync, 'Cannot have a method that is both async and a sync hook'); - const methodType = isPromise ? 'promise' : isSync ? 'sync' : 'async'; - module[methodName] = genMethod(moduleID, methodID, methodType); - }); + methods && + methods.forEach((methodName, methodID) => { + const isPromise = + promiseMethods && arrayContains(promiseMethods, methodID); + const isSync = syncMethods && arrayContains(syncMethods, methodID); + invariant( + !isPromise || !isSync, + 'Cannot have a method that is both async and a sync hook', + ); + const methodType = isPromise ? 'promise' : isSync ? 'sync' : 'async'; + module[methodName] = genMethod(moduleID, methodID, methodType); + }); Object.assign(module, constants); if (__DEV__) { BatchedBridge.createDebugLookup(moduleID, moduleName, methods); } - return { name: moduleName, module }; + return {name: moduleName, module}; } // export this method as a global so we can call it from native global.__fbGenNativeModule = genModule; function loadModule(name: string, moduleID: number): ?Object { - invariant(global.nativeRequireModuleConfig, - 'Can\'t lazily create module without nativeRequireModuleConfig'); + invariant( + global.nativeRequireModuleConfig, + "Can't lazily create module without nativeRequireModuleConfig", + ); const config = global.nativeRequireModuleConfig(name); const info = genModule(config, moduleID); return info && info.module; @@ -72,18 +87,25 @@ function genMethod(moduleID: number, methodID: number, type: MethodType) { if (type === 'promise') { fn = function(...args: Array) { return new Promise((resolve, reject) => { - BatchedBridge.enqueueNativeCall(moduleID, methodID, args, - (data) => resolve(data), - (errorData) => reject(createErrorFromErrorData(errorData))); + BatchedBridge.enqueueNativeCall( + moduleID, + methodID, + args, + data => resolve(data), + errorData => reject(createErrorFromErrorData(errorData)), + ); }); }; } else if (type === 'sync') { fn = function(...args: Array) { if (__DEV__) { - invariant(global.nativeCallSyncHook, 'Calling synchronous methods on native ' + - 'modules is not supported in Chrome.\n\n Consider providing alternative ' + - 'methods to expose this method in debug mode, e.g. by exposing constants ' + - 'ahead-of-time.'); + invariant( + global.nativeCallSyncHook, + 'Calling synchronous methods on native ' + + 'modules is not supported in Chrome.\n\n Consider providing alternative ' + + 'methods to expose this method in debug mode, e.g. by exposing constants ' + + 'ahead-of-time.', + ); } return global.nativeCallSyncHook(moduleID, methodID, args); }; @@ -93,15 +115,22 @@ function genMethod(moduleID: number, methodID: number, type: MethodType) { const secondLastArg = args.length > 1 ? args[args.length - 2] : null; const hasSuccessCallback = typeof lastArg === 'function'; const hasErrorCallback = typeof secondLastArg === 'function'; - hasErrorCallback && invariant( - hasSuccessCallback, - 'Cannot have a non-function arg after a function arg.' - ); + hasErrorCallback && + invariant( + hasSuccessCallback, + 'Cannot have a non-function arg after a function arg.', + ); const onSuccess = hasSuccessCallback ? lastArg : null; const onFail = hasErrorCallback ? secondLastArg : null; const callbackCount = hasSuccessCallback + hasErrorCallback; args = args.slice(0, args.length - callbackCount); - BatchedBridge.enqueueNativeCall(moduleID, methodID, args, onFail, onSuccess); + BatchedBridge.enqueueNativeCall( + moduleID, + methodID, + args, + onFail, + onSuccess, + ); }; } fn.type = type; @@ -113,41 +142,43 @@ function arrayContains(array: Array, value: T): boolean { } function createErrorFromErrorData(errorData: {message: string}): ExtendedError { - const { - message, - ...extraErrorInfo - } = errorData || {}; - const error : ExtendedError = new Error(message); + const {message, ...extraErrorInfo} = errorData || {}; + const error: ExtendedError = new Error(message); error.framesToPop = 1; return Object.assign(error, extraErrorInfo); } -let NativeModules : {[moduleName: string]: Object} = {}; +let NativeModules: {[moduleName: string]: Object} = {}; if (global.nativeModuleProxy) { NativeModules = global.nativeModuleProxy; } else { const bridgeConfig = global.__fbBatchedBridgeConfig; - invariant(bridgeConfig, '__fbBatchedBridgeConfig is not set, cannot invoke native modules'); + invariant( + bridgeConfig, + '__fbBatchedBridgeConfig is not set, cannot invoke native modules', + ); const defineLazyObjectProperty = require('defineLazyObjectProperty'); - (bridgeConfig.remoteModuleConfig || []).forEach((config: ModuleConfig, moduleID: number) => { - // Initially this config will only contain the module name when running in JSC. The actual - // configuration of the module will be lazily loaded. - const info = genModule(config, moduleID); - if (!info) { - return; - } - - if (info.module) { - NativeModules[info.name] = info.module; - } - // If there's no module config, define a lazy getter - else { - defineLazyObjectProperty(NativeModules, info.name, { - get: () => loadModule(info.name, moduleID) - }); - } - }); + (bridgeConfig.remoteModuleConfig || []).forEach( + (config: ModuleConfig, moduleID: number) => { + // Initially this config will only contain the module name when running in JSC. The actual + // configuration of the module will be lazily loaded. + const info = genModule(config, moduleID); + if (!info) { + return; + } + + if (info.module) { + NativeModules[info.name] = info.module; + } + // If there's no module config, define a lazy getter + else { + defineLazyObjectProperty(NativeModules, info.name, { + get: () => loadModule(info.name, moduleID), + }); + } + }, + ); } module.exports = NativeModules; diff --git a/Libraries/BatchedBridge/__mocks__/MessageQueueTestConfig.js b/Libraries/BatchedBridge/__mocks__/MessageQueueTestConfig.js index 2fa722fb39e89a..3f9ae5f0a4855c 100644 --- a/Libraries/BatchedBridge/__mocks__/MessageQueueTestConfig.js +++ b/Libraries/BatchedBridge/__mocks__/MessageQueueTestConfig.js @@ -5,11 +5,14 @@ * LICENSE file in the root directory of this source tree. * * These don't actually exist anywhere in the code. + * + * @format */ + 'use strict'; const remoteModulesConfig = [ - ['RemoteModule1',null,['remoteMethod','promiseMethod'],[]], - ['RemoteModule2',null,['remoteMethod','promiseMethod'],[]], + ['RemoteModule1', null, ['remoteMethod', 'promiseMethod'], []], + ['RemoteModule2', null, ['remoteMethod', 'promiseMethod'], []], ]; const MessageQueueTestConfig = { diff --git a/Libraries/BatchedBridge/__mocks__/MessageQueueTestModule.js b/Libraries/BatchedBridge/__mocks__/MessageQueueTestModule.js index 7d4f5f1a565a7d..05168a6b570094 100644 --- a/Libraries/BatchedBridge/__mocks__/MessageQueueTestModule.js +++ b/Libraries/BatchedBridge/__mocks__/MessageQueueTestModule.js @@ -4,7 +4,9 @@ * 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'; /** @@ -13,10 +15,8 @@ * cases. */ const MessageQueueTestModule = { - testHook1: function() { - }, - testHook2: function() { - } + testHook1: function() {}, + testHook2: function() {}, }; module.exports = MessageQueueTestModule; diff --git a/Libraries/BatchedBridge/__tests__/NativeModules-test.js b/Libraries/BatchedBridge/__tests__/NativeModules-test.js index b9cc2411d29512..9702146b719090 100644 --- a/Libraries/BatchedBridge/__tests__/NativeModules-test.js +++ b/Libraries/BatchedBridge/__tests__/NativeModules-test.js @@ -4,8 +4,10 @@ * 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'; jest @@ -59,7 +61,12 @@ describe('MessageQueue', function() { const onSucc = jest.fn(); // Perform communication - NativeModules.RemoteModule1.promiseMethod('paloAlto', 'menloPark', onFail, onSucc); + NativeModules.RemoteModule1.promiseMethod( + 'paloAlto', + 'menloPark', + onFail, + onSucc, + ); NativeModules.RemoteModule2.promiseMethod('mac', 'windows', onFail, onSucc); const resultingRemoteInvocations = BatchedBridge.flushedQueue(); @@ -73,9 +80,10 @@ describe('MessageQueue', function() { expect(resultingRemoteInvocations[0][0]).toBe(0); // `RemoteModule1` expect(resultingRemoteInvocations[1][0]).toBe(1); // `promiseMethod` - expect([ // the arguments + expect([ + // the arguments resultingRemoteInvocations[2][0][0], - resultingRemoteInvocations[2][0][1] + resultingRemoteInvocations[2][0][1], ]).toEqual(['paloAlto', 'menloPark']); // Callbacks ids are tacked onto the end of the remote arguments. const firstFailCBID = resultingRemoteInvocations[2][0][2]; @@ -83,9 +91,10 @@ describe('MessageQueue', function() { expect(resultingRemoteInvocations[0][1]).toBe(1); // `RemoteModule2` expect(resultingRemoteInvocations[1][1]).toBe(1); // `promiseMethod` - expect([ // the arguments + expect([ + // the arguments resultingRemoteInvocations[2][1][0], - resultingRemoteInvocations[2][1][1] + resultingRemoteInvocations[2][1][1], ]).toEqual(['mac', 'windows']); const secondFailCBID = resultingRemoteInvocations[2][1][2]; const secondSuccCBID = resultingRemoteInvocations[2][1][3]; diff --git a/Libraries/BugReporting/BugReporting.js b/Libraries/BugReporting/BugReporting.js index f196276c36fae6..6c63b6a1eebf98 100644 --- a/Libraries/BugReporting/BugReporting.js +++ b/Libraries/BugReporting/BugReporting.js @@ -4,8 +4,10 @@ * 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 RCTDeviceEventEmitter = require('RCTDeviceEventEmitter'); @@ -14,12 +16,14 @@ const infoLog = require('infoLog'); import type EmitterSubscription from 'EmitterSubscription'; -type ExtraData = { [key: string]: string }; +type ExtraData = {[key: string]: string}; type SourceCallback = () => string; -type DebugData = { extras: ExtraData, files: ExtraData }; +type DebugData = {extras: ExtraData, files: ExtraData}; function defaultExtras() { - BugReporting.addFileSource('react_hierarchy.txt', () => require('dumpReactTree')()); + BugReporting.addFileSource('react_hierarchy.txt', () => + require('dumpReactTree')(), + ); } /** @@ -36,14 +40,20 @@ class BugReporting { static _maybeInit() { if (!BugReporting._subscription) { - BugReporting._subscription = RCTDeviceEventEmitter - .addListener('collectBugExtraData', BugReporting.collectExtraData, null); + BugReporting._subscription = RCTDeviceEventEmitter.addListener( + 'collectBugExtraData', + BugReporting.collectExtraData, + null, + ); defaultExtras(); } if (!BugReporting._redboxSubscription) { - BugReporting._redboxSubscription = RCTDeviceEventEmitter - .addListener('collectRedBoxExtraData', BugReporting.collectExtraData, null); + BugReporting._redboxSubscription = RCTDeviceEventEmitter.addListener( + 'collectRedBoxExtraData', + BugReporting.collectExtraData, + null, + ); } } @@ -55,7 +65,10 @@ class BugReporting { * * Conflicts trample with a warning. */ - static addSource(key: string, callback: SourceCallback): {remove: () => void} { + static addSource( + key: string, + callback: SourceCallback, + ): {remove: () => void} { return this._addSource(key, callback, BugReporting._extraSources); } @@ -67,17 +80,30 @@ class BugReporting { * * Conflicts trample with a warning. */ - static addFileSource(key: string, callback: SourceCallback): {remove: () => void} { + static addFileSource( + key: string, + callback: SourceCallback, + ): {remove: () => void} { return this._addSource(key, callback, BugReporting._fileSources); } - static _addSource(key: string, callback: SourceCallback, source: Map): {remove: () => void} { + static _addSource( + key: string, + callback: SourceCallback, + source: Map, + ): {remove: () => void} { BugReporting._maybeInit(); if (source.has(key)) { - console.warn(`BugReporting.add* called multiple times for same key '${key}'`); + console.warn( + `BugReporting.add* called multiple times for same key '${key}'`, + ); } source.set(key, callback); - return {remove: () => { source.delete(key); }}; + return { + remove: () => { + source.delete(key); + }, + }; } /** @@ -106,7 +132,7 @@ class BugReporting { RedBoxNativeModule.setExtraData && RedBoxNativeModule.setExtraData(extraData, 'From BugReporting.js'); - return { extras: extraData, files: fileData }; + return {extras: extraData, files: fileData}; } } diff --git a/Libraries/BugReporting/dumpReactTree.js b/Libraries/BugReporting/dumpReactTree.js index 6ffe64244e50f9..844585714703c6 100644 --- a/Libraries/BugReporting/dumpReactTree.js +++ b/Libraries/BugReporting/dumpReactTree.js @@ -4,8 +4,10 @@ * 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'; /* @@ -35,7 +37,7 @@ function getReactTree() { 'React tree dumps have been temporarily disabled while React is ' + 'upgraded to Fiber.' ); -/* + /* let output = ''; const rootIds = Object.getOwnPropertyNames(ReactNativeMount._instancesByContainerID); for (const rootId of rootIds) { diff --git a/Libraries/BugReporting/getReactData.js b/Libraries/BugReporting/getReactData.js index f995e8f41967c4..b4d1c4a32fd557 100644 --- a/Libraries/BugReporting/getReactData.js +++ b/Libraries/BugReporting/getReactData.js @@ -4,8 +4,10 @@ * 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'; /** @@ -31,7 +33,10 @@ function getData(element: Object): Object { if (typeof element !== 'object') { nodeType = 'Text'; text = element + ''; - } else if (element._currentElement === null || element._currentElement === false) { + } else if ( + element._currentElement === null || + element._currentElement === false + ) { nodeType = 'Empty'; } else if (element._renderedComponent) { nodeType = 'NativeWrapper'; @@ -65,7 +70,11 @@ function getData(element: Object): Object { name = element.getName(); // 0.14 top-level wrapper // TODO(jared): The backend should just act as if these don't exist. - if (element._renderedComponent && element._currentElement.props === element._renderedComponent._currentElement) { + if ( + element._renderedComponent && + element._currentElement.props === + element._renderedComponent._currentElement + ) { nodeType = 'Wrapper'; } if (name === null) { @@ -133,7 +142,7 @@ function setInContext(inst, path: Array, value: any) { function setIn(obj: Object, path: Array, value: any) { const last = path.pop(); - const parent = path.reduce((obj_, attr) => obj_ ? obj_[attr] : null, obj); + const parent = path.reduce((obj_, attr) => (obj_ ? obj_[attr] : null), obj); if (parent) { parent[last] = value; } @@ -158,7 +167,11 @@ function copyWithSetImpl(obj, path, idx, value) { return updated; } -function copyWithSet(obj: Object | Array, path: Array, value: any): Object | Array { +function copyWithSet( + obj: Object | Array, + path: Array, + value: any, +): Object | Array { return copyWithSetImpl(obj, path, 0, value); } diff --git a/Libraries/CameraRoll/ImagePickerIOS.js b/Libraries/CameraRoll/ImagePickerIOS.js index b653c11090e2de..785f4b57cb6b56 100644 --- a/Libraries/CameraRoll/ImagePickerIOS.js +++ b/Libraries/CameraRoll/ImagePickerIOS.js @@ -4,8 +4,10 @@ * 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 RCTImagePicker = require('NativeModules').ImagePickerIOS; @@ -17,20 +19,36 @@ const ImagePickerIOS = { canUseCamera: function(callback: Function) { return RCTImagePicker.canUseCamera(callback); }, - openCameraDialog: function(config: Object, successCallback: Function, cancelCallback: Function) { + openCameraDialog: function( + config: Object, + successCallback: Function, + cancelCallback: Function, + ) { config = { videoMode: false, ...config, }; - return RCTImagePicker.openCameraDialog(config, successCallback, cancelCallback); + return RCTImagePicker.openCameraDialog( + config, + successCallback, + cancelCallback, + ); }, - openSelectDialog: function(config: Object, successCallback: Function, cancelCallback: Function) { + openSelectDialog: function( + config: Object, + successCallback: Function, + cancelCallback: Function, + ) { config = { showImages: true, showVideos: false, ...config, }; - return RCTImagePicker.openSelectDialog(config, successCallback, cancelCallback); + return RCTImagePicker.openSelectDialog( + config, + successCallback, + cancelCallback, + ); }, }; diff --git a/Libraries/Color/normalizeColor.js b/Libraries/Color/normalizeColor.js index 59b3eb33ba5d0e..7b4ca253107dd4 100755 --- a/Libraries/Color/normalizeColor.js +++ b/Libraries/Color/normalizeColor.js @@ -4,8 +4,10 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * + * @format * @flow */ + /* eslint no-bitwise: 0 */ 'use strict'; @@ -30,30 +32,39 @@ function normalizeColor(color: string | number): ?number { if ((match = matchers.rgb.exec(color))) { return ( - (// b - (parse255(match[1]) << 24 | // r - parse255(match[2]) << 16 | // g - parse255(match[3]) << 8 | 0x000000ff)) // a - ) >>> 0; + // b + ((parse255(match[1]) << 24) | // r + (parse255(match[2]) << 16) | // g + (parse255(match[3]) << 8) | + 0x000000ff) >>> // a + 0 + ); } if ((match = matchers.rgba.exec(color))) { return ( - (// b - (parse255(match[1]) << 24 | // r - parse255(match[2]) << 16 | // g - parse255(match[3]) << 8 | parse1(match[4]))) // a - ) >>> 0; + // b + ((parse255(match[1]) << 24) | // r + (parse255(match[2]) << 16) | // g + (parse255(match[3]) << 8) | + parse1(match[4])) >>> // a + 0 + ); } if ((match = matchers.hex3.exec(color))) { - return parseInt( - match[1] + match[1] + // r - match[2] + match[2] + // g - match[3] + match[3] + // b - 'ff', // a - 16 - ) >>> 0; + return ( + parseInt( + match[1] + + match[1] + // r + match[2] + + match[2] + // g + match[3] + + match[3] + // b + 'ff', // a + 16, + ) >>> 0 + ); } // https://drafts.csswg.org/css-color-4/#hex-notation @@ -62,13 +73,19 @@ function normalizeColor(color: string | number): ?number { } if ((match = matchers.hex4.exec(color))) { - return parseInt( - match[1] + match[1] + // r - match[2] + match[2] + // g - match[3] + match[3] + // b - match[4] + match[4], // a - 16 - ) >>> 0; + return ( + parseInt( + match[1] + + match[1] + // r + match[2] + + match[2] + // g + match[3] + + match[3] + // b + match[4] + + match[4], // a + 16, + ) >>> 0 + ); } if ((match = matchers.hsl.exec(color))) { @@ -76,9 +93,11 @@ function normalizeColor(color: string | number): ?number { (hslToRgb( parse360(match[1]), // h parsePercentage(match[2]), // s - parsePercentage(match[3]) // l - ) | 0x000000ff) // a - ) >>> 0; + parsePercentage(match[3]), // l + ) | + 0x000000ff) >>> // a + 0 + ); } if ((match = matchers.hsla.exec(color))) { @@ -86,9 +105,11 @@ function normalizeColor(color: string | number): ?number { (hslToRgb( parse360(match[1]), // h parsePercentage(match[2]), // s - parsePercentage(match[3]) // l - ) | parse1(match[4])) // a - ) >>> 0; + parsePercentage(match[3]), // l + ) | + parse1(match[4])) >>> // a + 0 + ); } return null; @@ -121,9 +142,9 @@ function hslToRgb(h: number, s: number, l: number): number { const b = hue2rgb(p, q, h - 1 / 3); return ( - Math.round(r * 255) << 24 | - Math.round(g * 255) << 16 | - Math.round(b * 255) << 8 + (Math.round(r * 255) << 24) | + (Math.round(g * 255) << 16) | + (Math.round(b * 255) << 8) ); } @@ -159,7 +180,7 @@ function parse255(str: string): number { function parse360(str: string): number { const int = parseFloat(str); - return (((int % 360) + 360) % 360) / 360; + return ((int % 360 + 360) % 360) / 360; } function parse1(str: string): number { diff --git a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js index 232370b5cbf827..dfa09b53a466aa 100644 --- a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js +++ b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js @@ -4,8 +4,10 @@ * 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 NativeModules = require('NativeModules'); @@ -32,33 +34,30 @@ const _subscriptions = new Map(); */ const AccessibilityInfo = { - fetch: function(): Promise { return new Promise((resolve, reject) => { - RCTAccessibilityInfo.isTouchExplorationEnabled( - function(resp) { - resolve(resp); - } - ); + RCTAccessibilityInfo.isTouchExplorationEnabled(function(resp) { + resolve(resp); + }); }); }, - addEventListener: function ( + addEventListener: function( eventName: ChangeEventName, - handler: Function + handler: Function, ): void { const listener = RCTDeviceEventEmitter.addListener( TOUCH_EXPLORATION_EVENT, - (enabled) => { + enabled => { handler(enabled); - } + }, ); _subscriptions.set(handler, listener); }, removeEventListener: function( eventName: ChangeEventName, - handler: Function + handler: Function, ): void { const listener = _subscriptions.get(handler); if (!listener) { @@ -67,7 +66,6 @@ const AccessibilityInfo = { listener.remove(); _subscriptions.delete(handler); }, - }; module.exports = AccessibilityInfo; diff --git a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.ios.js b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.ios.js index d1b36494e99acb..8f2b0aa78dc064 100644 --- a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.ios.js +++ b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.ios.js @@ -4,8 +4,10 @@ * 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 NativeModules = require('NativeModules'); @@ -19,7 +21,7 @@ const ANNOUNCEMENT_DID_FINISH_EVENT = 'announcementDidFinish'; type ChangeEventName = $Enum<{ change: string, - announcementFinished: string + announcementFinished: string, }>; const _subscriptions = new Map(); @@ -34,7 +36,6 @@ const _subscriptions = new Map(); * See http://facebook.github.io/react-native/docs/accessibilityinfo.html */ const AccessibilityInfo = { - /** * Query whether a screen reader is currently enabled. * @@ -45,10 +46,7 @@ const AccessibilityInfo = { */ fetch: function(): Promise { return new Promise((resolve, reject) => { - AccessibilityManager.getCurrentVoiceOverState( - resolve, - reject - ); + AccessibilityManager.getCurrentVoiceOverState(resolve, reject); }); }, @@ -67,27 +65,28 @@ const AccessibilityInfo = { * * See http://facebook.github.io/react-native/docs/accessibilityinfo.html#addeventlistener */ - addEventListener: function ( + addEventListener: function( eventName: ChangeEventName, - handler: Function + handler: Function, ): Object { let listener; if (eventName === 'change') { - listener = RCTDeviceEventEmitter.addListener( - VOICE_OVER_EVENT, - handler - ); + listener = RCTDeviceEventEmitter.addListener(VOICE_OVER_EVENT, handler); } else if (eventName === 'announcementFinished') { listener = RCTDeviceEventEmitter.addListener( ANNOUNCEMENT_DID_FINISH_EVENT, - handler + handler, ); } _subscriptions.set(handler, listener); return { - remove: AccessibilityInfo.removeEventListener.bind(null, eventName, handler), + remove: AccessibilityInfo.removeEventListener.bind( + null, + eventName, + handler, + ), }; }, @@ -98,9 +97,7 @@ const AccessibilityInfo = { * * See http://facebook.github.io/react-native/docs/accessibilityinfo.html#setaccessibilityfocus */ - setAccessibilityFocus: function( - reactTag: number - ): void { + setAccessibilityFocus: function(reactTag: number): void { AccessibilityManager.setAccessibilityFocus(reactTag); }, @@ -111,9 +108,7 @@ const AccessibilityInfo = { * * See http://facebook.github.io/react-native/docs/accessibilityinfo.html#announceforaccessibility */ - announceForAccessibility: function( - announcement: string - ): void { + announceForAccessibility: function(announcement: string): void { AccessibilityManager.announceForAccessibility(announcement); }, @@ -124,7 +119,7 @@ const AccessibilityInfo = { */ removeEventListener: function( eventName: ChangeEventName, - handler: Function + handler: Function, ): void { const listener = _subscriptions.get(handler); if (!listener) { @@ -133,7 +128,6 @@ const AccessibilityInfo = { listener.remove(); _subscriptions.delete(handler); }, - }; module.exports = AccessibilityInfo; diff --git a/Libraries/Components/ActivityIndicator/ActivityIndicator.js b/Libraries/Components/ActivityIndicator/ActivityIndicator.js index 9692cbf8073e11..a3bf769f77c761 100644 --- a/Libraries/Components/ActivityIndicator/ActivityIndicator.js +++ b/Libraries/Components/ActivityIndicator/ActivityIndicator.js @@ -4,8 +4,10 @@ * 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 ColorPropType = require('ColorPropType'); @@ -31,7 +33,7 @@ type DefaultProps = { color: any, hidesWhenStopped: boolean, size: IndicatorSize, -} +}; /** * Displays a circular loading indicator. @@ -63,7 +65,7 @@ const ActivityIndicator = createReactClass({ * See http://facebook.github.io/react-native/docs/activityindicator.html#size */ size: PropTypes.oneOfType([ - PropTypes.oneOf([ 'small', 'large' ]), + PropTypes.oneOf(['small', 'large']), PropTypes.number, ]), /** @@ -117,14 +119,14 @@ const ActivityIndicator = createReactClass({ )} ); - } + }, }); if (Platform.OS === 'ios') { RCTActivityIndicator = requireNativeComponent( 'RCTActivityIndicatorView', ActivityIndicator, - { nativeOnly: { activityIndicatorViewStyle: true } } + {nativeOnly: {activityIndicatorViewStyle: true}}, ); } diff --git a/Libraries/Components/AppleTV/TVEventHandler.js b/Libraries/Components/AppleTV/TVEventHandler.js index 303e07617f9825..567776b5d9bfa9 100644 --- a/Libraries/Components/AppleTV/TVEventHandler.js +++ b/Libraries/Components/AppleTV/TVEventHandler.js @@ -4,12 +4,15 @@ * 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 Platform = require('Platform'); -const TVNavigationEventEmitter = require('NativeModules').TVNavigationEventEmitter; +const TVNavigationEventEmitter = require('NativeModules') + .TVNavigationEventEmitter; const NativeEventEmitter = require('NativeEventEmitter'); function TVEventHandler() { @@ -17,19 +20,24 @@ function TVEventHandler() { this.__nativeTVNavigationEventEmitter = null; } -TVEventHandler.prototype.enable = function(component: ?any, callback: Function) { +TVEventHandler.prototype.enable = function( + component: ?any, + callback: Function, +) { if (Platform.OS === 'ios' && !TVNavigationEventEmitter) { return; } - this.__nativeTVNavigationEventEmitter = new NativeEventEmitter(TVNavigationEventEmitter); + this.__nativeTVNavigationEventEmitter = new NativeEventEmitter( + TVNavigationEventEmitter, + ); this.__nativeTVNavigationEventListener = this.__nativeTVNavigationEventEmitter.addListener( 'onHWKeyEvent', - (data) => { + data => { if (callback) { callback(component, data); } - } + }, ); }; diff --git a/Libraries/Components/AppleTV/TVViewPropTypes.js b/Libraries/Components/AppleTV/TVViewPropTypes.js index 831d5c3992d746..656450df247aea 100644 --- a/Libraries/Components/AppleTV/TVViewPropTypes.js +++ b/Libraries/Components/AppleTV/TVViewPropTypes.js @@ -4,8 +4,10 @@ * 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 PropTypes = require('prop-types'); @@ -13,66 +15,65 @@ const PropTypes = require('prop-types'); * Additional View properties for Apple TV */ const TVViewPropTypes = { - /** - * When set to true, this view will be focusable - * and navigable using the TV remote. - */ - isTVSelectable: PropTypes.bool, - - /** - * May be set to true to force the TV focus engine to move focus to this view. - */ - hasTVPreferredFocus: PropTypes.bool, + /** + * When set to true, this view will be focusable + * and navigable using the TV remote. + */ + isTVSelectable: PropTypes.bool, - /** - * *(Apple TV only)* Object with properties to control Apple TV parallax effects. - * - * enabled: If true, parallax effects are enabled. Defaults to true. - * shiftDistanceX: Defaults to 2.0. - * shiftDistanceY: Defaults to 2.0. - * tiltAngle: Defaults to 0.05. - * magnification: Defaults to 1.0. - * pressMagnification: Defaults to 1.0. - * pressDuration: Defaults to 0.3. - * pressDelay: Defaults to 0.0. - * - * @platform ios - */ - tvParallaxProperties: PropTypes.object, + /** + * May be set to true to force the TV focus engine to move focus to this view. + */ + hasTVPreferredFocus: PropTypes.bool, - /** - * *(Apple TV only)* May be used to change the appearance of the Apple TV parallax effect when this view goes in or out of focus. Defaults to 2.0. - * - * @platform ios - */ - tvParallaxShiftDistanceX: PropTypes.number, + /** + * *(Apple TV only)* Object with properties to control Apple TV parallax effects. + * + * enabled: If true, parallax effects are enabled. Defaults to true. + * shiftDistanceX: Defaults to 2.0. + * shiftDistanceY: Defaults to 2.0. + * tiltAngle: Defaults to 0.05. + * magnification: Defaults to 1.0. + * pressMagnification: Defaults to 1.0. + * pressDuration: Defaults to 0.3. + * pressDelay: Defaults to 0.0. + * + * @platform ios + */ + tvParallaxProperties: PropTypes.object, - /** - * *(Apple TV only)* May be used to change the appearance of the Apple TV parallax effect when this view goes in or out of focus. Defaults to 2.0. - * - * @platform ios - */ - tvParallaxShiftDistanceY: PropTypes.number, + /** + * *(Apple TV only)* May be used to change the appearance of the Apple TV parallax effect when this view goes in or out of focus. Defaults to 2.0. + * + * @platform ios + */ + tvParallaxShiftDistanceX: PropTypes.number, - /** - * *(Apple TV only)* May be used to change the appearance of the Apple TV parallax effect when this view goes in or out of focus. Defaults to 0.05. - * - * @platform ios - */ - tvParallaxTiltAngle: PropTypes.number, + /** + * *(Apple TV only)* May be used to change the appearance of the Apple TV parallax effect when this view goes in or out of focus. Defaults to 2.0. + * + * @platform ios + */ + tvParallaxShiftDistanceY: PropTypes.number, - /** - * *(Apple TV only)* May be used to change the appearance of the Apple TV parallax effect when this view goes in or out of focus. Defaults to 1.0. - * - * @platform ios - */ - tvParallaxMagnification: PropTypes.number, + /** + * *(Apple TV only)* May be used to change the appearance of the Apple TV parallax effect when this view goes in or out of focus. Defaults to 0.05. + * + * @platform ios + */ + tvParallaxTiltAngle: PropTypes.number, + /** + * *(Apple TV only)* May be used to change the appearance of the Apple TV parallax effect when this view goes in or out of focus. Defaults to 1.0. + * + * @platform ios + */ + tvParallaxMagnification: PropTypes.number, }; export type TVViewProps = { - isTVSelectable?: bool, - hasTVPreferredFocus?: bool, + isTVSelectable?: boolean, + hasTVPreferredFocus?: boolean, tvParallaxProperties?: Object, tvParallaxShiftDistanceX?: number, tvParallaxShiftDistanceY?: number, diff --git a/Libraries/Components/Button.js b/Libraries/Components/Button.js index 2956b1a1245b52..22c376467ea9bc 100644 --- a/Libraries/Components/Button.js +++ b/Libraries/Components/Button.js @@ -4,8 +4,10 @@ * 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 ColorPropType = require('ColorPropType'); @@ -117,8 +119,10 @@ class Button extends React.Component<{ typeof title === 'string', 'The title prop of a Button must be a string', ); - const formattedTitle = Platform.OS === 'android' ? title.toUpperCase() : title; - const Touchable = Platform.OS === 'android' ? TouchableNativeFeedback : TouchableOpacity; + const formattedTitle = + Platform.OS === 'android' ? title.toUpperCase() : title; + const Touchable = + Platform.OS === 'android' ? TouchableNativeFeedback : TouchableOpacity; return ( - {formattedTitle} + + {formattedTitle} + ); @@ -166,7 +172,7 @@ const styles = StyleSheet.create({ android: { elevation: 0, backgroundColor: '#dfdfdf', - } + }, }), textDisabled: Platform.select({ ios: { @@ -174,7 +180,7 @@ const styles = StyleSheet.create({ }, android: { color: '#a1a1a1', - } + }, }), }); diff --git a/Libraries/Components/Clipboard/Clipboard.js b/Libraries/Components/Clipboard/Clipboard.js index 0bf3b470774c1c..706bc0fba8c9b7 100644 --- a/Libraries/Components/Clipboard/Clipboard.js +++ b/Libraries/Components/Clipboard/Clipboard.js @@ -4,8 +4,10 @@ * 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 Clipboard = require('NativeModules').Clipboard; @@ -36,5 +38,5 @@ module.exports = { */ setString(content: string) { Clipboard.setString(content); - } + }, }; diff --git a/Libraries/Components/DatePicker/DatePickerIOS.android.js b/Libraries/Components/DatePicker/DatePickerIOS.android.js index d2053808699cad..585be6e297673d 100644 --- a/Libraries/Components/DatePicker/DatePickerIOS.android.js +++ b/Libraries/Components/DatePicker/DatePickerIOS.android.js @@ -4,6 +4,7 @@ * 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'; @@ -17,7 +18,9 @@ class DummyDatePickerIOS extends React.Component { render() { return ( - DatePickerIOS is not supported on this platform! + + DatePickerIOS is not supported on this platform! + ); } @@ -37,7 +40,7 @@ const styles = StyleSheet.create({ datePickerText: { color: '#333333', margin: 20, - } + }, }); module.exports = DummyDatePickerIOS; diff --git a/Libraries/Components/DatePicker/DatePickerIOS.ios.js b/Libraries/Components/DatePicker/DatePickerIOS.ios.js index 41b0a88969ab37..7a5455e60537dd 100644 --- a/Libraries/Components/DatePicker/DatePickerIOS.ios.js +++ b/Libraries/Components/DatePicker/DatePickerIOS.ios.js @@ -4,10 +4,13 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @flow * * This is a controlled component version of RCTDatePickerIOS + * + * @format + * @flow */ + 'use strict'; const NativeMethodsMixin = require('NativeMethodsMixin'); @@ -125,9 +128,8 @@ const DatePickerIOS = createReactClass({ _onChange: function(event: Event) { const nativeTimeStamp = event.nativeEvent.timestamp; - this.props.onDateChange && this.props.onDateChange( - new Date(nativeTimeStamp) - ); + this.props.onDateChange && + this.props.onDateChange(new Date(nativeTimeStamp)); // $FlowFixMe(>=0.41.0) this.props.onChange && this.props.onChange(event); }, @@ -141,9 +143,17 @@ const DatePickerIOS = createReactClass({ return ( { this._picker = picker; } } + ref={picker => { + this._picker = picker; + }} style={styles.datePickerIOS} - date={props.date ? props.date.getTime() : props.initialDate ? props.initialDate.getTime() : undefined} + date={ + props.date + ? props.date.getTime() + : props.initialDate + ? props.initialDate.getTime() + : undefined + } locale={props.locale ? props.locale : undefined} maximumDate={ props.maximumDate ? props.maximumDate.getTime() : undefined @@ -160,7 +170,7 @@ const DatePickerIOS = createReactClass({ /> ); - } + }, }); const styles = StyleSheet.create({ @@ -178,7 +188,7 @@ const RCTDatePickerIOS = requireNativeComponent('RCTDatePicker', { maximumDate: PropTypes.number, onDateChange: () => null, onChange: PropTypes.func, - } + }, }); module.exports = DatePickerIOS; diff --git a/Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js b/Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js index 23691ce10882de..bd91263a8f9b49 100644 --- a/Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js +++ b/Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js @@ -4,8 +4,10 @@ * 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 DatePickerModule = require('NativeModules').DatePickerAndroid; @@ -76,11 +78,15 @@ class DatePickerAndroid { /** * A date has been selected. */ - static get dateSetAction() { return 'dateSetAction'; } + static get dateSetAction() { + return 'dateSetAction'; + } /** * The dialog has been dismissed. */ - static get dismissedAction() { return 'dismissedAction'; } + static get dismissedAction() { + return 'dismissedAction'; + } } module.exports = DatePickerAndroid; diff --git a/Libraries/Components/DatePickerAndroid/DatePickerAndroid.ios.js b/Libraries/Components/DatePickerAndroid/DatePickerAndroid.ios.js index 4895dfd8286d18..a158f035c303d3 100644 --- a/Libraries/Components/DatePickerAndroid/DatePickerAndroid.ios.js +++ b/Libraries/Components/DatePickerAndroid/DatePickerAndroid.ios.js @@ -4,14 +4,16 @@ * 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 DatePickerAndroid = { async open(options: Object): Promise { return Promise.reject({ - message: 'DatePickerAndroid is not supported on this platform.' + message: 'DatePickerAndroid is not supported on this platform.', }); }, }; diff --git a/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js b/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js index f9d84442448b80..6b983cb2ad27f9 100644 --- a/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js +++ b/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js @@ -4,7 +4,9 @@ * 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 ColorPropType = require('ColorPropType'); @@ -28,11 +30,7 @@ const requireNativeComponent = require('requireNativeComponent'); const RK_DRAWER_REF = 'drawerlayout'; const INNERVIEW_REF = 'innerView'; -const DRAWER_STATES = [ - 'Idle', - 'Dragging', - 'Settling', -]; +const DRAWER_STATES = ['Idle', 'Dragging', 'Settling']; /** * React component that wraps the platform `DrawerLayout` (Android only). The @@ -99,7 +97,7 @@ const DrawerLayoutAndroid = createReactClass({ */ drawerPosition: PropTypes.oneOf([ DrawerConsts.DrawerPosition.Left, - DrawerConsts.DrawerPosition.Right + DrawerConsts.DrawerPosition.Right, ]), /** * Specifies the width of the drawer, more precisely the width of the view that be pulled in @@ -116,7 +114,7 @@ const DrawerLayoutAndroid = createReactClass({ drawerLockMode: PropTypes.oneOf([ 'unlocked', 'locked-closed', - 'locked-open' + 'locked-open', ]), /** * Function called whenever there is an interaction with the navigation view. @@ -168,31 +166,41 @@ const DrawerLayoutAndroid = createReactClass({ }, render: function() { - const drawStatusBar = Platform.Version >= 21 && this.props.statusBarBackgroundColor; - const drawerViewWrapper = + const drawStatusBar = + Platform.Version >= 21 && this.props.statusBarBackgroundColor; + const drawerViewWrapper = ( {this.props.renderNavigationView()} {drawStatusBar && } - ; - const childrenWrapper = + + ); + const childrenWrapper = ( - {drawStatusBar && - } - {drawStatusBar && - } + {drawStatusBar && ( + + )} + {drawStatusBar && ( + + )} {this.props.children} - ; + + ); return ( { - * this.refs.DRAWER.openDrawer() - * } - * this.closeDrawer = () => { - * this.refs.DRAWER.closeDrawer() - * } - * return ( - * - * - * ) - * } - */ + * Closing and opening example + * Note: To access the drawer you have to give it a ref. Refs do not work on stateless components + * render () { + * this.openDrawer = () => { + * this.refs.DRAWER.openDrawer() + * } + * this.closeDrawer = () => { + * this.refs.DRAWER.closeDrawer() + * } + * return ( + * + * + * ) + * } + */ _getDrawerLayoutHandle: function() { return ReactNative.findNodeHandle(this.refs[RK_DRAWER_REF]); }, - }); const styles = StyleSheet.create({ @@ -312,6 +321,9 @@ const styles = StyleSheet.create({ }); // The View that contains both the actual drawer and the main view -const AndroidDrawerLayout = requireNativeComponent('AndroidDrawerLayout', DrawerLayoutAndroid); +const AndroidDrawerLayout = requireNativeComponent( + 'AndroidDrawerLayout', + DrawerLayoutAndroid, +); module.exports = DrawerLayoutAndroid; diff --git a/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.ios.js b/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.ios.js index ebd42dd5b18bb0..260d559929796f 100644 --- a/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.ios.js +++ b/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.ios.js @@ -4,7 +4,9 @@ * 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('UnimplementedView'); diff --git a/Libraries/Components/Keyboard/Keyboard.js b/Libraries/Components/Keyboard/Keyboard.js index d61b07a88670f7..da76db76eee3d2 100644 --- a/Libraries/Components/Keyboard/Keyboard.js +++ b/Libraries/Components/Keyboard/Keyboard.js @@ -4,8 +4,10 @@ * 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 LayoutAnimation = require('LayoutAnimation'); diff --git a/Libraries/Components/Keyboard/KeyboardAvoidingView.js b/Libraries/Components/Keyboard/KeyboardAvoidingView.js index 87a0172f2091c0..c559608d34c6a4 100644 --- a/Libraries/Components/Keyboard/KeyboardAvoidingView.js +++ b/Libraries/Components/Keyboard/KeyboardAvoidingView.js @@ -4,8 +4,10 @@ * 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 createReactClass = require('create-react-class'); @@ -66,9 +68,9 @@ const KeyboardAvoidingView = createReactClass({ */ keyboardVerticalOffset: PropTypes.number.isRequired, /** - * This is to allow us to manually control which KAV shuld take effect when - * having more than one KAV at the same screen - */ + * This is to allow us to manually control which KAV shuld take effect when + * having more than one KAV at the same screen + */ enabled: PropTypes.bool.isRequired, }, @@ -130,10 +132,16 @@ const KeyboardAvoidingView = createReactClass({ this.frame = event.nativeEvent.layout; }, - UNSAFE_componentWillUpdate(nextProps: Object, nextState: Object, nextContext?: Object): void { - if (nextState.bottom === this.state.bottom && - this.props.behavior === 'height' && - nextProps.behavior === 'height') { + UNSAFE_componentWillUpdate( + nextProps: Object, + nextState: Object, + nextContext?: Object, + ): void { + if ( + nextState.bottom === this.state.bottom && + this.props.behavior === 'height' && + nextProps.behavior === 'height' + ) { // If the component rerenders without an internal state change, e.g. // triggered by parent component re-rendering, no need for bottom to change. nextState.bottom = 0; @@ -154,7 +162,7 @@ const KeyboardAvoidingView = createReactClass({ }, componentWillUnmount() { - this.subscriptions.forEach((sub) => sub.remove()); + this.subscriptions.forEach(sub => sub.remove()); }, render(): React.Element { @@ -172,17 +180,25 @@ const KeyboardAvoidingView = createReactClass({ heightStyle = {height: this.frame.height - bottomHeight, flex: 0}; } return ( - + {children} ); case 'position': const positionStyle = {bottom: bottomHeight}; - const { contentContainerStyle } = this.props; + const {contentContainerStyle} = this.props; return ( - + {children} @@ -192,14 +208,22 @@ const KeyboardAvoidingView = createReactClass({ case 'padding': const paddingStyle = {paddingBottom: bottomHeight}; return ( - + {children} ); default: return ( - + {children} ); diff --git a/Libraries/Components/LazyRenderer.js b/Libraries/Components/LazyRenderer.js index b1217aa1f3a2a9..23164141a3ede8 100644 --- a/Libraries/Components/LazyRenderer.js +++ b/Libraries/Components/LazyRenderer.js @@ -4,7 +4,9 @@ * 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'); @@ -22,14 +24,14 @@ const LazyRenderer = createReactClass({ UNSAFE_componentWillMount: function(): void { this.setState({ - _lazyRender : true, + _lazyRender: true, }); }, componentDidMount: function(): void { requestAnimationFrame(() => { this.setState({ - _lazyRender : false, + _lazyRender: false, }); }); }, diff --git a/Libraries/Components/MaskedView/MaskedViewIOS.android.js b/Libraries/Components/MaskedView/MaskedViewIOS.android.js index 9684447d0fea12..49d44e1541dcd5 100644 --- a/Libraries/Components/MaskedView/MaskedViewIOS.android.js +++ b/Libraries/Components/MaskedView/MaskedViewIOS.android.js @@ -4,8 +4,10 @@ * 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'; module.exports = require('UnimplementedView'); diff --git a/Libraries/Components/MaskedView/MaskedViewIOS.ios.js b/Libraries/Components/MaskedView/MaskedViewIOS.ios.js index 0407d3be089f04..9f24f4edcf8c53 100644 --- a/Libraries/Components/MaskedView/MaskedViewIOS.ios.js +++ b/Libraries/Components/MaskedView/MaskedViewIOS.ios.js @@ -4,6 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * + * @format * @flow */ @@ -14,7 +15,7 @@ const View = require('View'); const ViewPropTypes = require('ViewPropTypes'); const requireNativeComponent = require('requireNativeComponent'); -import type { ViewProps } from 'ViewPropTypes'; +import type {ViewProps} from 'ViewPropTypes'; type Props = ViewProps & { children: any, @@ -70,13 +71,13 @@ class MaskedViewIOS extends React.Component { _hasWarnedInvalidRenderMask = false; render() { - const { maskElement, children, ...otherViewProps } = this.props; + const {maskElement, children, ...otherViewProps} = this.props; if (!React.isValidElement(maskElement)) { if (!this._hasWarnedInvalidRenderMask) { console.warn( 'MaskedView: Invalid `maskElement` prop was passed to MaskedView. ' + - 'Expected a React Element. No mask will render.' + 'Expected a React Element. No mask will render.', ); this._hasWarnedInvalidRenderMask = true; } diff --git a/Libraries/Components/Navigation/NavigatorIOS.android.js b/Libraries/Components/Navigation/NavigatorIOS.android.js index ebd42dd5b18bb0..260d559929796f 100644 --- a/Libraries/Components/Navigation/NavigatorIOS.android.js +++ b/Libraries/Components/Navigation/NavigatorIOS.android.js @@ -4,7 +4,9 @@ * 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('UnimplementedView'); diff --git a/Libraries/Components/Navigation/NavigatorIOS.ios.js b/Libraries/Components/Navigation/NavigatorIOS.ios.js index 36223bfadca306..8f28d79147fe77 100644 --- a/Libraries/Components/Navigation/NavigatorIOS.ios.js +++ b/Libraries/Components/Navigation/NavigatorIOS.ios.js @@ -4,8 +4,10 @@ * 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 EventEmitter = require('EventEmitter'); @@ -40,14 +42,12 @@ class NavigatorTransitionerIOS extends React.Component<$FlowFixMeProps> { requestSchedulingNavigation(cb) { RCTNavigatorManager.requestSchedulingJavaScriptNavigation( ReactNative.findNodeHandle(this), - cb + cb, ); } render() { - return ( - - ); + return ; } } @@ -107,7 +107,7 @@ type State = { toIndex: number, makingNavigatorRequest: boolean, updatingAllIndicesAtOrBeyond: ?number, -} +}; type Event = Object; @@ -308,7 +308,6 @@ const NavigatorIOS = createReactClass({ displayName: 'NavigatorIOS', propTypes: { - /** * NavigatorIOS uses `route` objects to identify child views, their props, * and navigation bar configuration. Navigation operations such as push @@ -436,17 +435,16 @@ const NavigatorIOS = createReactClass({ */ barStyle: PropTypes.oneOf(['default', 'black']), - /** + /** * The text color of the navigation bar title. */ titleTextColor: PropTypes.string, - /** + /** * Boolean value that indicates whether the navigation bar is * translucent. */ translucent: PropTypes.bool, - }).isRequired, /** @@ -507,7 +505,6 @@ const NavigatorIOS = createReactClass({ * behavior. */ interactivePopGestureEnabled: PropTypes.bool, - }, navigator: (undefined: ?Object), @@ -608,7 +605,7 @@ const NavigatorIOS = createReactClass({ _tryLockNavigator: function(cb: () => void) { this.refs[TRANSITIONER_REF].requestSchedulingNavigation( - (acquiredLock) => acquiredLock && cb() + acquiredLock => acquiredLock && cb(), ); }, @@ -617,7 +614,9 @@ const NavigatorIOS = createReactClass({ invariant( newObservedTopOfStack <= this.state.requestedTopOfStack, - 'No navigator item should be pushed without JS knowing about it %s %s', newObservedTopOfStack, this.state.requestedTopOfStack + 'No navigator item should be pushed without JS knowing about it %s %s', + newObservedTopOfStack, + this.state.requestedTopOfStack, ); const wasWaitingForConfirmation = this.state.requestedTopOfStack !== this.state.observedTopOfStack; @@ -625,7 +624,7 @@ const NavigatorIOS = createReactClass({ invariant( newObservedTopOfStack === this.state.requestedTopOfStack, 'If waiting for observedTopOfStack to reach requestedTopOfStack, ' + - 'the only valid observedTopOfStack should be requestedTopOfStack.' + 'the only valid observedTopOfStack should be requestedTopOfStack.', ); } // Mark the most recent observation regardless of if we can lock the @@ -653,12 +652,15 @@ const NavigatorIOS = createReactClass({ // even uses the indices in this case, but let's make this describe the // truth anyways). const updatingAllIndicesAtOrBeyond = - this.state.routeStack.length > this.state.observedTopOfStack + 1 ? - this.state.observedTopOfStack + 1 : - null; + this.state.routeStack.length > this.state.observedTopOfStack + 1 + ? this.state.observedTopOfStack + 1 + : null; this.setState({ idStack: this.state.idStack.slice(0, this.state.observedTopOfStack + 1), - routeStack: this.state.routeStack.slice(0, this.state.observedTopOfStack + 1), + routeStack: this.state.routeStack.slice( + 0, + this.state.observedTopOfStack + 1, + ), // Now we rerequest the top of stack that we observed. requestedTopOfStack: this.state.observedTopOfStack, makingNavigatorRequest: true, @@ -675,7 +677,6 @@ const NavigatorIOS = createReactClass({ // Make sure all previous requests are caught up first. Otherwise reject. if (this.state.requestedTopOfStack === this.state.observedTopOfStack) { this._tryLockNavigator(() => { - const nextStack = this.state.routeStack.concat([route]); const nextIDStack = this.state.idStack.concat([getuid()]); this.setState({ @@ -752,7 +753,6 @@ const NavigatorIOS = createReactClass({ makingNavigatorRequest: false, updatingAllIndicesAtOrBeyond: index, }); - }, /** @@ -787,7 +787,7 @@ const NavigatorIOS = createReactClass({ const indexOfRoute = this.state.routeStack.indexOf(route); invariant( indexOfRoute !== -1, - 'Calling pop to route for a route that doesn\'t exist!' + "Calling pop to route for a route that doesn't exist!", ); const numToPop = this.state.routeStack.length - indexOfRoute - 1; this.popN(numToPop); @@ -851,16 +851,8 @@ const NavigatorIOS = createReactClass({ - + style={[styles.stackItem, itemWrapperStyle, wrapperStyle]}> + ); @@ -872,8 +864,9 @@ const NavigatorIOS = createReactClass({ this.state.updatingAllIndicesAtOrBeyond !== null; // If not recursing update to navigator at all, may as well avoid // computation of navigator children. - const items = shouldRecurseToNavigator ? - this.state.routeStack.map(this._routeToStackItem) : null; + const items = shouldRecurseToNavigator + ? this.state.routeStack.map(this._routeToStackItem) + : null; return ( + interactivePopGestureEnabled={ + this.props.interactivePopGestureEnabled + }> {items} @@ -911,9 +906,7 @@ const NavigatorIOS = createReactClass({ render: function() { return ( // $FlowFixMe(>=0.41.0) - - {this._renderNavigationStackItems()} - + {this._renderNavigationStackItems()} ); }, }); diff --git a/Libraries/Components/Picker/Picker.js b/Libraries/Components/Picker/Picker.js index 1212993191069a..1e3e96579e21cb 100644 --- a/Libraries/Components/Picker/Picker.js +++ b/Libraries/Components/Picker/Picker.js @@ -4,6 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * + * @format * @flow */ @@ -35,36 +36,36 @@ const MODE_DROPDOWN = 'dropdown'; * Individual selectable item in a Picker. */ class PickerItem extends React.Component<{ - label: string, - value?: any, - color?: ColorPropType, - testID?: string, + label: string, + value?: any, + color?: ColorPropType, + testID?: string, }> { - static propTypes = { - /** - * Text to display for this item. - */ - label: PropTypes.string.isRequired, - /** - * The value to be passed to picker's `onValueChange` callback when - * this item is selected. Can be a string or an integer. - */ - value: PropTypes.any, - /** - * Color of this item's text. - * @platform android - */ - color: ColorPropType, - /** - * Used to locate the item in end-to-end tests. - */ - testID: PropTypes.string, - }; + static propTypes = { + /** + * Text to display for this item. + */ + label: PropTypes.string.isRequired, + /** + * The value to be passed to picker's `onValueChange` callback when + * this item is selected. Can be a string or an integer. + */ + value: PropTypes.any, + /** + * Color of this item's text. + * @platform android + */ + color: ColorPropType, + /** + * Used to locate the item in end-to-end tests. + */ + testID: PropTypes.string, + }; - render() { - // The items are not rendered directly - throw null; - } + render() { + // The items are not rendered directly + throw null; + } } /** @@ -78,87 +79,89 @@ class PickerItem extends React.Component<{ * */ class Picker extends React.Component<{ - style?: $FlowFixMe, - selectedValue?: any, - onValueChange?: Function, - enabled?: boolean, - mode?: 'dialog' | 'dropdown', - itemStyle?: $FlowFixMe, - prompt?: string, - testID?: string, + style?: $FlowFixMe, + selectedValue?: any, + onValueChange?: Function, + enabled?: boolean, + mode?: 'dialog' | 'dropdown', + itemStyle?: $FlowFixMe, + prompt?: string, + testID?: string, }> { - /** - * On Android, display the options in a dialog. - */ - static MODE_DIALOG = MODE_DIALOG; + /** + * On Android, display the options in a dialog. + */ + static MODE_DIALOG = MODE_DIALOG; - /** - * On Android, display the options in a dropdown (this is the default). - */ - static MODE_DROPDOWN = MODE_DROPDOWN; + /** + * On Android, display the options in a dropdown (this is the default). + */ + static MODE_DROPDOWN = MODE_DROPDOWN; - static Item = PickerItem; + static Item = PickerItem; - static defaultProps = { - mode: MODE_DIALOG, - }; + static defaultProps = { + mode: MODE_DIALOG, + }; - // $FlowFixMe(>=0.41.0) - static propTypes = { - ...ViewPropTypes, - style: pickerStyleType, - /** - * Value matching value of one of the items. Can be a string or an integer. - */ - selectedValue: PropTypes.any, - /** - * Callback for when an item is selected. This is called with the following parameters: - * - `itemValue`: the `value` prop of the item that was selected - * - `itemPosition`: the index of the selected item in this picker - */ - onValueChange: PropTypes.func, - /** - * If set to false, the picker will be disabled, i.e. the user will not be able to make a - * selection. - * @platform android - */ - enabled: PropTypes.bool, - /** - * On Android, specifies how to display the selection items when the user taps on the picker: - * - * - 'dialog': Show a modal dialog. This is the default. - * - 'dropdown': Shows a dropdown anchored to the picker view - * - * @platform android - */ - mode: PropTypes.oneOf(['dialog', 'dropdown']), - /** - * Style to apply to each of the item labels. - * @platform ios - */ - itemStyle: itemStylePropType, - /** - * Prompt string for this picker, used on Android in dialog mode as the title of the dialog. - * @platform android - */ - prompt: PropTypes.string, - /** - * Used to locate this view in end-to-end tests. - */ - testID: PropTypes.string, - }; + // $FlowFixMe(>=0.41.0) + static propTypes = { + ...ViewPropTypes, + style: pickerStyleType, + /** + * Value matching value of one of the items. Can be a string or an integer. + */ + selectedValue: PropTypes.any, + /** + * Callback for when an item is selected. This is called with the following parameters: + * - `itemValue`: the `value` prop of the item that was selected + * - `itemPosition`: the index of the selected item in this picker + */ + onValueChange: PropTypes.func, + /** + * If set to false, the picker will be disabled, i.e. the user will not be able to make a + * selection. + * @platform android + */ + enabled: PropTypes.bool, + /** + * On Android, specifies how to display the selection items when the user taps on the picker: + * + * - 'dialog': Show a modal dialog. This is the default. + * - 'dropdown': Shows a dropdown anchored to the picker view + * + * @platform android + */ + mode: PropTypes.oneOf(['dialog', 'dropdown']), + /** + * Style to apply to each of the item labels. + * @platform ios + */ + itemStyle: itemStylePropType, + /** + * Prompt string for this picker, used on Android in dialog mode as the title of the dialog. + * @platform android + */ + prompt: PropTypes.string, + /** + * Used to locate this view in end-to-end tests. + */ + testID: PropTypes.string, + }; - render() { - if (Platform.OS === 'ios') { - // $FlowFixMe found when converting React.createClass to ES6 - return {this.props.children}; - } else if (Platform.OS === 'android') { - // $FlowFixMe found when converting React.createClass to ES6 - return {this.props.children}; - } else { - return ; - } - } + render() { + if (Platform.OS === 'ios') { + // $FlowFixMe found when converting React.createClass to ES6 + return {this.props.children}; + } else if (Platform.OS === 'android') { + return ( + // $FlowFixMe found when converting React.createClass to ES6 + {this.props.children} + ); + } else { + return ; + } + } } module.exports = Picker; diff --git a/Libraries/Components/Picker/PickerAndroid.android.js b/Libraries/Components/Picker/PickerAndroid.android.js index 6bc912bd6d33d3..c0ce723e479abb 100644 --- a/Libraries/Components/Picker/PickerAndroid.android.js +++ b/Libraries/Components/Picker/PickerAndroid.android.js @@ -4,6 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * + * @format * @flow */ @@ -33,15 +34,18 @@ type Event = Object; /** * Not exposed as a public API - use instead. */ -class PickerAndroid extends React.Component<{ - style?: $FlowFixMe, - selectedValue?: any, - enabled?: boolean, - mode?: 'dialog' | 'dropdown', - onValueChange?: Function, - prompt?: string, - testID?: string, -}, *> { +class PickerAndroid extends React.Component< + { + style?: $FlowFixMe, + selectedValue?: any, + enabled?: boolean, + mode?: 'dialog' | 'dropdown', + onValueChange?: Function, + prompt?: string, + testID?: string, + }, + *, +> { static propTypes = { ...ViewPropTypes, style: pickerStyleType, @@ -68,7 +72,7 @@ class PickerAndroid extends React.Component<{ } // Translate prop and children into stuff that the native picker understands. - _stateFromProps = (props) => { + _stateFromProps = props => { let selectedIndex = 0; const items = React.Children.map(props.children, (child, index) => { if (child.props.value === props.selectedValue) { @@ -87,7 +91,8 @@ class PickerAndroid extends React.Component<{ }; render() { - const Picker = this.props.mode === MODE_DROPDOWN ? DropdownPicker : DialogPicker; + const Picker = + this.props.mode === MODE_DROPDOWN ? DropdownPicker : DialogPicker; const nativeProps = { enabled: this.props.enabled, @@ -130,8 +135,13 @@ class PickerAndroid extends React.Component<{ // disallow/undo/mutate the selection of certain values. In other // words, the embedder of this component should be the source of // truth, not the native component. - if (this.refs[REF_PICKER] && this.state.selectedIndex !== this._lastNativePosition) { - this.refs[REF_PICKER].setNativeProps({selected: this.state.selectedIndex}); + if ( + this.refs[REF_PICKER] && + this.state.selectedIndex !== this._lastNativePosition + ) { + this.refs[REF_PICKER].setNativeProps({ + selected: this.state.selectedIndex, + }); this._lastNativePosition = this.state.selectedIndex; } } @@ -152,10 +162,18 @@ const cfg = { nativeOnly: { items: true, selected: true, - } + }, }; -const DropdownPicker = requireNativeComponent('AndroidDropdownPicker', PickerAndroid, cfg); -const DialogPicker = requireNativeComponent('AndroidDialogPicker', PickerAndroid, cfg); +const DropdownPicker = requireNativeComponent( + 'AndroidDropdownPicker', + PickerAndroid, + cfg, +); +const DialogPicker = requireNativeComponent( + 'AndroidDialogPicker', + PickerAndroid, + cfg, +); module.exports = PickerAndroid; diff --git a/Libraries/Components/Picker/PickerAndroid.ios.js b/Libraries/Components/Picker/PickerAndroid.ios.js index ebd42dd5b18bb0..260d559929796f 100644 --- a/Libraries/Components/Picker/PickerAndroid.ios.js +++ b/Libraries/Components/Picker/PickerAndroid.ios.js @@ -4,7 +4,9 @@ * 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('UnimplementedView'); diff --git a/Libraries/Components/Picker/PickerIOS.android.js b/Libraries/Components/Picker/PickerIOS.android.js index 2977696844b00f..36acfe18342b6f 100644 --- a/Libraries/Components/Picker/PickerIOS.android.js +++ b/Libraries/Components/Picker/PickerIOS.android.js @@ -6,7 +6,10 @@ * * * This is a controlled component version of RCTPickerIOS + * + * @format */ + 'use strict'; module.exports = require('UnimplementedView'); diff --git a/Libraries/Components/Picker/PickerIOS.ios.js b/Libraries/Components/Picker/PickerIOS.ios.js index fcd5b12c163322..881c33ce038ed3 100644 --- a/Libraries/Components/Picker/PickerIOS.ios.js +++ b/Libraries/Components/Picker/PickerIOS.ios.js @@ -6,7 +6,10 @@ * * * This is a controlled component version of RCTPickerIOS + * + * @format */ + 'use strict'; const NativeMethodsMixin = require('NativeMethodsMixin'); @@ -46,7 +49,7 @@ const PickerIOS = createReactClass({ _stateFromProps: function(props) { let selectedIndex = 0; const items = []; - React.Children.toArray(props.children).forEach(function (child, index) { + React.Children.toArray(props.children).forEach(function(child, index) { if (child.props.value === props.selectedValue) { selectedIndex = index; } @@ -63,7 +66,7 @@ const PickerIOS = createReactClass({ return ( this._picker = picker} + ref={picker => (this._picker = picker)} style={[styles.pickerIOS, this.props.itemStyle]} items={this.state.items} selectedIndex={this.state.selectedIndex} @@ -80,7 +83,10 @@ const PickerIOS = createReactClass({ this.props.onChange(event); } if (this.props.onValueChange) { - this.props.onValueChange(event.nativeEvent.newValue, event.nativeEvent.newIndex); + this.props.onValueChange( + event.nativeEvent.newValue, + event.nativeEvent.newIndex, + ); } // The picker is a controlled component. This means we expect the @@ -89,9 +95,12 @@ const PickerIOS = createReactClass({ // disallow/undo/mutate the selection of certain values. In other // words, the embedder of this component should be the source of // truth, not the native component. - if (this._picker && this.state.selectedIndex !== event.nativeEvent.newIndex) { + if ( + this._picker && + this.state.selectedIndex !== event.nativeEvent.newIndex + ) { this._picker.setNativeProps({ - selectedIndex: this.state.selectedIndex + selectedIndex: this.state.selectedIndex, }); } }, @@ -119,16 +128,20 @@ const styles = StyleSheet.create({ }, }); -const RCTPickerIOS = requireNativeComponent('RCTPicker', { - propTypes: { - style: itemStylePropType, +const RCTPickerIOS = requireNativeComponent( + 'RCTPicker', + { + propTypes: { + style: itemStylePropType, + }, }, -}, { - nativeOnly: { - items: true, - onChange: true, - selectedIndex: true, + { + nativeOnly: { + items: true, + onChange: true, + selectedIndex: true, + }, }, -}); +); module.exports = PickerIOS; diff --git a/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.ios.js b/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.ios.js index ebd42dd5b18bb0..260d559929796f 100644 --- a/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.ios.js +++ b/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.ios.js @@ -4,7 +4,9 @@ * 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('UnimplementedView'); diff --git a/Libraries/Components/ProgressViewIOS/ProgressViewIOS.android.js b/Libraries/Components/ProgressViewIOS/ProgressViewIOS.android.js index dcc8c3fc7489b7..8caa73db33e494 100644 --- a/Libraries/Components/ProgressViewIOS/ProgressViewIOS.android.js +++ b/Libraries/Components/ProgressViewIOS/ProgressViewIOS.android.js @@ -1,10 +1,10 @@ - /** * Copyright (c) 2015-present, Facebook, Inc. * * 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'; @@ -40,7 +40,7 @@ const styles = StyleSheet.create({ color: '#333333', margin: 5, fontSize: 10, - } + }, }); module.exports = DummyProgressViewIOS; diff --git a/Libraries/Components/ProgressViewIOS/ProgressViewIOS.ios.js b/Libraries/Components/ProgressViewIOS/ProgressViewIOS.ios.js index 2c14b4cddff768..dde9f399fdeffa 100644 --- a/Libraries/Components/ProgressViewIOS/ProgressViewIOS.ios.js +++ b/Libraries/Components/ProgressViewIOS/ProgressViewIOS.ios.js @@ -4,8 +4,10 @@ * 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 Image = require('Image'); @@ -65,7 +67,7 @@ const ProgressViewIOS = createReactClass({ style={[styles.progressView, this.props.style]} /> ); - } + }, }); const styles = StyleSheet.create({ @@ -76,7 +78,7 @@ const styles = StyleSheet.create({ const RCTProgressView = requireNativeComponent( 'RCTProgressView', - ProgressViewIOS + ProgressViewIOS, ); module.exports = ProgressViewIOS; diff --git a/Libraries/Components/RefreshControl/RefreshControl.js b/Libraries/Components/RefreshControl/RefreshControl.js index 07415276261ac3..e9389c1a400f34 100644 --- a/Libraries/Components/RefreshControl/RefreshControl.js +++ b/Libraries/Components/RefreshControl/RefreshControl.js @@ -4,8 +4,10 @@ * 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 ColorPropType = require('ColorPropType'); @@ -19,8 +21,8 @@ const createReactClass = require('create-react-class'); const requireNativeComponent = require('requireNativeComponent'); if (Platform.OS === 'android') { - const AndroidSwipeRefreshLayout = - require('UIManager').AndroidSwipeRefreshLayout; + const AndroidSwipeRefreshLayout = require('UIManager') + .AndroidSwipeRefreshLayout; var RefreshLayoutConsts = AndroidSwipeRefreshLayout ? AndroidSwipeRefreshLayout.Constants : {SIZE: {}}; @@ -125,7 +127,10 @@ const RefreshControl = createReactClass({ * Size of the refresh indicator, see RefreshControl.SIZE. * @platform android */ - size: PropTypes.oneOf([RefreshLayoutConsts.SIZE.DEFAULT, RefreshLayoutConsts.SIZE.LARGE]), + size: PropTypes.oneOf([ + RefreshLayoutConsts.SIZE.DEFAULT, + RefreshLayoutConsts.SIZE.LARGE, + ]), /** * Progress view top offset * @platform android @@ -156,7 +161,9 @@ const RefreshControl = createReactClass({ return ( {this._nativeRef = ref;}} + ref={ref => { + this._nativeRef = ref; + }} onRefresh={this._onRefresh} /> ); @@ -176,12 +183,12 @@ const RefreshControl = createReactClass({ if (Platform.OS === 'ios') { var NativeRefreshControl = requireNativeComponent( 'RCTRefreshControl', - RefreshControl + RefreshControl, ); } else if (Platform.OS === 'android') { var NativeRefreshControl = requireNativeComponent( 'AndroidSwipeRefreshLayout', - RefreshControl + RefreshControl, ); } diff --git a/Libraries/Components/RefreshControl/__mocks__/RefreshControlMock.js b/Libraries/Components/RefreshControl/__mocks__/RefreshControlMock.js index 04312d5d4c5dbe..bc03b7afa87878 100644 --- a/Libraries/Components/RefreshControl/__mocks__/RefreshControlMock.js +++ b/Libraries/Components/RefreshControl/__mocks__/RefreshControlMock.js @@ -4,8 +4,10 @@ * 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'); diff --git a/Libraries/Components/SafeAreaView/SafeAreaView.android.js b/Libraries/Components/SafeAreaView/SafeAreaView.android.js index fbc94020538334..a581258a57832f 100644 --- a/Libraries/Components/SafeAreaView/SafeAreaView.android.js +++ b/Libraries/Components/SafeAreaView/SafeAreaView.android.js @@ -4,8 +4,10 @@ * 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'; module.exports = require('View'); diff --git a/Libraries/Components/ScrollResponder.js b/Libraries/Components/ScrollResponder.js index 6a38cc7523dda4..ab388a31083f3f 100644 --- a/Libraries/Components/ScrollResponder.js +++ b/Libraries/Components/ScrollResponder.js @@ -4,8 +4,10 @@ * 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 Dimensions = require('Dimensions'); @@ -21,7 +23,7 @@ const nullthrows = require('fbjs/lib/nullthrows'); const performanceNow = require('fbjs/lib/performanceNow'); const warning = require('fbjs/lib/warning'); -const { ScrollViewManager } = require('NativeModules'); +const {ScrollViewManager} = require('NativeModules'); /** * Mixin that can be integrated in order to handle scrolling that plays well @@ -104,11 +106,11 @@ const { ScrollViewManager } = require('NativeModules'); const IS_ANIMATING_TOUCH_START_THRESHOLD_MS = 16; type State = { - isTouching: boolean, - lastMomentumScrollBeginTime: number, - lastMomentumScrollEndTime: number, - observedScrollSinceBecomingResponder: boolean, - becameResponderWhileAnimating: boolean, + isTouching: boolean, + lastMomentumScrollBeginTime: number, + lastMomentumScrollEndTime: number, + observedScrollSinceBecomingResponder: boolean, + becameResponderWhileAnimating: boolean, }; type Event = Object; @@ -165,9 +167,11 @@ const ScrollResponderMixin = { scrollResponderHandleStartShouldSetResponder: function(e: Event): boolean { const currentlyFocusedTextInput = TextInputState.currentlyFocusedField(); - if (this.props.keyboardShouldPersistTaps === 'handled' && + if ( + this.props.keyboardShouldPersistTaps === 'handled' && currentlyFocusedTextInput != null && - e.target !== currentlyFocusedTextInput) { + e.target !== currentlyFocusedTextInput + ) { return true; } return false; @@ -184,7 +188,9 @@ const ScrollResponderMixin = { * * Invoke this from an `onStartShouldSetResponderCapture` event. */ - scrollResponderHandleStartShouldSetResponderCapture: function(e: Event): boolean { + scrollResponderHandleStartShouldSetResponderCapture: function( + e: Event, + ): boolean { // The scroll view should receive taps instead of its descendants if: // * it is already animating/decelerating if (this.scrollResponderIsAnimating()) { @@ -197,11 +203,13 @@ const ScrollResponderMixin = { // then the second tap goes to the actual interior view) const currentlyFocusedTextInput = TextInputState.currentlyFocusedField(); const {keyboardShouldPersistTaps} = this.props; - const keyboardNeverPersistTaps = !keyboardShouldPersistTaps || - keyboardShouldPersistTaps === 'never'; - if (keyboardNeverPersistTaps && + const keyboardNeverPersistTaps = + !keyboardShouldPersistTaps || keyboardShouldPersistTaps === 'never'; + if ( + keyboardNeverPersistTaps && currentlyFocusedTextInput != null - /* && !TextInputState.isTextInput(e.target) */) { + /* && !TextInputState.isTextInput(e.target) */ + ) { return true; } @@ -218,8 +226,7 @@ const ScrollResponderMixin = { * altogether. To improve this, find a way to disable the `UIScrollView` after * a touch has already started. */ - scrollResponderHandleResponderReject: function() { - }, + scrollResponderHandleResponderReject: function() {}, /** * We will allow the scroll view to give up its lock iff it acquired the lock @@ -270,12 +277,14 @@ const ScrollResponderMixin = { // By default scroll views will unfocus a textField // if another touch occurs outside of it const currentlyFocusedTextInput = TextInputState.currentlyFocusedField(); - if (this.props.keyboardShouldPersistTaps !== true && + if ( + this.props.keyboardShouldPersistTaps !== true && this.props.keyboardShouldPersistTaps !== 'always' && currentlyFocusedTextInput != null && - e.target !== currentlyFocusedTextInput && + e.target !== currentlyFocusedTextInput && !this.state.observedScrollSinceBecomingResponder && - !this.state.becameResponderWhileAnimating) { + !this.state.becameResponderWhileAnimating + ) { this.props.onScrollResponderKeyboardDismissed && this.props.onScrollResponderKeyboardDismissed(e); TextInputState.blurTextInput(currentlyFocusedTextInput); @@ -318,8 +327,10 @@ const ScrollResponderMixin = { // - If velocity is non-zero, then the interaction will stop when momentum scroll ends or // another drag starts and ends. // - If we don't get velocity, better to stop the interaction twice than not stop it. - if (!this.scrollResponderIsAnimating() && - (!velocity || velocity.x === 0 && velocity.y === 0)) { + if ( + !this.scrollResponderIsAnimating() && + (!velocity || (velocity.x === 0 && velocity.y === 0)) + ) { FrameRateLogger.endScroll(); } this.props.onScrollEndDrag && this.props.onScrollEndDrag(e); @@ -380,9 +391,12 @@ const ScrollResponderMixin = { */ scrollResponderIsAnimating: function(): boolean { const now = performanceNow(); - const timeSinceLastMomentumScrollEnd = now - this.state.lastMomentumScrollEndTime; - const isAnimating = timeSinceLastMomentumScrollEnd < IS_ANIMATING_TOUCH_START_THRESHOLD_MS || - this.state.lastMomentumScrollEndTime < this.state.lastMomentumScrollBeginTime; + const timeSinceLastMomentumScrollEnd = + now - this.state.lastMomentumScrollEndTime; + const isAnimating = + timeSinceLastMomentumScrollEnd < IS_ANIMATING_TOUCH_START_THRESHOLD_MS || + this.state.lastMomentumScrollEndTime < + this.state.lastMomentumScrollBeginTime; return isAnimating; }, @@ -392,9 +406,9 @@ const ScrollResponderMixin = { * function otherwise `this` is used. */ scrollResponderGetScrollableNode: function(): any { - return this.getScrollableNode ? - this.getScrollableNode() : - ReactNative.findNodeHandle(this); + return this.getScrollableNode + ? this.getScrollableNode() + : ReactNative.findNodeHandle(this); }, /** @@ -409,12 +423,14 @@ const ScrollResponderMixin = { * This is deprecated due to ambiguity (y before x), and SHOULD NOT BE USED. */ scrollResponderScrollTo: function( - x?: number | { x?: number, y?: number, animated?: boolean }, + x?: number | {x?: number, y?: number, animated?: boolean}, y?: number, - animated?: boolean + animated?: boolean, ) { if (typeof x === 'number') { - console.warn('`scrollResponderScrollTo(x, y, animated)` is deprecated. Use `scrollResponderScrollTo({x: 5, y: 5, animated: true})` instead.'); + console.warn( + '`scrollResponderScrollTo(x, y, animated)` is deprecated. Use `scrollResponderScrollTo({x: 5, y: 5, animated: true})` instead.', + ); } else { ({x, y, animated} = x || {}); } @@ -433,9 +449,7 @@ const ScrollResponderMixin = { * * `scrollResponderScrollToEnd({animated: true})` */ - scrollResponderScrollToEnd: function( - options?: { animated?: boolean }, - ) { + scrollResponderScrollToEnd: function(options?: {animated?: boolean}) { // Default to true const animated = (options && options.animated) !== false; UIManager.dispatchViewManagerCommand( @@ -448,8 +462,13 @@ const ScrollResponderMixin = { /** * Deprecated, do not use. */ - scrollResponderScrollWithoutAnimationTo: function(offsetX: number, offsetY: number) { - console.warn('`scrollResponderScrollWithoutAnimationTo` is deprecated. Use `scrollResponderScrollTo` instead'); + scrollResponderScrollWithoutAnimationTo: function( + offsetX: number, + offsetY: number, + ) { + console.warn( + '`scrollResponderScrollWithoutAnimationTo` is deprecated. Use `scrollResponderScrollTo` instead', + ); this.scrollResponderScrollTo({x: offsetX, y: offsetY, animated: false}); }, @@ -460,17 +479,32 @@ const ScrollResponderMixin = { * @platform ios */ scrollResponderZoomTo: function( - rect: {| x: number, y: number, width: number, height: number, animated?: boolean |}, - animated?: boolean // deprecated, put this inside the rect argument instead + rect: {| + x: number, + y: number, + width: number, + height: number, + animated?: boolean, + |}, + animated?: boolean, // deprecated, put this inside the rect argument instead ) { - invariant(ScrollViewManager && ScrollViewManager.zoomToRect, 'zoomToRect is not implemented'); + invariant( + ScrollViewManager && ScrollViewManager.zoomToRect, + 'zoomToRect is not implemented', + ); if ('animated' in rect) { animated = rect.animated; delete rect.animated; } else if (typeof animated !== 'undefined') { - console.warn('`scrollResponderZoomTo` `animated` argument is deprecated. Use `options.animated` instead'); + console.warn( + '`scrollResponderZoomTo` `animated` argument is deprecated. Use `options.animated` instead', + ); } - ScrollViewManager.zoomToRect(this.scrollResponderGetScrollableNode(), rect, animated !== false); + ScrollViewManager.zoomToRect( + this.scrollResponderGetScrollableNode(), + rect, + animated !== false, + ); }, /** @@ -480,7 +514,7 @@ const ScrollResponderMixin = { UIManager.dispatchViewManagerCommand( this.scrollResponderGetScrollableNode(), UIManager.RCTScrollView.Commands.flashScrollIndicators, - [] + [], ); }, @@ -494,14 +528,18 @@ const ScrollResponderMixin = { * @param {bool} preventNegativeScrolling Whether to allow pulling the content * down to make it meet the keyboard's top. Default is false. */ - scrollResponderScrollNativeHandleToKeyboard: function(nodeHandle: any, additionalOffset?: number, preventNegativeScrollOffset?: bool) { + scrollResponderScrollNativeHandleToKeyboard: function( + nodeHandle: any, + additionalOffset?: number, + preventNegativeScrollOffset?: boolean, + ) { this.additionalScrollOffset = additionalOffset || 0; this.preventNegativeScrollOffset = !!preventNegativeScrollOffset; UIManager.measureLayout( nodeHandle, ReactNative.findNodeHandle(this.getInnerViewNode()), this.scrollResponderTextInputFocusError, - this.scrollResponderInputMeasureAndScrollToKeyboard + this.scrollResponderInputMeasureAndScrollToKeyboard, ); }, @@ -515,12 +553,18 @@ const ScrollResponderMixin = { * @param {number} width Width of the text input. * @param {number} height Height of the text input. */ - scrollResponderInputMeasureAndScrollToKeyboard: function(left: number, top: number, width: number, height: number) { + scrollResponderInputMeasureAndScrollToKeyboard: function( + left: number, + top: number, + width: number, + height: number, + ) { let keyboardScreenY = Dimensions.get('window').height; if (this.keyboardWillOpenTo) { keyboardScreenY = this.keyboardWillOpenTo.endCoordinates.screenY; } - let scrollOffsetY = top - keyboardScreenY + height + this.additionalScrollOffset; + let scrollOffsetY = + top - keyboardScreenY + height + this.additionalScrollOffset; // By default, this can scroll with negative offset, pulling the content // down so that the target component's bottom meets the keyboard's top. @@ -549,16 +593,34 @@ const ScrollResponderMixin = { const {keyboardShouldPersistTaps} = this.props; warning( typeof keyboardShouldPersistTaps !== 'boolean', - `'keyboardShouldPersistTaps={${keyboardShouldPersistTaps}}' is deprecated. ` - + `Use 'keyboardShouldPersistTaps="${keyboardShouldPersistTaps ? 'always' : 'never'}"' instead` + `'keyboardShouldPersistTaps={${keyboardShouldPersistTaps}}' is deprecated. ` + + `Use 'keyboardShouldPersistTaps="${ + keyboardShouldPersistTaps ? 'always' : 'never' + }"' instead`, ); this.keyboardWillOpenTo = null; this.additionalScrollOffset = 0; - this.addListenerOn(Keyboard, 'keyboardWillShow', this.scrollResponderKeyboardWillShow); - this.addListenerOn(Keyboard, 'keyboardWillHide', this.scrollResponderKeyboardWillHide); - this.addListenerOn(Keyboard, 'keyboardDidShow', this.scrollResponderKeyboardDidShow); - this.addListenerOn(Keyboard, 'keyboardDidHide', this.scrollResponderKeyboardDidHide); + this.addListenerOn( + Keyboard, + 'keyboardWillShow', + this.scrollResponderKeyboardWillShow, + ); + this.addListenerOn( + Keyboard, + 'keyboardWillHide', + this.scrollResponderKeyboardWillHide, + ); + this.addListenerOn( + Keyboard, + 'keyboardDidShow', + this.scrollResponderKeyboardDidShow, + ); + this.addListenerOn( + Keyboard, + 'keyboardDidHide', + this.scrollResponderKeyboardDidHide, + ); }, /** @@ -611,8 +673,7 @@ const ScrollResponderMixin = { scrollResponderKeyboardDidHide: function(e: Event) { this.keyboardWillOpenTo = null; this.props.onKeyboardDidHide && this.props.onKeyboardDidHide(e); - } - + }, }; const ScrollResponder = { diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js index 0ec0f188abd88f..4b9aa3cff4f556 100644 --- a/Libraries/Components/ScrollView/ScrollView.js +++ b/Libraries/Components/ScrollView/ScrollView.js @@ -4,8 +4,10 @@ * 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 AnimatedImplementation = require('AnimatedImplementation'); @@ -235,7 +237,13 @@ const ScrollView = createReactClass({ * - `false`, deprecated, use 'never' instead * - `true`, deprecated, use 'always' instead */ - keyboardShouldPersistTaps: PropTypes.oneOf(['always', 'never', 'handled', false, true]), + keyboardShouldPersistTaps: PropTypes.oneOf([ + 'always', + 'never', + 'handled', + false, + true, + ]), /** * When set, the scroll view will adjust the scroll position so that the first child that is * currently visible and at or beyond `minIndexForVisible` will not change position. This is @@ -274,7 +282,7 @@ const ScrollView = createReactClass({ * @platform ios */ minimumZoomScale: PropTypes.number, - /** + /** * Enables nested scrolling for Android API level 21+. * Nested scrolling is supported by default on iOS * @platform android @@ -321,10 +329,10 @@ const ScrollView = createReactClass({ */ pagingEnabled: PropTypes.bool, /** - * When true, ScrollView allows use of pinch gestures to zoom in and out. - * The default value is true. - * @platform ios - */ + * When true, ScrollView allows use of pinch gestures to zoom in and out. + * The default value is true. + * @platform ios + */ pinchGestureEnabled: PropTypes.bool, /** * When false, the view cannot be scrolled via touch interaction. @@ -453,7 +461,7 @@ const ScrollView = createReactClass({ */ scrollPerfTag: PropTypes.string, - /** + /** * Used to override default value of overScroll mode. * * Possible values: @@ -465,11 +473,7 @@ const ScrollView = createReactClass({ * * @platform android */ - overScrollMode: PropTypes.oneOf([ - 'auto', - 'always', - 'never', - ]), + overScrollMode: PropTypes.oneOf(['auto', 'always', 'never']), /** * When true, ScrollView will emit updateChildFrames data in scroll events, * otherwise will not compute or emit child frame data. This only exists @@ -491,18 +495,20 @@ const ScrollView = createReactClass({ * `import IMAGE from './image.jpg'`. * @platform vr */ - scrollBarThumbImage: PropTypes.oneOfType([ - PropTypes.shape({ - uri: PropTypes.string, - }), - // Opaque type returned by import IMAGE from './image.jpg' - PropTypes.number, - ]), + scrollBarThumbImage: PropTypes.oneOfType([ + PropTypes.shape({ + uri: PropTypes.string, + }), + // Opaque type returned by import IMAGE from './image.jpg' + PropTypes.number, + ]), }, mixins: [ScrollResponder.Mixin], - _scrollAnimatedValue: (new AnimatedImplementation.Value(0): AnimatedImplementation.Value), + _scrollAnimatedValue: (new AnimatedImplementation.Value( + 0, + ): AnimatedImplementation.Value), _scrollAnimatedValueAttachment: (null: ?{detach: () => void}), _stickyHeaderRefs: (new Map(): Map), _headerLayoutYs: (new Map(): Map), @@ -514,8 +520,12 @@ const ScrollView = createReactClass({ }, UNSAFE_componentWillMount: function() { - this._scrollAnimatedValue = new AnimatedImplementation.Value(this.props.contentOffset ? this.props.contentOffset.y : 0); - this._scrollAnimatedValue.setOffset(this.props.contentInset ? this.props.contentInset.top : 0); + this._scrollAnimatedValue = new AnimatedImplementation.Value( + this.props.contentOffset ? this.props.contentOffset.y : 0, + ); + this._scrollAnimatedValue.setOffset( + this.props.contentInset ? this.props.contentInset.top : 0, + ); this._stickyHeaderRefs = new Map(); this._headerLayoutYs = new Map(); }, @@ -568,19 +578,23 @@ const ScrollView = createReactClass({ * This is deprecated due to ambiguity (y before x), and SHOULD NOT BE USED. */ scrollTo: function( - y?: number | { x?: number, y?: number, animated?: boolean }, + y?: number | {x?: number, y?: number, animated?: boolean}, x?: number, - animated?: boolean + animated?: boolean, ) { if (typeof y === 'number') { - console.warn('`scrollTo(y, x, animated)` is deprecated. Use `scrollTo({x: 5, y: 5, ' + - 'animated: true})` instead.'); + console.warn( + '`scrollTo(y, x, animated)` is deprecated. Use `scrollTo({x: 5, y: 5, ' + + 'animated: true})` instead.', + ); } else { ({x, y, animated} = y || {}); } - this.getScrollResponder().scrollResponderScrollTo( - {x: x || 0, y: y || 0, animated: animated !== false} - ); + this.getScrollResponder().scrollResponderScrollTo({ + x: x || 0, + y: y || 0, + animated: animated !== false, + }); }, /** @@ -591,9 +605,7 @@ const ScrollView = createReactClass({ * `scrollToEnd({animated: false})` for immediate scrolling. * If no options are passed, `animated` defaults to true. */ - scrollToEnd: function( - options?: { animated?: boolean }, - ) { + scrollToEnd: function(options?: {animated?: boolean}) { // Default to true const animated = (options && options.animated) !== false; this.getScrollResponder().scrollResponderScrollToEnd({ @@ -605,7 +617,9 @@ const ScrollView = createReactClass({ * Deprecated, use `scrollTo` instead. */ scrollWithoutAnimationTo: function(y: number = 0, x: number = 0) { - console.warn('`scrollWithoutAnimationTo` is deprecated. Use `scrollTo` instead'); + console.warn( + '`scrollWithoutAnimationTo` is deprecated. Use `scrollTo` instead', + ); this.scrollTo({x, y, animated: false}); }, @@ -627,11 +641,14 @@ const ScrollView = createReactClass({ if (this._scrollAnimatedValueAttachment) { this._scrollAnimatedValueAttachment.detach(); } - if (this.props.stickyHeaderIndices && this.props.stickyHeaderIndices.length > 0) { + if ( + this.props.stickyHeaderIndices && + this.props.stickyHeaderIndices.length > 0 + ) { this._scrollAnimatedValueAttachment = AnimatedImplementation.attachNativeEvent( this._scrollViewRef, 'onScroll', - [{nativeEvent: {contentOffset: {y: this._scrollAnimatedValue}}}] + [{nativeEvent: {contentOffset: {y: this._scrollAnimatedValue}}}], ); } }, @@ -658,10 +675,12 @@ const ScrollView = createReactClass({ this._headerLayoutYs.set(key, layoutY); const indexOfIndex = this.props.stickyHeaderIndices.indexOf(index); - const previousHeaderIndex = this.props.stickyHeaderIndices[indexOfIndex - 1]; + const previousHeaderIndex = this.props.stickyHeaderIndices[ + indexOfIndex - 1 + ]; if (previousHeaderIndex != null) { const previousHeader = this._stickyHeaderRefs.get( - this._getKeyForIndex(previousHeaderIndex, childArray) + this._getKeyForIndex(previousHeaderIndex, childArray), ); previousHeader && previousHeader.setNextHeaderY(layoutY); } @@ -669,18 +688,25 @@ const ScrollView = createReactClass({ _handleScroll: function(e: Object) { if (__DEV__) { - if (this.props.onScroll && this.props.scrollEventThrottle == null && Platform.OS === 'ios') { + if ( + this.props.onScroll && + this.props.scrollEventThrottle == null && + Platform.OS === 'ios' + ) { console.log( 'You specified `onScroll` on a but not ' + - '`scrollEventThrottle`. You will only receive one event. ' + - 'Using `16` you get all the events but be aware that it may ' + - 'cause frame drops, use a bigger number if you don\'t need as ' + - 'much precision.' + '`scrollEventThrottle`. You will only receive one event. ' + + 'Using `16` you get all the events but be aware that it may ' + + "cause frame drops, use a bigger number if you don't need as " + + 'much precision.', ); } } if (Platform.OS === 'android') { - if (this.props.keyboardDismissMode === 'on-drag' && this.state.isTouching) { + if ( + this.props.keyboardDismissMode === 'on-drag' && + this.state.isTouching + ) { dismissKeyboard(); } } @@ -689,7 +715,7 @@ const ScrollView = createReactClass({ _handleLayout: function(e: Object) { if (this.props.invertStickyHeaders) { - this.setState({ layoutHeight: e.nativeEvent.layout.height }); + this.setState({layoutHeight: e.nativeEvent.layout.height}); } if (this.props.onLayout) { this.props.onLayout(e); @@ -698,7 +724,8 @@ const ScrollView = createReactClass({ _handleContentOnLayout: function(e: Object) { const {width, height} = e.nativeEvent.layout; - this.props.onContentSizeChange && this.props.onContentSizeChange(width, height); + this.props.onContentSizeChange && + this.props.onContentSizeChange(width, height); }, _scrollViewRef: (null: ?ScrollView), @@ -727,18 +754,18 @@ const ScrollView = createReactClass({ ScrollContentContainerViewClass = RCTScrollContentView; warning( !this.props.snapToInterval || !this.props.pagingEnabled, - 'snapToInterval is currently ignored when pagingEnabled is true.' + 'snapToInterval is currently ignored when pagingEnabled is true.', ); } invariant( ScrollViewClass !== undefined, - 'ScrollViewClass must not be undefined' + 'ScrollViewClass must not be undefined', ); invariant( ScrollContentContainerViewClass !== undefined, - 'ScrollContentContainerViewClass must not be undefined' + 'ScrollContentContainerViewClass must not be undefined', ); const contentContainerStyle = [ @@ -747,12 +774,14 @@ const ScrollView = createReactClass({ ]; if (__DEV__ && this.props.style) { const style = flattenStyle(this.props.style); - const childLayoutProps = ['alignItems', 'justifyContent'] - .filter((prop) => style && style[prop] !== undefined); + const childLayoutProps = ['alignItems', 'justifyContent'].filter( + prop => style && style[prop] !== undefined, + ); invariant( childLayoutProps.length === 0, - 'ScrollView child layout (' + JSON.stringify(childLayoutProps) + - ') must be applied through the contentContainerStyle prop.' + 'ScrollView child layout (' + + JSON.stringify(childLayoutProps) + + ') must be applied through the contentContainerStyle prop.', ); } @@ -764,34 +793,38 @@ const ScrollView = createReactClass({ } const {stickyHeaderIndices} = this.props; - const hasStickyHeaders = stickyHeaderIndices && stickyHeaderIndices.length > 0; - const childArray = hasStickyHeaders && React.Children.toArray(this.props.children); - const children = hasStickyHeaders ? - childArray.map((child, index) => { - const indexOfIndex = child ? stickyHeaderIndices.indexOf(index) : -1; - if (indexOfIndex > -1) { - const key = child.key; - const nextIndex = stickyHeaderIndices[indexOfIndex + 1]; - return ( - this._setStickyHeaderRef(key, ref)} - nextHeaderLayoutY={ - this._headerLayoutYs.get(this._getKeyForIndex(nextIndex, childArray)) - } - onLayout={(event) => this._onStickyHeaderLayout(index, event, key)} - scrollAnimatedValue={this._scrollAnimatedValue} - inverted={this.props.invertStickyHeaders} - scrollViewHeight={this.state.layoutHeight}> - {child} - - ); - } else { - return child; - } - }) : - this.props.children; - const contentContainer = + const hasStickyHeaders = + stickyHeaderIndices && stickyHeaderIndices.length > 0; + const childArray = + hasStickyHeaders && React.Children.toArray(this.props.children); + const children = hasStickyHeaders + ? childArray.map((child, index) => { + const indexOfIndex = child ? stickyHeaderIndices.indexOf(index) : -1; + if (indexOfIndex > -1) { + const key = child.key; + const nextIndex = stickyHeaderIndices[indexOfIndex + 1]; + return ( + this._setStickyHeaderRef(key, ref)} + nextHeaderLayoutY={this._headerLayoutYs.get( + this._getKeyForIndex(nextIndex, childArray), + )} + onLayout={event => + this._onStickyHeaderLayout(index, event, key) + } + scrollAnimatedValue={this._scrollAnimatedValue} + inverted={this.props.invertStickyHeaders} + scrollViewHeight={this.state.layoutHeight}> + {child} + + ); + } else { + return child; + } + }) + : this.props.children; + const contentContainer = ( {children} - ; + + ); const alwaysBounceHorizontal = - this.props.alwaysBounceHorizontal !== undefined ? - this.props.alwaysBounceHorizontal : - this.props.horizontal; + this.props.alwaysBounceHorizontal !== undefined + ? this.props.alwaysBounceHorizontal + : this.props.horizontal; const alwaysBounceVertical = - this.props.alwaysBounceVertical !== undefined ? - this.props.alwaysBounceVertical : - !this.props.horizontal; + this.props.alwaysBounceVertical !== undefined + ? this.props.alwaysBounceVertical + : !this.props.horizontal; - const DEPRECATED_sendUpdatedChildFrames = - !!this.props.DEPRECATED_sendUpdatedChildFrames; + const DEPRECATED_sendUpdatedChildFrames = !!this.props + .DEPRECATED_sendUpdatedChildFrames; - const baseStyle = this.props.horizontal ? styles.baseHorizontal : styles.baseVertical; + const baseStyle = this.props.horizontal + ? styles.baseHorizontal + : styles.baseVertical; const props = { ...this.props, alwaysBounceHorizontal, @@ -836,25 +872,33 @@ const ScrollView = createReactClass({ onResponderReject: this.scrollResponderHandleResponderReject, onResponderRelease: this.scrollResponderHandleResponderRelease, onResponderTerminate: this.scrollResponderHandleTerminate, - onResponderTerminationRequest: this.scrollResponderHandleTerminationRequest, + onResponderTerminationRequest: this + .scrollResponderHandleTerminationRequest, onScroll: this._handleScroll, onScrollBeginDrag: this.scrollResponderHandleScrollBeginDrag, onScrollEndDrag: this.scrollResponderHandleScrollEndDrag, - onScrollShouldSetResponder: this.scrollResponderHandleScrollShouldSetResponder, - onStartShouldSetResponder: this.scrollResponderHandleStartShouldSetResponder, - onStartShouldSetResponderCapture: this.scrollResponderHandleStartShouldSetResponderCapture, + onScrollShouldSetResponder: this + .scrollResponderHandleScrollShouldSetResponder, + onStartShouldSetResponder: this + .scrollResponderHandleStartShouldSetResponder, + onStartShouldSetResponderCapture: this + .scrollResponderHandleStartShouldSetResponderCapture, onTouchEnd: this.scrollResponderHandleTouchEnd, onTouchMove: this.scrollResponderHandleTouchMove, onTouchStart: this.scrollResponderHandleTouchStart, onTouchCancel: this.scrollResponderHandleTouchCancel, scrollBarThumbImage: resolveAssetSource(this.props.scrollBarThumbImage), - scrollEventThrottle: hasStickyHeaders ? 1 : this.props.scrollEventThrottle, - sendMomentumEvents: (this.props.onMomentumScrollBegin || this.props.onMomentumScrollEnd) ? - true : false, + scrollEventThrottle: hasStickyHeaders + ? 1 + : this.props.scrollEventThrottle, + sendMomentumEvents: + this.props.onMomentumScrollBegin || this.props.onMomentumScrollEnd + ? true + : false, DEPRECATED_sendUpdatedChildFrames, }; - const { decelerationRate } = this.props; + const {decelerationRate} = this.props; if (decelerationRate) { props.decelerationRate = processDecelerationRate(decelerationRate); } @@ -881,9 +925,12 @@ const ScrollView = createReactClass({ return React.cloneElement( refreshControl, {style: props.style}, - + {contentContainer} - + , ); } } @@ -892,7 +939,7 @@ const ScrollView = createReactClass({ {contentContainer} ); - } + }, }); const styles = StyleSheet.create({ @@ -923,29 +970,29 @@ if (Platform.OS === 'android') { nativeOnlyProps = { nativeOnly: { sendMomentumEvents: true, - } + }, }; AndroidScrollView = requireNativeComponent( 'RCTScrollView', (ScrollView: React.ComponentType), - nativeOnlyProps + nativeOnlyProps, ); AndroidHorizontalScrollView = requireNativeComponent( 'AndroidHorizontalScrollView', (ScrollView: React.ComponentType), - nativeOnlyProps + nativeOnlyProps, ); AndroidHorizontalScrollContentView = requireNativeComponent( - 'AndroidHorizontalScrollContentView' + 'AndroidHorizontalScrollContentView', ); } else if (Platform.OS === 'ios') { nativeOnlyProps = { nativeOnly: { onMomentumScrollBegin: true, - onMomentumScrollEnd : true, + onMomentumScrollEnd: true, onScrollBeginDrag: true, onScrollEndDrag: true, - } + }, }; RCTScrollView = requireNativeComponent( 'RCTScrollView', @@ -955,8 +1002,7 @@ if (Platform.OS === 'android') { RCTScrollContentView = requireNativeComponent('RCTScrollContentView', View); } else { nativeOnlyProps = { - nativeOnly: { - } + nativeOnly: {}, }; RCTScrollView = requireNativeComponent( 'RCTScrollView', diff --git a/Libraries/Components/ScrollView/__mocks__/ScrollViewMock.js b/Libraries/Components/ScrollView/__mocks__/ScrollViewMock.js index eaa8bb7385e367..46f691382d2f6e 100644 --- a/Libraries/Components/ScrollView/__mocks__/ScrollViewMock.js +++ b/Libraries/Components/ScrollView/__mocks__/ScrollViewMock.js @@ -4,6 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * + * @format * @flow */ @@ -27,9 +28,7 @@ class ScrollViewMock extends ScrollViewComponent { return ( {this.props.refreshControl} - - {this.props.children} - + {this.props.children} ); } diff --git a/Libraries/Components/ScrollView/processDecelerationRate.js b/Libraries/Components/ScrollView/processDecelerationRate.js index f46755fda278d3..18b903ffa3831c 100644 --- a/Libraries/Components/ScrollView/processDecelerationRate.js +++ b/Libraries/Components/ScrollView/processDecelerationRate.js @@ -4,7 +4,9 @@ * 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'; function processDecelerationRate(decelerationRate) { diff --git a/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.android.js b/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.android.js index a8b791e2f6ef1c..7a988960ceca96 100644 --- a/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.android.js +++ b/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.android.js @@ -1,10 +1,10 @@ - /** * Copyright (c) 2015-present, Facebook, Inc. * * 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'; @@ -40,7 +40,7 @@ const styles = StyleSheet.create({ color: '#333333', margin: 5, fontSize: 10, - } + }, }); module.exports = DummySegmentedControlIOS; diff --git a/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.ios.js b/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.ios.js index 620a8a3ec5c044..7324e4d8853314 100644 --- a/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.ios.js +++ b/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.ios.js @@ -4,8 +4,10 @@ * 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 NativeMethodsMixin = require('NativeMethodsMixin'); @@ -89,19 +91,20 @@ const SegmentedControlIOS = createReactClass({ * If true, then selecting a segment won't persist visually. * The `onValueChange` callback will still work as expected. */ - momentary: PropTypes.bool + momentary: PropTypes.bool, }, getDefaultProps: function(): DefaultProps { return { values: [], - enabled: true + enabled: true, }; }, _onChange: function(event: Event) { this.props.onChange && this.props.onChange(event); - this.props.onValueChange && this.props.onValueChange(event.nativeEvent.value); + this.props.onValueChange && + this.props.onValueChange(event.nativeEvent.value); }, render: function() { @@ -113,7 +116,7 @@ const SegmentedControlIOS = createReactClass({ onChange={this._onChange} /> ); - } + }, }); const styles = StyleSheet.create({ @@ -124,7 +127,7 @@ const styles = StyleSheet.create({ const RCTSegmentedControl = requireNativeComponent( 'RCTSegmentedControl', - SegmentedControlIOS + SegmentedControlIOS, ); module.exports = SegmentedControlIOS; diff --git a/Libraries/Components/Slider/Slider.js b/Libraries/Components/Slider/Slider.js index c0f3d015badb16..8e9eabd4361894 100644 --- a/Libraries/Components/Slider/Slider.js +++ b/Libraries/Components/Slider/Slider.js @@ -4,8 +4,10 @@ * 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 Image = require('Image'); @@ -192,13 +194,13 @@ const Slider = createReactClass({ testID: PropTypes.string, }, - getDefaultProps: function() : any { + getDefaultProps: function(): any { return { disabled: false, value: 0, minimumValue: 0, maximumValue: 1, - step: 0 + step: 0, }; }, @@ -206,8 +208,8 @@ const Slider = createReactClass({ uiViewClassName: 'RCTSlider', validAttributes: { ...ReactNativeViewAttributes.RCTView, - value: true - } + value: true, + }, }, render: function() { @@ -220,15 +222,17 @@ const Slider = createReactClass({ /* $FlowFixMe(>=0.54.0 site=react_native_fb,react_native_oss) This comment * suppresses an error found when Flow v0.54 was deployed. To see the error * delete this comment and run Flow. */ - props.onValueChange = onValueChange && ((event: Event) => { - let userEvent = true; - if (Platform.OS === 'android') { - // On Android there's a special flag telling us the user is - // dragging the slider. - userEvent = event.nativeEvent.fromUser; - } - onValueChange && userEvent && onValueChange(event.nativeEvent.value); - }); + props.onValueChange = + onValueChange && + ((event: Event) => { + let userEvent = true; + if (Platform.OS === 'android') { + // On Android there's a special flag telling us the user is + // dragging the slider. + userEvent = event.nativeEvent.fromUser; + } + onValueChange && userEvent && onValueChange(event.nativeEvent.value); + }); /* $FlowFixMe(>=0.54.0 site=react_native_fb,react_native_oss) This comment * suppresses an error found when Flow v0.54 was deployed. To see the error @@ -238,17 +242,21 @@ const Slider = createReactClass({ /* $FlowFixMe(>=0.54.0 site=react_native_fb,react_native_oss) This comment * suppresses an error found when Flow v0.54 was deployed. To see the error * delete this comment and run Flow. */ - props.onSlidingComplete = onSlidingComplete && ((event: Event) => { - onSlidingComplete && onSlidingComplete(event.nativeEvent.value); - }); - - return true} - onResponderTerminationRequest={() => false} - />; - } + props.onSlidingComplete = + onSlidingComplete && + ((event: Event) => { + onSlidingComplete && onSlidingComplete(event.nativeEvent.value); + }); + + return ( + true} + onResponderTerminationRequest={() => false} + /> + ); + }, }); let styles; @@ -269,7 +277,7 @@ if (Platform.OS === 'android') { options = { nativeOnly: { enabled: true, - } + }, }; } const RCTSlider = requireNativeComponent('RCTSlider', Slider, options); diff --git a/Libraries/Components/StaticContainer.react.js b/Libraries/Components/StaticContainer.react.js index a6a4454c8118c4..ffba809a46ab72 100644 --- a/Libraries/Components/StaticContainer.react.js +++ b/Libraries/Components/StaticContainer.react.js @@ -4,8 +4,10 @@ * 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'); @@ -26,18 +28,16 @@ const React = require('React'); * React reconciliation. */ class StaticContainer extends React.Component { - shouldComponentUpdate(nextProps: Object): boolean { return !!nextProps.shouldUpdate; } render() { const child = this.props.children; - return (child === null || child === false) + return child === null || child === false ? null : React.Children.only(child); } - } module.exports = StaticContainer; diff --git a/Libraries/Components/StaticRenderer.js b/Libraries/Components/StaticRenderer.js index 5bb9cb99f48493..4f8cfbd0989fa8 100644 --- a/Libraries/Components/StaticRenderer.js +++ b/Libraries/Components/StaticRenderer.js @@ -4,8 +4,10 @@ * 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'); @@ -21,7 +23,7 @@ class StaticRenderer extends React.Component<{ render: PropTypes.func.isRequired, }; - shouldComponentUpdate(nextProps: { shouldUpdate: boolean }): boolean { + shouldComponentUpdate(nextProps: {shouldUpdate: boolean}): boolean { return nextProps.shouldUpdate; } diff --git a/Libraries/Components/StatusBar/StatusBar.js b/Libraries/Components/StatusBar/StatusBar.js index 05bd9177ccd450..97db49fdd10283 100644 --- a/Libraries/Components/StatusBar/StatusBar.js +++ b/Libraries/Components/StatusBar/StatusBar.js @@ -4,8 +4,10 @@ * 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'); @@ -24,7 +26,7 @@ export type StatusBarStyle = $Enum<{ /** * Default status bar style (dark for iOS, light for Android) */ - 'default': string, + default: string, /** * Dark background, white texts and icons */ @@ -42,15 +44,15 @@ export type StatusBarAnimation = $Enum<{ /** * No animation */ - 'none': string, + none: string, /** * Fade animation */ - 'fade': string, + fade: string, /** * Slide animation */ - 'slide': string, + slide: string, }>; type DefaultProps = { @@ -62,7 +64,7 @@ type DefaultProps = { */ function mergePropsStack( propsStack: Array, - defaultValues: Object + defaultValues: Object, ): Object { return propsStack.reduce((prev, cur) => { for (const prop in cur) { @@ -223,7 +225,7 @@ class StatusBar extends React.Component<{ static setNetworkActivityIndicatorVisible(visible: boolean) { if (Platform.OS !== 'ios') { console.warn( - '`setNetworkActivityIndicatorVisible` is only available on iOS' + '`setNetworkActivityIndicatorVisible` is only available on iOS', ); return; } @@ -345,7 +347,7 @@ class StatusBar extends React.Component<{ const oldProps = StatusBar._currentValues; const mergedProps = mergePropsStack( StatusBar._propsStack, - StatusBar._defaultProps + StatusBar._defaultProps, ); // Update the props that have changed using the merged values from the props stack. @@ -356,13 +358,15 @@ class StatusBar extends React.Component<{ ) { StatusBarManager.setStyle( mergedProps.barStyle.value, - mergedProps.barStyle.animated + mergedProps.barStyle.animated, ); } if (!oldProps || oldProps.hidden.value !== mergedProps.hidden.value) { StatusBarManager.setHidden( mergedProps.hidden.value, - mergedProps.hidden.animated ? mergedProps.hidden.transition : 'none' + mergedProps.hidden.animated + ? mergedProps.hidden.transition + : 'none', ); } @@ -372,7 +376,7 @@ class StatusBar extends React.Component<{ mergedProps.networkActivityIndicatorVisible ) { StatusBarManager.setNetworkActivityIndicatorVisible( - mergedProps.networkActivityIndicatorVisible + mergedProps.networkActivityIndicatorVisible, ); } } else if (Platform.OS === 'android') { @@ -388,7 +392,7 @@ class StatusBar extends React.Component<{ ) { StatusBarManager.setColor( processColor(mergedProps.backgroundColor.value), - mergedProps.backgroundColor.animated + mergedProps.backgroundColor.animated, ); } if (!oldProps || oldProps.hidden.value !== mergedProps.hidden.value) { diff --git a/Libraries/Components/StatusBar/StatusBarIOS.android.js b/Libraries/Components/StatusBar/StatusBarIOS.android.js index 28ad139b8969e6..96f77d7868fbff 100644 --- a/Libraries/Components/StatusBar/StatusBarIOS.android.js +++ b/Libraries/Components/StatusBar/StatusBarIOS.android.js @@ -4,8 +4,10 @@ * 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 NativeEventEmitter = require('NativeEventEmitter'); diff --git a/Libraries/Components/StatusBar/StatusBarIOS.ios.js b/Libraries/Components/StatusBar/StatusBarIOS.ios.js index 3ccab44da625fc..529e01b308fd88 100644 --- a/Libraries/Components/StatusBar/StatusBarIOS.ios.js +++ b/Libraries/Components/StatusBar/StatusBarIOS.ios.js @@ -4,12 +4,14 @@ * 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 NativeEventEmitter = require('NativeEventEmitter'); -const { StatusBarManager } = require('NativeModules'); +const {StatusBarManager} = require('NativeModules'); /** * Use `StatusBar` for mutating the status bar. diff --git a/Libraries/Components/Subscribable.js b/Libraries/Components/Subscribable.js index a4fc660b5b9f50..a56d42ed864c8d 100644 --- a/Libraries/Components/Subscribable.js +++ b/Libraries/Components/Subscribable.js @@ -4,8 +4,10 @@ * 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 EventEmitter from 'EventEmitter'; @@ -21,7 +23,6 @@ import type EventEmitter from 'EventEmitter'; const Subscribable = {}; Subscribable.Mixin = { - UNSAFE_componentWillMount: function() { this._subscribableSubscriptions = []; }, @@ -29,9 +30,10 @@ Subscribable.Mixin = { componentWillUnmount: function() { // This null check is a fix for a broken version of uglify-es. Should be deleted eventually // https://github.com/facebook/react-native/issues/17348 - this._subscribableSubscriptions && this._subscribableSubscriptions.forEach( - (subscription) => subscription.remove() - ); + this._subscribableSubscriptions && + this._subscribableSubscriptions.forEach(subscription => + subscription.remove(), + ); this._subscribableSubscriptions = null; }, @@ -52,12 +54,12 @@ Subscribable.Mixin = { eventEmitter: EventEmitter, eventType: string, listener: Function, - context: Object + context: Object, ) { this._subscribableSubscriptions.push( - eventEmitter.addListener(eventType, listener, context) + eventEmitter.addListener(eventType, listener, context), ); - } + }, }; module.exports = Subscribable; diff --git a/Libraries/Components/Switch/Switch.js b/Libraries/Components/Switch/Switch.js index ad613e2c85d48e..88f916cf2040e2 100644 --- a/Libraries/Components/Switch/Switch.js +++ b/Libraries/Components/Switch/Switch.js @@ -4,8 +4,10 @@ * 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 ColorPropType = require('ColorPropType'); @@ -93,7 +95,8 @@ const Switch = createReactClass({ * suppresses an error when upgrading Flow's support for React. To see the * error delete this comment and run Flow. */ this.props.onChange && this.props.onChange(event); - this.props.onValueChange && this.props.onValueChange(event.nativeEvent.value); + this.props.onValueChange && + this.props.onValueChange(event.nativeEvent.value); }, render: function() { @@ -113,17 +116,21 @@ const Switch = createReactClass({ /* $FlowFixMe(>=0.70.0 site=react_native_fb) This comment suppresses an * error found when Flow v0.70 was deployed. To see the error delete * this comment and run Flow. */ - props.trackTintColor = this.props.value ? this.props.onTintColor : this.props.tintColor; + props.trackTintColor = this.props.value + ? this.props.onTintColor + : this.props.tintColor; } else if (Platform.OS === 'ios') { props.style = [styles.rctSwitchIOS, this.props.style]; } return ( =0.53.0 site=react_native_fb,react_native_oss) This - * comment suppresses an error when upgrading Flow's support for React. - * To see the error delete this comment and run Flow. */ - ref={(ref) => { this._rctSwitch = ref; }} + ref={ref => { + /* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This + * comment suppresses an error when upgrading Flow's support for React. + * To see the error delete this comment and run Flow. */ + this._rctSwitch = ref; + }} onChange={this._onChange} /> ); @@ -134,7 +141,7 @@ const styles = StyleSheet.create({ rctSwitchIOS: { height: 31, width: 51, - } + }, }); if (Platform.OS === 'android') { @@ -144,13 +151,13 @@ if (Platform.OS === 'android') { on: true, enabled: true, trackTintColor: true, - } + }, }); } else { var RCTSwitch = requireNativeComponent('RCTSwitch', Switch, { nativeOnly: { - onChange: true - } + onChange: true, + }, }); } diff --git a/Libraries/Components/TabBarIOS/TabBarIOS.android.js b/Libraries/Components/TabBarIOS/TabBarIOS.android.js index 62a6bbac8fb966..e8e376f8a9eb7e 100644 --- a/Libraries/Components/TabBarIOS/TabBarIOS.android.js +++ b/Libraries/Components/TabBarIOS/TabBarIOS.android.js @@ -4,6 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * + * @format * @flow */ @@ -29,7 +30,7 @@ class DummyTabBarIOS extends React.Component<$FlowFixMeProps> { const styles = StyleSheet.create({ tabGroup: { flex: 1, - } + }, }); module.exports = DummyTabBarIOS; diff --git a/Libraries/Components/TabBarIOS/TabBarIOS.ios.js b/Libraries/Components/TabBarIOS/TabBarIOS.ios.js index 57e32df01e5b49..686483f3b23219 100644 --- a/Libraries/Components/TabBarIOS/TabBarIOS.ios.js +++ b/Libraries/Components/TabBarIOS/TabBarIOS.ios.js @@ -4,8 +4,10 @@ * 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 ColorPropType = require('ColorPropType'); @@ -20,17 +22,19 @@ const requireNativeComponent = require('requireNativeComponent'); import type {DangerouslyImpreciseStyleProp} from 'StyleSheet'; import type {ViewProps} from 'ViewPropTypes'; -class TabBarIOS extends React.Component { +class TabBarIOS extends React.Component< + ViewProps & { + style?: DangerouslyImpreciseStyleProp, + unselectedTintColor?: string, + tintColor?: string, + unselectedItemTintColor?: string, + barTintColor?: string, + barStyle?: 'default' | 'black', + translucent?: boolean, + itemPositioning?: 'fill' | 'center' | 'auto', + children: React.Node, + }, +> { static Item = TabBarItemIOS; static propTypes = { @@ -94,7 +98,7 @@ class TabBarIOS extends React.Component; } return ( - - {this.props.children} - + {this.props.children} ); } } @@ -35,7 +34,7 @@ const styles = StyleSheet.create({ left: 0, borderColor: 'red', borderWidth: 1, - } + }, }); module.exports = DummyTab; diff --git a/Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js b/Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js index 3f0b85a0c501fe..44fb44da448681 100644 --- a/Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js +++ b/Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js @@ -4,8 +4,10 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * + * @format * @noflow */ + 'use strict'; const ColorPropType = require('ColorPropType'); @@ -26,10 +28,7 @@ class TabBarItemIOS extends React.Component { /** * Little red bubble that sits at the top right of the icon. */ - badge: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.number, - ]), + badge: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** * Background color for the badge. Available since iOS 10. */ @@ -105,7 +104,7 @@ class TabBarItemIOS extends React.Component { } } - UNSAFE_componentWillReceiveProps(nextProps: { selected?: boolean }) { + UNSAFE_componentWillReceiveProps(nextProps: {selected?: boolean}) { if (this.state.hasBeenSelected || nextProps.selected) { this.setState({hasBeenSelected: true}); } @@ -117,18 +116,17 @@ class TabBarItemIOS extends React.Component { // if the tab has already been shown once, always continue to show it so we // preserve state between tab transitions if (this.state.hasBeenSelected) { - var tabContents = + var tabContents = ( {children} - ; + + ); } else { var tabContents = ; } return ( - + {tabContents} ); @@ -142,7 +140,7 @@ const styles = StyleSheet.create({ right: 0, bottom: 0, left: 0, - } + }, }); const RCTTabBarItem = requireNativeComponent('RCTTabBarItem', TabBarItemIOS); diff --git a/Libraries/Components/TextInput/TextInputState.js b/Libraries/Components/TextInput/TextInputState.js index 47eeddf12189d5..95cd24fbe8d2dc 100644 --- a/Libraries/Components/TextInput/TextInputState.js +++ b/Libraries/Components/TextInput/TextInputState.js @@ -4,12 +4,15 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @flow * * This class is responsible for coordinating the "focused" * state for TextInputs. All calls relating to the keyboard * should be funneled through here + * + * @format + * @flow */ + 'use strict'; const Platform = require('Platform'); @@ -18,7 +21,7 @@ const UIManager = require('UIManager'); const inputs = new Set(); const TextInputState = { - /** + /** * Internal state */ _currentlyFocusedID: (null: ?number), @@ -45,7 +48,7 @@ const TextInputState = { UIManager.dispatchViewManagerCommand( textFieldID, UIManager.AndroidTextInput.Commands.focusTextInput, - null + null, ); } } @@ -65,7 +68,7 @@ const TextInputState = { UIManager.dispatchViewManagerCommand( textFieldID, UIManager.AndroidTextInput.Commands.blurTextInput, - null + null, ); } } diff --git a/Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js b/Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js index b2b8c759e59501..6cdd964cc8cea2 100644 --- a/Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js +++ b/Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js @@ -4,8 +4,10 @@ * 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 TimePickerModule = require('NativeModules').TimePickerAndroid; @@ -31,7 +33,6 @@ const TimePickerModule = require('NativeModules').TimePickerAndroid; * ``` */ class TimePickerAndroid { - /** * Opens the standard Android time picker dialog. * @@ -58,11 +59,15 @@ class TimePickerAndroid { /** * A time has been selected. */ - static get timeSetAction() { return 'timeSetAction'; } + static get timeSetAction() { + return 'timeSetAction'; + } /** * The dialog has been dismissed. */ - static get dismissedAction() { return 'dismissedAction'; } + static get dismissedAction() { + return 'dismissedAction'; + } } module.exports = TimePickerAndroid; diff --git a/Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js b/Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js index 3813b6522b00d9..6a0ecfa656313c 100644 --- a/Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js +++ b/Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js @@ -4,14 +4,16 @@ * 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 TimePickerAndroid = { async open(options: Object): Promise { return Promise.reject({ - message: 'TimePickerAndroid is not supported on this platform.' + message: 'TimePickerAndroid is not supported on this platform.', }); }, }; diff --git a/Libraries/Components/ToastAndroid/ToastAndroid.android.js b/Libraries/Components/ToastAndroid/ToastAndroid.android.js index b0a242ed5ffec1..c661adf503565d 100644 --- a/Libraries/Components/ToastAndroid/ToastAndroid.android.js +++ b/Libraries/Components/ToastAndroid/ToastAndroid.android.js @@ -4,6 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * + * @format * @flow */ @@ -33,7 +34,6 @@ const RCTToastAndroid = require('NativeModules').ToastAndroid; */ const ToastAndroid = { - // Toast duration constants SHORT: RCTToastAndroid.SHORT, LONG: RCTToastAndroid.LONG, @@ -43,14 +43,11 @@ const ToastAndroid = { BOTTOM: RCTToastAndroid.BOTTOM, CENTER: RCTToastAndroid.CENTER, - show: function ( - message: string, - duration: number - ): void { + show: function(message: string, duration: number): void { RCTToastAndroid.show(message, duration); }, - showWithGravity: function ( + showWithGravity: function( message: string, duration: number, gravity: number, @@ -58,14 +55,20 @@ const ToastAndroid = { RCTToastAndroid.showWithGravity(message, duration, gravity); }, - showWithGravityAndOffset: function ( + showWithGravityAndOffset: function( message: string, duration: number, gravity: number, xOffset: number, yOffset: number, ): void { - RCTToastAndroid.showWithGravityAndOffset(message, duration, gravity, xOffset, yOffset); + RCTToastAndroid.showWithGravityAndOffset( + message, + duration, + gravity, + xOffset, + yOffset, + ); }, }; diff --git a/Libraries/Components/ToastAndroid/ToastAndroid.ios.js b/Libraries/Components/ToastAndroid/ToastAndroid.ios.js index 94d0487647ac85..adb6032ef6731b 100644 --- a/Libraries/Components/ToastAndroid/ToastAndroid.ios.js +++ b/Libraries/Components/ToastAndroid/ToastAndroid.ios.js @@ -4,21 +4,18 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * + * @format * @noflow */ + 'use strict'; const warning = require('fbjs/lib/warning'); const ToastAndroid = { - - show: function ( - message: string, - duration: number - ): void { + show: function(message: string, duration: number): void { warning(false, 'ToastAndroid is not supported on this platform.'); }, - }; module.exports = ToastAndroid; diff --git a/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js b/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js index de6fd5aad12b99..5fc04a42530173 100644 --- a/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js +++ b/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js @@ -4,6 +4,7 @@ * 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'; @@ -82,12 +83,14 @@ const ToolbarAndroid = createReactClass({ * `ifRoom` or `never` * * `showWithText`: boolean, whether to show text alongside the icon or not */ - actions: PropTypes.arrayOf(PropTypes.shape({ - title: PropTypes.string.isRequired, - icon: optionalImageSource, - show: PropTypes.oneOf(['always', 'ifRoom', 'never']), - showWithText: PropTypes.bool - })), + actions: PropTypes.arrayOf( + PropTypes.shape({ + title: PropTypes.string.isRequired, + icon: optionalImageSource, + show: PropTypes.oneOf(['always', 'ifRoom', 'never']), + showWithText: PropTypes.bool, + }), + ), /** * Sets the toolbar logo. */ @@ -183,7 +186,8 @@ const ToolbarAndroid = createReactClass({ action.icon = resolveAssetSource(action.icon); } if (action.show) { - action.show = UIManager.ToolbarAndroid.Constants.ShowAsAction[action.show]; + action.show = + UIManager.ToolbarAndroid.Constants.ShowAsAction[action.show]; } nativeActions.push(action); } @@ -206,7 +210,7 @@ const ToolbarAndroid = createReactClass({ const NativeToolbar = requireNativeComponent('ToolbarAndroid', ToolbarAndroid, { nativeOnly: { nativeActions: true, - } + }, }); module.exports = ToolbarAndroid; diff --git a/Libraries/Components/ToolbarAndroid/ToolbarAndroid.ios.js b/Libraries/Components/ToolbarAndroid/ToolbarAndroid.ios.js index ebd42dd5b18bb0..260d559929796f 100644 --- a/Libraries/Components/ToolbarAndroid/ToolbarAndroid.ios.js +++ b/Libraries/Components/ToolbarAndroid/ToolbarAndroid.ios.js @@ -4,7 +4,9 @@ * 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('UnimplementedView'); diff --git a/Libraries/Components/Touchable/BoundingDimensions.js b/Libraries/Components/Touchable/BoundingDimensions.js index 898244979d28e8..755da5ab8937aa 100644 --- a/Libraries/Components/Touchable/BoundingDimensions.js +++ b/Libraries/Components/Touchable/BoundingDimensions.js @@ -4,6 +4,7 @@ * 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'; @@ -36,7 +37,7 @@ BoundingDimensions.prototype.destructor = function() { BoundingDimensions.getPooledFromElement = function(element) { return BoundingDimensions.getPooled( element.offsetWidth, - element.offsetHeight + element.offsetHeight, ); }; diff --git a/Libraries/Components/Touchable/PooledClass.js b/Libraries/Components/Touchable/PooledClass.js index 42cb503d07b791..a6934facae7049 100644 --- a/Libraries/Components/Touchable/PooledClass.js +++ b/Libraries/Components/Touchable/PooledClass.js @@ -4,6 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * + * @format * @flow */ diff --git a/Libraries/Components/Touchable/Position.js b/Libraries/Components/Touchable/Position.js index ce09d00a8e36a7..19899d74c49820 100644 --- a/Libraries/Components/Touchable/Position.js +++ b/Libraries/Components/Touchable/Position.js @@ -4,6 +4,7 @@ * 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'; diff --git a/Libraries/Components/Touchable/Touchable.js b/Libraries/Components/Touchable/Touchable.js index 20831533271624..ce449d6d99f8de 100644 --- a/Libraries/Components/Touchable/Touchable.js +++ b/Libraries/Components/Touchable/Touchable.js @@ -4,6 +4,7 @@ * 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'; @@ -110,14 +111,14 @@ const normalizeColor = require('normalizeColor'); * Touchable states. */ const States = keyMirror({ - NOT_RESPONDER: null, // Not the responder - RESPONDER_INACTIVE_PRESS_IN: null, // Responder, inactive, in the `PressRect` - RESPONDER_INACTIVE_PRESS_OUT: null, // Responder, inactive, out of `PressRect` - RESPONDER_ACTIVE_PRESS_IN: null, // Responder, active, in the `PressRect` - RESPONDER_ACTIVE_PRESS_OUT: null, // Responder, active, out of `PressRect` - RESPONDER_ACTIVE_LONG_PRESS_IN: null, // Responder, active, in the `PressRect`, after long press threshold + NOT_RESPONDER: null, // Not the responder + RESPONDER_INACTIVE_PRESS_IN: null, // Responder, inactive, in the `PressRect` + RESPONDER_INACTIVE_PRESS_OUT: null, // Responder, inactive, out of `PressRect` + RESPONDER_ACTIVE_PRESS_IN: null, // Responder, active, in the `PressRect` + RESPONDER_ACTIVE_PRESS_OUT: null, // Responder, active, out of `PressRect` + RESPONDER_ACTIVE_LONG_PRESS_IN: null, // Responder, active, in the `PressRect`, after long press threshold RESPONDER_ACTIVE_LONG_PRESS_OUT: null, // Responder, active, out of `PressRect`, after long press threshold - ERROR: null + ERROR: null, }); /** @@ -125,7 +126,7 @@ const States = keyMirror({ */ const IsActive = { RESPONDER_ACTIVE_PRESS_OUT: true, - RESPONDER_ACTIVE_PRESS_IN: true + RESPONDER_ACTIVE_PRESS_IN: true, }; /** @@ -230,7 +231,7 @@ const Transitions = { ENTER_PRESS_RECT: States.NOT_RESPONDER, LEAVE_PRESS_RECT: States.NOT_RESPONDER, LONG_PRESS_DETECTED: States.NOT_RESPONDER, - } + }, }; // ==== Typical Constants for integrating into UI components ==== @@ -324,11 +325,15 @@ const TouchableMixin = { evt.dispatchConfig = {}; if (myTag === evt.tag) { if (evt.eventType === 'focus') { - cmp.touchableHandleActivePressIn && cmp.touchableHandleActivePressIn(evt); + cmp.touchableHandleActivePressIn && + cmp.touchableHandleActivePressIn(evt); } else if (evt.eventType === 'blur') { - cmp.touchableHandleActivePressOut && cmp.touchableHandleActivePressOut(evt); + cmp.touchableHandleActivePressOut && + cmp.touchableHandleActivePressOut(evt); } else if (evt.eventType === 'select') { - cmp.touchableHandlePress && !cmp.props.disabled && cmp.touchableHandlePress(evt); + cmp.touchableHandlePress && + !cmp.props.disabled && + cmp.touchableHandlePress(evt); } } }); @@ -356,7 +361,7 @@ const TouchableMixin = { */ touchableGetInitialState: function() { return { - touchable: {touchState: undefined, responderID: null} + touchable: {touchState: undefined, responderID: null}, }; }, @@ -378,7 +383,7 @@ const TouchableMixin = { /** * Return true to cancel press on long press. */ - touchableLongPressCancelsPress: function () { + touchableLongPressCancelsPress: function() { return true; }, @@ -401,25 +406,27 @@ const TouchableMixin = { this.state.touchable.responderID = dispatchID; this._receiveSignal(Signals.RESPONDER_GRANT, e); let delayMS = - this.touchableGetHighlightDelayMS !== undefined ? - Math.max(this.touchableGetHighlightDelayMS(), 0) : HIGHLIGHT_DELAY_MS; + this.touchableGetHighlightDelayMS !== undefined + ? Math.max(this.touchableGetHighlightDelayMS(), 0) + : HIGHLIGHT_DELAY_MS; delayMS = isNaN(delayMS) ? HIGHLIGHT_DELAY_MS : delayMS; if (delayMS !== 0) { this.touchableDelayTimeout = setTimeout( this._handleDelay.bind(this, e), - delayMS + delayMS, ); } else { this._handleDelay(e); } let longDelayMS = - this.touchableGetLongPressDelayMS !== undefined ? - Math.max(this.touchableGetLongPressDelayMS(), 10) : LONG_PRESS_DELAY_MS; + this.touchableGetLongPressDelayMS !== undefined + ? Math.max(this.touchableGetLongPressDelayMS(), 10) + : LONG_PRESS_DELAY_MS; longDelayMS = isNaN(longDelayMS) ? LONG_PRESS_DELAY_MS : longDelayMS; this.longPressDelayTimeout = setTimeout( this._handleLongDelay.bind(this, e), - longDelayMS + delayMS + longDelayMS + delayMS, ); }, @@ -443,7 +450,9 @@ const TouchableMixin = { touchableHandleResponderMove: function(e) { // Not enough time elapsed yet, wait for highlight - // this is just a perf optimization. - if (this.state.touchable.touchState === States.RESPONDER_INACTIVE_PRESS_IN) { + if ( + this.state.touchable.touchState === States.RESPONDER_INACTIVE_PRESS_IN + ) { return; } @@ -454,21 +463,23 @@ const TouchableMixin = { const positionOnActivate = this.state.touchable.positionOnActivate; const dimensionsOnActivate = this.state.touchable.dimensionsOnActivate; - const pressRectOffset = this.touchableGetPressRectOffset ? - this.touchableGetPressRectOffset() : { - left: PRESS_EXPAND_PX, - right: PRESS_EXPAND_PX, - top: PRESS_EXPAND_PX, - bottom: PRESS_EXPAND_PX - }; + const pressRectOffset = this.touchableGetPressRectOffset + ? this.touchableGetPressRectOffset() + : { + left: PRESS_EXPAND_PX, + right: PRESS_EXPAND_PX, + top: PRESS_EXPAND_PX, + bottom: PRESS_EXPAND_PX, + }; let pressExpandLeft = pressRectOffset.left; let pressExpandTop = pressRectOffset.top; let pressExpandRight = pressRectOffset.right; let pressExpandBottom = pressRectOffset.bottom; - const hitSlop = this.touchableGetHitSlop ? - this.touchableGetHitSlop() : null; + const hitSlop = this.touchableGetHitSlop + ? this.touchableGetHitSlop() + : null; if (hitSlop) { pressExpandLeft += hitSlop.left; @@ -482,21 +493,26 @@ const TouchableMixin = { const pageY = touch && touch.pageY; if (this.pressInLocation) { - const movedDistance = this._getDistanceBetweenPoints(pageX, pageY, this.pressInLocation.pageX, this.pressInLocation.pageY); + const movedDistance = this._getDistanceBetweenPoints( + pageX, + pageY, + this.pressInLocation.pageX, + this.pressInLocation.pageY, + ); if (movedDistance > LONG_PRESS_ALLOWED_MOVEMENT) { this._cancelLongPressDelayTimeout(); } } const isTouchWithinActive = - pageX > positionOnActivate.left - pressExpandLeft && - pageY > positionOnActivate.top - pressExpandTop && - pageX < - positionOnActivate.left + + pageX > positionOnActivate.left - pressExpandLeft && + pageY > positionOnActivate.top - pressExpandTop && + pageX < + positionOnActivate.left + dimensionsOnActivate.width + pressExpandRight && - pageY < - positionOnActivate.top + + pageY < + positionOnActivate.top + dimensionsOnActivate.height + pressExpandBottom; if (isTouchWithinActive) { @@ -574,8 +590,6 @@ const TouchableMixin = { * touchableGetPressRectOffset: function */ - - // ==== Internal Logic ==== /** @@ -608,8 +622,14 @@ const TouchableMixin = { Position.release(this.state.touchable.positionOnActivate); this.state.touchable.dimensionsOnActivate && BoundingDimensions.release(this.state.touchable.dimensionsOnActivate); - this.state.touchable.positionOnActivate = Position.getPooled(globalX, globalY); - this.state.touchable.dimensionsOnActivate = BoundingDimensions.getPooled(w, h); + this.state.touchable.positionOnActivate = Position.getPooled( + globalX, + globalY, + ); + this.state.touchable.dimensionsOnActivate = BoundingDimensions.getPooled( + w, + h, + ); }, _handleDelay: function(e) { @@ -620,11 +640,18 @@ const TouchableMixin = { _handleLongDelay: function(e) { this.longPressDelayTimeout = null; const curState = this.state.touchable.touchState; - if (curState !== States.RESPONDER_ACTIVE_PRESS_IN && - curState !== States.RESPONDER_ACTIVE_LONG_PRESS_IN) { - console.error('Attempted to transition from state `' + curState + '` to `' + - States.RESPONDER_ACTIVE_LONG_PRESS_IN + '`, which is not supported. This is ' + - 'most likely due to `Touchable.longPressDelayTimeout` not being cancelled.'); + if ( + curState !== States.RESPONDER_ACTIVE_PRESS_IN && + curState !== States.RESPONDER_ACTIVE_LONG_PRESS_IN + ) { + console.error( + 'Attempted to transition from state `' + + curState + + '` to `' + + States.RESPONDER_ACTIVE_LONG_PRESS_IN + + '`, which is not supported. This is ' + + 'most likely due to `Touchable.longPressDelayTimeout` not being cancelled.', + ); } else { this._receiveSignal(Signals.LONG_PRESS_DETECTED, e); } @@ -647,14 +674,24 @@ const TouchableMixin = { } if (!nextState) { throw new Error( - 'Unrecognized signal `' + signal + '` or state `' + curState + - '` for Touchable responder `' + responderID + '`' + 'Unrecognized signal `' + + signal + + '` or state `' + + curState + + '` for Touchable responder `' + + responderID + + '`', ); } if (nextState === States.ERROR) { throw new Error( - 'Touchable cannot transition from `' + curState + '` to `' + signal + - '` for responder `' + responderID + '`' + 'Touchable cannot transition from `' + + curState + + '` to `' + + signal + + '` for responder `' + + responderID + + '`', ); } if (curState !== nextState) { @@ -663,14 +700,16 @@ const TouchableMixin = { } }, - _cancelLongPressDelayTimeout: function () { + _cancelLongPressDelayTimeout: function() { this.longPressDelayTimeout && clearTimeout(this.longPressDelayTimeout); this.longPressDelayTimeout = null; }, - _isHighlight: function (state) { - return state === States.RESPONDER_ACTIVE_PRESS_IN || - state === States.RESPONDER_ACTIVE_LONG_PRESS_IN; + _isHighlight: function(state) { + return ( + state === States.RESPONDER_ACTIVE_PRESS_IN || + state === States.RESPONDER_ACTIVE_LONG_PRESS_IN + ); }, _savePressInLocation: function(e) { @@ -682,7 +721,7 @@ const TouchableMixin = { this.pressInLocation = {pageX, pageY, locationX, locationY}; }, - _getDistanceBetweenPoints: function (aX, aY, bX, bY) { + _getDistanceBetweenPoints: function(aX, aY, bX, bY) { const deltaX = aX - bX; const deltaY = aY - bY; return Math.sqrt(deltaX * deltaX + deltaY * deltaY); @@ -728,12 +767,11 @@ const TouchableMixin = { if (IsPressingIn[curState] && signal === Signals.RESPONDER_RELEASE) { const hasLongPressHandler = !!this.props.onLongPress; const pressIsLongButStillCallOnPress = - IsLongPressingIn[curState] && ( // We *are* long pressing.. - (// But either has no long handler - !hasLongPressHandler || !this.touchableLongPressCancelsPress()) // or we're told to ignore it. - ); + IsLongPressingIn[curState] && // We *are* long pressing.. // But either has no long handler + (!hasLongPressHandler || !this.touchableLongPressCancelsPress()); // or we're told to ignore it. - const shouldInvokePress = !IsLongPressingIn[curState] || pressIsLongButStillCallOnPress; + const shouldInvokePress = + !IsLongPressingIn[curState] || pressIsLongButStillCallOnPress; if (shouldInvokePress && this.touchableHandlePress) { if (!newIsHighlight && !curIsHighlight) { // we never highlighted because of delay, but we should highlight now @@ -750,11 +788,11 @@ const TouchableMixin = { this.touchableDelayTimeout && clearTimeout(this.touchableDelayTimeout); this.touchableDelayTimeout = null; }, - + _playTouchSound: function() { UIManager.playTouchSound(); }, - + _startHighlight: function(e) { this._savePressInLocation(e); this.touchableHandleActivePressIn && this.touchableHandleActivePressIn(e); @@ -762,7 +800,10 @@ const TouchableMixin = { _endHighlight: function(e) { if (this.touchableHandleActivePressOut) { - if (this.touchableGetPressOutDelayMS && this.touchableGetPressOutDelayMS()) { + if ( + this.touchableGetPressOutDelayMS && + this.touchableGetPressOutDelayMS() + ) { this.pressOutDelayTimeout = setTimeout(() => { this.touchableHandleActivePressOut(e); }, this.touchableGetPressOutDelayMS()); @@ -771,7 +812,6 @@ const TouchableMixin = { } } }, - }; const Touchable = { @@ -785,14 +825,17 @@ const Touchable = { return null; } if (!__DEV__) { - throw Error('Touchable.TOUCH_TARGET_DEBUG should not be enabled in prod!'); + throw Error( + 'Touchable.TOUCH_TARGET_DEBUG should not be enabled in prod!', + ); } const debugHitSlopStyle = {}; hitSlop = hitSlop || {top: 0, bottom: 0, left: 0, right: 0}; for (const key in hitSlop) { debugHitSlopStyle[key] = -hitSlop[key]; } - const hexColor = '#' + ('00000000' + normalizeColor(color).toString(16)).substr(-8); + const hexColor = + '#' + ('00000000' + normalizeColor(color).toString(16)).substr(-8); return ( ); - } + }, }; module.exports = Touchable; diff --git a/Libraries/Components/Touchable/TouchableNativeFeedback.android.js b/Libraries/Components/Touchable/TouchableNativeFeedback.android.js index 00f67818bf455a..f727d5d8a2b6be 100644 --- a/Libraries/Components/Touchable/TouchableNativeFeedback.android.js +++ b/Libraries/Components/Touchable/TouchableNativeFeedback.android.js @@ -4,7 +4,9 @@ * 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 Platform = require('Platform'); @@ -112,7 +114,10 @@ const TouchableNativeFeedback = createReactClass({ * Available on android API level 21+. */ SelectableBackgroundBorderless: function() { - return {type: 'ThemeAttrAndroid', attribute: 'selectableItemBackgroundBorderless'}; + return { + type: 'ThemeAttrAndroid', + attribute: 'selectableItemBackgroundBorderless', + }; }, /** * Creates an object that represents ripple drawable with specified color (as a @@ -125,12 +130,16 @@ const TouchableNativeFeedback = createReactClass({ * @param borderless If the ripple can render outside it's bounds */ Ripple: function(color: string, borderless: boolean) { - return {type: 'RippleAndroid', color: processColor(color), borderless: borderless}; + return { + type: 'RippleAndroid', + color: processColor(color), + borderless: borderless, + }; }, canUseNativeForeground: function() { return Platform.OS === 'android' && Platform.Version >= 23; - } + }, }, mixins: [Touchable.Mixin], @@ -161,7 +170,10 @@ const TouchableNativeFeedback = createReactClass({ this.props.onPressIn && this.props.onPressIn(e); this._dispatchPressedStateChange(true); if (this.pressInLocation) { - this._dispatchHotspotUpdate(this.pressInLocation.locationX, this.pressInLocation.locationY); + this._dispatchHotspotUpdate( + this.pressInLocation.locationX, + this.pressInLocation.locationY, + ); } }, @@ -201,14 +213,17 @@ const TouchableNativeFeedback = createReactClass({ _handleResponderMove: function(e) { this.touchableHandleResponderMove(e); - this._dispatchHotspotUpdate(e.nativeEvent.locationX, e.nativeEvent.locationY); + this._dispatchHotspotUpdate( + e.nativeEvent.locationX, + e.nativeEvent.locationY, + ); }, _dispatchHotspotUpdate: function(destX, destY) { UIManager.dispatchViewManagerCommand( ReactNative.findNodeHandle(this), UIManager.RCTView.Commands.hotspotUpdate, - [destX || 0, destY || 0] + [destX || 0, destY || 0], ); }, @@ -216,7 +231,7 @@ const TouchableNativeFeedback = createReactClass({ UIManager.dispatchViewManagerCommand( ReactNative.findNodeHandle(this), UIManager.RCTView.Commands.setPressed, - [pressed] + [pressed], ); }, @@ -227,16 +242,26 @@ const TouchableNativeFeedback = createReactClass({ if (!Array.isArray(children)) { children = [children]; } - children.push(Touchable.renderDebugView({color: 'brown', hitSlop: this.props.hitSlop})); + children.push( + Touchable.renderDebugView({ + color: 'brown', + hitSlop: this.props.hitSlop, + }), + ); } - if (this.props.useForeground && !TouchableNativeFeedback.canUseNativeForeground()) { + if ( + this.props.useForeground && + !TouchableNativeFeedback.canUseNativeForeground() + ) { console.warn( 'Requested foreground ripple, but it is not available on this version of Android. ' + - 'Consider calling TouchableNativeFeedback.canUseNativeForeground() and using a different ' + - 'Touchable if the result is false.'); + 'Consider calling TouchableNativeFeedback.canUseNativeForeground() and using a different ' + + 'Touchable if the result is false.', + ); } const drawableProp = - this.props.useForeground && TouchableNativeFeedback.canUseNativeForeground() + this.props.useForeground && + TouchableNativeFeedback.canUseNativeForeground() ? 'nativeForegroundAndroid' : 'nativeBackgroundAndroid'; const childProps = { @@ -253,7 +278,8 @@ const TouchableNativeFeedback = createReactClass({ isTVSelectable: true, hasTVPreferredFocus: this.props.hasTVPreferredFocus, onStartShouldSetResponder: this.touchableHandleStartShouldSetResponder, - onResponderTerminationRequest: this.touchableHandleResponderTerminationRequest, + onResponderTerminationRequest: this + .touchableHandleResponderTerminationRequest, onResponderGrant: this.touchableHandleResponderGrant, onResponderMove: this._handleResponderMove, onResponderRelease: this.touchableHandleResponderRelease, @@ -263,11 +289,8 @@ const TouchableNativeFeedback = createReactClass({ // We need to clone the actual element so that the ripple background drawable // can be applied directly to the background of this element rather than to // a wrapper view as done in other Touchable* - return React.cloneElement( - child, - childProps - ); - } + return React.cloneElement(child, childProps); + }, }); module.exports = TouchableNativeFeedback; diff --git a/Libraries/Components/Touchable/TouchableNativeFeedback.ios.js b/Libraries/Components/Touchable/TouchableNativeFeedback.ios.js index 8c195b9549bd97..b0770047bbeef8 100644 --- a/Libraries/Components/Touchable/TouchableNativeFeedback.ios.js +++ b/Libraries/Components/Touchable/TouchableNativeFeedback.ios.js @@ -4,6 +4,7 @@ * 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'; @@ -22,7 +23,9 @@ class DummyTouchableNativeFeedback extends React.Component { render() { return ( - TouchableNativeFeedback is not supported on this platform! + + TouchableNativeFeedback is not supported on this platform! + ); } @@ -42,7 +45,7 @@ const styles = StyleSheet.create({ info: { color: '#333333', margin: 20, - } + }, }); module.exports = DummyTouchableNativeFeedback; diff --git a/Libraries/Components/Touchable/TouchableOpacity.js b/Libraries/Components/Touchable/TouchableOpacity.js index 4ae20db8fb287c..afb01b079af9f7 100644 --- a/Libraries/Components/Touchable/TouchableOpacity.js +++ b/Libraries/Components/Touchable/TouchableOpacity.js @@ -4,8 +4,10 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * + * @format * @noflow */ + 'use strict'; // Note (avik): add @flow when Flow supports spread properties in propTypes @@ -167,15 +169,12 @@ const TouchableOpacity = createReactClass({ * Animate the touchable to a new opacity. */ setOpacityTo: function(value: number, duration: number) { - Animated.timing( - this.state.anim, - { - toValue: value, - duration: duration, - easing: Easing.inOut(Easing.quad), - useNativeDriver: true, - } - ).start(); + Animated.timing(this.state.anim, { + toValue: value, + duration: duration, + easing: Easing.inOut(Easing.quad), + useNativeDriver: true, + }).start(); }, /** @@ -217,8 +216,9 @@ const TouchableOpacity = createReactClass({ }, touchableGetLongPressDelayMS: function() { - return this.props.delayLongPress === 0 ? 0 : - this.props.delayLongPress || 500; + return this.props.delayLongPress === 0 + ? 0 + : this.props.delayLongPress || 500; }, touchableGetPressOutDelayMS: function() { @@ -230,16 +230,13 @@ const TouchableOpacity = createReactClass({ }, _opacityInactive: function(duration: number) { - this.setOpacityTo( - this._getChildStyleOpacityWithDefault(), - duration - ); + this.setOpacityTo(this._getChildStyleOpacityWithDefault(), duration); }, _getChildStyleOpacityWithDefault: function() { - const childStyle = flattenStyle(this.props.style) || {}; - return childStyle.opacity == undefined ? 1 : childStyle.opacity; - }, + const childStyle = flattenStyle(this.props.style) || {}; + return childStyle.opacity == undefined ? 1 : childStyle.opacity; + }, render: function() { return ( @@ -257,13 +254,18 @@ const TouchableOpacity = createReactClass({ tvParallaxProperties={this.props.tvParallaxProperties} hitSlop={this.props.hitSlop} onStartShouldSetResponder={this.touchableHandleStartShouldSetResponder} - onResponderTerminationRequest={this.touchableHandleResponderTerminationRequest} + onResponderTerminationRequest={ + this.touchableHandleResponderTerminationRequest + } onResponderGrant={this.touchableHandleResponderGrant} onResponderMove={this.touchableHandleResponderMove} onResponderRelease={this.touchableHandleResponderRelease} onResponderTerminate={this.touchableHandleResponderTerminate}> {this.props.children} - {Touchable.renderDebugView({color: 'cyan', hitSlop: this.props.hitSlop})} + {Touchable.renderDebugView({ + color: 'cyan', + hitSlop: this.props.hitSlop, + })} ); }, diff --git a/Libraries/Components/Touchable/TouchableWithoutFeedback.js b/Libraries/Components/Touchable/TouchableWithoutFeedback.js index d59d04cf4e6cf9..2c6530733aa517 100755 --- a/Libraries/Components/Touchable/TouchableWithoutFeedback.js +++ b/Libraries/Components/Touchable/TouchableWithoutFeedback.js @@ -4,8 +4,10 @@ * 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 EdgeInsetsPropType = require('EdgeInsetsPropType'); @@ -46,9 +48,7 @@ const TouchableWithoutFeedback = createReactClass({ propTypes: { accessible: PropTypes.bool, - accessibilityComponentType: PropTypes.oneOf( - AccessibilityComponentTypes - ), + accessibilityComponentType: PropTypes.oneOf(AccessibilityComponentTypes), accessibilityTraits: PropTypes.oneOfType([ PropTypes.oneOf(AccessibilityTraits), PropTypes.arrayOf(PropTypes.oneOf(AccessibilityTraits)), @@ -63,14 +63,14 @@ const TouchableWithoutFeedback = createReactClass({ */ onPress: PropTypes.func, /** - * Called as soon as the touchable element is pressed and invoked even before onPress. - * This can be useful when making network requests. - */ + * Called as soon as the touchable element is pressed and invoked even before onPress. + * This can be useful when making network requests. + */ onPressIn: PropTypes.func, /** - * Called as soon as the touch is released even before onPress. - */ - onPressOut: PropTypes.func, + * Called as soon as the touch is released even before onPress. + */ + onPressOut: PropTypes.func, /** * Invoked on mount and layout changes with * @@ -156,8 +156,9 @@ const TouchableWithoutFeedback = createReactClass({ }, touchableGetLongPressDelayMS: function(): number { - return this.props.delayLongPress === 0 ? 0 : - this.props.delayLongPress || 500; + return this.props.delayLongPress === 0 + ? 0 + : this.props.delayLongPress || 500; }, touchableGetPressOutDelayMS: function(): number { @@ -172,15 +173,25 @@ const TouchableWithoutFeedback = createReactClass({ warning( !child.type || child.type.displayName !== 'Text', 'TouchableWithoutFeedback does not work well with Text children. Wrap children in a View instead. See ' + - ((child._owner && child._owner.getName && child._owner.getName()) || '') + ((child._owner && child._owner.getName && child._owner.getName()) || + ''), ); - if (Touchable.TOUCH_TARGET_DEBUG && child.type && child.type.displayName === 'View') { + if ( + Touchable.TOUCH_TARGET_DEBUG && + child.type && + child.type.displayName === 'View' + ) { children = React.Children.toArray(children); - children.push(Touchable.renderDebugView({color: 'red', hitSlop: this.props.hitSlop})); + children.push( + Touchable.renderDebugView({color: 'red', hitSlop: this.props.hitSlop}), + ); } - const style = (Touchable.TOUCH_TARGET_DEBUG && child.type && child.type.displayName === 'Text') ? - [child.props.style, {color: 'red'}] : - child.props.style; + const style = + Touchable.TOUCH_TARGET_DEBUG && + child.type && + child.type.displayName === 'Text' + ? [child.props.style, {color: 'red'}] + : child.props.style; return (React: any).cloneElement(child, { accessible: this.props.accessible !== false, accessibilityLabel: this.props.accessibilityLabel, @@ -191,7 +202,8 @@ const TouchableWithoutFeedback = createReactClass({ onLayout: this.props.onLayout, hitSlop: this.props.hitSlop, onStartShouldSetResponder: this.touchableHandleStartShouldSetResponder, - onResponderTerminationRequest: this.touchableHandleResponderTerminationRequest, + onResponderTerminationRequest: this + .touchableHandleResponderTerminationRequest, onResponderGrant: this.touchableHandleResponderGrant, onResponderMove: this.touchableHandleResponderMove, onResponderRelease: this.touchableHandleResponderRelease, @@ -199,7 +211,7 @@ const TouchableWithoutFeedback = createReactClass({ style, children, }); - } + }, }); module.exports = TouchableWithoutFeedback; diff --git a/Libraries/Components/Touchable/__mocks__/ensureComponentIsNative.js b/Libraries/Components/Touchable/__mocks__/ensureComponentIsNative.js index 8f036c71e8cddf..f152b68bba74a4 100644 --- a/Libraries/Components/Touchable/__mocks__/ensureComponentIsNative.js +++ b/Libraries/Components/Touchable/__mocks__/ensureComponentIsNative.js @@ -3,7 +3,10 @@ * * 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 = () => true; diff --git a/Libraries/Components/Touchable/__tests__/TouchableHighlight-test.js b/Libraries/Components/Touchable/__tests__/TouchableHighlight-test.js index 396b7387b218cc..f40cc0b7ad1be9 100644 --- a/Libraries/Components/Touchable/__tests__/TouchableHighlight-test.js +++ b/Libraries/Components/Touchable/__tests__/TouchableHighlight-test.js @@ -4,8 +4,10 @@ * 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 React = require('React'); @@ -18,7 +20,7 @@ describe('TouchableHighlight', () => { const instance = ReactTestRenderer.create( Touchable - + , ); expect(instance.toJSON()).toMatchSnapshot(); diff --git a/Libraries/Components/Touchable/ensureComponentIsNative.js b/Libraries/Components/Touchable/ensureComponentIsNative.js index 9b82aeb45ec6ae..5ce5a39d9baaf0 100644 --- a/Libraries/Components/Touchable/ensureComponentIsNative.js +++ b/Libraries/Components/Touchable/ensureComponentIsNative.js @@ -4,8 +4,10 @@ * 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 invariant = require('fbjs/lib/invariant'); @@ -14,7 +16,7 @@ const ensureComponentIsNative = function(component: any) { invariant( component && typeof component.setNativeProps === 'function', 'Touchable child must either be native or forward setNativeProps to a ' + - 'native component' + 'native component', ); }; diff --git a/Libraries/Components/Touchable/ensurePositiveDelayProps.js b/Libraries/Components/Touchable/ensurePositiveDelayProps.js index 9d0be5ccdc5e8d..01c001ad4b6a7e 100644 --- a/Libraries/Components/Touchable/ensurePositiveDelayProps.js +++ b/Libraries/Components/Touchable/ensurePositiveDelayProps.js @@ -4,17 +4,22 @@ * 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 invariant = require('fbjs/lib/invariant'); const ensurePositiveDelayProps = function(props: any) { invariant( - !(props.delayPressIn < 0 || props.delayPressOut < 0 || - props.delayLongPress < 0), - 'Touchable components cannot have negative delay properties' + !( + props.delayPressIn < 0 || + props.delayPressOut < 0 || + props.delayLongPress < 0 + ), + 'Touchable components cannot have negative delay properties', ); }; diff --git a/Libraries/Components/View/PlatformViewPropTypes.js b/Libraries/Components/View/PlatformViewPropTypes.js index 70ab6694192fb2..4c6105893cc6eb 100644 --- a/Libraries/Components/View/PlatformViewPropTypes.js +++ b/Libraries/Components/View/PlatformViewPropTypes.js @@ -4,6 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * + * @format * @flow */ diff --git a/Libraries/Components/View/ReactNativeStyleAttributes.js b/Libraries/Components/View/ReactNativeStyleAttributes.js index 7c8422413579ad..7a75dda8b7f41b 100644 --- a/Libraries/Components/View/ReactNativeStyleAttributes.js +++ b/Libraries/Components/View/ReactNativeStyleAttributes.js @@ -4,6 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * + * @format * @flow */ @@ -27,10 +28,10 @@ const ReactNativeStyleAttributes = { ...keyMirror(ImageStylePropTypes), }; -ReactNativeStyleAttributes.transform = { process: processTransform }; -ReactNativeStyleAttributes.shadowOffset = { diff: sizesDiffer }; +ReactNativeStyleAttributes.transform = {process: processTransform}; +ReactNativeStyleAttributes.shadowOffset = {diff: sizesDiffer}; -const colorAttributes = { process: processColor }; +const colorAttributes = {process: processColor}; ReactNativeStyleAttributes.backgroundColor = colorAttributes; ReactNativeStyleAttributes.borderBottomColor = colorAttributes; ReactNativeStyleAttributes.borderColor = colorAttributes; diff --git a/Libraries/Components/View/ReactNativeViewAttributes.js b/Libraries/Components/View/ReactNativeViewAttributes.js index f18b70281935bc..7bf8117710ef5d 100644 --- a/Libraries/Components/View/ReactNativeViewAttributes.js +++ b/Libraries/Components/View/ReactNativeViewAttributes.js @@ -4,8 +4,10 @@ * 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 ReactNativeStyleAttributes = require('ReactNativeStyleAttributes'); diff --git a/Libraries/Components/View/ViewAccessibility.js b/Libraries/Components/View/ViewAccessibility.js index edab2a5695112b..c5e44e289d08d3 100644 --- a/Libraries/Components/View/ViewAccessibility.js +++ b/Libraries/Components/View/ViewAccessibility.js @@ -4,34 +4,36 @@ * 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'; export type AccessibilityTrait = - 'none' | - 'button' | - 'link' | - 'header' | - 'search' | - 'image' | - 'selected' | - 'plays' | - 'key' | - 'text' | - 'summary' | - 'disabled' | - 'frequentUpdates' | - 'startsMedia' | - 'adjustable' | - 'allowsDirectInteraction' | - 'pageTurn'; + | 'none' + | 'button' + | 'link' + | 'header' + | 'search' + | 'image' + | 'selected' + | 'plays' + | 'key' + | 'text' + | 'summary' + | 'disabled' + | 'frequentUpdates' + | 'startsMedia' + | 'adjustable' + | 'allowsDirectInteraction' + | 'pageTurn'; export type AccessibilityComponentType = - 'none' | - 'button' | - 'radiobutton_checked' | - 'radiobutton_unchecked'; + | 'none' + | 'button' + | 'radiobutton_checked' + | 'radiobutton_unchecked'; module.exports = { AccessibilityTraits: [ diff --git a/Libraries/Components/View/ViewPropTypes.js b/Libraries/Components/View/ViewPropTypes.js index 332059ab0a222a..946368f267de91 100644 --- a/Libraries/Components/View/ViewPropTypes.js +++ b/Libraries/Components/View/ViewPropTypes.js @@ -4,8 +4,10 @@ * 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'); @@ -36,15 +38,20 @@ export type ViewLayoutEvent = LayoutEvent; // There's no easy way to create a different type if (Platform.isTVOS): // so we must include TVViewProps export type ViewProps = { - accessible?: bool, - accessibilityLabel?: null | React$PropType$Primitive | string | Array | any, + accessible?: boolean, + accessibilityLabel?: + | null + | React$PropType$Primitive + | string + | Array + | any, accessibilityActions?: Array, accessibilityComponentType?: AccessibilityComponentType, accessibilityLiveRegion?: 'none' | 'polite' | 'assertive', - importantForAccessibility?: 'auto'| 'yes'| 'no'| 'no-hide-descendants', + importantForAccessibility?: 'auto' | 'yes' | 'no' | 'no-hide-descendants', accessibilityTraits?: AccessibilityTrait | Array, - accessibilityViewIsModal?: bool, - accessibilityElementsHidden?: bool, + accessibilityViewIsModal?: boolean, + accessibilityElementsHidden?: boolean, children?: ?React.Node, onAccessibilityAction?: Function, onAccessibilityTap?: Function, @@ -63,13 +70,13 @@ export type ViewProps = { onMoveShouldSetResponder?: ?Function, onMoveShouldSetResponderCapture?: ?Function, hitSlop?: ?EdgeInsetsProp, - pointerEvents?: null | 'box-none'| 'none'| 'box-only'| 'auto', + pointerEvents?: null | 'box-none' | 'none' | 'box-only' | 'auto', style?: stylePropType, - removeClippedSubviews?: bool, - renderToHardwareTextureAndroid?: bool, - shouldRasterizeIOS?: bool, - collapsable?: bool, - needsOffscreenAlphaCompositing?: bool, + removeClippedSubviews?: boolean, + renderToHardwareTextureAndroid?: boolean, + shouldRasterizeIOS?: boolean, + collapsable?: boolean, + needsOffscreenAlphaCompositing?: boolean, } & TVViewProps; module.exports = { @@ -115,11 +122,7 @@ module.exports = { * * See http://facebook.github.io/react-native/docs/view.html#accessibilityliveregion */ - accessibilityLiveRegion: PropTypes.oneOf([ - 'none', - 'polite', - 'assertive', - ]), + accessibilityLiveRegion: PropTypes.oneOf(['none', 'polite', 'assertive']), /** * Controls how view is important for accessibility which is if it @@ -361,12 +364,7 @@ module.exports = { * * See http://facebook.github.io/react-native/docs/view.html#pointerevents */ - pointerEvents: PropTypes.oneOf([ - 'box-none', - 'none', - 'box-only', - 'auto', - ]), + pointerEvents: PropTypes.oneOf(['box-none', 'none', 'box-only', 'auto']), /** * See http://facebook.github.io/react-native/docs/style.html diff --git a/Libraries/Components/View/ViewStylePropTypes.js b/Libraries/Components/View/ViewStylePropTypes.js index e252cf5d2c7850..8f690fb32f6891 100644 --- a/Libraries/Components/View/ViewStylePropTypes.js +++ b/Libraries/Components/View/ViewStylePropTypes.js @@ -4,8 +4,10 @@ * 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 ColorPropType = require('ColorPropType'); diff --git a/Libraries/Components/ViewPager/ViewPagerAndroid.android.js b/Libraries/Components/ViewPager/ViewPagerAndroid.android.js index 19421ccc6436d1..4b75cfb42d5219 100644 --- a/Libraries/Components/ViewPager/ViewPagerAndroid.android.js +++ b/Libraries/Components/ViewPager/ViewPagerAndroid.android.js @@ -4,8 +4,10 @@ * 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'); @@ -132,16 +134,16 @@ class ViewPagerAndroid extends React.Component<{ ]), /** - * When false, the content does not scroll. - * The default value is true. - */ + * When false, the content does not scroll. + * The default value is true. + */ scrollEnabled: PropTypes.bool, /** * 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: PropTypes.bool, + peekEnabled: PropTypes.bool, }; componentDidMount() { @@ -164,22 +166,30 @@ class ViewPagerAndroid extends React.Component<{ } const newProps = { ...child.props, - style: [child.props.style, { - position: 'absolute', - left: 0, - top: 0, - right: 0, - bottom: 0, - width: undefined, - height: undefined, - }], + 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); + 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); }); @@ -245,6 +255,9 @@ class ViewPagerAndroid extends React.Component<{ } } -const NativeAndroidViewPager = requireNativeComponent('AndroidViewPager', ViewPagerAndroid); +const NativeAndroidViewPager = requireNativeComponent( + 'AndroidViewPager', + ViewPagerAndroid, +); module.exports = ViewPagerAndroid; diff --git a/Libraries/Components/ViewPager/ViewPagerAndroid.ios.js b/Libraries/Components/ViewPager/ViewPagerAndroid.ios.js index ebd42dd5b18bb0..260d559929796f 100644 --- a/Libraries/Components/ViewPager/ViewPagerAndroid.ios.js +++ b/Libraries/Components/ViewPager/ViewPagerAndroid.ios.js @@ -4,7 +4,9 @@ * 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('UnimplementedView'); diff --git a/Libraries/Components/WebView/WebView.android.js b/Libraries/Components/WebView/WebView.android.js index b6995458e59001..afc69bfcb912ee 100644 --- a/Libraries/Components/WebView/WebView.android.js +++ b/Libraries/Components/WebView/WebView.android.js @@ -4,7 +4,9 @@ * 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 EdgeInsetsPropType = require('EdgeInsetsPropType'); @@ -33,9 +35,7 @@ const WebViewState = keyMirror({ const defaultRenderLoading = () => ( - + ); @@ -69,13 +69,10 @@ class WebView extends React.Component { html: deprecatedPropType( PropTypes.string, - 'Use the `source` prop instead.' + 'Use the `source` prop instead.', ), - url: deprecatedPropType( - PropTypes.string, - 'Use the `source` prop instead.' - ), + url: deprecatedPropType(PropTypes.string, 'Use the `source` prop instead.'), /** * Loads static html or a uri (with optional headers) in the WebView. @@ -205,11 +202,7 @@ class WebView extends React.Component { * - `'compatibility'` - WebView will attempt to be compatible with the approach of a modern web browser with regard to mixed content. * @platform android */ - mixedContentMode: PropTypes.oneOf([ - 'never', - 'always', - 'compatibility' - ]), + mixedContentMode: PropTypes.oneOf(['never', 'always', 'compatibility']), /** * Used on Android only, controls whether form autocomplete data should be saved @@ -248,7 +241,7 @@ class WebView extends React.Component { }; static defaultProps = { - javaScriptEnabled : true, + javaScriptEnabled: true, thirdPartyCookiesEnabled: true, scalesPageToFit: true, saveFormDataDisabled: false, @@ -270,21 +263,28 @@ class WebView extends React.Component { render() { let otherView = null; - if (this.state.viewState === WebViewState.LOADING) { + if (this.state.viewState === WebViewState.LOADING) { otherView = (this.props.renderLoading || defaultRenderLoading)(); } else if (this.state.viewState === WebViewState.ERROR) { const errorEvent = this.state.lastErrorEvent; - otherView = this.props.renderError && this.props.renderError( - errorEvent.domain, - errorEvent.code, - errorEvent.description); + otherView = + this.props.renderError && + this.props.renderError( + errorEvent.domain, + errorEvent.code, + errorEvent.description, + ); } else if (this.state.viewState !== WebViewState.IDLE) { - console.error('RCTWebView invalid state encountered: ' + this.state.loading); + console.error( + 'RCTWebView invalid state encountered: ' + this.state.loading, + ); } const webViewStyles = [styles.container, this.props.style]; - if (this.state.viewState === WebViewState.LOADING || - this.state.viewState === WebViewState.ERROR) { + if ( + this.state.viewState === WebViewState.LOADING || + this.state.viewState === WebViewState.ERROR + ) { // if we're in either LOADING or ERROR states, don't show the webView webViewStyles.push(styles.hidden); } @@ -297,18 +297,22 @@ class WebView extends React.Component { } if (source.method === 'POST' && source.headers) { - console.warn('WebView: `source.headers` is not supported when using POST.'); + console.warn( + 'WebView: `source.headers` is not supported when using POST.', + ); } else if (source.method === 'GET' && source.body) { console.warn('WebView: `source.body` is not supported when using GET.'); } const nativeConfig = this.props.nativeConfig || {}; - const originWhitelist = (this.props.originWhitelist || []).map(WebViewShared.originWhitelistToRegex); + const originWhitelist = (this.props.originWhitelist || []).map( + WebViewShared.originWhitelistToRegex, + ); let NativeWebView = nativeConfig.component || RCTWebView; - const webView = + const webView = ( ; + /> + ); return ( @@ -351,7 +362,7 @@ class WebView extends React.Component { UIManager.dispatchViewManagerCommand( this.getWebViewHandle(), UIManager.RCTWebView.Commands.goForward, - null + null, ); }; @@ -359,18 +370,18 @@ class WebView extends React.Component { UIManager.dispatchViewManagerCommand( this.getWebViewHandle(), UIManager.RCTWebView.Commands.goBack, - null + null, ); }; reload = () => { this.setState({ - viewState: WebViewState.LOADING + viewState: WebViewState.LOADING, }); UIManager.dispatchViewManagerCommand( this.getWebViewHandle(), UIManager.RCTWebView.Commands.reload, - null + null, ); }; @@ -378,29 +389,29 @@ class WebView extends React.Component { UIManager.dispatchViewManagerCommand( this.getWebViewHandle(), UIManager.RCTWebView.Commands.stopLoading, - null + null, ); }; - postMessage = (data) => { + postMessage = data => { UIManager.dispatchViewManagerCommand( this.getWebViewHandle(), UIManager.RCTWebView.Commands.postMessage, - [String(data)] + [String(data)], ); }; /** - * Injects a javascript string into the referenced WebView. Deliberately does not - * return a response because using eval() to return a response breaks this method - * on pages with a Content Security Policy that disallows eval(). If you need that - * functionality, look into postMessage/onMessage. - */ - injectJavaScript = (data) => { + * Injects a javascript string into the referenced WebView. Deliberately does not + * return a response because using eval() to return a response breaks this method + * on pages with a Content Security Policy that disallows eval(). If you need that + * functionality, look into postMessage/onMessage. + */ + injectJavaScript = data => { UIManager.dispatchViewManagerCommand( this.getWebViewHandle(), UIManager.RCTWebView.Commands.injectJavaScript, - [data] + [data], ); }; @@ -408,7 +419,7 @@ class WebView extends React.Component { * We return an event with a bunch of fields including: * url, title, loading, canGoBack, canGoForward */ - updateNavigationState = (event) => { + updateNavigationState = event => { if (this.props.onNavigationStateChange) { this.props.onNavigationStateChange(event.nativeEvent); } @@ -418,13 +429,13 @@ class WebView extends React.Component { return ReactNative.findNodeHandle(this.refs[RCT_WEBVIEW_REF]); }; - onLoadingStart = (event) => { + onLoadingStart = event => { const onLoadStart = this.props.onLoadStart; onLoadStart && onLoadStart(event); this.updateNavigationState(event); }; - onLoadingError = (event) => { + onLoadingError = event => { event.persist(); // persist this event because we need to store it const {onError, onLoadEnd} = this.props; onError && onError(event); @@ -433,11 +444,11 @@ class WebView extends React.Component { this.setState({ lastErrorEvent: event.nativeEvent, - viewState: WebViewState.ERROR + viewState: WebViewState.ERROR, }); }; - onLoadingFinish = (event) => { + onLoadingFinish = event => { const {onLoad, onLoadEnd} = this.props; onLoad && onLoad(event); onLoadEnd && onLoadEnd(event); @@ -450,10 +461,14 @@ class WebView extends React.Component { onMessage = (event: Event) => { const {onMessage} = this.props; onMessage && onMessage(event); - } + }; } -const RCTWebView = requireNativeComponent('RCTWebView', WebView, WebView.extraNativeComponentConfig); +const RCTWebView = requireNativeComponent( + 'RCTWebView', + WebView, + WebView.extraNativeComponentConfig, +); const styles = StyleSheet.create({ container: { diff --git a/Libraries/Components/WebView/WebView.ios.js b/Libraries/Components/WebView/WebView.ios.js index 1d54f663f01b3f..8c0630c2c0e718 100644 --- a/Libraries/Components/WebView/WebView.ios.js +++ b/Libraries/Components/WebView/WebView.ios.js @@ -4,8 +4,10 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * + * @format * @noflow */ + 'use strict'; const ActivityIndicator = require('ActivityIndicator'); @@ -55,7 +57,7 @@ type ErrorEvent = { domain: any, code: any, description: any, -} +}; type Event = Object; @@ -75,18 +77,10 @@ const defaultRenderLoading = () => ( ); const defaultRenderError = (errorDomain, errorCode, errorDesc) => ( - - Error loading page - - - {'Domain: ' + errorDomain} - - - {'Error Code: ' + errorCode} - - - {'Description: ' + errorDesc} - + Error loading page + {'Domain: ' + errorDomain} + {'Error Code: ' + errorCode} + {'Description: ' + errorDesc} ); @@ -132,13 +126,10 @@ class WebView extends React.Component { html: deprecatedPropType( PropTypes.string, - 'Use the `source` prop instead.' + 'Use the `source` prop instead.', ), - url: deprecatedPropType( - PropTypes.string, - 'Use the `source` prop instead.' - ), + url: deprecatedPropType(PropTypes.string, 'Use the `source` prop instead.'), /** * Loads static html or a uri (with optional headers) in the WebView. @@ -380,11 +371,7 @@ class WebView extends React.Component { * - `'compatibility'` - WebView will attempt to be compatible with the approach of a modern web browser with regard to mixed content. * @platform android */ - mixedContentMode: PropTypes.oneOf([ - 'never', - 'always', - 'compatibility' - ]), + mixedContentMode: PropTypes.oneOf(['never', 'always', 'compatibility']), /** * Override the native component used to render the WebView. Enables a custom native @@ -432,24 +419,23 @@ class WebView extends React.Component { otherView = (this.props.renderLoading || defaultRenderLoading)(); } else if (this.state.viewState === WebViewState.ERROR) { const errorEvent = this.state.lastErrorEvent; - invariant( - errorEvent != null, - 'lastErrorEvent expected to be non-null' - ); + invariant(errorEvent != null, 'lastErrorEvent expected to be non-null'); otherView = (this.props.renderError || defaultRenderError)( errorEvent.domain, errorEvent.code, - errorEvent.description + errorEvent.description, ); } else if (this.state.viewState !== WebViewState.IDLE) { console.error( - 'RCTWebView invalid state encountered: ' + this.state.loading + 'RCTWebView invalid state encountered: ' + this.state.loading, ); } const webViewStyles = [styles.container, styles.webView, this.props.style]; - if (this.state.viewState === WebViewState.LOADING || - this.state.viewState === WebViewState.ERROR) { + if ( + this.state.viewState === WebViewState.LOADING || + this.state.viewState === WebViewState.ERROR + ) { // if we're in either LOADING or ERROR states, don't show the webView webViewStyles.push(styles.hidden); } @@ -458,23 +444,34 @@ class WebView extends React.Component { const viewManager = nativeConfig.viewManager || RCTWebViewManager; - const compiledWhitelist = (this.props.originWhitelist || []).map(WebViewShared.originWhitelistToRegex); - const onShouldStartLoadWithRequest = ((event: Event) => { + const compiledWhitelist = (this.props.originWhitelist || []).map( + WebViewShared.originWhitelistToRegex, + ); + const onShouldStartLoadWithRequest = (event: Event) => { let shouldStart = true; const {url} = event.nativeEvent; const origin = WebViewShared.extractOrigin(url); - const passesWhitelist = compiledWhitelist.some(x => new RegExp(x).test(origin)); + const passesWhitelist = compiledWhitelist.some(x => + new RegExp(x).test(origin), + ); shouldStart = shouldStart && passesWhitelist; if (!passesWhitelist) { Linking.openURL(url); } if (this.props.onShouldStartLoadWithRequest) { - shouldStart = shouldStart && this.props.onShouldStartLoadWithRequest(event.nativeEvent); + shouldStart = + shouldStart && + this.props.onShouldStartLoadWithRequest(event.nativeEvent); } - viewManager.startLoadWithResult(!!shouldStart, event.nativeEvent.lockIdentifier); - }); + viewManager.startLoadWithResult( + !!shouldStart, + event.nativeEvent.lockIdentifier, + ); + }; - const decelerationRate = processDecelerationRate(this.props.decelerationRate); + const decelerationRate = processDecelerationRate( + this.props.decelerationRate, + ); const source = this.props.source || {}; if (this.props.html) { @@ -485,9 +482,9 @@ class WebView extends React.Component { const messagingEnabled = typeof this.props.onMessage === 'function'; - const NativeWebView = nativeConfig.component || RCTWebView; + const NativeWebView = nativeConfig.component || RCTWebView; - const webView = + const webView = ( ; + /> + ); return ( @@ -527,7 +529,7 @@ class WebView extends React.Component { UIManager.dispatchViewManagerCommand( this.getWebViewHandle(), UIManager.RCTWebView.Commands.goForward, - null + null, ); }; @@ -538,7 +540,7 @@ class WebView extends React.Component { UIManager.dispatchViewManagerCommand( this.getWebViewHandle(), UIManager.RCTWebView.Commands.goBack, - null + null, ); }; @@ -550,7 +552,7 @@ class WebView extends React.Component { UIManager.dispatchViewManagerCommand( this.getWebViewHandle(), UIManager.RCTWebView.Commands.reload, - null + null, ); }; @@ -561,7 +563,7 @@ class WebView extends React.Component { UIManager.dispatchViewManagerCommand( this.getWebViewHandle(), UIManager.RCTWebView.Commands.stopLoading, - null + null, ); }; @@ -575,25 +577,25 @@ class WebView extends React.Component { * document.addEventListener('message', e => { document.title = e.data; }); * ``` */ - postMessage = (data) => { + postMessage = data => { UIManager.dispatchViewManagerCommand( this.getWebViewHandle(), UIManager.RCTWebView.Commands.postMessage, - [String(data)] + [String(data)], ); }; /** - * Injects a javascript string into the referenced WebView. Deliberately does not - * return a response because using eval() to return a response breaks this method - * on pages with a Content Security Policy that disallows eval(). If you need that - * functionality, look into postMessage/onMessage. - */ - injectJavaScript = (data) => { + * Injects a javascript string into the referenced WebView. Deliberately does not + * return a response because using eval() to return a response breaks this method + * on pages with a Content Security Policy that disallows eval(). If you need that + * functionality, look into postMessage/onMessage. + */ + injectJavaScript = data => { UIManager.dispatchViewManagerCommand( this.getWebViewHandle(), UIManager.RCTWebView.Commands.injectJavaScript, - [data] + [data], ); }; @@ -629,7 +631,7 @@ class WebView extends React.Component { this.setState({ lastErrorEvent: event.nativeEvent, - viewState: WebViewState.ERROR + viewState: WebViewState.ERROR, }); }; @@ -646,10 +648,14 @@ class WebView extends React.Component { _onMessage = (event: Event) => { const {onMessage} = this.props; onMessage && onMessage(event); - } + }; } -const RCTWebView = requireNativeComponent('RCTWebView', WebView, WebView.extraNativeComponentConfig); +const RCTWebView = requireNativeComponent( + 'RCTWebView', + WebView, + WebView.extraNativeComponentConfig, +); const styles = StyleSheet.create({ container: { @@ -684,7 +690,7 @@ const styles = StyleSheet.create({ }, webView: { backgroundColor: '#ffffff', - } + }, }); module.exports = WebView; diff --git a/Libraries/Components/WebView/WebViewShared.js b/Libraries/Components/WebView/WebViewShared.js index 744ea201f4670b..5a3006e845b0cc 100644 --- a/Libraries/Components/WebView/WebViewShared.js +++ b/Libraries/Components/WebView/WebViewShared.js @@ -4,8 +4,10 @@ * 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 escapeStringRegexp = require('escape-string-regexp'); diff --git a/Libraries/Components/WebView/__tests__/WebViewShared-test.js b/Libraries/Components/WebView/__tests__/WebViewShared-test.js index 37f52064c431e9..b7456638fedb71 100644 --- a/Libraries/Components/WebView/__tests__/WebViewShared-test.js +++ b/Libraries/Components/WebView/__tests__/WebViewShared-test.js @@ -4,25 +4,46 @@ * 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'; +'use strict'; const WebViewShared = require('WebViewShared'); describe('WebViewShared', () => { it('extracts the origin correctly', () => { - expect(WebViewShared.extractOrigin('http://facebook.com')).toBe('http://facebook.com'); - expect(WebViewShared.extractOrigin('https://facebook.com')).toBe('https://facebook.com'); - expect(WebViewShared.extractOrigin('http://facebook.com:8081')).toBe('http://facebook.com:8081'); - expect(WebViewShared.extractOrigin('ftp://facebook.com')).toBe('ftp://facebook.com'); - expect(WebViewShared.extractOrigin('myweirdscheme://')).toBe('myweirdscheme://'); - expect(WebViewShared.extractOrigin('http://facebook.com/')).toBe('http://facebook.com'); - expect(WebViewShared.extractOrigin('http://facebook.com/longerurl')).toBe('http://facebook.com'); - expect(WebViewShared.extractOrigin('http://facebook.com/http://facebook.com')).toBe('http://facebook.com'); - expect(WebViewShared.extractOrigin('http://facebook.com//http://facebook.com')).toBe('http://facebook.com'); - expect(WebViewShared.extractOrigin('http://facebook.com//http://facebook.com//')).toBe('http://facebook.com'); + expect(WebViewShared.extractOrigin('http://facebook.com')).toBe( + 'http://facebook.com', + ); + expect(WebViewShared.extractOrigin('https://facebook.com')).toBe( + 'https://facebook.com', + ); + expect(WebViewShared.extractOrigin('http://facebook.com:8081')).toBe( + 'http://facebook.com:8081', + ); + expect(WebViewShared.extractOrigin('ftp://facebook.com')).toBe( + 'ftp://facebook.com', + ); + expect(WebViewShared.extractOrigin('myweirdscheme://')).toBe( + 'myweirdscheme://', + ); + expect(WebViewShared.extractOrigin('http://facebook.com/')).toBe( + 'http://facebook.com', + ); + expect(WebViewShared.extractOrigin('http://facebook.com/longerurl')).toBe( + 'http://facebook.com', + ); + expect( + WebViewShared.extractOrigin('http://facebook.com/http://facebook.com'), + ).toBe('http://facebook.com'); + expect( + WebViewShared.extractOrigin('http://facebook.com//http://facebook.com'), + ).toBe('http://facebook.com'); + expect( + WebViewShared.extractOrigin('http://facebook.com//http://facebook.com//'), + ).toBe('http://facebook.com'); expect(WebViewShared.extractOrigin('about:blank')).toBe('about:blank'); }); diff --git a/Libraries/Core/Devtools/__tests__/parseErrorStack-test.js b/Libraries/Core/Devtools/__tests__/parseErrorStack-test.js index 7726a6117b9b83..79d677e217e71c 100644 --- a/Libraries/Core/Devtools/__tests__/parseErrorStack-test.js +++ b/Libraries/Core/Devtools/__tests__/parseErrorStack-test.js @@ -4,10 +4,11 @@ * 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'; +'use strict'; const parseErrorStack = require('parseErrorStack'); @@ -16,7 +17,6 @@ function getFakeError() { } describe('parseErrorStack', function() { - it('parses error stack', function() { const stack = parseErrorStack(getFakeError()); expect(stack.length).toBeGreaterThan(0); @@ -43,5 +43,4 @@ describe('parseErrorStack', function() { expect(parseErrorStack({})).toEqual([]); expect(parseErrorStack(null)).toEqual([]); }); - }); diff --git a/Libraries/Core/Devtools/getDevServer.js b/Libraries/Core/Devtools/getDevServer.js index 1087f6ead2b76f..adcc28c2d067e1 100644 --- a/Libraries/Core/Devtools/getDevServer.js +++ b/Libraries/Core/Devtools/getDevServer.js @@ -4,8 +4,10 @@ * 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 {SourceCode} = require('NativeModules'); @@ -24,7 +26,10 @@ type DevServerInfo = { */ function getDevServer(): DevServerInfo { if (_cachedDevServerURL === undefined) { - const match = SourceCode && SourceCode.scriptURL && SourceCode.scriptURL.match(/^https?:\/\/.*?\//); + const match = + SourceCode && + SourceCode.scriptURL && + SourceCode.scriptURL.match(/^https?:\/\/.*?\//); _cachedDevServerURL = match ? match[0] : null; } diff --git a/Libraries/Core/Devtools/openFileInEditor.js b/Libraries/Core/Devtools/openFileInEditor.js index 1f4437a5ef8c16..c085883920aeda 100644 --- a/Libraries/Core/Devtools/openFileInEditor.js +++ b/Libraries/Core/Devtools/openFileInEditor.js @@ -4,8 +4,10 @@ * 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 getDevServer = require('getDevServer'); diff --git a/Libraries/Core/Devtools/parseErrorStack.js b/Libraries/Core/Devtools/parseErrorStack.js index efcad10191d461..ec85260d7eaa35 100644 --- a/Libraries/Core/Devtools/parseErrorStack.js +++ b/Libraries/Core/Devtools/parseErrorStack.js @@ -4,8 +4,10 @@ * 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'; export type StackFrame = { @@ -28,7 +30,9 @@ function parseErrorStack(e: ExtendedError): Array { * error found when Flow v0.54 was deployed. To see the error delete this * comment and run Flow. */ const stacktraceParser = require('stacktrace-parser'); - const stack = Array.isArray(e.stack) ? e.stack : stacktraceParser.parse(e.stack); + const stack = Array.isArray(e.stack) + ? e.stack + : stacktraceParser.parse(e.stack); let framesToPop = typeof e.framesToPop === 'number' ? e.framesToPop : 0; while (framesToPop--) { diff --git a/Libraries/Core/Devtools/setupDevtools.js b/Libraries/Core/Devtools/setupDevtools.js index fec7ea6160cc5d..ddca7d04003025 100644 --- a/Libraries/Core/Devtools/setupDevtools.js +++ b/Libraries/Core/Devtools/setupDevtools.js @@ -4,8 +4,10 @@ * 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'; type DevToolsPluginConnection = { @@ -18,7 +20,7 @@ type DevToolsPlugin = { connectToDevTools: (connection: DevToolsPluginConnection) => void, }; -let register = function () { +let register = function() { // noop }; diff --git a/Libraries/Core/Devtools/symbolicateStackTrace.js b/Libraries/Core/Devtools/symbolicateStackTrace.js index 8933394ba92deb..b5d7d4e9754ff0 100644 --- a/Libraries/Core/Devtools/symbolicateStackTrace.js +++ b/Libraries/Core/Devtools/symbolicateStackTrace.js @@ -4,8 +4,10 @@ * 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 getDevServer = require('getDevServer'); @@ -21,7 +23,9 @@ function isSourcedFromDisk(sourcePath: string): boolean { return !/^http/.test(sourcePath) && /[\\/]/.test(sourcePath); } -async function symbolicateStackTrace(stack: Array): Promise> { +async function symbolicateStackTrace( + stack: Array, +): Promise> { // RN currently lazy loads whatwg-fetch using a custom fetch module, which, // when called for the first time, requires and re-exports 'whatwg-fetch'. // However, when a dependency of the project tries to require whatwg-fetch diff --git a/Libraries/Core/ExceptionsManager.js b/Libraries/Core/ExceptionsManager.js index 6a0ba132dc8133..bc32f5d0d23890 100644 --- a/Libraries/Core/ExceptionsManager.js +++ b/Libraries/Core/ExceptionsManager.js @@ -4,8 +4,10 @@ * 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 {ExtendedError} from 'parseErrorStack'; @@ -14,30 +16,42 @@ import type {ExtendedError} from 'parseErrorStack'; * Handles the developer-visible aspect of errors and exceptions */ let exceptionID = 0; -function reportException(e: ExtendedError, isFatal: bool) { +function reportException(e: ExtendedError, isFatal: boolean) { const {ExceptionsManager} = require('NativeModules'); if (ExceptionsManager) { const parseErrorStack = require('parseErrorStack'); const stack = parseErrorStack(e); const currentExceptionID = ++exceptionID; if (isFatal) { - ExceptionsManager.reportFatalException(e.message, stack, currentExceptionID); + ExceptionsManager.reportFatalException( + e.message, + stack, + currentExceptionID, + ); } else { - ExceptionsManager.reportSoftException(e.message, stack, currentExceptionID); + ExceptionsManager.reportSoftException( + e.message, + stack, + currentExceptionID, + ); } if (__DEV__) { const symbolicateStackTrace = require('symbolicateStackTrace'); - symbolicateStackTrace(stack).then( - (prettyStack) => { + symbolicateStackTrace(stack) + .then(prettyStack => { if (prettyStack) { - ExceptionsManager.updateExceptionMessage(e.message, prettyStack, currentExceptionID); + ExceptionsManager.updateExceptionMessage( + e.message, + prettyStack, + currentExceptionID, + ); } else { throw new Error('The stack is null'); } - } - ).catch( - (error) => console.warn('Unable to symbolicate stack trace: ' + error.message) - ); + }) + .catch(error => + console.warn('Unable to symbolicate stack trace: ' + error.message), + ); } } } @@ -83,7 +97,7 @@ function reactConsoleErrorHandler() { // (Note: Logic duplicated in polyfills/console.js.) return; } - const error : ExtendedError = new Error('console.error: ' + str); + const error: ExtendedError = new Error('console.error: ' + str); error.framesToPop = 1; reportException(error, /* isFatal */ false); } @@ -108,4 +122,4 @@ function installConsoleErrorReporter() { } } -module.exports = { handleException, installConsoleErrorReporter }; +module.exports = {handleException, installConsoleErrorReporter}; diff --git a/Libraries/Core/InitializeCore.js b/Libraries/Core/InitializeCore.js index 2f10d5fc0e05e9..119deb92b2b0bc 100644 --- a/Libraries/Core/InitializeCore.js +++ b/Libraries/Core/InitializeCore.js @@ -4,6 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * + * @format * @flow */ @@ -152,13 +153,25 @@ polyfillObjectProperty(navigator, 'geolocation', () => require('Geolocation')); const BatchedBridge = require('BatchedBridge'); BatchedBridge.registerLazyCallableModule('Systrace', () => require('Systrace')); BatchedBridge.registerLazyCallableModule('JSTimers', () => require('JSTimers')); -BatchedBridge.registerLazyCallableModule('HeapCapture', () => require('HeapCapture')); -BatchedBridge.registerLazyCallableModule('SamplingProfiler', () => require('SamplingProfiler')); +BatchedBridge.registerLazyCallableModule('HeapCapture', () => + require('HeapCapture'), +); +BatchedBridge.registerLazyCallableModule('SamplingProfiler', () => + require('SamplingProfiler'), +); BatchedBridge.registerLazyCallableModule('RCTLog', () => require('RCTLog')); -BatchedBridge.registerLazyCallableModule('RCTDeviceEventEmitter', () => require('RCTDeviceEventEmitter')); -BatchedBridge.registerLazyCallableModule('RCTNativeAppEventEmitter', () => require('RCTNativeAppEventEmitter')); -BatchedBridge.registerLazyCallableModule('PerformanceLogger', () => require('PerformanceLogger')); -BatchedBridge.registerLazyCallableModule('JSDevSupportModule', () => require('JSDevSupportModule')); +BatchedBridge.registerLazyCallableModule('RCTDeviceEventEmitter', () => + require('RCTDeviceEventEmitter'), +); +BatchedBridge.registerLazyCallableModule('RCTNativeAppEventEmitter', () => + require('RCTNativeAppEventEmitter'), +); +BatchedBridge.registerLazyCallableModule('PerformanceLogger', () => + require('PerformanceLogger'), +); +BatchedBridge.registerLazyCallableModule('JSDevSupportModule', () => + require('JSDevSupportModule'), +); global.__fetchSegment = function( segmentId: number, @@ -167,19 +180,25 @@ global.__fetchSegment = function( ) { const {SegmentFetcher} = require('NativeModules'); if (!SegmentFetcher) { - throw new Error('SegmentFetcher is missing. Please ensure that it is ' + - 'included as a NativeModule.'); + throw new Error( + 'SegmentFetcher is missing. Please ensure that it is ' + + 'included as a NativeModule.', + ); } - SegmentFetcher.fetchSegment(segmentId, options, (errorObject: ?{message: string, code: string}) => { - if (errorObject) { - const error = new Error(errorObject.message); - (error: any).code = errorObject.code; - callback(error); - } - - callback(null); - }); + SegmentFetcher.fetchSegment( + segmentId, + options, + (errorObject: ?{message: string, code: string}) => { + if (errorObject) { + const error = new Error(errorObject.message); + (error: any).code = errorObject.code; + callback(error); + } + + callback(null); + }, + ); }; // Set up devtools diff --git a/Libraries/Core/ReactNativeVersion.js b/Libraries/Core/ReactNativeVersion.js index 1b2b2155f55175..320b26ac84db6b 100644 --- a/Libraries/Core/ReactNativeVersion.js +++ b/Libraries/Core/ReactNativeVersion.js @@ -1,11 +1,11 @@ /** - * @generated by scripts/bump-oss-version.js - * * Copyright (c) 2015-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * + * @format + * @generated by scripts/bump-oss-version.js * @flow */ diff --git a/Libraries/Core/__mocks__/ErrorUtils.js b/Libraries/Core/__mocks__/ErrorUtils.js index 6b2282672de439..2719c138c4549d 100644 --- a/Libraries/Core/__mocks__/ErrorUtils.js +++ b/Libraries/Core/__mocks__/ErrorUtils.js @@ -3,6 +3,8 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. + * + * @format */ // This mock only provides short-circuited methods of applyWithGuard and guard. diff --git a/Libraries/EventEmitter/MissingNativeEventEmitterShim.js b/Libraries/EventEmitter/MissingNativeEventEmitterShim.js index e9c11b925c8e98..562964b85f4cf4 100644 --- a/Libraries/EventEmitter/MissingNativeEventEmitterShim.js +++ b/Libraries/EventEmitter/MissingNativeEventEmitterShim.js @@ -4,8 +4,10 @@ * 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 EmitterSubscription = require('EmitterSubscription'); @@ -28,9 +30,11 @@ class MissingNativeEventEmitterShim extends EventEmitter { invariant( false, `Cannot use '${this._nativeEventEmitterName}' module when ` + - `native '${this._nativeModuleName}' is not included in the build. ` + - `Either include it, or check '${this._nativeEventEmitterName}'.isAvailable ` + - 'before calling any methods.' + `native '${this._nativeModuleName}' is not included in the build. ` + + `Either include it, or check '${ + this._nativeEventEmitterName + }'.isAvailable ` + + 'before calling any methods.', ); } diff --git a/Libraries/EventEmitter/NativeEventEmitter.js b/Libraries/EventEmitter/NativeEventEmitter.js index 582cf9561f160a..2220670fc76909 100644 --- a/Libraries/EventEmitter/NativeEventEmitter.js +++ b/Libraries/EventEmitter/NativeEventEmitter.js @@ -4,8 +4,10 @@ * 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 EventEmitter = require('EventEmitter'); diff --git a/Libraries/EventEmitter/RCTDeviceEventEmitter.js b/Libraries/EventEmitter/RCTDeviceEventEmitter.js index 9378a5f5310bc4..b0977f219abc25 100644 --- a/Libraries/EventEmitter/RCTDeviceEventEmitter.js +++ b/Libraries/EventEmitter/RCTDeviceEventEmitter.js @@ -4,8 +4,10 @@ * 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 EventEmitter = require('EventEmitter'); @@ -16,13 +18,25 @@ import type EmitterSubscription from 'EmitterSubscription'; function checkNativeEventModule(eventType: ?string) { if (eventType) { if (eventType.lastIndexOf('statusBar', 0) === 0) { - throw new Error('`' + eventType + '` event should be registered via the StatusBarIOS module'); + throw new Error( + '`' + + eventType + + '` event should be registered via the StatusBarIOS module', + ); } if (eventType.lastIndexOf('keyboard', 0) === 0) { - throw new Error('`' + eventType + '` event should be registered via the Keyboard module'); + throw new Error( + '`' + + eventType + + '` event should be registered via the Keyboard module', + ); } if (eventType === 'appStateDidChange' || eventType === 'memoryWarning') { - throw new Error('`' + eventType + '` event should be registered via the AppState module'); + throw new Error( + '`' + + eventType + + '` event should be registered via the AppState module', + ); } } } @@ -32,7 +46,6 @@ function checkNativeEventModule(eventType: ?string) { * adding all event listeners directly to RCTDeviceEventEmitter. */ class RCTDeviceEventEmitter extends EventEmitter { - sharedSubscriber: EventSubscriptionVendor; constructor() { @@ -41,8 +54,11 @@ class RCTDeviceEventEmitter extends EventEmitter { this.sharedSubscriber = sharedSubscriber; } - - addListener(eventType: string, listener: Function, context: ?Object): EmitterSubscription { + addListener( + eventType: string, + listener: Function, + context: ?Object, + ): EmitterSubscription { if (__DEV__) { checkNativeEventModule(eventType); } diff --git a/Libraries/EventEmitter/RCTEventEmitter.js b/Libraries/EventEmitter/RCTEventEmitter.js index 976356b7aa07e1..1a51905ba20d1e 100644 --- a/Libraries/EventEmitter/RCTEventEmitter.js +++ b/Libraries/EventEmitter/RCTEventEmitter.js @@ -4,19 +4,18 @@ * 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 BatchedBridge = require('BatchedBridge'); const RCTEventEmitter = { register(eventEmitter: any) { - BatchedBridge.registerCallableModule( - 'RCTEventEmitter', - eventEmitter - ); - } + BatchedBridge.registerCallableModule('RCTEventEmitter', eventEmitter); + }, }; module.exports = RCTEventEmitter; diff --git a/Libraries/EventEmitter/RCTNativeAppEventEmitter.js b/Libraries/EventEmitter/RCTNativeAppEventEmitter.js index 43245aba558ec2..a32cfcef7cf9c7 100644 --- a/Libraries/EventEmitter/RCTNativeAppEventEmitter.js +++ b/Libraries/EventEmitter/RCTNativeAppEventEmitter.js @@ -4,8 +4,10 @@ * 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 RCTDeviceEventEmitter = require('RCTDeviceEventEmitter'); diff --git a/Libraries/EventEmitter/__mocks__/NativeEventEmitter.js b/Libraries/EventEmitter/__mocks__/NativeEventEmitter.js index d65243424b4a50..e822b72c73c192 100644 --- a/Libraries/EventEmitter/__mocks__/NativeEventEmitter.js +++ b/Libraries/EventEmitter/__mocks__/NativeEventEmitter.js @@ -4,8 +4,10 @@ * 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 EventEmitter = require('EventEmitter'); diff --git a/Libraries/Experimental/Incremental.js b/Libraries/Experimental/Incremental.js index 237e5dbc32e72d..cfd0c69fd03cfe 100644 --- a/Libraries/Experimental/Incremental.js +++ b/Libraries/Experimental/Incremental.js @@ -4,8 +4,10 @@ * 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 InteractionManager = require('InteractionManager'); @@ -79,16 +81,16 @@ const DEBUG = false; * component, saving us from ever doing the remaining rendering work. */ export type Props = { - /** - * Called when all the descendants have finished rendering and mounting - * recursively. - */ - onDone?: () => void, - /** - * Tags instances and associated tasks for easier debugging. - */ - name: string, - children?: any, + /** + * Called when all the descendants have finished rendering and mounting + * recursively. + */ + onDone?: () => void, + /** + * Tags instances and associated tasks for easier debugging. + */ + name: string, + children?: any, }; type DefaultProps = { name: string, @@ -131,30 +133,38 @@ class Incremental extends React.Component { if (!ctx) { return; } - this._incrementId = ++(ctx.incrementalCount); + this._incrementId = ++ctx.incrementalCount; InteractionManager.runAfterInteractions({ name: 'Incremental:' + this.getName(), - gen: () => new Promise(resolve => { - if (!this._mounted || this._rendered) { - resolve(); - return; - } - DEBUG && infoLog('set doIncrementalRender for ' + this.getName()); - this.setState({doIncrementalRender: true}, resolve); - }), - }).then(() => { - DEBUG && infoLog('call onDone for ' + this.getName()); - this._mounted && this.props.onDone && this.props.onDone(); - }).catch((ex) => { - ex.message = `Incremental render failed for ${this.getName()}: ${ex.message}`; - throw ex; - }).done(); + gen: () => + new Promise(resolve => { + if (!this._mounted || this._rendered) { + resolve(); + return; + } + DEBUG && infoLog('set doIncrementalRender for ' + this.getName()); + this.setState({doIncrementalRender: true}, resolve); + }), + }) + .then(() => { + DEBUG && infoLog('call onDone for ' + this.getName()); + this._mounted && this.props.onDone && this.props.onDone(); + }) + .catch(ex => { + ex.message = `Incremental render failed for ${this.getName()}: ${ + ex.message + }`; + throw ex; + }) + .done(); } render(): React.Node { - if (this._rendered || // Make sure that once we render once, we stay rendered even if incrementalGroupEnabled gets flipped. - !this.context.incrementalGroupEnabled || - this.state.doIncrementalRender) { + if ( + this._rendered || // Make sure that once we render once, we stay rendered even if incrementalGroupEnabled gets flipped. + !this.context.incrementalGroupEnabled || + this.state.doIncrementalRender + ) { DEBUG && infoLog('render ' + this.getName()); this._rendered = true; return this.props.children; diff --git a/Libraries/Experimental/IncrementalExample.js b/Libraries/Experimental/IncrementalExample.js index 7f006d38b6a7b4..3cc441fff38591 100644 --- a/Libraries/Experimental/IncrementalExample.js +++ b/Libraries/Experimental/IncrementalExample.js @@ -4,8 +4,10 @@ * 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'); @@ -35,7 +37,10 @@ JSEventLoopWatchdog.install({thresholdMS: 200}); let totalWidgets = 0; -class SlowWidget extends React.Component<$FlowFixMeProps, {ctorTimestamp: number, timeToMount: number}> { +class SlowWidget extends React.Component< + $FlowFixMeProps, + {ctorTimestamp: number, timeToMount: number}, +> { constructor(props, context) { super(props, context); this.state = { @@ -69,7 +74,9 @@ function stopInteraction() { } function Block(props: Object) { - const IncrementalContainer = props.stream ? IncrementalGroup : IncrementalPresenter; + const IncrementalContainer = props.stream + ? IncrementalGroup + : IncrementalPresenter; return ( { } render(): React.Node { return ( - + Press and hold on a row to pause rendering. - {this.state.stats && - Finished: {JSON.stringify(this.state.stats, null, 2)} - } - {Array(8).fill().map((_, blockIdx) => { - return ( - - {Array(4).fill().map((_b, rowIdx) => ( - - {Array(14).fill().map((_c, widgetIdx) => ( - - - + {this.state.stats && ( + Finished: {JSON.stringify(this.state.stats, null, 2)} + )} + {Array(8) + .fill() + .map((_, blockIdx) => { + return ( + + {Array(4) + .fill() + .map((_b, rowIdx) => ( + + {Array(14) + .fill() + .map((_c, widgetIdx) => ( + + + + ))} + ))} - - ))} - - ); - })} + + ); + })} ); @@ -150,7 +162,7 @@ class IncrementalExample extends React.Component { function burnCPU(milliseconds) { const start = performanceNow(); - while (performanceNow() < (start + milliseconds)) {} + while (performanceNow() < start + milliseconds) {} } const styles = StyleSheet.create({ diff --git a/Libraries/Experimental/IncrementalGroup.js b/Libraries/Experimental/IncrementalGroup.js index f630ba66c8c55e..af1a7ad63ddb79 100644 --- a/Libraries/Experimental/IncrementalGroup.js +++ b/Libraries/Experimental/IncrementalGroup.js @@ -4,8 +4,10 @@ * 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 Incremental = require('Incremental'); @@ -36,9 +38,7 @@ class IncrementalGroup extends React.Component { _groupInc: string; UNSAFE_componentWillMount() { this._groupInc = `g${++_groupCounter}-`; - DEBUG && infoLog( - 'create IncrementalGroup with id ' + this.getGroupId() - ); + DEBUG && infoLog('create IncrementalGroup with id ' + this.getGroupId()); } getGroupId(): string { @@ -65,10 +65,7 @@ class IncrementalGroup extends React.Component { render(): React.Node { return ( - + ); } } diff --git a/Libraries/Experimental/IncrementalPresenter.js b/Libraries/Experimental/IncrementalPresenter.js index 05520a3ec4879e..9927179d173966 100644 --- a/Libraries/Experimental/IncrementalPresenter.js +++ b/Libraries/Experimental/IncrementalPresenter.js @@ -4,8 +4,10 @@ * 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 IncrementalGroup = require('IncrementalGroup'); @@ -36,7 +38,7 @@ type Props = { onLayout?: (event: Object) => void, style?: mixed, children?: any, -} +}; class IncrementalPresenter extends React.Component { context: Context; _isDone: boolean; @@ -60,19 +62,23 @@ class IncrementalPresenter extends React.Component { } onDone() { this._isDone = true; - if (this.props.disabled !== true && - this.context.incrementalGroupEnabled !== false) { + if ( + this.props.disabled !== true && + this.context.incrementalGroupEnabled !== false + ) { // Avoid expensive re-renders and use setNativeProps - this.refs.view.setNativeProps( - {style: [this.props.style, {opacity: 1, position: 'relative'}]} - ); + this.refs.view.setNativeProps({ + style: [this.props.style, {opacity: 1, position: 'relative'}], + }); } this.props.onDone && this.props.onDone(); } render() { - if (this.props.disabled !== true && - this.context.incrementalGroupEnabled !== false && - !this._isDone) { + if ( + this.props.disabled !== true && + this.context.incrementalGroupEnabled !== false && + !this._isDone + ) { var style = [this.props.style, {opacity: 0, position: 'absolute'}]; } else { var style = this.props.style; diff --git a/Libraries/Experimental/SwipeableRow/SwipeableListView.js b/Libraries/Experimental/SwipeableRow/SwipeableListView.js index 4187684ddb674e..e449501c71835f 100644 --- a/Libraries/Experimental/SwipeableRow/SwipeableListView.js +++ b/Libraries/Experimental/SwipeableRow/SwipeableListView.js @@ -4,8 +4,10 @@ * 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 ListView = require('ListView'); @@ -22,7 +24,9 @@ type DefaultProps = { type Props = { bounceFirstRowOnMount: boolean, dataSource: SwipeableListViewDataSource, - maxSwipeDistance: number | (rowData: any, sectionID: string, rowID: string) => number, + maxSwipeDistance: + | number + | ((rowData: any, sectionID: string, rowID: string) => number), onScroll?: ?Function, renderRow: Function, renderQuickActions: Function, @@ -78,10 +82,8 @@ class SwipeableListView extends React.Component { */ dataSource: PropTypes.instanceOf(SwipeableListViewDataSource).isRequired, // Maximum distance to open to after a swipe - maxSwipeDistance: PropTypes.oneOfType([ - PropTypes.number, - PropTypes.func, - ]).isRequired, + maxSwipeDistance: PropTypes.oneOfType([PropTypes.number, PropTypes.func]) + .isRequired, // Callback method to render the swipeable view renderRow: PropTypes.func.isRequired, // Callback method to render the view that will be unveiled on swipe @@ -103,7 +105,10 @@ class SwipeableListView extends React.Component { } UNSAFE_componentWillReceiveProps(nextProps: Props): void { - if (this.state.dataSource.getDataSource() !== nextProps.dataSource.getDataSource()) { + if ( + this.state.dataSource.getDataSource() !== + nextProps.dataSource.getDataSource() + ) { this.setState({ dataSource: nextProps.dataSource, }); @@ -114,7 +119,7 @@ class SwipeableListView extends React.Component { return ( { + ref={ref => { this._listViewRef = ref; }} dataSource={this.state.dataSource.getDataSource()} @@ -132,7 +137,7 @@ class SwipeableListView extends React.Component { }); } this.props.onScroll && this.props.onScroll(e); - } + }; /** * This is a work-around to lock vertical `ListView` scrolling on iOS and @@ -141,10 +146,13 @@ class SwipeableListView extends React.Component { * (from high 20s to almost consistently 60 fps) */ _setListViewScrollable(value: boolean): void { - /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an - * error found when Flow v0.68 was deployed. To see the error delete this - * comment and run Flow. */ - if (this._listViewRef && typeof this._listViewRef.setNativeProps === 'function') { + if ( + this._listViewRef && + /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.68 was deployed. To see the error delete this + * comment and run Flow. */ + typeof this._listViewRef.setNativeProps === 'function' + ) { this._listViewRef.setNativeProps({ scrollEnabled: value, }); @@ -153,16 +161,23 @@ class SwipeableListView extends React.Component { // Passing through ListView's getScrollResponder() function getScrollResponder(): ?Object { - /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an - * error found when Flow v0.68 was deployed. To see the error delete this - * comment and run Flow. */ - if (this._listViewRef && typeof this._listViewRef.getScrollResponder === 'function') { + if ( + this._listViewRef && + /* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.68 was deployed. To see the error delete this + * comment and run Flow. */ + typeof this._listViewRef.getScrollResponder === 'function' + ) { return this._listViewRef.getScrollResponder(); } } // This enables rows having variable width slideoutView. - _getMaxSwipeDistance(rowData: Object, sectionID: string, rowID: string): number { + _getMaxSwipeDistance( + rowData: Object, + sectionID: string, + rowID: string, + ): number { if (typeof this.props.maxSwipeDistance === 'function') { return this.props.maxSwipeDistance(rowData, sectionID, rowID); } @@ -170,8 +185,16 @@ class SwipeableListView extends React.Component { return this.props.maxSwipeDistance; } - _renderRow = (rowData: Object, sectionID: string, rowID: string): React.Element => { - const slideoutView = this.props.renderQuickActions(rowData, sectionID, rowID); + _renderRow = ( + rowData: Object, + sectionID: string, + rowID: string, + ): React.Element => { + const slideoutView = this.props.renderQuickActions( + rowData, + sectionID, + rowID, + ); // If renderQuickActions is unspecified or returns falsey, don't allow swipe if (!slideoutView) { diff --git a/Libraries/Experimental/SwipeableRow/SwipeableListViewDataSource.js b/Libraries/Experimental/SwipeableRow/SwipeableListViewDataSource.js index da4377acad8fcb..6c409a9acad1c4 100644 --- a/Libraries/Experimental/SwipeableRow/SwipeableListViewDataSource.js +++ b/Libraries/Experimental/SwipeableRow/SwipeableListViewDataSource.js @@ -4,7 +4,9 @@ * 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 ListViewDataSource = require('ListViewDataSource'); @@ -37,8 +39,10 @@ class SwipeableListViewDataSource { * changed, or its data blob changed. */ return ( - (row1.id !== this._previousOpenRowID && row2.id === this._openRowID) || - (row1.id === this._previousOpenRowID && row2.id !== this._openRowID) || + (row1.id !== this._previousOpenRowID && + row2.id === this._openRowID) || + (row1.id === this._previousOpenRowID && + row2.id !== this._openRowID) || params.rowHasChanged(row1, row2) ); }, @@ -49,12 +53,12 @@ class SwipeableListViewDataSource { cloneWithRowsAndSections( dataBlob: any, sectionIdentities: ?Array, - rowIdentities: ?Array> + rowIdentities: ?Array>, ): SwipeableListViewDataSource { this._dataSource = this._dataSource.cloneWithRowsAndSections( dataBlob, sectionIdentities, - rowIdentities + rowIdentities, ); this._dataBlob = dataBlob; @@ -89,10 +93,10 @@ class SwipeableListViewDataSource { if (this.rowIdentities && this.rowIdentities.length) { const lastSection = this.rowIdentities[this.rowIdentities.length - 1]; if (lastSection && lastSection.length) { - return lastSection[lastSection.length - 1]; - } + return lastSection[lastSection.length - 1]; + } } - return Object.keys(this._dataBlob)[this._dataBlob.length - 1]; + return Object.keys(this._dataBlob)[this._dataBlob.length - 1]; } setOpenRowID(rowID: string): SwipeableListViewDataSource { @@ -102,7 +106,7 @@ class SwipeableListViewDataSource { this._dataSource = this._dataSource.cloneWithRowsAndSections( this._dataBlob, this.sectionIdentities, - this.rowIdentities + this.rowIdentities, ); return this; diff --git a/Libraries/Experimental/SwipeableRow/SwipeableQuickActionButton.js b/Libraries/Experimental/SwipeableRow/SwipeableQuickActionButton.js index 704f315961ceb5..dd002fe259745c 100644 --- a/Libraries/Experimental/SwipeableRow/SwipeableQuickActionButton.js +++ b/Libraries/Experimental/SwipeableRow/SwipeableQuickActionButton.js @@ -4,8 +4,10 @@ * 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 Image = require('Image'); @@ -60,9 +62,7 @@ class SwipeableQuickActionButton extends React.Component<{ source={this.props.imageSource} style={this.props.imageStyle} /> - - {this.props.text} - + {this.props.text} ); diff --git a/Libraries/Experimental/SwipeableRow/SwipeableQuickActions.js b/Libraries/Experimental/SwipeableRow/SwipeableQuickActions.js index 42d2f2cc060b90..3642b135d43191 100644 --- a/Libraries/Experimental/SwipeableRow/SwipeableQuickActions.js +++ b/Libraries/Experimental/SwipeableRow/SwipeableQuickActions.js @@ -4,8 +4,10 @@ * 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'); @@ -40,19 +42,17 @@ class SwipeableQuickActions extends React.Component<{style?: $FlowFixMe}> { buttons.push(children[i]); // $FlowFixMe found when converting React.createClass to ES6 - if (i < this.props.children.length - 1) { // Not last button + if (i < this.props.children.length - 1) { + // Not last button buttons.push(); } } - } else { // 1 child + } else { + // 1 child buttons = children; } - return ( - - {buttons} - - ); + return {buttons}; } } diff --git a/Libraries/Experimental/SwipeableRow/SwipeableRow.js b/Libraries/Experimental/SwipeableRow/SwipeableRow.js index 0c072611aaca44..26361625c5fc8c 100644 --- a/Libraries/Experimental/SwipeableRow/SwipeableRow.js +++ b/Libraries/Experimental/SwipeableRow/SwipeableRow.js @@ -4,8 +4,10 @@ * 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 Animated = require('Animated'); @@ -52,7 +54,7 @@ const RIGHT_SWIPE_BOUNCE_BACK_DURATION = 300; * Max distance of right swipe to allow (right swipes do functionally nothing). * Must be multiplied by SLOW_SPEED_SWIPE_FACTOR because gestureState.dx tracks * how far the finger swipes, and not the actual animation distance. -*/ + */ const RIGHT_SWIPE_THRESHOLD = 30 * SLOW_SPEED_SWIPE_FACTOR; /** @@ -121,7 +123,8 @@ const SwipeableRow = createReactClass({ UNSAFE_componentWillMount(): void { this._panResponder = PanResponder.create({ - onMoveShouldSetPanResponderCapture: this._handleMoveShouldSetPanResponderCapture, + onMoveShouldSetPanResponderCapture: this + ._handleMoveShouldSetPanResponderCapture, onPanResponderGrant: this._handlePanResponderGrant, onPanResponderMove: this._handlePanResponderMove, onPanResponderRelease: this._handlePanResponderEnd, @@ -158,10 +161,8 @@ const SwipeableRow = createReactClass({ let slideOutView; if (this.state.isSwipeableViewRendered && this.state.rowHeight) { slideOutView = ( - + {this.props.slideoutView} ); @@ -177,8 +178,7 @@ const SwipeableRow = createReactClass({ ); return ( - + {slideOutView} {swipeableView} @@ -205,9 +205,7 @@ const SwipeableRow = createReactClass({ return gestureState.dy < 10 && this._isValidSwipe(gestureState); }, - _handlePanResponderGrant(event: Object, gestureState: Object): void { - - }, + _handlePanResponderGrant(event: Object, gestureState: Object): void {}, _handlePanResponderMove(event: Object, gestureState: Object): void { if (this._isSwipingExcessivelyRightFromClosedPosition(gestureState)) { @@ -263,43 +261,42 @@ const SwipeableRow = createReactClass({ duration: number = SWIPE_DURATION, callback: Function = emptyFunction, ): void { - Animated.timing( - this.state.currentLeft, - { - duration, - toValue, - useNativeDriver: true, - }, - ).start(() => { + Animated.timing(this.state.currentLeft, { + duration, + toValue, + useNativeDriver: true, + }).start(() => { this._previousLeft = toValue; callback(); }); }, _animateToOpenPosition(): void { - const maxSwipeDistance = IS_RTL ? -this.props.maxSwipeDistance : this.props.maxSwipeDistance; + const maxSwipeDistance = IS_RTL + ? -this.props.maxSwipeDistance + : this.props.maxSwipeDistance; this._animateTo(-maxSwipeDistance); }, - _animateToOpenPositionWith( - speed: number, - distMoved: number, - ): void { + _animateToOpenPositionWith(speed: number, distMoved: number): void { /** * Ensure the speed is at least the set speed threshold to prevent a slow * swiping animation */ - speed = ( - speed > HORIZONTAL_FULL_SWIPE_SPEED_THRESHOLD ? - speed : - HORIZONTAL_FULL_SWIPE_SPEED_THRESHOLD - ); + speed = + speed > HORIZONTAL_FULL_SWIPE_SPEED_THRESHOLD + ? speed + : HORIZONTAL_FULL_SWIPE_SPEED_THRESHOLD; /** * Calculate the duration the row should take to swipe the remaining distance * at the same speed the user swiped (or the speed threshold) */ - const duration = Math.abs((this.props.maxSwipeDistance - Math.abs(distMoved)) / speed); - const maxSwipeDistance = IS_RTL ? -this.props.maxSwipeDistance : this.props.maxSwipeDistance; + const duration = Math.abs( + (this.props.maxSwipeDistance - Math.abs(distMoved)) / speed, + ); + const maxSwipeDistance = IS_RTL + ? -this.props.maxSwipeDistance + : this.props.maxSwipeDistance; this._animateTo(-maxSwipeDistance, duration); }, @@ -316,9 +313,9 @@ const SwipeableRow = createReactClass({ * When swiping right, we want to bounce back past closed position on release * so users know they should swipe right to get content. */ - const swipeBounceBackDistance = IS_RTL ? - -RIGHT_SWIPE_BOUNCE_BACK_DISTANCE : - RIGHT_SWIPE_BOUNCE_BACK_DISTANCE; + const swipeBounceBackDistance = IS_RTL + ? -RIGHT_SWIPE_BOUNCE_BACK_DISTANCE + : RIGHT_SWIPE_BOUNCE_BACK_DISTANCE; this._animateTo( -swipeBounceBackDistance, duration, @@ -328,7 +325,11 @@ const SwipeableRow = createReactClass({ // Ignore swipes due to user's finger moving slightly when tapping _isValidSwipe(gestureState: Object): boolean { - if (this.props.preventSwipeRight && this._previousLeft === CLOSED_LEFT_POSITION && gestureState.dx > 0) { + if ( + this.props.preventSwipeRight && + this._previousLeft === CLOSED_LEFT_POSITION && + gestureState.dx > 0 + ) { return false; } diff --git a/Libraries/Experimental/WindowedListView.js b/Libraries/Experimental/WindowedListView.js index bf7ef3324b8117..15f1d0b4a8755a 100644 --- a/Libraries/Experimental/WindowedListView.js +++ b/Libraries/Experimental/WindowedListView.js @@ -4,8 +4,10 @@ * 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 Batchinator = require('Batchinator'); @@ -67,7 +69,10 @@ type Props = { * return a row. */ renderRow: ( - rowData: any, sectionIdx: number, rowIdx: number, rowKey: string + rowData: any, + sectionIdx: number, + rowIdx: number, + rowKey: string, ) => ?React.Element, /** * Rendered when the list is scrolled faster than rows can be rendered. @@ -78,9 +83,7 @@ type Props = { /** * Always rendered at the bottom of all the rows. */ - renderFooter?: ( - showFooter: boolean, - ) => ?React.Element, + renderFooter?: (showFooter: boolean) => ?React.Element, /** * Pipes through normal onScroll events from the underlying `ScrollView`. */ @@ -178,7 +181,7 @@ class WindowedListView extends React.Component { * error is because an exported function parameter is missing an * annotation. Without an annotation, these parameters are uncovered by * Flow. */ - renderScrollComponent: (props) => , + renderScrollComponent: props => , disableIncrementalRendering: false, recomputeRowsBatchingPeriod: 10, // This should capture most events that happen within a frame }; @@ -187,7 +190,7 @@ class WindowedListView extends React.Component { super(props); invariant( this.props.numToRenderAhead < this.props.maxNumToRender, - 'WindowedListView: numToRenderAhead must be less than maxNumToRender' + 'WindowedListView: numToRenderAhead must be less than maxNumToRender', ); this._computeRowsToRenderBatcher = new Batchinator( () => this._computeRowsToRender(this.props), @@ -198,13 +201,16 @@ class WindowedListView extends React.Component { }); this.state = { firstRow: 0, - lastRow: Math.min(this.props.data.length, this.props.initialNumToRender) - 1, + lastRow: + Math.min(this.props.data.length, this.props.initialNumToRender) - 1, }; } getScrollResponder(): ?ScrollView { - return this._scrollRef && + return ( + this._scrollRef && this._scrollRef.getScrollResponder && - this._scrollRef.getScrollResponder(); + this._scrollRef.getScrollResponder() + ); } shouldComponentUpdate(newProps: Props, newState: State): boolean { DEBUG && infoLog('WLV: shouldComponentUpdate...'); @@ -218,22 +224,33 @@ class WindowedListView extends React.Component { return true; } } - const newDataSubset = newProps.data.slice(newState.firstRow, newState.lastRow + 1); - const prevDataSubset = this.props.data.slice(this.state.firstRow, this.state.lastRow + 1); + const newDataSubset = newProps.data.slice( + newState.firstRow, + newState.lastRow + 1, + ); + const prevDataSubset = this.props.data.slice( + this.state.firstRow, + this.state.lastRow + 1, + ); if (newDataSubset.length !== prevDataSubset.length) { - DEBUG && infoLog( - ' yes, subset length: ', - {newLen: newDataSubset.length, oldLen: prevDataSubset.length} - ); + DEBUG && + infoLog(' yes, subset length: ', { + newLen: newDataSubset.length, + oldLen: prevDataSubset.length, + }); return true; } for (let idx = 0; idx < newDataSubset.length; idx++) { - if (newDataSubset[idx].rowData !== prevDataSubset[idx].rowData || - newDataSubset[idx].rowKey !== prevDataSubset[idx].rowKey) { - DEBUG && infoLog( - ' yes, data change: ', - {idx, new: newDataSubset[idx], old: prevDataSubset[idx]} - ); + if ( + newDataSubset[idx].rowData !== prevDataSubset[idx].rowData || + newDataSubset[idx].rowKey !== prevDataSubset[idx].rowKey + ) { + DEBUG && + infoLog(' yes, data change: ', { + idx, + new: newDataSubset[idx], + old: prevDataSubset[idx], + }); return true; } } @@ -249,7 +266,7 @@ class WindowedListView extends React.Component { _getFrameMetrics = (index: number): ?{length: number, offset: number} => { const frame = this._rowFrames[this.props.data[index].rowKey]; return frame && {length: frame.height, offset: frame.y}; - } + }; _onScroll = (e: Object) => { const newScrollY = e.nativeEvent.contentOffset.y; this._isScrolling = this._scrollOffsetY !== newScrollY; @@ -260,7 +277,10 @@ class WindowedListView extends React.Component { if (this._cellsInProgress.size === 0) { this._computeRowsToRenderBatcher.schedule(); } - if (this.props.onViewableRowsChanged && Object.keys(this._rowFrames).length) { + if ( + this.props.onViewableRowsChanged && + Object.keys(this._rowFrames).length + ) { const viewableRows = this._viewabilityHelper.computeViewableItems( this.props.data.length, e.nativeEvent.contentOffset.y, @@ -279,19 +299,26 @@ class WindowedListView extends React.Component { const {rowKey, layout} = params; if (DEBUG) { const prev = this._rowFrames[rowKey] || {}; - infoLog( - 'record layout for row: ', - {k: rowKey, h: layout.height, y: layout.y, x: layout.x, hp: prev.height, yp: prev.y} - ); + infoLog('record layout for row: ', { + k: rowKey, + h: layout.height, + y: layout.y, + x: layout.x, + hp: prev.height, + yp: prev.y, + }); if (this._rowFrames[rowKey]) { const deltaY = Math.abs(this._rowFrames[rowKey].y - layout.y); const deltaH = Math.abs(this._rowFrames[rowKey].height - layout.height); if (deltaY > 2 || deltaH > 2) { - const dataEntry = this.props.data.find((datum) => datum.rowKey === rowKey); - console.warn( - 'layout jump: ', - {dataEntry, prevLayout: this._rowFrames[rowKey], newLayout: layout} + const dataEntry = this.props.data.find( + datum => datum.rowKey === rowKey, ); + console.warn('layout jump: ', { + dataEntry, + prevLayout: this._rowFrames[rowKey], + newLayout: layout, + }); } } } @@ -311,7 +338,13 @@ class WindowedListView extends React.Component { * This is used to keep track of cells that are in the process of rendering. If any cells are in * progress, then other updates are skipped because they will just be wasted work. */ - _onProgressChange = ({rowKey, inProgress}: {rowKey: string, inProgress: boolean}) => { + _onProgressChange = ({ + rowKey, + inProgress, + }: { + rowKey: string, + inProgress: boolean, + }) => { if (inProgress) { this._cellsInProgress.add(rowKey); } else { @@ -343,7 +376,7 @@ class WindowedListView extends React.Component { // No frame - sometimes happens when they come out of order, so just wait for the rest. return; } - if (((frame.y + frame.height) > top) && (firstVisible < 0)) { + if (frame.y + frame.height > top && firstVisible < 0) { firstVisible = idx; } if (frame.y < bottom) { @@ -390,7 +423,7 @@ class WindowedListView extends React.Component { if (props.onEndReached) { // Make sure we call onEndReached exactly once every time we reach the // end. Resets if scroll back up and down again. - const willBeAtTheEnd = lastRow === (totalRows - 1); + const willBeAtTheEnd = lastRow === totalRows - 1; if (willBeAtTheEnd && !this._hasCalledOnEndReached) { props.onEndReached(); this._hasCalledOnEndReached = true; @@ -399,15 +432,18 @@ class WindowedListView extends React.Component { this._hasCalledOnEndReached = this.state.lastRow === lastRow; } } - const rowsShouldChange = firstRow !== this.state.firstRow || lastRow !== this.state.lastRow; + const rowsShouldChange = + firstRow !== this.state.firstRow || lastRow !== this.state.lastRow; if (this._rowFramesDirty || rowsShouldChange) { if (rowsShouldChange) { props.onMountedRowsWillChange && props.onMountedRowsWillChange(firstRow, lastRow - firstRow + 1); - infoLog( - 'WLV: row render range will change:', - {firstRow, firstVis: this._firstVisible, lastVis: this._lastVisible, lastRow}, - ); + infoLog('WLV: row render range will change:', { + firstRow, + firstVis: this._firstVisible, + lastVis: this._lastVisible, + lastRow, + }); } this._rowFramesDirty = false; this.setState({firstRow, lastRow}); @@ -415,9 +451,14 @@ class WindowedListView extends React.Component { } _updateVisibleRows(newFirstVisible: number, newLastVisible: number) { if (this.props.onVisibleRowsChanged) { - if (this._firstVisible !== newFirstVisible || - this._lastVisible !== newLastVisible) { - this.props.onVisibleRowsChanged(newFirstVisible, newLastVisible - newFirstVisible + 1); + if ( + this._firstVisible !== newFirstVisible || + this._lastVisible !== newLastVisible + ) { + this.props.onVisibleRowsChanged( + newFirstVisible, + newLastVisible - newFirstVisible + 1, + ); } } this._firstVisible = newFirstVisible; @@ -435,14 +476,17 @@ class WindowedListView extends React.Component { // catch up as fast as possible. In the middle, we only disable incremental while scrolling // since it's unlikely the user will try to press a button while scrolling. We also ignore the // "buffer" size when we are bumped up against the edge of the available data. - const firstBuffer = firstRow === 0 ? Infinity : this._firstVisible - firstRow; - const lastBuffer = lastRow === this.props.data.length - 1 - ? Infinity - : lastRow - this._lastVisible; + const firstBuffer = + firstRow === 0 ? Infinity : this._firstVisible - firstRow; + const lastBuffer = + lastRow === this.props.data.length - 1 + ? Infinity + : lastRow - this._lastVisible; const minBuffer = Math.min(firstBuffer, lastBuffer); - const disableIncrementalRendering = this.props.disableIncrementalRendering || + const disableIncrementalRendering = + this.props.disableIncrementalRendering || (this._isScrolling && minBuffer < this.props.numToRenderAhead * 0.5) || - (minBuffer < this.props.numToRenderAhead * 0.25); + minBuffer < this.props.numToRenderAhead * 0.25; // Render mode is sticky while the component is mounted. for (let ii = firstRow; ii <= lastRow; ii++) { const rowKey = this.props.data[ii].rowKey; @@ -463,7 +507,10 @@ class WindowedListView extends React.Component { // Look for the first row where offscreen layout is done (only true for mounted rows) or it // will be rendered synchronously and set the spacer height such that it will offset all the // unmounted rows before that one using the saved frame data. - if (rowFrames[rowKey].offscreenLayoutDone || this._rowRenderMode[rowKey] === 'sync') { + if ( + rowFrames[rowKey].offscreenLayoutDone || + this._rowRenderMode[rowKey] === 'sync' + ) { if (ii > 0) { const prevRowKey = this.props.data[ii - 1].rowKey; const frame = rowFrames[prevRowKey]; @@ -490,20 +537,22 @@ class WindowedListView extends React.Component { { + onLayout={e => { const layout = e.nativeEvent.layout; if (layout.height !== this.state.boundaryIndicatorHeight) { this.setState({boundaryIndicatorHeight: layout.height}); } }}> {this.props.renderWindowBoundaryIndicator(showIndicator)} - + , ); } for (let idx = firstRow; idx <= lastRow; idx++) { const rowKey = this.props.data[idx].rowKey; - const includeInLayout = this._rowRenderMode[rowKey] === 'sync' || - (this._rowFrames[rowKey] && this._rowFrames[rowKey].offscreenLayoutDone); + const includeInLayout = + this._rowRenderMode[rowKey] === 'sync' || + (this._rowFrames[rowKey] && + this._rowFrames[rowKey].offscreenLayoutDone); rows.push( { asyncRowPerfEventName={this.props.asyncRowPerfEventName} rowData={this.props.data[idx].rowData} renderRow={this.props.renderRow} - /> + />, ); } const lastRowKey = this.props.data[lastRow].rowKey; - const showFooter = this._rowFrames[lastRowKey] && - this._rowFrames[lastRowKey].offscreenLayoutDone && - lastRow === this.props.data.length - 1; + const showFooter = + this._rowFrames[lastRowKey] && + this._rowFrames[lastRowKey].offscreenLayoutDone && + lastRow === this.props.data.length - 1; if (this.props.renderFooter) { rows.push( {this.props.renderFooter(showFooter)} - + , ); } if (this.props.renderWindowBoundaryIndicator) { @@ -537,30 +587,30 @@ class WindowedListView extends React.Component { { + onLayout={e => { const layout = e.nativeEvent.layout; if (layout.height !== this.state.boundaryIndicatorHeight) { this.setState({boundaryIndicatorHeight: layout.height}); } }}> {this.props.renderWindowBoundaryIndicator(!showFooter)} - + , ); } // Prevent user from scrolling into empty space of unmounted rows. const contentInset = {top: firstRow === 0 ? 0 : -spacerHeight}; - return ( - this.props.renderScrollComponent({ - scrollEventThrottle: 50, - removeClippedSubviews: true, - ...this.props, - contentInset, - ref: (ref) => { this._scrollRef = ref; }, - onScroll: this._onScroll, - onMomentumScrollEnd: this._onMomentumScrollEnd, - children: rows, - }) - ); + return this.props.renderScrollComponent({ + scrollEventThrottle: 50, + removeClippedSubviews: true, + ...this.props, + contentInset, + ref: ref => { + this._scrollRef = ref; + }, + onScroll: this._onScroll, + onMomentumScrollEnd: this._onMomentumScrollEnd, + children: rows, + }); } } @@ -576,9 +626,12 @@ type CellProps = { /** * Renders the actual row contents. */ - renderRow: ( - rowData: mixed, sectionIdx: number, rowIdx: number, rowKey: string - ) => ?React.Element, + renderRow: ( + rowData: mixed, + sectionIdx: number, + rowIdx: number, + rowKey: string, + ) => ?React.Element, /** * Index of the row, passed through to other callbacks. */ @@ -625,18 +678,21 @@ class CellRenderer extends React.Component { if (this.props.asyncRowPerfEventName) { this._perfUpdateID = g_perf_update_id++; this._asyncCookie = Systrace.beginAsyncEvent( - this.props.asyncRowPerfEventName + this._perfUpdateID + this.props.asyncRowPerfEventName + this._perfUpdateID, + ); + infoLog( + // $FlowFixMe(>=0.28.0) + `perf_asynctest_${this.props.asyncRowPerfEventName}_start ${ + this._perfUpdateID + } ` + `${Date.now()}`, ); - // $FlowFixMe(>=0.28.0) - infoLog(`perf_asynctest_${this.props.asyncRowPerfEventName}_start ${this._perfUpdateID} ` + - `${Date.now()}`); } if (this.props.includeInLayout) { this._includeInLayoutLatch = true; } this.props.onProgressChange({rowKey: this.props.rowKey, inProgress: true}); } - _onLayout = (e) => { + _onLayout = e => { const layout = e.nativeEvent.layout; const layoutChanged = deepDiffer(this._lastLayout, layout); this._lastLayout = layout; @@ -660,19 +716,26 @@ class CellRenderer extends React.Component { // This happens when Incremental is disabled and _onOffscreenRenderDone is called faster than // layout can happen. this._lastLayout && - this.props.onNewLayout({rowKey: this.props.rowKey, layout: this._lastLayout}); + this.props.onNewLayout({ + rowKey: this.props.rowKey, + layout: this._lastLayout, + }); - DEBUG && infoLog('\n >>>>> display row ' + this.props.rowIndex + '\n\n\n'); + DEBUG && + infoLog('\n >>>>> display row ' + this.props.rowIndex + '\n\n\n'); if (this.props.asyncRowPerfEventName) { // Note this doesn't include the native render time but is more accurate than also including // the JS render time of anything that has been queued up. Systrace.endAsyncEvent( this.props.asyncRowPerfEventName + this._perfUpdateID, - this._asyncCookie + this._asyncCookie, + ); + infoLog( + // $FlowFixMe(>=0.28.0) + `perf_asynctest_${this.props.asyncRowPerfEventName}_end ${ + this._perfUpdateID + } ` + `${Date.now()}`, ); - // $FlowFixMe(>=0.28.0) - infoLog(`perf_asynctest_${this.props.asyncRowPerfEventName}_end ${this._perfUpdateID} ` + - `${Date.now()}`); } } _onOffscreenRenderDone = () => { @@ -693,7 +756,10 @@ class CellRenderer extends React.Component { } UNSAFE_componentWillReceiveProps(newProps) { if (newProps.includeInLayout && !this.props.includeInLayout) { - invariant(this._offscreenRenderDone, 'Should never try to add to layout before render done'); + invariant( + this._offscreenRenderDone, + 'Should never try to add to layout before render done', + ); this._includeInLayoutLatch = true; // Once we render in layout, make sure it sticks. this._containerRef.setNativeProps({style: styles.include}); } @@ -701,7 +767,7 @@ class CellRenderer extends React.Component { shouldComponentUpdate(newProps: CellProps) { return newProps.rowData !== this.props.rowData; } - _setRef = (ref) => { + _setRef = ref => { /* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This comment * suppresses an error when upgrading Flow's support for React. To see the * error delete this comment and run Flow. */ @@ -712,9 +778,11 @@ class CellRenderer extends React.Component { if (DEBUG) { infoLog('render cell ' + this.props.rowIndex); const Text = require('Text'); - debug = - Row: {this.props.rowIndex} - ; + debug = ( + + Row: {this.props.rowIndex} + + ); } const style = this._includeInLayoutLatch ? styles.include : styles.remove; return ( @@ -722,12 +790,14 @@ class CellRenderer extends React.Component { disabled={this._includeInLayoutLatch} onDone={this._onOffscreenRenderDone} name={`WLVCell_${this.props.rowIndex}`}> - + {debug} - {this.props.renderRow(this.props.rowData, 0, this.props.rowIndex, this.props.rowKey)} + {this.props.renderRow( + this.props.rowData, + 0, + this.props.rowIndex, + this.props.rowKey, + )} {debug} diff --git a/Libraries/Geolocation/Geolocation.js b/Libraries/Geolocation/Geolocation.js index 8bdc212636beff..d252da95bca58f 100644 --- a/Libraries/Geolocation/Geolocation.js +++ b/Libraries/Geolocation/Geolocation.js @@ -4,8 +4,10 @@ * 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 NativeEventEmitter = require('NativeEventEmitter'); @@ -27,16 +29,16 @@ let subscriptions = []; let updatesEnabled = false; type GeoConfiguration = { - skipPermissionRequests: bool; -} + skipPermissionRequests: boolean, +}; type GeoOptions = { timeout?: number, maximumAge?: number, - enableHighAccuracy?: bool, + enableHighAccuracy?: boolean, distanceFilter: number, - useSignificantChanges?: bool, -} + useSignificantChanges?: boolean, +}; /** * The Geolocation API extends the web spec: @@ -45,16 +47,13 @@ type GeoOptions = { * See https://facebook.github.io/react-native/docs/geolocation.html */ const Geolocation = { - /* * Sets configuration options that will be used in all location requests. * * See https://facebook.github.io/react-native/docs/geolocation.html#setrnconfiguration * */ - setRNConfiguration: function( - config: GeoConfiguration - ) { + setRNConfiguration: function(config: GeoConfiguration) { if (RCTLocationObserver.setConfiguration) { RCTLocationObserver.setConfiguration(config); } @@ -77,11 +76,11 @@ const Geolocation = { getCurrentPosition: async function( geo_success: Function, geo_error?: Function, - geo_options?: GeoOptions + geo_options?: GeoOptions, ) { invariant( typeof geo_success === 'function', - 'Must provide a valid geo_success callback.' + 'Must provide a valid geo_success callback.', ); let hasPermission = true; // Supports Android's new permission model. For Android older devices, @@ -111,21 +110,21 @@ const Geolocation = { * * See https://facebook.github.io/react-native/docs/geolocation.html#watchposition */ - watchPosition: function(success: Function, error?: Function, options?: GeoOptions): number { + watchPosition: function( + success: Function, + error?: Function, + options?: GeoOptions, + ): number { if (!updatesEnabled) { RCTLocationObserver.startObserving(options || {}); updatesEnabled = true; } const watchID = subscriptions.length; subscriptions.push([ - LocationEventEmitter.addListener( - 'geolocationDidChange', - success - ), - error ? LocationEventEmitter.addListener( - 'geolocationError', - error - ) : null, + LocationEventEmitter.addListener('geolocationDidChange', success), + error + ? LocationEventEmitter.addListener('geolocationError', error) + : null, ]); return watchID; }, @@ -140,7 +139,8 @@ const Geolocation = { sub[0].remove(); // array element refinements not yet enabled in Flow - const sub1 = sub[1]; sub1 && sub1.remove(); + const sub1 = sub[1]; + sub1 && sub1.remove(); subscriptions[watchID] = undefined; let noWatchers = true; for (let ii = 0; ii < subscriptions.length; ii++) { @@ -163,12 +163,13 @@ const Geolocation = { warning(false, 'Called stopObserving with existing subscriptions.'); sub[0].remove(); // array element refinements not yet enabled in Flow - const sub1 = sub[1]; sub1 && sub1.remove(); + const sub1 = sub[1]; + sub1 && sub1.remove(); } } subscriptions = []; } - } + }, }; module.exports = Geolocation; diff --git a/Libraries/Image/AssetSourceResolver.js b/Libraries/Image/AssetSourceResolver.js index 6ae1a7801d09c5..a870a325242838 100644 --- a/Libraries/Image/AssetSourceResolver.js +++ b/Libraries/Image/AssetSourceResolver.js @@ -40,7 +40,10 @@ function getScaledAssetPath(asset): string { */ function getAssetPathInDrawableFolder(asset): string { const scale = AssetSourceResolver.pickScale(asset.scales, PixelRatio.get()); - const drawbleFolder = assetPathUtils.getAndroidResourceFolderName(asset, scale); + const drawbleFolder = assetPathUtils.getAndroidResourceFolderName( + asset, + scale, + ); const fileName = assetPathUtils.getAndroidResourceIdentifier(asset); return drawbleFolder + '/' + fileName + '.' + asset.type; } diff --git a/Libraries/Image/RelativeImageStub.js b/Libraries/Image/RelativeImageStub.js index 1a74c36cb1bd98..ab845a274d277a 100644 --- a/Libraries/Image/RelativeImageStub.js +++ b/Libraries/Image/RelativeImageStub.js @@ -4,8 +4,10 @@ * 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'; // This is a stub for flow to make it understand require('./icon.png') diff --git a/Libraries/Image/__tests__/assetRelativePathInSnapshot.js b/Libraries/Image/__tests__/assetRelativePathInSnapshot.js index 262e636b4710ff..973d7171c0cd56 100644 --- a/Libraries/Image/__tests__/assetRelativePathInSnapshot.js +++ b/Libraries/Image/__tests__/assetRelativePathInSnapshot.js @@ -4,8 +4,10 @@ * 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'; jest.disableAutomock(); @@ -16,10 +18,12 @@ const Image = require('Image'); const View = require('View'); it('renders assets based on relative path', () => { - expect(ReactTestRenderer.create( - - - - - )).toMatchSnapshot(); + expect( + ReactTestRenderer.create( + + + + , + ), + ).toMatchSnapshot(); }); diff --git a/Libraries/Image/__tests__/resolveAssetSource-test.js b/Libraries/Image/__tests__/resolveAssetSource-test.js index db1a0a853d9937..c22f32a6520413 100644 --- a/Libraries/Image/__tests__/resolveAssetSource-test.js +++ b/Libraries/Image/__tests__/resolveAssetSource-test.js @@ -4,8 +4,10 @@ * 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 AssetRegistry = require('AssetRegistry'); @@ -32,12 +34,14 @@ describe('resolveAssetSource', () => { }); it('does not change deprecated assets', () => { - expect(resolveAssetSource({ - deprecated: true, - width: 100, - height: 200, - uri: 'logo', - })).toEqual({ + expect( + resolveAssetSource({ + deprecated: true, + width: 100, + height: 200, + uri: 'logo', + }), + ).toEqual({ deprecated: true, width: 100, height: 200, @@ -53,51 +57,57 @@ describe('resolveAssetSource', () => { describe('bundle was loaded from network (DEV)', () => { beforeEach(() => { - NativeModules.SourceCode.scriptURL = - 'http://10.0.0.1:8081/main.bundle'; + NativeModules.SourceCode.scriptURL = 'http://10.0.0.1:8081/main.bundle'; Platform.OS = 'ios'; }); it('uses network image', () => { - expectResolvesAsset({ - __packager_asset: true, - fileSystemLocation: '/root/app/module/a', - httpServerLocation: '/assets/module/a', - width: 100, - height: 200, - scales: [1], - hash: '5b6f00f', - name: 'logo', - type: 'png', - }, { - __packager_asset: true, - width: 100, - height: 200, - uri: 'http://10.0.0.1:8081/assets/module/a/logo.png?platform=ios&hash=5b6f00f', - scale: 1, - }); + expectResolvesAsset( + { + __packager_asset: true, + fileSystemLocation: '/root/app/module/a', + httpServerLocation: '/assets/module/a', + width: 100, + height: 200, + scales: [1], + hash: '5b6f00f', + name: 'logo', + type: 'png', + }, + { + __packager_asset: true, + width: 100, + height: 200, + uri: + 'http://10.0.0.1:8081/assets/module/a/logo.png?platform=ios&hash=5b6f00f', + scale: 1, + }, + ); }); it('picks matching scale', () => { - expectResolvesAsset({ - __packager_asset: true, - fileSystemLocation: '/root/app/module/a', - httpServerLocation: '/assets/module/a', - width: 100, - height: 200, - scales: [1, 2, 3], - hash: '5b6f00f', - name: 'logo', - type: 'png', - }, { - __packager_asset: true, - width: 100, - height: 200, - uri: 'http://10.0.0.1:8081/assets/module/a/logo@2x.png?platform=ios&hash=5b6f00f', - scale: 2, - }); + expectResolvesAsset( + { + __packager_asset: true, + fileSystemLocation: '/root/app/module/a', + httpServerLocation: '/assets/module/a', + width: 100, + height: 200, + scales: [1, 2, 3], + hash: '5b6f00f', + name: 'logo', + type: 'png', + }, + { + __packager_asset: true, + width: 100, + height: 200, + uri: + 'http://10.0.0.1:8081/assets/module/a/logo@2x.png?platform=ios&hash=5b6f00f', + scale: 2, + }, + ); }); - }); describe('bundle was loaded from file on iOS', () => { @@ -108,23 +118,26 @@ describe('resolveAssetSource', () => { }); it('uses pre-packed image', () => { - expectResolvesAsset({ - __packager_asset: true, - fileSystemLocation: '/root/app/module/a', - httpServerLocation: '/assets/module/a', - width: 100, - height: 200, - scales: [1], - hash: '5b6f00f', - name: 'logo', - type: 'png', - }, { - __packager_asset: true, - width: 100, - height: 200, - uri: 'file:///Path/To/Sample.app/assets/module/a/logo.png', - scale: 1, - }); + expectResolvesAsset( + { + __packager_asset: true, + fileSystemLocation: '/root/app/module/a', + httpServerLocation: '/assets/module/a', + width: 100, + height: 200, + scales: [1], + hash: '5b6f00f', + name: 'logo', + type: 'png', + }, + { + __packager_asset: true, + width: 100, + height: 200, + uri: 'file:///Path/To/Sample.app/assets/module/a/logo.png', + scale: 1, + }, + ); }); }); @@ -136,23 +149,26 @@ describe('resolveAssetSource', () => { }); it('uses pre-packed image', () => { - expectResolvesAsset({ - __packager_asset: true, - fileSystemLocation: '/root/app/module/a', - httpServerLocation: '/assets/AwesomeModule/Subdir', - width: 100, - height: 200, - scales: [1], - hash: '5b6f00f', - name: '!@Logo#1_\u20ac', // Invalid chars shouldn't get passed to native - type: 'png', - }, { - __packager_asset: true, - width: 100, - height: 200, - uri: 'awesomemodule_subdir_logo1_', - scale: 1, - }); + expectResolvesAsset( + { + __packager_asset: true, + fileSystemLocation: '/root/app/module/a', + httpServerLocation: '/assets/AwesomeModule/Subdir', + width: 100, + height: 200, + scales: [1], + hash: '5b6f00f', + name: '!@Logo#1_\u20ac', // Invalid chars shouldn't get passed to native + type: 'png', + }, + { + __packager_asset: true, + width: 100, + height: 200, + uri: 'awesomemodule_subdir_logo1_', + scale: 1, + }, + ); }); }); @@ -164,23 +180,27 @@ describe('resolveAssetSource', () => { }); it('uses pre-packed image', () => { - expectResolvesAsset({ - __packager_asset: true, - fileSystemLocation: '/root/app/module/a', - httpServerLocation: '/assets/AwesomeModule/Subdir', - width: 100, - height: 200, - scales: [1], - hash: '5b6f00f', - name: '!@Logo#1_\u20ac', - type: 'png', - }, { - __packager_asset: true, - width: 100, - height: 200, - uri: 'file:///sdcard/Path/To/Simulator/drawable-mdpi/awesomemodule_subdir_logo1_.png', - scale: 1, - }); + expectResolvesAsset( + { + __packager_asset: true, + fileSystemLocation: '/root/app/module/a', + httpServerLocation: '/assets/AwesomeModule/Subdir', + width: 100, + height: 200, + scales: [1], + hash: '5b6f00f', + name: '!@Logo#1_\u20ac', + type: 'png', + }, + { + __packager_asset: true, + width: 100, + height: 200, + uri: + 'file:///sdcard/Path/To/Simulator/drawable-mdpi/awesomemodule_subdir_logo1_.png', + scale: 1, + }, + ); }); }); @@ -192,23 +212,27 @@ describe('resolveAssetSource', () => { }); it('uses sideloaded image', () => { - expectResolvesAsset({ - __packager_asset: true, - fileSystemLocation: '/root/app/module/a', - httpServerLocation: '/assets/AwesomeModule/Subdir', - width: 100, - height: 200, - scales: [1], - hash: '5b6f00f', - name: '!@Logo#1_\u20ac', - type: 'png', - }, { - __packager_asset: true, - width: 100, - height: 200, - uri: 'file:///sdcard/Path/To/Simulator/drawable-mdpi/awesomemodule_subdir_logo1_.png', - scale: 1, - }); + expectResolvesAsset( + { + __packager_asset: true, + fileSystemLocation: '/root/app/module/a', + httpServerLocation: '/assets/AwesomeModule/Subdir', + width: 100, + height: 200, + scales: [1], + hash: '5b6f00f', + name: '!@Logo#1_\u20ac', + type: 'png', + }, + { + __packager_asset: true, + width: 100, + height: 200, + uri: + 'file:///sdcard/Path/To/Simulator/drawable-mdpi/awesomemodule_subdir_logo1_.png', + scale: 1, + }, + ); }); }); @@ -220,52 +244,57 @@ describe('resolveAssetSource', () => { }); it('uses bundled source, event when js is sideloaded', () => { - resolveAssetSource.setCustomSourceTransformer( - (resolver) => resolver.resourceIdentifierWithoutScale(), + resolveAssetSource.setCustomSourceTransformer(resolver => + resolver.resourceIdentifierWithoutScale(), + ); + expectResolvesAsset( + { + __packager_asset: true, + fileSystemLocation: '/root/app/module/a', + httpServerLocation: '/assets/AwesomeModule/Subdir', + width: 100, + height: 200, + scales: [1], + hash: '5b6f00f', + name: '!@Logo#1_\u20ac', + type: 'png', + }, + { + __packager_asset: true, + width: 100, + height: 200, + uri: 'awesomemodule_subdir_logo1_', + scale: 1, + }, ); - expectResolvesAsset({ - __packager_asset: true, - fileSystemLocation: '/root/app/module/a', - httpServerLocation: '/assets/AwesomeModule/Subdir', - width: 100, - height: 200, - scales: [1], - hash: '5b6f00f', - name: '!@Logo#1_\u20ac', - type: 'png', - }, { - __packager_asset: true, - width: 100, - height: 200, - uri: 'awesomemodule_subdir_logo1_', - scale: 1, - }); }); it('allows any customization', () => { - resolveAssetSource.setCustomSourceTransformer( - (resolver) => resolver.fromSource('TEST') + resolveAssetSource.setCustomSourceTransformer(resolver => + resolver.fromSource('TEST'), + ); + expectResolvesAsset( + { + __packager_asset: true, + fileSystemLocation: '/root/app/module/a', + httpServerLocation: '/assets/AwesomeModule/Subdir', + width: 100, + height: 200, + scales: [1], + hash: '5b6f00f', + name: '!@Logo#1_\u20ac', + type: 'png', + }, + { + __packager_asset: true, + width: 100, + height: 200, + uri: 'TEST', + scale: 1, + }, ); - expectResolvesAsset({ - __packager_asset: true, - fileSystemLocation: '/root/app/module/a', - httpServerLocation: '/assets/AwesomeModule/Subdir', - width: 100, - height: 200, - scales: [1], - hash: '5b6f00f', - name: '!@Logo#1_\u20ac', - type: 'png', - }, { - __packager_asset: true, - width: 100, - height: 200, - uri: 'TEST', - scale: 1, - }); }); }); - }); describe('resolveAssetSource.pickScale', () => { diff --git a/Libraries/Image/resolveAssetSource.js b/Libraries/Image/resolveAssetSource.js index fe483beff59427..9c811e574400b1 100644 --- a/Libraries/Image/resolveAssetSource.js +++ b/Libraries/Image/resolveAssetSource.js @@ -4,16 +4,19 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @flow * * Resolves an asset into a `source` for `Image`. + * + * @format + * @flow */ + 'use strict'; const AssetRegistry = require('AssetRegistry'); const AssetSourceResolver = require('AssetSourceResolver'); -import type { ResolvedAssetSource } from 'AssetSourceResolver'; +import type {ResolvedAssetSource} from 'AssetSourceResolver'; let _customSourceTransformer, _serverURL, _scriptURL; @@ -23,7 +26,8 @@ function getSourceCodeScriptURL(): ?string { return _sourceCodeScriptURL; } - let sourceCode = global.nativeExtensions && global.nativeExtensions.SourceCode; + let sourceCode = + global.nativeExtensions && global.nativeExtensions.SourceCode; if (!sourceCode) { const NativeModules = require('NativeModules'); sourceCode = NativeModules && NativeModules.SourceCode; @@ -35,7 +39,8 @@ function getSourceCodeScriptURL(): ?string { function getDevServerURL(): ?string { if (_serverURL === undefined) { const sourceCodeScriptURL = getSourceCodeScriptURL(); - const match = sourceCodeScriptURL && sourceCodeScriptURL.match(/^https?:\/\/.*?\//); + const match = + sourceCodeScriptURL && sourceCodeScriptURL.match(/^https?:\/\/.*?\//); if (match) { // jsBundle was loaded from network _serverURL = match[0]; diff --git a/Libraries/Inspector/BorderBox.js b/Libraries/Inspector/BorderBox.js index 21ace69d9c90fa..b172871df8e2f2 100644 --- a/Libraries/Inspector/BorderBox.js +++ b/Libraries/Inspector/BorderBox.js @@ -4,8 +4,10 @@ * 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'); @@ -23,13 +25,8 @@ class BorderBox extends React.Component<$FlowFixMeProps> { borderLeftWidth: box.left, borderRightWidth: box.right, }; - return ( - - {this.props.children} - - ); + return {this.props.children}; } } module.exports = BorderBox; - diff --git a/Libraries/Inspector/BoxInspector.js b/Libraries/Inspector/BoxInspector.js index 11fe9c8c980787..af373460053609 100644 --- a/Libraries/Inspector/BoxInspector.js +++ b/Libraries/Inspector/BoxInspector.js @@ -4,8 +4,10 @@ * 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'); @@ -25,8 +27,8 @@ class BoxInspector extends React.Component<$FlowFixMeProps> { render() { const frame = this.props.frame; const style = this.props.style; - const margin = style && resolveBoxStyle('margin', style) || blank; - const padding = style && resolveBoxStyle('padding', style) || blank; + const margin = (style && resolveBoxStyle('margin', style)) || blank; + const padding = (style && resolveBoxStyle('padding', style)) || blank; return ( @@ -35,7 +37,8 @@ class BoxInspector extends React.Component<$FlowFixMeProps> { ({(frame.left || 0).toFixed(1)}, {(frame.top || 0).toFixed(1)}) - {(frame.width || 0).toFixed(1)} × {(frame.height || 0).toFixed(1)} + {(frame.width || 0).toFixed(1)} ×{' '} + {(frame.height || 0).toFixed(1)} @@ -50,9 +53,10 @@ class BoxContainer extends React.Component<$FlowFixMeProps> { return ( - { - } - {this.props.title} + {} + + {this.props.title} + {box.top} diff --git a/Libraries/Inspector/ElementBox.js b/Libraries/Inspector/ElementBox.js index 17b2c8920e8e5f..e43233fb0dce51 100644 --- a/Libraries/Inspector/ElementBox.js +++ b/Libraries/Inspector/ElementBox.js @@ -4,8 +4,10 @@ * 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'); @@ -68,4 +70,3 @@ const styles = StyleSheet.create({ }); module.exports = ElementBox; - diff --git a/Libraries/Inspector/ElementProperties.js b/Libraries/Inspector/ElementProperties.js index 75beaf93e233f8..1e360944716fd2 100644 --- a/Libraries/Inspector/ElementProperties.js +++ b/Libraries/Inspector/ElementProperties.js @@ -4,8 +4,10 @@ * 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 BoxInspector = require('BoxInspector'); @@ -79,16 +81,14 @@ class ElementProperties extends React.Component<{ style={[styles.breadItem, i === selection && styles.selected]} // $FlowFixMe found when converting React.createClass to ES6 onPress={() => this.props.setSelection(i)}> - - {hierarchyItem.name} - + {hierarchyItem.name} ), - (i) => ( + i => ( - ) + ), )} @@ -98,7 +98,8 @@ class ElementProperties extends React.Component<{ { // $FlowFixMe found when converting React.createClass to ES6 - } + + } @@ -152,7 +153,7 @@ const styles = StyleSheet.create({ openButtonTitle: { color: 'white', fontSize: 8, - } + }, }); module.exports = ElementProperties; diff --git a/Libraries/Inspector/Inspector.js b/Libraries/Inspector/Inspector.js index 73ce0719b36d03..a5ab122b0cde5b 100644 --- a/Libraries/Inspector/Inspector.js +++ b/Libraries/Inspector/Inspector.js @@ -4,6 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * + * @format * @flow */ @@ -37,8 +38,13 @@ const renderers = findRenderers(); hook.resolveRNStyle = require('flattenStyle'); function findRenderers(): $ReadOnlyArray { - const allRenderers = Object.keys(hook._renderers).map(key => hook._renderers[key]); - invariant(allRenderers.length >= 1, 'Expected to find at least one React Native renderer on DevTools hook.'); + const allRenderers = Object.keys(hook._renderers).map( + key => hook._renderers[key], + ); + invariant( + allRenderers.length >= 1, + 'Expected to find at least one React Native renderer on DevTools hook.', + ); return allRenderers; } @@ -53,20 +59,23 @@ function getInspectorDataForViewTag(touchedViewTag: number) { throw new Error('Expected to find at least one React renderer.'); } -class Inspector extends React.Component<{ - inspectedViewTag: ?number, - onRequestRerenderApp: (callback: (tag: ?number) => void) => void -}, { - devtoolsAgent: ?Object, - hierarchy: any, - panelPos: string, - inspecting: bool, - selection: ?number, - perfing: bool, - inspected: any, - inspectedViewTag: any, - networking: bool, -}> { +class Inspector extends React.Component< + { + inspectedViewTag: ?number, + onRequestRerenderApp: (callback: (tag: ?number) => void) => void, + }, + { + devtoolsAgent: ?Object, + hierarchy: any, + panelPos: string, + inspecting: boolean, + selection: ?number, + perfing: boolean, + inspected: any, + inspectedViewTag: any, + networking: boolean, + }, +> { _subs: ?Array<() => void>; constructor(props: Object) { @@ -149,15 +158,12 @@ class Inspector extends React.Component<{ }); }; - setSelection(i: number) { const hierarchyItem = this.state.hierarchy[i]; // we pass in ReactNative.findNodeHandle as the method is injected - const { - measure, - props, - source, - } = hierarchyItem.getInspectorData(ReactNative.findNodeHandle); + const {measure, props, source} = hierarchyItem.getInspectorData( + ReactNative.findNodeHandle, + ); measure((x, y, width, height, left, top) => { this.setState({ @@ -175,21 +181,23 @@ class Inspector extends React.Component<{ // Most likely the touched instance is a native wrapper (like RCTView) // which is not very interesting. Most likely user wants a composite // instance that contains it (like View) - const { - hierarchy, - props, - selection, - source, - } = getInspectorDataForViewTag(touchedViewTag); + const {hierarchy, props, selection, source} = getInspectorDataForViewTag( + touchedViewTag, + ); if (this.state.devtoolsAgent) { // Skip host leafs const offsetFromLeaf = hierarchy.length - 1 - selection; - this.state.devtoolsAgent.selectFromDOMNode(touchedViewTag, true, offsetFromLeaf); + this.state.devtoolsAgent.selectFromDOMNode( + touchedViewTag, + true, + offsetFromLeaf, + ); } this.setState({ - panelPos: pointerY > Dimensions.get('window').height / 2 ? 'top' : 'bottom', + panelPos: + pointerY > Dimensions.get('window').height / 2 ? 'top' : 'bottom', selection, hierarchy, inspected: { @@ -200,7 +208,7 @@ class Inspector extends React.Component<{ }); } - setPerfing(val: bool) { + setPerfing(val: boolean) { this.setState({ perfing: val, inspecting: false, @@ -209,21 +217,21 @@ class Inspector extends React.Component<{ }); } - setInspecting(val: bool) { + setInspecting(val: boolean) { this.setState({ inspecting: val, - inspected: null + inspected: null, }); } - setTouchTargeting(val: bool) { + setTouchTargeting(val: boolean) { Touchable.TOUCH_TARGET_DEBUG = val; - this.props.onRequestRerenderApp((inspectedViewTag) => { + this.props.onRequestRerenderApp(inspectedViewTag => { this.setState({inspectedViewTag}); }); } - setNetworking(val: bool) { + setNetworking(val: boolean) { this.setState({ networking: val, perfing: false, @@ -233,17 +241,19 @@ class Inspector extends React.Component<{ } render() { - const panelContainerStyle = (this.state.panelPos === 'bottom') ? - {bottom: 0} : - {top: Platform.OS === 'ios' ? 20 : 0}; + const panelContainerStyle = + this.state.panelPos === 'bottom' + ? {bottom: 0} + : {top: Platform.OS === 'ios' ? 20 : 0}; return ( - {this.state.inspecting && + {this.state.inspecting && ( } + /> + )} { - this.props.onTouchViewTag(nativeViewTag, {left, top, width, height}, locationY); - } + this.props.onTouchViewTag( + nativeViewTag, + {left, top, width, height}, + locationY, + ); + }, ); }; - shouldSetResponser = (e: EventLike): bool => { + shouldSetResponser = (e: EventLike): boolean => { this.findViewForTouchEvent(e); return true; }; @@ -56,7 +62,12 @@ class InspectorOverlay extends React.Component<{ render() { let content = null; if (this.props.inspected) { - content = ; + content = ( + + ); } return ( diff --git a/Libraries/Inspector/InspectorPanel.js b/Libraries/Inspector/InspectorPanel.js index b2dd639c4a898b..2793452d90e578 100644 --- a/Libraries/Inspector/InspectorPanel.js +++ b/Libraries/Inspector/InspectorPanel.js @@ -4,8 +4,10 @@ * 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 ElementProperties = require('ElementProperties'); @@ -23,9 +25,7 @@ class InspectorPanel extends React.Component<$FlowFixMeProps> { renderWaiting() { if (this.props.inspecting) { return ( - - Tap something to inspect it - + Tap something to inspect it ); } return Nothing is inspected; @@ -47,19 +47,11 @@ class InspectorPanel extends React.Component<$FlowFixMeProps> { ); } else if (this.props.perfing) { - contents = ( - - ); + contents = ; } else if (this.props.networking) { - contents = ( - - ); + contents = ; } else { - contents = ( - - {this.renderWaiting()} - - ); + contents = {this.renderWaiting()}; } return ( @@ -70,15 +62,18 @@ class InspectorPanel extends React.Component<$FlowFixMeProps> { pressed={this.props.inspecting} onClick={this.props.setInspecting} /> -