chromonym 2.0.0 → 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/NOTICE.md +32 -0
- package/README.md +138 -72
- package/dist/identify.d.ts +36 -11
- package/dist/identify.d.ts.map +1 -1
- package/dist/identify.js +34 -19
- package/dist/identify.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/indexing.d.ts +18 -0
- package/dist/indexing.d.ts.map +1 -1
- package/dist/indexing.js +62 -0
- package/dist/indexing.js.map +1 -1
- package/dist/math/editDistance.d.ts +17 -0
- package/dist/math/editDistance.d.ts.map +1 -0
- package/dist/math/editDistance.js +48 -0
- package/dist/math/editDistance.js.map +1 -0
- package/dist/palettes/crayola.d.ts +200 -0
- package/dist/palettes/crayola.d.ts.map +1 -0
- package/dist/palettes/crayola.js +121 -0
- package/dist/palettes/crayola.js.map +1 -0
- package/dist/palettes/index.d.ts +1 -0
- package/dist/palettes/index.d.ts.map +1 -1
- package/dist/palettes/index.js +1 -0
- package/dist/palettes/index.js.map +1 -1
- package/dist/resolve.d.ts +39 -6
- package/dist/resolve.d.ts.map +1 -1
- package/dist/resolve.js +39 -12
- package/dist/resolve.js.map +1 -1
- package/package.json +8 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crayola.js","sourceRoot":"","sources":["../../src/palettes/crayola.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Palette } from '../types.js';\nimport { standardNormalize } from './normalize.js';\n\n/**\n * Crayola crayon colors — canonical subset. ~85 entries covering the\n * current 64-standard box, iconic fluorescents, and widely-recognized\n * modern additions.\n *\n * Keys are Title Case with spaces (`'Granny Smith Apple'`,\n * `'Razzmatazz'`) — how the names are printed on the crayon wrapper.\n * `standardNormalize` strips spaces + case + punctuation on input, so\n * `resolve('granny-smith-apple')` and `resolve('Granny Smith Apple')`\n * both hit the same entry.\n *\n * sRGB values are community-sourced approximations (Wikipedia's\n * well-cited list of Crayola crayon colors). They do not represent\n * a licensed Crayola reference. See NOTICE.md for trademark note.\n *\n * Default metric: `deltaEok`. The Crayola set spans a wide gamut with\n * many saturated brights (fluorescents especially) where CIELAB-based\n * metrics are less perceptually uniform than OKLAB. Same cost profile\n * as deltaE76, better neighbor selection in saturated regions.\n */\nconst crayolaColors = {\n // --- Current standard box: the 12 primary/secondary hue wheel ---\n Red: '#ee204d',\n 'Red Orange': '#ff5349',\n Orange: '#ff7538',\n 'Yellow Orange': '#ffae42',\n Yellow: '#fce883',\n 'Yellow Green': '#c5e384',\n Green: '#1cac78',\n 'Blue Green': '#0d98ba',\n Blue: '#1f75fe',\n 'Blue Violet': '#7366bd',\n Violet: '#926eae',\n 'Red Violet': '#c0448f',\n\n // --- Achromatics ---\n Black: '#232323',\n Brown: '#b4674d',\n White: '#ededed',\n Gray: '#95918c',\n\n // --- 64-box additions (pre-1990 core set) ---\n 'Carnation Pink': '#ffaacc',\n 'Sky Blue': '#80daeb',\n Tan: '#faa76c',\n Apricot: '#fdd9b5',\n Peach: '#ffcfab',\n 'Cadet Blue': '#b0b7c6',\n Salmon: '#ff9baa',\n 'Forest Green': '#6dae81',\n 'Lemon Yellow': '#fff44f',\n Mahogany: '#cd4a4c',\n Maroon: '#c8385a',\n Bittersweet: '#fd7c6e',\n Sepia: '#a5694f',\n 'Burnt Sienna': '#ea7e5d',\n 'Burnt Orange': '#ff7f49',\n 'Raw Sienna': '#d68a59',\n\n // --- Metallics ---\n Silver: '#cdc5c2',\n Gold: '#e7c697',\n Copper: '#dd9475',\n\n // --- Earth / nature tones ---\n 'Green Yellow': '#f0e891',\n 'Pine Green': '#158078',\n 'Olive Green': '#bab86c',\n Indigo: '#5d76cb',\n Periwinkle: '#c5d0e6',\n Cerulean: '#1dacd6',\n 'Sea Green': '#9fe2bf',\n 'Turquoise Blue': '#77dde7',\n\n // --- Fluorescents (the iconic \"Neon 24\" era) ---\n 'Atomic Tangerine': '#ff9966',\n 'Blizzard Blue': '#ace5ee',\n 'Hot Magenta': '#ff1dce',\n 'Laser Lemon': '#fdfc74',\n 'Neon Carrot': '#ffa343',\n 'Purple Pizzazz': '#fe4eda',\n 'Razzle Dazzle Rose': '#ff48d0',\n Razzmatazz: '#e3256b',\n \"Screamin' Green\": '#76ff7a',\n 'Shocking Pink': '#fb7efd',\n 'Tickle Me Pink': '#fc89ac',\n 'Unmellow Yellow': '#ffff66',\n 'Wild Watermelon': '#fc6c85',\n 'Outrageous Orange': '#ff6e4a',\n 'Electric Lime': '#ceff1d',\n\n // --- Modern / whimsical additions ---\n 'Granny Smith Apple': '#a8e4a0',\n 'Macaroni and Cheese': '#ffbd88',\n 'Banana Mania': '#fae7b5',\n 'Caribbean Green': '#1cd3a2',\n Cerise: '#dd4492',\n 'Cotton Candy': '#ffbcd9',\n 'Fuzzy Wuzzy': '#cc6666',\n Inchworm: '#b2ec5d',\n 'Jazzberry Jam': '#ca3767',\n Manatee: '#979aaa',\n 'Mango Tango': '#ff8243',\n Mauvelous: '#ef98aa',\n 'Midnight Blue': '#1a4876',\n 'Navy Blue': '#1974d2',\n 'Pacific Blue': '#1ca9c9',\n 'Piggy Pink': '#fddde6',\n Plum: '#8e4585',\n 'Purple Heart': '#7442c8',\n \"Robin's Egg Blue\": '#1fcecb',\n 'Royal Purple': '#7851a9',\n Scarlet: '#fc2847',\n Timberwolf: '#dbd7d2',\n Tumbleweed: '#deaa88',\n 'Violet Red': '#f75394',\n 'Vivid Violet': '#8f509d',\n Wisteria: '#cda4de',\n} as const;\n\nexport type CrayolaColorName = keyof typeof crayolaColors;\n\nexport const crayola = {\n name: 'crayola',\n colors: crayolaColors,\n normalize: standardNormalize,\n defaultMetric: 'deltaEok',\n} as const satisfies Palette<CrayolaColorName>;\n"]}
|
package/dist/palettes/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/palettes/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,gBAAgB,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EAAE,KAAK,YAAY,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,KAAK,YAAY,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC","sourcesContent":["export { type PantoneColorName, pantone } from './pantone.js';\nexport { type WebColorName, web } from './web.js';\nexport { type X11ColorName, x11 } from './x11.js';\n"]}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/palettes/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,gBAAgB,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EAAE,KAAK,gBAAgB,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EAAE,KAAK,YAAY,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,KAAK,YAAY,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC","sourcesContent":["export { type CrayolaColorName, crayola } from './crayola.js';\nexport { type PantoneColorName, pantone } from './pantone.js';\nexport { type WebColorName, web } from './web.js';\nexport { type X11ColorName, x11 } from './x11.js';\n"]}
|
package/dist/palettes/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/palettes/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,OAAO,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EAAqB,GAAG,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAqB,GAAG,EAAE,MAAM,UAAU,CAAC","sourcesContent":["export { type PantoneColorName, pantone } from './pantone.js';\nexport { type WebColorName, web } from './web.js';\nexport { type X11ColorName, x11 } from './x11.js';\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/palettes/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,OAAO,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EAAyB,OAAO,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EAAqB,GAAG,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAqB,GAAG,EAAE,MAAM,UAAU,CAAC","sourcesContent":["export { type CrayolaColorName, crayola } from './crayola.js';\nexport { type PantoneColorName, pantone } from './pantone.js';\nexport { type WebColorName, web } from './web.js';\nexport { type X11ColorName, x11 } from './x11.js';\n"]}
|
package/dist/resolve.d.ts
CHANGED
|
@@ -1,16 +1,49 @@
|
|
|
1
|
+
import { web } from './palettes/web.js';
|
|
1
2
|
import type { ColorFormat, ColorValue, Palette } from './types.js';
|
|
3
|
+
/** Extract string keys from a Palette's `colors` map. */
|
|
4
|
+
type PaletteKey<P extends Palette> = Extract<keyof P['colors'], string>;
|
|
2
5
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
+
* One ranked fuzzy-match entry when `resolve` is called with `k`.
|
|
7
|
+
* `distance` is the Levenshtein edit distance between the normalized
|
|
8
|
+
* input and the normalized palette key — integer count of insertions,
|
|
9
|
+
* deletions, and substitutions.
|
|
10
|
+
*/
|
|
11
|
+
export type ResolveMatch<Name extends string> = {
|
|
12
|
+
readonly name: Name;
|
|
13
|
+
readonly value: ColorValue;
|
|
14
|
+
readonly distance: number;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Resolve a human-readable name to a color. Normalizes the input using
|
|
18
|
+
* the palette's own `normalize` function before looking it up.
|
|
19
|
+
*
|
|
20
|
+
* **Without `k`** (strict, unchanged): returns the exact match value, or
|
|
21
|
+
* `null` if the normalized name isn't in the palette.
|
|
6
22
|
*
|
|
7
|
-
*
|
|
23
|
+
* **With `k`** (fuzzy, typo-tolerant): returns an array of the top `k`
|
|
24
|
+
* matches ranked by Levenshtein edit distance against normalized keys.
|
|
25
|
+
* Useful for user-typed input where misspellings, casing, and
|
|
26
|
+
* punctuation can all be recovered.
|
|
8
27
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
28
|
+
* ```ts
|
|
29
|
+
* resolve('rebeccapurple') // '#663399'
|
|
30
|
+
* resolve('rebecapurple') // null (strict)
|
|
31
|
+
* resolve('rebecapurple', { palette: web, k: 3 }) // fuzzy:
|
|
32
|
+
* // [{ name: 'rebeccapurple', value: '#663399', distance: 1 },
|
|
33
|
+
* // { name: 'purple', value: '#800080', distance: 6 },
|
|
34
|
+
* // ...]
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* Defaults: palette = `web`, format = 'HEX', `k` = undefined (strict).
|
|
11
38
|
*/
|
|
12
39
|
export declare function resolve(name: string, opts?: {
|
|
13
40
|
palette?: Palette;
|
|
14
41
|
format?: ColorFormat;
|
|
15
42
|
}): ColorValue | null;
|
|
43
|
+
export declare function resolve<P extends Palette = typeof web>(name: string, opts: {
|
|
44
|
+
palette?: P;
|
|
45
|
+
format?: ColorFormat;
|
|
46
|
+
k: number;
|
|
47
|
+
}): Array<ResolveMatch<PaletteKey<P>>>;
|
|
48
|
+
export {};
|
|
16
49
|
//# sourceMappingURL=resolve.d.ts.map
|
package/dist/resolve.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAY,OAAO,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AACxC,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAY,OAAO,EAAE,MAAM,YAAY,CAAC;AAO7E,yDAAyD;AACzD,KAAK,UAAU,CAAC,CAAC,SAAS,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC;AAExE;;;;;GAKG;AACH,MAAM,MAAM,YAAY,CAAC,IAAI,SAAS,MAAM,IAAI;IAC9C,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,wBAAgB,OAAO,CACrB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,GACjD,UAAU,GAAG,IAAI,CAAC;AAGrB,wBAAgB,OAAO,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,GAAG,EACpD,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE;IAAE,OAAO,CAAC,EAAE,CAAC,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GACrD,KAAK,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC","sourcesContent":["import { hexToRgba } from './conversions/hex.js';\nimport { fromRgba } from './convert.js';\nimport { getNameIndex } from './indexing.js';\nimport { levenshtein } from './math/editDistance.js';\nimport { web } from './palettes/web.js';\nimport type { ColorFormat, ColorValue, HexColor, Palette } from './types.js';\n\n// No built-in palette key exceeds ~30 chars post-normalize; anything well past\n// that can't plausibly win a fuzzy match and risks pathological O(n·m) cost\n// across every palette entry. Guard the k-branch input at 64.\nconst MAX_FUZZY_INPUT_LENGTH = 64;\n\n/** Extract string keys from a Palette's `colors` map. */\ntype PaletteKey<P extends Palette> = Extract<keyof P['colors'], string>;\n\n/**\n * One ranked fuzzy-match entry when `resolve` is called with `k`.\n * `distance` is the Levenshtein edit distance between the normalized\n * input and the normalized palette key — integer count of insertions,\n * deletions, and substitutions.\n */\nexport type ResolveMatch<Name extends string> = {\n readonly name: Name;\n readonly value: ColorValue;\n readonly distance: number;\n};\n\n/**\n * Resolve a human-readable name to a color. Normalizes the input using\n * the palette's own `normalize` function before looking it up.\n *\n * **Without `k`** (strict, unchanged): returns the exact match value, or\n * `null` if the normalized name isn't in the palette.\n *\n * **With `k`** (fuzzy, typo-tolerant): returns an array of the top `k`\n * matches ranked by Levenshtein edit distance against normalized keys.\n * Useful for user-typed input where misspellings, casing, and\n * punctuation can all be recovered.\n *\n * ```ts\n * resolve('rebeccapurple') // '#663399'\n * resolve('rebecapurple') // null (strict)\n * resolve('rebecapurple', { palette: web, k: 3 }) // fuzzy:\n * // [{ name: 'rebeccapurple', value: '#663399', distance: 1 },\n * // { name: 'purple', value: '#800080', distance: 6 },\n * // ...]\n * ```\n *\n * Defaults: palette = `web`, format = 'HEX', `k` = undefined (strict).\n */\n\n// Overload 1: strict — single ColorValue or null (unchanged).\nexport function resolve(\n name: string,\n opts?: { palette?: Palette; format?: ColorFormat },\n): ColorValue | null;\n\n// Overload 2: fuzzy top-k — ranked Match[].\nexport function resolve<P extends Palette = typeof web>(\n name: string,\n opts: { palette?: P; format?: ColorFormat; k: number },\n): Array<ResolveMatch<PaletteKey<P>>>;\n\n// Implementation.\nexport function resolve(\n name: string,\n opts: { palette?: Palette; format?: ColorFormat; k?: number } = {},\n): ColorValue | null | Array<ResolveMatch<string>> {\n const palette = opts.palette ?? web;\n const format = opts.format ?? 'HEX';\n const normalized = palette.normalize(name);\n\n if (opts.k !== undefined) {\n const limit = Math.max(0, opts.k);\n if (limit === 0) return [];\n if (normalized.length > MAX_FUZZY_INPUT_LENGTH) return [];\n // Iterate the name index's normalized → canonical map once; for each\n // entry compute Levenshtein from the user's normalized input.\n const ranked: Array<[string, number]> = [];\n for (const [normalizedKey, canonical] of getNameIndex(palette).entries()) {\n ranked.push([canonical, levenshtein(normalized, normalizedKey)]);\n }\n ranked.sort((a, b) => a[1] - b[1]);\n const out: Array<ResolveMatch<string>> = [];\n const take = Math.min(limit, ranked.length);\n for (let i = 0; i < take; i++) {\n const entry = ranked[i];\n if (entry === undefined) continue;\n const hex = (palette.colors as Record<string, HexColor>)[entry[0]];\n if (hex === undefined) continue;\n out.push({\n name: entry[0],\n value: fromRgba(hexToRgba(hex), format),\n distance: entry[1],\n });\n }\n return out;\n }\n\n // Strict path.\n const canonical = getNameIndex(palette).get(normalized);\n if (canonical === undefined) return null;\n const hex = (palette.colors as Record<string, HexColor>)[canonical];\n if (hex === undefined) return null;\n return fromRgba(hexToRgba(hex), format);\n}\n"]}
|
package/dist/resolve.js
CHANGED
|
@@ -1,27 +1,54 @@
|
|
|
1
1
|
import { hexToRgba } from './conversions/hex.js';
|
|
2
2
|
import { fromRgba } from './convert.js';
|
|
3
3
|
import { getNameIndex } from './indexing.js';
|
|
4
|
+
import { levenshtein } from './math/editDistance.js';
|
|
4
5
|
import { web } from './palettes/web.js';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
* Defaults: palette = `web`, format = 'HEX'.
|
|
11
|
-
*
|
|
12
|
-
* BYO palettes: pass any object matching `Palette<Name>` — no registration
|
|
13
|
-
* needed; the palette's normalizer handles lookup.
|
|
14
|
-
*/
|
|
6
|
+
// No built-in palette key exceeds ~30 chars post-normalize; anything well past
|
|
7
|
+
// that can't plausibly win a fuzzy match and risks pathological O(n·m) cost
|
|
8
|
+
// across every palette entry. Guard the k-branch input at 64.
|
|
9
|
+
const MAX_FUZZY_INPUT_LENGTH = 64;
|
|
10
|
+
// Implementation.
|
|
15
11
|
export function resolve(name, opts = {}) {
|
|
16
12
|
const palette = opts.palette ?? web;
|
|
17
13
|
const format = opts.format ?? 'HEX';
|
|
18
|
-
const
|
|
14
|
+
const normalized = palette.normalize(name);
|
|
15
|
+
if (opts.k !== undefined) {
|
|
16
|
+
const limit = Math.max(0, opts.k);
|
|
17
|
+
if (limit === 0)
|
|
18
|
+
return [];
|
|
19
|
+
if (normalized.length > MAX_FUZZY_INPUT_LENGTH)
|
|
20
|
+
return [];
|
|
21
|
+
// Iterate the name index's normalized → canonical map once; for each
|
|
22
|
+
// entry compute Levenshtein from the user's normalized input.
|
|
23
|
+
const ranked = [];
|
|
24
|
+
for (const [normalizedKey, canonical] of getNameIndex(palette).entries()) {
|
|
25
|
+
ranked.push([canonical, levenshtein(normalized, normalizedKey)]);
|
|
26
|
+
}
|
|
27
|
+
ranked.sort((a, b) => a[1] - b[1]);
|
|
28
|
+
const out = [];
|
|
29
|
+
const take = Math.min(limit, ranked.length);
|
|
30
|
+
for (let i = 0; i < take; i++) {
|
|
31
|
+
const entry = ranked[i];
|
|
32
|
+
if (entry === undefined)
|
|
33
|
+
continue;
|
|
34
|
+
const hex = palette.colors[entry[0]];
|
|
35
|
+
if (hex === undefined)
|
|
36
|
+
continue;
|
|
37
|
+
out.push({
|
|
38
|
+
name: entry[0],
|
|
39
|
+
value: fromRgba(hexToRgba(hex), format),
|
|
40
|
+
distance: entry[1],
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
45
|
+
// Strict path.
|
|
46
|
+
const canonical = getNameIndex(palette).get(normalized);
|
|
19
47
|
if (canonical === undefined)
|
|
20
48
|
return null;
|
|
21
49
|
const hex = palette.colors[canonical];
|
|
22
50
|
if (hex === undefined)
|
|
23
51
|
return null;
|
|
24
|
-
// Skip detectFormat — we already know this is HEX (read from palette data).
|
|
25
52
|
return fromRgba(hexToRgba(hex), format);
|
|
26
53
|
}
|
|
27
54
|
//# sourceMappingURL=resolve.js.map
|
package/dist/resolve.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAGxC
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAGxC,+EAA+E;AAC/E,4EAA4E;AAC5E,8DAA8D;AAC9D,MAAM,sBAAsB,GAAG,EAAE,CAAC;AAqDlC,kBAAkB;AAClB,MAAM,UAAU,OAAO,CACrB,IAAY,EACZ,IAAI,GAA4D,EAAE;IAElE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,GAAG,CAAC;IACpC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC;IACpC,MAAM,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAE3C,IAAI,IAAI,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QAClC,IAAI,KAAK,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAC3B,IAAI,UAAU,CAAC,MAAM,GAAG,sBAAsB;YAAE,OAAO,EAAE,CAAC;QAC1D,qEAAqE;QACrE,8DAA8D;QAC9D,MAAM,MAAM,GAA4B,EAAE,CAAC;QAC3C,KAAK,MAAM,CAAC,aAAa,EAAE,SAAS,CAAC,IAAI,YAAY,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;YACzE,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,WAAW,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;QACnE,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,GAAG,GAAgC,EAAE,CAAC;QAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QAC5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9B,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACxB,IAAI,KAAK,KAAK,SAAS;gBAAE,SAAS;YAClC,MAAM,GAAG,GAAI,OAAO,CAAC,MAAmC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YACnE,IAAI,GAAG,KAAK,SAAS;gBAAE,SAAS;YAChC,GAAG,CAAC,IAAI,CAAC;gBACP,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;gBACd,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;gBACvC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC;aACnB,CAAC,CAAC;QACL,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED,eAAe;IACf,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACxD,IAAI,SAAS,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACzC,MAAM,GAAG,GAAI,OAAO,CAAC,MAAmC,CAAC,SAAS,CAAC,CAAC;IACpE,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACnC,OAAO,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;AAC1C,CAAC","sourcesContent":["import { hexToRgba } from './conversions/hex.js';\nimport { fromRgba } from './convert.js';\nimport { getNameIndex } from './indexing.js';\nimport { levenshtein } from './math/editDistance.js';\nimport { web } from './palettes/web.js';\nimport type { ColorFormat, ColorValue, HexColor, Palette } from './types.js';\n\n// No built-in palette key exceeds ~30 chars post-normalize; anything well past\n// that can't plausibly win a fuzzy match and risks pathological O(n·m) cost\n// across every palette entry. Guard the k-branch input at 64.\nconst MAX_FUZZY_INPUT_LENGTH = 64;\n\n/** Extract string keys from a Palette's `colors` map. */\ntype PaletteKey<P extends Palette> = Extract<keyof P['colors'], string>;\n\n/**\n * One ranked fuzzy-match entry when `resolve` is called with `k`.\n * `distance` is the Levenshtein edit distance between the normalized\n * input and the normalized palette key — integer count of insertions,\n * deletions, and substitutions.\n */\nexport type ResolveMatch<Name extends string> = {\n readonly name: Name;\n readonly value: ColorValue;\n readonly distance: number;\n};\n\n/**\n * Resolve a human-readable name to a color. Normalizes the input using\n * the palette's own `normalize` function before looking it up.\n *\n * **Without `k`** (strict, unchanged): returns the exact match value, or\n * `null` if the normalized name isn't in the palette.\n *\n * **With `k`** (fuzzy, typo-tolerant): returns an array of the top `k`\n * matches ranked by Levenshtein edit distance against normalized keys.\n * Useful for user-typed input where misspellings, casing, and\n * punctuation can all be recovered.\n *\n * ```ts\n * resolve('rebeccapurple') // '#663399'\n * resolve('rebecapurple') // null (strict)\n * resolve('rebecapurple', { palette: web, k: 3 }) // fuzzy:\n * // [{ name: 'rebeccapurple', value: '#663399', distance: 1 },\n * // { name: 'purple', value: '#800080', distance: 6 },\n * // ...]\n * ```\n *\n * Defaults: palette = `web`, format = 'HEX', `k` = undefined (strict).\n */\n\n// Overload 1: strict — single ColorValue or null (unchanged).\nexport function resolve(\n name: string,\n opts?: { palette?: Palette; format?: ColorFormat },\n): ColorValue | null;\n\n// Overload 2: fuzzy top-k — ranked Match[].\nexport function resolve<P extends Palette = typeof web>(\n name: string,\n opts: { palette?: P; format?: ColorFormat; k: number },\n): Array<ResolveMatch<PaletteKey<P>>>;\n\n// Implementation.\nexport function resolve(\n name: string,\n opts: { palette?: Palette; format?: ColorFormat; k?: number } = {},\n): ColorValue | null | Array<ResolveMatch<string>> {\n const palette = opts.palette ?? web;\n const format = opts.format ?? 'HEX';\n const normalized = palette.normalize(name);\n\n if (opts.k !== undefined) {\n const limit = Math.max(0, opts.k);\n if (limit === 0) return [];\n if (normalized.length > MAX_FUZZY_INPUT_LENGTH) return [];\n // Iterate the name index's normalized → canonical map once; for each\n // entry compute Levenshtein from the user's normalized input.\n const ranked: Array<[string, number]> = [];\n for (const [normalizedKey, canonical] of getNameIndex(palette).entries()) {\n ranked.push([canonical, levenshtein(normalized, normalizedKey)]);\n }\n ranked.sort((a, b) => a[1] - b[1]);\n const out: Array<ResolveMatch<string>> = [];\n const take = Math.min(limit, ranked.length);\n for (let i = 0; i < take; i++) {\n const entry = ranked[i];\n if (entry === undefined) continue;\n const hex = (palette.colors as Record<string, HexColor>)[entry[0]];\n if (hex === undefined) continue;\n out.push({\n name: entry[0],\n value: fromRgba(hexToRgba(hex), format),\n distance: entry[1],\n });\n }\n return out;\n }\n\n // Strict path.\n const canonical = getNameIndex(palette).get(normalized);\n if (canonical === undefined) return null;\n const hex = (palette.colors as Record<string, HexColor>)[canonical];\n if (hex === undefined) return null;\n return fromRgba(hexToRgba(hex), format);\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chromonym",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "One color-naming API for any palette. Identify, resolve, and convert colors across your own palette or the built-in CSS, X11, and
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "One color-naming API for any palette. Identify, resolve, and convert colors across your own palette or the built-in CSS, X11, Pantone, and Crayola sets — fully typed, tree-shakeable, perceptual distance metrics (CIEDE2000 / OKLAB).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"color",
|
|
7
7
|
"color-name",
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"css-colors",
|
|
14
14
|
"x11-colors",
|
|
15
15
|
"pantone",
|
|
16
|
+
"crayola",
|
|
16
17
|
"deltaE",
|
|
17
18
|
"ciede2000",
|
|
18
19
|
"lab",
|
|
@@ -64,6 +65,11 @@
|
|
|
64
65
|
"import": "./dist/palettes/pantone.js",
|
|
65
66
|
"default": "./dist/palettes/pantone.js"
|
|
66
67
|
},
|
|
68
|
+
"./crayola": {
|
|
69
|
+
"types": "./dist/palettes/crayola.d.ts",
|
|
70
|
+
"import": "./dist/palettes/crayola.js",
|
|
71
|
+
"default": "./dist/palettes/crayola.js"
|
|
72
|
+
},
|
|
67
73
|
"./conversions/hex": {
|
|
68
74
|
"types": "./dist/conversions/hex.d.ts",
|
|
69
75
|
"import": "./dist/conversions/hex.js",
|