@office-iss/react-native-win32 0.0.0-canary.258 → 0.0.0-canary.260

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/.flowconfig +2 -4
  2. package/CHANGELOG.json +31 -1
  3. package/CHANGELOG.md +24 -8
  4. package/Libraries/Alert/Alert.js +3 -0
  5. package/Libraries/Animated/AnimatedImplementation.js +7 -7
  6. package/Libraries/Animated/animations/Animation.js +10 -0
  7. package/Libraries/Animated/animations/TimingAnimation.js +1 -0
  8. package/Libraries/Animated/components/AnimatedScrollView.js +2 -2
  9. package/Libraries/Animated/createAnimatedComponent.js +1 -1
  10. package/Libraries/Animated/nodes/AnimatedValue.js +1 -0
  11. package/Libraries/Animated/useAnimatedProps.js +138 -6
  12. package/Libraries/BatchedBridge/NativeModules.js +2 -0
  13. package/Libraries/Blob/FileReader.js +1 -1
  14. package/Libraries/Blob/URL.js +2 -62
  15. package/Libraries/Blob/URLSearchParams.js +71 -0
  16. package/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js +1 -1
  17. package/Libraries/Components/RefreshControl/__mocks__/RefreshControlMock.js +1 -1
  18. package/Libraries/Components/ScrollView/AndroidHorizontalScrollViewNativeComponent.js +3 -0
  19. package/Libraries/Components/ScrollView/ScrollView.js +5 -5
  20. package/Libraries/Components/ScrollView/ScrollViewNativeComponent.js +3 -0
  21. package/Libraries/Components/ScrollView/ScrollViewStickyHeader.js +1 -1
  22. package/Libraries/Components/StatusBar/StatusBar.js +3 -1
  23. package/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js +3 -0
  24. package/Libraries/Components/TextInput/TextInput.d.ts +32 -2
  25. package/Libraries/Components/TextInput/TextInput.js +220 -80
  26. package/Libraries/Components/TextInput/TextInput.win32.js +220 -86
  27. package/Libraries/Components/View/ReactNativeStyleAttributes.js +22 -0
  28. package/Libraries/Components/View/ReactNativeViewAttributes.js +2 -0
  29. package/Libraries/Components/View/ReactNativeViewAttributes.win32.js +2 -0
  30. package/Libraries/Components/View/ViewAccessibility.d.ts +15 -0
  31. package/Libraries/Components/View/ViewNativeComponent.js +6 -0
  32. package/Libraries/Components/View/ViewPropTypes.js +14 -0
  33. package/Libraries/Components/View/ViewPropTypes.win32.js +14 -0
  34. package/Libraries/Core/ExceptionsManager.js +2 -0
  35. package/Libraries/Core/InitializeCore.js +1 -1
  36. package/Libraries/Core/ReactFiberErrorDialog.js +3 -0
  37. package/Libraries/Core/ReactNativeVersion.js +1 -1
  38. package/Libraries/Core/setUpErrorHandling.js +7 -1
  39. package/Libraries/Core/setUpReactRefresh.js +0 -4
  40. package/Libraries/Image/AssetSourceResolver.js +28 -1
  41. package/Libraries/Image/Image.android.js +9 -14
  42. package/Libraries/Image/Image.ios.js +11 -22
  43. package/Libraries/Image/Image.win32.js +10 -21
  44. package/Libraries/Image/ImageBackground.js +1 -8
  45. package/Libraries/Image/ImageUtils.js +9 -9
  46. package/Libraries/Image/ImageViewNativeComponent.js +4 -0
  47. package/Libraries/Inspector/NetworkOverlay.js +1 -1
  48. package/Libraries/Interaction/TaskQueue.js +1 -0
  49. package/Libraries/Lists/FlatList.js +1 -1
  50. package/Libraries/Lists/SectionList.js +2 -2
  51. package/Libraries/Lists/SectionListModern.js +1 -1
  52. package/Libraries/LogBox/Data/LogBoxData.js +31 -4
  53. package/Libraries/NativeComponent/BaseViewConfig.android.js +2 -0
  54. package/Libraries/NativeComponent/BaseViewConfig.ios.js +7 -0
  55. package/Libraries/NativeComponent/BaseViewConfig.win32.js +7 -0
  56. package/Libraries/NativeComponent/NativeComponentRegistry.js +9 -2
  57. package/Libraries/Network/XMLHttpRequest.js +4 -2
  58. package/Libraries/ReactNative/BridgelessUIManager.js +1 -0
  59. package/Libraries/ReactNative/ReactFabricPublicInstance/ReactFabricHostComponent.js +1 -1
  60. package/Libraries/ReactNative/ReactFabricPublicInstance/ReactFabricPublicInstance.js +5 -5
  61. package/Libraries/ReactNative/RendererImplementation.js +24 -2
  62. package/Libraries/ReactNative/getNativeComponentAttributes.js +8 -0
  63. package/Libraries/Renderer/shims/ReactNativeTypes.js +3 -1
  64. package/Libraries/StyleSheet/StyleSheet.js +1 -1
  65. package/Libraries/StyleSheet/StyleSheet.win32.js +1 -1
  66. package/Libraries/StyleSheet/StyleSheetTypes.d.ts +57 -19
  67. package/Libraries/StyleSheet/StyleSheetTypes.js +60 -23
  68. package/Libraries/StyleSheet/processBackgroundImage.js +286 -0
  69. package/Libraries/StyleSheet/processBoxShadow.js +211 -0
  70. package/Libraries/StyleSheet/processFilter.js +24 -14
  71. package/Libraries/Text/Text.js +395 -212
  72. package/Libraries/Text/Text.win32.js +443 -245
  73. package/Libraries/Text/TextNativeComponent.js +7 -0
  74. package/Libraries/Text/TextNativeComponent.win32.js +7 -0
  75. package/Libraries/TurboModule/TurboModuleRegistry.js +13 -50
  76. package/Libraries/Types/CodegenTypes.js +3 -1
  77. package/Libraries/Utilities/HMRClient.js +1 -0
  78. package/Libraries/Utilities/Platform.android.js +1 -1
  79. package/Libraries/Utilities/Platform.d.ts +1 -1
  80. package/Libraries/Utilities/Platform.flow.js +2 -2
  81. package/Libraries/Utilities/Platform.flow.win32.js +3 -3
  82. package/Libraries/Utilities/Platform.ios.js +1 -1
  83. package/Libraries/Utilities/Platform.win32.js +1 -1
  84. package/Libraries/Utilities/ReactNativeTestTools.js +1 -1
  85. package/Libraries/WebSocket/WebSocket.js +1 -1
  86. package/Libraries/vendor/emitter/EventEmitter.js +1 -0
  87. package/flow/jest.js +2 -2
  88. package/index.js +1 -0
  89. package/index.win32.js +1 -0
  90. package/jest/mockModal.js +1 -3
  91. package/jest/mockScrollView.js +1 -1
  92. package/jest/renderer.js +2 -2
  93. package/jest/setup.js +16 -9
  94. package/overrides.json +16 -16
  95. package/package.json +15 -15
  96. package/src/private/{core/components → components}/HScrollViewNativeComponents.js +8 -8
  97. package/src/private/{core/components → components}/VScrollViewNativeComponents.js +7 -7
  98. package/src/private/{core/components → components}/useSyncOnScroll.js +2 -2
  99. package/src/private/featureflags/ReactNativeFeatureFlags.js +143 -19
  100. package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +25 -5
  101. package/src/private/hooks/DebouncedEffectImplementation.js +148 -0
  102. package/src/private/hooks/useDebouncedEffect.js +23 -0
  103. package/{Libraries/Core → src/private/renderer/errorhandling}/ErrorHandlers.js +14 -4
  104. package/src/private/setup/setUpDOM.js +28 -0
  105. package/src/private/setup/setUpIntersectionObserver.js +27 -0
  106. package/src/private/setup/setUpMutationObserver.js +26 -0
  107. package/src/private/setup/setUpPerformanceObserver.js +64 -0
  108. package/src/private/specs/modules/NativeDebuggerSessionObserver.js +23 -0
  109. package/src/private/specs/modules/NativeLinkingManager.js +1 -1
  110. package/src/private/specs/modules/NativePlatformConstantsAndroid.js +1 -1
  111. package/src/private/specs/modules/NativePlatformConstantsIOS.js +1 -1
  112. package/src/private/specs/modules/NativePlatformConstantsWin.js +8 -1
  113. package/src/private/webapis/dom/nodes/ReadOnlyNode.js +6 -4
  114. package/{Libraries/IntersectionObserver → src/private/webapis/intersectionobserver}/IntersectionObserver.js +1 -1
  115. package/{Libraries/IntersectionObserver → src/private/webapis/intersectionobserver}/IntersectionObserverEntry.js +3 -3
  116. package/{Libraries/IntersectionObserver → src/private/webapis/intersectionobserver}/IntersectionObserverManager.js +5 -8
  117. package/src/private/{specs/modules → webapis/intersectionobserver/specs}/NativeIntersectionObserver.js +2 -2
  118. package/{Libraries/IntersectionObserver → src/private/webapis/intersectionobserver/specs}/__mocks__/NativeIntersectionObserver.js +4 -4
  119. package/{Libraries/MutationObserver → src/private/webapis/mutationobserver}/MutationObserver.js +1 -1
  120. package/{Libraries/MutationObserver → src/private/webapis/mutationobserver}/MutationObserverManager.js +5 -5
  121. package/{Libraries/MutationObserver → src/private/webapis/mutationobserver}/MutationRecord.js +4 -6
  122. package/src/private/{specs/modules → webapis/mutationobserver/specs}/NativeMutationObserver.js +2 -2
  123. package/{Libraries/MutationObserver → src/private/webapis/mutationobserver/specs}/__mocks__/NativeMutationObserver.js +5 -5
  124. package/src/private/webapis/performance/{EventCounts.js → EventTiming.js} +65 -3
  125. package/src/private/webapis/performance/LongTasks.js +39 -0
  126. package/src/private/webapis/performance/Performance.js +22 -9
  127. package/src/private/webapis/performance/PerformanceEntry.js +36 -18
  128. package/src/private/webapis/performance/PerformanceObserver.js +29 -43
  129. package/src/private/webapis/performance/RawPerformanceEntry.js +24 -1
  130. package/src/private/webapis/performance/UserTiming.js +17 -12
  131. package/src/private/webapis/performance/specs/NativePerformanceObserver.js +1 -1
  132. package/src-win/Libraries/Components/View/ViewAccessibility.d.ts +15 -0
  133. package/types/experimental.d.ts +20 -1
  134. package/Libraries/Core/setUpIntersectionObserver.js +0 -16
  135. package/Libraries/Core/setUpMutationObserver.js +0 -16
  136. package/Libraries/Core/setUpPerformanceObserver.js +0 -18
  137. package/Libraries/IntersectionObserver/NativeIntersectionObserver.js +0 -13
  138. package/Libraries/MutationObserver/NativeMutationObserver.js +0 -13
  139. package/Libraries/Text/TextOptimized.js +0 -538
  140. package/src/private/core/setUpDOM.js +0 -18
  141. package/src/private/webapis/performance/PerformanceEventTiming.js +0 -55
  142. /package/src/private/{core → styles}/composeStyles.js +0 -0
@@ -22,7 +22,7 @@ class RefreshControlMock extends React.Component<{...}> {
22
22
  componentDidMount() {
23
23
  RefreshControlMock.latestRef = this;
24
24
  }
25
- render(): React.Element<typeof RCTRefreshControl> {
25
+ render(): React.MixedElement {
26
26
  return <RCTRefreshControl />;
27
27
  }
28
28
  }
@@ -25,6 +25,9 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig = {
25
25
  disableIntervalMomentum: true,
26
26
  maintainVisibleContentPosition: true,
27
27
  endFillColor: {process: require('../../StyleSheet/processColor').default},
28
+ experimental_boxShadow: {
29
+ process: require('../../StyleSheet/processBoxShadow').default,
30
+ },
28
31
  fadingEdgeLength: true,
29
32
  nestedScrollEnabled: true,
30
33
  overScrollMode: true,
@@ -11,7 +11,7 @@
11
11
  import type {
12
12
  TScrollViewNativeComponentInstance,
13
13
  TScrollViewNativeImperativeHandle,
14
- } from '../../../src/private/core/components/useSyncOnScroll';
14
+ } from '../../../src/private/components/useSyncOnScroll';
15
15
  import type {HostComponent} from '../../Renderer/shims/ReactNativeTypes';
16
16
  import type {EdgeInsetsProp} from '../../StyleSheet/EdgeInsetsPropType';
17
17
  import type {PointProp} from '../../StyleSheet/PointPropType';
@@ -31,11 +31,11 @@ import type {Props as ScrollViewStickyHeaderProps} from './ScrollViewStickyHeade
31
31
  import {
32
32
  HScrollContentViewNativeComponent,
33
33
  HScrollViewNativeComponent,
34
- } from '../../../src/private/core/components/HScrollViewNativeComponents';
34
+ } from '../../../src/private/components/HScrollViewNativeComponents';
35
35
  import {
36
36
  VScrollContentViewNativeComponent,
37
37
  VScrollViewNativeComponent,
38
- } from '../../../src/private/core/components/VScrollViewNativeComponents';
38
+ } from '../../../src/private/components/VScrollViewNativeComponents';
39
39
  import AnimatedImplementation from '../../Animated/AnimatedImplementation';
40
40
  import FrameRateLogger from '../../Interaction/FrameRateLogger';
41
41
  import {findNodeHandle} from '../../ReactNative/RendererProxy';
@@ -643,7 +643,7 @@ export type Props = $ReadOnly<{|
643
643
  */
644
644
  /* $FlowFixMe[unclear-type] - how to handle generic type without existential
645
645
  * operator? */
646
- refreshControl?: ?React.Element<any>,
646
+ refreshControl?: ?ExactReactElement_DEPRECATED<any>,
647
647
  children?: React.Node,
648
648
  /**
649
649
  * A ref to the inner View element of the ScrollView. This should be used
@@ -1648,7 +1648,7 @@ class ScrollView extends React.Component<Props, State> {
1648
1648
  this.props.onTouchMove && this.props.onTouchMove(e);
1649
1649
  };
1650
1650
 
1651
- render(): React.Node | React.Element<string> {
1651
+ render(): React.Node {
1652
1652
  const horizontal = this.props.horizontal === true;
1653
1653
 
1654
1654
  const NativeScrollView = horizontal
@@ -46,6 +46,9 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig =
46
46
  },
47
47
  decelerationRate: true,
48
48
  enableSyncOnScroll: true, // Fabric only.
49
+ experimental_boxShadow: {
50
+ process: require('../../StyleSheet/processBoxShadow').default,
51
+ },
49
52
  disableIntervalMomentum: true,
50
53
  maintainVisibleContentPosition: true,
51
54
  pagingEnabled: true,
@@ -19,7 +19,7 @@ import * as React from 'react';
19
19
  import {useCallback, useEffect, useMemo, useRef, useState} from 'react';
20
20
 
21
21
  export type Props = $ReadOnly<{
22
- children?: React.Element<$FlowFixMe>,
22
+ children?: ExactReactElement_DEPRECATED<$FlowFixMe>,
23
23
  nextHeaderLayoutY: ?number,
24
24
  onLayout: (event: LayoutEvent) => void,
25
25
  scrollAnimatedValue: Animated.Value,
@@ -272,8 +272,10 @@ class StatusBar extends React.Component<Props> {
272
272
  }
273
273
 
274
274
  /**
275
- * Control the visibility of the network activity indicator
275
+ * DEPRECATED - The status bar network activity indicator is not supported in iOS 13 and later. This will be removed in a future release.
276
276
  * @param visible Show the indicator.
277
+ *
278
+ * @deprecated
277
279
  */
278
280
  static setNetworkActivityIndicatorVisible(visible: boolean) {
279
281
  if (Platform.OS !== 'ios') {
@@ -739,6 +739,9 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig = {
739
739
  },
740
740
  borderTopLeftRadius: true,
741
741
  borderTopColor: {process: require('../../StyleSheet/processColor').default},
742
+ experimental_boxShadow: {
743
+ process: require('../../StyleSheet/processBoxShadow').default,
744
+ },
742
745
  },
743
746
  };
744
747
 
@@ -90,6 +90,8 @@ type DataDetectorTypes =
90
90
  | 'none'
91
91
  | 'all';
92
92
 
93
+ export type SubmitBehavior = 'submit' | 'blurAndSubmit' | 'newline';
94
+
93
95
  /**
94
96
  * DocumentSelectionState is responsible for maintaining selection information
95
97
  * for a document.
@@ -649,11 +651,39 @@ export interface TextInputProps
649
651
  autoFocus?: boolean | undefined;
650
652
 
651
653
  /**
652
- * If true, the text field will blur when submitted.
653
- * The default value is true.
654
+ * If `true`, the text field will blur when submitted.
655
+ * The default value is true for single-line fields and false for
656
+ * multiline fields. Note that for multiline fields, setting `blurOnSubmit`
657
+ * to `true` means that pressing return will blur the field and trigger the
658
+ * `onSubmitEditing` event instead of inserting a newline into the field.
659
+ *
660
+ * @deprecated
661
+ * Note that `submitBehavior` now takes the place of `blurOnSubmit` and will
662
+ * override any behavior defined by `blurOnSubmit`.
663
+ * @see submitBehavior
654
664
  */
655
665
  blurOnSubmit?: boolean | undefined;
656
666
 
667
+ /**
668
+ * When the return key is pressed,
669
+ *
670
+ * For single line inputs:
671
+ *
672
+ * - `'newline`' defaults to `'blurAndSubmit'`
673
+ * - `undefined` defaults to `'blurAndSubmit'`
674
+ *
675
+ * For multiline inputs:
676
+ *
677
+ * - `'newline'` adds a newline
678
+ * - `undefined` defaults to `'newline'`
679
+ *
680
+ * For both single line and multiline inputs:
681
+ *
682
+ * - `'submit'` will only send a submit event and not blur the input
683
+ * - `'blurAndSubmit`' will both blur the input and send a submit event
684
+ */
685
+ submitBehavior?: SubmitBehavior | undefined;
686
+
657
687
  /**
658
688
  * If true, caret is hidden. The default value is false.
659
689
  */
@@ -9,6 +9,7 @@
9
9
  */
10
10
 
11
11
  import type {HostComponent} from '../../Renderer/shims/ReactNativeTypes';
12
+ import type {____TextStyle_Internal as TextStyleInternal} from '../../StyleSheet/StyleSheetTypes';
12
13
  import type {
13
14
  PressEvent,
14
15
  ScrollEvent,
@@ -17,6 +18,7 @@ import type {
17
18
  import type {ViewProps} from '../View/ViewPropTypes';
18
19
  import type {TextInputType} from './TextInput.flow';
19
20
 
21
+ import * as ReactNativeFeatureFlags from '../../../src/private/featureflags/ReactNativeFeatureFlags';
20
22
  import usePressability from '../../Pressability/usePressability';
21
23
  import flattenStyle from '../../StyleSheet/flattenStyle';
22
24
  import StyleSheet, {
@@ -957,8 +959,188 @@ export type Props = $ReadOnly<{|
957
959
  value?: ?Stringish,
958
960
  |}>;
959
961
 
962
+ type ViewCommands = $NonMaybeType<
963
+ | typeof AndroidTextInputCommands
964
+ | typeof RCTMultilineTextInputNativeCommands
965
+ | typeof RCTSinglelineTextInputNativeCommands,
966
+ >;
967
+
968
+ type LastNativeSelection = {|
969
+ selection: Selection,
970
+ mostRecentEventCount: number,
971
+ |};
972
+
960
973
  const emptyFunctionThatReturnsTrue = () => true;
961
974
 
975
+ /**
976
+ * This hook handles the synchronization between the state of the text input
977
+ * in native and in JavaScript. This is necessary due to the asynchronous nature
978
+ * of text input events.
979
+ */
980
+ function useTextInputStateSynchronization_STATE({
981
+ props,
982
+ mostRecentEventCount,
983
+ selection,
984
+ inputRef,
985
+ text,
986
+ viewCommands,
987
+ }: {
988
+ props: Props,
989
+ mostRecentEventCount: number,
990
+ selection: ?Selection,
991
+ inputRef: React.RefObject<null | React.ElementRef<HostComponent<mixed>>>,
992
+ text: string,
993
+ viewCommands: ViewCommands,
994
+ }): {
995
+ setLastNativeText: string => void,
996
+ setLastNativeSelection: LastNativeSelection => void,
997
+ } {
998
+ const [lastNativeText, setLastNativeText] = useState<?Stringish>(props.value);
999
+ const [lastNativeSelectionState, setLastNativeSelection] =
1000
+ useState<LastNativeSelection>({
1001
+ selection: {start: -1, end: -1},
1002
+ mostRecentEventCount: mostRecentEventCount,
1003
+ });
1004
+
1005
+ const lastNativeSelection = lastNativeSelectionState.selection;
1006
+
1007
+ // This is necessary in case native updates the text and JS decides
1008
+ // that the update should be ignored and we should stick with the value
1009
+ // that we have in JS.
1010
+ useLayoutEffect(() => {
1011
+ const nativeUpdate: {text?: string, selection?: Selection} = {};
1012
+
1013
+ if (lastNativeText !== props.value && typeof props.value === 'string') {
1014
+ nativeUpdate.text = props.value;
1015
+ setLastNativeText(props.value);
1016
+ }
1017
+
1018
+ if (
1019
+ selection &&
1020
+ lastNativeSelection &&
1021
+ (lastNativeSelection.start !== selection.start ||
1022
+ lastNativeSelection.end !== selection.end)
1023
+ ) {
1024
+ nativeUpdate.selection = selection;
1025
+ setLastNativeSelection({selection, mostRecentEventCount});
1026
+ }
1027
+
1028
+ if (Object.keys(nativeUpdate).length === 0) {
1029
+ return;
1030
+ }
1031
+
1032
+ if (inputRef.current != null) {
1033
+ viewCommands.setTextAndSelection(
1034
+ inputRef.current,
1035
+ mostRecentEventCount,
1036
+ text,
1037
+ selection?.start ?? -1,
1038
+ selection?.end ?? -1,
1039
+ );
1040
+ }
1041
+ }, [
1042
+ mostRecentEventCount,
1043
+ inputRef,
1044
+ props.value,
1045
+ props.defaultValue,
1046
+ lastNativeText,
1047
+ selection,
1048
+ lastNativeSelection,
1049
+ text,
1050
+ viewCommands,
1051
+ ]);
1052
+
1053
+ return {setLastNativeText, setLastNativeSelection};
1054
+ }
1055
+
1056
+ /**
1057
+ * This hook handles the synchronization between the state of the text input
1058
+ * in native and in JavaScript. This is necessary due to the asynchronous nature
1059
+ * of text input events.
1060
+ */
1061
+ function useTextInputStateSynchronization_REFS({
1062
+ props,
1063
+ mostRecentEventCount,
1064
+ selection,
1065
+ inputRef,
1066
+ text,
1067
+ viewCommands,
1068
+ }: {
1069
+ props: Props,
1070
+ mostRecentEventCount: number,
1071
+ selection: ?Selection,
1072
+ inputRef: React.RefObject<null | React.ElementRef<HostComponent<mixed>>>,
1073
+ text: string,
1074
+ viewCommands: ViewCommands,
1075
+ }): {
1076
+ setLastNativeText: string => void,
1077
+ setLastNativeSelection: LastNativeSelection => void,
1078
+ } {
1079
+ const lastNativeTextRef = useRef<?Stringish>(props.value);
1080
+ const lastNativeSelectionRef = useRef<LastNativeSelection>({
1081
+ selection: {start: -1, end: -1},
1082
+ mostRecentEventCount: mostRecentEventCount,
1083
+ });
1084
+
1085
+ // This is necessary in case native updates the text and JS decides
1086
+ // that the update should be ignored and we should stick with the value
1087
+ // that we have in JS.
1088
+ useLayoutEffect(() => {
1089
+ const nativeUpdate: {text?: string, selection?: Selection} = {};
1090
+
1091
+ const lastNativeSelection = lastNativeSelectionRef.current.selection;
1092
+
1093
+ if (
1094
+ lastNativeTextRef.current !== props.value &&
1095
+ typeof props.value === 'string'
1096
+ ) {
1097
+ nativeUpdate.text = props.value;
1098
+ lastNativeTextRef.current = props.value;
1099
+ }
1100
+
1101
+ if (
1102
+ selection &&
1103
+ lastNativeSelection &&
1104
+ (lastNativeSelection.start !== selection.start ||
1105
+ lastNativeSelection.end !== selection.end)
1106
+ ) {
1107
+ nativeUpdate.selection = selection;
1108
+ lastNativeSelectionRef.current = {selection, mostRecentEventCount};
1109
+ }
1110
+
1111
+ if (Object.keys(nativeUpdate).length === 0) {
1112
+ return;
1113
+ }
1114
+
1115
+ if (inputRef.current != null) {
1116
+ viewCommands.setTextAndSelection(
1117
+ inputRef.current,
1118
+ mostRecentEventCount,
1119
+ text,
1120
+ selection?.start ?? -1,
1121
+ selection?.end ?? -1,
1122
+ );
1123
+ }
1124
+ }, [
1125
+ mostRecentEventCount,
1126
+ inputRef,
1127
+ props.value,
1128
+ props.defaultValue,
1129
+ selection,
1130
+ text,
1131
+ viewCommands,
1132
+ ]);
1133
+
1134
+ return {
1135
+ setLastNativeText: lastNativeText => {
1136
+ lastNativeTextRef.current = lastNativeText;
1137
+ },
1138
+ setLastNativeSelection: lastNativeSelection => {
1139
+ lastNativeSelectionRef.current = lastNativeSelection;
1140
+ },
1141
+ };
1142
+ }
1143
+
962
1144
  /**
963
1145
  * A foundational component for inputting text into the app via a
964
1146
  * keyboard. Props provide configurability for several features, such as
@@ -1089,7 +1271,6 @@ function InternalTextInput(props: Props): React.Node {
1089
1271
 
1090
1272
  const inputRef = useRef<null | React.ElementRef<HostComponent<mixed>>>(null);
1091
1273
 
1092
- // eslint-disable-next-line react-hooks/exhaustive-deps
1093
1274
  const selection: ?Selection =
1094
1275
  propsSelection == null
1095
1276
  ? null
@@ -1098,28 +1279,6 @@ function InternalTextInput(props: Props): React.Node {
1098
1279
  end: propsSelection.end ?? propsSelection.start,
1099
1280
  };
1100
1281
 
1101
- const [mostRecentEventCount, setMostRecentEventCount] = useState<number>(0);
1102
- const [lastNativeText, setLastNativeText] = useState<?Stringish>(props.value);
1103
- const [lastNativeSelectionState, setLastNativeSelection] = useState<{|
1104
- selection: Selection,
1105
- mostRecentEventCount: number,
1106
- |}>({
1107
- selection: {start: -1, end: -1},
1108
- mostRecentEventCount: mostRecentEventCount,
1109
- });
1110
-
1111
- const lastNativeSelection = lastNativeSelectionState.selection;
1112
-
1113
- let viewCommands;
1114
- if (AndroidTextInputCommands) {
1115
- viewCommands = AndroidTextInputCommands;
1116
- } else {
1117
- viewCommands =
1118
- props.multiline === true
1119
- ? RCTMultilineTextInputNativeCommands
1120
- : RCTSinglelineTextInputNativeCommands;
1121
- }
1122
-
1123
1282
  const text =
1124
1283
  typeof props.value === 'string'
1125
1284
  ? props.value
@@ -1127,51 +1286,26 @@ function InternalTextInput(props: Props): React.Node {
1127
1286
  ? props.defaultValue
1128
1287
  : '';
1129
1288
 
1130
- // This is necessary in case native updates the text and JS decides
1131
- // that the update should be ignored and we should stick with the value
1132
- // that we have in JS.
1133
- useLayoutEffect(() => {
1134
- const nativeUpdate: {text?: string, selection?: Selection} = {};
1135
-
1136
- if (lastNativeText !== props.value && typeof props.value === 'string') {
1137
- nativeUpdate.text = props.value;
1138
- setLastNativeText(props.value);
1139
- }
1140
-
1141
- if (
1142
- selection &&
1143
- lastNativeSelection &&
1144
- (lastNativeSelection.start !== selection.start ||
1145
- lastNativeSelection.end !== selection.end)
1146
- ) {
1147
- nativeUpdate.selection = selection;
1148
- setLastNativeSelection({selection, mostRecentEventCount});
1149
- }
1150
-
1151
- if (Object.keys(nativeUpdate).length === 0) {
1152
- return;
1153
- }
1289
+ const viewCommands =
1290
+ AndroidTextInputCommands ||
1291
+ (props.multiline === true
1292
+ ? RCTMultilineTextInputNativeCommands
1293
+ : RCTSinglelineTextInputNativeCommands);
1154
1294
 
1155
- if (inputRef.current != null) {
1156
- viewCommands.setTextAndSelection(
1157
- inputRef.current,
1158
- mostRecentEventCount,
1159
- text,
1160
- selection?.start ?? -1,
1161
- selection?.end ?? -1,
1162
- );
1163
- }
1164
- }, [
1165
- mostRecentEventCount,
1166
- inputRef,
1167
- props.value,
1168
- props.defaultValue,
1169
- lastNativeText,
1170
- selection,
1171
- lastNativeSelection,
1172
- text,
1173
- viewCommands,
1174
- ]);
1295
+ const [mostRecentEventCount, setMostRecentEventCount] = useState<number>(0);
1296
+ const useTextInputStateSynchronization =
1297
+ ReactNativeFeatureFlags.useRefsForTextInputState()
1298
+ ? useTextInputStateSynchronization_REFS
1299
+ : useTextInputStateSynchronization_STATE;
1300
+ const {setLastNativeText, setLastNativeSelection} =
1301
+ useTextInputStateSynchronization({
1302
+ props,
1303
+ inputRef,
1304
+ mostRecentEventCount,
1305
+ selection,
1306
+ text,
1307
+ viewCommands,
1308
+ });
1175
1309
 
1176
1310
  useLayoutEffect(() => {
1177
1311
  const inputRefValue = inputRef.current;
@@ -1187,7 +1321,7 @@ function InternalTextInput(props: Props): React.Node {
1187
1321
  }
1188
1322
  };
1189
1323
  }
1190
- }, [inputRef]);
1324
+ }, []);
1191
1325
 
1192
1326
  const setLocalRef = useCallback(
1193
1327
  (instance: TextInputInstance | null) => {
@@ -1401,12 +1535,18 @@ function InternalTextInput(props: Props): React.Node {
1401
1535
  };
1402
1536
  }
1403
1537
 
1404
- const style = flattenStyle<TextStyleProp>(props.style);
1405
-
1406
- if (typeof style?.fontWeight === 'number') {
1407
- // $FlowFixMe[prop-missing]
1408
- // $FlowFixMe[cannot-write]
1409
- style.fontWeight = style?.fontWeight.toString();
1538
+ // Keep the original (potentially nested) style when possible, as React can diff these more efficiently
1539
+ let _style = props.style;
1540
+ const flattenedStyle = flattenStyle<TextStyleProp>(props.style);
1541
+ if (typeof flattenedStyle?.fontWeight === 'number') {
1542
+ _style = [
1543
+ _style,
1544
+ {
1545
+ fontWeight:
1546
+ // $FlowFixMe[incompatible-cast]
1547
+ (flattenedStyle.fontWeight.toString(): TextStyleInternal['fontWeight']),
1548
+ },
1549
+ ];
1410
1550
  }
1411
1551
 
1412
1552
  if (Platform.OS === 'ios') {
@@ -1417,10 +1557,10 @@ function InternalTextInput(props: Props): React.Node {
1417
1557
 
1418
1558
  const useMultilineDefaultStyle =
1419
1559
  props.multiline === true &&
1420
- (style == null ||
1421
- (style.padding == null &&
1422
- style.paddingVertical == null &&
1423
- style.paddingTop == null));
1560
+ (flattenedStyle == null ||
1561
+ (flattenedStyle.padding == null &&
1562
+ flattenedStyle.paddingVertical == null &&
1563
+ flattenedStyle.paddingTop == null));
1424
1564
 
1425
1565
  textInput = (
1426
1566
  <RCTTextInputView
@@ -1447,7 +1587,7 @@ function InternalTextInput(props: Props): React.Node {
1447
1587
  selectionColor={selectionColor}
1448
1588
  style={StyleSheet.compose(
1449
1589
  useMultilineDefaultStyle ? styles.multilineDefault : null,
1450
- style,
1590
+ _style,
1451
1591
  )}
1452
1592
  text={text}
1453
1593
  />
@@ -1514,7 +1654,7 @@ function InternalTextInput(props: Props): React.Node {
1514
1654
  onScroll={_onScroll}
1515
1655
  onSelectionChange={_onSelectionChange}
1516
1656
  placeholder={placeholder}
1517
- style={style}
1657
+ style={_style}
1518
1658
  text={text}
1519
1659
  textBreakStrategy={props.textBreakStrategy}
1520
1660
  />