@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.
- package/.flowconfig +2 -4
- package/CHANGELOG.json +31 -1
- package/CHANGELOG.md +24 -8
- package/Libraries/Alert/Alert.js +3 -0
- package/Libraries/Animated/AnimatedImplementation.js +7 -7
- package/Libraries/Animated/animations/Animation.js +10 -0
- package/Libraries/Animated/animations/TimingAnimation.js +1 -0
- package/Libraries/Animated/components/AnimatedScrollView.js +2 -2
- package/Libraries/Animated/createAnimatedComponent.js +1 -1
- package/Libraries/Animated/nodes/AnimatedValue.js +1 -0
- package/Libraries/Animated/useAnimatedProps.js +138 -6
- package/Libraries/BatchedBridge/NativeModules.js +2 -0
- package/Libraries/Blob/FileReader.js +1 -1
- package/Libraries/Blob/URL.js +2 -62
- package/Libraries/Blob/URLSearchParams.js +71 -0
- package/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js +1 -1
- package/Libraries/Components/RefreshControl/__mocks__/RefreshControlMock.js +1 -1
- package/Libraries/Components/ScrollView/AndroidHorizontalScrollViewNativeComponent.js +3 -0
- package/Libraries/Components/ScrollView/ScrollView.js +5 -5
- package/Libraries/Components/ScrollView/ScrollViewNativeComponent.js +3 -0
- package/Libraries/Components/ScrollView/ScrollViewStickyHeader.js +1 -1
- package/Libraries/Components/StatusBar/StatusBar.js +3 -1
- package/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js +3 -0
- package/Libraries/Components/TextInput/TextInput.d.ts +32 -2
- package/Libraries/Components/TextInput/TextInput.js +220 -80
- package/Libraries/Components/TextInput/TextInput.win32.js +220 -86
- package/Libraries/Components/View/ReactNativeStyleAttributes.js +22 -0
- package/Libraries/Components/View/ReactNativeViewAttributes.js +2 -0
- package/Libraries/Components/View/ReactNativeViewAttributes.win32.js +2 -0
- package/Libraries/Components/View/ViewAccessibility.d.ts +15 -0
- package/Libraries/Components/View/ViewNativeComponent.js +6 -0
- package/Libraries/Components/View/ViewPropTypes.js +14 -0
- package/Libraries/Components/View/ViewPropTypes.win32.js +14 -0
- package/Libraries/Core/ExceptionsManager.js +2 -0
- package/Libraries/Core/InitializeCore.js +1 -1
- package/Libraries/Core/ReactFiberErrorDialog.js +3 -0
- package/Libraries/Core/ReactNativeVersion.js +1 -1
- package/Libraries/Core/setUpErrorHandling.js +7 -1
- package/Libraries/Core/setUpReactRefresh.js +0 -4
- package/Libraries/Image/AssetSourceResolver.js +28 -1
- package/Libraries/Image/Image.android.js +9 -14
- package/Libraries/Image/Image.ios.js +11 -22
- package/Libraries/Image/Image.win32.js +10 -21
- package/Libraries/Image/ImageBackground.js +1 -8
- package/Libraries/Image/ImageUtils.js +9 -9
- package/Libraries/Image/ImageViewNativeComponent.js +4 -0
- package/Libraries/Inspector/NetworkOverlay.js +1 -1
- package/Libraries/Interaction/TaskQueue.js +1 -0
- package/Libraries/Lists/FlatList.js +1 -1
- package/Libraries/Lists/SectionList.js +2 -2
- package/Libraries/Lists/SectionListModern.js +1 -1
- package/Libraries/LogBox/Data/LogBoxData.js +31 -4
- package/Libraries/NativeComponent/BaseViewConfig.android.js +2 -0
- package/Libraries/NativeComponent/BaseViewConfig.ios.js +7 -0
- package/Libraries/NativeComponent/BaseViewConfig.win32.js +7 -0
- package/Libraries/NativeComponent/NativeComponentRegistry.js +9 -2
- package/Libraries/Network/XMLHttpRequest.js +4 -2
- package/Libraries/ReactNative/BridgelessUIManager.js +1 -0
- package/Libraries/ReactNative/ReactFabricPublicInstance/ReactFabricHostComponent.js +1 -1
- package/Libraries/ReactNative/ReactFabricPublicInstance/ReactFabricPublicInstance.js +5 -5
- package/Libraries/ReactNative/RendererImplementation.js +24 -2
- package/Libraries/ReactNative/getNativeComponentAttributes.js +8 -0
- package/Libraries/Renderer/shims/ReactNativeTypes.js +3 -1
- package/Libraries/StyleSheet/StyleSheet.js +1 -1
- package/Libraries/StyleSheet/StyleSheet.win32.js +1 -1
- package/Libraries/StyleSheet/StyleSheetTypes.d.ts +57 -19
- package/Libraries/StyleSheet/StyleSheetTypes.js +60 -23
- package/Libraries/StyleSheet/processBackgroundImage.js +286 -0
- package/Libraries/StyleSheet/processBoxShadow.js +211 -0
- package/Libraries/StyleSheet/processFilter.js +24 -14
- package/Libraries/Text/Text.js +395 -212
- package/Libraries/Text/Text.win32.js +443 -245
- package/Libraries/Text/TextNativeComponent.js +7 -0
- package/Libraries/Text/TextNativeComponent.win32.js +7 -0
- package/Libraries/TurboModule/TurboModuleRegistry.js +13 -50
- package/Libraries/Types/CodegenTypes.js +3 -1
- package/Libraries/Utilities/HMRClient.js +1 -0
- package/Libraries/Utilities/Platform.android.js +1 -1
- package/Libraries/Utilities/Platform.d.ts +1 -1
- package/Libraries/Utilities/Platform.flow.js +2 -2
- package/Libraries/Utilities/Platform.flow.win32.js +3 -3
- package/Libraries/Utilities/Platform.ios.js +1 -1
- package/Libraries/Utilities/Platform.win32.js +1 -1
- package/Libraries/Utilities/ReactNativeTestTools.js +1 -1
- package/Libraries/WebSocket/WebSocket.js +1 -1
- package/Libraries/vendor/emitter/EventEmitter.js +1 -0
- package/flow/jest.js +2 -2
- package/index.js +1 -0
- package/index.win32.js +1 -0
- package/jest/mockModal.js +1 -3
- package/jest/mockScrollView.js +1 -1
- package/jest/renderer.js +2 -2
- package/jest/setup.js +16 -9
- package/overrides.json +16 -16
- package/package.json +15 -15
- package/src/private/{core/components → components}/HScrollViewNativeComponents.js +8 -8
- package/src/private/{core/components → components}/VScrollViewNativeComponents.js +7 -7
- package/src/private/{core/components → components}/useSyncOnScroll.js +2 -2
- package/src/private/featureflags/ReactNativeFeatureFlags.js +143 -19
- package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +25 -5
- package/src/private/hooks/DebouncedEffectImplementation.js +148 -0
- package/src/private/hooks/useDebouncedEffect.js +23 -0
- package/{Libraries/Core → src/private/renderer/errorhandling}/ErrorHandlers.js +14 -4
- package/src/private/setup/setUpDOM.js +28 -0
- package/src/private/setup/setUpIntersectionObserver.js +27 -0
- package/src/private/setup/setUpMutationObserver.js +26 -0
- package/src/private/setup/setUpPerformanceObserver.js +64 -0
- package/src/private/specs/modules/NativeDebuggerSessionObserver.js +23 -0
- package/src/private/specs/modules/NativeLinkingManager.js +1 -1
- package/src/private/specs/modules/NativePlatformConstantsAndroid.js +1 -1
- package/src/private/specs/modules/NativePlatformConstantsIOS.js +1 -1
- package/src/private/specs/modules/NativePlatformConstantsWin.js +8 -1
- package/src/private/webapis/dom/nodes/ReadOnlyNode.js +6 -4
- package/{Libraries/IntersectionObserver → src/private/webapis/intersectionobserver}/IntersectionObserver.js +1 -1
- package/{Libraries/IntersectionObserver → src/private/webapis/intersectionobserver}/IntersectionObserverEntry.js +3 -3
- package/{Libraries/IntersectionObserver → src/private/webapis/intersectionobserver}/IntersectionObserverManager.js +5 -8
- package/src/private/{specs/modules → webapis/intersectionobserver/specs}/NativeIntersectionObserver.js +2 -2
- package/{Libraries/IntersectionObserver → src/private/webapis/intersectionobserver/specs}/__mocks__/NativeIntersectionObserver.js +4 -4
- package/{Libraries/MutationObserver → src/private/webapis/mutationobserver}/MutationObserver.js +1 -1
- package/{Libraries/MutationObserver → src/private/webapis/mutationobserver}/MutationObserverManager.js +5 -5
- package/{Libraries/MutationObserver → src/private/webapis/mutationobserver}/MutationRecord.js +4 -6
- package/src/private/{specs/modules → webapis/mutationobserver/specs}/NativeMutationObserver.js +2 -2
- package/{Libraries/MutationObserver → src/private/webapis/mutationobserver/specs}/__mocks__/NativeMutationObserver.js +5 -5
- package/src/private/webapis/performance/{EventCounts.js → EventTiming.js} +65 -3
- package/src/private/webapis/performance/LongTasks.js +39 -0
- package/src/private/webapis/performance/Performance.js +22 -9
- package/src/private/webapis/performance/PerformanceEntry.js +36 -18
- package/src/private/webapis/performance/PerformanceObserver.js +29 -43
- package/src/private/webapis/performance/RawPerformanceEntry.js +24 -1
- package/src/private/webapis/performance/UserTiming.js +17 -12
- package/src/private/webapis/performance/specs/NativePerformanceObserver.js +1 -1
- package/src-win/Libraries/Components/View/ViewAccessibility.d.ts +15 -0
- package/types/experimental.d.ts +20 -1
- package/Libraries/Core/setUpIntersectionObserver.js +0 -16
- package/Libraries/Core/setUpMutationObserver.js +0 -16
- package/Libraries/Core/setUpPerformanceObserver.js +0 -18
- package/Libraries/IntersectionObserver/NativeIntersectionObserver.js +0 -13
- package/Libraries/MutationObserver/NativeMutationObserver.js +0 -13
- package/Libraries/Text/TextOptimized.js +0 -538
- package/src/private/core/setUpDOM.js +0 -18
- package/src/private/webapis/performance/PerformanceEventTiming.js +0 -55
- /package/src/private/{core → styles}/composeStyles.js +0 -0
|
@@ -11,25 +11,6 @@ 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
|
-
|
|
33
14
|
type FlexAlignType =
|
|
34
15
|
| 'flex-start'
|
|
35
16
|
| 'flex-end'
|
|
@@ -246,6 +227,62 @@ export interface TransformsStyle {
|
|
|
246
227
|
translateY?: AnimatableNumericValue | undefined;
|
|
247
228
|
}
|
|
248
229
|
|
|
230
|
+
export type FilterFunction =
|
|
231
|
+
| {brightness: number | string}
|
|
232
|
+
| {blur: number | string}
|
|
233
|
+
| {contrast: number | string}
|
|
234
|
+
| {grayscale: number | string}
|
|
235
|
+
| {hueRotate: number | string}
|
|
236
|
+
| {invert: number | string}
|
|
237
|
+
| {opacity: number | string}
|
|
238
|
+
| {saturate: number | string}
|
|
239
|
+
| {sepia: number | string}
|
|
240
|
+
| {dropShadow: DropShadowPrimitive | string};
|
|
241
|
+
|
|
242
|
+
export type DropShadowPrimitive = {
|
|
243
|
+
offsetX: number | string;
|
|
244
|
+
offsetY: number | string;
|
|
245
|
+
standardDeviation?: number | string | undefined;
|
|
246
|
+
color?: ColorValue | number | undefined;
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
export type BoxShadowPrimitive = {
|
|
250
|
+
offsetX: number | string;
|
|
251
|
+
offsetY: number | string;
|
|
252
|
+
color?: string | undefined;
|
|
253
|
+
blurRadius?: ColorValue | number | undefined;
|
|
254
|
+
spreadDistance?: number | string | undefined;
|
|
255
|
+
inset?: boolean | undefined;
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
export type BlendMode =
|
|
259
|
+
| 'normal'
|
|
260
|
+
| 'multiply'
|
|
261
|
+
| 'screen'
|
|
262
|
+
| 'overlay'
|
|
263
|
+
| 'darken'
|
|
264
|
+
| 'lighten'
|
|
265
|
+
| 'color-dodge'
|
|
266
|
+
| 'color-burn'
|
|
267
|
+
| 'hard-light'
|
|
268
|
+
| 'soft-light'
|
|
269
|
+
| 'difference'
|
|
270
|
+
| 'exclusion'
|
|
271
|
+
| 'hue'
|
|
272
|
+
| 'saturation'
|
|
273
|
+
| 'color'
|
|
274
|
+
| 'luminosity';
|
|
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
|
+
|
|
249
286
|
/**
|
|
250
287
|
* @see https://reactnative.dev/docs/view#style
|
|
251
288
|
*/
|
|
@@ -295,6 +332,7 @@ export interface ViewStyle extends FlexStyle, ShadowStyleIOS, TransformsStyle {
|
|
|
295
332
|
* Controls whether the View can be the target of touch events.
|
|
296
333
|
*/
|
|
297
334
|
pointerEvents?: 'box-none' | 'none' | 'box-only' | 'auto' | undefined;
|
|
335
|
+
isolation?: 'auto' | 'isolate' | undefined;
|
|
298
336
|
cursor?: CursorValue | undefined;
|
|
299
337
|
}
|
|
300
338
|
|
|
@@ -34,25 +34,6 @@ export type EdgeInsetsValue = {
|
|
|
34
34
|
bottom: number,
|
|
35
35
|
};
|
|
36
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
|
-
|
|
56
37
|
export type DimensionValue = number | string | 'auto' | AnimatedNode | null;
|
|
57
38
|
export type AnimatableNumericValue = number | AnimatedNode;
|
|
58
39
|
|
|
@@ -709,15 +690,66 @@ export type ____ShadowStyle_Internal = $ReadOnly<{
|
|
|
709
690
|
...____ShadowStyle_InternalOverrides,
|
|
710
691
|
}>;
|
|
711
692
|
|
|
712
|
-
type
|
|
713
|
-
|
|
714
|
-
}
|
|
693
|
+
export type FilterFunction =
|
|
694
|
+
| {brightness: number | string}
|
|
695
|
+
| {blur: number | string}
|
|
696
|
+
| {contrast: number | string}
|
|
697
|
+
| {grayscale: number | string}
|
|
698
|
+
| {hueRotate: number | string}
|
|
699
|
+
| {invert: number | string}
|
|
700
|
+
| {opacity: number | string}
|
|
701
|
+
| {saturate: number | string}
|
|
702
|
+
| {sepia: number | string}
|
|
703
|
+
| {dropShadow: DropShadowPrimitive | string};
|
|
704
|
+
|
|
705
|
+
export type DropShadowPrimitive = {
|
|
706
|
+
offsetX: number | string,
|
|
707
|
+
offsetY: number | string,
|
|
708
|
+
standardDeviation?: number | string,
|
|
709
|
+
color?: ____ColorValue_Internal,
|
|
710
|
+
};
|
|
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
|
+
|
|
722
|
+
export type BoxShadowPrimitive = {
|
|
723
|
+
offsetX: number | string,
|
|
724
|
+
offsetY: number | string,
|
|
725
|
+
color?: ____ColorValue_Internal,
|
|
726
|
+
blurRadius?: number | string,
|
|
727
|
+
spreadDistance?: number | string,
|
|
728
|
+
inset?: boolean,
|
|
729
|
+
};
|
|
730
|
+
|
|
731
|
+
type ____BlendMode_Internal =
|
|
732
|
+
| 'normal'
|
|
733
|
+
| 'multiply'
|
|
734
|
+
| 'screen'
|
|
735
|
+
| 'overlay'
|
|
736
|
+
| 'darken'
|
|
737
|
+
| 'lighten'
|
|
738
|
+
| 'color-dodge'
|
|
739
|
+
| 'color-burn'
|
|
740
|
+
| 'hard-light'
|
|
741
|
+
| 'soft-light'
|
|
742
|
+
| 'difference'
|
|
743
|
+
| 'exclusion'
|
|
744
|
+
| 'hue'
|
|
745
|
+
| 'saturation'
|
|
746
|
+
| 'color'
|
|
747
|
+
| 'luminosity';
|
|
715
748
|
|
|
716
749
|
export type ____ViewStyle_InternalCore = $ReadOnly<{
|
|
717
750
|
...$Exact<____LayoutStyle_Internal>,
|
|
718
751
|
...$Exact<____ShadowStyle_Internal>,
|
|
719
752
|
...$Exact<____TransformStyle_Internal>,
|
|
720
|
-
...____FilterStyle_Internal,
|
|
721
753
|
backfaceVisibility?: 'visible' | 'hidden',
|
|
722
754
|
backgroundColor?: ____ColorValue_Internal,
|
|
723
755
|
borderColor?: ____ColorValue_Internal,
|
|
@@ -756,6 +788,11 @@ export type ____ViewStyle_InternalCore = $ReadOnly<{
|
|
|
756
788
|
elevation?: number,
|
|
757
789
|
pointerEvents?: 'auto' | 'none' | 'box-none' | 'box-only',
|
|
758
790
|
cursor?: CursorValue,
|
|
791
|
+
experimental_boxShadow?: $ReadOnlyArray<BoxShadowPrimitive> | string,
|
|
792
|
+
experimental_filter?: $ReadOnlyArray<FilterFunction> | string,
|
|
793
|
+
experimental_mixBlendMode?: ____BlendMode_Internal,
|
|
794
|
+
experimental_backgroundImage?: $ReadOnlyArray<GradientValue> | string,
|
|
795
|
+
isolation?: 'auto' | 'isolate',
|
|
759
796
|
}>;
|
|
760
797
|
|
|
761
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
|
+
}
|
|
@@ -0,0 +1,211 @@
|
|
|
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
|
+
* @flow strict-local
|
|
8
|
+
* @format
|
|
9
|
+
* @oncall react-native
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type {ProcessedColorValue} from './processColor';
|
|
13
|
+
import type {BoxShadowPrimitive} from './StyleSheetTypes';
|
|
14
|
+
|
|
15
|
+
import processColor from './processColor';
|
|
16
|
+
|
|
17
|
+
export type ParsedBoxShadow = {
|
|
18
|
+
offsetX: number,
|
|
19
|
+
offsetY: number,
|
|
20
|
+
color?: ProcessedColorValue,
|
|
21
|
+
blurRadius?: number,
|
|
22
|
+
spreadDistance?: number,
|
|
23
|
+
inset?: boolean,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export default function processBoxShadow(
|
|
27
|
+
rawBoxShadows: ?($ReadOnlyArray<BoxShadowPrimitive> | string),
|
|
28
|
+
): Array<ParsedBoxShadow> {
|
|
29
|
+
const result: Array<ParsedBoxShadow> = [];
|
|
30
|
+
if (rawBoxShadows == null) {
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const boxShadowList =
|
|
35
|
+
typeof rawBoxShadows === 'string'
|
|
36
|
+
? parseBoxShadowString(rawBoxShadows)
|
|
37
|
+
: rawBoxShadows;
|
|
38
|
+
|
|
39
|
+
for (const rawBoxShadow of boxShadowList) {
|
|
40
|
+
const parsedBoxShadow: ParsedBoxShadow = {
|
|
41
|
+
offsetX: 0,
|
|
42
|
+
offsetY: 0,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
let value;
|
|
46
|
+
for (const arg in rawBoxShadow) {
|
|
47
|
+
switch (arg) {
|
|
48
|
+
case 'offsetX':
|
|
49
|
+
value =
|
|
50
|
+
typeof rawBoxShadow.offsetX === 'string'
|
|
51
|
+
? parseLength(rawBoxShadow.offsetX)
|
|
52
|
+
: rawBoxShadow.offsetX;
|
|
53
|
+
if (value == null) {
|
|
54
|
+
return [];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
parsedBoxShadow.offsetX = value;
|
|
58
|
+
break;
|
|
59
|
+
case 'offsetY':
|
|
60
|
+
value =
|
|
61
|
+
typeof rawBoxShadow.offsetY === 'string'
|
|
62
|
+
? parseLength(rawBoxShadow.offsetY)
|
|
63
|
+
: rawBoxShadow.offsetY;
|
|
64
|
+
if (value == null) {
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
parsedBoxShadow.offsetY = value;
|
|
69
|
+
break;
|
|
70
|
+
case 'spreadDistance':
|
|
71
|
+
value =
|
|
72
|
+
typeof rawBoxShadow.spreadDistance === 'string'
|
|
73
|
+
? parseLength(rawBoxShadow.spreadDistance)
|
|
74
|
+
: rawBoxShadow.spreadDistance;
|
|
75
|
+
if (value == null) {
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
parsedBoxShadow.spreadDistance = value;
|
|
80
|
+
break;
|
|
81
|
+
case 'blurRadius':
|
|
82
|
+
value =
|
|
83
|
+
typeof rawBoxShadow.blurRadius === 'string'
|
|
84
|
+
? parseLength(rawBoxShadow.blurRadius)
|
|
85
|
+
: rawBoxShadow.blurRadius;
|
|
86
|
+
if (value == null || value < 0) {
|
|
87
|
+
return [];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
parsedBoxShadow.blurRadius = value;
|
|
91
|
+
break;
|
|
92
|
+
case 'color':
|
|
93
|
+
const color = processColor(rawBoxShadow.color);
|
|
94
|
+
if (color == null) {
|
|
95
|
+
return [];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
parsedBoxShadow.color = color;
|
|
99
|
+
break;
|
|
100
|
+
case 'inset':
|
|
101
|
+
parsedBoxShadow.inset = rawBoxShadow.inset;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
result.push(parsedBoxShadow);
|
|
105
|
+
}
|
|
106
|
+
return result;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function parseBoxShadowString(
|
|
110
|
+
rawBoxShadows: string,
|
|
111
|
+
): Array<BoxShadowPrimitive> {
|
|
112
|
+
let result: Array<BoxShadowPrimitive> = [];
|
|
113
|
+
|
|
114
|
+
for (const rawBoxShadow of rawBoxShadows
|
|
115
|
+
.split(/,(?![^()]*\))/) // split by comma that is not in parenthesis
|
|
116
|
+
.map(bS => bS.trim())
|
|
117
|
+
.filter(bS => bS !== '')) {
|
|
118
|
+
const boxShadow: BoxShadowPrimitive = {
|
|
119
|
+
offsetX: 0,
|
|
120
|
+
offsetY: 0,
|
|
121
|
+
};
|
|
122
|
+
let offsetX: number | string;
|
|
123
|
+
let offsetY: number | string;
|
|
124
|
+
let keywordDetectedAfterLength = false;
|
|
125
|
+
|
|
126
|
+
let lengthCount = 0;
|
|
127
|
+
|
|
128
|
+
// split rawBoxShadow string by all whitespaces that are not in parenthesis
|
|
129
|
+
const args = rawBoxShadow.split(/\s+(?![^(]*\))/);
|
|
130
|
+
for (const arg of args) {
|
|
131
|
+
const processedColor = processColor(arg);
|
|
132
|
+
if (processedColor != null) {
|
|
133
|
+
if (boxShadow.color != null) {
|
|
134
|
+
return [];
|
|
135
|
+
}
|
|
136
|
+
if (offsetX != null) {
|
|
137
|
+
keywordDetectedAfterLength = true;
|
|
138
|
+
}
|
|
139
|
+
boxShadow.color = arg;
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (arg === 'inset') {
|
|
144
|
+
if (boxShadow.inset != null) {
|
|
145
|
+
return [];
|
|
146
|
+
}
|
|
147
|
+
if (offsetX != null) {
|
|
148
|
+
keywordDetectedAfterLength = true;
|
|
149
|
+
}
|
|
150
|
+
boxShadow.inset = true;
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
switch (lengthCount) {
|
|
155
|
+
case 0:
|
|
156
|
+
offsetX = arg;
|
|
157
|
+
lengthCount++;
|
|
158
|
+
break;
|
|
159
|
+
case 1:
|
|
160
|
+
if (keywordDetectedAfterLength) {
|
|
161
|
+
return [];
|
|
162
|
+
}
|
|
163
|
+
offsetY = arg;
|
|
164
|
+
lengthCount++;
|
|
165
|
+
break;
|
|
166
|
+
case 2:
|
|
167
|
+
if (keywordDetectedAfterLength) {
|
|
168
|
+
return [];
|
|
169
|
+
}
|
|
170
|
+
boxShadow.blurRadius = arg;
|
|
171
|
+
lengthCount++;
|
|
172
|
+
break;
|
|
173
|
+
case 3:
|
|
174
|
+
if (keywordDetectedAfterLength) {
|
|
175
|
+
return [];
|
|
176
|
+
}
|
|
177
|
+
boxShadow.spreadDistance = arg;
|
|
178
|
+
lengthCount++;
|
|
179
|
+
break;
|
|
180
|
+
default:
|
|
181
|
+
return [];
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (offsetX == null || offsetY == null) {
|
|
186
|
+
return [];
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
boxShadow.offsetX = offsetX;
|
|
190
|
+
boxShadow.offsetY = offsetY;
|
|
191
|
+
|
|
192
|
+
result.push(boxShadow);
|
|
193
|
+
}
|
|
194
|
+
return result;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function parseLength(length: string): ?number {
|
|
198
|
+
// matches on args with units like "1.5 5% -80deg"
|
|
199
|
+
const argsWithUnitsRegex = /([+-]?\d*(\.\d+)?)([\w\W]+)?/g;
|
|
200
|
+
const match = argsWithUnitsRegex.exec(length);
|
|
201
|
+
|
|
202
|
+
if (!match || Number.isNaN(match[1])) {
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (match[3] != null && match[3] !== 'px') {
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return Number(match[1]);
|
|
211
|
+
}
|