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

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 (55) hide show
  1. package/.flowconfig +2 -4
  2. package/CHANGELOG.json +16 -1
  3. package/CHANGELOG.md +16 -8
  4. package/Libraries/Alert/Alert.js +3 -0
  5. package/Libraries/Animated/nodes/AnimatedValue.js +1 -0
  6. package/Libraries/Animated/useAnimatedProps.js +68 -3
  7. package/Libraries/BatchedBridge/NativeModules.js +2 -0
  8. package/Libraries/Components/ScrollView/ScrollViewNativeComponent.js +3 -0
  9. package/Libraries/Components/TextInput/TextInput.js +204 -73
  10. package/Libraries/Components/TextInput/TextInput.win32.js +204 -79
  11. package/Libraries/Components/View/ReactNativeStyleAttributes.js +11 -0
  12. package/Libraries/Core/ErrorHandlers.js +9 -0
  13. package/Libraries/Core/ExceptionsManager.js +2 -0
  14. package/Libraries/Core/ReactFiberErrorDialog.js +3 -0
  15. package/Libraries/Core/ReactNativeVersion.js +1 -1
  16. package/Libraries/Core/setUpReactRefresh.js +0 -4
  17. package/Libraries/Image/ImageViewNativeComponent.js +1 -0
  18. package/Libraries/Interaction/TaskQueue.js +1 -0
  19. package/Libraries/Lists/SectionList.js +1 -1
  20. package/Libraries/LogBox/Data/LogBoxData.js +1 -0
  21. package/Libraries/NativeComponent/BaseViewConfig.android.js +1 -0
  22. package/Libraries/NativeComponent/BaseViewConfig.ios.js +3 -0
  23. package/Libraries/NativeComponent/BaseViewConfig.win32.js +3 -0
  24. package/Libraries/NativeComponent/NativeComponentRegistry.js +9 -2
  25. package/Libraries/ReactNative/BridgelessUIManager.js +1 -0
  26. package/Libraries/Renderer/shims/ReactNativeTypes.js +3 -1
  27. package/Libraries/StyleSheet/StyleSheetTypes.d.ts +46 -19
  28. package/Libraries/StyleSheet/StyleSheetTypes.js +48 -23
  29. package/Libraries/StyleSheet/processBoxShadow.js +211 -0
  30. package/Libraries/StyleSheet/processFilter.js +24 -14
  31. package/Libraries/Text/Text.js +394 -212
  32. package/Libraries/Text/Text.win32.js +442 -245
  33. package/Libraries/TurboModule/TurboModuleRegistry.js +13 -50
  34. package/Libraries/Types/CodegenTypes.js +3 -1
  35. package/Libraries/Utilities/HMRClient.js +1 -0
  36. package/Libraries/Utilities/Platform.android.js +1 -1
  37. package/Libraries/Utilities/Platform.d.ts +1 -1
  38. package/Libraries/Utilities/Platform.flow.js +2 -2
  39. package/Libraries/Utilities/Platform.flow.win32.js +3 -3
  40. package/Libraries/Utilities/Platform.ios.js +1 -1
  41. package/Libraries/Utilities/Platform.win32.js +1 -1
  42. package/Libraries/vendor/emitter/EventEmitter.js +1 -0
  43. package/jest/setup.js +8 -1
  44. package/overrides.json +9 -9
  45. package/package.json +12 -12
  46. package/src/private/featureflags/ReactNativeFeatureFlags.js +65 -18
  47. package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +11 -4
  48. package/src/private/specs/modules/NativeLinkingManager.js +1 -1
  49. package/src/private/specs/modules/NativePlatformConstantsAndroid.js +1 -1
  50. package/src/private/specs/modules/NativePlatformConstantsIOS.js +1 -1
  51. package/src/private/specs/modules/NativePlatformConstantsWin.js +8 -1
  52. package/src/private/webapis/performance/PerformanceEntry.js +1 -1
  53. package/src/private/webapis/performance/RawPerformanceEntry.js +5 -0
  54. package/types/experimental.d.ts +12 -1
  55. package/Libraries/Text/TextOptimized.js +0 -538
package/.flowconfig CHANGED
@@ -127,9 +127,7 @@ module.name_mapper='^@office-iss/react-native-win32$' -> '<PROJECT_ROOT>/index.w
127
127
  module.name_mapper='^react-native/\(.*\)$' -> '<PROJECT_ROOT>/\1'
128
128
  module.name_mapper='^@office-iss/react-native-win32/\(.*\)$' -> '<PROJECT_ROOT>\/1'
129
129
  module.name_mapper='^@react-native/dev-middleware$' -> '<PROJECT_ROOT>/\1'
130
- module.name_mapper='^@?[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '<PROJECT_ROOT>/Libraries/Image/RelativeImageStub'
131
-
132
- one_sided_type_guards=true
130
+ module.name_mapper='^@?[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\|xml\)$' -> '<PROJECT_ROOT>/Libraries/Image/RelativeImageStub'
133
131
 
134
132
  suppress_type=$FlowIssue
135
133
  suppress_type=$FlowFixMe
@@ -161,4 +159,4 @@ untyped-import
161
159
  untyped-type-import
162
160
 
163
161
  [version]
164
- ^0.238.3
162
+ ^0.241.0
package/CHANGELOG.json CHANGED
@@ -2,7 +2,22 @@
2
2
  "name": "@office-iss/react-native-win32",
3
3
  "entries": [
4
4
  {
5
- "date": "Thu, 08 Aug 2024 05:14:50 GMT",
5
+ "date": "Thu, 22 Aug 2024 05:23:05 GMT",
6
+ "version": "0.0.0-canary.259",
7
+ "tag": "@office-iss/react-native-win32_v0.0.0-canary.259",
8
+ "comments": {
9
+ "prerelease": [
10
+ {
11
+ "author": "tatianakapos@microsoft.com",
12
+ "package": "@office-iss/react-native-win32",
13
+ "commit": "bccbec07eeeda80b870765f2b207a6616b69732b",
14
+ "comment": "integrate react native nightly 7-19"
15
+ }
16
+ ]
17
+ }
18
+ },
19
+ {
20
+ "date": "Thu, 08 Aug 2024 05:16:47 GMT",
6
21
  "version": "0.0.0-canary.258",
7
22
  "tag": "@office-iss/react-native-win32_v0.0.0-canary.258",
8
23
  "comments": {
package/CHANGELOG.md CHANGED
@@ -1,21 +1,29 @@
1
1
  # Change Log - @office-iss/react-native-win32
2
2
 
3
- This log was last generated on Thu, 08 Aug 2024 05:14:50 GMT and should not be manually modified.
3
+ This log was last generated on Thu, 22 Aug 2024 05:23:05 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
- ## 0.0.0-canary.258
7
+ ## 0.0.0-canary.259
8
8
 
9
- Thu, 08 Aug 2024 05:14:50 GMT
9
+ Thu, 22 Aug 2024 05:23:05 GMT
10
10
 
11
11
  ### Changes
12
12
 
13
- - Integrate 7/1 (jthysell@microsoft.com)
14
- - Bump @rnw-scripts/eslint-config to v1.2.26
15
- - Bump @rnw-scripts/jest-out-of-tree-snapshot-resolver to v1.1.30
16
- - Bump @rnw-scripts/just-task to v2.3.43
17
- - Bump react-native-platform-override to v1.9.45
13
+ - integrate react native nightly 7-19 (tatianakapos@microsoft.com)
18
14
 
15
+ ## 0.0.0-canary.258
16
+
17
+ Thu, 08 Aug 2024 05:16:47 GMT
18
+
19
+ ### Changes
20
+
21
+ - Integrate 7/1 (jthysell@microsoft.com)
22
+ - Bump @rnw-scripts/eslint-config to v1.2.26
23
+ - Bump @rnw-scripts/jest-out-of-tree-snapshot-resolver to v1.1.30
24
+ - Bump @rnw-scripts/just-task to v2.3.43
25
+ - Bump react-native-platform-override to v1.9.45
26
+
19
27
  ## 0.0.0-canary.257
20
28
 
21
29
  Wed, 24 Jul 2024 05:24:34 GMT
@@ -98,10 +98,13 @@ class Alert {
98
98
  const onAction = (action, buttonKey) => {
99
99
  if (action === constants.buttonClicked) {
100
100
  if (buttonKey === constants.buttonNeutral) {
101
+ // $FlowFixMe[incompatible-type]
101
102
  buttonNeutral.onPress && buttonNeutral.onPress();
102
103
  } else if (buttonKey === constants.buttonNegative) {
104
+ // $FlowFixMe[incompatible-type]
103
105
  buttonNegative.onPress && buttonNegative.onPress();
104
106
  } else if (buttonKey === constants.buttonPositive) {
107
+ // $FlowFixMe[incompatible-type]
105
108
  buttonPositive.onPress && buttonPositive.onPress();
106
109
  }
107
110
  } else if (action === constants.dismissed) {
@@ -49,6 +49,7 @@ const NativeAnimatedAPI = NativeAnimatedHelper.API;
49
49
  * transform which can receive values from multiple parents.
50
50
  */
51
51
  export function flushValue(rootNode: AnimatedNode): void {
52
+ // eslint-disable-next-line func-call-spacing
52
53
  const leaves = new Set<{update: () => void, ...}>();
53
54
  function findAnimatedStyles(node: AnimatedNode) {
54
55
  // $FlowFixMe[prop-missing]
@@ -49,6 +49,14 @@ export default function useAnimatedProps<TProps: {...}, TInstance>(
49
49
  );
50
50
  const useNativePropsInFabric =
51
51
  ReactNativeFeatureFlags.shouldUseSetNativePropsInFabric();
52
+ const useSetNativePropsInNativeAnimationsInFabric =
53
+ ReactNativeFeatureFlags.shouldUseSetNativePropsInNativeAnimationsInFabric();
54
+
55
+ const useAnimatedPropsLifecycle =
56
+ ReactNativeFeatureFlags.usePassiveEffectsForAnimations()
57
+ ? useAnimatedPropsLifecycle_passiveEffects
58
+ : useAnimatedPropsLifecycle_layoutEffects;
59
+
52
60
  useAnimatedPropsLifecycle(node);
53
61
 
54
62
  // TODO: This "effect" does three things:
@@ -87,7 +95,12 @@ export default function useAnimatedProps<TProps: {...}, TInstance>(
87
95
  if (isFabricNode) {
88
96
  // Call `scheduleUpdate` to synchronise Fiber and Shadow tree.
89
97
  // Must not be called in Paper.
90
- scheduleUpdate();
98
+ if (useSetNativePropsInNativeAnimationsInFabric) {
99
+ // $FlowFixMe[incompatible-use]
100
+ instance.setNativeProps(node.__getAnimatedValue());
101
+ } else {
102
+ scheduleUpdate();
103
+ }
91
104
  }
92
105
  return;
93
106
  }
@@ -157,7 +170,12 @@ export default function useAnimatedProps<TProps: {...}, TInstance>(
157
170
  }
158
171
  };
159
172
  },
160
- [props, node, useNativePropsInFabric],
173
+ [
174
+ node,
175
+ useNativePropsInFabric,
176
+ useSetNativePropsInNativeAnimationsInFabric,
177
+ props,
178
+ ],
161
179
  );
162
180
  const callbackRef = useRefEffect<TInstance>(refEffect);
163
181
 
@@ -182,7 +200,7 @@ function reduceAnimatedProps<TProps>(
182
200
  * nodes. So in order to optimize this, we avoid detaching until the next attach
183
201
  * unless we are unmounting.
184
202
  */
185
- function useAnimatedPropsLifecycle(node: AnimatedProps): void {
203
+ function useAnimatedPropsLifecycle_layoutEffects(node: AnimatedProps): void {
186
204
  const prevNodeRef = useRef<?AnimatedProps>(null);
187
205
  const isUnmountingRef = useRef<boolean>(false);
188
206
 
@@ -220,6 +238,53 @@ function useAnimatedPropsLifecycle(node: AnimatedProps): void {
220
238
  }, [node]);
221
239
  }
222
240
 
241
+ /**
242
+ * Manages the lifecycle of the supplied `AnimatedProps` by invoking `__attach`
243
+ * and `__detach`. However, this is more complicated because `AnimatedProps`
244
+ * uses reference counting to determine when to recursively detach its children
245
+ * nodes. So in order to optimize this, we avoid detaching until the next attach
246
+ * unless we are unmounting.
247
+ *
248
+ * NOTE: unlike `useAnimatedPropsLifecycle_layoutEffects`, this version uses passive effects to setup animation graph.
249
+ */
250
+ function useAnimatedPropsLifecycle_passiveEffects(node: AnimatedProps): void {
251
+ const prevNodeRef = useRef<?AnimatedProps>(null);
252
+ const isUnmountingRef = useRef<boolean>(false);
253
+
254
+ useEffect(() => {
255
+ // It is ok for multiple components to call `flushQueue` because it noops
256
+ // if the queue is empty. When multiple animated components are mounted at
257
+ // the same time. Only first component flushes the queue and the others will noop.
258
+ NativeAnimatedHelper.API.flushQueue();
259
+ });
260
+
261
+ useEffect(() => {
262
+ isUnmountingRef.current = false;
263
+ return () => {
264
+ isUnmountingRef.current = true;
265
+ };
266
+ }, []);
267
+
268
+ useEffect(() => {
269
+ node.__attach();
270
+ if (prevNodeRef.current != null) {
271
+ const prevNode = prevNodeRef.current;
272
+ // TODO: Stop restoring default values (unless `reset` is called).
273
+ prevNode.__restoreDefaultValues();
274
+ prevNode.__detach();
275
+ prevNodeRef.current = null;
276
+ }
277
+ return () => {
278
+ if (isUnmountingRef.current) {
279
+ // NOTE: Do not restore default values on unmount, see D18197735.
280
+ node.__detach();
281
+ } else {
282
+ prevNodeRef.current = node;
283
+ }
284
+ };
285
+ }, [node]);
286
+ }
287
+
223
288
  function getEventTarget<TInstance>(instance: TInstance): TInstance {
224
289
  return typeof instance === 'object' &&
225
290
  typeof instance?.getScrollableNode === 'function'
@@ -102,6 +102,7 @@ function genMethod(moduleID: number, methodID: number, type: MethodType) {
102
102
  // In case we reject, capture a useful stack trace here.
103
103
  /* $FlowFixMe[class-object-subtyping] added when improving typing for
104
104
  * this parameters */
105
+ // $FlowFixMe[incompatible-type]
105
106
  const enqueueingFrameError: ExtendedError = new Error();
106
107
  return new Promise((resolve, reject) => {
107
108
  BatchedBridge.enqueueNativeCall(
@@ -171,6 +172,7 @@ function updateErrorWithErrorData(
171
172
  ): ExtendedError {
172
173
  /* $FlowFixMe[class-object-subtyping] added when improving typing for this
173
174
  * parameters */
175
+ // $FlowFixMe[incompatible-return]
174
176
  return Object.assign(error, errorData || {});
175
177
  }
176
178
 
@@ -62,6 +62,9 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig =
62
62
  borderRadius: true,
63
63
  nestedScrollEnabled: true,
64
64
  scrollEventThrottle: true,
65
+ scrollIndicatorInsets: {
66
+ diff: require('../../Utilities/differ/insetsDiffer'),
67
+ },
65
68
  borderStyle: true,
66
69
  borderRightColor: {
67
70
  process: require('../../StyleSheet/processColor').default,
@@ -17,6 +17,7 @@ import type {
17
17
  import type {ViewProps} from '../View/ViewPropTypes';
18
18
  import type {TextInputType} from './TextInput.flow';
19
19
 
20
+ import * as ReactNativeFeatureFlags from '../../../src/private/featureflags/ReactNativeFeatureFlags';
20
21
  import usePressability from '../../Pressability/usePressability';
21
22
  import flattenStyle from '../../StyleSheet/flattenStyle';
22
23
  import StyleSheet, {
@@ -957,8 +958,188 @@ export type Props = $ReadOnly<{|
957
958
  value?: ?Stringish,
958
959
  |}>;
959
960
 
961
+ type ViewCommands = $NonMaybeType<
962
+ | typeof AndroidTextInputCommands
963
+ | typeof RCTMultilineTextInputNativeCommands
964
+ | typeof RCTSinglelineTextInputNativeCommands,
965
+ >;
966
+
967
+ type LastNativeSelection = {|
968
+ selection: Selection,
969
+ mostRecentEventCount: number,
970
+ |};
971
+
960
972
  const emptyFunctionThatReturnsTrue = () => true;
961
973
 
974
+ /**
975
+ * This hook handles the synchronization between the state of the text input
976
+ * in native and in JavaScript. This is necessary due to the asynchronous nature
977
+ * of text input events.
978
+ */
979
+ function useTextInputStateSynchronization_STATE({
980
+ props,
981
+ mostRecentEventCount,
982
+ selection,
983
+ inputRef,
984
+ text,
985
+ viewCommands,
986
+ }: {
987
+ props: Props,
988
+ mostRecentEventCount: number,
989
+ selection: ?Selection,
990
+ inputRef: React.RefObject<null | React.ElementRef<HostComponent<mixed>>>,
991
+ text: string,
992
+ viewCommands: ViewCommands,
993
+ }): {
994
+ setLastNativeText: string => void,
995
+ setLastNativeSelection: LastNativeSelection => void,
996
+ } {
997
+ const [lastNativeText, setLastNativeText] = useState<?Stringish>(props.value);
998
+ const [lastNativeSelectionState, setLastNativeSelection] =
999
+ useState<LastNativeSelection>({
1000
+ selection: {start: -1, end: -1},
1001
+ mostRecentEventCount: mostRecentEventCount,
1002
+ });
1003
+
1004
+ const lastNativeSelection = lastNativeSelectionState.selection;
1005
+
1006
+ // This is necessary in case native updates the text and JS decides
1007
+ // that the update should be ignored and we should stick with the value
1008
+ // that we have in JS.
1009
+ useLayoutEffect(() => {
1010
+ const nativeUpdate: {text?: string, selection?: Selection} = {};
1011
+
1012
+ if (lastNativeText !== props.value && typeof props.value === 'string') {
1013
+ nativeUpdate.text = props.value;
1014
+ setLastNativeText(props.value);
1015
+ }
1016
+
1017
+ if (
1018
+ selection &&
1019
+ lastNativeSelection &&
1020
+ (lastNativeSelection.start !== selection.start ||
1021
+ lastNativeSelection.end !== selection.end)
1022
+ ) {
1023
+ nativeUpdate.selection = selection;
1024
+ setLastNativeSelection({selection, mostRecentEventCount});
1025
+ }
1026
+
1027
+ if (Object.keys(nativeUpdate).length === 0) {
1028
+ return;
1029
+ }
1030
+
1031
+ if (inputRef.current != null) {
1032
+ viewCommands.setTextAndSelection(
1033
+ inputRef.current,
1034
+ mostRecentEventCount,
1035
+ text,
1036
+ selection?.start ?? -1,
1037
+ selection?.end ?? -1,
1038
+ );
1039
+ }
1040
+ }, [
1041
+ mostRecentEventCount,
1042
+ inputRef,
1043
+ props.value,
1044
+ props.defaultValue,
1045
+ lastNativeText,
1046
+ selection,
1047
+ lastNativeSelection,
1048
+ text,
1049
+ viewCommands,
1050
+ ]);
1051
+
1052
+ return {setLastNativeText, setLastNativeSelection};
1053
+ }
1054
+
1055
+ /**
1056
+ * This hook handles the synchronization between the state of the text input
1057
+ * in native and in JavaScript. This is necessary due to the asynchronous nature
1058
+ * of text input events.
1059
+ */
1060
+ function useTextInputStateSynchronization_REFS({
1061
+ props,
1062
+ mostRecentEventCount,
1063
+ selection,
1064
+ inputRef,
1065
+ text,
1066
+ viewCommands,
1067
+ }: {
1068
+ props: Props,
1069
+ mostRecentEventCount: number,
1070
+ selection: ?Selection,
1071
+ inputRef: React.RefObject<null | React.ElementRef<HostComponent<mixed>>>,
1072
+ text: string,
1073
+ viewCommands: ViewCommands,
1074
+ }): {
1075
+ setLastNativeText: string => void,
1076
+ setLastNativeSelection: LastNativeSelection => void,
1077
+ } {
1078
+ const lastNativeTextRef = useRef<?Stringish>(props.value);
1079
+ const lastNativeSelectionRef = useRef<LastNativeSelection>({
1080
+ selection: {start: -1, end: -1},
1081
+ mostRecentEventCount: mostRecentEventCount,
1082
+ });
1083
+
1084
+ // This is necessary in case native updates the text and JS decides
1085
+ // that the update should be ignored and we should stick with the value
1086
+ // that we have in JS.
1087
+ useLayoutEffect(() => {
1088
+ const nativeUpdate: {text?: string, selection?: Selection} = {};
1089
+
1090
+ const lastNativeSelection = lastNativeSelectionRef.current.selection;
1091
+
1092
+ if (
1093
+ lastNativeTextRef.current !== props.value &&
1094
+ typeof props.value === 'string'
1095
+ ) {
1096
+ nativeUpdate.text = props.value;
1097
+ lastNativeTextRef.current = props.value;
1098
+ }
1099
+
1100
+ if (
1101
+ selection &&
1102
+ lastNativeSelection &&
1103
+ (lastNativeSelection.start !== selection.start ||
1104
+ lastNativeSelection.end !== selection.end)
1105
+ ) {
1106
+ nativeUpdate.selection = selection;
1107
+ lastNativeSelectionRef.current = {selection, mostRecentEventCount};
1108
+ }
1109
+
1110
+ if (Object.keys(nativeUpdate).length === 0) {
1111
+ return;
1112
+ }
1113
+
1114
+ if (inputRef.current != null) {
1115
+ viewCommands.setTextAndSelection(
1116
+ inputRef.current,
1117
+ mostRecentEventCount,
1118
+ text,
1119
+ selection?.start ?? -1,
1120
+ selection?.end ?? -1,
1121
+ );
1122
+ }
1123
+ }, [
1124
+ mostRecentEventCount,
1125
+ inputRef,
1126
+ props.value,
1127
+ props.defaultValue,
1128
+ selection,
1129
+ text,
1130
+ viewCommands,
1131
+ ]);
1132
+
1133
+ return {
1134
+ setLastNativeText: lastNativeText => {
1135
+ lastNativeTextRef.current = lastNativeText;
1136
+ },
1137
+ setLastNativeSelection: lastNativeSelection => {
1138
+ lastNativeSelectionRef.current = lastNativeSelection;
1139
+ },
1140
+ };
1141
+ }
1142
+
962
1143
  /**
963
1144
  * A foundational component for inputting text into the app via a
964
1145
  * keyboard. Props provide configurability for several features, such as
@@ -1089,7 +1270,6 @@ function InternalTextInput(props: Props): React.Node {
1089
1270
 
1090
1271
  const inputRef = useRef<null | React.ElementRef<HostComponent<mixed>>>(null);
1091
1272
 
1092
- // eslint-disable-next-line react-hooks/exhaustive-deps
1093
1273
  const selection: ?Selection =
1094
1274
  propsSelection == null
1095
1275
  ? null
@@ -1098,28 +1278,6 @@ function InternalTextInput(props: Props): React.Node {
1098
1278
  end: propsSelection.end ?? propsSelection.start,
1099
1279
  };
1100
1280
 
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
1281
  const text =
1124
1282
  typeof props.value === 'string'
1125
1283
  ? props.value
@@ -1127,51 +1285,26 @@ function InternalTextInput(props: Props): React.Node {
1127
1285
  ? props.defaultValue
1128
1286
  : '';
1129
1287
 
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
- }
1288
+ const viewCommands =
1289
+ AndroidTextInputCommands ||
1290
+ (props.multiline === true
1291
+ ? RCTMultilineTextInputNativeCommands
1292
+ : RCTSinglelineTextInputNativeCommands);
1150
1293
 
1151
- if (Object.keys(nativeUpdate).length === 0) {
1152
- return;
1153
- }
1154
-
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
- ]);
1294
+ const [mostRecentEventCount, setMostRecentEventCount] = useState<number>(0);
1295
+ const useTextInputStateSynchronization =
1296
+ ReactNativeFeatureFlags.useRefsForTextInputState()
1297
+ ? useTextInputStateSynchronization_REFS
1298
+ : useTextInputStateSynchronization_STATE;
1299
+ const {setLastNativeText, setLastNativeSelection} =
1300
+ useTextInputStateSynchronization({
1301
+ props,
1302
+ inputRef,
1303
+ mostRecentEventCount,
1304
+ selection,
1305
+ text,
1306
+ viewCommands,
1307
+ });
1175
1308
 
1176
1309
  useLayoutEffect(() => {
1177
1310
  const inputRefValue = inputRef.current;
@@ -1187,7 +1320,7 @@ function InternalTextInput(props: Props): React.Node {
1187
1320
  }
1188
1321
  };
1189
1322
  }
1190
- }, [inputRef]);
1323
+ }, []);
1191
1324
 
1192
1325
  const setLocalRef = useCallback(
1193
1326
  (instance: TextInputInstance | null) => {
@@ -1401,12 +1534,10 @@ function InternalTextInput(props: Props): React.Node {
1401
1534
  };
1402
1535
  }
1403
1536
 
1404
- const style = flattenStyle<TextStyleProp>(props.style);
1405
-
1537
+ let style = flattenStyle<TextStyleProp>(props.style);
1406
1538
  if (typeof style?.fontWeight === 'number') {
1407
- // $FlowFixMe[prop-missing]
1408
- // $FlowFixMe[cannot-write]
1409
- style.fontWeight = style?.fontWeight.toString();
1539
+ // $FlowFixMe
1540
+ style = [style, {fontWeight: style.fontWeight.toString()}];
1410
1541
  }
1411
1542
 
1412
1543
  if (Platform.OS === 'ios') {