theme-vir 28.18.7 → 28.20.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/dist/color-theme/apply-color-theme.d.ts +31 -0
- package/dist/color-theme/apply-color-theme.js +94 -0
- package/dist/color-theme/build-color-theme.js +64 -31
- package/dist/color-theme/color-theme.d.ts +2 -10
- package/dist/color-theme/color-theme.js +3 -35
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +6 -6
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type ColorThemeOverride } from './color-theme-init.js';
|
|
2
|
+
import { type ColorTheme } from './color-theme.js';
|
|
3
|
+
/**
|
|
4
|
+
* Create the `<style>` id used to apply color themes globally by {@link applyGlobalColorTheme}.
|
|
5
|
+
*
|
|
6
|
+
* @category Internal
|
|
7
|
+
*/
|
|
8
|
+
export declare function createGlobalThemeStyleId(colorTheme: Readonly<ColorTheme>): string;
|
|
9
|
+
/**
|
|
10
|
+
* Create the global `<style>` element used by {@link applyGlobalColorTheme} to apply a color theme.
|
|
11
|
+
*
|
|
12
|
+
* @category Internal
|
|
13
|
+
*/
|
|
14
|
+
export declare function createGlobalThemeStyleElement(colorTheme: Readonly<ColorTheme>, context?: Element): HTMLStyleElement;
|
|
15
|
+
/**
|
|
16
|
+
* Sets all of a color theme's CSS vars in a global style element. If no override is given, the
|
|
17
|
+
* theme color default values are assigned.
|
|
18
|
+
*
|
|
19
|
+
* @category Color Theme
|
|
20
|
+
*/
|
|
21
|
+
export declare function applyGlobalColorTheme(fullTheme: ColorTheme, themeOverride?: ColorThemeOverride | undefined): void;
|
|
22
|
+
/**
|
|
23
|
+
* A very inefficient way of setting all of a color theme's CSS vars on a given element. If no
|
|
24
|
+
* override is given, the theme color default values are assigned.
|
|
25
|
+
*
|
|
26
|
+
* @deprecated Use {@link applyGlobalColorTheme} instead whenever possible.
|
|
27
|
+
* @category Internal
|
|
28
|
+
*/
|
|
29
|
+
export declare function applyColorTheme(
|
|
30
|
+
/** This should usually be the top-level `html` element. */
|
|
31
|
+
element: HTMLElement, fullTheme: ColorTheme, themeOverride?: ColorThemeOverride | undefined): void;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { camelCaseToKebabCase, getObjectTypedValues } from '@augment-vir/common';
|
|
2
|
+
import { setCssVarValue } from 'lit-css-vars';
|
|
3
|
+
/**
|
|
4
|
+
* Create the `<style>` id used to apply color themes globally by {@link applyGlobalColorTheme}.
|
|
5
|
+
*
|
|
6
|
+
* @category Internal
|
|
7
|
+
*/
|
|
8
|
+
export function createGlobalThemeStyleId(colorTheme) {
|
|
9
|
+
return [
|
|
10
|
+
camelCaseToKebabCase(colorTheme.prefix),
|
|
11
|
+
'global-theme-vir-style',
|
|
12
|
+
].join('-');
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Create the global `<style>` element used by {@link applyGlobalColorTheme} to apply a color theme.
|
|
16
|
+
*
|
|
17
|
+
* @category Internal
|
|
18
|
+
*/
|
|
19
|
+
export function createGlobalThemeStyleElement(colorTheme, context = document.head) {
|
|
20
|
+
const styleId = createGlobalThemeStyleId(colorTheme);
|
|
21
|
+
const existingElement = context.querySelector(`style#${styleId}`);
|
|
22
|
+
if (existingElement instanceof HTMLStyleElement) {
|
|
23
|
+
return existingElement;
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
const newStyleElement = globalThis.document.createElement('style');
|
|
27
|
+
newStyleElement.id = styleId;
|
|
28
|
+
context.append(newStyleElement);
|
|
29
|
+
return newStyleElement;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Sets all of a color theme's CSS vars in a global style element. If no override is given, the
|
|
34
|
+
* theme color default values are assigned.
|
|
35
|
+
*
|
|
36
|
+
* @category Color Theme
|
|
37
|
+
*/
|
|
38
|
+
export function applyGlobalColorTheme(fullTheme, themeOverride) {
|
|
39
|
+
const styleElement = createGlobalThemeStyleElement(fullTheme);
|
|
40
|
+
const cssVarDeclarations = getObjectTypedValues(fullTheme.colors).flatMap((themeColor) => {
|
|
41
|
+
return [
|
|
42
|
+
buildCssVarDeclaration({
|
|
43
|
+
layerKey: 'background',
|
|
44
|
+
themeColor,
|
|
45
|
+
themeOverride,
|
|
46
|
+
}),
|
|
47
|
+
buildCssVarDeclaration({
|
|
48
|
+
layerKey: 'foreground',
|
|
49
|
+
themeColor,
|
|
50
|
+
themeOverride,
|
|
51
|
+
}),
|
|
52
|
+
];
|
|
53
|
+
});
|
|
54
|
+
styleElement.textContent = `:root {\n ${cssVarDeclarations.join('\n ')}\n}`;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* A very inefficient way of setting all of a color theme's CSS vars on a given element. If no
|
|
58
|
+
* override is given, the theme color default values are assigned.
|
|
59
|
+
*
|
|
60
|
+
* @deprecated Use {@link applyGlobalColorTheme} instead whenever possible.
|
|
61
|
+
* @category Internal
|
|
62
|
+
*/
|
|
63
|
+
export function applyColorTheme(
|
|
64
|
+
/** This should usually be the top-level `html` element. */
|
|
65
|
+
element, fullTheme, themeOverride) {
|
|
66
|
+
getObjectTypedValues(fullTheme.colors).forEach((themeColor) => {
|
|
67
|
+
applyIndividualThemeColorValue({
|
|
68
|
+
element,
|
|
69
|
+
layerKey: 'background',
|
|
70
|
+
themeColor,
|
|
71
|
+
themeOverride,
|
|
72
|
+
});
|
|
73
|
+
applyIndividualThemeColorValue({
|
|
74
|
+
element,
|
|
75
|
+
layerKey: 'foreground',
|
|
76
|
+
themeColor,
|
|
77
|
+
themeOverride,
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
function buildCssVarDeclaration({ layerKey, themeOverride, themeColor, }) {
|
|
82
|
+
const override = themeOverride?.overrides[String(themeColor[layerKey].name)];
|
|
83
|
+
const value = override || themeColor[layerKey].default;
|
|
84
|
+
return `${themeColor[layerKey].name}: ${value};`;
|
|
85
|
+
}
|
|
86
|
+
function applyIndividualThemeColorValue({ element, layerKey, themeOverride, themeColor, }) {
|
|
87
|
+
const override = themeOverride?.overrides[String(themeColor[layerKey].name)];
|
|
88
|
+
const value = override || themeColor[layerKey].default;
|
|
89
|
+
setCssVarValue({
|
|
90
|
+
forCssVar: themeColor[layerKey],
|
|
91
|
+
onElement: element,
|
|
92
|
+
toValue: value,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
@@ -111,11 +111,13 @@ export function buildColorTheme(colorPalette, { omittedColorValues = defaultOmit
|
|
|
111
111
|
const allCrosses = crossProduct({
|
|
112
112
|
crossWith: [
|
|
113
113
|
'color-in-foreground-light-mode',
|
|
114
|
-
'color-in-background-light-mode',
|
|
115
114
|
'color-in-foreground-dark-mode',
|
|
116
|
-
'color-
|
|
117
|
-
'color-
|
|
115
|
+
'color-behind-bg-light-mode',
|
|
116
|
+
'color-behind-bg-dark-mode',
|
|
117
|
+
'color-behind-fg-light-mode',
|
|
118
|
+
'color-behind-fg-dark-mode',
|
|
118
119
|
'color-on-self-light-mode',
|
|
120
|
+
'color-on-self-dark-mode',
|
|
119
121
|
],
|
|
120
122
|
contrast: contrastLevels,
|
|
121
123
|
});
|
|
@@ -130,8 +132,10 @@ export function buildColorTheme(colorPalette, { omittedColorValues = defaultOmit
|
|
|
130
132
|
key: color.definition.default,
|
|
131
133
|
value: color,
|
|
132
134
|
}));
|
|
133
|
-
const
|
|
134
|
-
const
|
|
135
|
+
const lightestSelfString = findClosestColor('white', colorStrings);
|
|
136
|
+
const darkestSelfString = findClosestColor('black', colorStrings);
|
|
137
|
+
const lightestSelf = colorByDefault[lightestSelfString];
|
|
138
|
+
const darkestSelf = colorByDefault[darkestSelfString];
|
|
135
139
|
// Pre-compute base name parts that don't change per cross
|
|
136
140
|
const baseNameParts = [
|
|
137
141
|
prefix,
|
|
@@ -143,33 +147,43 @@ export function buildColorTheme(colorPalette, { omittedColorValues = defaultOmit
|
|
|
143
147
|
foreground: colorStrings,
|
|
144
148
|
background: defaultBackgroundString,
|
|
145
149
|
}
|
|
146
|
-
: cross.crossWith === 'color-in-
|
|
150
|
+
: cross.crossWith === 'color-in-foreground-dark-mode'
|
|
147
151
|
? {
|
|
148
|
-
foreground:
|
|
149
|
-
background:
|
|
152
|
+
foreground: colorStrings,
|
|
153
|
+
background: defaultForegroundString,
|
|
150
154
|
}
|
|
151
|
-
: cross.crossWith === 'color-
|
|
155
|
+
: cross.crossWith === 'color-on-self-dark-mode'
|
|
152
156
|
? {
|
|
153
157
|
foreground: colorStrings,
|
|
154
|
-
background:
|
|
158
|
+
background: darkestSelfString,
|
|
155
159
|
}
|
|
156
|
-
: cross.crossWith === 'color-
|
|
160
|
+
: cross.crossWith === 'color-on-self-light-mode'
|
|
157
161
|
? {
|
|
158
|
-
foreground:
|
|
159
|
-
background:
|
|
162
|
+
foreground: colorStrings,
|
|
163
|
+
background: lightestSelfString,
|
|
160
164
|
}
|
|
161
|
-
: cross.crossWith === 'color-
|
|
165
|
+
: cross.crossWith === 'color-behind-bg-light-mode'
|
|
162
166
|
? {
|
|
163
|
-
foreground:
|
|
164
|
-
background:
|
|
167
|
+
foreground: defaultBackgroundString,
|
|
168
|
+
background: colorStrings,
|
|
165
169
|
}
|
|
166
|
-
:
|
|
167
|
-
|
|
170
|
+
: cross.crossWith === 'color-behind-bg-dark-mode'
|
|
171
|
+
? {
|
|
172
|
+
foreground: defaultForegroundString,
|
|
173
|
+
background: colorStrings,
|
|
174
|
+
}
|
|
175
|
+
: cross.crossWith === 'color-behind-fg-light-mode'
|
|
168
176
|
? {
|
|
169
|
-
foreground:
|
|
170
|
-
background:
|
|
177
|
+
foreground: defaultForegroundString,
|
|
178
|
+
background: colorStrings,
|
|
171
179
|
}
|
|
172
|
-
:
|
|
180
|
+
: // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
181
|
+
cross.crossWith === 'color-behind-fg-dark-mode'
|
|
182
|
+
? {
|
|
183
|
+
foreground: defaultBackgroundString,
|
|
184
|
+
background: colorStrings,
|
|
185
|
+
}
|
|
186
|
+
: undefined;
|
|
173
187
|
if (!comparison) {
|
|
174
188
|
throw new Error(`Forgot to handle crossWith: '${cross.crossWith}'`);
|
|
175
189
|
}
|
|
@@ -181,8 +195,21 @@ export function buildColorTheme(colorPalette, { omittedColorValues = defaultOmit
|
|
|
181
195
|
log.error(`No valid '${colorGroupName}' color cross found for: ${stringify(cross)} with ${stringify(colorStrings)}`);
|
|
182
196
|
return undefined;
|
|
183
197
|
}
|
|
198
|
+
const isSelfContrast = cross.crossWith === 'color-on-self-light-mode' ||
|
|
199
|
+
cross.crossWith === 'color-on-self-dark-mode';
|
|
200
|
+
const isBehindBg = cross.crossWith === 'color-behind-bg-light-mode' ||
|
|
201
|
+
cross.crossWith === 'color-behind-bg-dark-mode';
|
|
202
|
+
const isBehindFg = cross.crossWith === 'color-behind-fg-light-mode' ||
|
|
203
|
+
cross.crossWith === 'color-behind-fg-dark-mode';
|
|
184
204
|
const colorValue = mapObjectValues(comparison, (key, value) => {
|
|
185
205
|
if (check.isString(value)) {
|
|
206
|
+
// For self-contrast modes, use the CSS var reference for the background
|
|
207
|
+
if (isSelfContrast && key === 'background') {
|
|
208
|
+
const selfColor = cross.crossWith === 'color-on-self-light-mode'
|
|
209
|
+
? lightestSelf
|
|
210
|
+
: darkestSelf;
|
|
211
|
+
return selfColor?.definition.value ?? value;
|
|
212
|
+
}
|
|
186
213
|
return value;
|
|
187
214
|
}
|
|
188
215
|
else {
|
|
@@ -190,25 +217,31 @@ export function buildColorTheme(colorPalette, { omittedColorValues = defaultOmit
|
|
|
190
217
|
}
|
|
191
218
|
});
|
|
192
219
|
const isLightMode = cross.crossWith === 'color-in-foreground-light-mode' ||
|
|
193
|
-
cross.crossWith === 'color-
|
|
194
|
-
cross.crossWith === 'color-
|
|
195
|
-
|
|
196
|
-
cross.crossWith === 'color-on-self-dark-mode';
|
|
220
|
+
cross.crossWith === 'color-on-self-light-mode' ||
|
|
221
|
+
cross.crossWith === 'color-behind-bg-light-mode' ||
|
|
222
|
+
cross.crossWith === 'color-behind-fg-light-mode';
|
|
197
223
|
const nameSuffix = isSelfContrast
|
|
198
224
|
? [
|
|
199
225
|
'on',
|
|
200
226
|
'self',
|
|
201
227
|
cross.contrast,
|
|
202
228
|
]
|
|
203
|
-
:
|
|
229
|
+
: isBehindBg
|
|
204
230
|
? [
|
|
205
|
-
'
|
|
231
|
+
'behind',
|
|
232
|
+
'bg',
|
|
206
233
|
cross.contrast,
|
|
207
234
|
]
|
|
208
|
-
:
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
235
|
+
: isBehindFg
|
|
236
|
+
? [
|
|
237
|
+
'behind',
|
|
238
|
+
'fg',
|
|
239
|
+
cross.contrast,
|
|
240
|
+
]
|
|
241
|
+
: [
|
|
242
|
+
'foreground',
|
|
243
|
+
cross.contrast,
|
|
244
|
+
];
|
|
212
245
|
const name = [
|
|
213
246
|
...baseNameParts,
|
|
214
247
|
...nameSuffix,
|
|
@@ -2,7 +2,7 @@ import { type RequiredAndNotNull, type Values } from '@augment-vir/common';
|
|
|
2
2
|
import { CSSResult } from 'element-vir';
|
|
3
3
|
import { type CssVarName, type SingleCssVarDefinition } from 'lit-css-vars';
|
|
4
4
|
import { type RequireAtLeastOne } from 'type-fest';
|
|
5
|
-
import { type ColorInit, type ColorInitReference, type ColorInitValue, type ColorThemeInit
|
|
5
|
+
import { type ColorInit, type ColorInitReference, type ColorInitValue, type ColorThemeInit } from './color-theme-init.js';
|
|
6
6
|
/**
|
|
7
7
|
* Same as {@link ColorInit} but without references.
|
|
8
8
|
*
|
|
@@ -40,6 +40,7 @@ export type ColorTheme<Init extends ColorThemeInit = ColorThemeInit> = {
|
|
|
40
40
|
colors: Init;
|
|
41
41
|
default: Readonly<DefaultColorThemeInit>;
|
|
42
42
|
};
|
|
43
|
+
prefix: string;
|
|
43
44
|
};
|
|
44
45
|
/**
|
|
45
46
|
* All colors within a {@link ColorTheme}.
|
|
@@ -74,15 +75,6 @@ export type DefaultColorThemeInit = RequiredAndNotNull<NoRefColorInit> & {
|
|
|
74
75
|
* @category Internal
|
|
75
76
|
*/
|
|
76
77
|
export declare const themeDefaultKey = "theme-default";
|
|
77
|
-
/**
|
|
78
|
-
* Set all color theme CSS vars on the given element. If no override is given, the theme color
|
|
79
|
-
* default values are assigned.
|
|
80
|
-
*
|
|
81
|
-
* @category Color Theme
|
|
82
|
-
*/
|
|
83
|
-
export declare function applyColorTheme<const Theme extends ColorTheme>(
|
|
84
|
-
/** This should usually be the top-level `html` element. */
|
|
85
|
-
element: HTMLElement, fullTheme: Theme, themeOverride?: ColorThemeOverride | undefined): void;
|
|
86
78
|
/**
|
|
87
79
|
* Define a color theme.
|
|
88
80
|
*
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { assert, check } from '@augment-vir/assert';
|
|
2
|
-
import { getObjectTypedEntries,
|
|
2
|
+
import { getObjectTypedEntries, log, } from '@augment-vir/common';
|
|
3
3
|
import { CSSResult } from 'element-vir';
|
|
4
|
-
import { defineCssVars,
|
|
4
|
+
import { defineCssVars, } from 'lit-css-vars';
|
|
5
5
|
/** @category Internal */
|
|
6
6
|
export function noRefColorInitToString(init) {
|
|
7
7
|
if (check.isPrimitive(init) || init instanceof CSSResult) {
|
|
@@ -57,39 +57,6 @@ export function createColorCssVarDefault(fromName, init, defaultInit, colorsInit
|
|
|
57
57
|
* @category Internal
|
|
58
58
|
*/
|
|
59
59
|
export const themeDefaultKey = 'theme-default';
|
|
60
|
-
/**
|
|
61
|
-
* Set all color theme CSS vars on the given element. If no override is given, the theme color
|
|
62
|
-
* default values are assigned.
|
|
63
|
-
*
|
|
64
|
-
* @category Color Theme
|
|
65
|
-
*/
|
|
66
|
-
export function applyColorTheme(
|
|
67
|
-
/** This should usually be the top-level `html` element. */
|
|
68
|
-
element, fullTheme, themeOverride) {
|
|
69
|
-
getObjectTypedValues(fullTheme.colors).forEach((themeColor) => {
|
|
70
|
-
applyIndividualThemeColorValue({
|
|
71
|
-
element,
|
|
72
|
-
layerKey: 'background',
|
|
73
|
-
themeColor,
|
|
74
|
-
themeOverride,
|
|
75
|
-
});
|
|
76
|
-
applyIndividualThemeColorValue({
|
|
77
|
-
element,
|
|
78
|
-
layerKey: 'foreground',
|
|
79
|
-
themeColor,
|
|
80
|
-
themeOverride,
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
function applyIndividualThemeColorValue({ element, layerKey, themeOverride, themeColor, }) {
|
|
85
|
-
const override = themeOverride?.overrides[String(themeColor[layerKey].name)];
|
|
86
|
-
const value = override || themeColor[layerKey].default;
|
|
87
|
-
setCssVarValue({
|
|
88
|
-
forCssVar: themeColor[layerKey],
|
|
89
|
-
onElement: element,
|
|
90
|
-
toValue: value,
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
60
|
/**
|
|
94
61
|
* Define a color theme.
|
|
95
62
|
*
|
|
@@ -193,6 +160,7 @@ export function defineColorTheme(defaultInit, allColorsInit) {
|
|
|
193
160
|
colors: allColorsInit,
|
|
194
161
|
default: defaultInit,
|
|
195
162
|
},
|
|
163
|
+
prefix: defaultInit.prefix,
|
|
196
164
|
};
|
|
197
165
|
}
|
|
198
166
|
catch (error) {
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "theme-vir",
|
|
3
|
-
"version": "28.
|
|
3
|
+
"version": "28.20.0",
|
|
4
4
|
"description": "Create an entire web theme.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"design",
|
|
@@ -43,15 +43,15 @@
|
|
|
43
43
|
"test:update": "virmator test web update"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@augment-vir/assert": "^31.59.
|
|
47
|
-
"@augment-vir/common": "^31.59.
|
|
46
|
+
"@augment-vir/assert": "^31.59.2",
|
|
47
|
+
"@augment-vir/common": "^31.59.2",
|
|
48
48
|
"@electrovir/color": "^1.7.8",
|
|
49
49
|
"apca-w3": "^0.1.9",
|
|
50
50
|
"lit-css-vars": "^3.4.0",
|
|
51
51
|
"type-fest": "^5.4.1"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@augment-vir/test": "^31.59.
|
|
54
|
+
"@augment-vir/test": "^31.59.2",
|
|
55
55
|
"@types/apca-w3": "^0.1.3",
|
|
56
56
|
"@web/dev-server-esbuild": "^1.0.4",
|
|
57
57
|
"@web/test-runner": "^0.20.2",
|
|
@@ -60,12 +60,12 @@
|
|
|
60
60
|
"@web/test-runner-visual-regression": "^0.10.0",
|
|
61
61
|
"element-book": "^26.16.0",
|
|
62
62
|
"element-vir": "^26.14.3",
|
|
63
|
-
"esbuild": "^0.27.
|
|
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.16",
|
|
67
67
|
"typescript": "5.9.3",
|
|
68
|
-
"vira": "^29.
|
|
68
|
+
"vira": "^29.3.0",
|
|
69
69
|
"vite": "^7.3.1",
|
|
70
70
|
"vite-tsconfig-paths": "^6.0.5"
|
|
71
71
|
},
|