-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
index.js
128 lines (115 loc) · 2.75 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import {
parse,
to as convertColor,
ColorSpace,
sRGB,
P3,
LCH,
HSL,
OKLCH,
} from "colorjs.io/fn"
// Register color spaces for parsing and converting
ColorSpace.register(sRGB) // Can parse keywords and hex colors
ColorSpace.register(P3)
ColorSpace.register(HSL)
ColorSpace.register(LCH)
ColorSpace.register(OKLCH)
/**
* @typedef NormalizedColor
* @property {number} hue
* @property {number} saturation
* @property {number} lightness
* @property {number} alpha
*/
/**
* @param {string | number | {raw: string} | undefined} value
* @returns {number}
* @todo Make this faster based on usage heuristics
*/
function numerify(value) {
if (typeof value === 'number' && Number.isFinite(value)) {
return value
}
if (Number.isNaN(value)) {
return 0
}
if (typeof value === 'object' && 'raw' in value) {
return parseFloat(value.raw)
}
return 0
}
/**
* Convert a CSS (string) color into a normalized object that can be used for comparison
* @param {string} authored
* @returns {NormalizedColor & { authored: string }}
*/
export function convert(authored) {
try {
let parsed = parse(authored)
let converted = parsed.spaceId === 'hsl' ? parsed : convertColor(parsed, HSL)
let hsl = converted.coords
let hue = numerify(hsl[0])
let saturation = numerify(hsl[1])
let lightness = numerify(hsl[2])
let alpha = numerify(converted.alpha)
return {
hue,
saturation,
lightness,
alpha,
authored
}
} catch (error) {
return {
hue: 0,
saturation: 0,
lightness: 0,
alpha: 0,
authored
}
}
}
/**
* Function that sorts colors
* @param {string} a
* @param {string} b
* @returns {number}
*/
export function sortFn(a, b) {
let colorA = convert(a)
let colorB = convert(b)
// Move grey-ish values to the back
if (
(colorA.saturation === 0 || colorB.saturation === 0) &&
colorA.saturation !== colorB.saturation
) {
return colorB.saturation - colorA.saturation
}
// Sort by hue (lowest first)
if (colorA.hue !== colorB.hue) {
return colorA.hue - colorB.hue
}
// Sort by saturation (highest first)
if (colorA.saturation !== colorB.saturation) {
return colorA.saturation - colorB.saturation
}
// Comparing gray values, light before dark
if (colorA.saturation === 0 && colorB.saturation === 0) {
if (colorA.lightness !== colorB.lightness) {
return colorB.lightness - colorA.lightness
}
}
// Sort by transparency, least transparent first
if (colorA.alpha === colorB.alpha) {
return colorA.authored.toLowerCase().localeCompare(colorB.authored.toLowerCase())
}
return colorB.alpha - colorA.alpha
}
/**
* Sort the `colors` array using `Array.sort()`, so beware that it changes the source input
* @param {string[]} colors
* @returns {string[]} sorted
*/
export function sort(colors) {
return colors.sort(sortFn)
}