@versatiles/style 5.7.0 → 5.8.0
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/README.MD +15 -14
- package/dist/index.d.ts +10 -1
- package/dist/index.js +137 -136
- package/dist/index.js.map +1 -1
- package/package.json +33 -32
- package/src/color/hsl.test.ts +21 -20
- package/src/color/hsv.test.ts +19 -18
- package/src/color/hsv.ts +5 -0
- package/src/color/index.test.ts +12 -10
- package/src/color/random.test.ts +7 -6
- package/src/color/rgb.test.ts +25 -24
- package/src/color/utils.test.ts +16 -15
- package/src/guess_style/guess_style.test.ts +1 -1
- package/src/index.test.ts +42 -16
- package/src/index.ts +4 -4
- package/src/lib/utils.test.ts +1 -0
- package/src/lib/utils.ts +3 -6
- package/src/shortbread/layers.test.ts +1 -0
- package/src/shortbread/properties.test.ts +1 -0
- package/src/shortbread/template.test.ts +1 -0
- package/src/style_builder/decorator.test.ts +1 -0
- package/src/style_builder/recolor.test.ts +1 -0
- package/src/style_builder/style_builder.test.ts +1 -1
- package/src/style_builder/style_builder.ts +1 -2
- package/src/types/tilejson.test.ts +1 -2
- package/src/types/vector_layer.test.ts +1 -0
package/package.json
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@versatiles/style",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.8.0",
|
|
4
4
|
"description": "Generate StyleJSON for MapLibre",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
|
+
"devEngines": {
|
|
8
|
+
"runtime": {
|
|
9
|
+
"name": "node",
|
|
10
|
+
"version": ">=20.0.0 <24.0.0"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
7
13
|
"scripts": {
|
|
8
14
|
"check": "npm run lint && npm run build && npm run test ",
|
|
9
15
|
"build": "rm -rf release; npm run build-browser && npm run build-node && npm run build-styles && npm run build-sprites && npm run doc",
|
|
10
|
-
"build-browser": "rollup
|
|
11
|
-
"build-node": "rm -rf dist && rollup
|
|
16
|
+
"build-browser": "rollup -c --environment BUILD:browser && $(cd release/versatiles-style; tar -cf - versatiles-style.* | gzip -9 > ../versatiles-style.tar.gz)",
|
|
17
|
+
"build-node": "rm -rf dist && rollup -c --environment BUILD:node && chmod +x dist/index.js && rm -r dist/declaration",
|
|
12
18
|
"build-styles": "tsx scripts/build-styles.ts",
|
|
13
19
|
"build-sprites": "tsx scripts/build-sprites.ts",
|
|
14
20
|
"dev": "tsx scripts/dev.ts",
|
|
@@ -20,8 +26,8 @@
|
|
|
20
26
|
"prepack": "npm run build",
|
|
21
27
|
"release": "vrt release-npm",
|
|
22
28
|
"test": "npm run test-typescript",
|
|
23
|
-
"test-coverage": "
|
|
24
|
-
"test-typescript": "
|
|
29
|
+
"test-coverage": "vitest run --coverage",
|
|
30
|
+
"test-typescript": "vitest run",
|
|
25
31
|
"upgrade": "vrt deps-upgrade"
|
|
26
32
|
},
|
|
27
33
|
"repository": {
|
|
@@ -32,7 +38,6 @@
|
|
|
32
38
|
"license": "MIT",
|
|
33
39
|
"type": "module",
|
|
34
40
|
"dependencies": {
|
|
35
|
-
"@versatiles/style": "^5.6.0",
|
|
36
41
|
"brace-expansion": "^4.0.1"
|
|
37
42
|
},
|
|
38
43
|
"files": [
|
|
@@ -40,37 +45,33 @@
|
|
|
40
45
|
"src/*"
|
|
41
46
|
],
|
|
42
47
|
"devDependencies": {
|
|
43
|
-
"@maplibre/maplibre-gl-native": "^6.
|
|
44
|
-
"@maplibre/maplibre-gl-style-spec": "^
|
|
45
|
-
"@rollup/plugin-commonjs": "^
|
|
46
|
-
"@rollup/plugin-node-resolve": "^16.0.
|
|
48
|
+
"@maplibre/maplibre-gl-native": "^6.2.0",
|
|
49
|
+
"@maplibre/maplibre-gl-style-spec": "^24.3.1",
|
|
50
|
+
"@rollup/plugin-commonjs": "^29.0.0",
|
|
51
|
+
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
47
52
|
"@rollup/plugin-terser": "^0.4.4",
|
|
48
|
-
"@rollup/plugin-typescript": "^12.
|
|
53
|
+
"@rollup/plugin-typescript": "^12.3.0",
|
|
49
54
|
"@types/bin-pack": "^1.0.3",
|
|
50
55
|
"@types/brace-expansion": "^1.1.2",
|
|
51
|
-
"@types/inquirer": "^9.0.
|
|
52
|
-
"@types/
|
|
53
|
-
"@types/node": "^24.0.4",
|
|
56
|
+
"@types/inquirer": "^9.0.9",
|
|
57
|
+
"@types/node": "^24.10.1",
|
|
54
58
|
"@types/tar-stream": "^3.1.4",
|
|
55
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
56
|
-
"@typescript-eslint/parser": "^8.
|
|
57
|
-
"@versatiles/release-tool": "^2.4.
|
|
59
|
+
"@typescript-eslint/eslint-plugin": "^8.47.0",
|
|
60
|
+
"@typescript-eslint/parser": "^8.47.0",
|
|
61
|
+
"@versatiles/release-tool": "^2.4.5",
|
|
62
|
+
"@vitest/coverage-v8": "^4.0.10",
|
|
58
63
|
"bin-pack": "^1.0.2",
|
|
59
|
-
"esbuild": "^0.
|
|
60
|
-
"eslint": "^9.
|
|
61
|
-
"inquirer": "^
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"rollup-plugin-dts": "^6.2.1",
|
|
67
|
-
"rollup-plugin-sourcemaps2": "^0.5.2",
|
|
68
|
-
"sharp": "^0.34.2",
|
|
64
|
+
"esbuild": "^0.27.0",
|
|
65
|
+
"eslint": "^9.39.1",
|
|
66
|
+
"inquirer": "^13.0.1",
|
|
67
|
+
"rollup": "^4.53.3",
|
|
68
|
+
"rollup-plugin-dts": "^6.2.3",
|
|
69
|
+
"rollup-plugin-sourcemaps2": "^0.5.4",
|
|
70
|
+
"sharp": "^0.34.5",
|
|
69
71
|
"tar-stream": "^3.1.7",
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"typescript-eslint": "^8.35.0"
|
|
72
|
+
"tsx": "^4.20.6",
|
|
73
|
+
"typescript": "^5.9.3",
|
|
74
|
+
"typescript-eslint": "^8.47.0",
|
|
75
|
+
"vitest": "^4.0.10"
|
|
75
76
|
}
|
|
76
77
|
}
|
package/src/color/hsl.test.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { describe, expect, it, beforeEach } from 'vitest';
|
|
1
2
|
import { HSL } from './hsl.js';
|
|
2
3
|
import { HSV } from './hsv.js';
|
|
3
4
|
import { RGB } from './rgb.js';
|
|
@@ -6,23 +7,23 @@ describe('HSL Class', () => {
|
|
|
6
7
|
|
|
7
8
|
describe('constructor', () => {
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
it('should initialize small HSL values correctly', () => {
|
|
10
11
|
const color = new HSL(10, 20, 30, 0.4);
|
|
11
12
|
expect(color.asArray()).toStrictEqual([10, 20, 30, 0.4]);
|
|
12
13
|
});
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
it('should initialize big HSL values correctly', () => {
|
|
15
16
|
const color = new HSL(400, 120, 120, 2);
|
|
16
17
|
expect(color.asArray()).toStrictEqual([40, 100, 100, 1]);
|
|
17
18
|
});
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
it('should initialize small HSL values correctly', () => {
|
|
20
21
|
const color = new HSL(-60, -10, -10, -1);
|
|
21
22
|
expect(color.asArray()).toStrictEqual([300, 0, 0, 0]);
|
|
22
23
|
});
|
|
23
24
|
})
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
it('clone should return a new HSL instance with identical values', () => {
|
|
26
27
|
const color = new HSL(120, 50, 50, 0.5);
|
|
27
28
|
const clone = color.clone();
|
|
28
29
|
expect(clone).toBeInstanceOf(HSL);
|
|
@@ -32,7 +33,7 @@ describe('HSL Class', () => {
|
|
|
32
33
|
|
|
33
34
|
describe('conversion', () => {
|
|
34
35
|
|
|
35
|
-
|
|
36
|
+
it('asString should return correct HSL and HSLA strings', () => {
|
|
36
37
|
const color1 = new HSL(120, 50, 50);
|
|
37
38
|
expect(color1.asString()).toBe('hsl(120,50%,50%)');
|
|
38
39
|
|
|
@@ -40,13 +41,13 @@ describe('HSL Class', () => {
|
|
|
40
41
|
expect(color2.asString()).toBe('hsla(120,50%,50%,0.5)');
|
|
41
42
|
});
|
|
42
43
|
|
|
43
|
-
|
|
44
|
+
it('asHSL and toHSL should return the same instance', () => {
|
|
44
45
|
const color = new HSL(120, 50, 50);
|
|
45
46
|
expect(color.asHSL()).toStrictEqual(color);
|
|
46
47
|
expect(color.toHSL()).toStrictEqual(color);
|
|
47
48
|
});
|
|
48
49
|
|
|
49
|
-
|
|
50
|
+
it('asHSV should correctly convert HSL to HSV', () => {
|
|
50
51
|
function check(input: [number, number, number], output: [number, number, number]) {
|
|
51
52
|
const hsl = new HSL(...input);
|
|
52
53
|
const hsv = hsl.asHSV();
|
|
@@ -66,7 +67,7 @@ describe('HSL Class', () => {
|
|
|
66
67
|
check([18, 100, 100], [18, 0, 100]);
|
|
67
68
|
});
|
|
68
69
|
|
|
69
|
-
|
|
70
|
+
it('asRGB should correctly convert HSL to RGB', () => {
|
|
70
71
|
function check(input: [number, number, number], output: [number, number, number]) {
|
|
71
72
|
const hsl = new HSL(...input)
|
|
72
73
|
const rgb = hsl.asRGB();
|
|
@@ -90,7 +91,7 @@ describe('HSL Class', () => {
|
|
|
90
91
|
|
|
91
92
|
describe('should parse valid HSL and HSLA strings', () => {
|
|
92
93
|
function check(str: string, result: number[]) {
|
|
93
|
-
|
|
94
|
+
it(`parse "${str}"`, () => {
|
|
94
95
|
const color = HSL.parse(str);
|
|
95
96
|
expect(color).toBeInstanceOf(HSL);
|
|
96
97
|
expect(color.asArray()).toStrictEqual(result);
|
|
@@ -101,7 +102,7 @@ describe('HSL Class', () => {
|
|
|
101
102
|
check('hsla(240,100%,50%,0.75)', [240, 100, 50, 0.75]);
|
|
102
103
|
check('hsl(400,50%,50%)', [40, 50, 50, 1]);
|
|
103
104
|
|
|
104
|
-
|
|
105
|
+
it('parse should throw an error for invalid strings', () => {
|
|
105
106
|
expect(() => HSL.parse('invalid')).toThrow('Invalid HSL color string');
|
|
106
107
|
});
|
|
107
108
|
});
|
|
@@ -110,11 +111,11 @@ describe('HSL Class', () => {
|
|
|
110
111
|
let color: HSL;
|
|
111
112
|
beforeEach(() => color = new HSL(120, 50, 50, 0.8));
|
|
112
113
|
|
|
113
|
-
|
|
114
|
+
it('inverts luminosity correctly', () => {
|
|
114
115
|
expect(color.invertLuminosity().asArray()).toStrictEqual([120, 50, 50, 0.8]); // Luminosity inverted to 50%
|
|
115
116
|
});
|
|
116
117
|
|
|
117
|
-
|
|
118
|
+
it('handles edge cases for luminosity inversion', () => {
|
|
118
119
|
const black = new HSL(0, 0, 0, 1);
|
|
119
120
|
expect(black.invertLuminosity().asArray()).toStrictEqual([0, 0, 100, 1]); // Black becomes white
|
|
120
121
|
|
|
@@ -127,15 +128,15 @@ describe('HSL Class', () => {
|
|
|
127
128
|
let color: HSL;
|
|
128
129
|
beforeEach(() => color = new HSL(120, 50, 50, 0.8));
|
|
129
130
|
|
|
130
|
-
|
|
131
|
+
it('rotates hue correctly within the range of 0-360', () => {
|
|
131
132
|
expect(color.rotateHue(180).asArray()).toStrictEqual([300, 50, 50, 0.8]); // Hue rotated by 180 degrees
|
|
132
133
|
});
|
|
133
134
|
|
|
134
|
-
|
|
135
|
+
it('handles negative rotation correctly', () => {
|
|
135
136
|
expect(color.rotateHue(-270).asArray()).toStrictEqual([210, 50, 50, 0.8]); // Hue rotated negatively
|
|
136
137
|
});
|
|
137
138
|
|
|
138
|
-
|
|
139
|
+
it('handles rotations that exceed 360 degrees', () => {
|
|
139
140
|
expect(color.rotateHue(540).asArray()).toStrictEqual([300, 50, 50, 0.8]); // Hue wrapped around to 300
|
|
140
141
|
});
|
|
141
142
|
});
|
|
@@ -147,16 +148,16 @@ describe('HSL Class', () => {
|
|
|
147
148
|
grey = new HSL(120, 0, 50, 0.8);
|
|
148
149
|
});
|
|
149
150
|
|
|
150
|
-
|
|
151
|
+
it('increases saturation correctly', () => {
|
|
151
152
|
expect(color.saturate(0.5).asArray()).toStrictEqual([120, 75, 50, 0.8]);
|
|
152
153
|
expect(grey.saturate(0.5).asArray()).toStrictEqual([120, 0, 50, 0.8]);
|
|
153
154
|
});
|
|
154
155
|
|
|
155
|
-
|
|
156
|
+
it('decreases saturation correctly', () => {
|
|
156
157
|
expect(color.saturate(-0.5).asArray()).toStrictEqual([120, 25, 50, 0.8]); // Saturation decreased by 50%
|
|
157
158
|
});
|
|
158
159
|
|
|
159
|
-
|
|
160
|
+
it('clamps saturation to the valid range', () => {
|
|
160
161
|
expect(color.saturate(1.5).asArray()).toStrictEqual([120, 100, 50, 0.8]); // Saturation clamped to 100%
|
|
161
162
|
|
|
162
163
|
expect(color.saturate(-2).asArray()).toStrictEqual([120, 0, 50, 0.8]); // Saturation clamped to 0%
|
|
@@ -167,11 +168,11 @@ describe('HSL Class', () => {
|
|
|
167
168
|
let color: HSL;
|
|
168
169
|
beforeEach(() => color = new HSL(120, 50, 50, 0.8));
|
|
169
170
|
|
|
170
|
-
|
|
171
|
+
it('reduces alpha correctly', () => {
|
|
171
172
|
expect(color.fade(0.5).asArray()).toStrictEqual([120, 50, 50, 0.4]); // Alpha reduced by 50%
|
|
172
173
|
});
|
|
173
174
|
|
|
174
|
-
|
|
175
|
+
it('handles edge cases for fading', () => {
|
|
175
176
|
const opaque = new HSL(0, 50, 50, 1);
|
|
176
177
|
expect(opaque.fade(1).asArray()).toStrictEqual([0, 50, 50, 0]); // Fully faded to transparent
|
|
177
178
|
|
package/src/color/hsv.test.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
1
2
|
import { HSV } from './hsv.js';
|
|
2
3
|
import { HSL } from './hsl.js';
|
|
3
4
|
import { RGB } from './rgb.js';
|
|
4
5
|
|
|
5
6
|
describe('HSV Class', () => {
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
it('constructor initializes values correctly with clamping', () => {
|
|
8
9
|
const color = new HSV(400, 120, 120, 2);
|
|
9
10
|
expect(color.asArray()).toStrictEqual([40, 100, 100, 1]);
|
|
10
11
|
|
|
@@ -12,12 +13,12 @@ describe('HSV Class', () => {
|
|
|
12
13
|
expect(colorNegative.asArray()).toStrictEqual([300, 0, 0, 0]);
|
|
13
14
|
});
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
it('asArray returns correct array representation', () => {
|
|
16
17
|
const color = new HSV(120, 50, 50, 0.5);
|
|
17
18
|
expect(color.asArray()).toStrictEqual([120, 50, 50, 0.5]);
|
|
18
19
|
});
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
it('clone returns a new instance with identical values', () => {
|
|
21
22
|
const color = new HSV(180, 70, 70, 0.7);
|
|
22
23
|
const clone = color.clone();
|
|
23
24
|
expect(clone).toBeInstanceOf(HSV);
|
|
@@ -26,35 +27,35 @@ describe('HSV Class', () => {
|
|
|
26
27
|
});
|
|
27
28
|
|
|
28
29
|
describe('asString', () => {
|
|
29
|
-
|
|
30
|
+
it('converts fully saturated colors correctly', () => {
|
|
30
31
|
expect(new HSV(0, 100, 100).asString()).toBe('hsl(0,100%,50%)');
|
|
31
32
|
expect(new HSV(120, 100, 100).asString()).toBe('hsl(120,100%,50%)');
|
|
32
33
|
expect(new HSV(240, 100, 100).asString()).toBe('hsl(240,100%,50%)');
|
|
33
34
|
});
|
|
34
35
|
|
|
35
|
-
|
|
36
|
+
it('handles partially saturated colors', () => {
|
|
36
37
|
expect(new HSV(60, 50, 100).asString()).toBe('hsl(60,100%,75%)');
|
|
37
38
|
expect(new HSV(300, 25, 50).asString()).toBe('hsl(300,14%,44%)');
|
|
38
39
|
});
|
|
39
40
|
|
|
40
|
-
|
|
41
|
+
it('handles achromatic (grey) colors', () => {
|
|
41
42
|
expect(new HSV(0, 0, 0).asString()).toBe('hsl(0,0%,0%)');
|
|
42
43
|
expect(new HSV(0, 0, 50).asString()).toBe('hsl(0,0%,50%)');
|
|
43
44
|
expect(new HSV(0, 0, 100).asString()).toBe('hsl(0,0%,100%)');
|
|
44
45
|
});
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
it('handles hue wrapping and extreme values', () => {
|
|
47
48
|
expect(new HSV(-60, 100, 100).asString()).toBe('hsl(300,100%,50%)');
|
|
48
49
|
expect(new HSV(420, 100, 100).asString()).toBe('hsl(60,100%,50%)');
|
|
49
50
|
});
|
|
50
51
|
|
|
51
|
-
|
|
52
|
+
it('handles alpha transparency', () => {
|
|
52
53
|
expect(new HSV(0, 100, 100, 0.5).asString()).toBe('hsla(0,100%,50%,0.5)');
|
|
53
54
|
expect(new HSV(120, 100, 100, 0.25).asString()).toBe('hsla(120,100%,50%,0.25)');
|
|
54
55
|
expect(new HSV(240, 100, 100, 1).asString()).toBe('hsl(240,100%,50%)');
|
|
55
56
|
});
|
|
56
57
|
|
|
57
|
-
|
|
58
|
+
it('produces consistent results for repeated calls', () => {
|
|
58
59
|
const color = new HSV(60, 50, 50);
|
|
59
60
|
expect(color.asString()).toBe('hsl(60,33%,38%)');
|
|
60
61
|
expect(color.asString()).toBe('hsl(60,33%,38%)');
|
|
@@ -63,7 +64,7 @@ describe('HSV Class', () => {
|
|
|
63
64
|
|
|
64
65
|
describe('color conversion', () => {
|
|
65
66
|
|
|
66
|
-
|
|
67
|
+
it('asHSL converts HSV to HSL correctly', () => {
|
|
67
68
|
function check(input: [number, number, number], output: [number, number, number]) {
|
|
68
69
|
const hsv = new HSV(...input);
|
|
69
70
|
const hsl = hsv.asHSL();
|
|
@@ -85,7 +86,7 @@ describe('HSV Class', () => {
|
|
|
85
86
|
check([18, 100, 100], [18, 100, 50]);
|
|
86
87
|
});
|
|
87
88
|
|
|
88
|
-
|
|
89
|
+
it('asRGB converts HSV to RGB correctly', () => {
|
|
89
90
|
const color = new HSV(120, 100, 100);
|
|
90
91
|
const rgb = color.asRGB();
|
|
91
92
|
expect(rgb).toBeInstanceOf(RGB);
|
|
@@ -93,13 +94,13 @@ describe('HSV Class', () => {
|
|
|
93
94
|
.toStrictEqual([0, 255, 0, 1]);
|
|
94
95
|
});
|
|
95
96
|
|
|
96
|
-
|
|
97
|
+
it('asHSV and toHSV return the same instance or clone', () => {
|
|
97
98
|
const color = new HSV(240, 100, 50, 1);
|
|
98
99
|
expect(color.asHSV()).toStrictEqual(color);
|
|
99
100
|
expect(color.toHSV()).toStrictEqual(color);
|
|
100
101
|
});
|
|
101
102
|
|
|
102
|
-
|
|
103
|
+
it('asRGB conversion S and V', () => {
|
|
103
104
|
function check(input: [number, number, number], output: [number, number, number]) {
|
|
104
105
|
const color = new HSV(...input);
|
|
105
106
|
const rgb = color.asRGB();
|
|
@@ -118,7 +119,7 @@ describe('HSV Class', () => {
|
|
|
118
119
|
check([18, 100, 100], [255, 77, 0]);
|
|
119
120
|
});
|
|
120
121
|
|
|
121
|
-
|
|
122
|
+
it('asRGB conversion H', () => {
|
|
122
123
|
function check(hue: number, output: string) {
|
|
123
124
|
const color = new HSV(hue, 100, 100);
|
|
124
125
|
expect(color.asRGB().asHex()).toBe(output);
|
|
@@ -146,24 +147,24 @@ describe('HSV Class', () => {
|
|
|
146
147
|
});
|
|
147
148
|
|
|
148
149
|
describe('parse errors and validations', () => {
|
|
149
|
-
|
|
150
|
+
it('constructor clamps out-of-bound values', () => {
|
|
150
151
|
const color = new HSV(400, 150, 150, 2);
|
|
151
152
|
expect(color.asArray()).toStrictEqual([40, 100, 100, 1]);
|
|
152
153
|
});
|
|
153
154
|
|
|
154
|
-
|
|
155
|
+
it('negative values are handled correctly', () => {
|
|
155
156
|
const color = new HSV(-360, -50, -50, -1);
|
|
156
157
|
expect(color.asArray()).toStrictEqual([0, 0, 0, 0]);
|
|
157
158
|
});
|
|
158
159
|
});
|
|
159
160
|
|
|
160
161
|
describe('fade', () => {
|
|
161
|
-
|
|
162
|
+
it('reduces alpha correctly', () => {
|
|
162
163
|
const color = new HSV(120, 50, 50, 0.8);
|
|
163
164
|
expect(color.fade(0.5).asArray()).toStrictEqual([120, 50, 50, 0.4]); // Alpha reduced by 50%
|
|
164
165
|
});
|
|
165
166
|
|
|
166
|
-
|
|
167
|
+
it('handles edge cases for fading', () => {
|
|
167
168
|
const opaque = new HSV(0, 50, 50, 1);
|
|
168
169
|
expect(opaque.fade(1).asArray()).toStrictEqual([0, 50, 50, 0]); // Fully faded to transparent
|
|
169
170
|
|
package/src/color/hsv.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Color } from './abstract.js';
|
|
2
2
|
import { HSL } from './hsl.js';
|
|
3
|
+
import randomColor, { RandomColorOptions } from './random.js';
|
|
3
4
|
import { RGB } from './rgb.js';
|
|
4
5
|
import { clamp, mod } from './utils.js';
|
|
5
6
|
|
|
@@ -165,4 +166,8 @@ export class HSV extends Color {
|
|
|
165
166
|
setHue(value: number): HSV {
|
|
166
167
|
return new HSV(value, this.s, this.v, this.a);
|
|
167
168
|
}
|
|
169
|
+
|
|
170
|
+
static randomColor(options?: RandomColorOptions): HSV {
|
|
171
|
+
return randomColor(options);
|
|
172
|
+
}
|
|
168
173
|
}
|
package/src/color/index.test.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
1
2
|
import { Color } from './index.js';
|
|
2
3
|
import { HSL } from './hsl.js';
|
|
3
4
|
import { HSV } from './hsv.js';
|
|
4
5
|
import { RGB } from './rgb.js';
|
|
5
6
|
|
|
7
|
+
|
|
6
8
|
describe('Color Conversions', () => {
|
|
7
9
|
|
|
8
10
|
const scenarios: [number, number, number, number][] = [
|
|
@@ -18,7 +20,7 @@ describe('Color Conversions', () => {
|
|
|
18
20
|
[800, 100, 100, 0.9],
|
|
19
21
|
[900, 12, 13, 1.0],
|
|
20
22
|
]
|
|
21
|
-
|
|
23
|
+
it('test HSV -> HSL -> RGB', () => {
|
|
22
24
|
for (const v of scenarios) {
|
|
23
25
|
const hsv = new HSV(...v);
|
|
24
26
|
expect(hsv.a).toEqual(v[3]);
|
|
@@ -29,7 +31,7 @@ describe('Color Conversions', () => {
|
|
|
29
31
|
}
|
|
30
32
|
});
|
|
31
33
|
|
|
32
|
-
|
|
34
|
+
it('test HSL -> HSV -> RGB', () => {
|
|
33
35
|
for (const v of scenarios) {
|
|
34
36
|
const hsl = new HSL(...v);
|
|
35
37
|
expect(hsl.a).toEqual(v[3]);
|
|
@@ -42,7 +44,7 @@ describe('Color Conversions', () => {
|
|
|
42
44
|
})
|
|
43
45
|
|
|
44
46
|
describe('Color.parse', () => {
|
|
45
|
-
|
|
47
|
+
it('parses hexadecimal color strings correctly', () => {
|
|
46
48
|
const color = Color.parse('#ff8040');
|
|
47
49
|
expect(color).toBeInstanceOf(RGB);
|
|
48
50
|
expect(color.asArray()).toStrictEqual([255, 128, 64, 1]);
|
|
@@ -52,7 +54,7 @@ describe('Color.parse', () => {
|
|
|
52
54
|
expect(colorWithAlpha.asHex()).toStrictEqual('#FF80407F');
|
|
53
55
|
});
|
|
54
56
|
|
|
55
|
-
|
|
57
|
+
it('parses RGB strings correctly', () => {
|
|
56
58
|
const color = Color.parse('rgb(255, 128, 64)');
|
|
57
59
|
expect(color).toBeInstanceOf(RGB);
|
|
58
60
|
expect(color.asArray()).toStrictEqual([255, 128, 64, 1]);
|
|
@@ -62,7 +64,7 @@ describe('Color.parse', () => {
|
|
|
62
64
|
expect(colorWithAlpha.asArray()).toStrictEqual([255, 128, 64, 0.5]);
|
|
63
65
|
});
|
|
64
66
|
|
|
65
|
-
|
|
67
|
+
it('parses HSL strings correctly', () => {
|
|
66
68
|
const color = Color.parse('hsl(120, 50%, 50%)');
|
|
67
69
|
expect(color).toBeInstanceOf(HSL);
|
|
68
70
|
expect(color.asArray()).toStrictEqual([120, 50, 50, 1]);
|
|
@@ -72,27 +74,27 @@ describe('Color.parse', () => {
|
|
|
72
74
|
expect(colorWithAlpha.asArray()).toStrictEqual([120, 50, 50, 0.5]);
|
|
73
75
|
});
|
|
74
76
|
|
|
75
|
-
|
|
77
|
+
it('throws an error for unsupported formats', () => {
|
|
76
78
|
expect(() => Color.parse('invalid color string')).toThrow('Unknown color format: invalid color string');
|
|
77
79
|
});
|
|
78
80
|
});
|
|
79
81
|
|
|
80
82
|
describe('Color Class Properties', () => {
|
|
81
|
-
|
|
83
|
+
it('Color.HSL is accessible', () => {
|
|
82
84
|
expect(Color.HSL).toBe(HSL);
|
|
83
85
|
});
|
|
84
86
|
|
|
85
|
-
|
|
87
|
+
it('Color.HSV is accessible', () => {
|
|
86
88
|
expect(Color.HSV).toBe(HSV);
|
|
87
89
|
});
|
|
88
90
|
|
|
89
|
-
|
|
91
|
+
it('Color.RGB is accessible', () => {
|
|
90
92
|
expect(Color.RGB).toBe(RGB);
|
|
91
93
|
});
|
|
92
94
|
});
|
|
93
95
|
|
|
94
96
|
describe('Exported Module', () => {
|
|
95
|
-
|
|
97
|
+
it('named export is Color', async () => {
|
|
96
98
|
const module = await import('./index.js');
|
|
97
99
|
expect(module.Color).toBe(Color);
|
|
98
100
|
});
|
package/src/color/random.test.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
1
2
|
import { HSV } from './hsv.js';
|
|
2
3
|
import type { RandomColorOptions } from './random.js';
|
|
3
4
|
import randomColor from './random.js';
|
|
4
5
|
|
|
5
6
|
describe('RandomColor', () => {
|
|
6
|
-
|
|
7
|
+
it('constructor initializes without errors', () => {
|
|
7
8
|
expect(randomColor).toBeDefined();
|
|
8
9
|
});
|
|
9
10
|
|
|
10
11
|
describe('Color.random', () => {
|
|
11
|
-
|
|
12
|
+
it('generates random HSV colors', () => {
|
|
12
13
|
const random = randomColor();
|
|
13
14
|
expect(random).toBeInstanceOf(HSV);
|
|
14
15
|
const array = random.asArray();
|
|
@@ -20,7 +21,7 @@ describe('RandomColor', () => {
|
|
|
20
21
|
expect(array[2]).toBeLessThanOrEqual(100);
|
|
21
22
|
});
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
it('supports options for generating random colors', () => {
|
|
24
25
|
const random = randomColor({ hue: 'red', luminosity: 'bright' });
|
|
25
26
|
expect(random).toBeInstanceOf(HSV);
|
|
26
27
|
// Additional checks based on the options provided can be added here
|
|
@@ -28,7 +29,7 @@ describe('RandomColor', () => {
|
|
|
28
29
|
});
|
|
29
30
|
|
|
30
31
|
describe('randomColor method', () => {
|
|
31
|
-
|
|
32
|
+
it('returns correct color string for some test cases', () => {
|
|
32
33
|
function t(options: RandomColorOptions): string {
|
|
33
34
|
return randomColor(options).asHSL().asString();
|
|
34
35
|
}
|
|
@@ -41,13 +42,13 @@ describe('RandomColor', () => {
|
|
|
41
42
|
expect(t({ seed: 'testSeed' })).toBe('hsl(185,90%,23%)');
|
|
42
43
|
});
|
|
43
44
|
|
|
44
|
-
|
|
45
|
+
it('consistent color generation with a seed', () => {
|
|
45
46
|
const color1 = randomColor({ seed: 'consistentSeed' });
|
|
46
47
|
const color2 = randomColor({ seed: 'consistentSeed' });
|
|
47
48
|
expect(color1.asHex()).toBe(color2.asHex());
|
|
48
49
|
});
|
|
49
50
|
|
|
50
|
-
|
|
51
|
+
it('different color generation without a seed', () => {
|
|
51
52
|
const color1 = randomColor({ seed: 'seed1' });
|
|
52
53
|
const color2 = randomColor({ seed: 'seed2' });
|
|
53
54
|
expect(color1.asHex()).not.toBe(color2.asHex());
|