@luntta/swatch 3.0.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/CHANGELOG.md +56 -0
- package/CONTRIBUTING.md +89 -0
- package/LICENSE +21 -0
- package/MIGRATING.md +189 -0
- package/README.md +463 -0
- package/package.json +57 -0
- package/scripts/pack-check.mjs +18 -0
- package/src/bootstrap.js +159 -0
- package/src/core/registry.js +81 -0
- package/src/core/state.js +36 -0
- package/src/core/swatch-class.js +524 -0
- package/src/data/cvd-matrices.js +179 -0
- package/src/data/named-colors.js +157 -0
- package/src/format/css.js +256 -0
- package/src/operations/accessibility.js +103 -0
- package/src/operations/apca.js +80 -0
- package/src/operations/blend.js +72 -0
- package/src/operations/channels.js +123 -0
- package/src/operations/cvd.js +119 -0
- package/src/operations/deltaE.js +207 -0
- package/src/operations/gamut.js +206 -0
- package/src/operations/image.js +192 -0
- package/src/operations/manipulation.js +100 -0
- package/src/operations/mix.js +129 -0
- package/src/operations/naming.js +158 -0
- package/src/operations/palette.js +133 -0
- package/src/operations/random.js +75 -0
- package/src/operations/temperature.js +126 -0
- package/src/operations/tint-shade.js +42 -0
- package/src/palettes/colorbrewer.js +232 -0
- package/src/palettes/index.js +58 -0
- package/src/palettes/viridis.js +59 -0
- package/src/parse/css.js +241 -0
- package/src/parse/hex.js +38 -0
- package/src/parse/index.js +43 -0
- package/src/parse/legacy.js +88 -0
- package/src/parse/named.js +11 -0
- package/src/parse/objects.js +125 -0
- package/src/scale/index.js +382 -0
- package/src/scale/interpolators.js +83 -0
- package/src/spaces/a98.js +55 -0
- package/src/spaces/cmyk.js +75 -0
- package/src/spaces/display-p3.js +50 -0
- package/src/spaces/hsl.js +93 -0
- package/src/spaces/hsluv.js +211 -0
- package/src/spaces/hsv.js +78 -0
- package/src/spaces/hwb.js +48 -0
- package/src/spaces/lab.js +70 -0
- package/src/spaces/lch.js +65 -0
- package/src/spaces/oklab.js +79 -0
- package/src/spaces/oklch.js +53 -0
- package/src/spaces/prophoto.js +72 -0
- package/src/spaces/rec2020.js +65 -0
- package/src/spaces/srgb.js +85 -0
- package/src/spaces/xyz.js +71 -0
- package/src/swatch.js +57 -0
- package/src/util/math.js +53 -0
- package/src/util/matrix.js +92 -0
- package/src/util/suggest.js +66 -0
- package/types/swatch.d.ts +664 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// Small string-suggestion helpers for developer-facing error messages.
|
|
2
|
+
|
|
3
|
+
function editDistance(a, b) {
|
|
4
|
+
const left = String(a).toLowerCase();
|
|
5
|
+
const right = String(b).toLowerCase();
|
|
6
|
+
const rows = left.length + 1;
|
|
7
|
+
const cols = right.length + 1;
|
|
8
|
+
const dp = Array.from({ length: rows }, () => new Array(cols).fill(0));
|
|
9
|
+
|
|
10
|
+
for (let i = 0; i < rows; i++) dp[i][0] = i;
|
|
11
|
+
for (let j = 0; j < cols; j++) dp[0][j] = j;
|
|
12
|
+
|
|
13
|
+
for (let i = 1; i <= left.length; i++) {
|
|
14
|
+
for (let j = 1; j <= right.length; j++) {
|
|
15
|
+
const cost = left[i - 1] === right[j - 1] ? 0 : 1;
|
|
16
|
+
dp[i][j] = Math.min(
|
|
17
|
+
dp[i - 1][j] + 1,
|
|
18
|
+
dp[i][j - 1] + 1,
|
|
19
|
+
dp[i - 1][j - 1] + cost
|
|
20
|
+
);
|
|
21
|
+
if (
|
|
22
|
+
i > 1 &&
|
|
23
|
+
j > 1 &&
|
|
24
|
+
left[i - 1] === right[j - 2] &&
|
|
25
|
+
left[i - 2] === right[j - 1]
|
|
26
|
+
) {
|
|
27
|
+
dp[i][j] = Math.min(dp[i][j], dp[i - 2][j - 2] + 1);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return dp[left.length][right.length];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function closestMatch(value, candidates, maxDistance) {
|
|
36
|
+
if (value == null) return null;
|
|
37
|
+
const input = String(value);
|
|
38
|
+
if (!input || !Array.isArray(candidates) || candidates.length === 0) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
let best = null;
|
|
43
|
+
let bestDistance = Infinity;
|
|
44
|
+
for (const candidate of candidates) {
|
|
45
|
+
const distance = editDistance(input, candidate);
|
|
46
|
+
if (distance < bestDistance) {
|
|
47
|
+
best = candidate;
|
|
48
|
+
bestDistance = distance;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const threshold =
|
|
53
|
+
maxDistance ?? Math.max(2, Math.floor(Math.max(input.length, 4) * 0.4));
|
|
54
|
+
return bestDistance <= threshold ? best : null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function quotedList(items) {
|
|
58
|
+
return items.map((item) => `"${item}"`).join(", ");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function appendSuggestion(message, value, candidates) {
|
|
62
|
+
const match = closestMatch(value, candidates);
|
|
63
|
+
const suffix = [`Valid options: ${quotedList(candidates)}.`];
|
|
64
|
+
if (match) suffix.unshift(`Did you mean "${match}"?`);
|
|
65
|
+
return `${message}. ${suffix.join(" ")}`;
|
|
66
|
+
}
|
|
@@ -0,0 +1,664 @@
|
|
|
1
|
+
// Type definitions for swatch 3.0
|
|
2
|
+
// Project: https://github.com/luntta/swatch
|
|
3
|
+
|
|
4
|
+
// ─── Space names ──────────────────────────────────────────────────────
|
|
5
|
+
|
|
6
|
+
export type SpaceId =
|
|
7
|
+
| "srgb"
|
|
8
|
+
| "srgb-linear"
|
|
9
|
+
| "display-p3"
|
|
10
|
+
| "rec2020"
|
|
11
|
+
| "a98"
|
|
12
|
+
| "prophoto"
|
|
13
|
+
| "xyz"
|
|
14
|
+
| "xyz-d65"
|
|
15
|
+
| "xyz-d50"
|
|
16
|
+
| "lab"
|
|
17
|
+
| "lab-d50"
|
|
18
|
+
| "lch"
|
|
19
|
+
| "lch-d50"
|
|
20
|
+
| "oklab"
|
|
21
|
+
| "oklch"
|
|
22
|
+
| "hsl"
|
|
23
|
+
| "hsv"
|
|
24
|
+
| "hwb"
|
|
25
|
+
| "cmyk"
|
|
26
|
+
| "luv"
|
|
27
|
+
| "hsluv";
|
|
28
|
+
|
|
29
|
+
export interface SpaceConstants {
|
|
30
|
+
readonly srgb: "srgb";
|
|
31
|
+
readonly linearSrgb: "srgb-linear";
|
|
32
|
+
readonly displayP3: "display-p3";
|
|
33
|
+
readonly rec2020: "rec2020";
|
|
34
|
+
readonly a98: "a98";
|
|
35
|
+
readonly prophoto: "prophoto";
|
|
36
|
+
readonly xyz: "xyz";
|
|
37
|
+
readonly xyzD65: "xyz-d65";
|
|
38
|
+
readonly xyzD50: "xyz-d50";
|
|
39
|
+
readonly lab: "lab";
|
|
40
|
+
readonly labD50: "lab-d50";
|
|
41
|
+
readonly lch: "lch";
|
|
42
|
+
readonly lchD50: "lch-d50";
|
|
43
|
+
readonly oklab: "oklab";
|
|
44
|
+
readonly oklch: "oklch";
|
|
45
|
+
readonly hsl: "hsl";
|
|
46
|
+
readonly hsv: "hsv";
|
|
47
|
+
readonly hwb: "hwb";
|
|
48
|
+
readonly cmyk: "cmyk";
|
|
49
|
+
readonly luv: "luv";
|
|
50
|
+
readonly hsluv: "hsluv";
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
type RgbLikeSpaceId =
|
|
54
|
+
| "rgb"
|
|
55
|
+
| "srgb"
|
|
56
|
+
| "srgb-linear"
|
|
57
|
+
| "display-p3"
|
|
58
|
+
| "rec2020"
|
|
59
|
+
| "a98"
|
|
60
|
+
| "prophoto";
|
|
61
|
+
type XyzLikeSpaceId = "xyz" | "xyz-d65" | "xyz-d50";
|
|
62
|
+
type LabLikeSpaceId = "lab" | "lab-d50" | "oklab";
|
|
63
|
+
type LchLikeSpaceId = "lch" | "lch-d50" | "oklch";
|
|
64
|
+
|
|
65
|
+
export type ChannelPath =
|
|
66
|
+
| "alpha"
|
|
67
|
+
| `${RgbLikeSpaceId}.${"r" | "g" | "b"}`
|
|
68
|
+
| `${XyzLikeSpaceId}.${"x" | "y" | "z"}`
|
|
69
|
+
| `${LabLikeSpaceId}.${"l" | "a" | "b"}`
|
|
70
|
+
| `${LchLikeSpaceId}.${"l" | "c" | "h"}`
|
|
71
|
+
| `hsl.${"h" | "s" | "l"}`
|
|
72
|
+
| `hsv.${"h" | "s" | "v"}`
|
|
73
|
+
| `hwb.${"h" | "w" | "b"}`
|
|
74
|
+
| `hsluv.${"h" | "s" | "l"}`
|
|
75
|
+
| `luv.${"l" | "u" | "v"}`
|
|
76
|
+
| `cmyk.${"c" | "m" | "y" | "k"}`;
|
|
77
|
+
|
|
78
|
+
// ─── Channel object shapes (returned by the per-space getters) ─────
|
|
79
|
+
|
|
80
|
+
export interface SrgbChannels {
|
|
81
|
+
r: number;
|
|
82
|
+
g: number;
|
|
83
|
+
b: number;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface XyzChannels {
|
|
87
|
+
x: number;
|
|
88
|
+
y: number;
|
|
89
|
+
z: number;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface LabChannels {
|
|
93
|
+
l: number;
|
|
94
|
+
a: number;
|
|
95
|
+
b: number;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface LchChannels {
|
|
99
|
+
l: number;
|
|
100
|
+
c: number;
|
|
101
|
+
h: number;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface HslChannels {
|
|
105
|
+
h: number;
|
|
106
|
+
s: number;
|
|
107
|
+
l: number;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export interface HsvChannels {
|
|
111
|
+
h: number;
|
|
112
|
+
s: number;
|
|
113
|
+
v: number;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export interface HwbChannels {
|
|
117
|
+
h: number;
|
|
118
|
+
w: number;
|
|
119
|
+
b: number;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export interface CmykChannels {
|
|
123
|
+
c: number;
|
|
124
|
+
m: number;
|
|
125
|
+
y: number;
|
|
126
|
+
k: number;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export interface HsluvChannels {
|
|
130
|
+
h: number;
|
|
131
|
+
s: number;
|
|
132
|
+
l: number;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export interface LuvChannels {
|
|
136
|
+
l: number;
|
|
137
|
+
u: number;
|
|
138
|
+
v: number;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ─── Input forms ──────────────────────────────────────────────────────
|
|
142
|
+
|
|
143
|
+
export interface StateInput {
|
|
144
|
+
space: SpaceId;
|
|
145
|
+
coords: [number, number, number];
|
|
146
|
+
alpha?: number;
|
|
147
|
+
a?: number;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export interface LegacyRgbInput {
|
|
151
|
+
/** Legacy object input in 0..255 channel units. */
|
|
152
|
+
r: number;
|
|
153
|
+
g: number;
|
|
154
|
+
b: number;
|
|
155
|
+
a?: number;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export interface HslInput {
|
|
159
|
+
h: number;
|
|
160
|
+
s: number;
|
|
161
|
+
l: number;
|
|
162
|
+
a?: number;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export interface HsvInput {
|
|
166
|
+
h: number;
|
|
167
|
+
s: number;
|
|
168
|
+
v: number;
|
|
169
|
+
a?: number;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export interface HwbInput {
|
|
173
|
+
h: number;
|
|
174
|
+
w: number;
|
|
175
|
+
b: number;
|
|
176
|
+
a?: number;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export interface LabInput {
|
|
180
|
+
l: number;
|
|
181
|
+
a: number;
|
|
182
|
+
b: number;
|
|
183
|
+
alpha?: number;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export interface LchInput {
|
|
187
|
+
l: number;
|
|
188
|
+
c: number;
|
|
189
|
+
h: number;
|
|
190
|
+
alpha?: number;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export interface CmykInput {
|
|
194
|
+
c: number;
|
|
195
|
+
m: number;
|
|
196
|
+
y: number;
|
|
197
|
+
k: number;
|
|
198
|
+
alpha?: number;
|
|
199
|
+
a?: number;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export type ColorInput =
|
|
203
|
+
| string
|
|
204
|
+
| Swatch
|
|
205
|
+
| StateInput
|
|
206
|
+
| LegacyRgbInput
|
|
207
|
+
| HslInput
|
|
208
|
+
| LabInput
|
|
209
|
+
| LchInput
|
|
210
|
+
| HsvInput
|
|
211
|
+
| HwbInput
|
|
212
|
+
| CmykInput;
|
|
213
|
+
|
|
214
|
+
// ─── Options bags ─────────────────────────────────────────────────────
|
|
215
|
+
|
|
216
|
+
export type CVDType =
|
|
217
|
+
| "protan"
|
|
218
|
+
| "protanopia"
|
|
219
|
+
| "protanomaly"
|
|
220
|
+
| "deutan"
|
|
221
|
+
| "deuteranopia"
|
|
222
|
+
| "deuteranomaly"
|
|
223
|
+
| "tritan"
|
|
224
|
+
| "tritanopia"
|
|
225
|
+
| "tritanomaly"
|
|
226
|
+
| "achroma"
|
|
227
|
+
| "achromatopsia";
|
|
228
|
+
|
|
229
|
+
export interface CvdConstants {
|
|
230
|
+
readonly protan: "protan";
|
|
231
|
+
readonly protanopia: "protanopia";
|
|
232
|
+
readonly protanomaly: "protanomaly";
|
|
233
|
+
readonly deutan: "deutan";
|
|
234
|
+
readonly deuteranopia: "deuteranopia";
|
|
235
|
+
readonly deuteranomaly: "deuteranomaly";
|
|
236
|
+
readonly tritan: "tritan";
|
|
237
|
+
readonly tritanopia: "tritanopia";
|
|
238
|
+
readonly tritanomaly: "tritanomaly";
|
|
239
|
+
readonly achroma: "achroma";
|
|
240
|
+
readonly achromatopsia: "achromatopsia";
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export type DeltaEMode = "76" | "94" | "2000" | "cmc" | "hyab" | "ok";
|
|
244
|
+
|
|
245
|
+
export interface DeltaECmcOptions {
|
|
246
|
+
l?: number;
|
|
247
|
+
c?: number;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export type WCAGLevel = "AA" | "AAA";
|
|
251
|
+
export type WCAGSize = "normal" | "large" | "ui";
|
|
252
|
+
|
|
253
|
+
export interface IsReadableOptions {
|
|
254
|
+
level?: WCAGLevel;
|
|
255
|
+
size?: WCAGSize;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export interface EnsureContrastOptions {
|
|
259
|
+
minRatio?: number;
|
|
260
|
+
direction?: "auto" | "lighter" | "darker";
|
|
261
|
+
step?: number;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export interface MixOptions {
|
|
265
|
+
space?: SpaceId;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export interface EqualsOptions {
|
|
269
|
+
epsilon?: number;
|
|
270
|
+
/** Alias for epsilon. */
|
|
271
|
+
tolerance?: number;
|
|
272
|
+
/** Compare both colors in this space instead of the receiver's native space. */
|
|
273
|
+
space?: SpaceId;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export interface HexOptions {
|
|
277
|
+
/** Include alpha as #rrggbbaa. Default false. */
|
|
278
|
+
alpha?: boolean;
|
|
279
|
+
/** Map wide-gamut colors into sRGB before serializing. Default true. */
|
|
280
|
+
gamut?: boolean;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export interface RgbOptions {
|
|
284
|
+
/** Include `a`; default "auto" includes it only when alpha < 1. */
|
|
285
|
+
alpha?: boolean | "auto" | "always" | "never";
|
|
286
|
+
/** Map wide-gamut colors into sRGB before serializing. Default true. */
|
|
287
|
+
gamut?: boolean;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export interface SimulateOptions {
|
|
291
|
+
severity?: number;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
export interface DaltonizeOptions {
|
|
295
|
+
severity?: number;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export interface ImageDataLike {
|
|
299
|
+
data: Uint8ClampedArray;
|
|
300
|
+
width: number;
|
|
301
|
+
height: number;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export interface ImageDataTransformOptions {
|
|
305
|
+
severity?: number;
|
|
306
|
+
/** Mutate and return the provided ImageData-like object. Default true. */
|
|
307
|
+
inPlace?: boolean;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export interface ImageApi {
|
|
311
|
+
simulate<T extends ImageDataLike>(
|
|
312
|
+
imageData: T,
|
|
313
|
+
type: CVDType,
|
|
314
|
+
opts?: ImageDataTransformOptions & { inPlace?: true }
|
|
315
|
+
): T;
|
|
316
|
+
simulate(
|
|
317
|
+
imageData: ImageDataLike,
|
|
318
|
+
type: CVDType,
|
|
319
|
+
opts: ImageDataTransformOptions & { inPlace: false }
|
|
320
|
+
): ImageDataLike;
|
|
321
|
+
daltonize<T extends ImageDataLike>(
|
|
322
|
+
imageData: T,
|
|
323
|
+
type: Exclude<CVDType, "achroma" | "achromatopsia">,
|
|
324
|
+
opts?: ImageDataTransformOptions & { inPlace?: true }
|
|
325
|
+
): T;
|
|
326
|
+
daltonize(
|
|
327
|
+
imageData: ImageDataLike,
|
|
328
|
+
type: Exclude<CVDType, "achroma" | "achromatopsia">,
|
|
329
|
+
opts: ImageDataTransformOptions & { inPlace: false }
|
|
330
|
+
): ImageDataLike;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
export interface ManipulationOptions {
|
|
334
|
+
/** Skip sRGB gamut mapping after the op. Default true (mapping on). */
|
|
335
|
+
gamut?: boolean;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
export interface GamutOptions {
|
|
339
|
+
space?: SpaceId;
|
|
340
|
+
method?: "clip" | "css4" | "oklch-chroma";
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
export type BlendMode =
|
|
344
|
+
| "normal"
|
|
345
|
+
| "multiply"
|
|
346
|
+
| "screen"
|
|
347
|
+
| "darken"
|
|
348
|
+
| "lighten"
|
|
349
|
+
| "overlay"
|
|
350
|
+
| "color-dodge"
|
|
351
|
+
| "color-burn"
|
|
352
|
+
| "hard-light"
|
|
353
|
+
| "soft-light"
|
|
354
|
+
| "difference"
|
|
355
|
+
| "exclusion";
|
|
356
|
+
|
|
357
|
+
export type FormatName =
|
|
358
|
+
| "hex"
|
|
359
|
+
| "hex-alpha"
|
|
360
|
+
| "rgb"
|
|
361
|
+
| "rgb-legacy"
|
|
362
|
+
| "hsl"
|
|
363
|
+
| "hsl-legacy"
|
|
364
|
+
| "hwb"
|
|
365
|
+
| "lab"
|
|
366
|
+
| "lch"
|
|
367
|
+
| "oklab"
|
|
368
|
+
| "oklch"
|
|
369
|
+
| "color";
|
|
370
|
+
|
|
371
|
+
export type ColorFunctionSpaceId =
|
|
372
|
+
| "srgb"
|
|
373
|
+
| "srgb-linear"
|
|
374
|
+
| "display-p3"
|
|
375
|
+
| "rec2020"
|
|
376
|
+
| "a98"
|
|
377
|
+
| "prophoto"
|
|
378
|
+
| "xyz"
|
|
379
|
+
| "xyz-d65"
|
|
380
|
+
| "xyz-d50";
|
|
381
|
+
|
|
382
|
+
export interface FormatOptions {
|
|
383
|
+
format?: FormatName;
|
|
384
|
+
precision?: number;
|
|
385
|
+
space?: ColorFunctionSpaceId;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
export interface NameResult {
|
|
389
|
+
name: string;
|
|
390
|
+
hex: string;
|
|
391
|
+
deltaE: number;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
export interface CheckPaletteOptions {
|
|
395
|
+
cvd?: CVDType | null;
|
|
396
|
+
severity?: number;
|
|
397
|
+
minDeltaE?: number;
|
|
398
|
+
mode?: DeltaEMode;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
export interface PalettePair {
|
|
402
|
+
i: number;
|
|
403
|
+
j: number;
|
|
404
|
+
deltaE: number;
|
|
405
|
+
safe: boolean;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
export interface PaletteReport {
|
|
409
|
+
pairs: PalettePair[];
|
|
410
|
+
unsafe: PalettePair[];
|
|
411
|
+
minDeltaE: number;
|
|
412
|
+
safe: boolean;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
export interface NearestDistinguishableOptions extends CheckPaletteOptions {
|
|
416
|
+
step?: number;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
export interface MostReadableOptions extends IsReadableOptions {
|
|
420
|
+
includeFallback?: boolean;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
export interface RandomRange {
|
|
424
|
+
hue?: number | [number, number];
|
|
425
|
+
lightness?: number | [number, number];
|
|
426
|
+
chroma?: number | [number, number];
|
|
427
|
+
saturation?: number | [number, number];
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
export interface RandomOptions extends RandomRange {
|
|
431
|
+
space?: "oklch" | "hsl";
|
|
432
|
+
seed?: number;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
export interface CubehelixOptions {
|
|
436
|
+
start?: number;
|
|
437
|
+
rotations?: number;
|
|
438
|
+
hue?: number;
|
|
439
|
+
gamma?: number;
|
|
440
|
+
lightness?: [number, number];
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// ─── Scale ────────────────────────────────────────────────────────────
|
|
444
|
+
|
|
445
|
+
export interface Scale {
|
|
446
|
+
(t: number): Swatch;
|
|
447
|
+
colors(n: number): Swatch[];
|
|
448
|
+
colors(n: number, format: FormatName): string[];
|
|
449
|
+
domain(): [number, number];
|
|
450
|
+
domain(d: [number, number]): Scale;
|
|
451
|
+
classes(): number[] | null;
|
|
452
|
+
classes(n: number | number[] | null): Scale;
|
|
453
|
+
padding(): [number, number];
|
|
454
|
+
padding(p: number | [number, number]): Scale;
|
|
455
|
+
gamma(): number;
|
|
456
|
+
gamma(g: number): Scale;
|
|
457
|
+
mode(): SpaceId;
|
|
458
|
+
mode(space: SpaceId): Scale;
|
|
459
|
+
correctLightness(enable?: boolean): Scale;
|
|
460
|
+
cache(): boolean;
|
|
461
|
+
cache(on: boolean): Scale;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// ─── Swatch class ─────────────────────────────────────────────────────
|
|
465
|
+
|
|
466
|
+
export interface Swatch {
|
|
467
|
+
readonly space: SpaceId;
|
|
468
|
+
readonly alpha: number;
|
|
469
|
+
readonly coords: [number, number, number];
|
|
470
|
+
|
|
471
|
+
// Per-space getters.
|
|
472
|
+
readonly srgb: SrgbChannels;
|
|
473
|
+
readonly linearSrgb: SrgbChannels;
|
|
474
|
+
readonly xyz: XyzChannels;
|
|
475
|
+
readonly lab: LabChannels;
|
|
476
|
+
readonly lch: LchChannels;
|
|
477
|
+
readonly oklab: LabChannels;
|
|
478
|
+
readonly oklch: LchChannels;
|
|
479
|
+
readonly hsl: HslChannels;
|
|
480
|
+
readonly hsv: HsvChannels;
|
|
481
|
+
readonly hwb: HwbChannels;
|
|
482
|
+
readonly cmyk: CmykChannels;
|
|
483
|
+
readonly hsluv: HsluvChannels;
|
|
484
|
+
readonly luv: LuvChannels;
|
|
485
|
+
readonly displayP3: SrgbChannels;
|
|
486
|
+
readonly rec2020: SrgbChannels;
|
|
487
|
+
readonly a98: SrgbChannels;
|
|
488
|
+
readonly prophoto: SrgbChannels;
|
|
489
|
+
|
|
490
|
+
// Core plumbing.
|
|
491
|
+
to(space: SpaceId): Swatch;
|
|
492
|
+
clone(): Swatch;
|
|
493
|
+
equals(other: ColorInput, epsilon?: number): boolean;
|
|
494
|
+
equals(other: ColorInput, opts?: EqualsOptions): boolean;
|
|
495
|
+
toJSON(): { space: SpaceId; coords: [number, number, number]; alpha: number };
|
|
496
|
+
toString(opts?: FormatOptions): string;
|
|
497
|
+
toCss(opts?: FormatOptions): string;
|
|
498
|
+
css(opts?: FormatOptions): string;
|
|
499
|
+
hex(opts?: boolean | HexOptions): string;
|
|
500
|
+
rgb(opts?: boolean | RgbOptions): LegacyRgbInput;
|
|
501
|
+
|
|
502
|
+
// Channel get/set.
|
|
503
|
+
get(path: ChannelPath): number;
|
|
504
|
+
set(path: ChannelPath, value: number): Swatch;
|
|
505
|
+
|
|
506
|
+
// Gamut.
|
|
507
|
+
/** Smallest standard RGB gamut containing this color (srgb ⊂ display-p3 ⊂ rec2020 ⊂ prophoto), or null if outside all of them. */
|
|
508
|
+
readonly gamut: SpaceId | null;
|
|
509
|
+
inGamut(space?: SpaceId, opts?: { epsilon?: number }): boolean;
|
|
510
|
+
toGamut(opts?: GamutOptions): Swatch;
|
|
511
|
+
|
|
512
|
+
// Manipulation (OKLCh-based).
|
|
513
|
+
lighten(amount?: number, opts?: ManipulationOptions): Swatch;
|
|
514
|
+
darken(amount?: number, opts?: ManipulationOptions): Swatch;
|
|
515
|
+
saturate(amount?: number, opts?: ManipulationOptions): Swatch;
|
|
516
|
+
desaturate(amount?: number, opts?: ManipulationOptions): Swatch;
|
|
517
|
+
spin(degrees: number, opts?: ManipulationOptions): Swatch;
|
|
518
|
+
greyscale(opts?: ManipulationOptions): Swatch;
|
|
519
|
+
complement(opts?: ManipulationOptions): Swatch;
|
|
520
|
+
invert(): Swatch;
|
|
521
|
+
|
|
522
|
+
// Tint/shade/tone.
|
|
523
|
+
tint(amount?: number): Swatch;
|
|
524
|
+
shade(amount?: number): Swatch;
|
|
525
|
+
tone(amount?: number): Swatch;
|
|
526
|
+
|
|
527
|
+
// Mix / blend.
|
|
528
|
+
mix(other: ColorInput, amount?: number, opts?: MixOptions): Swatch;
|
|
529
|
+
blend(other: ColorInput, mode: BlendMode): Swatch;
|
|
530
|
+
|
|
531
|
+
// ΔE / naming.
|
|
532
|
+
deltaE(other: ColorInput, mode?: DeltaEMode, opts?: DeltaECmcOptions): number;
|
|
533
|
+
name(): NameResult;
|
|
534
|
+
toName(): string;
|
|
535
|
+
|
|
536
|
+
// Temperature (inverse).
|
|
537
|
+
temperature(): number;
|
|
538
|
+
|
|
539
|
+
// Accessibility.
|
|
540
|
+
luminance(): number;
|
|
541
|
+
contrast(other: ColorInput): number;
|
|
542
|
+
isReadable(other: ColorInput, opts?: IsReadableOptions): boolean;
|
|
543
|
+
ensureContrast(other: ColorInput, opts?: EnsureContrastOptions): Swatch;
|
|
544
|
+
apcaContrast(background: ColorInput): number;
|
|
545
|
+
|
|
546
|
+
// CVD.
|
|
547
|
+
simulate(type: CVDType, opts?: SimulateOptions): Swatch;
|
|
548
|
+
daltonize(
|
|
549
|
+
type: Exclude<CVDType, "achroma" | "achromatopsia">,
|
|
550
|
+
opts?: DaltonizeOptions
|
|
551
|
+
): Swatch;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// ─── Factory / statics ────────────────────────────────────────────────
|
|
555
|
+
|
|
556
|
+
export interface SwatchFactory {
|
|
557
|
+
(input: ColorInput): Swatch;
|
|
558
|
+
|
|
559
|
+
// Safe parsing.
|
|
560
|
+
"try"(input: unknown): Swatch | null;
|
|
561
|
+
isColor(input: unknown): input is ColorInput;
|
|
562
|
+
|
|
563
|
+
// String constants for autocomplete-friendly call sites.
|
|
564
|
+
readonly spaces: SpaceConstants;
|
|
565
|
+
readonly cvd: CvdConstants;
|
|
566
|
+
|
|
567
|
+
// Temperature.
|
|
568
|
+
temperature(kelvin: number): Swatch;
|
|
569
|
+
|
|
570
|
+
// Random.
|
|
571
|
+
random(opts?: RandomOptions): Swatch;
|
|
572
|
+
|
|
573
|
+
// Accessibility.
|
|
574
|
+
contrast(a: ColorInput, b: ColorInput): number;
|
|
575
|
+
isReadable(a: ColorInput, b: ColorInput, opts?: IsReadableOptions): boolean;
|
|
576
|
+
ensureContrast(
|
|
577
|
+
a: ColorInput,
|
|
578
|
+
b: ColorInput,
|
|
579
|
+
opts?: EnsureContrastOptions
|
|
580
|
+
): Swatch;
|
|
581
|
+
apcaContrast(text: ColorInput, background: ColorInput): number;
|
|
582
|
+
|
|
583
|
+
// CVD.
|
|
584
|
+
simulate(c: ColorInput, type: CVDType, opts?: SimulateOptions): Swatch;
|
|
585
|
+
daltonize(
|
|
586
|
+
c: ColorInput,
|
|
587
|
+
type: Exclude<CVDType, "achroma" | "achromatopsia">,
|
|
588
|
+
opts?: DaltonizeOptions
|
|
589
|
+
): Swatch;
|
|
590
|
+
simulateImageData<T extends ImageDataLike>(
|
|
591
|
+
imageData: T,
|
|
592
|
+
type: CVDType,
|
|
593
|
+
opts?: ImageDataTransformOptions & { inPlace?: true }
|
|
594
|
+
): T;
|
|
595
|
+
simulateImageData(
|
|
596
|
+
imageData: ImageDataLike,
|
|
597
|
+
type: CVDType,
|
|
598
|
+
opts: ImageDataTransformOptions & { inPlace: false }
|
|
599
|
+
): ImageDataLike;
|
|
600
|
+
daltonizeImageData<T extends ImageDataLike>(
|
|
601
|
+
imageData: T,
|
|
602
|
+
type: Exclude<CVDType, "achroma" | "achromatopsia">,
|
|
603
|
+
opts?: ImageDataTransformOptions & { inPlace?: true }
|
|
604
|
+
): T;
|
|
605
|
+
daltonizeImageData(
|
|
606
|
+
imageData: ImageDataLike,
|
|
607
|
+
type: Exclude<CVDType, "achroma" | "achromatopsia">,
|
|
608
|
+
opts: ImageDataTransformOptions & { inPlace: false }
|
|
609
|
+
): ImageDataLike;
|
|
610
|
+
readonly image: ImageApi;
|
|
611
|
+
|
|
612
|
+
// Palette helpers.
|
|
613
|
+
checkPalette(
|
|
614
|
+
palette: ColorInput[],
|
|
615
|
+
opts?: CheckPaletteOptions
|
|
616
|
+
): PaletteReport;
|
|
617
|
+
nearestDistinguishable(
|
|
618
|
+
target: ColorInput,
|
|
619
|
+
against: ColorInput,
|
|
620
|
+
opts?: NearestDistinguishableOptions
|
|
621
|
+
): Swatch;
|
|
622
|
+
mostReadable(
|
|
623
|
+
background: ColorInput,
|
|
624
|
+
candidates: ColorInput[],
|
|
625
|
+
opts?: MostReadableOptions
|
|
626
|
+
): Swatch;
|
|
627
|
+
|
|
628
|
+
// Scales.
|
|
629
|
+
scale(stops: ColorInput[] | ((t: number) => Swatch) | string): Scale;
|
|
630
|
+
bezier(colors: ColorInput[]): (t: number) => Swatch;
|
|
631
|
+
cubehelix(opts?: CubehelixOptions): (t: number) => Swatch;
|
|
632
|
+
palettes(): string[];
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
declare const swatch: SwatchFactory;
|
|
636
|
+
export default swatch;
|
|
637
|
+
export { swatch };
|
|
638
|
+
|
|
639
|
+
// ─── Named re-exports of the factory statics ──────────────────────────
|
|
640
|
+
//
|
|
641
|
+
// import { scale, contrast, spaces } from "@luntta/swatch";
|
|
642
|
+
//
|
|
643
|
+
// `swatch.try` stays on the factory only (`try` is a reserved word).
|
|
644
|
+
export const temperature: SwatchFactory["temperature"];
|
|
645
|
+
export const random: SwatchFactory["random"];
|
|
646
|
+
export const contrast: SwatchFactory["contrast"];
|
|
647
|
+
export const isReadable: SwatchFactory["isReadable"];
|
|
648
|
+
export const ensureContrast: SwatchFactory["ensureContrast"];
|
|
649
|
+
export const apcaContrast: SwatchFactory["apcaContrast"];
|
|
650
|
+
export const simulate: SwatchFactory["simulate"];
|
|
651
|
+
export const daltonize: SwatchFactory["daltonize"];
|
|
652
|
+
export const simulateImageData: SwatchFactory["simulateImageData"];
|
|
653
|
+
export const daltonizeImageData: SwatchFactory["daltonizeImageData"];
|
|
654
|
+
export const image: SwatchFactory["image"];
|
|
655
|
+
export const checkPalette: SwatchFactory["checkPalette"];
|
|
656
|
+
export const nearestDistinguishable: SwatchFactory["nearestDistinguishable"];
|
|
657
|
+
export const mostReadable: SwatchFactory["mostReadable"];
|
|
658
|
+
export const scale: SwatchFactory["scale"];
|
|
659
|
+
export const bezier: SwatchFactory["bezier"];
|
|
660
|
+
export const cubehelix: SwatchFactory["cubehelix"];
|
|
661
|
+
export const palettes: SwatchFactory["palettes"];
|
|
662
|
+
export const isColor: SwatchFactory["isColor"];
|
|
663
|
+
export const spaces: SwatchFactory["spaces"];
|
|
664
|
+
export const cvd: SwatchFactory["cvd"];
|