@office-iss/react-native-win32 0.0.0-canary.257 → 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 (73) hide show
  1. package/.flowconfig +3 -3
  2. package/CHANGELOG.json +55 -1
  3. package/CHANGELOG.md +28 -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/ScrollView.js +124 -165
  9. package/Libraries/Components/ScrollView/ScrollViewNativeComponent.js +3 -0
  10. package/Libraries/Components/TextInput/TextInput.js +204 -73
  11. package/Libraries/Components/TextInput/TextInput.win32.js +204 -79
  12. package/Libraries/Components/View/ReactNativeStyleAttributes.js +11 -0
  13. package/Libraries/Core/ErrorHandlers.js +9 -0
  14. package/Libraries/Core/ExceptionsManager.js +2 -0
  15. package/Libraries/Core/InitializeCore.js +2 -0
  16. package/Libraries/Core/ReactFiberErrorDialog.js +3 -0
  17. package/Libraries/Core/ReactNativeVersion.js +3 -3
  18. package/Libraries/Core/ReactNativeVersionCheck.win32.js +1 -1
  19. package/Libraries/Core/setUpGlobals.js +1 -0
  20. package/Libraries/Core/setUpReactRefresh.js +0 -4
  21. package/Libraries/Image/ImageViewNativeComponent.js +1 -0
  22. package/Libraries/Interaction/TaskQueue.js +1 -0
  23. package/Libraries/Lists/SectionList.js +1 -1
  24. package/Libraries/LogBox/Data/LogBoxData.js +1 -0
  25. package/Libraries/LogBox/UI/LogBoxInspectorHeader.js +20 -8
  26. package/Libraries/LogBox/UI/LogBoxInspectorHeader.win32.js +20 -8
  27. package/Libraries/NativeComponent/BaseViewConfig.android.js +1 -0
  28. package/Libraries/NativeComponent/BaseViewConfig.ios.js +3 -0
  29. package/Libraries/NativeComponent/BaseViewConfig.win32.js +3 -0
  30. package/Libraries/NativeComponent/NativeComponentRegistry.js +9 -2
  31. package/Libraries/ReactNative/AppContainer-dev.js +1 -5
  32. package/Libraries/ReactNative/AppContainer-prod.js +1 -5
  33. package/Libraries/ReactNative/AppContainer.js +0 -1
  34. package/Libraries/ReactNative/AppRegistry.js +0 -6
  35. package/Libraries/ReactNative/BridgelessUIManager.js +1 -0
  36. package/Libraries/ReactNative/renderApplication.js +0 -2
  37. package/Libraries/Renderer/shims/ReactNativeTypes.js +3 -1
  38. package/Libraries/StyleSheet/StyleSheetTypes.d.ts +46 -0
  39. package/Libraries/StyleSheet/StyleSheetTypes.js +48 -5
  40. package/Libraries/StyleSheet/processBoxShadow.js +211 -0
  41. package/Libraries/StyleSheet/processFilter.js +226 -41
  42. package/Libraries/Text/Text.js +393 -196
  43. package/Libraries/Text/Text.win32.js +440 -228
  44. package/Libraries/TurboModule/TurboModuleRegistry.js +13 -50
  45. package/Libraries/Types/CodegenTypes.js +3 -1
  46. package/Libraries/Utilities/HMRClient.js +1 -0
  47. package/Libraries/Utilities/Platform.android.js +1 -1
  48. package/Libraries/Utilities/Platform.d.ts +1 -1
  49. package/Libraries/Utilities/Platform.flow.js +2 -2
  50. package/Libraries/Utilities/Platform.flow.win32.js +3 -3
  51. package/Libraries/Utilities/Platform.ios.js +1 -1
  52. package/Libraries/Utilities/Platform.win32.js +1 -1
  53. package/Libraries/vendor/emitter/EventEmitter.js +1 -0
  54. package/index.js +1 -0
  55. package/index.win32.js +1 -0
  56. package/jest/mockComponent.js +4 -1
  57. package/jest/setup.js +8 -1
  58. package/overrides.json +11 -11
  59. package/package.json +23 -23
  60. package/src/private/core/components/HScrollViewNativeComponents.js +55 -0
  61. package/src/private/core/components/VScrollViewNativeComponents.js +47 -0
  62. package/src/private/core/components/useSyncOnScroll.js +48 -0
  63. package/src/private/featureflags/ReactNativeFeatureFlags.js +70 -12
  64. package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +12 -4
  65. package/src/private/specs/modules/NativeLinkingManager.js +1 -1
  66. package/src/private/specs/modules/NativePlatformConstantsAndroid.js +1 -1
  67. package/src/private/specs/modules/NativePlatformConstantsIOS.js +1 -1
  68. package/src/private/specs/modules/NativePlatformConstantsWin.js +8 -1
  69. package/src/private/specs/modules/NativeSampleTurboModule.js +14 -1
  70. package/src/private/webapis/performance/PerformanceEntry.js +1 -1
  71. package/src/private/webapis/performance/RawPerformanceEntry.js +5 -0
  72. package/types/experimental.d.ts +12 -1
  73. package/Libraries/Text/TextOptimized.js +0 -538
@@ -8,8 +8,10 @@
8
8
  * @format
9
9
  */
10
10
 
11
+ import type {____TextStyle_Internal as TextStyleInternal} from '../StyleSheet/StyleSheetTypes';
11
12
  import type {PressEvent} from '../Types/CoreEventTypes';
12
- import type {TextProps} from './TextProps';
13
+ import type {NativeTextProps} from './TextNativeComponent';
14
+ import type {PressRetentionOffset, TextProps} from './TextProps';
13
15
 
14
16
  import * as PressabilityDebug from '../Pressability/PressabilityDebug';
15
17
  import usePressability from '../Pressability/usePressability';
@@ -21,117 +23,399 @@ import {NativeText, NativeVirtualText} from './TextNativeComponent';
21
23
  import * as React from 'react';
22
24
  import {useContext, useMemo, useState} from 'react';
23
25
 
26
+ type TextForwardRef = React.ElementRef<
27
+ typeof NativeText | typeof NativeVirtualText,
28
+ >;
29
+
24
30
  /**
25
31
  * Text is the fundamental component for displaying text.
26
32
  *
27
33
  * @see https://reactnative.dev/docs/text
28
34
  */
29
- const Text: React.AbstractComponent<
30
- TextProps,
31
- React.ElementRef<typeof NativeText | typeof NativeVirtualText>,
32
- > = React.forwardRef((props: TextProps, forwardedRef) => {
33
- const {
34
- accessible,
35
- accessibilityControls, // Win32
36
- accessibilityDescribedBy, // Win32
37
- accessibilityDescription, // Win32
38
- accessibilityLabel,
39
- accessibilityLevel, // Win32
40
- accessibilityPositionInSet, // Win32
41
- accessibilitySetSize, // Win32
42
- accessibilityState,
43
- allowFontScaling,
44
- 'aria-busy': ariaBusy,
45
- 'aria-checked': ariaChecked,
46
- 'aria-controls': ariaControls, // Win32
47
- 'aria-describedby': ariaDescribedBy, // Win32
48
- 'aria-description': ariaDescription, // Win32
49
- 'aria-disabled': ariaDisabled,
50
- 'aria-expanded': ariaExpanded,
51
- 'aria-label': ariaLabel,
52
- 'aria-level': ariaLevel, // Win32
53
- 'aria-multiselectable': ariaMultiselectable, // Win32
54
- 'aria-posinset': ariaPosinset, // Win32
55
- 'aria-required': ariaRequired, // Win32
56
- 'aria-selected': ariaSelected,
57
- 'aria-setsize': ariaSetsize, // Win32
58
- ellipsizeMode,
59
- disabled,
60
- id,
61
- nativeID,
62
- numberOfLines,
63
- onLongPress,
64
- onPress,
65
- onPressIn,
66
- onPressOut,
67
- onResponderGrant,
68
- onResponderMove,
69
- onResponderRelease,
70
- onResponderTerminate,
71
- onResponderTerminationRequest,
72
- onStartShouldSetResponder,
73
- pressRetentionOffset,
74
- selectable,
75
- selectionColor,
76
- suppressHighlighting,
77
- style,
78
- ...restProps
79
- } = props;
35
+ const Text: React.AbstractComponent<TextProps, TextForwardRef> =
36
+ React.forwardRef(
37
+ (
38
+ {
39
+ accessible,
40
+ accessibilityControls, // Win32
41
+ accessibilityDescribedBy, // Win32
42
+ accessibilityDescription, // Win32
43
+ accessibilityLabel,
44
+ accessibilityLevel, // Win32
45
+ accessibilityPositionInSet, // Win32
46
+ accessibilitySetSize, // Win32
47
+ accessibilityState,
48
+ allowFontScaling,
49
+ 'aria-busy': ariaBusy,
50
+ 'aria-checked': ariaChecked,
51
+ 'aria-controls': ariaControls, // Win32
52
+ 'aria-describedby': ariaDescribedBy, // Win32
53
+ 'aria-description': ariaDescription, // Win32
54
+ 'aria-disabled': ariaDisabled,
55
+ 'aria-expanded': ariaExpanded,
56
+ 'aria-label': ariaLabel,
57
+ 'aria-level': ariaLevel, // Win32
58
+ 'aria-multiselectable': ariaMultiselectable, // Win32
59
+ 'aria-posinset': ariaPosinset, // Win32
60
+ 'aria-required': ariaRequired, // Win32
61
+ 'aria-selected': ariaSelected,
62
+ 'aria-setsize': ariaSetsize, // Win32
63
+ children,
64
+ ellipsizeMode,
65
+ disabled,
66
+ id,
67
+ nativeID,
68
+ numberOfLines,
69
+ onLongPress,
70
+ onPress,
71
+ onPressIn,
72
+ onPressOut,
73
+ onResponderGrant,
74
+ onResponderMove,
75
+ onResponderRelease,
76
+ onResponderTerminate,
77
+ onResponderTerminationRequest,
78
+ onStartShouldSetResponder,
79
+ pressRetentionOffset,
80
+ selectable,
81
+ selectionColor,
82
+ suppressHighlighting,
83
+ style,
84
+ ...restProps
85
+ }: TextProps,
86
+ forwardedRef,
87
+ ) => {
88
+ const _accessibilityLabel = ariaLabel ?? accessibilityLabel;
89
+ const _accessibilityControls = ariaControls ?? accessibilityControls; // Win32
90
+ const _accessibilityDescribedBy = ariaDescribedBy ?? accessibilityDescribedBy; // Win32
91
+ const _accessibilityDescription = ariaDescription ?? accessibilityDescription; // Win32
92
+ const _accessibilityLevel = ariaLevel ?? accessibilityLevel; // Win32
93
+ const _accessibilityPositionInSet = ariaPosinset ?? accessibilityPositionInSet; // Win32
94
+ const _accessibilitySetSize = ariaSetsize ?? accessibilitySetSize; // Win32
80
95
 
81
- const [isHighlighted, setHighlighted] = useState(false);
96
+ let _accessibilityState: ?TextProps['accessibilityState'] =
97
+ accessibilityState;
98
+ if (
99
+ ariaBusy != null ||
100
+ ariaChecked != null ||
101
+ ariaDisabled != null ||
102
+ ariaExpanded != null ||
103
+ ariaSelected != null
104
+ ) {
105
+ if (_accessibilityState != null) {
106
+ _accessibilityState = {
107
+ busy: ariaBusy ?? _accessibilityState.busy,
108
+ checked: ariaChecked ?? _accessibilityState.checked,
109
+ disabled: ariaDisabled ?? _accessibilityState.disabled,
110
+ expanded: ariaExpanded ?? _accessibilityState.expanded,
111
+ multiselectable: ariaMultiselectable ?? accessibilityState?.multiselectable, // Win32
112
+ required: ariaRequired ?? accessibilityState?.required, // Win32
113
+ selected: ariaSelected ?? _accessibilityState.selected,
114
+ };
115
+ } else {
116
+ _accessibilityState = {
117
+ busy: ariaBusy,
118
+ checked: ariaChecked,
119
+ disabled: ariaDisabled,
120
+ expanded: ariaExpanded,
121
+ multiselectable: ariaMultiselectable, // Win32,
122
+ required: ariaRequired, // Win32
123
+ selected: ariaSelected,
124
+ };
125
+ }
126
+ }
82
127
 
83
- const _accessibilityLabel = ariaLabel ?? accessibilityLabel;
84
-
85
- let _accessibilityState: ?TextProps['accessibilityState'] =
86
- accessibilityState;
87
- if (
88
- ariaBusy != null ||
89
- ariaChecked != null ||
90
- ariaDisabled != null ||
91
- ariaExpanded != null ||
92
- ariaMultiselectable != null ||
93
- ariaRequired != null ||
94
- ariaSelected != null
95
- ) {
96
- if (_accessibilityState != null) {
97
- _accessibilityState = {
98
- busy: ariaBusy ?? _accessibilityState.busy,
99
- checked: ariaChecked ?? _accessibilityState.checked,
100
- disabled: ariaDisabled ?? _accessibilityState.disabled,
101
- expanded: ariaExpanded ?? _accessibilityState.expanded,
102
- multiselectable:
103
- ariaMultiselectable ?? accessibilityState?.multiselectable, // Win32
104
- required: ariaRequired ?? accessibilityState?.required, // Win32
105
- selected: ariaSelected ?? _accessibilityState.selected,
106
- };
107
- } else {
108
- _accessibilityState = {
109
- busy: ariaBusy,
110
- checked: ariaChecked,
111
- disabled: ariaDisabled,
112
- expanded: ariaExpanded,
113
- multiselectable: ariaMultiselectable, // Win32,
114
- required: ariaRequired, // Win32
115
- selected: ariaSelected,
116
- };
117
- }
118
- }
128
+ const _accessibilityStateDisabled = _accessibilityState?.disabled;
129
+ const _disabled = disabled ?? _accessibilityStateDisabled;
119
130
 
120
- const _accessibilityStateDisabled = _accessibilityState?.disabled;
121
- const _disabled = disabled ?? _accessibilityStateDisabled;
131
+ const isPressable =
132
+ (onPress != null ||
133
+ onLongPress != null ||
134
+ onStartShouldSetResponder != null) &&
135
+ _disabled !== true;
122
136
 
123
- const isPressable =
124
- (onPress != null ||
125
- onLongPress != null ||
126
- onStartShouldSetResponder != null) &&
127
- _disabled !== true;
137
+ // TODO: Move this processing to the view configuration.
138
+ const _selectionColor =
139
+ selectionColor == null ? null : processColor(selectionColor);
128
140
 
129
- const initialized = useLazyInitialization(isPressable);
130
- const config = useMemo(() => {
131
- if (!initialized) {
132
- return null;
141
+ let _style = style;
142
+ if (__DEV__) {
143
+ if (PressabilityDebug.isEnabled() && onPress != null) {
144
+ _style = [style, {color: 'magenta'}];
145
+ }
146
+ }
147
+
148
+ let _numberOfLines = numberOfLines;
149
+ if (_numberOfLines != null && !(_numberOfLines >= 0)) {
150
+ if (__DEV__) {
151
+ console.error(
152
+ `'numberOfLines' in <Text> must be a non-negative number, received: ${_numberOfLines}. The value will be set to 0.`,
153
+ );
154
+ }
155
+ _numberOfLines = 0;
156
+ }
157
+
158
+ let _selectable = selectable;
159
+
160
+ let processedStyle: ?TextStyleInternal = flattenStyle(_style);
161
+ if (processedStyle != null) {
162
+ let overrides: ?{...TextStyleInternal} = null;
163
+ if (typeof processedStyle.fontWeight === 'number') {
164
+ overrides = overrides || ({}: {...TextStyleInternal});
165
+ overrides.fontWeight =
166
+ // $FlowFixMe[incompatible-cast]
167
+ (processedStyle.fontWeight.toString(): TextStyleInternal['fontWeight']);
168
+ }
169
+
170
+ if (processedStyle.userSelect != null) {
171
+ _selectable = userSelectToSelectableMap[processedStyle.userSelect];
172
+ overrides = overrides || ({}: {...TextStyleInternal});
173
+ overrides.userSelect = undefined;
174
+ }
175
+
176
+ if (processedStyle.verticalAlign != null) {
177
+ overrides = overrides || ({}: {...TextStyleInternal});
178
+ overrides.textAlignVertical =
179
+ verticalAlignToTextAlignVerticalMap[processedStyle.verticalAlign];
180
+ overrides.verticalAlign = undefined;
181
+ }
182
+
183
+ if (overrides != null) {
184
+ // $FlowFixMe[incompatible-type]
185
+ processedStyle = [processedStyle, overrides];
186
+ }
187
+ }
188
+
189
+ const _nativeID = id ?? nativeID;
190
+
191
+ const hasTextAncestor = useContext(TextAncestor);
192
+ if (hasTextAncestor) {
193
+ if (isPressable) {
194
+ return (
195
+ <NativePressableVirtualText
196
+ ref={forwardedRef}
197
+ textProps={{
198
+ ...restProps,
199
+ accessibilityLabel: _accessibilityLabel,
200
+ accessibilityState: _accessibilityState,
201
+ accessibilityControls: _accessibilityControls, // Win32
202
+ accessibilityDescribedBy: _accessibilityDescribedBy, // Win32
203
+ accessibilityDescription: _accessibilityDescription, // Win32
204
+ accessibilityLevel: _accessibilityLevel, // Win32
205
+ accessibilityPositionInSet: _accessibilityPositionInSet, // Win32
206
+ accessibilitySetSize: _accessibilitySetSize, // Win32
207
+ nativeID: _nativeID,
208
+ numberOfLines: _numberOfLines,
209
+ selectable: _selectable,
210
+ selectionColor: _selectionColor,
211
+ style: processedStyle,
212
+ disabled: disabled,
213
+ children,
214
+ }}
215
+ textPressabilityProps={{
216
+ onLongPress,
217
+ onPress,
218
+ onPressIn,
219
+ onPressOut,
220
+ onResponderGrant,
221
+ onResponderMove,
222
+ onResponderRelease,
223
+ onResponderTerminate,
224
+ onResponderTerminationRequest,
225
+ onStartShouldSetResponder,
226
+ pressRetentionOffset,
227
+ suppressHighlighting,
228
+ }}
229
+ />
230
+ );
231
+ }
232
+
233
+ return (
234
+ <NativeVirtualText
235
+ {...restProps}
236
+ accessibilityLabel={_accessibilityLabel}
237
+ accessibilityState={_accessibilityState}
238
+ accessibilityControls={_accessibilityControls} // Win32
239
+ accessibilityDescribedBy={_accessibilityDescribedBy} // Win32
240
+ accessibilityDescription={_accessibilityDescription} // Win32
241
+ accessibilityLevel={_accessibilityLevel} // Win32
242
+ accessibilityPositionInSet={_accessibilityPositionInSet} // Win32
243
+ accessibilitySetSize={_accessibilitySetSize} // Win32
244
+ isHighlighted={false}
245
+ isPressable={false}
246
+ nativeID={_nativeID}
247
+ numberOfLines={_numberOfLines}
248
+ ref={forwardedRef}
249
+ selectable={_selectable}
250
+ selectionColor={_selectionColor}
251
+ style={processedStyle}
252
+ disabled={disabled}>
253
+ {children}
254
+ </NativeVirtualText>
255
+ );
256
+ }
257
+
258
+ // If the disabled prop and accessibilityState.disabled are out of sync but not both in
259
+ // falsy states we need to update the accessibilityState object to use the disabled prop.
260
+ if (
261
+ _disabled !== _accessibilityStateDisabled &&
262
+ ((_disabled != null && _disabled !== false) ||
263
+ (_accessibilityStateDisabled != null &&
264
+ _accessibilityStateDisabled !== false))
265
+ ) {
266
+ _accessibilityState = {..._accessibilityState, disabled: _disabled};
267
+ }
268
+
269
+ const _accessible = Platform.select({
270
+ ios: accessible !== false,
271
+ android:
272
+ accessible == null
273
+ ? onPress != null || onLongPress != null
274
+ : accessible,
275
+ default: accessible,
276
+ });
277
+
278
+ let nativeText = null;
279
+ if (isPressable) {
280
+ nativeText = (
281
+ <NativePressableText
282
+ ref={forwardedRef}
283
+ textProps={{
284
+ ...restProps,
285
+ accessibilityLabel: _accessibilityLabel,
286
+ accessibilityState: _accessibilityState,
287
+ accessibilityControls: _accessibilityControls, // Win32
288
+ accessibilityDescribedBy: _accessibilityDescribedBy, // Win32
289
+ accessibilityDescription: _accessibilityDescription, // Win32
290
+ accessibilityLevel: _accessibilityLevel, // Win32
291
+ accessibilityPositionInSet: _accessibilityPositionInSet, // Win32
292
+ accessibilitySetSize: _accessibilitySetSize, // Win32
293
+ accessible: _accessible,
294
+ allowFontScaling: allowFontScaling !== false,
295
+ disabled: _disabled,
296
+ ellipsizeMode: ellipsizeMode ?? 'tail',
297
+ nativeID: _nativeID,
298
+ numberOfLines: _numberOfLines,
299
+ selectable: _selectable,
300
+ selectionColor: _selectionColor,
301
+ style: processedStyle,
302
+ children,
303
+ }}
304
+ textPressabilityProps={{
305
+ onLongPress,
306
+ onPress,
307
+ onPressIn,
308
+ onPressOut,
309
+ onResponderGrant,
310
+ onResponderMove,
311
+ onResponderRelease,
312
+ onResponderTerminate,
313
+ onResponderTerminationRequest,
314
+ onStartShouldSetResponder,
315
+ pressRetentionOffset,
316
+ suppressHighlighting,
317
+ }}
318
+ />
319
+ );
320
+ } else {
321
+ nativeText = (
322
+ <NativeText
323
+ {...restProps}
324
+ accessibilityLabel={_accessibilityLabel}
325
+ accessibilityState={_accessibilityState}
326
+ accessibilityControls={_accessibilityControls} // Win32
327
+ accessibilityDescribedBy={_accessibilityDescribedBy} // Win32
328
+ accessibilityDescription={_accessibilityDescription} // Win32
329
+ accessibilityLevel={_accessibilityLevel} // Win32
330
+ accessibilityPositionInSet={_accessibilityPositionInSet} // Win32
331
+ accessibilitySetSize={_accessibilitySetSize} // Win32
332
+ accessible={_accessible}
333
+ allowFontScaling={allowFontScaling !== false}
334
+ disabled={_disabled}
335
+ ellipsizeMode={ellipsizeMode ?? 'tail'}
336
+ isHighlighted={false}
337
+ nativeID={_nativeID}
338
+ numberOfLines={_numberOfLines}
339
+ ref={forwardedRef}
340
+ selectable={_selectable}
341
+ selectionColor={_selectionColor}
342
+ style={processedStyle}>
343
+ {children}
344
+ </NativeText>
345
+ );
346
+ }
347
+
348
+ if (children == null) {
349
+ return nativeText;
350
+ }
351
+
352
+ // If the children do not contain a JSX element it would not be possible to have a
353
+ // nested `Text` component so we can skip adding the `TextAncestor` context wrapper
354
+ // which has a performance overhead. Since we do this for performance reasons we need
355
+ // to keep the check simple to avoid regressing overall perf. For this reason the
356
+ // `children.length` constant is set to `3`, this should be a reasonable tradeoff
357
+ // to capture the majority of `Text` uses but also not make this check too expensive.
358
+ if (Array.isArray(children) && children.length <= 3) {
359
+ let hasNonTextChild = false;
360
+ for (let child of children) {
361
+ if (child != null && typeof child === 'object') {
362
+ hasNonTextChild = true;
363
+ break;
364
+ }
365
+ }
366
+ if (!hasNonTextChild) {
367
+ return nativeText;
368
+ }
369
+ } else if (typeof children !== 'object') {
370
+ return nativeText;
371
+ }
372
+
373
+ return (
374
+ <TextAncestor.Provider value={true}>{nativeText}</TextAncestor.Provider>
375
+ );
133
376
  }
377
+ );
378
+
379
+ Text.displayName = 'Text';
134
380
 
381
+ type TextPressabilityProps = $ReadOnly<{
382
+ onLongPress?: ?(event: PressEvent) => mixed,
383
+ onPress?: ?(event: PressEvent) => mixed,
384
+ onPressIn?: ?(event: PressEvent) => mixed,
385
+ onPressOut?: ?(event: PressEvent) => mixed,
386
+ onResponderGrant?: ?(event: PressEvent) => void,
387
+ onResponderMove?: ?(event: PressEvent) => void,
388
+ onResponderRelease?: ?(event: PressEvent) => void,
389
+ onResponderTerminate?: ?(event: PressEvent) => void,
390
+ onResponderTerminationRequest?: ?() => boolean,
391
+ onStartShouldSetResponder?: ?() => boolean,
392
+ pressRetentionOffset?: ?PressRetentionOffset,
393
+ suppressHighlighting?: ?boolean,
394
+ }>;
395
+
396
+ /**
397
+ * Hook that handles setting up Pressability of Text components.
398
+ *
399
+ * NOTE: This hook is relatively expensive so it should only be used absolutely necessary.
400
+ */
401
+ function useTextPressability({
402
+ onLongPress,
403
+ onPress,
404
+ onPressIn,
405
+ onPressOut,
406
+ onResponderGrant,
407
+ onResponderMove,
408
+ onResponderRelease,
409
+ onResponderTerminate,
410
+ onResponderTerminationRequest,
411
+ onStartShouldSetResponder,
412
+ pressRetentionOffset,
413
+ suppressHighlighting,
414
+ }: TextPressabilityProps) {
415
+ const [isHighlighted, setHighlighted] = useState(false);
416
+
417
+ // Setup pressability config and wrap callbacks needs to track the highlight state.
418
+ const config = useMemo(() => {
135
419
  let _onPressIn = onPressIn;
136
420
  let _onPressOut = onPressOut;
137
421
 
@@ -151,7 +435,7 @@ const Text: React.AbstractComponent<
151
435
  }
152
436
 
153
437
  return {
154
- disabled: !isPressable,
438
+ disabled: false,
155
439
  pressRectOffset: pressRetentionOffset,
156
440
  onLongPress,
157
441
  onPress,
@@ -159,8 +443,6 @@ const Text: React.AbstractComponent<
159
443
  onPressOut: _onPressOut,
160
444
  };
161
445
  }, [
162
- initialized,
163
- isPressable,
164
446
  pressRetentionOffset,
165
447
  onLongPress,
166
448
  onPress,
@@ -169,7 +451,10 @@ const Text: React.AbstractComponent<
169
451
  suppressHighlighting,
170
452
  ]);
171
453
 
454
+ // Init the pressability class
172
455
  const eventHandlers = usePressability(config);
456
+
457
+ // Create NativeText event handlers which proxy events to pressability
173
458
  const eventHandlersForText = useMemo(
174
459
  () =>
175
460
  eventHandlers == null
@@ -220,140 +505,67 @@ const Text: React.AbstractComponent<
220
505
  ],
221
506
  );
222
507
 
223
- // TODO: Move this processing to the view configuration.
224
- const _selectionColor =
225
- selectionColor == null ? null : processColor(selectionColor);
226
-
227
- let _style = style;
228
- if (__DEV__) {
229
- if (PressabilityDebug.isEnabled() && onPress != null) {
230
- _style = [style, {color: 'magenta'}];
231
- }
232
- }
508
+ // Return the highlight state and NativeText event handlers
509
+ return useMemo(
510
+ () => [isHighlighted, eventHandlersForText],
511
+ [isHighlighted, eventHandlersForText],
512
+ );
513
+ }
233
514
 
234
- let _numberOfLines = numberOfLines;
235
- if (_numberOfLines != null && !(_numberOfLines >= 0)) {
236
- if (__DEV__) {
237
- console.error(
238
- `'numberOfLines' in <Text> must be a non-negative number, received: ${_numberOfLines}. The value will be set to 0.`,
239
- );
240
- }
241
- _numberOfLines = 0;
242
- }
243
-
244
- let _selectable = selectable;
245
- const processedStyle = flattenStyle(_style);
246
- if (processedStyle != null) {
247
- if (typeof processedStyle.fontWeight === 'number') {
248
- // $FlowFixMe[cannot-write]
249
- processedStyle.fontWeight = processedStyle.fontWeight.toString();
250
- }
515
+ type NativePressableTextProps = $ReadOnly<{
516
+ textProps: NativeTextProps,
517
+ textPressabilityProps: TextPressabilityProps,
518
+ }>;
251
519
 
252
- if (processedStyle.userSelect != null) {
253
- _selectable = userSelectToSelectableMap[processedStyle.userSelect];
254
- // $FlowFixMe[cannot-write]
255
- delete processedStyle.userSelect;
256
- }
257
-
258
- if (processedStyle.verticalAlign != null) {
259
- // $FlowFixMe[cannot-write]
260
- processedStyle.textAlignVertical =
261
- verticalAlignToTextAlignVerticalMap[processedStyle.verticalAlign];
262
- // $FlowFixMe[cannot-write]
263
- delete processedStyle.verticalAlign;
264
- }
265
- }
266
-
267
- const _nativeID = id ?? nativeID;
268
-
269
- const hasTextAncestor = useContext(TextAncestor);
270
- if (hasTextAncestor) {
271
- return (
272
- <NativeVirtualText
273
- {...restProps}
274
- {...eventHandlersForText}
275
- accessibilityLabel={_accessibilityLabel}
276
- accessibilityState={_accessibilityState}
277
- accessibilityControls={ariaControls ?? accessibilityControls} // Win32
278
- accessibilityDescribedBy={ariaDescribedBy ?? accessibilityDescribedBy} // Win32
279
- accessibilityDescription={ariaDescription ?? accessibilityDescription} // Win32
280
- accessibilityLevel={ariaLevel ?? accessibilityLevel} // Win32
281
- accessibilityPositionInSet={ariaPosinset ?? accessibilityPositionInSet} // Win32
282
- accessibilitySetSize={ariaSetsize ?? accessibilitySetSize} // Win32
283
- isHighlighted={isHighlighted}
284
- isPressable={isPressable}
285
- nativeID={_nativeID}
286
- numberOfLines={_numberOfLines}
287
- ref={forwardedRef}
288
- selectable={_selectable}
289
- selectionColor={_selectionColor}
290
- style={processedStyle}
291
- disabled={disabled}
292
- />
293
- );
294
- }
295
-
296
- // If the disabled prop and accessibilityState.disabled are out of sync but not both in
297
- // falsy states we need to update the accessibilityState object to use the disabled prop.
298
- if (
299
- _disabled !== _accessibilityStateDisabled &&
300
- ((_disabled != null && _disabled !== false) ||
301
- (_accessibilityStateDisabled != null &&
302
- _accessibilityStateDisabled !== false))
303
- ) {
304
- _accessibilityState = {..._accessibilityState, disabled: _disabled};
305
- }
306
-
307
- const _accessible = Platform.select({
308
- ios: accessible !== false,
309
- android:
310
- accessible == null ? onPress != null || onLongPress != null : accessible,
311
- default: accessible !== false,
312
- });
520
+ /**
521
+ * Wrap the NativeVirtualText component and initialize pressability.
522
+ *
523
+ * This logic is split out from the main Text component to enable the more
524
+ * expensive pressability logic to be only initialized when needed.
525
+ */
526
+ const NativePressableVirtualText: React.AbstractComponent<
527
+ NativePressableTextProps,
528
+ TextForwardRef,
529
+ > = React.forwardRef(({textProps, textPressabilityProps}, forwardedRef) => {
530
+ const [isHighlighted, eventHandlersForText] = useTextPressability(
531
+ textPressabilityProps,
532
+ );
313
533
 
314
534
  return (
315
- <TextAncestor.Provider value={true}>
316
- <NativeText
317
- {...restProps}
318
- {...eventHandlersForText}
319
- accessibilityLabel={_accessibilityLabel}
320
- accessibilityState={_accessibilityState}
321
- accessible={_accessible}
322
- accessibilityControls={ariaControls ?? accessibilityControls} // Win32
323
- accessibilityDescribedBy={ariaDescribedBy ?? accessibilityDescribedBy} // Win32
324
- accessibilityDescription={ariaDescription ?? accessibilityDescription} // Win32
325
- accessibilityLevel={ariaLevel ?? accessibilityLevel} // Win32
326
- accessibilityPositionInSet={ariaPosinset ?? accessibilityPositionInSet} // Win32
327
- accessibilitySetSize={ariaSetsize ?? accessibilitySetSize} // Win32
328
- allowFontScaling={allowFontScaling !== false}
329
- disabled={_disabled}
330
- ellipsizeMode={ellipsizeMode ?? 'tail'}
331
- isHighlighted={isHighlighted}
332
- nativeID={_nativeID}
333
- numberOfLines={_numberOfLines}
334
- ref={forwardedRef}
335
- selectable={_selectable}
336
- selectionColor={_selectionColor}
337
- style={processedStyle}
338
- />
339
- </TextAncestor.Provider>
535
+ <NativeVirtualText
536
+ {...textProps}
537
+ {...eventHandlersForText}
538
+ isHighlighted={isHighlighted}
539
+ isPressable={true}
540
+ ref={forwardedRef}
541
+ />
340
542
  );
341
543
  });
342
544
 
343
- Text.displayName = 'Text';
344
-
345
545
  /**
346
- * Returns false until the first time `newValue` is true, after which this will
347
- * always return true. This is necessary to lazily initialize `Pressability` so
348
- * we do not eagerly create one for every pressable `Text` component.
546
+ * Wrap the NativeText component and initialize pressability.
547
+ *
548
+ * This logic is split out from the main Text component to enable the more
549
+ * expensive pressability logic to be only initialized when needed.
349
550
  */
350
- function useLazyInitialization(newValue: boolean): boolean {
351
- const [oldValue, setValue] = useState(newValue);
352
- if (!oldValue && newValue) {
353
- setValue(newValue);
354
- }
355
- return oldValue;
356
- }
551
+ const NativePressableText: React.AbstractComponent<
552
+ NativePressableTextProps,
553
+ TextForwardRef,
554
+ > = React.forwardRef(({textProps, textPressabilityProps}, forwardedRef) => {
555
+ const [isHighlighted, eventHandlersForText] = useTextPressability(
556
+ textPressabilityProps,
557
+ );
558
+
559
+ return (
560
+ <NativeText
561
+ {...textProps}
562
+ {...eventHandlersForText}
563
+ isHighlighted={isHighlighted}
564
+ isPressable={true}
565
+ ref={forwardedRef}
566
+ />
567
+ );
568
+ });
357
569
 
358
570
  const userSelectToSelectableMap = {
359
571
  auto: true,