@kastov/uuid-color 0.0.2 → 0.1.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/lib/index.d.ts +25 -1
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +108 -80
- package/lib/index.js.map +1 -0
- package/package.json +21 -13
- package/src/index.ts +202 -0
- package/.prettierrc +0 -21
package/lib/index.d.ts
CHANGED
|
@@ -42,7 +42,7 @@ export interface Options {
|
|
|
42
42
|
* Attach callbacks to {@link SupportedColorNotations | supported color notations} as keys that will be called with the corresponding generated color components or code. Eliminates the need to parse the returned string if further manipulation is desired.
|
|
43
43
|
*
|
|
44
44
|
* @remarks
|
|
45
|
-
* Does not affect the return value of
|
|
45
|
+
* Does not affect the return value of the color generation functions.
|
|
46
46
|
*
|
|
47
47
|
* @see {@link Receivers | the Receivers type}
|
|
48
48
|
*/
|
|
@@ -61,4 +61,28 @@ export interface Options {
|
|
|
61
61
|
* @public
|
|
62
62
|
*/
|
|
63
63
|
export declare function colorFromUuid(uuid: string, options?: Options): string;
|
|
64
|
+
/**
|
|
65
|
+
* Returns the generated color associated with the given numeric id.
|
|
66
|
+
*
|
|
67
|
+
* @remarks
|
|
68
|
+
* Unlike {@link colorFromUuid | colorFromUuid}, whose input bits are already uniformly
|
|
69
|
+
* distributed, numeric ids are typically sequential. The id is therefore run through a
|
|
70
|
+
* SplitMix64 bit-mixer so that consecutive ids (e.g. `1`, `2`, `3`) map to well-separated,
|
|
71
|
+
* visually distinct colors instead of near-identical ones. The mapping is deterministic:
|
|
72
|
+
* the same id always yields the same color.
|
|
73
|
+
*
|
|
74
|
+
* The id must be a non-negative integer. `number` inputs are subject to the usual
|
|
75
|
+
* `Number.MAX_SAFE_INTEGER` limit; pass a `bigint` for larger ids.
|
|
76
|
+
*
|
|
77
|
+
* @param id - The numeric id (a `number` or `bigint`) for which to generate a color
|
|
78
|
+
* @param options - An optional object to configure the color generation, and attach callbacks that directly receive the generated color code or components in various formats
|
|
79
|
+
* @returns The generated color as a CSS `<color>` notation string
|
|
80
|
+
*
|
|
81
|
+
* @throws {@link https://developer.mozilla.org/en-US/docs/web/javascript/reference/global_objects/error | Error}
|
|
82
|
+
* This exception is thrown if the input id is not a non-negative integer.
|
|
83
|
+
*
|
|
84
|
+
* @public
|
|
85
|
+
*/
|
|
86
|
+
export declare function colorFromId(id: number | bigint, options?: Options): string;
|
|
64
87
|
export {};
|
|
88
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,KAAK,uBAAuB,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;AAErD,KAAK,SAAS,GAAG;IACb,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACzE,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACtF,CAAC;AAEF,MAAM,WAAW,OAAO;IACpB;;;;;;;OAOG;IACH,GAAG,CAAC,EAAE,OAAO,CAAC;IAEd;;;;;;;;OAQG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,EAAE,uBAAuB,CAAC;IAEjC;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;CACzB;AA4FD;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,OAAY,GAAG,MAAM,CAEzE;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,OAAO,GAAE,OAAY,GAAG,MAAM,CAe9E"}
|
package/lib/index.js
CHANGED
|
@@ -1,57 +1,43 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
8
|
-
}
|
|
9
|
-
return to.concat(ar || Array.prototype.slice.call(from));
|
|
10
|
-
};
|
|
11
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.colorFromUuid = colorFromUuid;
|
|
13
|
-
var convert = require("color-convert");
|
|
14
|
-
var DEFAULT_COLOR_FORMAT = 'hex';
|
|
15
|
-
var DEFAULT_IS_RAW = false;
|
|
1
|
+
import convert from 'color-convert';
|
|
2
|
+
const DEFAULT_COLOR_FORMAT = 'hex';
|
|
3
|
+
const DEFAULT_IS_RAW = false;
|
|
4
|
+
const U64_MASK = 0xffffffffffffffffn;
|
|
5
|
+
const MIX_C1 = 0xbf58476d1ce4e5b9n;
|
|
6
|
+
const MIX_C2 = 0x94d049bb133111ebn;
|
|
16
7
|
function uuidToBigInt(uuid) {
|
|
17
8
|
return BigInt('0x' + uuid.replace(/-/g, ''));
|
|
18
9
|
}
|
|
19
10
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* @param options - An optional object to configure the color generation, and attach callbacks that directly receive the generated color code or components in various formats
|
|
24
|
-
* @returns The generated color as a CSS `<color>` notation string
|
|
25
|
-
*
|
|
26
|
-
* @throws {@link https://developer.mozilla.org/en-US/docs/web/javascript/reference/global_objects/error | Error}
|
|
27
|
-
* This exception is thrown if the input uuid string is not a valid UUID.
|
|
28
|
-
*
|
|
29
|
-
* @public
|
|
11
|
+
* Mixes a non-negative integer into a well-distributed 64-bit value using the
|
|
12
|
+
* SplitMix64 finalizer, so that sequential ids (1, 2, 3, …) map to colors that
|
|
13
|
+
* are far apart rather than nearly identical.
|
|
30
14
|
*/
|
|
31
|
-
function
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
15
|
+
function mixId(id) {
|
|
16
|
+
let z = id & U64_MASK;
|
|
17
|
+
z = ((z ^ (z >> 30n)) * MIX_C1) & U64_MASK;
|
|
18
|
+
z = ((z ^ (z >> 27n)) * MIX_C2) & U64_MASK;
|
|
19
|
+
z = z ^ (z >> 31n);
|
|
20
|
+
return z & U64_MASK;
|
|
21
|
+
}
|
|
22
|
+
/** Converts a clamped alpha value in [0; 1] to its hexadecimal channel representation. */
|
|
23
|
+
function alphaToHex(alpha) {
|
|
24
|
+
return Math.floor(alpha * 255).toString(16);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Returns the generated color associated with the given encoded value by taking
|
|
28
|
+
* its lowest 24 bits as the RGB channels and formatting them per {@link Options}.
|
|
29
|
+
*/
|
|
30
|
+
function colorFromBigInt(encoded, options) {
|
|
31
|
+
const colorCode = Number(encoded % 0x1000000n);
|
|
32
|
+
const red = colorCode >> 16;
|
|
33
|
+
const green = (colorCode >> 8) & 0xff;
|
|
34
|
+
const blue = colorCode & 0xff;
|
|
35
|
+
const isRaw = options.raw ?? DEFAULT_IS_RAW;
|
|
36
|
+
// clamp to [0; 1]
|
|
37
|
+
const alpha = options.alpha === undefined ? undefined : Math.min(Math.max(options.alpha, 0), 1);
|
|
38
|
+
const toHsl = () => isRaw ? convert.rgb.hsl.raw(red, green, blue) : convert.rgb.hsl(red, green, blue);
|
|
39
|
+
const receivers = options.receivers;
|
|
40
|
+
if (receivers?.rgb) {
|
|
55
41
|
if (alpha === undefined) {
|
|
56
42
|
receivers.rgb(red, green, blue);
|
|
57
43
|
}
|
|
@@ -59,47 +45,89 @@ function colorFromUuid(uuid, options) {
|
|
|
59
45
|
receivers.rgb(red, green, blue, alpha);
|
|
60
46
|
}
|
|
61
47
|
}
|
|
62
|
-
if (
|
|
63
|
-
|
|
64
|
-
? convert.default.rgb.hsl.raw(red, green, blue)
|
|
65
|
-
: convert.default.rgb.hsl(red, green, blue);
|
|
66
|
-
if (alpha === undefined) {
|
|
67
|
-
receivers.hsl.apply(receivers, hsl);
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
receivers.hsl.apply(receivers, __spreadArray(__spreadArray([], hsl, true), [alpha], false));
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
if ('hex' in receivers) {
|
|
74
|
-
var hexColorCode = convert.default.rgb.hex(red, green, blue).toLowerCase();
|
|
48
|
+
if (receivers?.hsl) {
|
|
49
|
+
const [hue, saturation, lightness] = toHsl();
|
|
75
50
|
if (alpha === undefined) {
|
|
76
|
-
receivers.
|
|
51
|
+
receivers.hsl(hue, saturation, lightness);
|
|
77
52
|
}
|
|
78
53
|
else {
|
|
79
|
-
|
|
80
|
-
receivers.hex(hexColorCode + hexAlphaCode);
|
|
54
|
+
receivers.hsl(hue, saturation, lightness, alpha);
|
|
81
55
|
}
|
|
82
56
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
57
|
+
if (receivers?.hex) {
|
|
58
|
+
const hexColorCode = convert.rgb.hex(red, green, blue).toLowerCase();
|
|
59
|
+
receivers.hex(alpha === undefined ? hexColorCode : hexColorCode + alphaToHex(alpha));
|
|
86
60
|
}
|
|
61
|
+
const format = options.format ?? DEFAULT_COLOR_FORMAT;
|
|
87
62
|
switch (format) {
|
|
88
63
|
case 'rgb':
|
|
89
64
|
return alpha === undefined
|
|
90
|
-
?
|
|
91
|
-
:
|
|
92
|
-
case 'hsl':
|
|
93
|
-
|
|
94
|
-
? convert.default.rgb.hsl.raw(red, green, blue)
|
|
95
|
-
: convert.default.rgb.hsl(red, green, blue);
|
|
65
|
+
? `rgb(${red}, ${green}, ${blue})`
|
|
66
|
+
: `rgb(${red}, ${green}, ${blue}, ${alpha})`;
|
|
67
|
+
case 'hsl': {
|
|
68
|
+
const [hue, saturation, lightness] = toHsl();
|
|
96
69
|
return alpha === undefined
|
|
97
|
-
?
|
|
98
|
-
:
|
|
99
|
-
|
|
70
|
+
? `hsl(${hue}, ${saturation}%, ${lightness}%)`
|
|
71
|
+
: `hsl(${hue}, ${saturation}%, ${lightness}%, ${alpha})`;
|
|
72
|
+
}
|
|
100
73
|
case 'hex':
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
return alpha === undefined ?
|
|
74
|
+
default: {
|
|
75
|
+
const hexColorCode = convert.rgb.hex(red, green, blue).toLowerCase();
|
|
76
|
+
return alpha === undefined ? `#${hexColorCode}` : `#${hexColorCode}${alphaToHex(alpha)}`;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Returns the generated color associated with the given uuid.
|
|
82
|
+
*
|
|
83
|
+
* @param uuid - The uuid for which to generate a color
|
|
84
|
+
* @param options - An optional object to configure the color generation, and attach callbacks that directly receive the generated color code or components in various formats
|
|
85
|
+
* @returns The generated color as a CSS `<color>` notation string
|
|
86
|
+
*
|
|
87
|
+
* @throws {@link https://developer.mozilla.org/en-US/docs/web/javascript/reference/global_objects/error | Error}
|
|
88
|
+
* This exception is thrown if the input uuid string is not a valid UUID.
|
|
89
|
+
*
|
|
90
|
+
* @public
|
|
91
|
+
*/
|
|
92
|
+
export function colorFromUuid(uuid, options = {}) {
|
|
93
|
+
return colorFromBigInt(uuidToBigInt(uuid), options);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Returns the generated color associated with the given numeric id.
|
|
97
|
+
*
|
|
98
|
+
* @remarks
|
|
99
|
+
* Unlike {@link colorFromUuid | colorFromUuid}, whose input bits are already uniformly
|
|
100
|
+
* distributed, numeric ids are typically sequential. The id is therefore run through a
|
|
101
|
+
* SplitMix64 bit-mixer so that consecutive ids (e.g. `1`, `2`, `3`) map to well-separated,
|
|
102
|
+
* visually distinct colors instead of near-identical ones. The mapping is deterministic:
|
|
103
|
+
* the same id always yields the same color.
|
|
104
|
+
*
|
|
105
|
+
* The id must be a non-negative integer. `number` inputs are subject to the usual
|
|
106
|
+
* `Number.MAX_SAFE_INTEGER` limit; pass a `bigint` for larger ids.
|
|
107
|
+
*
|
|
108
|
+
* @param id - The numeric id (a `number` or `bigint`) for which to generate a color
|
|
109
|
+
* @param options - An optional object to configure the color generation, and attach callbacks that directly receive the generated color code or components in various formats
|
|
110
|
+
* @returns The generated color as a CSS `<color>` notation string
|
|
111
|
+
*
|
|
112
|
+
* @throws {@link https://developer.mozilla.org/en-US/docs/web/javascript/reference/global_objects/error | Error}
|
|
113
|
+
* This exception is thrown if the input id is not a non-negative integer.
|
|
114
|
+
*
|
|
115
|
+
* @public
|
|
116
|
+
*/
|
|
117
|
+
export function colorFromId(id, options = {}) {
|
|
118
|
+
let encoded;
|
|
119
|
+
if (typeof id === 'bigint') {
|
|
120
|
+
encoded = id;
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
if (!Number.isInteger(id)) {
|
|
124
|
+
throw new Error(`Invalid id: expected an integer, received ${id}`);
|
|
125
|
+
}
|
|
126
|
+
encoded = BigInt(id);
|
|
127
|
+
}
|
|
128
|
+
if (encoded < 0n) {
|
|
129
|
+
throw new Error(`Invalid id: expected a non-negative integer, received ${id}`);
|
|
104
130
|
}
|
|
131
|
+
return colorFromBigInt(mixId(encoded), options);
|
|
105
132
|
}
|
|
133
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,24 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kastov/uuid-color",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"description": "A lightweight package to generate unique and uniformly sampled colors from UUIDs.",
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A lightweight package to generate unique and uniformly sampled colors from UUIDs and numeric ids.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./lib/index.js",
|
|
7
|
+
"types": "./lib/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./lib/index.d.ts",
|
|
11
|
+
"default": "./lib/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"lib",
|
|
16
|
+
"src"
|
|
17
|
+
],
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=24"
|
|
20
|
+
},
|
|
6
21
|
"scripts": {
|
|
7
22
|
"build": "tsc",
|
|
8
|
-
"
|
|
23
|
+
"clean": "rm -rf lib",
|
|
24
|
+
"prepare": "npm run clean && tsc"
|
|
9
25
|
},
|
|
10
26
|
"repository": {
|
|
11
27
|
"type": "git",
|
|
12
28
|
"url": "git+https://github.com/kastov/uuid-color.git"
|
|
13
29
|
},
|
|
14
|
-
"keywords": [
|
|
15
|
-
"uuid",
|
|
16
|
-
"color",
|
|
17
|
-
"colour",
|
|
18
|
-
"unique",
|
|
19
|
-
"hash",
|
|
20
|
-
"uuid-v4"
|
|
21
|
-
],
|
|
22
30
|
"author": "Louca Dufault",
|
|
23
31
|
"license": "ISC",
|
|
24
32
|
"bugs": {
|
|
@@ -32,4 +40,4 @@
|
|
|
32
40
|
"color-convert": "^3.1.3"
|
|
33
41
|
},
|
|
34
42
|
"sideEffects": false
|
|
35
|
-
}
|
|
43
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import convert from 'color-convert';
|
|
2
|
+
|
|
3
|
+
type SupportedColorNotations = 'hex' | 'rgb' | 'hsl';
|
|
4
|
+
|
|
5
|
+
type Receivers = {
|
|
6
|
+
hex?: (hexString: string) => void;
|
|
7
|
+
rgb?: (red: number, green: number, blue: number, alpha?: number) => void;
|
|
8
|
+
hsl?: (hue: number, saturation: number, lightness: number, alpha?: number) => void;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export interface Options {
|
|
12
|
+
/**
|
|
13
|
+
* Determines whether to skip rounding the generated color components.
|
|
14
|
+
*
|
|
15
|
+
* @remarks
|
|
16
|
+
* Only applies when the specified format is `"hsl"`, as this is the only output format that involves a lossy conversion (from RGB model components).
|
|
17
|
+
*
|
|
18
|
+
* @defaultValue `false`
|
|
19
|
+
*/
|
|
20
|
+
raw?: boolean;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Determines the alpha of the generated color as a number between 0 and 1. Passed through to the final generated color without any involvement in the generation process.
|
|
24
|
+
*
|
|
25
|
+
* @remarks
|
|
26
|
+
* Specifying any value (even if it is equal to or greater than 1) will cause the function to return the generated color as a notation string including the alpha component (see the alpha variants in {@link Options.format | Options.format}), and cause the alpha to be included in the parameter(s) of the call to the supplied {@link Receivers} value(s).
|
|
27
|
+
* Values are not validated, but are clamped to between 0 and 1.
|
|
28
|
+
*
|
|
29
|
+
* @defaultValue `1`
|
|
30
|
+
*/
|
|
31
|
+
alpha?: number;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Determines the output format of the generated color.
|
|
35
|
+
*
|
|
36
|
+
* hex: #rrggbb[aa]
|
|
37
|
+
* rgb: rgb[a](R, G, B[, A])
|
|
38
|
+
* hsl: hsl[a](H, S, L[, A])
|
|
39
|
+
* @see { @link https://developer.mozilla.org/en-US/docs/Web/CSS/color_value | \<color\> }
|
|
40
|
+
*
|
|
41
|
+
* @remarks
|
|
42
|
+
* Colors are returned as strings in the CSS <color> data type hexadecimal or comma-separated functional notation corresponding to the specified format.
|
|
43
|
+
*
|
|
44
|
+
* @defaultValue `"hex"`
|
|
45
|
+
*/
|
|
46
|
+
format?: SupportedColorNotations;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Attach callbacks to {@link SupportedColorNotations | supported color notations} as keys that will be called with the corresponding generated color components or code. Eliminates the need to parse the returned string if further manipulation is desired.
|
|
50
|
+
*
|
|
51
|
+
* @remarks
|
|
52
|
+
* Does not affect the return value of the color generation functions.
|
|
53
|
+
*
|
|
54
|
+
* @see {@link Receivers | the Receivers type}
|
|
55
|
+
*/
|
|
56
|
+
receivers?: Receivers;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const DEFAULT_COLOR_FORMAT: SupportedColorNotations = 'hex';
|
|
60
|
+
const DEFAULT_IS_RAW = false;
|
|
61
|
+
|
|
62
|
+
const U64_MASK = 0xffffffffffffffffn;
|
|
63
|
+
const MIX_C1 = 0xbf58476d1ce4e5b9n;
|
|
64
|
+
const MIX_C2 = 0x94d049bb133111ebn;
|
|
65
|
+
|
|
66
|
+
function uuidToBigInt(uuid: string): bigint {
|
|
67
|
+
return BigInt('0x' + uuid.replace(/-/g, ''));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Mixes a non-negative integer into a well-distributed 64-bit value using the
|
|
72
|
+
* SplitMix64 finalizer, so that sequential ids (1, 2, 3, …) map to colors that
|
|
73
|
+
* are far apart rather than nearly identical.
|
|
74
|
+
*/
|
|
75
|
+
function mixId(id: bigint): bigint {
|
|
76
|
+
let z = id & U64_MASK;
|
|
77
|
+
z = ((z ^ (z >> 30n)) * MIX_C1) & U64_MASK;
|
|
78
|
+
z = ((z ^ (z >> 27n)) * MIX_C2) & U64_MASK;
|
|
79
|
+
z = z ^ (z >> 31n);
|
|
80
|
+
return z & U64_MASK;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Converts a clamped alpha value in [0; 1] to its hexadecimal channel representation. */
|
|
84
|
+
function alphaToHex(alpha: number): string {
|
|
85
|
+
return Math.floor(alpha * 255).toString(16);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Returns the generated color associated with the given encoded value by taking
|
|
90
|
+
* its lowest 24 bits as the RGB channels and formatting them per {@link Options}.
|
|
91
|
+
*/
|
|
92
|
+
function colorFromBigInt(encoded: bigint, options: Options): string {
|
|
93
|
+
const colorCode = Number(encoded % 0x1000000n);
|
|
94
|
+
const red = colorCode >> 16;
|
|
95
|
+
const green = (colorCode >> 8) & 0xff;
|
|
96
|
+
const blue = colorCode & 0xff;
|
|
97
|
+
|
|
98
|
+
const isRaw = options.raw ?? DEFAULT_IS_RAW;
|
|
99
|
+
|
|
100
|
+
// clamp to [0; 1]
|
|
101
|
+
const alpha =
|
|
102
|
+
options.alpha === undefined ? undefined : Math.min(Math.max(options.alpha, 0), 1);
|
|
103
|
+
|
|
104
|
+
const toHsl = () =>
|
|
105
|
+
isRaw ? convert.rgb.hsl.raw(red, green, blue) : convert.rgb.hsl(red, green, blue);
|
|
106
|
+
|
|
107
|
+
const receivers = options.receivers;
|
|
108
|
+
if (receivers?.rgb) {
|
|
109
|
+
if (alpha === undefined) {
|
|
110
|
+
receivers.rgb(red, green, blue);
|
|
111
|
+
} else {
|
|
112
|
+
receivers.rgb(red, green, blue, alpha);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (receivers?.hsl) {
|
|
116
|
+
const [hue, saturation, lightness] = toHsl();
|
|
117
|
+
if (alpha === undefined) {
|
|
118
|
+
receivers.hsl(hue, saturation, lightness);
|
|
119
|
+
} else {
|
|
120
|
+
receivers.hsl(hue, saturation, lightness, alpha);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (receivers?.hex) {
|
|
124
|
+
const hexColorCode = convert.rgb.hex(red, green, blue).toLowerCase();
|
|
125
|
+
receivers.hex(alpha === undefined ? hexColorCode : hexColorCode + alphaToHex(alpha));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const format = options.format ?? DEFAULT_COLOR_FORMAT;
|
|
129
|
+
|
|
130
|
+
switch (format) {
|
|
131
|
+
case 'rgb':
|
|
132
|
+
return alpha === undefined
|
|
133
|
+
? `rgb(${red}, ${green}, ${blue})`
|
|
134
|
+
: `rgb(${red}, ${green}, ${blue}, ${alpha})`;
|
|
135
|
+
case 'hsl': {
|
|
136
|
+
const [hue, saturation, lightness] = toHsl();
|
|
137
|
+
return alpha === undefined
|
|
138
|
+
? `hsl(${hue}, ${saturation}%, ${lightness}%)`
|
|
139
|
+
: `hsl(${hue}, ${saturation}%, ${lightness}%, ${alpha})`;
|
|
140
|
+
}
|
|
141
|
+
case 'hex':
|
|
142
|
+
default: {
|
|
143
|
+
const hexColorCode = convert.rgb.hex(red, green, blue).toLowerCase();
|
|
144
|
+
return alpha === undefined ? `#${hexColorCode}` : `#${hexColorCode}${alphaToHex(alpha)}`;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Returns the generated color associated with the given uuid.
|
|
151
|
+
*
|
|
152
|
+
* @param uuid - The uuid for which to generate a color
|
|
153
|
+
* @param options - An optional object to configure the color generation, and attach callbacks that directly receive the generated color code or components in various formats
|
|
154
|
+
* @returns The generated color as a CSS `<color>` notation string
|
|
155
|
+
*
|
|
156
|
+
* @throws {@link https://developer.mozilla.org/en-US/docs/web/javascript/reference/global_objects/error | Error}
|
|
157
|
+
* This exception is thrown if the input uuid string is not a valid UUID.
|
|
158
|
+
*
|
|
159
|
+
* @public
|
|
160
|
+
*/
|
|
161
|
+
export function colorFromUuid(uuid: string, options: Options = {}): string {
|
|
162
|
+
return colorFromBigInt(uuidToBigInt(uuid), options);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Returns the generated color associated with the given numeric id.
|
|
167
|
+
*
|
|
168
|
+
* @remarks
|
|
169
|
+
* Unlike {@link colorFromUuid | colorFromUuid}, whose input bits are already uniformly
|
|
170
|
+
* distributed, numeric ids are typically sequential. The id is therefore run through a
|
|
171
|
+
* SplitMix64 bit-mixer so that consecutive ids (e.g. `1`, `2`, `3`) map to well-separated,
|
|
172
|
+
* visually distinct colors instead of near-identical ones. The mapping is deterministic:
|
|
173
|
+
* the same id always yields the same color.
|
|
174
|
+
*
|
|
175
|
+
* The id must be a non-negative integer. `number` inputs are subject to the usual
|
|
176
|
+
* `Number.MAX_SAFE_INTEGER` limit; pass a `bigint` for larger ids.
|
|
177
|
+
*
|
|
178
|
+
* @param id - The numeric id (a `number` or `bigint`) for which to generate a color
|
|
179
|
+
* @param options - An optional object to configure the color generation, and attach callbacks that directly receive the generated color code or components in various formats
|
|
180
|
+
* @returns The generated color as a CSS `<color>` notation string
|
|
181
|
+
*
|
|
182
|
+
* @throws {@link https://developer.mozilla.org/en-US/docs/web/javascript/reference/global_objects/error | Error}
|
|
183
|
+
* This exception is thrown if the input id is not a non-negative integer.
|
|
184
|
+
*
|
|
185
|
+
* @public
|
|
186
|
+
*/
|
|
187
|
+
export function colorFromId(id: number | bigint, options: Options = {}): string {
|
|
188
|
+
let encoded: bigint;
|
|
189
|
+
if (typeof id === 'bigint') {
|
|
190
|
+
encoded = id;
|
|
191
|
+
} else {
|
|
192
|
+
if (!Number.isInteger(id)) {
|
|
193
|
+
throw new Error(`Invalid id: expected an integer, received ${id}`);
|
|
194
|
+
}
|
|
195
|
+
encoded = BigInt(id);
|
|
196
|
+
}
|
|
197
|
+
if (encoded < 0n) {
|
|
198
|
+
throw new Error(`Invalid id: expected a non-negative integer, received ${id}`);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return colorFromBigInt(mixId(encoded), options);
|
|
202
|
+
}
|
package/.prettierrc
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"bracketSpacing": true,
|
|
3
|
-
"tabWidth": 4,
|
|
4
|
-
"printWidth": 100,
|
|
5
|
-
"singleQuote": true,
|
|
6
|
-
"trailingComma": "all",
|
|
7
|
-
"overrides": [
|
|
8
|
-
{
|
|
9
|
-
"files": ["*.js", "*.jsx", "*.ts", "*.tsx"],
|
|
10
|
-
"options": {
|
|
11
|
-
"parser": "typescript"
|
|
12
|
-
}
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
"files": ["*.md", "*.json", "*.yaml", "*.yml"],
|
|
16
|
-
"options": {
|
|
17
|
-
"tabWidth": 2
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
]
|
|
21
|
-
}
|