@office-iss/react-native-win32 0.0.0-canary.259 → 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 (115) hide show
  1. package/.flowconfig +1 -1
  2. package/CHANGELOG.json +16 -1
  3. package/CHANGELOG.md +12 -4
  4. package/Libraries/Animated/AnimatedImplementation.js +7 -7
  5. package/Libraries/Animated/animations/Animation.js +10 -0
  6. package/Libraries/Animated/animations/TimingAnimation.js +1 -0
  7. package/Libraries/Animated/components/AnimatedScrollView.js +2 -2
  8. package/Libraries/Animated/createAnimatedComponent.js +1 -1
  9. package/Libraries/Animated/useAnimatedProps.js +71 -4
  10. package/Libraries/Blob/FileReader.js +1 -1
  11. package/Libraries/Blob/URL.js +2 -62
  12. package/Libraries/Blob/URLSearchParams.js +71 -0
  13. package/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js +1 -1
  14. package/Libraries/Components/RefreshControl/__mocks__/RefreshControlMock.js +1 -1
  15. package/Libraries/Components/ScrollView/AndroidHorizontalScrollViewNativeComponent.js +3 -0
  16. package/Libraries/Components/ScrollView/ScrollView.js +5 -5
  17. package/Libraries/Components/ScrollView/ScrollViewNativeComponent.js +3 -3
  18. package/Libraries/Components/ScrollView/ScrollViewStickyHeader.js +1 -1
  19. package/Libraries/Components/StatusBar/StatusBar.js +3 -1
  20. package/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js +3 -0
  21. package/Libraries/Components/TextInput/TextInput.d.ts +32 -2
  22. package/Libraries/Components/TextInput/TextInput.js +19 -10
  23. package/Libraries/Components/TextInput/TextInput.win32.js +19 -10
  24. package/Libraries/Components/View/ReactNativeStyleAttributes.js +11 -0
  25. package/Libraries/Components/View/ReactNativeViewAttributes.js +2 -0
  26. package/Libraries/Components/View/ReactNativeViewAttributes.win32.js +2 -0
  27. package/Libraries/Components/View/ViewAccessibility.d.ts +15 -0
  28. package/Libraries/Components/View/ViewNativeComponent.js +6 -0
  29. package/Libraries/Components/View/ViewPropTypes.js +14 -0
  30. package/Libraries/Components/View/ViewPropTypes.win32.js +14 -0
  31. package/Libraries/Core/InitializeCore.js +1 -1
  32. package/Libraries/Core/ReactNativeVersion.js +1 -1
  33. package/Libraries/Core/setUpErrorHandling.js +7 -1
  34. package/Libraries/Image/AssetSourceResolver.js +28 -1
  35. package/Libraries/Image/Image.android.js +9 -14
  36. package/Libraries/Image/Image.ios.js +11 -22
  37. package/Libraries/Image/Image.win32.js +10 -21
  38. package/Libraries/Image/ImageBackground.js +1 -8
  39. package/Libraries/Image/ImageUtils.js +9 -9
  40. package/Libraries/Image/ImageViewNativeComponent.js +3 -0
  41. package/Libraries/Inspector/NetworkOverlay.js +1 -1
  42. package/Libraries/Lists/FlatList.js +1 -1
  43. package/Libraries/Lists/SectionList.js +1 -1
  44. package/Libraries/Lists/SectionListModern.js +1 -1
  45. package/Libraries/LogBox/Data/LogBoxData.js +30 -4
  46. package/Libraries/NativeComponent/BaseViewConfig.android.js +1 -0
  47. package/Libraries/NativeComponent/BaseViewConfig.ios.js +4 -0
  48. package/Libraries/NativeComponent/BaseViewConfig.win32.js +4 -0
  49. package/Libraries/Network/XMLHttpRequest.js +4 -2
  50. package/Libraries/ReactNative/ReactFabricPublicInstance/ReactFabricHostComponent.js +1 -1
  51. package/Libraries/ReactNative/ReactFabricPublicInstance/ReactFabricPublicInstance.js +5 -5
  52. package/Libraries/ReactNative/RendererImplementation.js +24 -2
  53. package/Libraries/ReactNative/getNativeComponentAttributes.js +8 -0
  54. package/Libraries/StyleSheet/StyleSheet.js +1 -1
  55. package/Libraries/StyleSheet/StyleSheet.win32.js +1 -1
  56. package/Libraries/StyleSheet/StyleSheetTypes.d.ts +11 -0
  57. package/Libraries/StyleSheet/StyleSheetTypes.js +14 -2
  58. package/Libraries/StyleSheet/processBackgroundImage.js +286 -0
  59. package/Libraries/Text/Text.js +7 -6
  60. package/Libraries/Text/Text.win32.js +7 -6
  61. package/Libraries/Text/TextNativeComponent.js +7 -0
  62. package/Libraries/Text/TextNativeComponent.win32.js +7 -0
  63. package/Libraries/Utilities/ReactNativeTestTools.js +1 -1
  64. package/Libraries/WebSocket/WebSocket.js +1 -1
  65. package/flow/jest.js +2 -2
  66. package/index.js +1 -0
  67. package/index.win32.js +1 -0
  68. package/jest/mockModal.js +1 -3
  69. package/jest/mockScrollView.js +1 -1
  70. package/jest/renderer.js +2 -2
  71. package/jest/setup.js +8 -8
  72. package/overrides.json +12 -12
  73. package/package.json +13 -13
  74. package/src/private/{core/components → components}/HScrollViewNativeComponents.js +8 -8
  75. package/src/private/{core/components → components}/VScrollViewNativeComponents.js +7 -7
  76. package/src/private/{core/components → components}/useSyncOnScroll.js +2 -2
  77. package/src/private/featureflags/ReactNativeFeatureFlags.js +84 -7
  78. package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +15 -2
  79. package/src/private/hooks/DebouncedEffectImplementation.js +148 -0
  80. package/src/private/hooks/useDebouncedEffect.js +23 -0
  81. package/{Libraries/Core → src/private/renderer/errorhandling}/ErrorHandlers.js +5 -4
  82. package/src/private/setup/setUpDOM.js +28 -0
  83. package/src/private/setup/setUpIntersectionObserver.js +27 -0
  84. package/src/private/setup/setUpMutationObserver.js +26 -0
  85. package/src/private/setup/setUpPerformanceObserver.js +64 -0
  86. package/src/private/specs/modules/NativeDebuggerSessionObserver.js +23 -0
  87. package/src/private/webapis/dom/nodes/ReadOnlyNode.js +6 -4
  88. package/{Libraries/IntersectionObserver → src/private/webapis/intersectionobserver}/IntersectionObserver.js +1 -1
  89. package/{Libraries/IntersectionObserver → src/private/webapis/intersectionobserver}/IntersectionObserverEntry.js +3 -3
  90. package/{Libraries/IntersectionObserver → src/private/webapis/intersectionobserver}/IntersectionObserverManager.js +5 -8
  91. package/src/private/{specs/modules → webapis/intersectionobserver/specs}/NativeIntersectionObserver.js +2 -2
  92. package/{Libraries/IntersectionObserver → src/private/webapis/intersectionobserver/specs}/__mocks__/NativeIntersectionObserver.js +4 -4
  93. package/{Libraries/MutationObserver → src/private/webapis/mutationobserver}/MutationObserver.js +1 -1
  94. package/{Libraries/MutationObserver → src/private/webapis/mutationobserver}/MutationObserverManager.js +5 -5
  95. package/{Libraries/MutationObserver → src/private/webapis/mutationobserver}/MutationRecord.js +4 -6
  96. package/src/private/{specs/modules → webapis/mutationobserver/specs}/NativeMutationObserver.js +2 -2
  97. package/{Libraries/MutationObserver → src/private/webapis/mutationobserver/specs}/__mocks__/NativeMutationObserver.js +5 -5
  98. package/src/private/webapis/performance/{EventCounts.js → EventTiming.js} +65 -3
  99. package/src/private/webapis/performance/LongTasks.js +39 -0
  100. package/src/private/webapis/performance/Performance.js +22 -9
  101. package/src/private/webapis/performance/PerformanceEntry.js +35 -17
  102. package/src/private/webapis/performance/PerformanceObserver.js +29 -43
  103. package/src/private/webapis/performance/RawPerformanceEntry.js +19 -1
  104. package/src/private/webapis/performance/UserTiming.js +17 -12
  105. package/src/private/webapis/performance/specs/NativePerformanceObserver.js +1 -1
  106. package/src-win/Libraries/Components/View/ViewAccessibility.d.ts +15 -0
  107. package/types/experimental.d.ts +10 -2
  108. package/Libraries/Core/setUpIntersectionObserver.js +0 -16
  109. package/Libraries/Core/setUpMutationObserver.js +0 -16
  110. package/Libraries/Core/setUpPerformanceObserver.js +0 -18
  111. package/Libraries/IntersectionObserver/NativeIntersectionObserver.js +0 -13
  112. package/Libraries/MutationObserver/NativeMutationObserver.js +0 -13
  113. package/src/private/core/setUpDOM.js +0 -18
  114. package/src/private/webapis/performance/PerformanceEventTiming.js +0 -55
  115. /package/src/private/{core → styles}/composeStyles.js +0 -0
@@ -193,6 +193,8 @@ const validAttributesForNonEventProps = {
193
193
  accessibilityViewIsModal: true,
194
194
  accessibilityElementsHidden: true,
195
195
  accessibilityIgnoresInvertColors: true,
196
+ accessibilityShowsLargeContentViewer: true,
197
+ accessibilityLargeContentTitle: true,
196
198
  testID: true,
197
199
  backgroundColor: {process: require('../StyleSheet/processColor').default},
198
200
  backfaceVisibility: true,
@@ -226,6 +228,8 @@ const validAttributesForNonEventProps = {
226
228
  experimental_boxShadow: {
227
229
  process: require('../StyleSheet/processBoxShadow').default,
228
230
  },
231
+ experimental_mixBlendMode: true,
232
+ isolation: true,
229
233
 
230
234
  borderTopWidth: true,
231
235
  borderTopColor: {process: require('../StyleSheet/processColor').default},
@@ -193,6 +193,8 @@ const validAttributesForNonEventProps = {
193
193
  accessibilityViewIsModal: true,
194
194
  accessibilityElementsHidden: true,
195
195
  accessibilityIgnoresInvertColors: true,
196
+ accessibilityShowsLargeContentViewer: true,
197
+ accessibilityLargeContentTitle: true,
196
198
  testID: true,
197
199
  backgroundColor: {process: require('../StyleSheet/processColor').default},
198
200
  backfaceVisibility: true,
@@ -226,6 +228,8 @@ const validAttributesForNonEventProps = {
226
228
  experimental_boxShadow: {
227
229
  process: require('../StyleSheet/processBoxShadow').default,
228
230
  },
231
+ experimental_mixBlendMode: true,
232
+ isolation: true,
229
233
 
230
234
  borderTopWidth: true,
231
235
  borderTopColor: {process: require('../StyleSheet/processColor').default},
@@ -78,7 +78,9 @@ const REQUEST_EVENTS = [
78
78
 
79
79
  const XHR_EVENTS = REQUEST_EVENTS.concat('readystatechange');
80
80
 
81
- class XMLHttpRequestEventTarget extends (EventTarget(...REQUEST_EVENTS): any) {
81
+ class XMLHttpRequestEventTarget extends (EventTarget(
82
+ ...REQUEST_EVENTS,
83
+ ): typeof EventTarget) {
82
84
  onload: ?Function;
83
85
  onloadstart: ?Function;
84
86
  onprogress: ?Function;
@@ -91,7 +93,7 @@ class XMLHttpRequestEventTarget extends (EventTarget(...REQUEST_EVENTS): any) {
91
93
  /**
92
94
  * Shared base for platform-specific XMLHttpRequest implementations.
93
95
  */
94
- class XMLHttpRequest extends (EventTarget(...XHR_EVENTS): any) {
96
+ class XMLHttpRequest extends (EventTarget(...XHR_EVENTS): typeof EventTarget) {
95
97
  static UNSENT: number = UNSENT;
96
98
  static OPENED: number = OPENED;
97
99
  static HEADERS_RECEIVED: number = HEADERS_RECEIVED;
@@ -20,7 +20,7 @@ import type {
20
20
  import type {ElementRef} from 'react';
21
21
 
22
22
  import TextInputState from '../../Components/TextInput/TextInputState';
23
- import {getNodeFromInternalInstanceHandle} from '../../Renderer/shims/ReactFabric';
23
+ import {getNodeFromInternalInstanceHandle} from '../../ReactNative/RendererProxy';
24
24
  import {getFabricUIManager} from '../FabricUIManager';
25
25
  import {create} from './ReactNativeAttributePayload';
26
26
  import warnForStyleProps from './warnForStyleProps';
@@ -15,7 +15,7 @@
15
15
 
16
16
  import type ReactNativeElement from '../../../src/private/webapis/dom/nodes/ReactNativeElement';
17
17
  import type ReadOnlyText from '../../../src/private/webapis/dom/nodes/ReadOnlyText';
18
- import typeof ReactFabricType from '../../Renderer/shims/ReactFabric';
18
+ import typeof * as RendererProxyT from '../../ReactNative/RendererProxy';
19
19
  import type {
20
20
  InternalInstanceHandle,
21
21
  Node,
@@ -32,7 +32,7 @@ let PublicInstanceClass:
32
32
  let ReadOnlyTextClass: Class<ReadOnlyText>;
33
33
 
34
34
  // Lazy loaded to avoid evaluating the module when using the legacy renderer.
35
- let ReactFabric: ReactFabricType;
35
+ let RendererProxy: RendererProxyT;
36
36
 
37
37
  export function createPublicInstance(
38
38
  tag: number,
@@ -78,10 +78,10 @@ export function getNodeFromPublicInstance(
78
78
  return null;
79
79
  }
80
80
 
81
- if (ReactFabric == null) {
82
- ReactFabric = require('../../Renderer/shims/ReactFabric');
81
+ if (RendererProxy == null) {
82
+ RendererProxy = require('../../ReactNative/RendererProxy');
83
83
  }
84
- return ReactFabric.getNodeFromInternalInstanceHandle(
84
+ return RendererProxy.getNodeFromInternalInstanceHandle(
85
85
  publicInstance.__internalInstanceHandle,
86
86
  );
87
87
  }
@@ -8,7 +8,11 @@
8
8
  * @flow strict-local
9
9
  */
10
10
 
11
- import type {HostComponent} from '../Renderer/shims/ReactNativeTypes';
11
+ import type {
12
+ HostComponent,
13
+ InternalInstanceHandle,
14
+ Node,
15
+ } from '../Renderer/shims/ReactNativeTypes';
12
16
  import type ReactFabricHostComponent from './ReactFabricPublicInstance/ReactFabricHostComponent';
13
17
  import type {Element, ElementRef, ElementType} from 'react';
14
18
 
@@ -16,7 +20,7 @@ import {
16
20
  onCaughtError,
17
21
  onRecoverableError,
18
22
  onUncaughtError,
19
- } from '../Core/ErrorHandlers';
23
+ } from '../../src/private/renderer/errorhandling/ErrorHandlers';
20
24
  import {type RootTag} from './RootTag';
21
25
  export function renderElement({
22
26
  element,
@@ -139,3 +143,21 @@ export function isChildPublicInstance(
139
143
  childInstance,
140
144
  );
141
145
  }
146
+
147
+ export function getNodeFromInternalInstanceHandle(
148
+ internalInstanceHandle: InternalInstanceHandle,
149
+ ): ?Node {
150
+ // This is only available in Fabric
151
+ return require('../Renderer/shims/ReactFabric').getNodeFromInternalInstanceHandle(
152
+ internalInstanceHandle,
153
+ );
154
+ }
155
+
156
+ export function getPublicInstanceFromInternalInstanceHandle(
157
+ internalInstanceHandle: InternalInstanceHandle,
158
+ ): mixed /*PublicInstance | PublicTextInstance | null*/ {
159
+ // This is only available in Fabric
160
+ return require('../Renderer/shims/ReactFabric').getPublicInstanceFromInternalInstanceHandle(
161
+ internalInstanceHandle,
162
+ );
163
+ }
@@ -10,8 +10,12 @@
10
10
 
11
11
  'use strict';
12
12
 
13
+ import processBoxShadow from '../StyleSheet/processBoxShadow';
14
+
13
15
  const ReactNativeStyleAttributes = require('../Components/View/ReactNativeStyleAttributes');
14
16
  const resolveAssetSource = require('../Image/resolveAssetSource');
17
+ const processBackgroundImage =
18
+ require('../StyleSheet/processBackgroundImage').default;
15
19
  const processColor = require('../StyleSheet/processColor').default;
16
20
  const processColorArray = require('../StyleSheet/processColorArray');
17
21
  const processFilter = require('../StyleSheet/processFilter').default;
@@ -191,8 +195,12 @@ function getProcessorForType(typeName: string): ?(nextProp: any) => any {
191
195
  return processColorArray;
192
196
  case 'Filter':
193
197
  return processFilter;
198
+ case 'BackgroundImage':
199
+ return processBackgroundImage;
194
200
  case 'ImageSource':
195
201
  return resolveAssetSource;
202
+ case 'BoxShadow':
203
+ return processBoxShadow;
196
204
  }
197
205
  return null;
198
206
  }
@@ -23,7 +23,7 @@ import type {
23
23
  ____ViewStyleProp_Internal,
24
24
  } from './StyleSheetTypes';
25
25
 
26
- import composeStyles from '../../src/private/core/composeStyles';
26
+ import composeStyles from '../../src/private/styles/composeStyles';
27
27
 
28
28
  const ReactNativeStyleAttributes = require('../Components/View/ReactNativeStyleAttributes');
29
29
  const PixelRatio = require('../Utilities/PixelRatio').default;
@@ -23,7 +23,7 @@ import type {
23
23
  ____ViewStyleProp_Internal,
24
24
  } from './StyleSheetTypes';
25
25
 
26
- import composeStyles from '../../src/private/core/composeStyles';
26
+ import composeStyles from '../../src/private/styles/composeStyles';
27
27
 
28
28
  const ReactNativeStyleAttributes = require('../Components/View/ReactNativeStyleAttributes');
29
29
  const PixelRatio = require('../Utilities/PixelRatio').default;
@@ -273,6 +273,16 @@ export type BlendMode =
273
273
  | 'color'
274
274
  | 'luminosity';
275
275
 
276
+ export type GradientValue = {
277
+ type: 'linearGradient';
278
+ // Angle or direction enums
279
+ direction: string | undefined;
280
+ colorStops: Array<{
281
+ color: ColorValue;
282
+ position: number | undefined;
283
+ }>;
284
+ };
285
+
276
286
  /**
277
287
  * @see https://reactnative.dev/docs/view#style
278
288
  */
@@ -322,6 +332,7 @@ export interface ViewStyle extends FlexStyle, ShadowStyleIOS, TransformsStyle {
322
332
  * Controls whether the View can be the target of touch events.
323
333
  */
324
334
  pointerEvents?: 'box-none' | 'none' | 'box-only' | 'auto' | undefined;
335
+ isolation?: 'auto' | 'isolate' | undefined;
325
336
  cursor?: CursorValue | undefined;
326
337
  }
327
338
 
@@ -709,6 +709,16 @@ export type DropShadowPrimitive = {
709
709
  color?: ____ColorValue_Internal,
710
710
  };
711
711
 
712
+ export type GradientValue = {
713
+ type: 'linearGradient',
714
+ // Angle or direction enums
715
+ direction?: string,
716
+ colorStops: $ReadOnlyArray<{
717
+ color: ____ColorValue_Internal,
718
+ position?: string,
719
+ }>,
720
+ };
721
+
712
722
  export type BoxShadowPrimitive = {
713
723
  offsetX: number | string,
714
724
  offsetY: number | string,
@@ -778,9 +788,11 @@ export type ____ViewStyle_InternalCore = $ReadOnly<{
778
788
  elevation?: number,
779
789
  pointerEvents?: 'auto' | 'none' | 'box-none' | 'box-only',
780
790
  cursor?: CursorValue,
781
- experimental_boxShadow?: $ReadOnlyArray<BoxShadowPrimitive>,
782
- experimental_filter?: $ReadOnlyArray<FilterFunction>,
791
+ experimental_boxShadow?: $ReadOnlyArray<BoxShadowPrimitive> | string,
792
+ experimental_filter?: $ReadOnlyArray<FilterFunction> | string,
783
793
  experimental_mixBlendMode?: ____BlendMode_Internal,
794
+ experimental_backgroundImage?: $ReadOnlyArray<GradientValue> | string,
795
+ isolation?: 'auto' | 'isolate',
784
796
  }>;
785
797
 
786
798
  export type ____ViewStyle_Internal = $ReadOnly<{
@@ -0,0 +1,286 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ * @flow strict-local
9
+ */
10
+
11
+ 'use strict';
12
+
13
+ import type {ProcessedColorValue} from './processColor';
14
+ import type {GradientValue} from './StyleSheetTypes';
15
+
16
+ const processColor = require('./processColor').default;
17
+ const DIRECTION_REGEX =
18
+ /^to\s+(?:top|bottom|left|right)(?:\s+(?:top|bottom|left|right))?/;
19
+ const ANGLE_UNIT_REGEX = /^([+-]?\d*\.?\d+)(deg|grad|rad|turn)$/i;
20
+
21
+ const TO_BOTTOM_START_END_POINTS = {
22
+ start: {x: 0.5, y: 0},
23
+ end: {x: 0.5, y: 1},
24
+ };
25
+
26
+ type ParsedGradientValue = {
27
+ type: 'linearGradient',
28
+ start: {x: number, y: number},
29
+ end: {x: number, y: number},
30
+ colorStops: $ReadOnlyArray<{
31
+ color: ProcessedColorValue,
32
+ position: number,
33
+ }>,
34
+ };
35
+
36
+ export default function processBackgroundImage(
37
+ backgroundImage: ?($ReadOnlyArray<GradientValue> | string),
38
+ ): $ReadOnlyArray<ParsedGradientValue> {
39
+ let result: $ReadOnlyArray<ParsedGradientValue> = [];
40
+ if (backgroundImage == null) {
41
+ return result;
42
+ }
43
+
44
+ if (typeof backgroundImage === 'string') {
45
+ result = parseCSSLinearGradient(backgroundImage);
46
+ } else if (Array.isArray(backgroundImage)) {
47
+ for (const bgImage of backgroundImage) {
48
+ const processedColorStops = [];
49
+ for (let index = 0; index < bgImage.colorStops.length; index++) {
50
+ const stop = bgImage.colorStops[index];
51
+ const processedColor = processColor(stop.color);
52
+ let processedPosition: number | null = null;
53
+
54
+ // Currently we only support percentage and undefined value for color stop position.
55
+ if (typeof stop.position === 'undefined') {
56
+ processedPosition =
57
+ bgImage.colorStops.length === 1
58
+ ? 1
59
+ : index / (bgImage.colorStops.length - 1);
60
+ } else if (stop.position.endsWith('%')) {
61
+ processedPosition = parseFloat(stop.position) / 100;
62
+ } else {
63
+ // If a color stop position is invalid, return an empty array and do not apply gradient. Same as web.
64
+ return [];
65
+ }
66
+
67
+ if (processedColor != null) {
68
+ processedColorStops.push({
69
+ color: processedColor,
70
+ position: processedPosition,
71
+ });
72
+ } else {
73
+ // If a color is invalid, return an empty array and do not apply gradient. Same as web.
74
+ return [];
75
+ }
76
+ }
77
+
78
+ let points: {
79
+ start: ParsedGradientValue['start'],
80
+ end: ParsedGradientValue['end'],
81
+ } | null = null;
82
+
83
+ if (typeof bgImage.direction === 'undefined') {
84
+ points = TO_BOTTOM_START_END_POINTS;
85
+ } else if (ANGLE_UNIT_REGEX.test(bgImage.direction)) {
86
+ const angle = parseAngle(bgImage.direction);
87
+ if (angle != null) {
88
+ points = calculateStartEndPointsFromAngle(angle);
89
+ }
90
+ } else if (DIRECTION_REGEX.test(bgImage.direction)) {
91
+ const processedPoints = calculateStartEndPointsFromDirection(
92
+ bgImage.direction,
93
+ );
94
+ if (processedPoints != null) {
95
+ points = processedPoints;
96
+ }
97
+ }
98
+
99
+ if (points != null) {
100
+ result = result.concat({
101
+ type: 'linearGradient',
102
+ start: points.start,
103
+ end: points.end,
104
+ colorStops: processedColorStops,
105
+ });
106
+ }
107
+ }
108
+ }
109
+
110
+ return result;
111
+ }
112
+
113
+ function parseCSSLinearGradient(
114
+ cssString: string,
115
+ ): $ReadOnlyArray<ParsedGradientValue> {
116
+ const gradients = [];
117
+ let match;
118
+ const linearGradientRegex = /linear-gradient\s*\(((?:\([^)]*\)|[^())])*)\)/gi;
119
+
120
+ while ((match = linearGradientRegex.exec(cssString))) {
121
+ const gradientContent = match[1];
122
+ const parts = gradientContent.split(',');
123
+ let points = TO_BOTTOM_START_END_POINTS;
124
+ const trimmedDirection = parts[0].trim().toLowerCase();
125
+ const colorStopRegex =
126
+ /\s*((?:(?:rgba?|hsla?)\s*\([^)]+\))|#[0-9a-fA-F]+|[a-zA-Z]+)(?:\s+([0-9.]+%?))?\s*/gi;
127
+
128
+ if (ANGLE_UNIT_REGEX.test(trimmedDirection)) {
129
+ const angle = parseAngle(trimmedDirection);
130
+ if (angle != null) {
131
+ points = calculateStartEndPointsFromAngle(angle);
132
+ parts.shift();
133
+ } else {
134
+ // If an angle is invalid, return an empty array and do not apply any gradient. Same as web.
135
+ return [];
136
+ }
137
+ } else if (DIRECTION_REGEX.test(trimmedDirection)) {
138
+ const parsedPoints =
139
+ calculateStartEndPointsFromDirection(trimmedDirection);
140
+ if (parsedPoints != null) {
141
+ points = parsedPoints;
142
+ parts.shift();
143
+ } else {
144
+ // If a direction is invalid, return an empty array and do not apply any gradient. Same as web.
145
+ return [];
146
+ }
147
+ } else if (!colorStopRegex.test(trimmedDirection)) {
148
+ // If first part is not an angle/direction or a color stop, return an empty array and do not apply any gradient. Same as web.
149
+ return [];
150
+ }
151
+ colorStopRegex.lastIndex = 0;
152
+
153
+ const colorStops = [];
154
+ const fullColorStopsStr = parts.join(',');
155
+ let colorStopMatch;
156
+ while ((colorStopMatch = colorStopRegex.exec(fullColorStopsStr))) {
157
+ const [, color, position] = colorStopMatch;
158
+ const processedColor = processColor(color.trim().toLowerCase());
159
+ if (
160
+ processedColor != null &&
161
+ (typeof position === 'undefined' || position.endsWith('%'))
162
+ ) {
163
+ colorStops.push({
164
+ color: processedColor,
165
+ position: position ? parseFloat(position) / 100 : null,
166
+ });
167
+ } else {
168
+ // If a color or position is invalid, return an empty array and do not apply any gradient. Same as web.
169
+ return [];
170
+ }
171
+ }
172
+
173
+ gradients.push({
174
+ type: 'linearGradient',
175
+ start: points.start,
176
+ end: points.end,
177
+ colorStops: colorStops.map((stop, index, array) => ({
178
+ color: stop.color,
179
+ position:
180
+ stop.position ??
181
+ (array.length === 1 ? 1 : index / (array.length - 1)),
182
+ })),
183
+ });
184
+ }
185
+
186
+ return gradients;
187
+ }
188
+
189
+ function calculateStartEndPointsFromDirection(direction: string): ?{
190
+ start: {x: number, y: number},
191
+ end: {x: number, y: number},
192
+ } {
193
+ // Remove extra whitespace
194
+ const normalizedDirection = direction.replace(/\s+/g, ' ');
195
+
196
+ switch (normalizedDirection) {
197
+ case 'to right':
198
+ return {
199
+ start: {x: 0, y: 0.5},
200
+ end: {x: 1, y: 0.5},
201
+ };
202
+ case 'to left':
203
+ return {
204
+ start: {x: 1, y: 0.5},
205
+ end: {x: 0, y: 0.5},
206
+ };
207
+ case 'to bottom':
208
+ return TO_BOTTOM_START_END_POINTS;
209
+ case 'to top':
210
+ return {
211
+ start: {x: 0.5, y: 1},
212
+ end: {x: 0.5, y: 0},
213
+ };
214
+ case 'to bottom right':
215
+ case 'to right bottom':
216
+ return {
217
+ start: {x: 0, y: 0},
218
+ end: {x: 1, y: 1},
219
+ };
220
+ case 'to top left':
221
+ case 'to left top':
222
+ return {
223
+ start: {x: 1, y: 1},
224
+ end: {x: 0, y: 0},
225
+ };
226
+ case 'to bottom left':
227
+ case 'to left bottom':
228
+ return {
229
+ start: {x: 1, y: 0},
230
+ end: {x: 0, y: 1},
231
+ };
232
+ case 'to top right':
233
+ case 'to right top':
234
+ return {
235
+ start: {x: 0, y: 1},
236
+ end: {x: 1, y: 0},
237
+ };
238
+ default:
239
+ return null;
240
+ }
241
+ }
242
+
243
+ function calculateStartEndPointsFromAngle(angleRadians: number): {
244
+ start: {x: number, y: number},
245
+ end: {x: number, y: number},
246
+ } {
247
+ // Normalize angle to be between 0 and 2π
248
+ let angleRadiansNormalized = angleRadians % (2 * Math.PI);
249
+ if (angleRadiansNormalized < 0) {
250
+ angleRadiansNormalized += 2 * Math.PI;
251
+ }
252
+
253
+ const endX = 0.5 + 0.5 * Math.sin(angleRadiansNormalized);
254
+ const endY = 0.5 - 0.5 * Math.cos(angleRadiansNormalized);
255
+
256
+ const startX = 1 - endX;
257
+ const startY = 1 - endY;
258
+
259
+ return {
260
+ start: {x: startX, y: startY},
261
+ end: {x: endX, y: endY},
262
+ };
263
+ }
264
+
265
+ function parseAngle(angle: string): ?number {
266
+ const match = angle.match(ANGLE_UNIT_REGEX);
267
+ if (!match) {
268
+ return null;
269
+ }
270
+
271
+ const [, value, unit] = match;
272
+
273
+ const numericValue = parseFloat(value);
274
+ switch (unit) {
275
+ case 'deg':
276
+ return (numericValue * Math.PI) / 180;
277
+ case 'grad':
278
+ return (numericValue * Math.PI) / 200;
279
+ case 'rad':
280
+ return numericValue;
281
+ case 'turn':
282
+ return numericValue * 2 * Math.PI;
283
+ default:
284
+ return null;
285
+ }
286
+ }
@@ -8,6 +8,7 @@
8
8
  * @format
9
9
  */
10
10
 
11
+ import type {TextStyleProp} from '../StyleSheet/StyleSheet';
11
12
  import type {____TextStyle_Internal as TextStyleInternal} from '../StyleSheet/StyleSheetTypes';
12
13
  import type {PressEvent} from '../Types/CoreEventTypes';
13
14
  import type {NativeTextProps} from './TextNativeComponent';
@@ -133,7 +134,7 @@ const Text: React.AbstractComponent<TextProps, TextForwardRef> =
133
134
 
134
135
  let _selectable = selectable;
135
136
 
136
- let processedStyle: ?TextStyleInternal = flattenStyle(_style);
137
+ let processedStyle = flattenStyle<TextStyleProp>(_style);
137
138
  if (processedStyle != null) {
138
139
  let overrides: ?{...TextStyleInternal} = null;
139
140
  if (typeof processedStyle.fontWeight === 'number') {
@@ -158,7 +159,7 @@ const Text: React.AbstractComponent<TextProps, TextForwardRef> =
158
159
 
159
160
  if (overrides != null) {
160
161
  // $FlowFixMe[incompatible-type]
161
- processedStyle = [processedStyle, overrides];
162
+ _style = [_style, overrides];
162
163
  }
163
164
  }
164
165
 
@@ -178,7 +179,7 @@ const Text: React.AbstractComponent<TextProps, TextForwardRef> =
178
179
  numberOfLines: _numberOfLines,
179
180
  selectable: _selectable,
180
181
  selectionColor: _selectionColor,
181
- style: processedStyle,
182
+ style: _style,
182
183
  disabled: disabled,
183
184
  children,
184
185
  }}
@@ -212,7 +213,7 @@ const Text: React.AbstractComponent<TextProps, TextForwardRef> =
212
213
  ref={forwardedRef}
213
214
  selectable={_selectable}
214
215
  selectionColor={_selectionColor}
215
- style={processedStyle}
216
+ style={_style}
216
217
  disabled={disabled}>
217
218
  {children}
218
219
  </NativeVirtualText>
@@ -256,7 +257,7 @@ const Text: React.AbstractComponent<TextProps, TextForwardRef> =
256
257
  numberOfLines: _numberOfLines,
257
258
  selectable: _selectable,
258
259
  selectionColor: _selectionColor,
259
- style: processedStyle,
260
+ style: _style,
260
261
  children,
261
262
  }}
262
263
  textPressabilityProps={{
@@ -291,7 +292,7 @@ const Text: React.AbstractComponent<TextProps, TextForwardRef> =
291
292
  ref={forwardedRef}
292
293
  selectable={_selectable}
293
294
  selectionColor={_selectionColor}
294
- style={processedStyle}>
295
+ style={_style}>
295
296
  {children}
296
297
  </NativeText>
297
298
  );
@@ -8,6 +8,7 @@
8
8
  * @format
9
9
  */
10
10
 
11
+ import type {TextStyleProp} from '../StyleSheet/StyleSheet';
11
12
  import type {____TextStyle_Internal as TextStyleInternal} from '../StyleSheet/StyleSheetTypes';
12
13
  import type {PressEvent} from '../Types/CoreEventTypes';
13
14
  import type {NativeTextProps} from './TextNativeComponent';
@@ -157,7 +158,7 @@ const Text: React.AbstractComponent<TextProps, TextForwardRef> =
157
158
 
158
159
  let _selectable = selectable;
159
160
 
160
- let processedStyle: ?TextStyleInternal = flattenStyle(_style);
161
+ let processedStyle = flattenStyle<TextStyleProp>(_style);
161
162
  if (processedStyle != null) {
162
163
  let overrides: ?{...TextStyleInternal} = null;
163
164
  if (typeof processedStyle.fontWeight === 'number') {
@@ -182,7 +183,7 @@ const Text: React.AbstractComponent<TextProps, TextForwardRef> =
182
183
 
183
184
  if (overrides != null) {
184
185
  // $FlowFixMe[incompatible-type]
185
- processedStyle = [processedStyle, overrides];
186
+ _style = [_style, overrides];
186
187
  }
187
188
  }
188
189
 
@@ -208,7 +209,7 @@ const Text: React.AbstractComponent<TextProps, TextForwardRef> =
208
209
  numberOfLines: _numberOfLines,
209
210
  selectable: _selectable,
210
211
  selectionColor: _selectionColor,
211
- style: processedStyle,
212
+ style: _style,
212
213
  disabled: disabled,
213
214
  children,
214
215
  }}
@@ -248,7 +249,7 @@ const Text: React.AbstractComponent<TextProps, TextForwardRef> =
248
249
  ref={forwardedRef}
249
250
  selectable={_selectable}
250
251
  selectionColor={_selectionColor}
251
- style={processedStyle}
252
+ style={_style}
252
253
  disabled={disabled}>
253
254
  {children}
254
255
  </NativeVirtualText>
@@ -298,7 +299,7 @@ const Text: React.AbstractComponent<TextProps, TextForwardRef> =
298
299
  numberOfLines: _numberOfLines,
299
300
  selectable: _selectable,
300
301
  selectionColor: _selectionColor,
301
- style: processedStyle,
302
+ style: _style,
302
303
  children,
303
304
  }}
304
305
  textPressabilityProps={{
@@ -339,7 +340,7 @@ const Text: React.AbstractComponent<TextProps, TextForwardRef> =
339
340
  ref={forwardedRef}
340
341
  selectable={_selectable}
341
342
  selectionColor={_selectionColor}
342
- style={processedStyle}>
343
+ style={_style}>
343
344
  {children}
344
345
  </NativeText>
345
346
  );
@@ -16,6 +16,7 @@ import type {TextProps} from './TextProps';
16
16
  import {createViewConfig} from '../NativeComponent/ViewConfig';
17
17
  import UIManager from '../ReactNative/UIManager';
18
18
  import createReactNativeComponentClass from '../Renderer/shims/createReactNativeComponentClass';
19
+ import Platform from '../Utilities/Platform';
19
20
 
20
21
  export type NativeTextProps = $ReadOnly<{
21
22
  ...TextProps,
@@ -48,6 +49,12 @@ const textViewConfig = {
48
49
  dataDetectorType: true,
49
50
  android_hyphenationFrequency: true,
50
51
  lineBreakStrategyIOS: true,
52
+ // boxShadow is currently per-component on Android instead of being on BaseViewConfig yet
53
+ ...(Platform.OS === 'android' && {
54
+ experimental_boxShadow: {
55
+ process: require('../StyleSheet/processBoxShadow').default,
56
+ },
57
+ }),
51
58
  },
52
59
  directEventTypes: {
53
60
  topTextLayout: {