@office-iss/react-native-win32 0.0.0-canary.257 → 0.0.0-canary.258

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 (31) hide show
  1. package/.flowconfig +4 -2
  2. package/CHANGELOG.json +40 -1
  3. package/CHANGELOG.md +20 -8
  4. package/Libraries/Components/ScrollView/ScrollView.js +124 -165
  5. package/Libraries/Core/InitializeCore.js +2 -0
  6. package/Libraries/Core/ReactNativeVersion.js +3 -3
  7. package/Libraries/Core/ReactNativeVersionCheck.win32.js +1 -1
  8. package/Libraries/Core/setUpGlobals.js +1 -0
  9. package/Libraries/LogBox/UI/LogBoxInspectorHeader.js +20 -8
  10. package/Libraries/LogBox/UI/LogBoxInspectorHeader.win32.js +20 -8
  11. package/Libraries/ReactNative/AppContainer-dev.js +1 -5
  12. package/Libraries/ReactNative/AppContainer-prod.js +1 -5
  13. package/Libraries/ReactNative/AppContainer.js +0 -1
  14. package/Libraries/ReactNative/AppRegistry.js +0 -6
  15. package/Libraries/ReactNative/renderApplication.js +0 -2
  16. package/Libraries/StyleSheet/StyleSheetTypes.d.ts +19 -0
  17. package/Libraries/StyleSheet/StyleSheetTypes.js +19 -1
  18. package/Libraries/StyleSheet/processFilter.js +214 -39
  19. package/Libraries/Text/Text.js +17 -2
  20. package/Libraries/Text/Text.win32.js +17 -2
  21. package/index.js +1 -0
  22. package/index.win32.js +1 -0
  23. package/jest/mockComponent.js +4 -1
  24. package/overrides.json +5 -5
  25. package/package.json +22 -22
  26. package/src/private/core/components/HScrollViewNativeComponents.js +55 -0
  27. package/src/private/core/components/VScrollViewNativeComponents.js +47 -0
  28. package/src/private/core/components/useSyncOnScroll.js +48 -0
  29. package/src/private/featureflags/ReactNativeFeatureFlags.js +12 -1
  30. package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +2 -1
  31. package/src/private/specs/modules/NativeSampleTurboModule.js +14 -1
@@ -36,7 +36,7 @@ const checkVersions = function checkVersions(): void {
36
36
  `Native version: ${_formatVersion(nativeVersion)}\n\n` +
37
37
  'Make sure that you have rebuilt the native code. If the problem ' +
38
38
  'persists try clearing the Watchman and packager caches with ' +
39
- '`watchman watch-del-all && npx react-native start --reset-cache`.',
39
+ '`watchman watch-del-all && npx @react-native-community/cli start --reset-cache`.',
40
40
  );
41
41
  }
42
42
  };
@@ -8,6 +8,7 @@
8
8
  * @format
9
9
  */
10
10
 
11
+ 'use client';
11
12
  'use strict';
12
13
 
13
14
  /**
@@ -8,9 +8,10 @@
8
8
  * @format
9
9
  */
10
10
 
11
+ import type {ViewProps} from '../../Components/View/ViewPropTypes';
11
12
  import type {LogLevel} from '../Data/LogBoxLog';
12
13
 
13
- import StatusBar from '../../Components/StatusBar/StatusBar';
14
+ import SafeAreaView from '../../Components/SafeAreaView/SafeAreaView';
14
15
  import View from '../../Components/View/View';
15
16
  import StyleSheet from '../../StyleSheet/StyleSheet';
16
17
  import Text from '../../Text/Text';
@@ -26,16 +27,30 @@ type Props = $ReadOnly<{
26
27
  level: LogLevel,
27
28
  }>;
28
29
 
30
+ const LogBoxInspectorHeaderSafeArea: React.AbstractComponent<ViewProps> =
31
+ Platform.OS === 'android'
32
+ ? function LogBoxInspectorHeaderSafeArea(props) {
33
+ // NOTE: Inline the import of `StatusBar` so that initializing this module
34
+ // does not require initializing a TurboModule (and main thread one, too).
35
+ const {currentHeight} = require('../../Components/StatusBar/StatusBar');
36
+ const style = StyleSheet.compose(
37
+ {paddingTop: currentHeight},
38
+ props.style,
39
+ );
40
+ return <View {...props} style={style} />;
41
+ }
42
+ : SafeAreaView;
43
+
29
44
  export default function LogBoxInspectorHeader(props: Props): React.Node {
30
45
  if (props.level === 'syntax') {
31
46
  return (
32
- <View style={[styles.safeArea, styles[props.level]]}>
47
+ <LogBoxInspectorHeaderSafeArea style={styles[props.level]}>
33
48
  <View style={styles.header}>
34
49
  <View style={styles.title}>
35
50
  <Text style={styles.titleText}>Failed to compile</Text>
36
51
  </View>
37
52
  </View>
38
- </View>
53
+ </LogBoxInspectorHeaderSafeArea>
39
54
  );
40
55
  }
41
56
 
@@ -47,7 +62,7 @@ export default function LogBoxInspectorHeader(props: Props): React.Node {
47
62
  const titleText = `Log ${props.selectedIndex + 1} of ${props.total}`;
48
63
 
49
64
  return (
50
- <View style={[styles.safeArea, styles[props.level]]}>
65
+ <LogBoxInspectorHeaderSafeArea style={styles[props.level]}>
51
66
  <View style={styles.header}>
52
67
  <LogBoxInspectorHeaderButton
53
68
  disabled={props.total <= 1}
@@ -65,7 +80,7 @@ export default function LogBoxInspectorHeader(props: Props): React.Node {
65
80
  onPress={() => props.onSelectIndex(nextIndex)}
66
81
  />
67
82
  </View>
68
- </View>
83
+ </LogBoxInspectorHeaderSafeArea>
69
84
  );
70
85
  }
71
86
 
@@ -101,7 +116,4 @@ const styles = StyleSheet.create({
101
116
  includeFontPadding: false,
102
117
  lineHeight: 20,
103
118
  },
104
- safeArea: {
105
- paddingTop: Platform.OS === 'android' ? StatusBar.currentHeight : 40,
106
- },
107
119
  });
@@ -10,9 +10,10 @@
10
10
 
11
11
  'use strict';
12
12
 
13
+ import type {ViewProps} from '../../Components/View/ViewPropTypes';
13
14
  import type {LogLevel} from '../Data/LogBoxLog';
14
15
 
15
- import StatusBar from '../../Components/StatusBar/StatusBar';
16
+ import SafeAreaView from '../../Components/SafeAreaView/SafeAreaView';
16
17
  import View from '../../Components/View/View';
17
18
  import StyleSheet from '../../StyleSheet/StyleSheet';
18
19
  import Text from '../../Text/Text';
@@ -28,16 +29,30 @@ type Props = $ReadOnly<{
28
29
  level: LogLevel,
29
30
  }>;
30
31
 
32
+ const LogBoxInspectorHeaderSafeArea: React.AbstractComponent<ViewProps> =
33
+ Platform.OS === 'android'
34
+ ? function LogBoxInspectorHeaderSafeArea(props) {
35
+ // NOTE: Inline the import of `StatusBar` so that initializing this module
36
+ // does not require initializing a TurboModule (and main thread one, too).
37
+ const {currentHeight} = require('../../Components/StatusBar/StatusBar');
38
+ const style = StyleSheet.compose(
39
+ {paddingTop: currentHeight},
40
+ props.style,
41
+ );
42
+ return <View {...props} style={style} />;
43
+ }
44
+ : SafeAreaView;
45
+
31
46
  export default function LogBoxInspectorHeader(props: Props): React.Node {
32
47
  if (props.level === 'syntax') {
33
48
  return (
34
- <View style={[styles.safeArea, styles[props.level]]}>
49
+ <LogBoxInspectorHeaderSafeArea style={styles[props.level]}>
35
50
  <View style={styles.header}>
36
51
  <View style={styles.title}>
37
52
  <Text style={styles.titleText}>Failed to compile</Text>
38
53
  </View>
39
54
  </View>
40
- </View>
55
+ </LogBoxInspectorHeaderSafeArea>
41
56
  );
42
57
  }
43
58
 
@@ -49,7 +64,7 @@ export default function LogBoxInspectorHeader(props: Props): React.Node {
49
64
  const titleText = `Log ${props.selectedIndex + 1} of ${props.total}`;
50
65
 
51
66
  return (
52
- <View style={[styles.safeArea, styles[props.level]]}>
67
+ <LogBoxInspectorHeaderSafeArea style={styles[props.level]}>
53
68
  <View style={styles.header}>
54
69
  <LogBoxInspectorHeaderButton
55
70
  disabled={props.total <= 1}
@@ -67,7 +82,7 @@ export default function LogBoxInspectorHeader(props: Props): React.Node {
67
82
  onPress={() => props.onSelectIndex(nextIndex)}
68
83
  />
69
84
  </View>
70
- </View>
85
+ </LogBoxInspectorHeaderSafeArea>
71
86
  );
72
87
  }
73
88
 
@@ -106,7 +121,4 @@ const styles = StyleSheet.create({
106
121
  includeFontPadding: false,
107
122
  lineHeight: 20,
108
123
  },
109
- safeArea: {
110
- paddingTop: Platform.OS === 'android' ? StatusBar.currentHeight : 40,
111
- },
112
124
  });
@@ -90,7 +90,6 @@ const AppContainer = ({
90
90
  internal_excludeInspector = false,
91
91
  internal_excludeLogBox = false,
92
92
  rootTag,
93
- showArchitectureIndicator,
94
93
  WrapperComponent,
95
94
  rootViewStyle,
96
95
  }: Props): React.Node => {
@@ -150,10 +149,7 @@ const AppContainer = ({
150
149
 
151
150
  if (WrapperComponent != null) {
152
151
  innerView = (
153
- <WrapperComponent
154
- initialProps={initialProps}
155
- fabric={fabric === true}
156
- showArchitectureIndicator={showArchitectureIndicator === true}>
152
+ <WrapperComponent initialProps={initialProps} fabric={fabric === true}>
157
153
  {innerView}
158
154
  </WrapperComponent>
159
155
  );
@@ -21,7 +21,6 @@ const AppContainer = ({
21
21
  fabric,
22
22
  initialProps,
23
23
  rootTag,
24
- showArchitectureIndicator,
25
24
  WrapperComponent,
26
25
  rootViewStyle,
27
26
  }: Props): React.Node => {
@@ -29,10 +28,7 @@ const AppContainer = ({
29
28
 
30
29
  if (WrapperComponent != null) {
31
30
  innerView = (
32
- <WrapperComponent
33
- initialProps={initialProps}
34
- fabric={fabric === true}
35
- showArchitectureIndicator={showArchitectureIndicator === true}>
31
+ <WrapperComponent initialProps={initialProps} fabric={fabric === true}>
36
32
  {innerView}
37
33
  </WrapperComponent>
38
34
  );
@@ -18,7 +18,6 @@ export type Props = $ReadOnly<{|
18
18
  fabric?: boolean,
19
19
  rootTag: number | RootTag,
20
20
  initialProps?: {...},
21
- showArchitectureIndicator?: boolean,
22
21
  WrapperComponent?: ?React.ComponentType<any>,
23
22
  rootViewStyle?: ?ViewStyleProp,
24
23
  internal_excludeLogBox?: boolean,
@@ -73,7 +73,6 @@ let componentProviderInstrumentationHook: ComponentProviderInstrumentationHook =
73
73
 
74
74
  let wrapperComponentProvider: ?WrapperComponentProvider;
75
75
  let rootViewStyleProvider: ?RootViewStyleProvider;
76
- let showArchitectureIndicator = false;
77
76
 
78
77
  /**
79
78
  * `AppRegistry` is the JavaScript entry point to running all React Native apps.
@@ -89,10 +88,6 @@ const AppRegistry = {
89
88
  rootViewStyleProvider = provider;
90
89
  },
91
90
 
92
- enableArchitectureIndicator(enabled: boolean): void {
93
- showArchitectureIndicator = enabled;
94
- },
95
-
96
91
  registerConfig(config: Array<AppConfig>): void {
97
92
  config.forEach(appConfig => {
98
93
  if (appConfig.run) {
@@ -139,7 +134,6 @@ const AppRegistry = {
139
134
  wrapperComponentProvider && wrapperComponentProvider(appParameters),
140
135
  rootViewStyleProvider && rootViewStyleProvider(appParameters),
141
136
  appParameters.fabric,
142
- showArchitectureIndicator,
143
137
  scopedPerformanceLogger,
144
138
  appKey === 'LogBox', // is logbox
145
139
  appKey,
@@ -35,7 +35,6 @@ export default function renderApplication<Props: Object>(
35
35
  WrapperComponent?: ?React.ComponentType<any>,
36
36
  rootViewStyle?: ?ViewStyleProp,
37
37
  fabric?: boolean,
38
- showArchitectureIndicator?: boolean,
39
38
  scopedPerformanceLogger?: IPerformanceLogger,
40
39
  isLogBox?: boolean,
41
40
  debugName?: string,
@@ -52,7 +51,6 @@ export default function renderApplication<Props: Object>(
52
51
  <AppContainer
53
52
  rootTag={rootTag}
54
53
  fabric={fabric}
55
- showArchitectureIndicator={showArchitectureIndicator}
56
54
  WrapperComponent={WrapperComponent}
57
55
  rootViewStyle={rootViewStyle}
58
56
  initialProps={initialProps ?? Object.freeze({})}
@@ -11,6 +11,25 @@ import {Animated} from '../Animated/Animated';
11
11
  import {ImageResizeMode} from '../Image/ImageResizeMode';
12
12
  import {ColorValue} from './StyleSheet';
13
13
 
14
+ export type FilterPrimitive =
15
+ | {brightness: number | string}
16
+ | {blur: number | string}
17
+ | {contrast: number | string}
18
+ | {grayscale: number | string}
19
+ | {'hue-rotate': number | string}
20
+ | {invert: number | string}
21
+ | {opacity: number | string}
22
+ | {saturate: number | string}
23
+ | {sepia: number | string}
24
+ | {'drop-shadow': DropShadowPrimitive | string};
25
+
26
+ export type DropShadowPrimitive = {
27
+ offsetX: number | string;
28
+ offsetY: number | string;
29
+ standardDeviation?: number | string | undefined;
30
+ color?: ColorValue | number | undefined;
31
+ };
32
+
14
33
  type FlexAlignType =
15
34
  | 'flex-start'
16
35
  | 'flex-end'
@@ -11,7 +11,6 @@
11
11
  'use strict';
12
12
 
13
13
  import type AnimatedNode from '../Animated/nodes/AnimatedNode';
14
- import type {FilterPrimitive} from '../StyleSheet/processFilter';
15
14
  import type {
16
15
  ____DangerouslyImpreciseStyle_InternalOverrides,
17
16
  ____ImageStyle_InternalOverrides,
@@ -35,6 +34,25 @@ export type EdgeInsetsValue = {
35
34
  bottom: number,
36
35
  };
37
36
 
37
+ export type FilterPrimitive =
38
+ | {brightness: number | string}
39
+ | {blur: number | string}
40
+ | {contrast: number | string}
41
+ | {grayscale: number | string}
42
+ | {'hue-rotate': number | string}
43
+ | {invert: number | string}
44
+ | {opacity: number | string}
45
+ | {saturate: number | string}
46
+ | {sepia: number | string}
47
+ | {'drop-shadow': DropShadowPrimitive | string};
48
+
49
+ export type DropShadowPrimitive = {
50
+ offsetX: number | string,
51
+ offsetY: number | string,
52
+ standardDeviation?: number | string,
53
+ color?: ____ColorValue_Internal | number,
54
+ };
55
+
38
56
  export type DimensionValue = number | string | 'auto' | AnimatedNode | null;
39
57
  export type AnimatableNumericValue = number | AnimatedNode;
40
58
 
@@ -4,64 +4,97 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @format
7
+ * @format strict-local
8
8
  * @flow
9
+ * @oncall react-native
9
10
  */
10
11
 
11
12
  'use strict';
12
13
 
13
- export type FilterPrimitive =
14
- | {brightness: number | string}
15
- | {blur: number | string}
16
- | {contrast: number | string}
17
- | {grayscale: number | string}
18
- | {hueRotate: number | string}
19
- | {invert: number | string}
20
- | {opacity: number | string}
21
- | {saturate: number | string}
22
- | {sepia: number | string};
14
+ import type {ColorValue} from './StyleSheet';
15
+ import type {DropShadowPrimitive, FilterPrimitive} from './StyleSheetTypes';
16
+
17
+ import processColor from './processColor';
18
+
19
+ type ParsedFilter =
20
+ | {brightness: number}
21
+ | {blur: number}
22
+ | {contrast: number}
23
+ | {grayscale: number}
24
+ | {'hue-rotate': number}
25
+ | {invert: number}
26
+ | {opacity: number}
27
+ | {saturate: number}
28
+ | {sepia: number}
29
+ | {'drop-shadow': ParsedDropShadow};
30
+
31
+ type ParsedDropShadow = {
32
+ offsetX: number,
33
+ offsetY: number,
34
+ standardDeviation?: number,
35
+ color?: ColorValue,
36
+ };
23
37
 
24
38
  export default function processFilter(
25
39
  filter: $ReadOnlyArray<FilterPrimitive> | string,
26
- ): $ReadOnlyArray<FilterPrimitive> {
27
- let result: Array<FilterPrimitive> = [];
40
+ ): $ReadOnlyArray<ParsedFilter> {
41
+ let result: Array<ParsedFilter> = [];
28
42
  if (typeof filter === 'string') {
29
- // matches on functions with args like "brightness(1.5)"
30
- const regex = new RegExp(/(\w+)\(([^)]+)\)/g);
43
+ // matches on functions with args like "drop-shadow(1.5)"
44
+ const regex = /([\w-]+)\(([^)]+)\)/g;
31
45
  let matches;
32
46
 
33
47
  while ((matches = regex.exec(filter))) {
34
- const amount = _getFilterAmount(matches[1], matches[2]);
35
-
36
- if (amount != null) {
37
- const filterPrimitive = {};
38
- // $FlowFixMe The key will be the correct one but flow can't see that.
39
- filterPrimitive[matches[1]] = amount;
40
- // $FlowFixMe The key will be the correct one but flow can't see that.
41
- result.push(filterPrimitive);
48
+ let filterName = matches[1].toLowerCase();
49
+ if (filterName === 'drop-shadow') {
50
+ const dropShadow = parseDropShadow(matches[2]);
51
+ if (dropShadow != null) {
52
+ result.push({'drop-shadow': dropShadow});
53
+ } else {
54
+ return [];
55
+ }
42
56
  } else {
43
- // If any primitive is invalid then apply none of the filters. This is how
44
- // web works and makes it clear that something is wrong becuase no
45
- // graphical effects are happening.
46
- return [];
57
+ const amount = _getFilterAmount(filterName, matches[2]);
58
+
59
+ if (amount != null) {
60
+ const filterPrimitive = {};
61
+ // $FlowFixMe The key will be the correct one but flow can't see that.
62
+ filterPrimitive[filterName] = amount;
63
+ // $FlowFixMe The key will be the correct one but flow can't see that.
64
+ result.push(filterPrimitive);
65
+ } else {
66
+ // If any primitive is invalid then apply none of the filters. This is how
67
+ // web works and makes it clear that something is wrong becuase no
68
+ // graphical effects are happening.
69
+ return [];
70
+ }
47
71
  }
48
72
  }
49
73
  } else {
50
74
  for (const filterPrimitive of filter) {
51
75
  const [filterName, filterValue] = Object.entries(filterPrimitive)[0];
52
- const amount = _getFilterAmount(filterName, filterValue);
53
-
54
- if (amount != null) {
55
- const resultObject = {};
76
+ if (filterName === 'drop-shadow') {
56
77
  // $FlowFixMe
57
- resultObject[filterName] = amount;
58
- // $FlowFixMe
59
- result.push(resultObject);
78
+ const dropShadow = parseDropShadow(filterValue);
79
+ if (dropShadow == null) {
80
+ return [];
81
+ }
82
+ result.push({'drop-shadow': dropShadow});
60
83
  } else {
61
- // If any primitive is invalid then apply none of the filters. This is how
62
- // web works and makes it clear that something is wrong becuase no
63
- // graphical effects are happening.
64
- return [];
84
+ const amount = _getFilterAmount(filterName, filterValue);
85
+
86
+ if (amount != null) {
87
+ const resultObject = {};
88
+ // $FlowFixMe
89
+ resultObject[filterName] = amount;
90
+ // $FlowFixMe
91
+ result.push(resultObject);
92
+ } else {
93
+ // If any primitive is invalid then apply none of the filters. This is how
94
+ // web works and makes it clear that something is wrong becuase no
95
+ // graphical effects are happening.
96
+ return [];
97
+ }
65
98
  }
66
99
  }
67
100
  }
@@ -92,7 +125,7 @@ function _getFilterAmount(filterName: string, filterArgs: mixed): ?number {
92
125
  switch (filterName) {
93
126
  // Hue rotate takes some angle that can have a unit and can be
94
127
  // negative. Additionally, 0 with no unit is allowed.
95
- case 'hueRotate':
128
+ case 'hue-rotate':
96
129
  if (filterArgAsNumber === 0) {
97
130
  return 0;
98
131
  }
@@ -130,3 +163,145 @@ function _getFilterAmount(filterName: string, filterArgs: mixed): ?number {
130
163
  return undefined;
131
164
  }
132
165
  }
166
+
167
+ function parseDropShadow(
168
+ rawDropShadow: string | DropShadowPrimitive,
169
+ ): ?ParsedDropShadow {
170
+ const dropShadow =
171
+ typeof rawDropShadow === 'string'
172
+ ? parseDropShadowString(rawDropShadow)
173
+ : rawDropShadow;
174
+
175
+ const parsedDropShadow: ParsedDropShadow = {
176
+ offsetX: 0,
177
+ offsetY: 0,
178
+ };
179
+ let offsetX: number;
180
+ let offsetY: number;
181
+
182
+ for (const arg in dropShadow) {
183
+ let value;
184
+ switch (arg) {
185
+ case 'offsetX':
186
+ value =
187
+ typeof dropShadow.offsetX === 'string'
188
+ ? parseLength(dropShadow.offsetX)
189
+ : dropShadow.offsetX;
190
+ if (value == null) {
191
+ return null;
192
+ }
193
+ offsetX = value;
194
+ break;
195
+ case 'offsetY':
196
+ value =
197
+ typeof dropShadow.offsetY === 'string'
198
+ ? parseLength(dropShadow.offsetY)
199
+ : dropShadow.offsetY;
200
+ if (value == null) {
201
+ return null;
202
+ }
203
+ offsetY = value;
204
+ break;
205
+ case 'standardDeviation':
206
+ value =
207
+ typeof dropShadow.standardDeviation === 'string'
208
+ ? parseLength(dropShadow.standardDeviation)
209
+ : dropShadow.standardDeviation;
210
+ if (value == null || value < 0) {
211
+ return null;
212
+ }
213
+ parsedDropShadow.standardDeviation = value;
214
+ break;
215
+ case 'color':
216
+ const color = processColor(dropShadow.color);
217
+ if (color == null) {
218
+ return null;
219
+ }
220
+ parsedDropShadow.color = color;
221
+ break;
222
+ default:
223
+ return null;
224
+ }
225
+ }
226
+
227
+ if (offsetX == null || offsetY == null) {
228
+ return null;
229
+ }
230
+
231
+ parsedDropShadow.offsetX = offsetX;
232
+ parsedDropShadow.offsetY = offsetY;
233
+
234
+ return parsedDropShadow;
235
+ }
236
+
237
+ function parseDropShadowString(rawDropShadow: string): ?DropShadowPrimitive {
238
+ const dropShadow: DropShadowPrimitive = {
239
+ offsetX: 0,
240
+ offsetY: 0,
241
+ };
242
+ let offsetX: string;
243
+ let offsetY: string;
244
+ let lengthCount = 0;
245
+ let keywordDetectedAfterLength = false;
246
+
247
+ // split on all whitespaces
248
+ for (const arg of rawDropShadow.split(/\s+/)) {
249
+ const processedColor = processColor(arg);
250
+ if (processedColor != null) {
251
+ if (dropShadow.color != null) {
252
+ return null;
253
+ }
254
+ if (offsetX != null) {
255
+ keywordDetectedAfterLength = true;
256
+ }
257
+ dropShadow.color = arg;
258
+ continue;
259
+ }
260
+
261
+ switch (lengthCount) {
262
+ case 0:
263
+ offsetX = arg;
264
+ lengthCount++;
265
+ break;
266
+ case 1:
267
+ if (keywordDetectedAfterLength) {
268
+ return null;
269
+ }
270
+ offsetY = arg;
271
+ lengthCount++;
272
+ break;
273
+ case 2:
274
+ if (keywordDetectedAfterLength) {
275
+ return null;
276
+ }
277
+ dropShadow.standardDeviation = arg;
278
+ lengthCount++;
279
+ break;
280
+ default:
281
+ return null;
282
+ }
283
+ }
284
+ if (offsetX == null || offsetY == null) {
285
+ return null;
286
+ }
287
+
288
+ dropShadow.offsetX = offsetX;
289
+ dropShadow.offsetY = offsetY;
290
+ return dropShadow;
291
+ }
292
+
293
+ function parseLength(length: string): ?number {
294
+ // matches on args with units like "1.5 5% -80deg"
295
+ const argsWithUnitsRegex = /([+-]?\d*(\.\d+)?)([\w\W]+)?/g;
296
+ const match = argsWithUnitsRegex.exec(length);
297
+
298
+ if (!match || Number.isNaN(match[1])) {
299
+ return null;
300
+ }
301
+
302
+ if (match[3] != null && match[3] !== 'px') {
303
+ return null;
304
+ }
305
+
306
+ return Number(match[1]);
307
+ }
@@ -11,6 +11,7 @@
11
11
  import type {PressEvent} from '../Types/CoreEventTypes';
12
12
  import type {TextProps} from './TextProps';
13
13
 
14
+ import * as ReactNativeFeatureFlags from '../../src/private/featureflags/ReactNativeFeatureFlags';
14
15
  import * as PressabilityDebug from '../Pressability/PressabilityDebug';
15
16
  import usePressability from '../Pressability/usePressability';
16
17
  import flattenStyle from '../StyleSheet/flattenStyle';
@@ -18,6 +19,7 @@ import processColor from '../StyleSheet/processColor';
18
19
  import Platform from '../Utilities/Platform';
19
20
  import TextAncestor from './TextAncestor';
20
21
  import {NativeText, NativeVirtualText} from './TextNativeComponent';
22
+ import TextOptimized from './TextOptimized';
21
23
  import * as React from 'react';
22
24
  import {useContext, useMemo, useState} from 'react';
23
25
 
@@ -26,7 +28,7 @@ import {useContext, useMemo, useState} from 'react';
26
28
  *
27
29
  * @see https://reactnative.dev/docs/text
28
30
  */
29
- const Text: React.AbstractComponent<
31
+ const TextLegacy: React.AbstractComponent<
30
32
  TextProps,
31
33
  React.ElementRef<typeof NativeText | typeof NativeVirtualText>,
32
34
  > = React.forwardRef((props: TextProps, forwardedRef) => {
@@ -307,7 +309,7 @@ const Text: React.AbstractComponent<
307
309
  );
308
310
  });
309
311
 
310
- Text.displayName = 'Text';
312
+ TextLegacy.displayName = 'TextLegacy';
311
313
 
312
314
  /**
313
315
  * Returns false until the first time `newValue` is true, after which this will
@@ -337,4 +339,17 @@ const verticalAlignToTextAlignVerticalMap = {
337
339
  middle: 'center',
338
340
  };
339
341
 
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
+
340
355
  module.exports = Text;