@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.
- package/.flowconfig +2 -4
- package/CHANGELOG.json +16 -1
- package/CHANGELOG.md +16 -8
- package/Libraries/Alert/Alert.js +3 -0
- package/Libraries/Animated/nodes/AnimatedValue.js +1 -0
- package/Libraries/Animated/useAnimatedProps.js +68 -3
- package/Libraries/BatchedBridge/NativeModules.js +2 -0
- package/Libraries/Components/ScrollView/ScrollViewNativeComponent.js +3 -0
- package/Libraries/Components/TextInput/TextInput.js +204 -73
- package/Libraries/Components/TextInput/TextInput.win32.js +204 -79
- package/Libraries/Components/View/ReactNativeStyleAttributes.js +11 -0
- package/Libraries/Core/ErrorHandlers.js +9 -0
- package/Libraries/Core/ExceptionsManager.js +2 -0
- package/Libraries/Core/ReactFiberErrorDialog.js +3 -0
- package/Libraries/Core/ReactNativeVersion.js +1 -1
- package/Libraries/Core/setUpReactRefresh.js +0 -4
- package/Libraries/Image/ImageViewNativeComponent.js +1 -0
- package/Libraries/Interaction/TaskQueue.js +1 -0
- package/Libraries/Lists/SectionList.js +1 -1
- package/Libraries/LogBox/Data/LogBoxData.js +1 -0
- package/Libraries/NativeComponent/BaseViewConfig.android.js +1 -0
- package/Libraries/NativeComponent/BaseViewConfig.ios.js +3 -0
- package/Libraries/NativeComponent/BaseViewConfig.win32.js +3 -0
- package/Libraries/NativeComponent/NativeComponentRegistry.js +9 -2
- package/Libraries/ReactNative/BridgelessUIManager.js +1 -0
- package/Libraries/Renderer/shims/ReactNativeTypes.js +3 -1
- package/Libraries/StyleSheet/StyleSheetTypes.d.ts +46 -19
- package/Libraries/StyleSheet/StyleSheetTypes.js +48 -23
- package/Libraries/StyleSheet/processBoxShadow.js +211 -0
- package/Libraries/StyleSheet/processFilter.js +24 -14
- package/Libraries/Text/Text.js +394 -212
- package/Libraries/Text/Text.win32.js +442 -245
- package/Libraries/TurboModule/TurboModuleRegistry.js +13 -50
- package/Libraries/Types/CodegenTypes.js +3 -1
- package/Libraries/Utilities/HMRClient.js +1 -0
- package/Libraries/Utilities/Platform.android.js +1 -1
- package/Libraries/Utilities/Platform.d.ts +1 -1
- package/Libraries/Utilities/Platform.flow.js +2 -2
- package/Libraries/Utilities/Platform.flow.win32.js +3 -3
- package/Libraries/Utilities/Platform.ios.js +1 -1
- package/Libraries/Utilities/Platform.win32.js +1 -1
- package/Libraries/vendor/emitter/EventEmitter.js +1 -0
- package/jest/setup.js +8 -1
- package/overrides.json +9 -9
- package/package.json +12 -12
- package/src/private/featureflags/ReactNativeFeatureFlags.js +65 -18
- package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +11 -4
- package/src/private/specs/modules/NativeLinkingManager.js +1 -1
- package/src/private/specs/modules/NativePlatformConstantsAndroid.js +1 -1
- package/src/private/specs/modules/NativePlatformConstantsIOS.js +1 -1
- package/src/private/specs/modules/NativePlatformConstantsWin.js +8 -1
- package/src/private/webapis/performance/PerformanceEntry.js +1 -1
- package/src/private/webapis/performance/RawPerformanceEntry.js +5 -0
- package/types/experimental.d.ts +12 -1
- 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.
|
|
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,
|
|
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,
|
|
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.
|
|
7
|
+
## 0.0.0-canary.259
|
|
8
8
|
|
|
9
|
-
Thu,
|
|
9
|
+
Thu, 22 Aug 2024 05:23:05 GMT
|
|
10
10
|
|
|
11
11
|
### Changes
|
|
12
12
|
|
|
13
|
-
-
|
|
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
|
package/Libraries/Alert/Alert.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
[
|
|
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
|
|
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
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
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
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
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
|
-
}, [
|
|
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
|
-
|
|
1405
|
-
|
|
1537
|
+
let style = flattenStyle<TextStyleProp>(props.style);
|
|
1406
1538
|
if (typeof style?.fontWeight === 'number') {
|
|
1407
|
-
// $FlowFixMe
|
|
1408
|
-
|
|
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') {
|