pacem-less 0.51.4-babbage → 0.51.4-cantor
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/package.json +1 -1
- package/themebuilder.js +73 -52
package/package.json
CHANGED
package/themebuilder.js
CHANGED
|
@@ -30,6 +30,14 @@ const argv = yargs
|
|
|
30
30
|
.option('void', {
|
|
31
31
|
type: 'string',
|
|
32
32
|
description: 'Creates an empty palette file.',
|
|
33
|
+
})
|
|
34
|
+
.option('mincontrast', {
|
|
35
|
+
type: 'number',
|
|
36
|
+
description: 'The minimum WCAG contrast (1 to 21) container-to-background (default 1.5).',
|
|
37
|
+
})
|
|
38
|
+
.option('maxcontrast', {
|
|
39
|
+
type: 'number',
|
|
40
|
+
description: 'The maximum WCAG contrast (1 to 21) default-to-background (default 15).',
|
|
33
41
|
})
|
|
34
42
|
.help()
|
|
35
43
|
.argv;
|
|
@@ -55,7 +63,7 @@ function readFile(src) {
|
|
|
55
63
|
const json = fs.readFileSync(src, 'utf-8');
|
|
56
64
|
return JSON.parse(json);
|
|
57
65
|
}
|
|
58
|
-
const palette =
|
|
66
|
+
const palette = Object.assign({
|
|
59
67
|
background: '#1e2336',
|
|
60
68
|
primary: '#429bbb',
|
|
61
69
|
secondary: '#5e7881',
|
|
@@ -75,24 +83,30 @@ const palette = readFile(argv.src) ?? {
|
|
|
75
83
|
purple: '#624472',
|
|
76
84
|
teal: '#429bbb',
|
|
77
85
|
gray: '#808080',
|
|
78
|
-
};
|
|
79
|
-
const WCAG_MINIMUM_CONTRAST =
|
|
86
|
+
}, readFile(argv.src) ?? {});
|
|
87
|
+
const WCAG_MINIMUM_CONTRAST = argv.mincontrast ?? 1.5;
|
|
80
88
|
const WCAG_NORMAL_TEXT_CONTRAST = 4.5;
|
|
81
89
|
const WCAG_SAFE_CONTRAST = 7;
|
|
82
|
-
const WCAG_MAX_CONTRAST =
|
|
90
|
+
const WCAG_MAX_CONTRAST = argv.maxcontrast ?? 15;
|
|
91
|
+
const WCAG_DISABLED_CONTRAST = 1.6;
|
|
83
92
|
const SURFACE_LIGHT = .95;
|
|
84
93
|
const SURFACE_DARK = .02;
|
|
85
94
|
const MIN_SATURATION = .175;
|
|
86
95
|
const searchFn = Pacem.Mathematics.DataAnalysis.SearchFunctions.goldenRatio;
|
|
96
|
+
let backgroundModule;
|
|
97
|
+
let rootModule;
|
|
87
98
|
function isColorLight(clr) {
|
|
88
99
|
return Pacem.Colors.luminance(clr) >= .2;
|
|
89
100
|
}
|
|
90
|
-
function contrastColor(baseColor,
|
|
101
|
+
function contrastColor(baseColor, arg1 = baseColor, arg2 = WCAG_NORMAL_TEXT_CONTRAST, arg3 = null) {
|
|
102
|
+
const benchmarkColor = typeof arg1 === 'object' ? arg1 : baseColor;
|
|
103
|
+
const targetContrast = typeof arg1 === 'number' ? arg1 : (typeof arg2 === 'number' ? arg2 : WCAG_NORMAL_TEXT_CONTRAST);
|
|
104
|
+
const preferDark = typeof arg2 === 'boolean' ? arg2 : arg3;
|
|
91
105
|
const { h, s, l, a } = Pacem.Colors.hsl(baseColor);
|
|
92
|
-
const isDark = !isColorLight(baseColor);
|
|
106
|
+
const isDark = preferDark ?? !isColorLight(baseColor);
|
|
93
107
|
const min = isDark ? l : 0;
|
|
94
108
|
const max = isDark ? 1 : l;
|
|
95
|
-
const newL = searchFn(min, max, x => Math.abs(targetContrast - Pacem.Colors.contrastRatio(
|
|
109
|
+
const newL = searchFn(min, max, x => Math.abs(targetContrast - Pacem.Colors.contrastRatio(benchmarkColor, { h, s, l: x, a })));
|
|
96
110
|
return Pacem.Colors.rgb({ h, s, l: newL, a });
|
|
97
111
|
}
|
|
98
112
|
function luminanceColor(baseColor, targetLuminance) {
|
|
@@ -100,11 +114,32 @@ function luminanceColor(baseColor, targetLuminance) {
|
|
|
100
114
|
const newL = searchFn(0, 1, x => Math.abs(targetLuminance - Pacem.Colors.luminance({ h, s, l: x, a })));
|
|
101
115
|
return Pacem.Colors.rgb({ h, s, l: newL, a });
|
|
102
116
|
}
|
|
117
|
+
function invertModule(mod) {
|
|
118
|
+
return {
|
|
119
|
+
base: mod.contrast,
|
|
120
|
+
contrast: mod.base,
|
|
121
|
+
active: mod.activeContrast,
|
|
122
|
+
activeContrast: mod.active,
|
|
123
|
+
emphasis: mod.base,
|
|
124
|
+
container: mod.containerContrast,
|
|
125
|
+
containerContrast: mod.container,
|
|
126
|
+
containerActive: mod.containerActiveContrast,
|
|
127
|
+
containerActiveContrast: mod.containerActive,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function desaturateColor(clr, threshold = MIN_SATURATION) {
|
|
131
|
+
const { h, s, l, a } = Pacem.Colors.hsl(clr);
|
|
132
|
+
if (s > threshold) {
|
|
133
|
+
return Pacem.Colors.rgb({ h, s: threshold, l, a });
|
|
134
|
+
}
|
|
135
|
+
else
|
|
136
|
+
return clr;
|
|
137
|
+
}
|
|
103
138
|
function colorModule(clr, name, arg2) {
|
|
104
139
|
const isDisabled = name === 'disabled';
|
|
105
|
-
const isSurfaceColor = name === 'root' || name === 'background'
|
|
140
|
+
const isSurfaceColor = name === 'root' || name === 'background';
|
|
106
141
|
const isDesaturated = isDisabled || name === 'gray';
|
|
107
|
-
const forcedContrast = (arg2 && typeof arg2 === 'number') ? arg2 : (isDisabled ?
|
|
142
|
+
const forcedContrast = (arg2 && typeof arg2 === 'number') ? arg2 : (isDisabled ? WCAG_DISABLED_CONTRAST : null);
|
|
108
143
|
const baseContrast = forcedContrast ?? (isSurfaceColor ? WCAG_MAX_CONTRAST : WCAG_SAFE_CONTRAST);
|
|
109
144
|
const contrastClr = arg2 && typeof arg2 === 'object' ? arg2 : null;
|
|
110
145
|
const surfaceLight = name === 'background' ? SURFACE_LIGHT + .015 : SURFACE_LIGHT;
|
|
@@ -114,19 +149,19 @@ function colorModule(clr, name, arg2) {
|
|
|
114
149
|
const lightTargetLuminance = isDisabled ? (surfaceLight - .1) : (isSurfaceColor ? surfaceLight : .333);
|
|
115
150
|
const referenceColor = isColorRight ? clr
|
|
116
151
|
: (isSurfaceColor ? (!darkTheme ? luminanceColor(clr, lightTargetLuminance) : luminanceColor(clr, darkTargetLuminance))
|
|
117
|
-
: (
|
|
152
|
+
: contrastColor(clr, backgroundModule.base, WCAG_NORMAL_TEXT_CONTRAST, darkTheme));
|
|
118
153
|
let actualColor = contrastClr ? clr : referenceColor;
|
|
119
154
|
if (isDesaturated) {
|
|
120
|
-
|
|
121
|
-
if (s > MIN_SATURATION) {
|
|
122
|
-
actualColor = Pacem.Colors.rgb({ h, s: MIN_SATURATION, l, a });
|
|
123
|
-
}
|
|
155
|
+
actualColor = desaturateColor(actualColor);
|
|
124
156
|
}
|
|
125
157
|
const luminanceBackContainer = darkTheme ? .075 : .5;
|
|
126
158
|
const luminanceBackActiveOffset = darkTheme ? (isSurfaceColor ? .035 : .1) : (isSurfaceColor ? -.08 : -.06);
|
|
127
159
|
const contrastForeActive = forcedContrast ?? WCAG_SAFE_CONTRAST;
|
|
128
160
|
const contrast = contrastClr ?? contrastColor(actualColor, baseContrast);
|
|
129
|
-
const
|
|
161
|
+
const containerTargetContrast = (isDisabled ? Math.min(forcedContrast, .5 * (1 + WCAG_MINIMUM_CONTRAST)) : WCAG_MINIMUM_CONTRAST).roundoff();
|
|
162
|
+
const containerBenchmarkColor = isSurfaceColor ? actualColor : backgroundModule.base;
|
|
163
|
+
const container = contrastColor(actualColor, containerBenchmarkColor, containerTargetContrast, !(+isSurfaceColor ^ +darkTheme));
|
|
164
|
+
console.log(name + ' container yields ' + Pacem.Colors.stringify(container) + ', which should contrast ' + containerTargetContrast + ' with ' + Pacem.Colors.stringify(containerBenchmarkColor));
|
|
130
165
|
const containerContrast = contrastColor(container, isDisabled ? forcedContrast : WCAG_NORMAL_TEXT_CONTRAST);
|
|
131
166
|
const active = isDisabled ? actualColor : luminanceColor(actualColor, Pacem.Colors.luminance(actualColor) + luminanceBackActiveOffset);
|
|
132
167
|
const activeContrast = isDisabled ? contrast : contrastColor(active, contrastForeActive);
|
|
@@ -146,8 +181,6 @@ function colorModule(clr, name, arg2) {
|
|
|
146
181
|
};
|
|
147
182
|
}
|
|
148
183
|
const lessVariables = {};
|
|
149
|
-
let backgroundModule;
|
|
150
|
-
let rootModule;
|
|
151
184
|
const a255 = (x) => Math.round(x * 255);
|
|
152
185
|
const a255s = (c) => `${a255(c.r)}, ${a255(c.g)}, ${a255(c.b)}`;
|
|
153
186
|
const pushLessVariables = (name, mod) => {
|
|
@@ -170,47 +203,35 @@ const pushLessVariables = (name, mod) => {
|
|
|
170
203
|
lessVariables[`@color_${name}_emphasis`] = Pacem.Colors.stringify(mod.emphasis);
|
|
171
204
|
lessVariables[`@color_${name}_emphasis_rgb`] = a255s(mod.emphasis);
|
|
172
205
|
};
|
|
206
|
+
const backgroundColor = Pacem.Colors.parse(palette['background']);
|
|
207
|
+
backgroundModule = colorModule(backgroundColor, 'background');
|
|
208
|
+
pushLessVariables('background', backgroundModule);
|
|
209
|
+
const rootColor = 'root' in palette ? Pacem.Colors.parse(palette['root']) : Pacem.Colors.darken(backgroundModule.base, darkTheme ? .02 : .01);
|
|
210
|
+
rootModule = colorModule(rootColor, 'root');
|
|
211
|
+
pushLessVariables('root', rootModule);
|
|
212
|
+
if ('default' in palette) {
|
|
213
|
+
const defaultColor = contrastColor(desaturateColor(Pacem.Colors.parse(palette['default'])), rootModule.base, WCAG_MAX_CONTRAST, darkTheme);
|
|
214
|
+
const defaultModule = colorModule(defaultColor, 'default');
|
|
215
|
+
pushLessVariables('default', defaultModule);
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
pushLessVariables('default', invertModule(rootModule));
|
|
219
|
+
}
|
|
173
220
|
for (let name in palette) {
|
|
221
|
+
if (['default', 'background', 'root'].indexOf(name) >= 0) {
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
174
224
|
const color = Pacem.Colors.parse(palette[name]);
|
|
175
225
|
const mod = colorModule(color, name);
|
|
176
|
-
if (name === 'background') {
|
|
177
|
-
backgroundModule = mod;
|
|
178
|
-
}
|
|
179
|
-
if (name === 'root') {
|
|
180
|
-
rootModule = mod;
|
|
181
|
-
}
|
|
182
226
|
pushLessVariables(name, mod);
|
|
183
227
|
}
|
|
184
|
-
if (!('root' in palette)) {
|
|
185
|
-
const rootColor = Pacem.Colors.darken(backgroundModule.base, darkTheme ? .02 : .01);
|
|
186
|
-
rootModule = colorModule(rootColor, 'root');
|
|
187
|
-
pushLessVariables('root', rootModule);
|
|
188
|
-
}
|
|
189
228
|
if (!('disabled' in palette)) {
|
|
190
|
-
const disabledColor =
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
lessVariables[`@color_${name}_rgb`] = a255s(rootModule.contrast);
|
|
197
|
-
lessVariables[`@color_${name}_inv`] = Pacem.Colors.stringify(rootModule.base);
|
|
198
|
-
lessVariables[`@color_${name}_inv_rgb`] = a255s(rootModule.base);
|
|
199
|
-
lessVariables[`@color_${name}_container`] = Pacem.Colors.stringify(rootModule.containerContrast);
|
|
200
|
-
lessVariables[`@color_${name}_container_rgb`] = a255s(rootModule.containerContrast);
|
|
201
|
-
lessVariables[`@color_${name}_container_inv`] = Pacem.Colors.stringify(rootModule.container);
|
|
202
|
-
lessVariables[`@color_${name}_container_inv_rgb`] = a255s(rootModule.container);
|
|
203
|
-
lessVariables[`@color_${name}_active`] = Pacem.Colors.stringify(rootModule.activeContrast);
|
|
204
|
-
lessVariables[`@color_${name}_active_rgb`] = a255s(rootModule.activeContrast);
|
|
205
|
-
lessVariables[`@color_${name}_active_inv`] = Pacem.Colors.stringify(rootModule.active);
|
|
206
|
-
lessVariables[`@color_${name}_active_inv_rgb`] = a255s(rootModule.active);
|
|
207
|
-
lessVariables[`@color_${name}_container_active`] = Pacem.Colors.stringify(rootModule.containerActiveContrast);
|
|
208
|
-
lessVariables[`@color_${name}_container_active_rgb`] = a255s(rootModule.containerActiveContrast);
|
|
209
|
-
lessVariables[`@color_${name}_container_active_inv`] = Pacem.Colors.stringify(rootModule.containerActive);
|
|
210
|
-
lessVariables[`@color_${name}_container_active_inv_rgb`] = a255s(rootModule.containerActive);
|
|
211
|
-
lessVariables[`@color_${name}_emphasis`] = lessVariables[`@color_${name}`];
|
|
212
|
-
lessVariables[`@color_${name}_emphasis_rgb`] = lessVariables[`@color_${name}_rgb`];
|
|
213
|
-
}
|
|
229
|
+
const disabledColor = contrastColor(backgroundModule.base, WCAG_DISABLED_CONTRAST);
|
|
230
|
+
const disabledContrastColor = contrastColor(disabledColor, WCAG_DISABLED_CONTRAST * (darkTheme ? 1 : .9), !darkTheme);
|
|
231
|
+
pushLessVariables('disabled', colorModule(disabledColor, 'disabled', disabledContrastColor));
|
|
232
|
+
}
|
|
233
|
+
if (!('invert' in palette)) {
|
|
234
|
+
pushLessVariables('invert', invertModule(backgroundModule));
|
|
214
235
|
}
|
|
215
236
|
let lessText = '@palette_prebuilt: true;\r\n';
|
|
216
237
|
for (let name in lessVariables) {
|