theme-vir 28.23.1 → 28.25.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.
|
@@ -43,6 +43,17 @@ export type ArrayOrSelectParam<T extends PropertyKey> = ReadonlyArray<T> | Reado
|
|
|
43
43
|
export declare const defaultLightThemePair: RequiredAndNotNull<NoRefColorInit>;
|
|
44
44
|
/** @category Internal */
|
|
45
45
|
export declare const defaultContrastLevels: Readonly<ArrayOrSelectParam<ContrastLevelName>>;
|
|
46
|
+
/**
|
|
47
|
+
* Extra contrast levels generated by {@link buildColorTheme} beyond the standard `ContrastLevelName`
|
|
48
|
+
* values. `highest-contrast` always picks the palette color with the most contrast against the
|
|
49
|
+
* fixed color; `lowest-contrast` always picks the closest.
|
|
50
|
+
*
|
|
51
|
+
* @category Internal
|
|
52
|
+
*/
|
|
53
|
+
export declare enum ExtremeContrastLevel {
|
|
54
|
+
HighestContrast = "highest-contrast",
|
|
55
|
+
LowestContrast = "lowest-contrast"
|
|
56
|
+
}
|
|
46
57
|
/**
|
|
47
58
|
* Options for {@link buildColorTheme}.
|
|
48
59
|
*
|
|
@@ -90,6 +90,55 @@ export const defaultLightThemePair = {
|
|
|
90
90
|
};
|
|
91
91
|
/** @category Internal */
|
|
92
92
|
export const defaultContrastLevels = getEnumValues(ContrastLevelName);
|
|
93
|
+
/**
|
|
94
|
+
* Extra contrast levels generated by {@link buildColorTheme} beyond the standard `ContrastLevelName`
|
|
95
|
+
* values. `highest-contrast` always picks the palette color with the most contrast against the
|
|
96
|
+
* fixed color; `lowest-contrast` always picks the closest.
|
|
97
|
+
*
|
|
98
|
+
* @category Internal
|
|
99
|
+
*/
|
|
100
|
+
export var ExtremeContrastLevel;
|
|
101
|
+
(function (ExtremeContrastLevel) {
|
|
102
|
+
ExtremeContrastLevel["HighestContrast"] = "highest-contrast";
|
|
103
|
+
ExtremeContrastLevel["LowestContrast"] = "lowest-contrast";
|
|
104
|
+
})(ExtremeContrastLevel || (ExtremeContrastLevel = {}));
|
|
105
|
+
/**
|
|
106
|
+
* Picks the absolute lightest or darkest palette color based on which extreme produces the most (or
|
|
107
|
+
* least) contrast against the fixed color.
|
|
108
|
+
*/
|
|
109
|
+
function resolveExtremeContrastColor({ comparison, isHighestContrast, lightestColorString, darkestColorString, }) {
|
|
110
|
+
const paletteIsBackground = check.isArray(comparison.background);
|
|
111
|
+
const fixedColor = paletteIsBackground
|
|
112
|
+
? comparison.foreground
|
|
113
|
+
: comparison.background;
|
|
114
|
+
const lightContrastParams = paletteIsBackground
|
|
115
|
+
? {
|
|
116
|
+
foreground: fixedColor,
|
|
117
|
+
background: lightestColorString,
|
|
118
|
+
}
|
|
119
|
+
: {
|
|
120
|
+
foreground: lightestColorString,
|
|
121
|
+
background: fixedColor,
|
|
122
|
+
};
|
|
123
|
+
const darkContrastParams = paletteIsBackground
|
|
124
|
+
? {
|
|
125
|
+
foreground: fixedColor,
|
|
126
|
+
background: darkestColorString,
|
|
127
|
+
}
|
|
128
|
+
: {
|
|
129
|
+
foreground: darkestColorString,
|
|
130
|
+
background: fixedColor,
|
|
131
|
+
};
|
|
132
|
+
const lightestContrast = Math.abs(calculateContrast(lightContrastParams).contrast);
|
|
133
|
+
const darkestContrast = Math.abs(calculateContrast(darkContrastParams).contrast);
|
|
134
|
+
return isHighestContrast
|
|
135
|
+
? lightestContrast > darkestContrast
|
|
136
|
+
? lightestColorString
|
|
137
|
+
: darkestColorString
|
|
138
|
+
: lightestContrast < darkestContrast
|
|
139
|
+
? lightestColorString
|
|
140
|
+
: darkestColorString;
|
|
141
|
+
}
|
|
93
142
|
function findColorWithPreference(colors, desiredContrastLevel, preference,
|
|
94
143
|
/** Pre-computed contrast-against-white values per color string. Higher = darker. */
|
|
95
144
|
lightnessProxies) {
|
|
@@ -140,6 +189,11 @@ export function buildColorTheme(colorPalette, { omittedColorValues = defaultOmit
|
|
|
140
189
|
const lightThemeColors = {};
|
|
141
190
|
const darkThemeOverrides = {};
|
|
142
191
|
// Compute these once outside the loop since they don't change
|
|
192
|
+
const allContrastLevels = [
|
|
193
|
+
ExtremeContrastLevel.HighestContrast,
|
|
194
|
+
...contrastLevels,
|
|
195
|
+
ExtremeContrastLevel.LowestContrast,
|
|
196
|
+
];
|
|
143
197
|
const allCrosses = crossProduct({
|
|
144
198
|
crossWith: [
|
|
145
199
|
'color-in-foreground-light-mode',
|
|
@@ -151,7 +205,7 @@ export function buildColorTheme(colorPalette, { omittedColorValues = defaultOmit
|
|
|
151
205
|
'color-on-self-light-mode',
|
|
152
206
|
'color-on-self-dark-mode',
|
|
153
207
|
],
|
|
154
|
-
contrast:
|
|
208
|
+
contrast: allContrastLevels,
|
|
155
209
|
});
|
|
156
210
|
const defaultForegroundString = noRefColorInitToString(defaultTheme.foreground);
|
|
157
211
|
const defaultBackgroundString = noRefColorInitToString(defaultTheme.background);
|
|
@@ -196,6 +250,15 @@ export function buildColorTheme(colorPalette, { omittedColorValues = defaultOmit
|
|
|
196
250
|
foreground: colorStrings,
|
|
197
251
|
background: darkestColorString,
|
|
198
252
|
}, ContrastLevelName.SmallBodyText, 'darkest', lightnessProxies), `Failed to find dark mode on-self foreground color for ${firstColor.colorName}`);
|
|
253
|
+
/**
|
|
254
|
+
* Reversed palette order for dark mode on-self backgrounds. `findColorAtContrastLevel`
|
|
255
|
+
* picks the last qualifying color in array order. With the natural lightest-to-darkest
|
|
256
|
+
* order, high-contrast backgrounds end up as the darkest palette colors, which are
|
|
257
|
+
* indistinguishable from the dark page background. Reversing the order makes it select
|
|
258
|
+
* the lightest palette color that still achieves the required contrast level, producing
|
|
259
|
+
* backgrounds that are visible against the dark page.
|
|
260
|
+
*/
|
|
261
|
+
const reversedColorStrings = colorStrings.toReversed();
|
|
199
262
|
// Pre-compute base name parts that don't change per cross
|
|
200
263
|
const baseNameParts = [
|
|
201
264
|
prefix,
|
|
@@ -215,7 +278,7 @@ export function buildColorTheme(colorPalette, { omittedColorValues = defaultOmit
|
|
|
215
278
|
: cross.crossWith === 'color-on-self-dark-mode'
|
|
216
279
|
? {
|
|
217
280
|
foreground: darkSelfFgString,
|
|
218
|
-
background:
|
|
281
|
+
background: reversedColorStrings,
|
|
219
282
|
}
|
|
220
283
|
: cross.crossWith === 'color-on-self-light-mode'
|
|
221
284
|
? {
|
|
@@ -285,7 +348,15 @@ export function buildColorTheme(colorPalette, { omittedColorValues = defaultOmit
|
|
|
285
348
|
if (!comparison) {
|
|
286
349
|
throw new Error(`Forgot to handle crossWith: '${cross.crossWith}'`);
|
|
287
350
|
}
|
|
288
|
-
const matchedColorString =
|
|
351
|
+
const matchedColorString = cross.contrast === ExtremeContrastLevel.HighestContrast ||
|
|
352
|
+
cross.contrast === ExtremeContrastLevel.LowestContrast
|
|
353
|
+
? resolveExtremeContrastColor({
|
|
354
|
+
comparison,
|
|
355
|
+
isHighestContrast: cross.contrast === ExtremeContrastLevel.HighestContrast,
|
|
356
|
+
lightestColorString,
|
|
357
|
+
darkestColorString,
|
|
358
|
+
})
|
|
359
|
+
: findColorAtContrastLevel(comparison, cross.contrast);
|
|
289
360
|
const matchedColor = matchedColorString
|
|
290
361
|
? colorByDefault[matchedColorString]
|
|
291
362
|
: undefined;
|
|
@@ -8,10 +8,10 @@ import { type BuildLowLevelColorThemeOptions, type ColorPaletteVars } from './bu
|
|
|
8
8
|
* @see `createColorThemeBookPages` for creating full color theme pages.
|
|
9
9
|
*/
|
|
10
10
|
export declare function createColorPaletteBookPages({ colors, parent, title, includeContrast, includeTheme, useVerticalTheme, options, }: {
|
|
11
|
-
parent: Readonly<BookPage>;
|
|
12
11
|
title: string;
|
|
13
12
|
colors: Readonly<ColorPaletteVars>;
|
|
14
13
|
} & PartialWithUndefined<{
|
|
14
|
+
parent: Readonly<BookPage>;
|
|
15
15
|
includeContrast: boolean;
|
|
16
16
|
includeTheme: boolean;
|
|
17
17
|
useVerticalTheme: boolean;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { check } from '@augment-vir/assert';
|
|
2
2
|
import { VirColorPair } from '@electrovir/color';
|
|
3
3
|
import { defineBookPage } from 'element-book';
|
|
4
|
-
import { css, html, unsafeCSS } from 'element-vir';
|
|
4
|
+
import { css, html, listen, unsafeCSS } from 'element-vir';
|
|
5
5
|
import { noNativeSpacing, viraTheme } from 'vira';
|
|
6
6
|
import { buildColorTheme, groupColors, } from './build-color-theme.js';
|
|
7
7
|
import { createColorThemeBookPages } from './color-theme-book-pages.js';
|
|
@@ -64,59 +64,94 @@ export function createColorPaletteBookPages({ colors, parent, title, includeCont
|
|
|
64
64
|
parent: topColorsPage,
|
|
65
65
|
title: 'Palette',
|
|
66
66
|
defineExamples({ defineExample }) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
67
|
+
defineExample({
|
|
68
|
+
title: 'All Colors',
|
|
69
|
+
styles: css `
|
|
70
|
+
:host {
|
|
71
|
+
display: flex;
|
|
72
|
+
flex-direction: row;
|
|
73
|
+
}
|
|
75
74
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
align-items: center;
|
|
75
|
+
p {
|
|
76
|
+
${noNativeSpacing}
|
|
77
|
+
}
|
|
80
78
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
79
|
+
.color-column {
|
|
80
|
+
display: flex;
|
|
81
|
+
flex-direction: column;
|
|
82
|
+
}
|
|
85
83
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
84
|
+
.column-title {
|
|
85
|
+
text-align: center;
|
|
86
|
+
font-size: 12px;
|
|
87
|
+
padding-bottom: 4px;
|
|
88
|
+
border-bottom: 1px solid
|
|
89
|
+
${viraTheme.colors['vira-grey-foreground-decoration'].foreground.value};
|
|
90
|
+
margin-bottom: 4px;
|
|
91
|
+
color: ${viraTheme.colors['vira-grey-foreground-non-body'].foreground
|
|
92
|
+
.value};
|
|
93
|
+
}
|
|
92
94
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
95
|
+
.swatch-wrapper {
|
|
96
|
+
display: flex;
|
|
97
|
+
gap: 4px;
|
|
98
|
+
align-items: center;
|
|
99
|
+
|
|
100
|
+
& .swatch {
|
|
101
|
+
width: 50px;
|
|
102
|
+
height: 50px;
|
|
103
|
+
cursor: pointer;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
& .color-details {
|
|
107
|
+
display: none;
|
|
108
|
+
font-family: monospace;
|
|
109
|
+
font-size: 12px;
|
|
110
|
+
color: ${viraTheme.colors['vira-grey-foreground-non-body'].foreground
|
|
111
|
+
.value};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
&.expanded .color-details {
|
|
115
|
+
display: block;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
& .color-value {
|
|
119
|
+
margin-left: 1ch;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
`,
|
|
123
|
+
render() {
|
|
124
|
+
return Object.entries(colorGroups).map(([groupName, colors,]) => {
|
|
125
|
+
return html `
|
|
126
|
+
<div class="color-column">
|
|
127
|
+
<p class="column-title">${groupName}</p>
|
|
128
|
+
${colors.map((color) => {
|
|
100
129
|
return html `
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
130
|
+
<div class="swatch-wrapper">
|
|
131
|
+
<div
|
|
132
|
+
class="swatch"
|
|
133
|
+
style=${css `
|
|
134
|
+
background-color: ${unsafeCSS(color.definition.default)};
|
|
135
|
+
`}
|
|
136
|
+
${listen('click', (event) => {
|
|
137
|
+
const wrapper = event.currentTarget.parentElement;
|
|
138
|
+
wrapper?.classList.toggle('expanded');
|
|
139
|
+
})}
|
|
140
|
+
></div>
|
|
141
|
+
<p class="color-details">
|
|
142
|
+
<span>${color.cssVarName}</span>
|
|
143
|
+
<br />
|
|
144
|
+
<span class="color-value">
|
|
145
|
+
${color.definition.default}
|
|
146
|
+
</span>
|
|
147
|
+
</p>
|
|
148
|
+
</div>
|
|
149
|
+
`;
|
|
150
|
+
})}
|
|
151
|
+
</div>
|
|
152
|
+
`;
|
|
153
|
+
});
|
|
154
|
+
},
|
|
120
155
|
});
|
|
121
156
|
},
|
|
122
157
|
});
|
|
@@ -214,24 +249,25 @@ export function createColorPaletteBookPages({ colors, parent, title, includeCont
|
|
|
214
249
|
};
|
|
215
250
|
}));
|
|
216
251
|
}
|
|
217
|
-
|
|
252
|
+
function createThemePages() {
|
|
253
|
+
const generatedTheme = buildColorTheme(colors, options);
|
|
254
|
+
return createColorThemeBookPages({
|
|
255
|
+
parent: topColorsPage,
|
|
256
|
+
title: 'Theme (auto)',
|
|
257
|
+
theme: generatedTheme.defaultLight,
|
|
258
|
+
hideInverseColors: true,
|
|
259
|
+
useVerticalLayout: useVerticalTheme,
|
|
260
|
+
prefixGroupByCount: 2,
|
|
261
|
+
overrides: [generatedTheme.darkOverride],
|
|
262
|
+
});
|
|
263
|
+
}
|
|
218
264
|
return [
|
|
219
265
|
topColorsPage,
|
|
220
266
|
colorPalettePage,
|
|
221
|
-
contrastsPage,
|
|
267
|
+
includeContrast ? contrastsPage : undefined,
|
|
222
268
|
includeContrast ? blackWhiteContrastPage : undefined,
|
|
223
269
|
includeContrast ? createSelfContrastPage(400) : undefined,
|
|
224
270
|
includeContrast ? createSelfContrastPage(700) : undefined,
|
|
225
|
-
...(includeTheme
|
|
226
|
-
? createColorThemeBookPages({
|
|
227
|
-
parent: topColorsPage,
|
|
228
|
-
title: 'Theme (auto)',
|
|
229
|
-
theme: generatedTheme.defaultLight,
|
|
230
|
-
hideInverseColors: true,
|
|
231
|
-
useVerticalLayout: useVerticalTheme,
|
|
232
|
-
prefixGroupByCount: 2,
|
|
233
|
-
overrides: [generatedTheme.darkOverride],
|
|
234
|
-
})
|
|
235
|
-
: []),
|
|
271
|
+
...(includeTheme ? createThemePages() : []),
|
|
236
272
|
].filter(check.isTruthy);
|
|
237
273
|
}
|