expo-linear-gradient 12.0.0 → 12.0.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.
- package/CHANGELOG.md +4 -0
- package/android/build.gradle +2 -2
- package/build/NativeLinearGradient.types.d.ts +1 -0
- package/build/NativeLinearGradient.types.d.ts.map +1 -1
- package/build/NativeLinearGradient.types.js.map +1 -1
- package/build/NativeLinearGradient.web.d.ts +5 -1
- package/build/NativeLinearGradient.web.d.ts.map +1 -1
- package/build/NativeLinearGradient.web.js +52 -43
- package/build/NativeLinearGradient.web.js.map +1 -1
- package/package.json +6 -3
- package/src/NativeLinearGradient.types.ts +9 -0
- package/src/NativeLinearGradient.web.tsx +70 -47
- package/.babelrc +0 -3
package/CHANGELOG.md
CHANGED
package/android/build.gradle
CHANGED
|
@@ -3,7 +3,7 @@ apply plugin: 'kotlin-android'
|
|
|
3
3
|
apply plugin: 'maven-publish'
|
|
4
4
|
|
|
5
5
|
group = 'host.exp.exponent'
|
|
6
|
-
version = '12.0.
|
|
6
|
+
version = '12.0.1'
|
|
7
7
|
|
|
8
8
|
buildscript {
|
|
9
9
|
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
|
@@ -74,7 +74,7 @@ android {
|
|
|
74
74
|
minSdkVersion safeExtGet("minSdkVersion", 21)
|
|
75
75
|
targetSdkVersion safeExtGet("targetSdkVersion", 31)
|
|
76
76
|
versionCode 17
|
|
77
|
-
versionName "12.0.
|
|
77
|
+
versionName "12.0.1"
|
|
78
78
|
}
|
|
79
79
|
lintOptions {
|
|
80
80
|
abortOnError false
|
|
@@ -6,5 +6,6 @@ export declare type NativeLinearGradientProps = ViewProps & PropsWithChildren<{
|
|
|
6
6
|
startPoint?: NativeLinearGradientPoint | null;
|
|
7
7
|
endPoint?: NativeLinearGradientPoint | null;
|
|
8
8
|
}>;
|
|
9
|
+
export declare type getLinearGradientBackgroundImage = (colors: number[], width?: number, height?: number, locations?: number[] | null, startPoint?: NativeLinearGradientPoint | null, endPoint?: NativeLinearGradientPoint | null) => string;
|
|
9
10
|
export declare type NativeLinearGradientPoint = [number, number];
|
|
10
11
|
//# sourceMappingURL=NativeLinearGradient.types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NativeLinearGradient.types.d.ts","sourceRoot":"","sources":["../src/NativeLinearGradient.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,oBAAY,yBAAyB,GAAG,SAAS,GAC/C,iBAAiB,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC5B,UAAU,CAAC,EAAE,yBAAyB,GAAG,IAAI,CAAC;IAC9C,QAAQ,CAAC,EAAE,yBAAyB,GAAG,IAAI,CAAC;CAC7C,CAAC,CAAC;AAEL,oBAAY,yBAAyB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"NativeLinearGradient.types.d.ts","sourceRoot":"","sources":["../src/NativeLinearGradient.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,oBAAY,yBAAyB,GAAG,SAAS,GAC/C,iBAAiB,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC5B,UAAU,CAAC,EAAE,yBAAyB,GAAG,IAAI,CAAC;IAC9C,QAAQ,CAAC,EAAE,yBAAyB,GAAG,IAAI,CAAC;CAC7C,CAAC,CAAC;AAEL,oBAAY,gCAAgC,GAAG,CAC7C,MAAM,EAAE,MAAM,EAAE,EAChB,KAAK,CAAC,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAC3B,UAAU,CAAC,EAAE,yBAAyB,GAAG,IAAI,EAC7C,QAAQ,CAAC,EAAE,yBAAyB,GAAG,IAAI,KACxC,MAAM,CAAC;AAEZ,oBAAY,yBAAyB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NativeLinearGradient.types.js","sourceRoot":"","sources":["../src/NativeLinearGradient.types.ts"],"names":[],"mappings":"","sourcesContent":["import { PropsWithChildren } from 'react';\nimport { ViewProps } from 'react-native';\n\nexport type NativeLinearGradientProps = ViewProps &\n PropsWithChildren<{\n colors: number[];\n locations?: number[] | null;\n startPoint?: NativeLinearGradientPoint | null;\n endPoint?: NativeLinearGradientPoint | null;\n }>;\n\nexport type NativeLinearGradientPoint = [number, number];\n"]}
|
|
1
|
+
{"version":3,"file":"NativeLinearGradient.types.js","sourceRoot":"","sources":["../src/NativeLinearGradient.types.ts"],"names":[],"mappings":"","sourcesContent":["import { PropsWithChildren } from 'react';\nimport { ViewProps } from 'react-native';\n\nexport type NativeLinearGradientProps = ViewProps &\n PropsWithChildren<{\n colors: number[];\n locations?: number[] | null;\n startPoint?: NativeLinearGradientPoint | null;\n endPoint?: NativeLinearGradientPoint | null;\n }>;\n\nexport type getLinearGradientBackgroundImage = (\n colors: number[],\n width?: number,\n height?: number,\n locations?: number[] | null,\n startPoint?: NativeLinearGradientPoint | null,\n endPoint?: NativeLinearGradientPoint | null\n) => string;\n\nexport type NativeLinearGradientPoint = [number, number];\n"]}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { NativeLinearGradientProps } from './NativeLinearGradient.types';
|
|
2
|
+
import { NativeLinearGradientPoint, NativeLinearGradientProps } from './NativeLinearGradient.types';
|
|
3
3
|
export default function NativeLinearGradient({ colors, locations, startPoint, endPoint, ...props }: NativeLinearGradientProps): React.ReactElement;
|
|
4
|
+
/**
|
|
5
|
+
* Extracted to a separate function in order to be able to test logic independently.
|
|
6
|
+
*/
|
|
7
|
+
export declare function getLinearGradientBackgroundImage(colors: number[] | string[], locations?: number[] | null, startPoint?: NativeLinearGradientPoint | null, endPoint?: NativeLinearGradientPoint | null, width?: number, height?: number): string;
|
|
4
8
|
//# sourceMappingURL=NativeLinearGradient.web.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NativeLinearGradient.web.d.ts","sourceRoot":"","sources":["../src/NativeLinearGradient.web.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,
|
|
1
|
+
{"version":3,"file":"NativeLinearGradient.web.d.ts","sourceRoot":"","sources":["../src/NativeLinearGradient.web.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,EAAE,yBAAyB,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AAGpG,MAAM,CAAC,OAAO,UAAU,oBAAoB,CAAC,EAC3C,MAAM,EACN,SAAS,EACT,UAAU,EACV,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,yBAAyB,GAAG,KAAK,CAAC,YAAY,CAsChD;AAED;;GAEG;AACH,wBAAgB,gCAAgC,CAC9C,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,EAC3B,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAC3B,UAAU,CAAC,EAAE,yBAAyB,GAAG,IAAI,EAC7C,QAAQ,CAAC,EAAE,yBAAyB,GAAG,IAAI,EAC3C,KAAK,GAAE,MAAU,EACjB,MAAM,GAAE,MAAU,UAKnB"}
|
|
@@ -4,54 +4,15 @@ import { normalizeColor } from './normalizeColor';
|
|
|
4
4
|
export default function NativeLinearGradient({ colors, locations, startPoint, endPoint, ...props }) {
|
|
5
5
|
const [layout, setLayout] = React.useState(null);
|
|
6
6
|
const { width = 1, height = 1 } = layout ?? {};
|
|
7
|
-
const pseudoAngle = React.useMemo(() => {
|
|
8
|
-
const getControlPoints = () => {
|
|
9
|
-
let correctedStartPoint = [0, 0];
|
|
10
|
-
if (Array.isArray(startPoint)) {
|
|
11
|
-
correctedStartPoint = [
|
|
12
|
-
startPoint[0] != null ? startPoint[0] : 0.0,
|
|
13
|
-
startPoint[1] != null ? startPoint[1] : 0.0,
|
|
14
|
-
];
|
|
15
|
-
}
|
|
16
|
-
let correctedEndPoint = [0.0, 1.0];
|
|
17
|
-
if (Array.isArray(endPoint)) {
|
|
18
|
-
correctedEndPoint = [
|
|
19
|
-
endPoint[0] != null ? endPoint[0] : 0.0,
|
|
20
|
-
endPoint[1] != null ? endPoint[1] : 1.0,
|
|
21
|
-
];
|
|
22
|
-
}
|
|
23
|
-
return [correctedStartPoint, correctedEndPoint];
|
|
24
|
-
};
|
|
25
|
-
const [start, end] = getControlPoints();
|
|
26
|
-
start[0] *= width;
|
|
27
|
-
end[0] *= width;
|
|
28
|
-
start[1] *= height;
|
|
29
|
-
end[1] *= height;
|
|
30
|
-
const py = end[1] - start[1];
|
|
31
|
-
const px = end[0] - start[0];
|
|
32
|
-
return 90 + (Math.atan2(py, px) * 180) / Math.PI;
|
|
33
|
-
}, [width, height, startPoint, endPoint]);
|
|
34
|
-
const gradientColors = React.useMemo(() => {
|
|
35
|
-
return colors.map((color, index) => {
|
|
36
|
-
const hexColor = normalizeColor(color);
|
|
37
|
-
let output = hexColor;
|
|
38
|
-
if (locations && locations[index]) {
|
|
39
|
-
const location = Math.max(0, Math.min(1, locations[index]));
|
|
40
|
-
// Convert 0...1 to 0...100
|
|
41
|
-
const percentage = location * 100;
|
|
42
|
-
output += ` ${percentage}%`;
|
|
43
|
-
}
|
|
44
|
-
return output;
|
|
45
|
-
});
|
|
46
|
-
}, [colors, locations]);
|
|
47
|
-
const colorStyle = gradientColors.join(',');
|
|
48
|
-
const backgroundImage = `linear-gradient(${pseudoAngle}deg, ${colorStyle})`;
|
|
49
7
|
// TODO(Bacon): In the future we could consider adding `backgroundRepeat: "no-repeat"`. For more
|
|
50
8
|
// browser support.
|
|
9
|
+
const linearGradientBackgroundImage = React.useMemo(() => {
|
|
10
|
+
return getLinearGradientBackgroundImage(colors, locations, startPoint, endPoint, width, height);
|
|
11
|
+
}, [colors, locations, startPoint, endPoint, width, height]);
|
|
51
12
|
return (React.createElement(View, { ...props, style: [
|
|
52
13
|
props.style,
|
|
53
14
|
// @ts-ignore: [ts] Property 'backgroundImage' does not exist on type 'ViewStyle'.
|
|
54
|
-
{ backgroundImage },
|
|
15
|
+
{ backgroundImage: linearGradientBackgroundImage },
|
|
55
16
|
], onLayout: (event) => {
|
|
56
17
|
const { x, y, width, height } = event.nativeEvent.layout;
|
|
57
18
|
const oldLayout = layout ?? { x: 0, y: 0, width: 1, height: 1 };
|
|
@@ -67,4 +28,52 @@ export default function NativeLinearGradient({ colors, locations, startPoint, en
|
|
|
67
28
|
}
|
|
68
29
|
} }));
|
|
69
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Extracted to a separate function in order to be able to test logic independently.
|
|
33
|
+
*/
|
|
34
|
+
export function getLinearGradientBackgroundImage(colors, locations, startPoint, endPoint, width = 1, height = 1) {
|
|
35
|
+
const gradientColors = calculateGradientColors(colors, locations);
|
|
36
|
+
const angle = calculatePseudoAngle(width, height, startPoint, endPoint);
|
|
37
|
+
return `linear-gradient(${angle}deg, ${gradientColors.join(', ')})`;
|
|
38
|
+
}
|
|
39
|
+
function calculatePseudoAngle(width, height, startPoint, endPoint) {
|
|
40
|
+
const getControlPoints = () => {
|
|
41
|
+
let correctedStartPoint = [0, 0];
|
|
42
|
+
if (Array.isArray(startPoint)) {
|
|
43
|
+
correctedStartPoint = [
|
|
44
|
+
startPoint[0] != null ? startPoint[0] : 0.0,
|
|
45
|
+
startPoint[1] != null ? startPoint[1] : 0.0,
|
|
46
|
+
];
|
|
47
|
+
}
|
|
48
|
+
let correctedEndPoint = [0.0, 1.0];
|
|
49
|
+
if (Array.isArray(endPoint)) {
|
|
50
|
+
correctedEndPoint = [
|
|
51
|
+
endPoint[0] != null ? endPoint[0] : 0.0,
|
|
52
|
+
endPoint[1] != null ? endPoint[1] : 1.0,
|
|
53
|
+
];
|
|
54
|
+
}
|
|
55
|
+
return [correctedStartPoint, correctedEndPoint];
|
|
56
|
+
};
|
|
57
|
+
const [start, end] = getControlPoints();
|
|
58
|
+
start[0] *= width;
|
|
59
|
+
end[0] *= width;
|
|
60
|
+
start[1] *= height;
|
|
61
|
+
end[1] *= height;
|
|
62
|
+
const py = end[1] - start[1];
|
|
63
|
+
const px = end[0] - start[0];
|
|
64
|
+
return 90 + (Math.atan2(py, px) * 180) / Math.PI;
|
|
65
|
+
}
|
|
66
|
+
function calculateGradientColors(colors, locations) {
|
|
67
|
+
return colors.map((color, index) => {
|
|
68
|
+
const hexColor = normalizeColor(color);
|
|
69
|
+
let output = hexColor;
|
|
70
|
+
if (locations && locations[index]) {
|
|
71
|
+
const location = Math.max(0, Math.min(1, locations[index]));
|
|
72
|
+
// Convert 0...1 to 0...100
|
|
73
|
+
const percentage = location * 100;
|
|
74
|
+
output += ` ${percentage}%`;
|
|
75
|
+
}
|
|
76
|
+
return output;
|
|
77
|
+
});
|
|
78
|
+
}
|
|
70
79
|
//# sourceMappingURL=NativeLinearGradient.web.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NativeLinearGradient.web.js","sourceRoot":"","sources":["../src/NativeLinearGradient.web.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAmB,IAAI,EAAE,MAAM,cAAc,CAAC;AAGrD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,MAAM,CAAC,OAAO,UAAU,oBAAoB,CAAC,EAC3C,MAAM,EACN,SAAS,EACT,UAAU,EACV,QAAQ,EACR,GAAG,KAAK,EACkB;IAC1B,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAyB,IAAI,CAAC,CAAC;IAEzE,MAAM,EAAE,KAAK,GAAG,CAAC,EAAE,MAAM,GAAG,CAAC,EAAE,GAAG,MAAM,IAAI,EAAE,CAAC;IAE/C,MAAM,
|
|
1
|
+
{"version":3,"file":"NativeLinearGradient.web.js","sourceRoot":"","sources":["../src/NativeLinearGradient.web.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react';\nimport { LayoutRectangle, View } from 'react-native';\n\nimport { NativeLinearGradientPoint, NativeLinearGradientProps } from './NativeLinearGradient.types';\nimport { normalizeColor } from './normalizeColor';\n\nexport default function NativeLinearGradient({\n colors,\n locations,\n startPoint,\n endPoint,\n ...props\n}: NativeLinearGradientProps): React.ReactElement {\n const [layout, setLayout] = React.useState<LayoutRectangle | null>(null);\n\n const { width = 1, height = 1 } = layout ?? {};\n\n // TODO(Bacon): In the future we could consider adding `backgroundRepeat: \"no-repeat\"`. For more\n // browser support.\n const linearGradientBackgroundImage = React.useMemo(() => {\n return getLinearGradientBackgroundImage(colors, locations, startPoint, endPoint, width, height);\n }, [colors, locations, startPoint, endPoint, width, height]);\n\n return (\n <View\n {...props}\n style={[\n props.style,\n // @ts-ignore: [ts] Property 'backgroundImage' does not exist on type 'ViewStyle'.\n { backgroundImage: linearGradientBackgroundImage },\n ]}\n onLayout={(event) => {\n const { x, y, width, height } = event.nativeEvent.layout;\n const oldLayout = layout ?? { x: 0, y: 0, width: 1, height: 1 };\n // don't set new layout state unless the layout has actually changed\n if (\n x !== oldLayout.x ||\n y !== oldLayout.y ||\n width !== oldLayout.width ||\n height !== oldLayout.height\n ) {\n setLayout({ x, y, width, height });\n }\n\n if (props.onLayout) {\n props.onLayout(event);\n }\n }}\n />\n );\n}\n\n/**\n * Extracted to a separate function in order to be able to test logic independently.\n */\nexport function getLinearGradientBackgroundImage(\n colors: number[] | string[],\n locations?: number[] | null,\n startPoint?: NativeLinearGradientPoint | null,\n endPoint?: NativeLinearGradientPoint | null,\n width: number = 1,\n height: number = 1\n) {\n const gradientColors = calculateGradientColors(colors, locations);\n const angle = calculatePseudoAngle(width, height, startPoint, endPoint);\n return `linear-gradient(${angle}deg, ${gradientColors.join(', ')})`;\n}\n\nfunction calculatePseudoAngle(\n width: number,\n height: number,\n startPoint?: NativeLinearGradientPoint | null,\n endPoint?: NativeLinearGradientPoint | null\n) {\n const getControlPoints = (): NativeLinearGradientPoint[] => {\n let correctedStartPoint: NativeLinearGradientPoint = [0, 0];\n if (Array.isArray(startPoint)) {\n correctedStartPoint = [\n startPoint[0] != null ? startPoint[0] : 0.0,\n startPoint[1] != null ? startPoint[1] : 0.0,\n ];\n }\n let correctedEndPoint: NativeLinearGradientPoint = [0.0, 1.0];\n if (Array.isArray(endPoint)) {\n correctedEndPoint = [\n endPoint[0] != null ? endPoint[0] : 0.0,\n endPoint[1] != null ? endPoint[1] : 1.0,\n ];\n }\n return [correctedStartPoint, correctedEndPoint];\n };\n\n const [start, end] = getControlPoints();\n start[0] *= width;\n end[0] *= width;\n start[1] *= height;\n end[1] *= height;\n const py = end[1] - start[1];\n const px = end[0] - start[0];\n\n return 90 + (Math.atan2(py, px) * 180) / Math.PI;\n}\n\nfunction calculateGradientColors(colors: number[] | string[], locations?: number[] | null) {\n return colors.map((color: number | string, index: number): string | void => {\n const hexColor = normalizeColor(color);\n let output = hexColor;\n if (locations && locations[index]) {\n const location = Math.max(0, Math.min(1, locations[index]));\n // Convert 0...1 to 0...100\n const percentage = location * 100;\n output += ` ${percentage}%`;\n }\n return output;\n });\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-linear-gradient",
|
|
3
|
-
"version": "12.0.
|
|
3
|
+
"version": "12.0.1",
|
|
4
4
|
"description": "Provides a React component that renders a gradient view.",
|
|
5
5
|
"main": "build/LinearGradient.js",
|
|
6
6
|
"types": "build/LinearGradient.d.ts",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"gradient"
|
|
21
21
|
],
|
|
22
22
|
"jest": {
|
|
23
|
-
"preset": "expo-module-scripts
|
|
23
|
+
"preset": "expo-module-scripts"
|
|
24
24
|
},
|
|
25
25
|
"repository": {
|
|
26
26
|
"type": "git",
|
|
@@ -34,10 +34,13 @@
|
|
|
34
34
|
"license": "MIT",
|
|
35
35
|
"homepage": "https://docs.expo.dev/versions/latest/sdk/linear-gradient/",
|
|
36
36
|
"devDependencies": {
|
|
37
|
+
"@testing-library/jest-dom": "^5.16.5",
|
|
38
|
+
"@testing-library/react": "^13.4.0",
|
|
39
|
+
"@testing-library/react-native": "^11.3.0",
|
|
37
40
|
"expo-module-scripts": "^3.0.0"
|
|
38
41
|
},
|
|
39
42
|
"peerDependencies": {
|
|
40
43
|
"expo": "*"
|
|
41
44
|
},
|
|
42
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "1a87dcc55895a9e16e3d4fd0fa78f2244c1d961f"
|
|
43
46
|
}
|
|
@@ -9,4 +9,13 @@ export type NativeLinearGradientProps = ViewProps &
|
|
|
9
9
|
endPoint?: NativeLinearGradientPoint | null;
|
|
10
10
|
}>;
|
|
11
11
|
|
|
12
|
+
export type getLinearGradientBackgroundImage = (
|
|
13
|
+
colors: number[],
|
|
14
|
+
width?: number,
|
|
15
|
+
height?: number,
|
|
16
|
+
locations?: number[] | null,
|
|
17
|
+
startPoint?: NativeLinearGradientPoint | null,
|
|
18
|
+
endPoint?: NativeLinearGradientPoint | null
|
|
19
|
+
) => string;
|
|
20
|
+
|
|
12
21
|
export type NativeLinearGradientPoint = [number, number];
|
|
@@ -15,61 +15,19 @@ export default function NativeLinearGradient({
|
|
|
15
15
|
|
|
16
16
|
const { width = 1, height = 1 } = layout ?? {};
|
|
17
17
|
|
|
18
|
-
const pseudoAngle = React.useMemo(() => {
|
|
19
|
-
const getControlPoints = (): NativeLinearGradientPoint[] => {
|
|
20
|
-
let correctedStartPoint: NativeLinearGradientPoint = [0, 0];
|
|
21
|
-
if (Array.isArray(startPoint)) {
|
|
22
|
-
correctedStartPoint = [
|
|
23
|
-
startPoint[0] != null ? startPoint[0] : 0.0,
|
|
24
|
-
startPoint[1] != null ? startPoint[1] : 0.0,
|
|
25
|
-
];
|
|
26
|
-
}
|
|
27
|
-
let correctedEndPoint: NativeLinearGradientPoint = [0.0, 1.0];
|
|
28
|
-
if (Array.isArray(endPoint)) {
|
|
29
|
-
correctedEndPoint = [
|
|
30
|
-
endPoint[0] != null ? endPoint[0] : 0.0,
|
|
31
|
-
endPoint[1] != null ? endPoint[1] : 1.0,
|
|
32
|
-
];
|
|
33
|
-
}
|
|
34
|
-
return [correctedStartPoint, correctedEndPoint];
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
const [start, end] = getControlPoints();
|
|
38
|
-
start[0] *= width;
|
|
39
|
-
end[0] *= width;
|
|
40
|
-
start[1] *= height;
|
|
41
|
-
end[1] *= height;
|
|
42
|
-
const py = end[1] - start[1];
|
|
43
|
-
const px = end[0] - start[0];
|
|
44
|
-
|
|
45
|
-
return 90 + (Math.atan2(py, px) * 180) / Math.PI;
|
|
46
|
-
}, [width, height, startPoint, endPoint]);
|
|
47
|
-
|
|
48
|
-
const gradientColors = React.useMemo(() => {
|
|
49
|
-
return colors.map((color: number, index: number): string | void => {
|
|
50
|
-
const hexColor = normalizeColor(color);
|
|
51
|
-
let output = hexColor;
|
|
52
|
-
if (locations && locations[index]) {
|
|
53
|
-
const location = Math.max(0, Math.min(1, locations[index]));
|
|
54
|
-
// Convert 0...1 to 0...100
|
|
55
|
-
const percentage = location * 100;
|
|
56
|
-
output += ` ${percentage}%`;
|
|
57
|
-
}
|
|
58
|
-
return output;
|
|
59
|
-
});
|
|
60
|
-
}, [colors, locations]);
|
|
61
|
-
|
|
62
|
-
const colorStyle = gradientColors.join(',');
|
|
63
|
-
const backgroundImage = `linear-gradient(${pseudoAngle}deg, ${colorStyle})`;
|
|
64
18
|
// TODO(Bacon): In the future we could consider adding `backgroundRepeat: "no-repeat"`. For more
|
|
65
19
|
// browser support.
|
|
20
|
+
const linearGradientBackgroundImage = React.useMemo(() => {
|
|
21
|
+
return getLinearGradientBackgroundImage(colors, locations, startPoint, endPoint, width, height);
|
|
22
|
+
}, [colors, locations, startPoint, endPoint, width, height]);
|
|
23
|
+
|
|
66
24
|
return (
|
|
67
25
|
<View
|
|
68
26
|
{...props}
|
|
69
27
|
style={[
|
|
70
28
|
props.style,
|
|
71
29
|
// @ts-ignore: [ts] Property 'backgroundImage' does not exist on type 'ViewStyle'.
|
|
72
|
-
{ backgroundImage },
|
|
30
|
+
{ backgroundImage: linearGradientBackgroundImage },
|
|
73
31
|
]}
|
|
74
32
|
onLayout={(event) => {
|
|
75
33
|
const { x, y, width, height } = event.nativeEvent.layout;
|
|
@@ -91,3 +49,68 @@ export default function NativeLinearGradient({
|
|
|
91
49
|
/>
|
|
92
50
|
);
|
|
93
51
|
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Extracted to a separate function in order to be able to test logic independently.
|
|
55
|
+
*/
|
|
56
|
+
export function getLinearGradientBackgroundImage(
|
|
57
|
+
colors: number[] | string[],
|
|
58
|
+
locations?: number[] | null,
|
|
59
|
+
startPoint?: NativeLinearGradientPoint | null,
|
|
60
|
+
endPoint?: NativeLinearGradientPoint | null,
|
|
61
|
+
width: number = 1,
|
|
62
|
+
height: number = 1
|
|
63
|
+
) {
|
|
64
|
+
const gradientColors = calculateGradientColors(colors, locations);
|
|
65
|
+
const angle = calculatePseudoAngle(width, height, startPoint, endPoint);
|
|
66
|
+
return `linear-gradient(${angle}deg, ${gradientColors.join(', ')})`;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function calculatePseudoAngle(
|
|
70
|
+
width: number,
|
|
71
|
+
height: number,
|
|
72
|
+
startPoint?: NativeLinearGradientPoint | null,
|
|
73
|
+
endPoint?: NativeLinearGradientPoint | null
|
|
74
|
+
) {
|
|
75
|
+
const getControlPoints = (): NativeLinearGradientPoint[] => {
|
|
76
|
+
let correctedStartPoint: NativeLinearGradientPoint = [0, 0];
|
|
77
|
+
if (Array.isArray(startPoint)) {
|
|
78
|
+
correctedStartPoint = [
|
|
79
|
+
startPoint[0] != null ? startPoint[0] : 0.0,
|
|
80
|
+
startPoint[1] != null ? startPoint[1] : 0.0,
|
|
81
|
+
];
|
|
82
|
+
}
|
|
83
|
+
let correctedEndPoint: NativeLinearGradientPoint = [0.0, 1.0];
|
|
84
|
+
if (Array.isArray(endPoint)) {
|
|
85
|
+
correctedEndPoint = [
|
|
86
|
+
endPoint[0] != null ? endPoint[0] : 0.0,
|
|
87
|
+
endPoint[1] != null ? endPoint[1] : 1.0,
|
|
88
|
+
];
|
|
89
|
+
}
|
|
90
|
+
return [correctedStartPoint, correctedEndPoint];
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const [start, end] = getControlPoints();
|
|
94
|
+
start[0] *= width;
|
|
95
|
+
end[0] *= width;
|
|
96
|
+
start[1] *= height;
|
|
97
|
+
end[1] *= height;
|
|
98
|
+
const py = end[1] - start[1];
|
|
99
|
+
const px = end[0] - start[0];
|
|
100
|
+
|
|
101
|
+
return 90 + (Math.atan2(py, px) * 180) / Math.PI;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function calculateGradientColors(colors: number[] | string[], locations?: number[] | null) {
|
|
105
|
+
return colors.map((color: number | string, index: number): string | void => {
|
|
106
|
+
const hexColor = normalizeColor(color);
|
|
107
|
+
let output = hexColor;
|
|
108
|
+
if (locations && locations[index]) {
|
|
109
|
+
const location = Math.max(0, Math.min(1, locations[index]));
|
|
110
|
+
// Convert 0...1 to 0...100
|
|
111
|
+
const percentage = location * 100;
|
|
112
|
+
output += ` ${percentage}%`;
|
|
113
|
+
}
|
|
114
|
+
return output;
|
|
115
|
+
});
|
|
116
|
+
}
|
package/.babelrc
DELETED