theme-vir 28.22.0 → 28.23.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.
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { assert, assertWrap, check } from '@augment-vir/assert';
|
|
2
2
|
import { arrayToObject, crossProduct, filterMap, getEnumValues, getOrSet, log, mapObjectValues, removeDuplicates, stringify, } from '@augment-vir/common';
|
|
3
|
-
import { ContrastLevelName, contrastLevelLabel, findColorAtContrastLevel } from '@electrovir/color';
|
|
3
|
+
import { ContrastLevelName, calculateContrast, contrastLevelLabel, contrastLevelNameMap, findColorAtContrastLevel, } from '@electrovir/color';
|
|
4
4
|
import { defineColorThemeOverride } from './color-theme-override.js';
|
|
5
5
|
import { defineColorTheme, noRefColorInitToString, } from './color-theme.js';
|
|
6
6
|
/**
|
|
@@ -90,6 +90,38 @@ export const defaultLightThemePair = {
|
|
|
90
90
|
};
|
|
91
91
|
/** @category Internal */
|
|
92
92
|
export const defaultContrastLevels = getEnumValues(ContrastLevelName);
|
|
93
|
+
function findColorWithPreference(colors, desiredContrastLevel, preference,
|
|
94
|
+
/** Pre-computed contrast-against-white values per color string. Higher = darker. */
|
|
95
|
+
lightnessProxies) {
|
|
96
|
+
const minContrast = contrastLevelNameMap[desiredContrastLevel].min;
|
|
97
|
+
const candidateColors = check.isArray(colors.foreground)
|
|
98
|
+
? colors.foreground
|
|
99
|
+
: check.isArray(colors.background)
|
|
100
|
+
? colors.background
|
|
101
|
+
: [];
|
|
102
|
+
const qualifying = candidateColors.filter((candidate) => {
|
|
103
|
+
const foreground = check.isArray(colors.foreground) ? candidate : colors.foreground;
|
|
104
|
+
const background = check.isArray(colors.foreground) ? colors.background : candidate;
|
|
105
|
+
return (Math.abs(calculateContrast({
|
|
106
|
+
foreground,
|
|
107
|
+
background: background,
|
|
108
|
+
}).contrast) >= minContrast);
|
|
109
|
+
});
|
|
110
|
+
if (qualifying.length === 0) {
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
return qualifying.reduce((best, color) => {
|
|
114
|
+
const bestProxy = lightnessProxies[best] ?? 0;
|
|
115
|
+
const colorProxy = lightnessProxies[color] ?? 0;
|
|
116
|
+
return preference === 'lightest'
|
|
117
|
+
? colorProxy < bestProxy
|
|
118
|
+
? color
|
|
119
|
+
: best
|
|
120
|
+
: colorProxy > bestProxy
|
|
121
|
+
? color
|
|
122
|
+
: best;
|
|
123
|
+
});
|
|
124
|
+
}
|
|
93
125
|
/**
|
|
94
126
|
* Creates a color theme from a color palette.
|
|
95
127
|
*
|
|
@@ -132,14 +164,38 @@ export function buildColorTheme(colorPalette, { omittedColorValues = defaultOmit
|
|
|
132
164
|
key: color.definition.default,
|
|
133
165
|
value: color,
|
|
134
166
|
}));
|
|
135
|
-
|
|
167
|
+
/** Pre-computed contrast-against-white per color. Higher value = darker shade. */
|
|
168
|
+
const lightnessProxies = arrayToObject(colorStrings, (colorString) => {
|
|
169
|
+
return {
|
|
170
|
+
key: colorString,
|
|
171
|
+
value: Math.abs(calculateContrast({
|
|
172
|
+
foreground: colorString,
|
|
173
|
+
background: '#ffffff',
|
|
174
|
+
}).contrast),
|
|
175
|
+
};
|
|
176
|
+
});
|
|
177
|
+
/** Lightest palette color (least contrast against white). */
|
|
178
|
+
const lightestColorString = colorStrings.reduce((lightest, color) => (lightnessProxies[color] ?? 0) < (lightnessProxies[lightest] ?? 0)
|
|
179
|
+
? color
|
|
180
|
+
: lightest);
|
|
181
|
+
/** Darkest palette color (most contrast against white). */
|
|
182
|
+
const darkestColorString = colorStrings.reduce((darkest, color) => (lightnessProxies[color] ?? 0) > (lightnessProxies[darkest] ?? 0) ? color : darkest);
|
|
183
|
+
/**
|
|
184
|
+
* On-self light mode: lightest fg achieving small-body contrast on the lightest palette
|
|
185
|
+
* bg. Fixed across all on-self contrast levels.
|
|
186
|
+
*/
|
|
187
|
+
const lightSelfFgString = assertWrap.isTruthy(findColorWithPreference({
|
|
136
188
|
foreground: colorStrings,
|
|
137
|
-
background:
|
|
138
|
-
}, ContrastLevelName.SmallBodyText), `Failed to find light mode
|
|
139
|
-
|
|
189
|
+
background: lightestColorString,
|
|
190
|
+
}, ContrastLevelName.SmallBodyText, 'lightest', lightnessProxies), `Failed to find light mode on-self foreground color for ${firstColor.colorName}`);
|
|
191
|
+
/**
|
|
192
|
+
* On-self dark mode: darkest fg achieving small-body contrast on the darkest palette
|
|
193
|
+
* bg. Fixed across all on-self contrast levels.
|
|
194
|
+
*/
|
|
195
|
+
const darkSelfFgString = assertWrap.isTruthy(findColorWithPreference({
|
|
140
196
|
foreground: colorStrings,
|
|
141
|
-
background:
|
|
142
|
-
}, ContrastLevelName.SmallBodyText), `Failed to find dark mode
|
|
197
|
+
background: darkestColorString,
|
|
198
|
+
}, ContrastLevelName.SmallBodyText, 'darkest', lightnessProxies), `Failed to find dark mode on-self foreground color for ${firstColor.colorName}`);
|
|
143
199
|
// Pre-compute base name parts that don't change per cross
|
|
144
200
|
const baseNameParts = [
|
|
145
201
|
prefix,
|
|
@@ -10,8 +10,12 @@ export var HeadingLevel;
|
|
|
10
10
|
export function createDefaultThemeOptions() {
|
|
11
11
|
const defaultFont = {
|
|
12
12
|
family: 'sans-serif',
|
|
13
|
-
lineHeight: {
|
|
14
|
-
|
|
13
|
+
lineHeight: {
|
|
14
|
+
ratio: 1.1,
|
|
15
|
+
},
|
|
16
|
+
size: {
|
|
17
|
+
pixels: 14,
|
|
18
|
+
},
|
|
15
19
|
weight: 400,
|
|
16
20
|
};
|
|
17
21
|
const bold = {
|
|
@@ -29,31 +33,43 @@ export function createDefaultThemeOptions() {
|
|
|
29
33
|
monospace: {
|
|
30
34
|
...defaultFont,
|
|
31
35
|
family: 'monospace',
|
|
32
|
-
size: {
|
|
36
|
+
size: {
|
|
37
|
+
ratio: 1.2,
|
|
38
|
+
},
|
|
33
39
|
},
|
|
34
40
|
headings: {
|
|
35
41
|
h1: {
|
|
36
42
|
...bold,
|
|
37
|
-
size: {
|
|
43
|
+
size: {
|
|
44
|
+
ratio: 2,
|
|
45
|
+
},
|
|
38
46
|
},
|
|
39
47
|
h2: {
|
|
40
48
|
...bold,
|
|
41
|
-
size: {
|
|
49
|
+
size: {
|
|
50
|
+
ratio: 1.5,
|
|
51
|
+
},
|
|
42
52
|
},
|
|
43
53
|
h3: {
|
|
44
54
|
...bold,
|
|
45
|
-
size: {
|
|
55
|
+
size: {
|
|
56
|
+
ratio: 1.17,
|
|
57
|
+
},
|
|
46
58
|
},
|
|
47
59
|
h4: {
|
|
48
60
|
...bold,
|
|
49
61
|
},
|
|
50
62
|
h5: {
|
|
51
63
|
...bold,
|
|
52
|
-
size: {
|
|
64
|
+
size: {
|
|
65
|
+
ratio: 0.83,
|
|
66
|
+
},
|
|
53
67
|
},
|
|
54
68
|
h6: {
|
|
55
69
|
...bold,
|
|
56
|
-
size: {
|
|
70
|
+
size: {
|
|
71
|
+
ratio: 0.67,
|
|
72
|
+
},
|
|
57
73
|
},
|
|
58
74
|
},
|
|
59
75
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "theme-vir",
|
|
3
|
-
"version": "28.
|
|
3
|
+
"version": "28.23.0",
|
|
4
4
|
"description": "Create an entire web theme.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"design",
|
|
@@ -43,29 +43,29 @@
|
|
|
43
43
|
"test:update": "virmator test web update"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@augment-vir/assert": "^31.
|
|
47
|
-
"@augment-vir/common": "^31.
|
|
46
|
+
"@augment-vir/assert": "^31.67.1",
|
|
47
|
+
"@augment-vir/common": "^31.67.1",
|
|
48
48
|
"@electrovir/color": "^1.7.8",
|
|
49
49
|
"apca-w3": "^0.1.9",
|
|
50
50
|
"lit-css-vars": "^3.5.0",
|
|
51
51
|
"type-fest": "^5.4.4"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@augment-vir/test": "^31.
|
|
54
|
+
"@augment-vir/test": "^31.67.1",
|
|
55
55
|
"@types/apca-w3": "^0.1.3",
|
|
56
56
|
"@web/dev-server-esbuild": "^1.0.5",
|
|
57
57
|
"@web/test-runner": "^0.20.2",
|
|
58
58
|
"@web/test-runner-commands": "^0.9.0",
|
|
59
59
|
"@web/test-runner-playwright": "^0.11.1",
|
|
60
60
|
"@web/test-runner-visual-regression": "^0.10.0",
|
|
61
|
-
"element-book": "^26.
|
|
62
|
-
"element-vir": "^26.14.
|
|
61
|
+
"element-book": "^26.17.0",
|
|
62
|
+
"element-vir": "^26.14.5",
|
|
63
63
|
"esbuild": "^0.27.3",
|
|
64
64
|
"istanbul-smart-text-reporter": "^1.1.5",
|
|
65
65
|
"markdown-code-example-inserter": "^3.0.3",
|
|
66
66
|
"typedoc": "^0.28.17",
|
|
67
67
|
"typescript": "5.9.3",
|
|
68
|
-
"vira": "^
|
|
68
|
+
"vira": "^30.6.0",
|
|
69
69
|
"vite": "^7.3.1",
|
|
70
70
|
"vite-tsconfig-paths": "^6.1.1"
|
|
71
71
|
},
|