color-bits 1.1.0 → 1.2.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.
Files changed (83) hide show
  1. package/.claude/settings.local.json +9 -0
  2. package/README.md +30 -14
  3. package/benchmarks/compare-oklab.ts +44 -0
  4. package/benchmarks/compare-srgb.ts +59 -0
  5. package/benchmarks/compare.ts +46 -0
  6. package/benchmarks/parse.ts +41 -0
  7. package/build/conversion/channels.d.ts +61 -0
  8. package/build/conversion/channels.js +353 -0
  9. package/build/conversion/channels.js.map +1 -0
  10. package/build/{convert.d.ts → conversion/color-spaces.d.ts} +25 -23
  11. package/build/conversion/color-spaces.js +263 -0
  12. package/build/conversion/color-spaces.js.map +1 -0
  13. package/build/core/bits.d.ts +28 -0
  14. package/build/{core.js → core/bits.js} +25 -26
  15. package/build/core/bits.js.map +1 -0
  16. package/build/core/bytes.d.ts +5 -0
  17. package/build/core/bytes.js +12 -0
  18. package/build/core/bytes.js.map +1 -0
  19. package/build/css.d.ts +1 -0
  20. package/build/css.js +18 -0
  21. package/build/css.js.map +1 -0
  22. package/build/formatting/index.d.ts +27 -0
  23. package/build/{format.js → formatting/index.js} +13 -67
  24. package/build/formatting/index.js.map +1 -0
  25. package/build/index.d.ts +6 -4
  26. package/build/index.js +6 -4
  27. package/build/index.js.map +1 -1
  28. package/build/namedColors.d.ts +1 -0
  29. package/build/namedColors.js +18 -0
  30. package/build/namedColors.js.map +1 -0
  31. package/build/operations/adjust.d.ts +19 -0
  32. package/build/operations/adjust.js +40 -0
  33. package/build/operations/adjust.js.map +1 -0
  34. package/build/operations/blend.d.ts +9 -0
  35. package/build/operations/blend.js +19 -0
  36. package/build/operations/blend.js.map +1 -0
  37. package/build/operations/color-mix.d.ts +20 -0
  38. package/build/operations/color-mix.js +144 -0
  39. package/build/operations/color-mix.js.map +1 -0
  40. package/build/operations/luminance.d.ts +7 -0
  41. package/build/operations/luminance.js +20 -0
  42. package/build/operations/luminance.js.map +1 -0
  43. package/build/parsing/calc.d.ts +8 -0
  44. package/build/parsing/calc.js +205 -0
  45. package/build/parsing/calc.js.map +1 -0
  46. package/build/parsing/color-mix.d.ts +8 -0
  47. package/build/parsing/color-mix.js +70 -0
  48. package/build/parsing/color-mix.js.map +1 -0
  49. package/build/parsing/css.d.ts +23 -0
  50. package/build/parsing/css.js +115 -0
  51. package/build/parsing/css.js.map +1 -0
  52. package/build/parsing/fast.d.ts +19 -0
  53. package/build/parsing/fast.js +184 -0
  54. package/build/parsing/fast.js.map +1 -0
  55. package/build/parsing/named-colors.d.ts +12 -0
  56. package/build/parsing/named-colors.js +68 -0
  57. package/build/parsing/named-colors.js.map +1 -0
  58. package/build/parsing/relative.d.ts +9 -0
  59. package/build/parsing/relative.js +158 -0
  60. package/build/parsing/relative.js.map +1 -0
  61. package/build/parsing/tokenizer.d.ts +16 -0
  62. package/build/parsing/tokenizer.js +78 -0
  63. package/build/parsing/tokenizer.js.map +1 -0
  64. package/build/parsing/values.d.ts +41 -0
  65. package/build/parsing/values.js +139 -0
  66. package/build/parsing/values.js.map +1 -0
  67. package/package.json +30 -12
  68. package/benchmarks/index.ts +0 -35
  69. package/build/bit.d.ts +0 -3
  70. package/build/bit.js +0 -29
  71. package/build/bit.js.map +0 -1
  72. package/build/convert.js +0 -347
  73. package/build/convert.js.map +0 -1
  74. package/build/core.d.ts +0 -27
  75. package/build/core.js.map +0 -1
  76. package/build/format.d.ts +0 -27
  77. package/build/format.js.map +0 -1
  78. package/build/functions.d.ts +0 -33
  79. package/build/functions.js +0 -95
  80. package/build/functions.js.map +0 -1
  81. package/build/parse.d.ts +0 -17
  82. package/build/parse.js +0 -392
  83. package/build/parse.js.map +0 -1
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ // Nesting-aware scanner for CSS color functions. Unlike the fast-path regex in
3
+ // the fast parser, it correctly handles nested parentheses — needed for relative colors
4
+ // whose origin can be another function (`rgb(from hsl(0 100% 50%) r g b)`) and
5
+ // for `calc(...)` channel expressions — and it keeps `/` (the alpha separator)
6
+ // as its own token.
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.tokenize = tokenize;
9
+ const SPACE = 32; // ' '
10
+ const TAB = 9; // '\t'
11
+ const NEWLINE = 10; // '\n'
12
+ const RETURN = 13; // '\r'
13
+ const COMMA = 44; // ','
14
+ const SLASH = 47; // '/'
15
+ const OPEN = 40; // '('
16
+ const CLOSE = 41; // ')'
17
+ function isSeparator(c) {
18
+ return c === SPACE || c === TAB || c === NEWLINE || c === RETURN;
19
+ }
20
+ /**
21
+ * Tokenize a CSS color function string, e.g. "oklch(from green l c h / .5)".
22
+ * @returns the function name and its top-level tokens, or null if the input is
23
+ * not a function call (no parentheses).
24
+ */
25
+ function tokenize(input) {
26
+ const open = input.indexOf('(');
27
+ if (open === -1) {
28
+ return null;
29
+ }
30
+ const name = input.slice(0, open).trim().toLowerCase();
31
+ // Inner content is everything between the first '(' and the matching last ')'.
32
+ let end = input.length;
33
+ while (end > open && input.charCodeAt(end - 1) !== CLOSE) {
34
+ end--;
35
+ }
36
+ if (end <= open) {
37
+ return null; // unterminated
38
+ }
39
+ const tokens = [];
40
+ let depth = 0;
41
+ let start = -1; // start index of the current token, or -1 when between tokens
42
+ for (let i = open + 1; i < end - 1; i++) {
43
+ const c = input.charCodeAt(i);
44
+ if (depth === 0 && (isSeparator(c) || c === SLASH || c === COMMA)) {
45
+ if (start !== -1) {
46
+ tokens.push(input.slice(start, i));
47
+ start = -1;
48
+ }
49
+ if (c === SLASH) {
50
+ tokens.push('/');
51
+ }
52
+ else if (c === COMMA) {
53
+ tokens.push(',');
54
+ }
55
+ continue;
56
+ }
57
+ if (c === OPEN) {
58
+ depth++;
59
+ }
60
+ else if (c === CLOSE) {
61
+ depth--;
62
+ if (depth < 0) {
63
+ return null; // unbalanced
64
+ }
65
+ }
66
+ if (start === -1) {
67
+ start = i;
68
+ }
69
+ }
70
+ if (depth !== 0) {
71
+ return null; // unbalanced
72
+ }
73
+ if (start !== -1) {
74
+ tokens.push(input.slice(start, end - 1));
75
+ }
76
+ return { name, tokens };
77
+ }
78
+ //# sourceMappingURL=tokenizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenizer.js","sourceRoot":"","sources":["../../src/parsing/tokenizer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /** ASCII case-insensitive check for the `from` keyword of relative colors. */
2
+ export declare function isFromKeyword(token: string): boolean;
3
+ /**
4
+ * Accepts: "50%", "128", "none"
5
+ * https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/rgb#values
6
+ * @returns a value clamped to the 0 to 255 range
7
+ */
8
+ export declare function parseColorChannel(channel: string): number;
9
+ /**
10
+ * Accepts: "50%", ".5", "0.5", "none"
11
+ * https://developer.mozilla.org/en-US/docs/Web/CSS/alpha-value
12
+ * @returns a value clamped to the [0, 255] range
13
+ */
14
+ export declare function parseAlphaChannel(channel: string): number;
15
+ /**
16
+ * Accepts: "50%", ".5", "0.5", "none"
17
+ * https://developer.mozilla.org/en-US/docs/Web/CSS/alpha-value
18
+ * @returns a value in the [0, 1] range
19
+ */
20
+ export declare function parseAlphaValue(channel: string): number;
21
+ /**
22
+ * Accepts: "360", "360deg", "400grad", "6.28rad", "1turn", "none"
23
+ * https://developer.mozilla.org/en-US/docs/Web/CSS/angle
24
+ * @returns a value in degrees
25
+ */
26
+ export declare function parseAngle(angle: string): number;
27
+ /**
28
+ * Accepts: "100%", "50", "none"
29
+ * @returns the numeric value, with percentages resolved against 100 (so "50%" -> 50)
30
+ */
31
+ export declare function parsePercent(value: string): number;
32
+ /**
33
+ * Accepts: "1.0", "100%", "none"
34
+ * @returns a value in the 0.0 to 1.0 range
35
+ */
36
+ export declare function parsePercentageOrValue(value: string): number;
37
+ /**
38
+ * Accepts: "100", "100%", "none"
39
+ * @returns a raw number, with percentages resolved against @range (so "50%" -> 0.5 * range)
40
+ */
41
+ export declare function parseNumberOrPercentage(value: string, range: number): number;
@@ -0,0 +1,139 @@
1
+ "use strict";
2
+ // Primitive CSS value parsers shared by the fast and relative parsers. Kept in
3
+ // their own module so both paths use the exact same unit conventions and neither
4
+ // can drift from the other.
5
+ //
6
+ // Keyword and unit matching is ASCII case-insensitive, as CSS is: comparisons
7
+ // use `charCode | 0x20`, which lowercases A-Z and leaves digits, '.', '-', '+'
8
+ // and '%' unchanged.
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.isFromKeyword = isFromKeyword;
11
+ exports.parseColorChannel = parseColorChannel;
12
+ exports.parseAlphaChannel = parseAlphaChannel;
13
+ exports.parseAlphaValue = parseAlphaValue;
14
+ exports.parseAngle = parseAngle;
15
+ exports.parsePercent = parsePercent;
16
+ exports.parsePercentageOrValue = parsePercentageOrValue;
17
+ exports.parseNumberOrPercentage = parseNumberOrPercentage;
18
+ const bytes_1 = require("../core/bytes");
19
+ const PERCENT = 37; // '%'
20
+ const G = 103; // 'g'
21
+ const N = 110; // 'n'
22
+ const D = 100; // 'd'
23
+ const E = 101; // 'e'
24
+ /** ASCII case-insensitive check for the `from` keyword of relative colors. */
25
+ function isFromKeyword(token) {
26
+ return token.length === 4
27
+ && (token.charCodeAt(0) | 0x20) === 102 // 'f'
28
+ && (token.charCodeAt(1) | 0x20) === 114 // 'r'
29
+ && (token.charCodeAt(2) | 0x20) === 111 // 'o'
30
+ && (token.charCodeAt(3) | 0x20) === 109; // 'm'
31
+ }
32
+ /**
33
+ * Accepts: "50%", "128", "none"
34
+ * https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/rgb#values
35
+ * @returns a value clamped to the 0 to 255 range
36
+ */
37
+ function parseColorChannel(channel) {
38
+ // No explicit 'none' check: parseFloat('none') is NaN, which clampByte
39
+ // passes through and newColor packs as 0 — exactly CSS none = 0.
40
+ if (channel.charCodeAt(channel.length - 1) === PERCENT) {
41
+ return (0, bytes_1.clampByte)((parseFloat(channel) / 100) * 255);
42
+ }
43
+ return (0, bytes_1.clampByte)(parseFloat(channel));
44
+ }
45
+ /**
46
+ * Accepts: "50%", ".5", "0.5", "none"
47
+ * https://developer.mozilla.org/en-US/docs/Web/CSS/alpha-value
48
+ * @returns a value clamped to the [0, 255] range
49
+ */
50
+ function parseAlphaChannel(channel) {
51
+ return (0, bytes_1.clampByte)(parseAlphaValue(channel) * 255);
52
+ }
53
+ /**
54
+ * Accepts: "50%", ".5", "0.5", "none"
55
+ * https://developer.mozilla.org/en-US/docs/Web/CSS/alpha-value
56
+ * @returns a value in the [0, 1] range
57
+ */
58
+ function parseAlphaValue(channel) {
59
+ if ((channel.charCodeAt(0) | 0x20) === N) {
60
+ return 0;
61
+ }
62
+ if (channel.charCodeAt(channel.length - 1) === PERCENT) {
63
+ return parseFloat(channel) / 100;
64
+ }
65
+ return parseFloat(channel);
66
+ }
67
+ /**
68
+ * Accepts: "360", "360deg", "400grad", "6.28rad", "1turn", "none"
69
+ * https://developer.mozilla.org/en-US/docs/Web/CSS/angle
70
+ * @returns a value in degrees
71
+ */
72
+ function parseAngle(angle) {
73
+ let factor = 1;
74
+ switch (angle.charCodeAt(angle.length - 1) | 0x20) {
75
+ case E: {
76
+ // 'none'
77
+ return 0;
78
+ }
79
+ case D: {
80
+ // 'rad', 'grad'
81
+ if ((angle.charCodeAt(Math.max(0, angle.length - 4)) | 0x20) === G) {
82
+ // 'grad': 400grad = 360deg
83
+ factor = 360 / 400;
84
+ }
85
+ else {
86
+ // 'rad': 2π rad = 360deg
87
+ factor = 360 / (2 * Math.PI); // 360 / TAU
88
+ }
89
+ break;
90
+ }
91
+ case N: {
92
+ // 'turn': 1turn = 360deg
93
+ factor = 360;
94
+ break;
95
+ }
96
+ // case G: // 'deg', but no need to check as it's also the default
97
+ default: {
98
+ return parseFloat(angle); // degrees
99
+ }
100
+ }
101
+ return parseFloat(angle) * factor;
102
+ }
103
+ /**
104
+ * Accepts: "100%", "50", "none"
105
+ * @returns the numeric value, with percentages resolved against 100 (so "50%" -> 50)
106
+ */
107
+ function parsePercent(value) {
108
+ if ((value.charCodeAt(0) | 0x20) === N) {
109
+ return 0;
110
+ }
111
+ return parseFloat(value);
112
+ }
113
+ /**
114
+ * Accepts: "1.0", "100%", "none"
115
+ * @returns a value in the 0.0 to 1.0 range
116
+ */
117
+ function parsePercentageOrValue(value) {
118
+ if ((value.charCodeAt(0) | 0x20) === N) {
119
+ return 0;
120
+ }
121
+ if (value.charCodeAt(value.length - 1) === PERCENT) {
122
+ return parseFloat(value) / 100;
123
+ }
124
+ return parseFloat(value);
125
+ }
126
+ /**
127
+ * Accepts: "100", "100%", "none"
128
+ * @returns a raw number, with percentages resolved against @range (so "50%" -> 0.5 * range)
129
+ */
130
+ function parseNumberOrPercentage(value, range) {
131
+ if ((value.charCodeAt(0) | 0x20) === N) {
132
+ return 0;
133
+ }
134
+ if (value.charCodeAt(value.length - 1) === PERCENT) {
135
+ return (parseFloat(value) / 100) * range;
136
+ }
137
+ return parseFloat(value);
138
+ }
139
+ //# sourceMappingURL=values.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"values.js","sourceRoot":"","sources":["../../src/parsing/values.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,12 +1,37 @@
1
1
  {
2
2
  "name": "color-bits",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "main": "./build/index.js",
5
5
  "sideEffects": false,
6
+ "homepage": "https://github.com/romgrk/color-bits",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/romgrk/color-bits.git"
10
+ },
11
+ "scripts": {
12
+ "prepack": "pnpm run build && npmignore --auto",
13
+ "build": "tsc",
14
+ "start": "tsc --watch",
15
+ "docs": "pnpm run docs:core && pnpm run docs:string",
16
+ "docs:core": "typedoc --readme none --plugin typedoc-plugin-markdown --out ./docs ./src/index.ts",
17
+ "docs:string": "typedoc --readme none --plugin typedoc-plugin-markdown --out ./docs/string ./src/string.ts",
18
+ "benchmark": "pnpm run benchmark:srgb",
19
+ "benchmark:srgb": "tsx ./benchmarks/compare-srgb.ts",
20
+ "benchmark:oklab": "tsx ./benchmarks/compare-oklab.ts",
21
+ "test": "NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" jest --watch"
22
+ },
6
23
  "exports": {
7
24
  ".": "./build/index.js",
8
25
  "./*": "./build/*",
9
- "./string": "./build/string.js"
26
+ "./string": "./build/string.js",
27
+ "./css": {
28
+ "types": "./build/css.d.ts",
29
+ "default": "./build/css.js"
30
+ },
31
+ "./named": {
32
+ "types": "./build/namedColors.d.ts",
33
+ "default": "./build/namedColors.js"
34
+ }
10
35
  },
11
36
  "types": "./build/index.d.ts",
12
37
  "keywords": [
@@ -28,6 +53,7 @@
28
53
  "@babel/preset-env": "^7.25.4",
29
54
  "@babel/preset-typescript": "^7.24.7",
30
55
  "@jest/globals": "^29.7.0",
56
+ "@texel/color": "^1.1.11",
31
57
  "@types/chai": "^4.3.19",
32
58
  "@types/jest": "^29.5.12",
33
59
  "benny": "^3.7.1",
@@ -35,6 +61,7 @@
35
61
  "chroma-js": "^3.0.0",
36
62
  "color": "^4.2.3",
37
63
  "colord": "^2.9.3",
64
+ "culori": "^4.0.2",
38
65
  "jest": "^29.7.0",
39
66
  "npmignore": "^0.3.1",
40
67
  "tinycolor2": "^1.6.0",
@@ -44,14 +71,5 @@
44
71
  "typedoc": "^0.26.6",
45
72
  "typedoc-plugin-markdown": "^4.2.6",
46
73
  "typescript": "^5.5.4"
47
- },
48
- "scripts": {
49
- "build": "tsc",
50
- "start": "tsc --watch",
51
- "docs": "pnpm run docs:core && pnpm run docs:string",
52
- "docs:core": "typedoc --readme none --plugin typedoc-plugin-markdown --out ./docs ./src/index.ts",
53
- "docs:string": "typedoc --readme none --plugin typedoc-plugin-markdown --out ./docs/string ./src/string.ts",
54
- "benchmark": "tsx ./benchmarks/index.ts",
55
- "test": "NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" jest --watch"
56
74
  }
57
- }
75
+ }
@@ -1,35 +0,0 @@
1
- import b from 'benny'
2
- import { alpha as colorBitsAlpha } from '../src/string'
3
- import { colord } from 'colord'
4
- import tinycolor2 from 'tinycolor2'
5
- import color from 'color'
6
- import chroma from 'chroma-js'
7
-
8
- const input = '#808080'
9
-
10
- b.suite(
11
- `Parse color, set to 0.5 opacity, and convert back to hexadecimal`,
12
-
13
- b.add('color-bits', () => {
14
- colorBitsAlpha(input, 0.5)
15
- }),
16
-
17
- b.add('colord', () => {
18
- colord(input).alpha(0.5).toHex()
19
- }),
20
-
21
- b.add('color', () => {
22
- color(input).alpha(0.5).hex()
23
- }),
24
-
25
- b.add('tinycolor2', () => {
26
- tinycolor2(input).setAlpha(0.5).toHexString()
27
- }),
28
-
29
- b.add('chroma-js', () => {
30
- chroma(input).alpha(0.5).hex()
31
- }),
32
-
33
- b.cycle(),
34
- b.complete()
35
- )
package/build/bit.d.ts DELETED
@@ -1,3 +0,0 @@
1
- export declare function cast(n: number): number;
2
- export declare function get(n: number, offset: number): number;
3
- export declare function set(n: number, offset: number, byte: number): number;
package/build/bit.js DELETED
@@ -1,29 +0,0 @@
1
- "use strict";
2
- // Bitwise functions
3
- //
4
- // The color representation would ideally be 32-bits unsigned, but JS bitwise
5
- // operators only work as 32-bits signed. The range of Smi values on V8 is also
6
- // 32-bits signed. Those two factors make it that it's much more efficient to just
7
- // use signed integers to represent the data.
8
- //
9
- // Colors with a R channel >= 0x80 will be a negative number, but that's not really
10
- // an issue at any point because the bits for signed and unsigned integers are always
11
- // the same, only their interpretation changes.
12
- Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.cast = cast;
14
- exports.get = get;
15
- exports.set = set;
16
- const INT32_TO_UINT32_OFFSET = 2 ** 32;
17
- function cast(n) {
18
- if (n < 0) {
19
- return n + INT32_TO_UINT32_OFFSET;
20
- }
21
- return n;
22
- }
23
- function get(n, offset) {
24
- return (n >> offset) & 0xff;
25
- }
26
- function set(n, offset, byte) {
27
- return n ^ ((n ^ (byte << offset)) & (0xff << offset));
28
- }
29
- //# sourceMappingURL=bit.js.map
package/build/bit.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"bit.js","sourceRoot":"","sources":["../src/bit.ts"],"names":[],"mappings":";AAAA,oBAAoB;AACpB,EAAE;AACF,6EAA6E;AAC7E,+EAA+E;AAC/E,kFAAkF;AAClF,6CAA6C;AAC7C,EAAE;AACF,mFAAmF;AACnF,qFAAqF;AACrF,+CAA+C;;AAI/C,oBAKC;AAED,kBAEC;AAED,kBAEC;AAfD,MAAM,sBAAsB,GAAG,CAAC,IAAI,EAAE,CAAC;AAEvC,SAAgB,IAAI,CAAC,CAAS;IAC5B,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACV,OAAO,CAAC,GAAG,sBAAsB,CAAC;IACpC,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAgB,GAAG,CAAC,CAAS,EAAE,MAAc;IAC3C,OAAO,CAAC,CAAC,IAAI,MAAM,CAAC,GAAG,IAAI,CAAC;AAC9B,CAAC;AAED,SAAgB,GAAG,CAAC,CAAS,EAAE,MAAc,EAAE,IAAY;IACzD,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,IAAI,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,IAAI,MAAM,CAAC,CAAC,CAAC;AACzD,CAAC"}