From 27378b7f10ddfa73e8de0aaea1f6fea82894d601 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Sat, 26 Sep 2020 17:21:50 -0700 Subject: [PATCH 01/11] Animated: Early detection of division by zero in AnimatedDivision Summary: Same as D20969087 (https://github.com/facebook/react-native/commit/be7867375580ed391bb10c50b768d998087e848d) but a bit more sophisticated. We currently see a lot of errors happens because of division by zero in AnimatedDivision module. We already have a check for that in the module but it happens during the animation tick where the context of execution is already lost and it's hard to find why exactly it happens. Adding an additional check to the constructor should trigger an error right inside render function which should make the error actionable. Changelog: [Internal] Fabric-specific internal change. Reviewed By: fkgozali Differential Revision: D23908993 fbshipit-source-id: d21be9a72ec04fe4ff0740777d9ff49cf1bcde73 --- Libraries/Animated/nodes/AnimatedDivision.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/Animated/nodes/AnimatedDivision.js b/Libraries/Animated/nodes/AnimatedDivision.js index 437b013b52..fad47ae87d 100644 --- a/Libraries/Animated/nodes/AnimatedDivision.js +++ b/Libraries/Animated/nodes/AnimatedDivision.js @@ -24,7 +24,7 @@ class AnimatedDivision extends AnimatedWithChildren { constructor(a: AnimatedNode | number, b: AnimatedNode | number) { super(); - if (b === 0) { + if (b === 0 || (b instanceof AnimatedNode && b.__getValue() === 0)) { console.error('Detected potential division by zero in AnimatedDivision'); } this._a = typeof a === 'number' ? new AnimatedValue(a) : a; From 308f9a131af23b98ff2ce9ffd72f43dc015f116e Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Sat, 26 Sep 2020 22:00:15 -0700 Subject: [PATCH 02/11] Fabric: Failing early in case if a argument of `-[RCTComponentViewFactory registerComponentViewClass:]` is nil Summary: Subject. Changelog: [Internal] Fabric-specific internal change. Reviewed By: JoshuaGross Differential Revision: D23914517 fbshipit-source-id: 1c909e7d21b12326881990ecf855e814bf957f3c --- React/Fabric/Mounting/RCTComponentViewFactory.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/React/Fabric/Mounting/RCTComponentViewFactory.mm b/React/Fabric/Mounting/RCTComponentViewFactory.mm index 88489f2b3c..1c857b440c 100644 --- a/React/Fabric/Mounting/RCTComponentViewFactory.mm +++ b/React/Fabric/Mounting/RCTComponentViewFactory.mm @@ -117,6 +117,7 @@ static Class RCTComponentViewClassWithName(const char - (void)registerComponentViewClass:(Class)componentViewClass { + RCTAssert(componentViewClass, @"RCTComponentViewFactory: Provided `componentViewClass` is `nil`."); std::unique_lock lock(_mutex); auto componentDescriptorProvider = [componentViewClass componentDescriptorProvider]; From 0b96ada9acd18eadf9455a5cfef7da39a3dc8648 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Sat, 26 Sep 2020 22:00:15 -0700 Subject: [PATCH 03/11] Fabric: Adding `#pragma once` to `ImageTelemetry.h` Summary: Without this thing some stuff does not compile. Changelog: [Internal] Fabric-specific internal change. Reviewed By: fkgozali Differential Revision: D23948622 fbshipit-source-id: f066ada183c0fd6a7b5eec542395d44bbbfe80a3 --- ReactCommon/react/renderer/imagemanager/ImageTelemetry.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ReactCommon/react/renderer/imagemanager/ImageTelemetry.h b/ReactCommon/react/renderer/imagemanager/ImageTelemetry.h index b85ea7afad..312d19b19e 100644 --- a/ReactCommon/react/renderer/imagemanager/ImageTelemetry.h +++ b/ReactCommon/react/renderer/imagemanager/ImageTelemetry.h @@ -5,6 +5,8 @@ * LICENSE file in the root directory of this source tree. */ +#pragma once + #include #include From 863dd2df234718e0430679b3c061c228fd8da797 Mon Sep 17 00:00:00 2001 From: Lulu Wu Date: Mon, 28 Sep 2020 03:07:57 -0700 Subject: [PATCH 04/11] Make blocking people work in Dating Settings Summary: Blocking people didn't work in Dating Settings without the Bridge. Changelog: [Internal] Reviewed By: ejanzer Differential Revision: D23904867 fbshipit-source-id: 4a68b9d99fcc812f6616783a06dc047a3bc64491 --- .../com/facebook/react/modules/dialog/DialogModule.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/dialog/DialogModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/dialog/DialogModule.java index e3a2507215..664b359a27 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/dialog/DialogModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/dialog/DialogModule.java @@ -129,7 +129,8 @@ public class DialogModule extends NativeDialogManagerAndroidSpec implements Life @Override public void onClick(DialogInterface dialog, int which) { if (!mCallbackConsumed) { - if (getReactApplicationContext().hasActiveCatalystInstance()) { + if (getReactApplicationContext().isBridgeless() + || getReactApplicationContext().hasActiveCatalystInstance()) { mCallback.invoke(ACTION_BUTTON_CLICKED, which); mCallbackConsumed = true; } @@ -139,7 +140,8 @@ public class DialogModule extends NativeDialogManagerAndroidSpec implements Life @Override public void onDismiss(DialogInterface dialog) { if (!mCallbackConsumed) { - if (getReactApplicationContext().hasActiveCatalystInstance()) { + if (getReactApplicationContext().isBridgeless() + || getReactApplicationContext().hasActiveCatalystInstance()) { mCallback.invoke(ACTION_DISMISSED); mCallbackConsumed = true; } From e5006b3436e376cc5781566c65060b489e91338c Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Mon, 28 Sep 2020 03:13:06 -0700 Subject: [PATCH 05/11] Fix slider's initial value Summary: Changelog: [Internal] value needs to be set after minimum and maximum, otherwise it gets pinned to previous minimum/maximum. Default minimum is 0 and maximum is 1. If we set value to 20 and maximum to 50, previously the value would get pinned to 1 (maximum value). See [Apple Docs](https://developer.apple.com/documentation/uikit/uislider/1621346-value?language=objc) for more. Reviewed By: JoshuaGross Differential Revision: D23903545 fbshipit-source-id: 8e9dd49ced79d43b9591c7d24de59b9eaff5bdfd --- .../ComponentViews/Slider/RCTSliderComponentView.mm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/React/Fabric/Mounting/ComponentViews/Slider/RCTSliderComponentView.mm b/React/Fabric/Mounting/ComponentViews/Slider/RCTSliderComponentView.mm index 26375050f8..af62366caa 100644 --- a/React/Fabric/Mounting/ComponentViews/Slider/RCTSliderComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/Slider/RCTSliderComponentView.mm @@ -110,12 +110,6 @@ using namespace facebook::react; const auto &oldSliderProps = *std::static_pointer_cast(_props); const auto &newSliderProps = *std::static_pointer_cast(props); - // `value` - if (oldSliderProps.value != newSliderProps.value) { - _sliderView.value = newSliderProps.value; - _previousValue = newSliderProps.value; - } - // `minimumValue` if (oldSliderProps.minimumValue != newSliderProps.minimumValue) { _sliderView.minimumValue = newSliderProps.minimumValue; @@ -126,6 +120,12 @@ using namespace facebook::react; _sliderView.maximumValue = newSliderProps.maximumValue; } + // `value` + if (oldSliderProps.value != newSliderProps.value) { + _sliderView.value = newSliderProps.value; + _previousValue = newSliderProps.value; + } + // `disabled` if (oldSliderProps.disabled != newSliderProps.disabled) { _sliderView.enabled = !newSliderProps.disabled; From 2c896d35782cd04c873aefadc947447cc30a7f60 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Mon, 28 Sep 2020 04:18:49 -0700 Subject: [PATCH 06/11] Do not attach root view until size is available Summary: Changelog: [internal] # Why is text laid out twice in Fabric? Layout constraints (min and max size) change during startup of Fabric surface. 1. `Scheduler::startSurface` is called with max size being {inf, inf}. 2. `Scheduler::constraintSurfaceLayout` is called with max size equal to viewport. These are two operations that don't happen one after the other and on Android, CompleteRoot is called from JS before second operation is called. This triggers layout with max size {inf, inf} and later when second operation is called. Layout happens again now with correct size. # Fix Make sure `Scheduler::startSurface` is called with proper values and not {inf, inf}. Reviewed By: JoshuaGross, yungsters Differential Revision: D23866735 fbshipit-source-id: b16307543cc75c689d0c1f0a16aa581458f7417d --- .../src/main/java/com/facebook/react/ReactRootView.java | 2 -- 1 file changed, 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 2af6a23fbd..c21bffc720 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java @@ -382,8 +382,6 @@ public class ReactRootView extends FrameLayout implements RootView, ReactRoot { mReactInstanceManager.createReactContextInBackground(); - attachToReactInstanceManager(); - } finally { Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE); } From 35b8f76c9e7cc1660b7c32b95f9bd5509e600de7 Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Mon, 28 Sep 2020 10:43:02 -0700 Subject: [PATCH 07/11] RNTester: Add TextInput example to RTL tester Summary: Add a TextInput to RTL screen in RNTester, to test RTL languages with TextInput. Changelog: [Internal] Reviewed By: shergin Differential Revision: D23914627 fbshipit-source-id: 84c62efe7034c0dfa2ef21be3f085880292c3930 --- .../rn-tester/js/examples/RTL/RTLExample.js | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/packages/rn-tester/js/examples/RTL/RTLExample.js b/packages/rn-tester/js/examples/RTL/RTLExample.js index d6b1c1827e..d93995a038 100644 --- a/packages/rn-tester/js/examples/RTL/RTLExample.js +++ b/packages/rn-tester/js/examples/RTL/RTLExample.js @@ -21,6 +21,7 @@ const { Platform, StyleSheet, Text, + TextInput, TouchableWithoutFeedback, Switch, View, @@ -86,6 +87,18 @@ const TextAlignmentExample = withRTLState(({isRTL, setRTL, ...props}) => { ); }); +const TextInputExample = withRTLState(({isRTL, setRTL, ...props}) => { + return ( + + + + LRT or RTL TextInput. + + + + ); +}); + const IconsExample = withRTLState(({isRTL, setRTL}) => { return ( @@ -682,6 +695,13 @@ exports.examples = [ ); }, }, + { + title: "Using textAlign: 'right' for TextInput", + description: ('Flip TextInput direction to RTL': string), + render: function(): React.Element { + return ; + }, + }, { title: 'Working With Icons', render: function(): React.Element { From b85b4f46af422b2b942f3ecb3c61cb562bfebc02 Mon Sep 17 00:00:00 2001 From: Luna Wei Date: Mon, 28 Sep 2020 10:51:54 -0700 Subject: [PATCH 08/11] Update PerformanceLogger to nullable timespans, points, extras Summary: Changelog: [Internal][Fixed] - When we close performance loggers (D23845307 (https://github.com/facebook/react-native/commit/aebb97b9c64a8d84cf852ae8efc5ef28b36da610)) we cannot rely that a timespan/point/extra will be in perf logger. Update types to reflect that. Reviewed By: rubennorte Differential Revision: D23907741 fbshipit-source-id: 63673aa69cd8c76253e4fee3463e37c86265cf7b --- Libraries/Inspector/PerformanceOverlay.js | 2 +- .../__tests__/PerformanceLogger-test.js | 12 ++++---- .../Utilities/createPerformanceLogger.js | 30 ++++++++++--------- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/Libraries/Inspector/PerformanceOverlay.js b/Libraries/Inspector/PerformanceOverlay.js index a7307bda91..128abb4309 100644 --- a/Libraries/Inspector/PerformanceOverlay.js +++ b/Libraries/Inspector/PerformanceOverlay.js @@ -22,7 +22,7 @@ class PerformanceOverlay extends React.Component<{...}> { const items = []; for (const key in perfLogs) { - if (perfLogs[key].totalTime) { + if (perfLogs[key]?.totalTime) { const unit = key === 'BundleSize' ? 'b' : 'ms'; items.push( diff --git a/Libraries/Utilities/__tests__/PerformanceLogger-test.js b/Libraries/Utilities/__tests__/PerformanceLogger-test.js index 45837855b6..d26cbede53 100644 --- a/Libraries/Utilities/__tests__/PerformanceLogger-test.js +++ b/Libraries/Utilities/__tests__/PerformanceLogger-test.js @@ -54,12 +54,12 @@ describe('PerformanceLogger', () => { perfLogger.startTimespan(TIMESPAN_1); perfLogger.close(); let timespan = perfLogger.getTimespans()[TIMESPAN_1]; - expect(timespan.endTime).toBeUndefined(); - expect(timespan.totalTime).toBeUndefined(); + expect(timespan?.endTime).toBeUndefined(); + expect(timespan?.totalTime).toBeUndefined(); perfLogger.stopTimespan(TIMESPAN_1); timespan = perfLogger.getTimespans()[TIMESPAN_1]; - expect(timespan.endTime).toBeUndefined(); - expect(timespan.totalTime).toBeUndefined(); + expect(timespan?.endTime).toBeUndefined(); + expect(timespan?.totalTime).toBeUndefined(); }); }); @@ -208,10 +208,10 @@ describe('PerformanceLogger', () => { let perfLogger = createPerformanceLogger(); perfLogger.startTimespan(TIMESPAN_1, POINT_ANNOTATION_1); perfLogger.stopTimespan(TIMESPAN_1, POINT_ANNOTATION_2); - expect(perfLogger.getTimespans()[TIMESPAN_1].startExtras).toEqual( + expect(perfLogger.getTimespans()[TIMESPAN_1]?.startExtras).toEqual( POINT_ANNOTATION_1, ); - expect(perfLogger.getTimespans()[TIMESPAN_1].endExtras).toEqual( + expect(perfLogger.getTimespans()[TIMESPAN_1]?.endExtras).toEqual( POINT_ANNOTATION_2, ); }); diff --git a/Libraries/Utilities/createPerformanceLogger.js b/Libraries/Utilities/createPerformanceLogger.js index e94b8bd3a0..2e8753f9ec 100644 --- a/Libraries/Utilities/createPerformanceLogger.js +++ b/Libraries/Utilities/createPerformanceLogger.js @@ -41,15 +41,15 @@ export interface IPerformanceLogger { clearCompleted(): void; close(): void; currentTimestamp(): number; - getExtras(): {[key: string]: ExtraValue, ...}; - getPoints(): {[key: string]: number, ...}; - getPointExtras(): {[key: string]: Extras, ...}; - getTimespans(): {[key: string]: Timespan, ...}; + getExtras(): {[key: string]: ?ExtraValue, ...}; + getPoints(): {[key: string]: ?number, ...}; + getPointExtras(): {[key: string]: ?Extras, ...}; + getTimespans(): {[key: string]: ?Timespan, ...}; hasTimespan(key: string): boolean; isClosed(): boolean; logEverything(): void; markPoint(key: string, timestamp?: number, extras?: Extras): void; - removeExtra(key: string): ExtraValue | void; + removeExtra(key: string): ?ExtraValue; setExtra(key: string, value: ExtraValue): void; startTimespan(key: string, extras?: Extras): void; stopTimespan(key: string, extras?: Extras): void; @@ -60,10 +60,10 @@ const _cookies: {[key: string]: number, ...} = {}; const PRINT_TO_CONSOLE: false = false; // Type as false to prevent accidentally committing `true`; class PerformanceLogger implements IPerformanceLogger { - _timespans: {[key: string]: Timespan} = {}; - _extras: {[key: string]: ExtraValue} = {}; - _points: {[key: string]: number} = {}; - _pointExtras: {[key: string]: Extras, ...} = {}; + _timespans: {[key: string]: ?Timespan} = {}; + _extras: {[key: string]: ?ExtraValue} = {}; + _points: {[key: string]: ?number} = {}; + _pointExtras: {[key: string]: ?Extras, ...} = {}; _closed: boolean = false; addTimespan( @@ -109,7 +109,7 @@ class PerformanceLogger implements IPerformanceLogger { clearCompleted() { for (const key in this._timespans) { - if (this._timespans[key].totalTime != null) { + if (this._timespans[key]?.totalTime != null) { delete this._timespans[key]; } } @@ -156,7 +156,7 @@ class PerformanceLogger implements IPerformanceLogger { if (PRINT_TO_CONSOLE) { // log timespans for (const key in this._timespans) { - if (this._timespans[key].totalTime != null) { + if (this._timespans[key]?.totalTime != null) { infoLog(key + ': ' + this._timespans[key].totalTime + 'ms'); } } @@ -166,7 +166,9 @@ class PerformanceLogger implements IPerformanceLogger { // log points for (const key in this._points) { - infoLog(key + ': ' + this._points[key] + 'ms'); + if (this._points[key] != null) { + infoLog(key + ': ' + this._points[key] + 'ms'); + } } } } @@ -178,7 +180,7 @@ class PerformanceLogger implements IPerformanceLogger { } return; } - if (this._points[key]) { + if (this._points[key] != null) { if (PRINT_TO_CONSOLE && __DEV__) { infoLog( 'PerformanceLogger: Attempting to mark a point that has been already logged ', @@ -193,7 +195,7 @@ class PerformanceLogger implements IPerformanceLogger { } } - removeExtra(key: string): ExtraValue | void { + removeExtra(key: string): ?ExtraValue { const value = this._extras[key]; delete this._extras[key]; return value; From 0a0d2c990d6b666c962ca3a513f5fdb74eb79e0a Mon Sep 17 00:00:00 2001 From: Martin Ortega Date: Mon, 28 Sep 2020 12:33:57 -0700 Subject: [PATCH 09/11] Make the Instagram app compile again Summary: Wrap iOS 14 SDK code in a `#if/#endif` so that the Instagram app compiles again Changelog: [Internal] Reviewed By: PeteTheHeat Differential Revision: D23948336 fbshipit-source-id: 67e6ee48d1951ae405c12b4ad39cf8c9817df627 --- React/Views/RCTDatePicker.m | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/React/Views/RCTDatePicker.m b/React/Views/RCTDatePicker.m index 3ba934d152..9fee82b3cf 100644 --- a/React/Views/RCTDatePicker.m +++ b/React/Views/RCTDatePicker.m @@ -7,9 +7,20 @@ #import "RCTDatePicker.h" +#import +#import + #import "RCTUtils.h" #import "UIView+React.h" +#ifndef __IPHONE_14_0 + #define __IPHONE_14_0 140000 +#endif // __IPHONE_14_0 + +#ifndef RCT_IOS_14_0_SDK_OR_LATER + #define RCT_IOS_14_0_SDK_OR_LATER (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0) +#endif // RCT_IOS_14_0_SDK_OR_LATER + @interface RCTDatePicker () @property (nonatomic, copy) RCTBubblingEventBlock onChange; @@ -25,9 +36,11 @@ [self addTarget:self action:@selector(didChange) forControlEvents:UIControlEventValueChanged]; _reactMinuteInterval = 1; +#if RCT_IOS_14_0_SDK_OR_LATER if (@available(iOS 14, *)) { self.preferredDatePickerStyle = UIDatePickerStyleWheels; } +#endif // RCT_IOS_14_0_SDK_OR_LATER } return self; } From 9da4d87798b8811795838f84739f9e98c2099ff8 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Mon, 28 Sep 2020 17:21:14 -0700 Subject: [PATCH 10/11] Pressability: Support Lazy Hook Initialization Summary: Changes `usePressability` so that it accepts a nullable `config` argument. This makes it possible for a component to use `usePressability` and lazily allocate the `config` and subsequent instance of `Pressability`. This can be useful for components that are commonly allocated but seldom pressed because it lets many usages of `usePressability` avoid allocating many extraneous objects. Changelog: [Internal] Reviewed By: kacieb Differential Revision: D23708206 fbshipit-source-id: 4a5063067131ce8c957fb16c49a2045e8c0b19fa --- Libraries/Components/Pressable/Pressable.js | 14 +++++++----- Libraries/Pressability/usePressability.js | 25 ++++++++++++++------- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/Libraries/Components/Pressable/Pressable.js b/Libraries/Components/Pressable/Pressable.js index 48ebd05576..a6692c92bd 100644 --- a/Libraries/Components/Pressable/Pressable.js +++ b/Libraries/Components/Pressable/Pressable.js @@ -170,6 +170,14 @@ function Pressable(props: Props, forwardedRef): React.Node { const hitSlop = normalizeRect(props.hitSlop); + const restPropsWithDefaults: React.ElementConfig = { + ...restProps, + ...android_rippleConfig?.viewProps, + accessible: accessible !== false, + focusable: focusable !== false, + hitSlop, + }; + const config = useMemo( () => ({ disabled, @@ -219,12 +227,8 @@ function Pressable(props: Props, forwardedRef): React.Node { return ( diff --git a/Libraries/Pressability/usePressability.js b/Libraries/Pressability/usePressability.js index 3538524239..9ed4cc2219 100644 --- a/Libraries/Pressability/usePressability.js +++ b/Libraries/Pressability/usePressability.js @@ -16,11 +16,16 @@ import Pressability, { } from './Pressability'; import {useEffect, useRef} from 'react'; +/** + * Creates a persistent instance of `Pressability` that automatically configures + * itself and resets. Accepts null `config` to support lazy initialization. Once + * initialized, will not un-initialize until the component has been unmounted. + */ export default function usePressability( - config: PressabilityConfig, -): EventHandlers { + config: ?PressabilityConfig, +): ?EventHandlers { const pressabilityRef = useRef(null); - if (pressabilityRef.current == null) { + if (config != null && pressabilityRef.current == null) { pressabilityRef.current = new Pressability(config); } const pressability = pressabilityRef.current; @@ -28,16 +33,20 @@ export default function usePressability( // On the initial mount, this is a no-op. On updates, `pressability` will be // re-configured to use the new configuration. useEffect(() => { - pressability.configure(config); + if (config != null && pressability != null) { + pressability.configure(config); + } }, [config, pressability]); // On unmount, reset pending state and timers inside `pressability`. This is // a separate effect because we do not want to reset when `config` changes. useEffect(() => { - return () => { - pressability.reset(); - }; + if (pressability != null) { + return () => { + pressability.reset(); + }; + } }, [pressability]); - return pressability.getEventHandlers(); + return pressability == null ? null : pressability.getEventHandlers(); } From 06ce64356594a921cd9ae4f71c15dd56dd0e53a3 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Mon, 28 Sep 2020 17:21:14 -0700 Subject: [PATCH 11/11] Text: Cleanup Native Component Configuration Summary: Cleans up the native component configuration for `RCTText` and `RCTVirtualText`. This //does// lead to a breaking change because `Text.viewConfig` will no longer exist. However, I think this is acceptable because `viewConfig` has already long stopped being an exported prop on other core components (e.g. `View`). Changelog: [General][Removed] - `Text.viewConfig` is no longer exported. Reviewed By: shergin Differential Revision: D23708205 fbshipit-source-id: 1ad0b0772735834d9162a65d9434a9bbbd142416 --- Libraries/Text/Text.js | 75 +++++---------------------- Libraries/Text/TextNativeComponent.js | 68 ++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 62 deletions(-) create mode 100644 Libraries/Text/TextNativeComponent.js diff --git a/Libraries/Text/Text.js b/Libraries/Text/Text.js index 7d34417875..681922ea13 100644 --- a/Libraries/Text/Text.js +++ b/Libraries/Text/Text.js @@ -10,14 +10,13 @@ 'use strict'; +import {NativeText, NativeVirtualText} from './TextNativeComponent'; + const DeprecatedTextPropTypes = require('../DeprecatedPropTypes/DeprecatedTextPropTypes'); const React = require('react'); -const ReactNativeViewAttributes = require('../Components/View/ReactNativeViewAttributes'); const TextAncestor = require('./TextAncestor'); const Touchable = require('../Components/Touchable/Touchable'); -const UIManager = require('../ReactNative/UIManager'); -const createReactNativeComponentClass = require('../Renderer/shims/createReactNativeComponentClass'); const nullthrows = require('nullthrows'); const processColor = require('../StyleSheet/processColor'); @@ -27,7 +26,7 @@ import type {PressRetentionOffset, TextProps} from './TextProps'; type ResponseHandlers = $ReadOnly<{| onStartShouldSetResponder: () => boolean, - onResponderGrant: (event: PressEvent, dispatchID: string) => void, + onResponderGrant: (event: PressEvent) => void, onResponderMove: (event: PressEvent) => void, onResponderRelease: (event: PressEvent) => void, onResponderTerminate: (event: PressEvent) => void, @@ -36,7 +35,7 @@ type ResponseHandlers = $ReadOnly<{| type Props = $ReadOnly<{| ...TextProps, - forwardedRef: ?React.Ref<'RCTText' | 'RCTVirtualText'>, + forwardedRef: ?React.Ref, |}>; type State = {| @@ -51,36 +50,6 @@ type State = {| const PRESS_RECT_OFFSET = {top: 20, left: 20, right: 20, bottom: 30}; -const viewConfig = { - validAttributes: { - ...ReactNativeViewAttributes.UIView, - isHighlighted: true, - numberOfLines: true, - ellipsizeMode: true, - allowFontScaling: true, - maxFontSizeMultiplier: true, - disabled: true, - selectable: true, - selectionColor: true, - adjustsFontSizeToFit: true, - minimumFontScale: true, - textBreakStrategy: true, - onTextLayout: true, - onInlineViewLayout: true, - dataDetectorType: true, - android_hyphenationFrequency: true, - }, - directEventTypes: { - topTextLayout: { - registrationName: 'onTextLayout', - }, - topInlineViewLayout: { - registrationName: 'onInlineViewLayout', - }, - }, - uiViewClassName: 'RCTText', -}; - /** * A React component for displaying text. * @@ -122,21 +91,19 @@ class TouchableText extends React.Component { : null; } - static viewConfig = viewConfig; - render(): React.Node { - let props = this.props; - if (isTouchable(props)) { + let {forwardedRef, selectionColor, ...props} = this.props; + if (isTouchable(this.props)) { props = { ...props, ...this.state.responseHandlers, isHighlighted: this.state.isHighlighted, }; } - if (props.selectionColor != null) { + if (selectionColor != null) { props = { ...props, - selectionColor: processColor(props.selectionColor), + selectionColor: processColor(selectionColor), }; } if (__DEV__) { @@ -151,16 +118,17 @@ class TouchableText extends React.Component { {hasTextAncestor => hasTextAncestor ? ( - ) : ( - + ) } @@ -263,26 +231,9 @@ const isTouchable = (props: Props): boolean => props.onLongPress != null || props.onStartShouldSetResponder != null; -const RCTText = createReactNativeComponentClass( - viewConfig.uiViewClassName, - () => viewConfig, -); - -const RCTVirtualText = - UIManager.getViewManagerConfig('RCTVirtualText') == null - ? RCTText - : createReactNativeComponentClass('RCTVirtualText', () => ({ - validAttributes: { - ...ReactNativeViewAttributes.UIView, - isHighlighted: true, - maxFontSizeMultiplier: true, - }, - uiViewClassName: 'RCTVirtualText', - })); - const Text = ( props: TextProps, - forwardedRef: ?React.Ref<'RCTText' | 'RCTVirtualText'>, + forwardedRef: ?React.Ref, ) => { return ; }; diff --git a/Libraries/Text/TextNativeComponent.js b/Libraries/Text/TextNativeComponent.js new file mode 100644 index 0000000000..eafc7ddf8d --- /dev/null +++ b/Libraries/Text/TextNativeComponent.js @@ -0,0 +1,68 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import ReactNativeViewAttributes from '../Components/View/ReactNativeViewAttributes'; +import UIManager from '../ReactNative/UIManager'; +import {type HostComponent} from '../Renderer/shims/ReactNativeTypes'; +import createReactNativeComponentClass from '../Renderer/shims/createReactNativeComponentClass'; +import {type ProcessedColorValue} from '../StyleSheet/processColor'; +import {type TextProps} from './TextProps'; + +type NativeTextProps = $ReadOnly<{ + ...TextProps, + isHighlighted?: ?boolean, + selectionColor?: ?ProcessedColorValue, +}>; + +export const NativeText: HostComponent = (createReactNativeComponentClass( + 'RCTText', + () => ({ + validAttributes: { + ...ReactNativeViewAttributes.UIView, + isHighlighted: true, + numberOfLines: true, + ellipsizeMode: true, + allowFontScaling: true, + maxFontSizeMultiplier: true, + disabled: true, + selectable: true, + selectionColor: true, + adjustsFontSizeToFit: true, + minimumFontScale: true, + textBreakStrategy: true, + onTextLayout: true, + onInlineViewLayout: true, + dataDetectorType: true, + }, + directEventTypes: { + topTextLayout: { + registrationName: 'onTextLayout', + }, + topInlineViewLayout: { + registrationName: 'onInlineViewLayout', + }, + }, + uiViewClassName: 'RCTText', + }), +): any); + +export const NativeVirtualText: HostComponent = + UIManager.getViewManagerConfig('RCTVirtualText') == null + ? NativeText + : (createReactNativeComponentClass('RCTVirtualText', () => ({ + validAttributes: { + ...ReactNativeViewAttributes.UIView, + isHighlighted: true, + maxFontSizeMultiplier: true, + }, + uiViewClassName: 'RCTVirtualText', + })): any);