@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
@@ -8,10 +8,12 @@
8
8
  * @format
9
9
  */
10
10
 
11
+ import type {TextStyleProp} from '../StyleSheet/StyleSheet';
12
+ import type {____TextStyle_Internal as TextStyleInternal} from '../StyleSheet/StyleSheetTypes';
11
13
  import type {PressEvent} from '../Types/CoreEventTypes';
12
- import type {TextProps} from './TextProps';
14
+ import type {NativeTextProps} from './TextNativeComponent';
15
+ import type {PressRetentionOffset, TextProps} from './TextProps';
13
16
 
14
- import * as ReactNativeFeatureFlags from '../../src/private/featureflags/ReactNativeFeatureFlags';
15
17
  import * as PressabilityDebug from '../Pressability/PressabilityDebug';
16
18
  import usePressability from '../Pressability/usePressability';
17
19
  import flattenStyle from '../StyleSheet/flattenStyle';
@@ -19,100 +21,354 @@ import processColor from '../StyleSheet/processColor';
19
21
  import Platform from '../Utilities/Platform';
20
22
  import TextAncestor from './TextAncestor';
21
23
  import {NativeText, NativeVirtualText} from './TextNativeComponent';
22
- import TextOptimized from './TextOptimized';
23
24
  import * as React from 'react';
24
25
  import {useContext, useMemo, useState} from 'react';
25
26
 
27
+ type TextForwardRef = React.ElementRef<
28
+ typeof NativeText | typeof NativeVirtualText,
29
+ >;
30
+
26
31
  /**
27
32
  * Text is the fundamental component for displaying text.
28
33
  *
29
34
  * @see https://reactnative.dev/docs/text
30
35
  */
31
- const TextLegacy: React.AbstractComponent<
32
- TextProps,
33
- React.ElementRef<typeof NativeText | typeof NativeVirtualText>,
34
- > = React.forwardRef((props: TextProps, forwardedRef) => {
35
- const {
36
- accessible,
37
- accessibilityLabel,
38
- accessibilityState,
39
- allowFontScaling,
40
- 'aria-busy': ariaBusy,
41
- 'aria-checked': ariaChecked,
42
- 'aria-disabled': ariaDisabled,
43
- 'aria-expanded': ariaExpanded,
44
- 'aria-label': ariaLabel,
45
- 'aria-selected': ariaSelected,
46
- ellipsizeMode,
47
- disabled,
48
- id,
49
- nativeID,
50
- numberOfLines,
51
- onLongPress,
52
- onPress,
53
- onPressIn,
54
- onPressOut,
55
- onResponderGrant,
56
- onResponderMove,
57
- onResponderRelease,
58
- onResponderTerminate,
59
- onResponderTerminationRequest,
60
- onStartShouldSetResponder,
61
- pressRetentionOffset,
62
- selectable,
63
- selectionColor,
64
- suppressHighlighting,
65
- style,
66
- ...restProps
67
- } = props;
68
-
69
- const [isHighlighted, setHighlighted] = useState(false);
36
+ const Text: React.AbstractComponent<TextProps, TextForwardRef> =
37
+ React.forwardRef(
38
+ (
39
+ {
40
+ accessible,
41
+ accessibilityLabel,
42
+ accessibilityState,
43
+ allowFontScaling,
44
+ 'aria-busy': ariaBusy,
45
+ 'aria-checked': ariaChecked,
46
+ 'aria-disabled': ariaDisabled,
47
+ 'aria-expanded': ariaExpanded,
48
+ 'aria-label': ariaLabel,
49
+ 'aria-selected': ariaSelected,
50
+ children,
51
+ ellipsizeMode,
52
+ disabled,
53
+ id,
54
+ nativeID,
55
+ numberOfLines,
56
+ onLongPress,
57
+ onPress,
58
+ onPressIn,
59
+ onPressOut,
60
+ onResponderGrant,
61
+ onResponderMove,
62
+ onResponderRelease,
63
+ onResponderTerminate,
64
+ onResponderTerminationRequest,
65
+ onStartShouldSetResponder,
66
+ pressRetentionOffset,
67
+ selectable,
68
+ selectionColor,
69
+ suppressHighlighting,
70
+ style,
71
+ ...restProps
72
+ }: TextProps,
73
+ forwardedRef,
74
+ ) => {
75
+ const _accessibilityLabel = ariaLabel ?? accessibilityLabel;
76
+
77
+ let _accessibilityState: ?TextProps['accessibilityState'] =
78
+ accessibilityState;
79
+ if (
80
+ ariaBusy != null ||
81
+ ariaChecked != null ||
82
+ ariaDisabled != null ||
83
+ ariaExpanded != null ||
84
+ ariaSelected != null
85
+ ) {
86
+ if (_accessibilityState != null) {
87
+ _accessibilityState = {
88
+ busy: ariaBusy ?? _accessibilityState.busy,
89
+ checked: ariaChecked ?? _accessibilityState.checked,
90
+ disabled: ariaDisabled ?? _accessibilityState.disabled,
91
+ expanded: ariaExpanded ?? _accessibilityState.expanded,
92
+ selected: ariaSelected ?? _accessibilityState.selected,
93
+ };
94
+ } else {
95
+ _accessibilityState = {
96
+ busy: ariaBusy,
97
+ checked: ariaChecked,
98
+ disabled: ariaDisabled,
99
+ expanded: ariaExpanded,
100
+ selected: ariaSelected,
101
+ };
102
+ }
103
+ }
104
+
105
+ const _accessibilityStateDisabled = _accessibilityState?.disabled;
106
+ const _disabled = disabled ?? _accessibilityStateDisabled;
107
+
108
+ const isPressable =
109
+ (onPress != null ||
110
+ onLongPress != null ||
111
+ onStartShouldSetResponder != null) &&
112
+ _disabled !== true;
113
+
114
+ // TODO: Move this processing to the view configuration.
115
+ const _selectionColor =
116
+ selectionColor == null ? null : processColor(selectionColor);
117
+
118
+ let _style = style;
119
+ if (__DEV__) {
120
+ if (PressabilityDebug.isEnabled() && onPress != null) {
121
+ _style = [style, {color: 'magenta'}];
122
+ }
123
+ }
124
+
125
+ let _numberOfLines = numberOfLines;
126
+ if (_numberOfLines != null && !(_numberOfLines >= 0)) {
127
+ if (__DEV__) {
128
+ console.error(
129
+ `'numberOfLines' in <Text> must be a non-negative number, received: ${_numberOfLines}. The value will be set to 0.`,
130
+ );
131
+ }
132
+ _numberOfLines = 0;
133
+ }
134
+
135
+ let _selectable = selectable;
136
+
137
+ let processedStyle = flattenStyle<TextStyleProp>(_style);
138
+ if (processedStyle != null) {
139
+ let overrides: ?{...TextStyleInternal} = null;
140
+ if (typeof processedStyle.fontWeight === 'number') {
141
+ overrides = overrides || ({}: {...TextStyleInternal});
142
+ overrides.fontWeight =
143
+ // $FlowFixMe[incompatible-cast]
144
+ (processedStyle.fontWeight.toString(): TextStyleInternal['fontWeight']);
145
+ }
146
+
147
+ if (processedStyle.userSelect != null) {
148
+ _selectable = userSelectToSelectableMap[processedStyle.userSelect];
149
+ overrides = overrides || ({}: {...TextStyleInternal});
150
+ overrides.userSelect = undefined;
151
+ }
152
+
153
+ if (processedStyle.verticalAlign != null) {
154
+ overrides = overrides || ({}: {...TextStyleInternal});
155
+ overrides.textAlignVertical =
156
+ verticalAlignToTextAlignVerticalMap[processedStyle.verticalAlign];
157
+ overrides.verticalAlign = undefined;
158
+ }
159
+
160
+ if (overrides != null) {
161
+ // $FlowFixMe[incompatible-type]
162
+ _style = [_style, overrides];
163
+ }
164
+ }
165
+
166
+ const _nativeID = id ?? nativeID;
167
+
168
+ const hasTextAncestor = useContext(TextAncestor);
169
+ if (hasTextAncestor) {
170
+ if (isPressable) {
171
+ return (
172
+ <NativePressableVirtualText
173
+ ref={forwardedRef}
174
+ textProps={{
175
+ ...restProps,
176
+ accessibilityLabel: _accessibilityLabel,
177
+ accessibilityState: _accessibilityState,
178
+ nativeID: _nativeID,
179
+ numberOfLines: _numberOfLines,
180
+ selectable: _selectable,
181
+ selectionColor: _selectionColor,
182
+ style: _style,
183
+ disabled: disabled,
184
+ children,
185
+ }}
186
+ textPressabilityProps={{
187
+ onLongPress,
188
+ onPress,
189
+ onPressIn,
190
+ onPressOut,
191
+ onResponderGrant,
192
+ onResponderMove,
193
+ onResponderRelease,
194
+ onResponderTerminate,
195
+ onResponderTerminationRequest,
196
+ onStartShouldSetResponder,
197
+ pressRetentionOffset,
198
+ suppressHighlighting,
199
+ }}
200
+ />
201
+ );
202
+ }
203
+
204
+ return (
205
+ <NativeVirtualText
206
+ {...restProps}
207
+ accessibilityLabel={_accessibilityLabel}
208
+ accessibilityState={_accessibilityState}
209
+ isHighlighted={false}
210
+ isPressable={false}
211
+ nativeID={_nativeID}
212
+ numberOfLines={_numberOfLines}
213
+ ref={forwardedRef}
214
+ selectable={_selectable}
215
+ selectionColor={_selectionColor}
216
+ style={_style}
217
+ disabled={disabled}>
218
+ {children}
219
+ </NativeVirtualText>
220
+ );
221
+ }
222
+
223
+ // If the disabled prop and accessibilityState.disabled are out of sync but not both in
224
+ // falsy states we need to update the accessibilityState object to use the disabled prop.
225
+ if (
226
+ _disabled !== _accessibilityStateDisabled &&
227
+ ((_disabled != null && _disabled !== false) ||
228
+ (_accessibilityStateDisabled != null &&
229
+ _accessibilityStateDisabled !== false))
230
+ ) {
231
+ _accessibilityState = {..._accessibilityState, disabled: _disabled};
232
+ }
233
+
234
+ const _accessible = Platform.select({
235
+ ios: accessible !== false,
236
+ android:
237
+ accessible == null
238
+ ? onPress != null || onLongPress != null
239
+ : accessible,
240
+ default: accessible,
241
+ });
242
+
243
+ let nativeText = null;
244
+ if (isPressable) {
245
+ nativeText = (
246
+ <NativePressableText
247
+ ref={forwardedRef}
248
+ textProps={{
249
+ ...restProps,
250
+ accessibilityLabel: _accessibilityLabel,
251
+ accessibilityState: _accessibilityState,
252
+ accessible: _accessible,
253
+ allowFontScaling: allowFontScaling !== false,
254
+ disabled: _disabled,
255
+ ellipsizeMode: ellipsizeMode ?? 'tail',
256
+ nativeID: _nativeID,
257
+ numberOfLines: _numberOfLines,
258
+ selectable: _selectable,
259
+ selectionColor: _selectionColor,
260
+ style: _style,
261
+ children,
262
+ }}
263
+ textPressabilityProps={{
264
+ onLongPress,
265
+ onPress,
266
+ onPressIn,
267
+ onPressOut,
268
+ onResponderGrant,
269
+ onResponderMove,
270
+ onResponderRelease,
271
+ onResponderTerminate,
272
+ onResponderTerminationRequest,
273
+ onStartShouldSetResponder,
274
+ pressRetentionOffset,
275
+ suppressHighlighting,
276
+ }}
277
+ />
278
+ );
279
+ } else {
280
+ nativeText = (
281
+ <NativeText
282
+ {...restProps}
283
+ accessibilityLabel={_accessibilityLabel}
284
+ accessibilityState={_accessibilityState}
285
+ accessible={_accessible}
286
+ allowFontScaling={allowFontScaling !== false}
287
+ disabled={_disabled}
288
+ ellipsizeMode={ellipsizeMode ?? 'tail'}
289
+ isHighlighted={false}
290
+ nativeID={_nativeID}
291
+ numberOfLines={_numberOfLines}
292
+ ref={forwardedRef}
293
+ selectable={_selectable}
294
+ selectionColor={_selectionColor}
295
+ style={_style}>
296
+ {children}
297
+ </NativeText>
298
+ );
299
+ }
300
+
301
+ if (children == null) {
302
+ return nativeText;
303
+ }
304
+
305
+ // If the children do not contain a JSX element it would not be possible to have a
306
+ // nested `Text` component so we can skip adding the `TextAncestor` context wrapper
307
+ // which has a performance overhead. Since we do this for performance reasons we need
308
+ // to keep the check simple to avoid regressing overall perf. For this reason the
309
+ // `children.length` constant is set to `3`, this should be a reasonable tradeoff
310
+ // to capture the majority of `Text` uses but also not make this check too expensive.
311
+ if (Array.isArray(children) && children.length <= 3) {
312
+ let hasNonTextChild = false;
313
+ for (let child of children) {
314
+ if (child != null && typeof child === 'object') {
315
+ hasNonTextChild = true;
316
+ break;
317
+ }
318
+ }
319
+ if (!hasNonTextChild) {
320
+ return nativeText;
321
+ }
322
+ } else if (typeof children !== 'object') {
323
+ return nativeText;
324
+ }
325
+
326
+ return (
327
+ <TextAncestor.Provider value={true}>{nativeText}</TextAncestor.Provider>
328
+ );
329
+ },
330
+ );
70
331
 
71
- const _accessibilityLabel = ariaLabel ?? accessibilityLabel;
72
-
73
- let _accessibilityState: ?TextProps['accessibilityState'] =
74
- accessibilityState;
75
- if (
76
- ariaBusy != null ||
77
- ariaChecked != null ||
78
- ariaDisabled != null ||
79
- ariaExpanded != null ||
80
- ariaSelected != null
81
- ) {
82
- if (_accessibilityState != null) {
83
- _accessibilityState = {
84
- busy: ariaBusy ?? _accessibilityState.busy,
85
- checked: ariaChecked ?? _accessibilityState.checked,
86
- disabled: ariaDisabled ?? _accessibilityState.disabled,
87
- expanded: ariaExpanded ?? _accessibilityState.expanded,
88
- selected: ariaSelected ?? _accessibilityState.selected,
89
- };
90
- } else {
91
- _accessibilityState = {
92
- busy: ariaBusy,
93
- checked: ariaChecked,
94
- disabled: ariaDisabled,
95
- expanded: ariaExpanded,
96
- selected: ariaSelected,
97
- };
98
- }
99
- }
332
+ Text.displayName = 'Text';
100
333
 
101
- const _accessibilityStateDisabled = _accessibilityState?.disabled;
102
- const _disabled = disabled ?? _accessibilityStateDisabled;
334
+ type TextPressabilityProps = $ReadOnly<{
335
+ onLongPress?: ?(event: PressEvent) => mixed,
336
+ onPress?: ?(event: PressEvent) => mixed,
337
+ onPressIn?: ?(event: PressEvent) => mixed,
338
+ onPressOut?: ?(event: PressEvent) => mixed,
339
+ onResponderGrant?: ?(event: PressEvent) => void,
340
+ onResponderMove?: ?(event: PressEvent) => void,
341
+ onResponderRelease?: ?(event: PressEvent) => void,
342
+ onResponderTerminate?: ?(event: PressEvent) => void,
343
+ onResponderTerminationRequest?: ?() => boolean,
344
+ onStartShouldSetResponder?: ?() => boolean,
345
+ pressRetentionOffset?: ?PressRetentionOffset,
346
+ suppressHighlighting?: ?boolean,
347
+ }>;
103
348
 
104
- const isPressable =
105
- (onPress != null ||
106
- onLongPress != null ||
107
- onStartShouldSetResponder != null) &&
108
- _disabled !== true;
349
+ /**
350
+ * Hook that handles setting up Pressability of Text components.
351
+ *
352
+ * NOTE: This hook is relatively expensive so it should only be used absolutely necessary.
353
+ */
354
+ function useTextPressability({
355
+ onLongPress,
356
+ onPress,
357
+ onPressIn,
358
+ onPressOut,
359
+ onResponderGrant,
360
+ onResponderMove,
361
+ onResponderRelease,
362
+ onResponderTerminate,
363
+ onResponderTerminationRequest,
364
+ onStartShouldSetResponder,
365
+ pressRetentionOffset,
366
+ suppressHighlighting,
367
+ }: TextPressabilityProps) {
368
+ const [isHighlighted, setHighlighted] = useState(false);
109
369
 
110
- const initialized = useLazyInitialization(isPressable);
370
+ // Setup pressability config and wrap callbacks needs to track the highlight state.
111
371
  const config = useMemo(() => {
112
- if (!initialized) {
113
- return null;
114
- }
115
-
116
372
  let _onPressIn = onPressIn;
117
373
  let _onPressOut = onPressOut;
118
374
 
@@ -132,7 +388,7 @@ const TextLegacy: React.AbstractComponent<
132
388
  }
133
389
 
134
390
  return {
135
- disabled: !isPressable,
391
+ disabled: false,
136
392
  pressRectOffset: pressRetentionOffset,
137
393
  onLongPress,
138
394
  onPress,
@@ -140,8 +396,6 @@ const TextLegacy: React.AbstractComponent<
140
396
  onPressOut: _onPressOut,
141
397
  };
142
398
  }, [
143
- initialized,
144
- isPressable,
145
399
  pressRetentionOffset,
146
400
  onLongPress,
147
401
  onPress,
@@ -150,7 +404,10 @@ const TextLegacy: React.AbstractComponent<
150
404
  suppressHighlighting,
151
405
  ]);
152
406
 
407
+ // Init the pressability class
153
408
  const eventHandlers = usePressability(config);
409
+
410
+ // Create NativeText event handlers which proxy events to pressability
154
411
  const eventHandlersForText = useMemo(
155
412
  () =>
156
413
  eventHandlers == null
@@ -201,128 +458,67 @@ const TextLegacy: React.AbstractComponent<
201
458
  ],
202
459
  );
203
460
 
204
- // TODO: Move this processing to the view configuration.
205
- const _selectionColor =
206
- selectionColor == null ? null : processColor(selectionColor);
207
-
208
- let _style = style;
209
- if (__DEV__) {
210
- if (PressabilityDebug.isEnabled() && onPress != null) {
211
- _style = [style, {color: 'magenta'}];
212
- }
213
- }
214
-
215
- let _numberOfLines = numberOfLines;
216
- if (_numberOfLines != null && !(_numberOfLines >= 0)) {
217
- if (__DEV__) {
218
- console.error(
219
- `'numberOfLines' in <Text> must be a non-negative number, received: ${_numberOfLines}. The value will be set to 0.`,
220
- );
221
- }
222
- _numberOfLines = 0;
223
- }
224
-
225
- let _selectable = selectable;
226
- const processedStyle = flattenStyle(_style);
227
- if (processedStyle != null) {
228
- if (typeof processedStyle.fontWeight === 'number') {
229
- // $FlowFixMe[cannot-write]
230
- processedStyle.fontWeight = processedStyle.fontWeight.toString();
231
- }
461
+ // Return the highlight state and NativeText event handlers
462
+ return useMemo(
463
+ () => [isHighlighted, eventHandlersForText],
464
+ [isHighlighted, eventHandlersForText],
465
+ );
466
+ }
232
467
 
233
- if (processedStyle.userSelect != null) {
234
- _selectable = userSelectToSelectableMap[processedStyle.userSelect];
235
- // $FlowFixMe[cannot-write]
236
- delete processedStyle.userSelect;
237
- }
468
+ type NativePressableTextProps = $ReadOnly<{
469
+ textProps: NativeTextProps,
470
+ textPressabilityProps: TextPressabilityProps,
471
+ }>;
238
472
 
239
- if (processedStyle.verticalAlign != null) {
240
- // $FlowFixMe[cannot-write]
241
- processedStyle.textAlignVertical =
242
- verticalAlignToTextAlignVerticalMap[processedStyle.verticalAlign];
243
- // $FlowFixMe[cannot-write]
244
- delete processedStyle.verticalAlign;
245
- }
246
- }
247
-
248
- const _nativeID = id ?? nativeID;
249
-
250
- const hasTextAncestor = useContext(TextAncestor);
251
- if (hasTextAncestor) {
252
- return (
253
- <NativeVirtualText
254
- {...restProps}
255
- {...eventHandlersForText}
256
- accessibilityLabel={_accessibilityLabel}
257
- accessibilityState={_accessibilityState}
258
- isHighlighted={isHighlighted}
259
- isPressable={isPressable}
260
- nativeID={_nativeID}
261
- numberOfLines={_numberOfLines}
262
- ref={forwardedRef}
263
- selectable={_selectable}
264
- selectionColor={_selectionColor}
265
- style={processedStyle}
266
- disabled={disabled}
267
- />
268
- );
269
- }
270
-
271
- // If the disabled prop and accessibilityState.disabled are out of sync but not both in
272
- // falsy states we need to update the accessibilityState object to use the disabled prop.
273
- if (
274
- _disabled !== _accessibilityStateDisabled &&
275
- ((_disabled != null && _disabled !== false) ||
276
- (_accessibilityStateDisabled != null &&
277
- _accessibilityStateDisabled !== false))
278
- ) {
279
- _accessibilityState = {..._accessibilityState, disabled: _disabled};
280
- }
281
-
282
- const _accessible = Platform.select({
283
- ios: accessible !== false,
284
- android:
285
- accessible == null ? onPress != null || onLongPress != null : accessible,
286
- default: accessible,
287
- });
473
+ /**
474
+ * Wrap the NativeVirtualText component and initialize pressability.
475
+ *
476
+ * This logic is split out from the main Text component to enable the more
477
+ * expensive pressability logic to be only initialized when needed.
478
+ */
479
+ const NativePressableVirtualText: React.AbstractComponent<
480
+ NativePressableTextProps,
481
+ TextForwardRef,
482
+ > = React.forwardRef(({textProps, textPressabilityProps}, forwardedRef) => {
483
+ const [isHighlighted, eventHandlersForText] = useTextPressability(
484
+ textPressabilityProps,
485
+ );
288
486
 
289
487
  return (
290
- <TextAncestor.Provider value={true}>
291
- <NativeText
292
- {...restProps}
293
- {...eventHandlersForText}
294
- accessibilityLabel={_accessibilityLabel}
295
- accessibilityState={_accessibilityState}
296
- accessible={_accessible}
297
- allowFontScaling={allowFontScaling !== false}
298
- disabled={_disabled}
299
- ellipsizeMode={ellipsizeMode ?? 'tail'}
300
- isHighlighted={isHighlighted}
301
- nativeID={_nativeID}
302
- numberOfLines={_numberOfLines}
303
- ref={forwardedRef}
304
- selectable={_selectable}
305
- selectionColor={_selectionColor}
306
- style={processedStyle}
307
- />
308
- </TextAncestor.Provider>
488
+ <NativeVirtualText
489
+ {...textProps}
490
+ {...eventHandlersForText}
491
+ isHighlighted={isHighlighted}
492
+ isPressable={true}
493
+ ref={forwardedRef}
494
+ />
309
495
  );
310
496
  });
311
497
 
312
- TextLegacy.displayName = 'TextLegacy';
313
-
314
498
  /**
315
- * Returns false until the first time `newValue` is true, after which this will
316
- * always return true. This is necessary to lazily initialize `Pressability` so
317
- * we do not eagerly create one for every pressable `Text` component.
499
+ * Wrap the NativeText component and initialize pressability.
500
+ *
501
+ * This logic is split out from the main Text component to enable the more
502
+ * expensive pressability logic to be only initialized when needed.
318
503
  */
319
- function useLazyInitialization(newValue: boolean): boolean {
320
- const [oldValue, setValue] = useState(newValue);
321
- if (!oldValue && newValue) {
322
- setValue(newValue);
323
- }
324
- return oldValue;
325
- }
504
+ const NativePressableText: React.AbstractComponent<
505
+ NativePressableTextProps,
506
+ TextForwardRef,
507
+ > = React.forwardRef(({textProps, textPressabilityProps}, forwardedRef) => {
508
+ const [isHighlighted, eventHandlersForText] = useTextPressability(
509
+ textPressabilityProps,
510
+ );
511
+
512
+ return (
513
+ <NativeText
514
+ {...textProps}
515
+ {...eventHandlersForText}
516
+ isHighlighted={isHighlighted}
517
+ isPressable={true}
518
+ ref={forwardedRef}
519
+ />
520
+ );
521
+ });
326
522
 
327
523
  const userSelectToSelectableMap = {
328
524
  auto: true,
@@ -339,17 +535,4 @@ const verticalAlignToTextAlignVerticalMap = {
339
535
  middle: 'center',
340
536
  };
341
537
 
342
- const Text: React.AbstractComponent<
343
- TextProps,
344
- React.ElementRef<typeof NativeText | typeof NativeVirtualText>,
345
- > = React.forwardRef((props: TextProps, forwardedRef) => {
346
- if (ReactNativeFeatureFlags.shouldUseOptimizedText()) {
347
- return <TextOptimized {...props} ref={forwardedRef} />;
348
- } else {
349
- return <TextLegacy {...props} ref={forwardedRef} />;
350
- }
351
- });
352
-
353
- Text.displayName = 'Text';
354
-
355
538
  module.exports = Text;