@office-iss/react-native-win32 0.75.2 → 0.76.0-preview.1

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 (174) hide show
  1. package/.eslintrc.js +11 -0
  2. package/.flowconfig +5 -4
  3. package/CHANGELOG.json +164 -47
  4. package/CHANGELOG.md +53 -28
  5. package/Libraries/Alert/Alert.js +3 -0
  6. package/Libraries/Animated/AnimatedEvent.js +1 -1
  7. package/Libraries/Animated/AnimatedImplementation.js +7 -7
  8. package/Libraries/Animated/NativeAnimatedAllowlist.js +111 -0
  9. package/Libraries/Animated/animations/Animation.js +11 -1
  10. package/Libraries/Animated/animations/DecayAnimation.js +1 -1
  11. package/Libraries/Animated/animations/SpringAnimation.js +1 -1
  12. package/Libraries/Animated/animations/TimingAnimation.js +2 -1
  13. package/Libraries/Animated/components/AnimatedScrollView.js +3 -2
  14. package/Libraries/Animated/createAnimatedComponent.js +10 -9
  15. package/Libraries/Animated/nodes/AnimatedColor.js +1 -1
  16. package/Libraries/Animated/nodes/AnimatedInterpolation.js +3 -2
  17. package/Libraries/Animated/nodes/AnimatedNode.js +42 -33
  18. package/Libraries/Animated/nodes/AnimatedObject.js +56 -50
  19. package/Libraries/Animated/nodes/AnimatedProps.js +77 -40
  20. package/Libraries/Animated/nodes/AnimatedStyle.js +103 -59
  21. package/Libraries/Animated/nodes/AnimatedTracking.js +1 -1
  22. package/Libraries/Animated/nodes/AnimatedTransform.js +102 -67
  23. package/Libraries/Animated/nodes/AnimatedValue.js +2 -1
  24. package/Libraries/Animated/nodes/AnimatedWithChildren.js +21 -22
  25. package/Libraries/Animated/useAnimatedProps.js +142 -7
  26. package/Libraries/BatchedBridge/NativeModules.js +2 -0
  27. package/Libraries/Blob/FileReader.js +1 -1
  28. package/Libraries/Blob/URL.js +2 -62
  29. package/Libraries/Blob/URLSearchParams.js +71 -0
  30. package/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js +1 -1
  31. package/Libraries/Components/RefreshControl/__mocks__/RefreshControlMock.js +1 -1
  32. package/Libraries/Components/ScrollView/ScrollView.js +131 -169
  33. package/Libraries/Components/ScrollView/ScrollViewStickyHeader.js +1 -1
  34. package/Libraries/Components/StatusBar/StatusBar.js +3 -1
  35. package/Libraries/Components/TextInput/TextInput.d.ts +32 -2
  36. package/Libraries/Components/TextInput/TextInput.js +230 -94
  37. package/Libraries/Components/TextInput/TextInput.win32.js +230 -100
  38. package/Libraries/Components/View/ReactNativeStyleAttributes.js +22 -0
  39. package/Libraries/Components/View/ReactNativeViewAttributes.js +2 -0
  40. package/Libraries/Components/View/ReactNativeViewAttributes.win32.js +2 -0
  41. package/Libraries/Components/View/ViewAccessibility.d.ts +15 -0
  42. package/Libraries/Components/View/ViewNativeComponent.js +0 -1
  43. package/Libraries/Components/View/ViewPropTypes.js +14 -0
  44. package/Libraries/Components/View/ViewPropTypes.win32.js +14 -0
  45. package/Libraries/Core/ExceptionsManager.js +2 -0
  46. package/Libraries/Core/InitializeCore.js +3 -1
  47. package/Libraries/Core/ReactFiberErrorDialog.js +3 -0
  48. package/Libraries/Core/ReactNativeVersion.js +4 -4
  49. package/Libraries/Core/ReactNativeVersionCheck.win32.js +1 -1
  50. package/Libraries/Core/setUpErrorHandling.js +7 -1
  51. package/Libraries/Core/setUpGlobals.js +1 -0
  52. package/Libraries/Core/setUpReactRefresh.js +0 -4
  53. package/Libraries/Image/AssetSourceResolver.js +28 -1
  54. package/Libraries/Image/Image.android.js +9 -14
  55. package/Libraries/Image/Image.ios.js +11 -22
  56. package/Libraries/Image/Image.win32.js +11 -24
  57. package/Libraries/Image/ImageBackground.js +1 -8
  58. package/Libraries/Image/ImageUtils.js +9 -9
  59. package/Libraries/Image/ImageViewNativeComponent.js +1 -0
  60. package/Libraries/Inspector/Inspector.js +3 -2
  61. package/Libraries/Inspector/Inspector.win32.js +3 -2
  62. package/Libraries/Inspector/InspectorPanel.js +16 -10
  63. package/Libraries/Inspector/NetworkOverlay.js +1 -1
  64. package/Libraries/Interaction/TaskQueue.js +1 -0
  65. package/Libraries/Lists/FlatList.js +1 -1
  66. package/Libraries/Lists/SectionList.js +2 -2
  67. package/Libraries/Lists/SectionListModern.js +3 -3
  68. package/Libraries/LogBox/Data/LogBoxData.js +24 -3
  69. package/Libraries/LogBox/LogBoxNotificationContainer.js +3 -2
  70. package/Libraries/LogBox/UI/LogBoxInspectorHeader.js +9 -8
  71. package/Libraries/LogBox/UI/LogBoxInspectorHeader.win32.js +9 -29
  72. package/Libraries/Modal/Modal.js +0 -1
  73. package/Libraries/NativeComponent/BaseViewConfig.android.js +8 -0
  74. package/Libraries/NativeComponent/BaseViewConfig.ios.js +7 -0
  75. package/Libraries/NativeComponent/BaseViewConfig.win32.js +7 -0
  76. package/Libraries/NativeComponent/NativeComponentRegistry.js +22 -22
  77. package/Libraries/NativeComponent/StaticViewConfigValidator.js +0 -21
  78. package/Libraries/Network/XMLHttpRequest.js +4 -2
  79. package/Libraries/ReactNative/AppContainer-dev.js +1 -5
  80. package/Libraries/ReactNative/AppContainer-prod.js +1 -5
  81. package/Libraries/ReactNative/AppContainer.js +0 -1
  82. package/Libraries/ReactNative/AppRegistry.js +0 -6
  83. package/Libraries/ReactNative/BridgelessUIManager.js +1 -0
  84. package/Libraries/ReactNative/ReactFabricPublicInstance/ReactFabricHostComponent.js +1 -1
  85. package/Libraries/ReactNative/ReactFabricPublicInstance/ReactFabricPublicInstance.js +5 -5
  86. package/Libraries/ReactNative/RendererImplementation.js +26 -4
  87. package/Libraries/ReactNative/getNativeComponentAttributes.js +8 -0
  88. package/Libraries/ReactNative/renderApplication.js +0 -2
  89. package/Libraries/Renderer/shims/ReactNativeTypes.js +11 -4
  90. package/Libraries/StyleSheet/StyleSheet.js +1 -1
  91. package/Libraries/StyleSheet/StyleSheet.win32.js +1 -1
  92. package/Libraries/StyleSheet/StyleSheetTypes.d.ts +57 -0
  93. package/Libraries/StyleSheet/StyleSheetTypes.js +60 -5
  94. package/Libraries/StyleSheet/processBackgroundImage.js +384 -0
  95. package/Libraries/StyleSheet/processBoxShadow.js +211 -0
  96. package/Libraries/StyleSheet/processFilter.js +231 -42
  97. package/Libraries/Text/Text.js +394 -196
  98. package/Libraries/Text/Text.win32.js +442 -229
  99. package/Libraries/Text/TextNativeComponent.js +2 -1
  100. package/Libraries/Text/TextNativeComponent.win32.js +1 -1
  101. package/Libraries/TurboModule/TurboModuleRegistry.js +13 -50
  102. package/Libraries/Types/CodegenTypes.js +3 -1
  103. package/Libraries/Utilities/Appearance.js +108 -84
  104. package/Libraries/Utilities/DevLoadingView.js +2 -4
  105. package/Libraries/Utilities/HMRClient.js +2 -1
  106. package/Libraries/Utilities/ReactNativeTestTools.js +1 -1
  107. package/Libraries/Utilities/createPerformanceLogger.js +0 -9
  108. package/Libraries/Utilities/stringifyViewConfig.js +22 -0
  109. package/Libraries/Utilities/useColorScheme.js +3 -3
  110. package/Libraries/WebSocket/WebSocket.js +1 -1
  111. package/Libraries/promiseRejectionTrackingOptions.js +1 -1
  112. package/Libraries/vendor/emitter/EventEmitter.js +6 -5
  113. package/flow/jest.js +2 -2
  114. package/index.js +3 -1
  115. package/index.win32.js +3 -1
  116. package/jest/mockComponent.js +4 -1
  117. package/jest/mockModal.js +1 -3
  118. package/jest/mockScrollView.js +1 -1
  119. package/jest/renderer.js +2 -2
  120. package/jest/setup.js +16 -13
  121. package/jest.config.js +1 -2
  122. package/overrides.json +22 -22
  123. package/package.json +30 -30
  124. package/src/private/animated/NativeAnimatedHelper.js +438 -0
  125. package/src/private/animated/NativeAnimatedHelper.win32.js +440 -0
  126. package/src/private/animated/NativeAnimatedValidation.js +64 -0
  127. package/src/private/components/HScrollViewNativeComponents.js +56 -0
  128. package/src/private/components/SafeAreaView_INTERNAL_DO_NOT_USE.js +27 -0
  129. package/src/private/components/VScrollViewNativeComponents.js +48 -0
  130. package/src/private/components/useSyncOnScroll.js +48 -0
  131. package/src/private/featureflags/ReactNativeFeatureFlags.js +166 -16
  132. package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +29 -5
  133. package/src/private/fusebox/FuseboxSessionObserver.js +42 -0
  134. package/{Libraries/Core → src/private/renderer/errorhandling}/ErrorHandlers.js +14 -4
  135. package/src/private/setup/setUpDOM.js +28 -0
  136. package/src/private/setup/setUpIntersectionObserver.js +27 -0
  137. package/src/private/setup/setUpMutationObserver.js +26 -0
  138. package/src/private/setup/setUpPerformanceObserver.js +64 -0
  139. package/src/private/specs/modules/NativeAppearance.js +3 -3
  140. package/src/private/specs/modules/NativeLinkingManager.js +1 -1
  141. package/src/private/specs/modules/NativePlatformConstantsWin.js +7 -0
  142. package/src/private/specs/modules/NativeSampleTurboModule.js +14 -1
  143. package/src/private/webapis/dom/nodes/ReadOnlyNode.js +6 -4
  144. package/{Libraries/IntersectionObserver → src/private/webapis/intersectionobserver}/IntersectionObserver.js +5 -3
  145. package/{Libraries/IntersectionObserver → src/private/webapis/intersectionobserver}/IntersectionObserverEntry.js +3 -3
  146. package/{Libraries/IntersectionObserver → src/private/webapis/intersectionobserver}/IntersectionObserverManager.js +14 -17
  147. package/src/private/{specs/modules → webapis/intersectionobserver/specs}/NativeIntersectionObserver.js +2 -2
  148. package/{Libraries/IntersectionObserver → src/private/webapis/intersectionobserver/specs}/__mocks__/NativeIntersectionObserver.js +4 -4
  149. package/{Libraries/MutationObserver → src/private/webapis/mutationobserver}/MutationObserver.js +5 -3
  150. package/{Libraries/MutationObserver → src/private/webapis/mutationobserver}/MutationObserverManager.js +24 -15
  151. package/{Libraries/MutationObserver → src/private/webapis/mutationobserver}/MutationRecord.js +4 -6
  152. package/src/private/{specs/modules → webapis/mutationobserver/specs}/NativeMutationObserver.js +2 -2
  153. package/{Libraries/MutationObserver → src/private/webapis/mutationobserver/specs}/__mocks__/NativeMutationObserver.js +5 -5
  154. package/src/private/webapis/performance/{EventCounts.js → EventTiming.js} +65 -3
  155. package/src/private/webapis/performance/LongTasks.js +39 -0
  156. package/src/private/webapis/performance/Performance.js +22 -9
  157. package/src/private/webapis/performance/PerformanceEntry.js +36 -18
  158. package/src/private/webapis/performance/PerformanceObserver.js +29 -43
  159. package/src/private/webapis/performance/RawPerformanceEntry.js +24 -1
  160. package/src/private/webapis/performance/UserTiming.js +17 -12
  161. package/src/private/webapis/performance/specs/NativePerformanceObserver.js +1 -1
  162. package/src-win/Libraries/Components/View/ViewAccessibility.d.ts +15 -0
  163. package/types/experimental.d.ts +20 -1
  164. package/Libraries/Animated/NativeAnimatedHelper.js +0 -615
  165. package/Libraries/Animated/NativeAnimatedHelper.win32.js +0 -617
  166. package/Libraries/Core/setUpIntersectionObserver.js +0 -16
  167. package/Libraries/Core/setUpMutationObserver.js +0 -16
  168. package/Libraries/Core/setUpPerformanceObserver.js +0 -18
  169. package/Libraries/IntersectionObserver/NativeIntersectionObserver.js +0 -13
  170. package/Libraries/MutationObserver/NativeMutationObserver.js +0 -13
  171. package/Libraries/Utilities/verifyComponentAttributeEquivalence.js +0 -135
  172. package/src/private/core/setUpDOM.js +0 -18
  173. package/src/private/webapis/performance/PerformanceEventTiming.js +0 -55
  174. /package/src/private/{core → styles}/composeStyles.js +0 -0
@@ -8,8 +8,11 @@
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
17
  import * as PressabilityDebug from '../Pressability/PressabilityDebug';
15
18
  import usePressability from '../Pressability/usePressability';
@@ -21,96 +24,351 @@ import {NativeText, NativeVirtualText} from './TextNativeComponent';
21
24
  import * as React from 'react';
22
25
  import {useContext, useMemo, useState} from 'react';
23
26
 
27
+ type TextForwardRef = React.ElementRef<
28
+ typeof NativeText | typeof NativeVirtualText,
29
+ >;
30
+
24
31
  /**
25
32
  * Text is the fundamental component for displaying text.
26
33
  *
27
34
  * @see https://reactnative.dev/docs/text
28
35
  */
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
- accessibilityLabel,
36
- accessibilityState,
37
- allowFontScaling,
38
- 'aria-busy': ariaBusy,
39
- 'aria-checked': ariaChecked,
40
- 'aria-disabled': ariaDisabled,
41
- 'aria-expanded': ariaExpanded,
42
- 'aria-label': ariaLabel,
43
- 'aria-selected': ariaSelected,
44
- ellipsizeMode,
45
- disabled,
46
- id,
47
- nativeID,
48
- numberOfLines,
49
- onLongPress,
50
- onPress,
51
- onPressIn,
52
- onPressOut,
53
- onResponderGrant,
54
- onResponderMove,
55
- onResponderRelease,
56
- onResponderTerminate,
57
- onResponderTerminationRequest,
58
- onStartShouldSetResponder,
59
- pressRetentionOffset,
60
- selectable,
61
- selectionColor,
62
- suppressHighlighting,
63
- style,
64
- ...restProps
65
- } = props;
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;
66
76
 
67
- const [isHighlighted, setHighlighted] = useState(false);
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
+ }
68
104
 
69
- const _accessibilityLabel = ariaLabel ?? accessibilityLabel;
70
-
71
- let _accessibilityState: ?TextProps['accessibilityState'] =
72
- accessibilityState;
73
- if (
74
- ariaBusy != null ||
75
- ariaChecked != null ||
76
- ariaDisabled != null ||
77
- ariaExpanded != null ||
78
- ariaSelected != null
79
- ) {
80
- if (_accessibilityState != null) {
81
- _accessibilityState = {
82
- busy: ariaBusy ?? _accessibilityState.busy,
83
- checked: ariaChecked ?? _accessibilityState.checked,
84
- disabled: ariaDisabled ?? _accessibilityState.disabled,
85
- expanded: ariaExpanded ?? _accessibilityState.expanded,
86
- selected: ariaSelected ?? _accessibilityState.selected,
87
- };
88
- } else {
89
- _accessibilityState = {
90
- busy: ariaBusy,
91
- checked: ariaChecked,
92
- disabled: ariaDisabled,
93
- expanded: ariaExpanded,
94
- selected: ariaSelected,
95
- };
96
- }
97
- }
105
+ const _accessibilityStateDisabled = _accessibilityState?.disabled;
106
+ const _disabled = disabled ?? _accessibilityStateDisabled;
98
107
 
99
- const _accessibilityStateDisabled = _accessibilityState?.disabled;
100
- const _disabled = disabled ?? _accessibilityStateDisabled;
108
+ const isPressable =
109
+ (onPress != null ||
110
+ onLongPress != null ||
111
+ onStartShouldSetResponder != null) &&
112
+ _disabled !== true;
101
113
 
102
- const isPressable =
103
- (onPress != null ||
104
- onLongPress != null ||
105
- onStartShouldSetResponder != null) &&
106
- _disabled !== true;
114
+ // TODO: Move this processing to the view configuration.
115
+ const _selectionColor =
116
+ selectionColor == null ? null : processColor(selectionColor);
107
117
 
108
- const initialized = useLazyInitialization(isPressable);
109
- const config = useMemo(() => {
110
- if (!initialized) {
111
- return null;
112
- }
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
+ );
331
+
332
+ Text.displayName = 'Text';
113
333
 
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
+ }>;
348
+
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);
369
+
370
+ // Setup pressability config and wrap callbacks needs to track the highlight state.
371
+ const config = useMemo(() => {
114
372
  let _onPressIn = onPressIn;
115
373
  let _onPressOut = onPressOut;
116
374
 
@@ -130,7 +388,7 @@ const Text: React.AbstractComponent<
130
388
  }
131
389
 
132
390
  return {
133
- disabled: !isPressable,
391
+ disabled: false,
134
392
  pressRectOffset: pressRetentionOffset,
135
393
  onLongPress,
136
394
  onPress,
@@ -138,8 +396,6 @@ const Text: React.AbstractComponent<
138
396
  onPressOut: _onPressOut,
139
397
  };
140
398
  }, [
141
- initialized,
142
- isPressable,
143
399
  pressRetentionOffset,
144
400
  onLongPress,
145
401
  onPress,
@@ -148,7 +404,10 @@ const Text: React.AbstractComponent<
148
404
  suppressHighlighting,
149
405
  ]);
150
406
 
407
+ // Init the pressability class
151
408
  const eventHandlers = usePressability(config);
409
+
410
+ // Create NativeText event handlers which proxy events to pressability
152
411
  const eventHandlersForText = useMemo(
153
412
  () =>
154
413
  eventHandlers == null
@@ -199,128 +458,67 @@ const Text: React.AbstractComponent<
199
458
  ],
200
459
  );
201
460
 
202
- // TODO: Move this processing to the view configuration.
203
- const _selectionColor =
204
- selectionColor == null ? null : processColor(selectionColor);
205
-
206
- let _style = style;
207
- if (__DEV__) {
208
- if (PressabilityDebug.isEnabled() && onPress != null) {
209
- _style = [style, {color: 'magenta'}];
210
- }
211
- }
461
+ // Return the highlight state and NativeText event handlers
462
+ return useMemo(
463
+ () => [isHighlighted, eventHandlersForText],
464
+ [isHighlighted, eventHandlersForText],
465
+ );
466
+ }
212
467
 
213
- let _numberOfLines = numberOfLines;
214
- if (_numberOfLines != null && !(_numberOfLines >= 0)) {
215
- if (__DEV__) {
216
- console.error(
217
- `'numberOfLines' in <Text> must be a non-negative number, received: ${_numberOfLines}. The value will be set to 0.`,
218
- );
219
- }
220
- _numberOfLines = 0;
221
- }
222
-
223
- let _selectable = selectable;
224
- const processedStyle = flattenStyle(_style);
225
- if (processedStyle != null) {
226
- if (typeof processedStyle.fontWeight === 'number') {
227
- // $FlowFixMe[cannot-write]
228
- processedStyle.fontWeight = processedStyle.fontWeight.toString();
229
- }
468
+ type NativePressableTextProps = $ReadOnly<{
469
+ textProps: NativeTextProps,
470
+ textPressabilityProps: TextPressabilityProps,
471
+ }>;
230
472
 
231
- if (processedStyle.userSelect != null) {
232
- _selectable = userSelectToSelectableMap[processedStyle.userSelect];
233
- // $FlowFixMe[cannot-write]
234
- delete processedStyle.userSelect;
235
- }
236
-
237
- if (processedStyle.verticalAlign != null) {
238
- // $FlowFixMe[cannot-write]
239
- processedStyle.textAlignVertical =
240
- verticalAlignToTextAlignVerticalMap[processedStyle.verticalAlign];
241
- // $FlowFixMe[cannot-write]
242
- delete processedStyle.verticalAlign;
243
- }
244
- }
245
-
246
- const _nativeID = id ?? nativeID;
247
-
248
- const hasTextAncestor = useContext(TextAncestor);
249
- if (hasTextAncestor) {
250
- return (
251
- <NativeVirtualText
252
- {...restProps}
253
- {...eventHandlersForText}
254
- accessibilityLabel={_accessibilityLabel}
255
- accessibilityState={_accessibilityState}
256
- isHighlighted={isHighlighted}
257
- isPressable={isPressable}
258
- nativeID={_nativeID}
259
- numberOfLines={_numberOfLines}
260
- ref={forwardedRef}
261
- selectable={_selectable}
262
- selectionColor={_selectionColor}
263
- style={processedStyle}
264
- disabled={disabled}
265
- />
266
- );
267
- }
268
-
269
- // If the disabled prop and accessibilityState.disabled are out of sync but not both in
270
- // falsy states we need to update the accessibilityState object to use the disabled prop.
271
- if (
272
- _disabled !== _accessibilityStateDisabled &&
273
- ((_disabled != null && _disabled !== false) ||
274
- (_accessibilityStateDisabled != null &&
275
- _accessibilityStateDisabled !== false))
276
- ) {
277
- _accessibilityState = {..._accessibilityState, disabled: _disabled};
278
- }
279
-
280
- const _accessible = Platform.select({
281
- ios: accessible !== false,
282
- android:
283
- accessible == null ? onPress != null || onLongPress != null : accessible,
284
- default: accessible,
285
- });
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
+ );
286
486
 
287
487
  return (
288
- <TextAncestor.Provider value={true}>
289
- <NativeText
290
- {...restProps}
291
- {...eventHandlersForText}
292
- accessibilityLabel={_accessibilityLabel}
293
- accessibilityState={_accessibilityState}
294
- accessible={_accessible}
295
- allowFontScaling={allowFontScaling !== false}
296
- disabled={_disabled}
297
- ellipsizeMode={ellipsizeMode ?? 'tail'}
298
- isHighlighted={isHighlighted}
299
- nativeID={_nativeID}
300
- numberOfLines={_numberOfLines}
301
- ref={forwardedRef}
302
- selectable={_selectable}
303
- selectionColor={_selectionColor}
304
- style={processedStyle}
305
- />
306
- </TextAncestor.Provider>
488
+ <NativeVirtualText
489
+ {...textProps}
490
+ {...eventHandlersForText}
491
+ isHighlighted={isHighlighted}
492
+ isPressable={true}
493
+ ref={forwardedRef}
494
+ />
307
495
  );
308
496
  });
309
497
 
310
- Text.displayName = 'Text';
311
-
312
498
  /**
313
- * Returns false until the first time `newValue` is true, after which this will
314
- * always return true. This is necessary to lazily initialize `Pressability` so
315
- * 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.
316
503
  */
317
- function useLazyInitialization(newValue: boolean): boolean {
318
- const [oldValue, setValue] = useState(newValue);
319
- if (!oldValue && newValue) {
320
- setValue(newValue);
321
- }
322
- return oldValue;
323
- }
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
+ });
324
522
 
325
523
  const userSelectToSelectableMap = {
326
524
  auto: true,