@synnaxlabs/x 0.41.0 → 0.42.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/.turbo/turbo-build.log +23 -23
- package/dist/binary.cjs +1 -1
- package/dist/binary.js +2 -2
- package/dist/{bounds-M-SZ3X1Z.cjs → bounds-BQo7rvs9.cjs} +1 -1
- package/dist/{bounds-DQrjn60Q.js → bounds-Bn5_l4Z3.js} +10 -9
- package/dist/bounds.cjs +1 -1
- package/dist/bounds.js +1 -1
- package/dist/compare.cjs +1 -1
- package/dist/compare.js +1 -1
- package/dist/deep.cjs +1 -1
- package/dist/deep.js +84 -77
- package/dist/{dimensions-PWy5QZoM.cjs → dimensions-D2QGoNXO.cjs} +1 -1
- package/dist/dimensions.cjs +1 -1
- package/dist/{external-CvWr1nhS.cjs → external-DWQITF5_.cjs} +1 -1
- package/dist/index-BywOGO8U.js +1074 -0
- package/dist/index-CYYjI7Uf.cjs +1 -0
- package/dist/index-C_6NXBlg.cjs +3 -0
- package/dist/{index-BVC_8Cg9.js → index-QGplUHuy.js} +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.js +702 -243
- package/dist/record.js +3 -1
- package/dist/{scale-DL9VFGhL.cjs → scale-BtZINJ-A.cjs} +1 -1
- package/dist/{scale-DQwBWnwc.js → scale-DfJe9755.js} +1 -1
- package/dist/scale.cjs +1 -1
- package/dist/scale.js +1 -1
- package/dist/{series-D0zxMWxP.js → series-B9JERcqi.js} +571 -492
- package/dist/series-DqJ6f97G.cjs +11 -0
- package/dist/spatial.cjs +1 -1
- package/dist/spatial.js +2 -2
- package/dist/src/binary/{encoder.d.ts → codec.d.ts} +14 -8
- package/dist/src/binary/codec.d.ts.map +1 -0
- package/dist/src/binary/codec.spec.d.ts +2 -0
- package/dist/src/binary/codec.spec.d.ts.map +1 -0
- package/dist/src/binary/index.d.ts +1 -1
- package/dist/src/binary/index.d.ts.map +1 -1
- package/dist/src/breaker/breaker.d.ts +14 -21
- package/dist/src/breaker/breaker.d.ts.map +1 -1
- package/dist/src/change/change.d.ts +5 -18
- package/dist/src/change/change.d.ts.map +1 -1
- package/dist/src/color/color.d.ts +126 -0
- package/dist/src/color/color.d.ts.map +1 -0
- package/dist/src/color/color.spec.d.ts +2 -0
- package/dist/src/color/color.spec.d.ts.map +1 -0
- package/dist/src/color/external.d.ts +5 -0
- package/dist/src/color/external.d.ts.map +1 -0
- package/dist/src/color/gradient.d.ts +18 -0
- package/dist/src/color/gradient.d.ts.map +1 -0
- package/dist/src/color/index.d.ts +2 -0
- package/dist/src/color/index.d.ts.map +1 -0
- package/dist/src/color/palette.d.ts +19 -0
- package/dist/src/color/palette.d.ts.map +1 -0
- package/dist/src/color/transformColorsToHex.d.ts +6 -0
- package/dist/src/color/transformColorsToHex.d.ts.map +1 -0
- package/dist/src/control/control.d.ts +69 -74
- package/dist/src/control/control.d.ts.map +1 -1
- package/dist/src/deep/merge.d.ts +1 -1
- package/dist/src/deep/merge.d.ts.map +1 -1
- package/dist/src/errors/errors.d.ts +127 -7
- package/dist/src/errors/errors.d.ts.map +1 -1
- package/dist/src/errors/errors.spec.d.ts +2 -0
- package/dist/src/errors/errors.spec.d.ts.map +1 -0
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/jsonrpc/jsonrpc.d.ts +10 -7
- package/dist/src/jsonrpc/jsonrpc.d.ts.map +1 -1
- package/dist/src/kv/types.d.ts +1 -7
- package/dist/src/kv/types.d.ts.map +1 -1
- package/dist/src/migrate/migrate.d.ts +1 -1
- package/dist/src/notation/notation.d.ts +5 -1
- package/dist/src/notation/notation.d.ts.map +1 -1
- package/dist/src/record.d.ts +2 -1
- package/dist/src/record.d.ts.map +1 -1
- package/dist/src/replace.d.ts +2 -0
- package/dist/src/replace.d.ts.map +1 -0
- package/dist/src/runtime/os.d.ts +9 -1
- package/dist/src/runtime/os.d.ts.map +1 -1
- package/dist/src/singleton/define.d.ts +9 -0
- package/dist/src/singleton/define.d.ts.map +1 -0
- package/dist/src/singleton/define.spec.d.ts +2 -0
- package/dist/src/singleton/define.spec.d.ts.map +1 -0
- package/dist/src/singleton/index.d.ts +2 -0
- package/dist/src/singleton/index.d.ts.map +1 -0
- package/dist/src/spatial/base.d.ts +74 -70
- package/dist/src/spatial/base.d.ts.map +1 -1
- package/dist/src/spatial/box/box.d.ts +18 -76
- package/dist/src/spatial/box/box.d.ts.map +1 -1
- package/dist/src/spatial/dimensions/dimensions.d.ts +5 -29
- package/dist/src/spatial/dimensions/dimensions.d.ts.map +1 -1
- package/dist/src/spatial/direction/direction.d.ts +9 -1
- package/dist/src/spatial/direction/direction.d.ts.map +1 -1
- package/dist/src/spatial/location/location.d.ts +43 -22
- package/dist/src/spatial/location/location.d.ts.map +1 -1
- package/dist/src/spatial/scale/scale.d.ts +12 -120
- package/dist/src/spatial/scale/scale.d.ts.map +1 -1
- package/dist/src/spatial/xy/xy.d.ts +5 -29
- package/dist/src/spatial/xy/xy.d.ts.map +1 -1
- package/dist/src/sync/index.d.ts +2 -0
- package/dist/src/sync/index.d.ts.map +1 -0
- package/dist/src/sync/mutex.d.ts +8 -0
- package/dist/src/sync/mutex.d.ts.map +1 -0
- package/dist/src/telem/gl.d.ts +4 -1
- package/dist/src/telem/gl.d.ts.map +1 -1
- package/dist/src/telem/series.d.ts +46 -125
- package/dist/src/telem/series.d.ts.map +1 -1
- package/dist/src/telem/telem.d.ts +101 -86
- package/dist/src/telem/telem.d.ts.map +1 -1
- package/dist/src/toArray.d.ts +1 -1
- package/dist/src/toArray.d.ts.map +1 -1
- package/dist/src/zod/util.d.ts.map +1 -1
- package/dist/telem.cjs +1 -1
- package/dist/telem.js +1 -1
- package/dist/toArray.cjs +1 -1
- package/dist/toArray.js +1 -1
- package/dist/zod.cjs +1 -1
- package/package.json +5 -2
- package/src/binary/codec.spec.ts +370 -0
- package/src/binary/{encoder.ts → codec.ts} +55 -11
- package/src/binary/index.ts +1 -1
- package/src/breaker/breaker.spec.ts +16 -25
- package/src/breaker/breaker.ts +36 -19
- package/src/color/color.spec.ts +673 -0
- package/src/color/color.ts +317 -0
- package/src/color/external.ts +13 -0
- package/src/color/gradient.ts +78 -0
- package/src/color/index.ts +10 -0
- package/src/color/palette.ts +28 -0
- package/src/color/transformColorsToHex.ts +30 -0
- package/src/control/control.ts +30 -22
- package/src/deep/merge.spec.ts +60 -0
- package/src/deep/merge.ts +13 -8
- package/src/errors/errors.spec.ts +152 -0
- package/src/errors/errors.ts +225 -10
- package/src/index.ts +4 -0
- package/src/jsonrpc/jsonrpc.ts +12 -8
- package/src/migrate/migrate.ts +2 -2
- package/src/primitive.ts +1 -1
- package/src/record.ts +5 -1
- package/src/replace.ts +1 -0
- package/src/singleton/define.spec.ts +93 -0
- package/src/singleton/define.ts +27 -0
- package/src/singleton/index.ts +10 -0
- package/src/sync/index.ts +1 -0
- package/src/sync/mutex.ts +16 -0
- package/src/telem/series.spec.ts +32 -0
- package/src/telem/series.ts +54 -19
- package/src/telem/telem.spec.ts +151 -10
- package/src/telem/telem.ts +126 -73
- package/src/toArray.ts +2 -2
- package/src/zod/util.spec.ts +17 -1
- package/src/zod/util.ts +4 -2
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/index-BG3Scw3G.cjs +0 -1
- package/dist/index-C3QzbIwt.js +0 -101
- package/dist/index-CnclyYpG.cjs +0 -3
- package/dist/series-BMma2b5q.cjs +0 -11
- package/dist/src/binary/encoder.d.ts.map +0 -1
- package/dist/src/binary/encoder.spec.d.ts +0 -2
- package/dist/src/binary/encoder.spec.d.ts.map +0 -1
- package/src/binary/encoder.spec.ts +0 -174
|
@@ -0,0 +1,673 @@
|
|
|
1
|
+
// Copyright 2025 Synnax Labs, Inc.
|
|
2
|
+
//
|
|
3
|
+
// Use of this software is governed by the Business Source License included in the file
|
|
4
|
+
// licenses/BSL.txt.
|
|
5
|
+
//
|
|
6
|
+
// As of the Change Date specified in that file, in accordance with the Business Source
|
|
7
|
+
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
|
+
// included in the file licenses/APL.txt.
|
|
9
|
+
|
|
10
|
+
import { describe, expect, test } from "vitest";
|
|
11
|
+
|
|
12
|
+
import { color } from "@/color";
|
|
13
|
+
|
|
14
|
+
describe("color.Color", () => {
|
|
15
|
+
describe("constructor", () => {
|
|
16
|
+
test("from hex", () => {
|
|
17
|
+
const c = color.construct("#7a2c26");
|
|
18
|
+
expect(color.rValue(c)).toEqual(122);
|
|
19
|
+
expect(color.gValue(c)).toEqual(44);
|
|
20
|
+
expect(color.bValue(c)).toEqual(38);
|
|
21
|
+
});
|
|
22
|
+
test("from hex with alpha", () => {
|
|
23
|
+
const c = color.construct("#7a2c26", 0.5);
|
|
24
|
+
expect(color.rValue(c)).toEqual(122);
|
|
25
|
+
expect(color.gValue(c)).toEqual(44);
|
|
26
|
+
expect(color.bValue(c)).toEqual(38);
|
|
27
|
+
expect(color.aValue(c)).toEqual(0.5);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe("from eight digit hex", () => {
|
|
31
|
+
test("case 1", () => {
|
|
32
|
+
const c = color.construct("#7a2c26ff");
|
|
33
|
+
expect(color.rValue(c)).toEqual(122);
|
|
34
|
+
expect(color.gValue(c)).toEqual(44);
|
|
35
|
+
expect(color.bValue(c)).toEqual(38);
|
|
36
|
+
expect(color.aValue(c)).toEqual(1);
|
|
37
|
+
});
|
|
38
|
+
test("case 2", () => {
|
|
39
|
+
const c = color.construct("#7a2c2605");
|
|
40
|
+
expect(color.rValue(c)).toEqual(122);
|
|
41
|
+
expect(color.gValue(c)).toEqual(44);
|
|
42
|
+
expect(color.bValue(c)).toEqual(38);
|
|
43
|
+
expect(color.aValue(c)).toEqual(5 / 255);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("from rgb", () => {
|
|
48
|
+
const c = color.construct([122, 44, 38]);
|
|
49
|
+
expect(color.rValue(c)).toEqual(122);
|
|
50
|
+
expect(color.gValue(c)).toEqual(44);
|
|
51
|
+
expect(color.bValue(c)).toEqual(38);
|
|
52
|
+
});
|
|
53
|
+
test("from rgba", () => {
|
|
54
|
+
const c = color.construct([122, 44, 38, 0.5]);
|
|
55
|
+
expect(color.rValue(c)).toEqual(122);
|
|
56
|
+
expect(color.gValue(c)).toEqual(44);
|
|
57
|
+
expect(color.bValue(c)).toEqual(38);
|
|
58
|
+
expect(color.aValue(c)).toEqual(0.5);
|
|
59
|
+
});
|
|
60
|
+
test("from c", () => {
|
|
61
|
+
const c = color.construct(color.construct("#7a2c26"));
|
|
62
|
+
expect(color.rValue(c)).toEqual(122);
|
|
63
|
+
expect(color.gValue(c)).toEqual(44);
|
|
64
|
+
expect(color.bValue(c)).toEqual(38);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe("to hex", () => {
|
|
69
|
+
test("without alpha", () => {
|
|
70
|
+
const c = color.construct("#7a2c26");
|
|
71
|
+
expect(color.hex(c)).toEqual("#7a2c26");
|
|
72
|
+
});
|
|
73
|
+
test("with alpha", () => {
|
|
74
|
+
const c = color.construct("#7a2c26", 0.5);
|
|
75
|
+
expect(color.hex(c)).toEqual("#7a2c267f");
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe("to RGBA255", () => {
|
|
80
|
+
test("with alpha", () => {
|
|
81
|
+
const c = color.construct("#7a2c26", 0.5);
|
|
82
|
+
const expected = [122, 44, 38, 0.5];
|
|
83
|
+
expect(color.construct(c)).toEqual(expected);
|
|
84
|
+
});
|
|
85
|
+
test("without alpha", () => {
|
|
86
|
+
const c = color.construct("#7a2c26");
|
|
87
|
+
const expected = [122, 44, 38, 1];
|
|
88
|
+
expect(color.construct(c)).toEqual(expected);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
describe("to RGBA1", () => {
|
|
93
|
+
test("with alpha", () => {
|
|
94
|
+
const c = color.construct("#7a2c26", 0.5);
|
|
95
|
+
const expected = [122 / 255, 44 / 255, 38 / 255, 0.5];
|
|
96
|
+
expected.forEach((v, i) => {
|
|
97
|
+
expect(color.rgba1(c)[i]).toBeCloseTo(v);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
test("without alpha", () => {
|
|
101
|
+
const c = color.construct("#7a2c26");
|
|
102
|
+
const expected = [122 / 255, 44 / 255, 38 / 255, 1];
|
|
103
|
+
expected.forEach((v, i) => {
|
|
104
|
+
expect(color.rgba1(c)[i]).toBeCloseTo(v);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
describe("luminance", () => {
|
|
110
|
+
const tests: Array<[string, number]> = [
|
|
111
|
+
["#000000", 0],
|
|
112
|
+
["#ffffff", 1],
|
|
113
|
+
];
|
|
114
|
+
tests.forEach(([hex, expected]) => {
|
|
115
|
+
test(hex, () => {
|
|
116
|
+
const c = color.construct(hex);
|
|
117
|
+
expect(color.luminance(c)).toBeCloseTo(expected);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
describe("contrast", () => {
|
|
123
|
+
const tests: Array<[string, string, number]> = [
|
|
124
|
+
["#000000", "#ffffff", 3],
|
|
125
|
+
["#ffffff", "#000000", 3],
|
|
126
|
+
["#000000", "#000000", 1],
|
|
127
|
+
["#ffffff", "#ffffff", 1],
|
|
128
|
+
];
|
|
129
|
+
tests.forEach(([hex1, hex2, expected]) => {
|
|
130
|
+
test(`${hex1} ${hex2}`, () => {
|
|
131
|
+
const c1 = color.construct(hex1);
|
|
132
|
+
const c2 = color.construct(hex2);
|
|
133
|
+
expect(color.contrast(c1, c2)).toBeCloseTo(expected);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
test("pick c with highest contrast", () => {
|
|
137
|
+
const c = color.construct("#000000");
|
|
138
|
+
const c1 = color.construct("#ffffff");
|
|
139
|
+
const c2 = color.construct("#0000ff");
|
|
140
|
+
expect(color.pickByContrast(c, c1, c2)).toEqual(c1);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
describe("grayness", () => {
|
|
145
|
+
const tests: Array<[string, number]> = [
|
|
146
|
+
["#000000", 1],
|
|
147
|
+
["#ffffff", 1],
|
|
148
|
+
["#0000ff", 0],
|
|
149
|
+
["#00ff00", 0],
|
|
150
|
+
["#ff0000", 0],
|
|
151
|
+
["#ffff00", 0],
|
|
152
|
+
["#fefed4", 0.834],
|
|
153
|
+
["#5c6670", 0.92],
|
|
154
|
+
["#d3c5c5", 0.945],
|
|
155
|
+
];
|
|
156
|
+
tests.forEach(([hex, expected]) => {
|
|
157
|
+
test(hex, () => {
|
|
158
|
+
const c = color.construct(hex);
|
|
159
|
+
expect(color.grayness(c)).toBeCloseTo(expected);
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
describe("fromHSLA", () => {
|
|
165
|
+
const tests: Array<
|
|
166
|
+
[string, [number, number, number, number], [number, number, number, number]]
|
|
167
|
+
> = [
|
|
168
|
+
["Red", [0, 100, 50, 1], [255, 0, 0, 1]],
|
|
169
|
+
["Green", [120, 100, 50, 1], [0, 255, 0, 1]],
|
|
170
|
+
["Blue", [240, 100, 50, 1], [0, 0, 255, 1]],
|
|
171
|
+
["Yellow", [60, 100, 50, 1], [255, 255, 0, 1]],
|
|
172
|
+
["Cyan", [180, 100, 50, 1], [0, 255, 255, 1]],
|
|
173
|
+
["Magenta", [300, 100, 50, 1], [255, 0, 255, 1]],
|
|
174
|
+
["Black", [0, 0, 0, 1], [0, 0, 0, 1]],
|
|
175
|
+
["White", [0, 0, 100, 1], [255, 255, 255, 1]],
|
|
176
|
+
["Mid Gray", [0, 0, 50, 1], [128, 128, 128, 1]],
|
|
177
|
+
["Semi-transparent Red", [0, 100, 50, 0.5], [255, 0, 0, 0.5]],
|
|
178
|
+
];
|
|
179
|
+
|
|
180
|
+
tests.forEach(([name, hsla, expected]) => {
|
|
181
|
+
test(name, () => {
|
|
182
|
+
const result = color.fromHSLA(hsla);
|
|
183
|
+
expect(result).toEqual(expected);
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
test("converts HSLA to RGBA", () => {
|
|
188
|
+
const hsla: color.HSLA = [0, 100, 50, 1]; // Red in HSLA
|
|
189
|
+
const expected: color.RGBA = [255, 0, 0, 1]; // Red in RGBA
|
|
190
|
+
expect(color.fromHSLA(hsla)).toEqual(expected);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
test("handles hue wrapping properly", () => {
|
|
194
|
+
const hsla1: color.HSLA = [0, 100, 50, 1]; // 0 degrees = red
|
|
195
|
+
const hsla2: color.HSLA = [360, 100, 50, 1]; // 360 degrees = red
|
|
196
|
+
expect(color.fromHSLA(hsla1)).toEqual(color.fromHSLA(hsla2));
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
test("handles zero saturation (grayscale)", () => {
|
|
200
|
+
// For zero saturation, hue doesn't matter, only lightness
|
|
201
|
+
const white: color.HSLA = [0, 0, 100, 1];
|
|
202
|
+
const black: color.HSLA = [0, 0, 0, 1];
|
|
203
|
+
const gray: color.HSLA = [0, 0, 50, 1];
|
|
204
|
+
|
|
205
|
+
expect(color.fromHSLA(white)).toEqual([255, 255, 255, 1]);
|
|
206
|
+
expect(color.fromHSLA(black)).toEqual([0, 0, 0, 1]);
|
|
207
|
+
expect(color.fromHSLA(gray)).toEqual([128, 128, 128, 1]);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
test("preserves alpha value", () => {
|
|
211
|
+
const transparent: color.HSLA = [0, 100, 50, 0]; // Transparent red
|
|
212
|
+
const semiTransparent: color.HSLA = [0, 100, 50, 0.5]; // Semi-transparent red
|
|
213
|
+
|
|
214
|
+
expect(color.fromHSLA(transparent)[3]).toEqual(0);
|
|
215
|
+
expect(color.fromHSLA(semiTransparent)[3]).toEqual(0.5);
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
describe("hsla", () => {
|
|
220
|
+
const tests: Array<
|
|
221
|
+
[string, [number, number, number, number], [number, number, number, number]]
|
|
222
|
+
> = [
|
|
223
|
+
// Test primary colors
|
|
224
|
+
["Red", [255, 0, 0, 1], [0, 100, 50, 1]],
|
|
225
|
+
["Green", [0, 255, 0, 1], [120, 100, 50, 1]],
|
|
226
|
+
["Blue", [0, 0, 255, 1], [240, 100, 50, 1]],
|
|
227
|
+
|
|
228
|
+
// Test secondary colors
|
|
229
|
+
["Yellow", [255, 255, 0, 1], [60, 100, 50, 1]],
|
|
230
|
+
["Cyan", [0, 255, 255, 1], [180, 100, 50, 1]],
|
|
231
|
+
["Magenta", [255, 0, 255, 1], [300, 100, 50, 1]],
|
|
232
|
+
|
|
233
|
+
// Test shades of gray
|
|
234
|
+
["Black", [0, 0, 0, 1], [0, 0, 0, 1]],
|
|
235
|
+
["White", [255, 255, 255, 1], [0, 0, 100, 1]],
|
|
236
|
+
["Mid Gray", [128, 128, 128, 1], [0, 0, 50, 1]],
|
|
237
|
+
|
|
238
|
+
// Test different alpha values
|
|
239
|
+
["Transparent Red", [255, 0, 0, 0], [0, 100, 50, 0]],
|
|
240
|
+
["Semi-transparent Blue", [0, 0, 255, 0.5], [240, 100, 50, 0.5]],
|
|
241
|
+
|
|
242
|
+
// Test different lightness levels
|
|
243
|
+
["Dark Red", [128, 0, 0, 1], [0, 100, 25, 1]],
|
|
244
|
+
["Light Blue", [128, 128, 255, 1], [240, 100, 75, 1]],
|
|
245
|
+
|
|
246
|
+
// Test different saturation levels
|
|
247
|
+
["Desaturated Red", [191, 64, 64, 1], [0, 50, 50, 1]],
|
|
248
|
+
["Slightly Saturated Green", [96, 159, 96, 1], [120, 25, 50, 1]],
|
|
249
|
+
];
|
|
250
|
+
|
|
251
|
+
tests.forEach(([name, rgba, expected]) => {
|
|
252
|
+
test(name, () => {
|
|
253
|
+
const result = color.hsla(rgba);
|
|
254
|
+
// Note: Due to potential rounding differences in conversion,
|
|
255
|
+
// we use toBeCloseTo for HSL values with precision 0
|
|
256
|
+
for (let i = 0; i < 3; i++) expect(result[i]).toBeCloseTo(expected[i], 0);
|
|
257
|
+
|
|
258
|
+
// Alpha should match exactly
|
|
259
|
+
expect(result[3]).toEqual(expected[3]);
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
test("handles hex color input", () => {
|
|
264
|
+
// Red in hex
|
|
265
|
+
const hexColor = "#ff0000";
|
|
266
|
+
const expected = [0, 100, 50, 1];
|
|
267
|
+
const result = color.hsla(hexColor);
|
|
268
|
+
|
|
269
|
+
for (let i = 0; i < 3; i++) expect(result[i]).toBeCloseTo(expected[i], 0);
|
|
270
|
+
|
|
271
|
+
expect(result[3]).toEqual(expected[3]);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
test("handles RGB array input", () => {
|
|
275
|
+
// Green as RGB array
|
|
276
|
+
const rgbColor: color.RGB = [0, 255, 0];
|
|
277
|
+
const expected = [120, 100, 50, 1];
|
|
278
|
+
const result = color.hsla(rgbColor);
|
|
279
|
+
|
|
280
|
+
for (let i = 0; i < 3; i++) expect(result[i]).toBeCloseTo(expected[i], 0);
|
|
281
|
+
|
|
282
|
+
expect(result[3]).toEqual(1); // Default alpha
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
test("preserves original color after round-trip conversion", () => {
|
|
286
|
+
const originalColors: color.RGBA[] = [
|
|
287
|
+
[255, 0, 0, 1], // Red
|
|
288
|
+
[0, 255, 0, 1], // Green
|
|
289
|
+
[0, 0, 255, 1], // Blue
|
|
290
|
+
[255, 255, 0, 1], // Yellow
|
|
291
|
+
[0, 255, 255, 1], // Cyan
|
|
292
|
+
[255, 0, 255, 1], // Magenta
|
|
293
|
+
[128, 128, 128, 1], // Gray
|
|
294
|
+
[255, 255, 255, 0.5], // Semi-transparent white
|
|
295
|
+
];
|
|
296
|
+
|
|
297
|
+
for (const original of originalColors) {
|
|
298
|
+
const hsla = color.hsla(original);
|
|
299
|
+
const converted = color.fromHSLA(hsla);
|
|
300
|
+
|
|
301
|
+
// Compare RGB values with some tolerance for rounding
|
|
302
|
+
for (let i = 0; i < 3; i++) expect(converted[i]).toBeCloseTo(original[i], 0);
|
|
303
|
+
|
|
304
|
+
// Alpha should match exactly
|
|
305
|
+
expect(converted[3]).toEqual(original[3]);
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
test("handles achromatic colors correctly", () => {
|
|
310
|
+
// For achromatic colors (black, white, gray),
|
|
311
|
+
// hue is 0 and saturation is 0
|
|
312
|
+
const gray: color.RGBA = [100, 100, 100, 1];
|
|
313
|
+
const result = color.hsla(gray);
|
|
314
|
+
|
|
315
|
+
expect(result[0]).toEqual(0); // Hue
|
|
316
|
+
expect(result[1]).toEqual(0); // Saturation
|
|
317
|
+
expect(result[2]).toBeCloseTo(39, 0); // Lightness ~39%
|
|
318
|
+
expect(result[3]).toEqual(1); // Alpha
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
describe("setAlpha", () => {
|
|
323
|
+
test("sets alpha on RGB color", () => {
|
|
324
|
+
const rgb: color.RGB = [255, 0, 0];
|
|
325
|
+
const result = color.setAlpha(rgb, 0.5);
|
|
326
|
+
|
|
327
|
+
expect(result).toEqual([255, 0, 0, 0.5]);
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
test("sets alpha on RGBA color", () => {
|
|
331
|
+
const rgba: color.RGBA = [0, 255, 0, 1];
|
|
332
|
+
const result = color.setAlpha(rgba, 0.3);
|
|
333
|
+
|
|
334
|
+
expect(result).toEqual([0, 255, 0, 0.3]);
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
test("sets alpha on hex color", () => {
|
|
338
|
+
const hex = "#0000ff";
|
|
339
|
+
const result = color.setAlpha(hex, 0.7);
|
|
340
|
+
|
|
341
|
+
expect(result).toEqual([0, 0, 255, 0.7]);
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
test("overrides existing alpha in RGBA color", () => {
|
|
345
|
+
const rgba: color.RGBA = [128, 128, 128, 0.2];
|
|
346
|
+
const result = color.setAlpha(rgba, 0.8);
|
|
347
|
+
|
|
348
|
+
expect(result).toEqual([128, 128, 128, 0.8]);
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
test("handles alpha value of 0", () => {
|
|
352
|
+
const color1 = color.construct("#ff0000");
|
|
353
|
+
const result = color.setAlpha(color1, 0);
|
|
354
|
+
|
|
355
|
+
expect(result[3]).toEqual(0);
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
test("handles alpha value of 1", () => {
|
|
359
|
+
const color1 = color.construct("#ff0000", 0.5);
|
|
360
|
+
const result = color.setAlpha(color1, 1);
|
|
361
|
+
|
|
362
|
+
expect(result[3]).toEqual(1);
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
test("converts percentage (>1) alpha values to 0-1 range", () => {
|
|
366
|
+
const color1 = color.construct("#ff0000");
|
|
367
|
+
const result = color.setAlpha(color1, 50);
|
|
368
|
+
|
|
369
|
+
expect(result[3]).toEqual(0.5);
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
test("throws error for alpha values > 100", () => {
|
|
373
|
+
const color1 = color.construct("#ff0000");
|
|
374
|
+
expect(() => color.setAlpha(color1, 101)).toThrow();
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
test("preserves RGB values when setting alpha", () => {
|
|
378
|
+
const originalColor: color.RGBA = [123, 45, 67, 0.8];
|
|
379
|
+
const result = color.setAlpha(originalColor, 0.4);
|
|
380
|
+
|
|
381
|
+
expect(result[0]).toEqual(123);
|
|
382
|
+
expect(result[1]).toEqual(45);
|
|
383
|
+
expect(result[2]).toEqual(67);
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
test("return type is Color (RGBA format)", () => {
|
|
387
|
+
const hex = "#123456";
|
|
388
|
+
const result = color.setAlpha(hex, 0.5);
|
|
389
|
+
|
|
390
|
+
expect(Array.isArray(result)).toBe(true);
|
|
391
|
+
expect(result.length).toEqual(4);
|
|
392
|
+
expect(typeof result[3]).toBe("number");
|
|
393
|
+
});
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
describe("rgbaCSS", () => {
|
|
397
|
+
test("converts RGB array to CSS rgba string", () => {
|
|
398
|
+
const rgb: color.RGB = [255, 0, 0];
|
|
399
|
+
expect(color.rgbaCSS(rgb)).toEqual("rgba(255, 0, 0, 1)");
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
test("converts RGBA array to CSS rgba string", () => {
|
|
403
|
+
const rgba: color.RGBA = [0, 255, 0, 0.5];
|
|
404
|
+
expect(color.rgbaCSS(rgba)).toEqual("rgba(0, 255, 0, 0.5)");
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
test("converts hex to CSS rgba string", () => {
|
|
408
|
+
const hex = "#0000ff";
|
|
409
|
+
expect(color.rgbaCSS(hex)).toEqual("rgba(0, 0, 255, 1)");
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
test("converts hex with alpha to CSS rgba string", () => {
|
|
413
|
+
const hex = "#ff000080";
|
|
414
|
+
expect(color.rgbaCSS(hex)).toEqual("rgba(255, 0, 0, 0.5019607843137255)");
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
test("handles Color object", () => {
|
|
418
|
+
const c = color.construct([128, 128, 128, 0.7]);
|
|
419
|
+
expect(color.rgbaCSS(c)).toEqual("rgba(128, 128, 128, 0.7)");
|
|
420
|
+
});
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
describe("rgbCSS", () => {
|
|
424
|
+
test("converts RGB array to CSS rgb string", () => {
|
|
425
|
+
const rgb: color.RGB = [255, 0, 0];
|
|
426
|
+
expect(color.rgbCSS(rgb)).toEqual("rgb(255, 0, 0)");
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
test("converts RGBA array to CSS rgb string (ignores alpha)", () => {
|
|
430
|
+
const rgba: color.RGBA = [0, 255, 0, 0.5];
|
|
431
|
+
expect(color.rgbCSS(rgba)).toEqual("rgb(0, 255, 0)");
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
test("converts hex to CSS rgb string", () => {
|
|
435
|
+
const hex = "#0000ff";
|
|
436
|
+
expect(color.rgbCSS(hex)).toEqual("rgb(0, 0, 255)");
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
test("handles Color object", () => {
|
|
440
|
+
const c = color.construct([128, 128, 128, 0.7]);
|
|
441
|
+
expect(color.rgbCSS(c)).toEqual("rgb(128, 128, 128)");
|
|
442
|
+
});
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
describe("rgbString", () => {
|
|
446
|
+
test("converts RGB array to comma-separated string", () => {
|
|
447
|
+
const rgb: color.RGB = [255, 0, 0];
|
|
448
|
+
expect(color.rgbString(rgb)).toEqual("255, 0, 0");
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
test("converts RGBA array to comma-separated string (ignores alpha)", () => {
|
|
452
|
+
const rgba: color.RGBA = [0, 255, 0, 0.5];
|
|
453
|
+
expect(color.rgbString(rgba)).toEqual("0, 255, 0");
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
test("converts hex to comma-separated string", () => {
|
|
457
|
+
const hex = "#0000ff";
|
|
458
|
+
expect(color.rgbString(hex)).toEqual("0, 0, 255");
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
test("handles Color object", () => {
|
|
462
|
+
const c = color.construct([128, 128, 128, 0.7]);
|
|
463
|
+
expect(color.rgbString(c)).toEqual("128, 128, 128");
|
|
464
|
+
});
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
describe("equals", () => {
|
|
468
|
+
test("same RGB values are equal", () => {
|
|
469
|
+
const c1: color.RGB = [255, 0, 0];
|
|
470
|
+
const c2: color.RGB = [255, 0, 0];
|
|
471
|
+
expect(color.equals(c1, c2)).toBe(true);
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
test("different RGB values are not equal", () => {
|
|
475
|
+
const c1: color.RGB = [255, 0, 0];
|
|
476
|
+
const c2: color.RGB = [0, 255, 0];
|
|
477
|
+
expect(color.equals(c1, c2)).toBe(false);
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
test("RGBA and RGB with default alpha are equal", () => {
|
|
481
|
+
const c1: color.RGB = [255, 0, 0];
|
|
482
|
+
const c2: color.RGBA = [255, 0, 0, 1];
|
|
483
|
+
expect(color.equals(c1, c2)).toBe(true);
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
test("different alpha values are not equal", () => {
|
|
487
|
+
const c1: color.RGBA = [255, 0, 0, 1];
|
|
488
|
+
const c2: color.RGBA = [255, 0, 0, 0.5];
|
|
489
|
+
expect(color.equals(c1, c2)).toBe(false);
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
test("hex and RGB with same values are equal", () => {
|
|
493
|
+
const c1 = "#ff0000";
|
|
494
|
+
const c2: color.RGB = [255, 0, 0];
|
|
495
|
+
expect(color.equals(c1, c2)).toBe(true);
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
test("eight-digit hex and RGBA with same values are equal", () => {
|
|
499
|
+
const c1 = "#ff000080";
|
|
500
|
+
const c2: color.RGBA = [255, 0, 0, 0.5019607843137255];
|
|
501
|
+
expect(color.equals(c1, c2)).toBe(true);
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
test("undefined values return false", () => {
|
|
505
|
+
const c1: color.RGB = [255, 0, 0];
|
|
506
|
+
expect(color.equals(c1, undefined)).toBe(false);
|
|
507
|
+
expect(color.equals(undefined, c1)).toBe(false);
|
|
508
|
+
expect(color.equals(undefined, undefined)).toBe(false);
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
test("comparing color with itself returns true", () => {
|
|
512
|
+
const c = color.construct("#ff0000");
|
|
513
|
+
expect(color.equals(c, c)).toBe(true);
|
|
514
|
+
});
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
describe("cssString", () => {
|
|
518
|
+
test("returns undefined for undefined input", () => {
|
|
519
|
+
expect(color.cssString(undefined)).toBeUndefined();
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
test("returns undefined for null input", () => {
|
|
523
|
+
expect(color.cssString(null as any)).toBeUndefined();
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
test("converts RGB array to rgba CSS string", () => {
|
|
527
|
+
const rgb: color.RGB = [255, 0, 0];
|
|
528
|
+
expect(color.cssString(rgb)).toEqual("rgba(255, 0, 0, 1)");
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
test("converts RGBA array to rgba CSS string", () => {
|
|
532
|
+
const rgba: color.RGBA = [0, 255, 0, 0.5];
|
|
533
|
+
expect(color.cssString(rgba)).toEqual("rgba(0, 255, 0, 0.5)");
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
test("converts hex to rgba CSS string", () => {
|
|
537
|
+
const hex = "#0000ff";
|
|
538
|
+
expect(color.cssString(hex)).toEqual("rgba(0, 0, 255, 1)");
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
test("returns CSS variables as-is", () => {
|
|
542
|
+
const cssVar = "var(--primary-color)";
|
|
543
|
+
expect(color.cssString(cssVar)).toEqual(cssVar);
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
test("handles eight-digit hex with alpha", () => {
|
|
547
|
+
const hex = "#00ff0080";
|
|
548
|
+
expect(color.cssString(hex)).toEqual("rgba(0, 255, 0, 0.5019607843137255)");
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
test("handles Color object", () => {
|
|
552
|
+
const c = color.construct([128, 128, 128, 0.7]);
|
|
553
|
+
expect(color.cssString(c)).toEqual("rgba(128, 128, 128, 0.7)");
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
test("throws error for invalid color format", () => {
|
|
557
|
+
expect(() => color.cssString({} as any)).toThrow();
|
|
558
|
+
expect(() => color.cssString([1, 2] as any)).toThrow();
|
|
559
|
+
expect(() => color.cssString([300, 0, 0] as any)).toThrow();
|
|
560
|
+
});
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
describe("isCrude", () => {
|
|
564
|
+
test("RGB array is a crude color", () => {
|
|
565
|
+
const rgb: color.RGB = [255, 0, 0];
|
|
566
|
+
expect(color.isCrude(rgb)).toBe(true);
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
test("RGBA array is a crude color", () => {
|
|
570
|
+
const rgba: color.RGBA = [0, 255, 0, 0.5];
|
|
571
|
+
expect(color.isCrude(rgba)).toBe(true);
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
test("hex string is a crude color", () => {
|
|
575
|
+
expect(color.isCrude("#ff0000")).toBe(true);
|
|
576
|
+
});
|
|
577
|
+
|
|
578
|
+
test("hex string with hash is a crude color", () => {
|
|
579
|
+
expect(color.isCrude("#00ff00")).toBe(true);
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
test("eight-digit hex is a crude color", () => {
|
|
583
|
+
expect(color.isCrude("#0000ff80")).toBe(true);
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
test("Color object is a crude color", () => {
|
|
587
|
+
const c = color.construct("#ff0000");
|
|
588
|
+
expect(color.isCrude(c)).toBe(true);
|
|
589
|
+
});
|
|
590
|
+
|
|
591
|
+
test("rejects invalid hex strings", () => {
|
|
592
|
+
expect(color.isCrude("#xyz")).toBe(false);
|
|
593
|
+
expect(color.isCrude("#12345")).toBe(false);
|
|
594
|
+
expect(color.isCrude("#1234567")).toBe(false);
|
|
595
|
+
expect(color.isCrude("#123456789")).toBe(false);
|
|
596
|
+
});
|
|
597
|
+
|
|
598
|
+
test("rejects invalid RGB arrays", () => {
|
|
599
|
+
expect(color.isCrude([255])).toBe(false);
|
|
600
|
+
expect(color.isCrude([255, 0])).toBe(false);
|
|
601
|
+
expect(color.isCrude([255, 0, 0, 0.5, 1])).toBe(false);
|
|
602
|
+
expect(color.isCrude([-1, 0, 0])).toBe(false);
|
|
603
|
+
expect(color.isCrude([0, 256, 0])).toBe(false);
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
test("rejects invalid RGBA arrays", () => {
|
|
607
|
+
expect(color.isCrude([255, 0, 0, 1.1])).toBe(false);
|
|
608
|
+
expect(color.isCrude([255, 0, 0, -0.1])).toBe(false);
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
test("rejects non-color values", () => {
|
|
612
|
+
expect(color.isCrude(null)).toBe(false);
|
|
613
|
+
expect(color.isCrude(undefined)).toBe(false);
|
|
614
|
+
expect(color.isCrude({})).toBe(false);
|
|
615
|
+
expect(color.isCrude("not a color")).toBe(false);
|
|
616
|
+
expect(color.isCrude(123)).toBe(false);
|
|
617
|
+
expect(color.isCrude(true)).toBe(false);
|
|
618
|
+
});
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
describe("isColor", () => {
|
|
622
|
+
test("valid RGBA array is a Color", () => {
|
|
623
|
+
const rgba: color.RGBA = [0, 255, 0, 0.5];
|
|
624
|
+
expect(color.isColor(rgba)).toBe(true);
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
test("RGB array with 3 elements is not a Color", () => {
|
|
628
|
+
const rgb: color.RGB = [255, 0, 0];
|
|
629
|
+
expect(color.isColor(rgb)).toBe(false);
|
|
630
|
+
});
|
|
631
|
+
|
|
632
|
+
test("constructed Color is a Color", () => {
|
|
633
|
+
const c = color.construct("#ff0000");
|
|
634
|
+
expect(color.isColor(c)).toBe(true);
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
test("hex string is not a Color", () => {
|
|
638
|
+
expect(color.isColor("#ff0000")).toBe(false);
|
|
639
|
+
});
|
|
640
|
+
|
|
641
|
+
test("rejects invalid RGBA arrays", () => {
|
|
642
|
+
expect(color.isColor([255, 0, 0])).toBe(false); // Missing alpha
|
|
643
|
+
expect(color.isColor([255, 0, 0, 0, 0])).toBe(false); // Too many elements
|
|
644
|
+
expect(color.isColor([255, 0, -1, 1])).toBe(false); // Negative value
|
|
645
|
+
expect(color.isColor([255, 0, 256, 1])).toBe(false); // Value > 255
|
|
646
|
+
expect(color.isColor([255, 0, 0, 1.1])).toBe(false); // Alpha > 1
|
|
647
|
+
expect(color.isColor([255, 0, 0, -0.1])).toBe(false); // Alpha < 0
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
test("rejects non-array values", () => {
|
|
651
|
+
expect(color.isColor(null)).toBe(false);
|
|
652
|
+
expect(color.isColor(undefined)).toBe(false);
|
|
653
|
+
expect(color.isColor({})).toBe(false);
|
|
654
|
+
expect(color.isColor("rgba(255,0,0,1)")).toBe(false);
|
|
655
|
+
expect(color.isColor(123)).toBe(false);
|
|
656
|
+
});
|
|
657
|
+
|
|
658
|
+
test("validates RGB values are within range", () => {
|
|
659
|
+
expect(color.isColor([0, 0, 0, 0])).toBe(true);
|
|
660
|
+
expect(color.isColor([255, 255, 255, 1])).toBe(true);
|
|
661
|
+
expect(color.isColor([300, 0, 0, 1])).toBe(false);
|
|
662
|
+
expect(color.isColor([0, -10, 0, 1])).toBe(false);
|
|
663
|
+
});
|
|
664
|
+
|
|
665
|
+
test("validates alpha is within 0-1 range", () => {
|
|
666
|
+
expect(color.isColor([0, 0, 0, 0])).toBe(true);
|
|
667
|
+
expect(color.isColor([0, 0, 0, 1])).toBe(true);
|
|
668
|
+
expect(color.isColor([0, 0, 0, 0.5])).toBe(true);
|
|
669
|
+
expect(color.isColor([0, 0, 0, -0.1])).toBe(false);
|
|
670
|
+
expect(color.isColor([0, 0, 0, 1.1])).toBe(false);
|
|
671
|
+
});
|
|
672
|
+
});
|
|
673
|
+
});
|