theme-vir 28.16.1 → 28.17.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,7 +43,7 @@ export declare const defaultLightThemePair: RequiredAndNotNull<NoRefColorInit>;
43
43
  /** @category Internal */
44
44
  export declare const defaultContrastLevels: Readonly<ArrayOrSelectParam<ContrastLevelName>>;
45
45
  /**
46
- * Options for {@link buildLowLevelColorTheme}.
46
+ * Options for {@link buildColorTheme}.
47
47
  *
48
48
  * @category Internal
49
49
  */
@@ -74,8 +74,8 @@ export type BuildLowLevelColorThemeOptions = PartialWithUndefined<{
74
74
  *
75
75
  * @category Color Theme
76
76
  */
77
- export declare function buildLowLevelColorTheme(colorPalette: Readonly<ColorPaletteVars>, { defaultTheme, omittedColorValues, crossContrastLevels, }?: Readonly<BuildLowLevelColorThemeOptions>): import("./color-theme.js").ColorTheme<{
78
- [k: string]: ((Required<Pick<{
77
+ export declare function buildColorTheme(colorPalette: Readonly<ColorPaletteVars>, { omittedColorValues, crossContrastLevels, }?: Readonly<BuildLowLevelColorThemeOptions>): {
78
+ defaultLight: import("./color-theme.js").ColorTheme<Record<`${Lowercase<string>}-${Lowercase<string>}`, ((Required<Pick<{
79
79
  foreground: import("./color-theme.js").ColorInitValue;
80
80
  background: import("./color-theme.js").ColorInitValue;
81
81
  }, "foreground">> & Partial<Pick<{
@@ -87,5 +87,18 @@ export declare function buildLowLevelColorTheme(colorPalette: Readonly<ColorPale
87
87
  }, "background">> & Partial<Pick<{
88
88
  foreground: import("./color-theme.js").ColorInitValue;
89
89
  background: import("./color-theme.js").ColorInitValue;
90
- }, "foreground">>)) & {};
91
- }>;
90
+ }, "foreground">>)) & {}>>;
91
+ darkOverride: import("./color-theme-override.js").ColorThemeOverride<Record<`${Lowercase<string>}-${Lowercase<string>}`, ((Required<Pick<{
92
+ foreground: import("./color-theme.js").ColorInitValue;
93
+ background: import("./color-theme.js").ColorInitValue;
94
+ }, "foreground">> & Partial<Pick<{
95
+ foreground: import("./color-theme.js").ColorInitValue;
96
+ background: import("./color-theme.js").ColorInitValue;
97
+ }, "background">>) | (Required<Pick<{
98
+ foreground: import("./color-theme.js").ColorInitValue;
99
+ background: import("./color-theme.js").ColorInitValue;
100
+ }, "background">> & Partial<Pick<{
101
+ foreground: import("./color-theme.js").ColorInitValue;
102
+ background: import("./color-theme.js").ColorInitValue;
103
+ }, "foreground">>)) & {}>>;
104
+ };
@@ -1,6 +1,7 @@
1
1
  import { assert, assertWrap, check } from '@augment-vir/assert';
2
2
  import { crossProduct, filterMap, getOrSet, log, mapObjectValues, removeDuplicates, stringify, } from '@augment-vir/common';
3
3
  import { ContrastLevelName, contrastLevelLabel, findClosestColor, findColorAtContrastLevel, } from '@electrovir/color';
4
+ import { defineColorThemeOverride } from './color-theme-override.js';
4
5
  import { defineColorTheme, noRefColorInitToString, } from './color-theme.js';
5
6
  /**
6
7
  * Black and white color values.
@@ -99,22 +100,28 @@ export const defaultContrastLevels = {
99
100
  *
100
101
  * @category Color Theme
101
102
  */
102
- export function buildLowLevelColorTheme(colorPalette, { defaultTheme = defaultLightThemePair, omittedColorValues = defaultOmittedColorGroupColorValues, crossContrastLevels = defaultContrastLevels, } = {}) {
103
+ export function buildColorTheme(colorPalette, { omittedColorValues = defaultOmittedColorGroupColorValues, crossContrastLevels = defaultContrastLevels, } = {}) {
103
104
  const contrastLevels = extractParam(crossContrastLevels, {
104
105
  mapFrom: contrastLevelLabel,
105
106
  });
106
107
  const colorGroups = groupColors(colorPalette, omittedColorValues);
107
- const themeColors = Object.fromEntries(Object.entries(colorGroups).flatMap(([colorGroupName, colors,]) => {
108
+ const defaultTheme = {
109
+ background: 'white',
110
+ foreground: 'black',
111
+ };
112
+ const lightThemeColors = {};
113
+ const darkThemeOverrides = {};
114
+ Object.entries(colorGroups).forEach(([colorGroupName, colors,]) => {
108
115
  assert.isLengthAtLeast(colors, 1);
109
116
  const colorStrings = colors.map((color) => color.definition.default);
110
117
  const allCrosses = crossProduct({
111
118
  crossWith: [
112
- 'ahead-background',
113
- 'behind-background',
114
- 'ahead-foreground',
115
- 'behind-foreground',
116
- 'self-light-front',
117
- 'self-light-back',
119
+ 'color-in-foreground-light-mode',
120
+ 'color-in-background-light-mode',
121
+ 'color-in-foreground-dark-mode',
122
+ 'color-in-background-dark-mode',
123
+ 'color-on-self-dark-mode',
124
+ 'color-on-self-light-mode',
118
125
  ],
119
126
  contrast: contrastLevels,
120
127
  // fontWeight: fontWeights,
@@ -123,61 +130,129 @@ export function buildLowLevelColorTheme(colorPalette, { defaultTheme = defaultLi
123
130
  const defaultForegroundString = noRefColorInitToString(defaultTheme.foreground);
124
131
  const defaultBackgroundString = noRefColorInitToString(defaultTheme.background);
125
132
  const lightestSelf = findClosestColor('white', colorStrings);
126
- return filterMap(allCrosses, (cross) => {
127
- const crossName = [
128
- firstColor.prefix,
129
- firstColor.colorName,
130
- cross.crossWith,
131
- cross.contrast,
132
- // cross.fontWeight,
133
- ].join('-');
134
- const comparison = cross.crossWith === 'ahead-background'
133
+ const darkestSelf = findClosestColor('black', colorStrings);
134
+ allCrosses.forEach((cross) => {
135
+ const comparison = cross.crossWith === 'color-in-foreground-light-mode'
135
136
  ? {
136
137
  foreground: colorStrings,
137
138
  background: defaultBackgroundString,
138
139
  }
139
- : cross.crossWith === 'behind-background'
140
+ : cross.crossWith === 'color-in-background-light-mode'
140
141
  ? {
141
142
  foreground: defaultBackgroundString,
142
143
  background: colorStrings,
143
144
  }
144
- : cross.crossWith === 'ahead-foreground'
145
+ : cross.crossWith === 'color-in-foreground-dark-mode'
145
146
  ? {
146
147
  foreground: colorStrings,
147
148
  background: defaultForegroundString,
148
149
  }
149
- : cross.crossWith === 'behind-foreground'
150
+ : cross.crossWith === 'color-in-background-dark-mode'
150
151
  ? {
151
152
  foreground: defaultForegroundString,
152
153
  background: colorStrings,
153
154
  }
154
- : cross.crossWith === 'self-light-back'
155
+ : cross.crossWith === 'color-on-self-dark-mode'
155
156
  ? {
156
157
  foreground: colorStrings,
157
- background: lightestSelf,
158
+ background: darkestSelf,
158
159
  }
159
- : {
160
- foreground: lightestSelf,
161
- background: colorStrings,
162
- };
160
+ : // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
161
+ cross.crossWith === 'color-on-self-light-mode'
162
+ ? {
163
+ foreground: colorStrings,
164
+ background: lightestSelf,
165
+ }
166
+ : undefined;
167
+ if (!comparison) {
168
+ throw new Error(`Forgot to handle crossWith: '${cross.crossWith}'`);
169
+ }
163
170
  const matchedColorString = findColorAtContrastLevel(comparison, cross.contrast);
164
171
  const matchedColor = colors.find((color) => color.definition.default === matchedColorString);
165
172
  if (!matchedColor) {
166
173
  log.error(`No valid '${colorGroupName}' color cross found for: ${stringify(cross)} with ${stringify(colorStrings)}`);
167
174
  return undefined;
168
175
  }
169
- return [
170
- crossName,
171
- mapObjectValues(comparison, (key, value) => {
172
- if (check.isString(value)) {
173
- return value;
174
- }
175
- else {
176
- return matchedColor.definition.value;
177
- }
178
- }),
179
- ];
180
- }, check.isTruthy);
181
- }));
182
- return defineColorTheme(defaultTheme, themeColors);
176
+ const colorValue = mapObjectValues(comparison, (key, value) => {
177
+ if (check.isString(value)) {
178
+ return value;
179
+ }
180
+ else {
181
+ return matchedColor.definition.value;
182
+ }
183
+ });
184
+ if (cross.crossWith === 'color-in-foreground-light-mode') {
185
+ const name = [
186
+ firstColor.prefix,
187
+ firstColor.colorName,
188
+ 'foreground',
189
+ cross.contrast,
190
+ ].join('-');
191
+ lightThemeColors[name] = colorValue;
192
+ }
193
+ else if (cross.crossWith === 'color-in-background-light-mode') {
194
+ const name = [
195
+ firstColor.prefix,
196
+ firstColor.colorName,
197
+ 'background',
198
+ cross.contrast,
199
+ ].join('-');
200
+ lightThemeColors[name] = colorValue;
201
+ }
202
+ else if (cross.crossWith === 'color-on-self-light-mode') {
203
+ const name = [
204
+ firstColor.prefix,
205
+ firstColor.colorName,
206
+ 'on',
207
+ 'self',
208
+ cross.contrast,
209
+ ].join('-');
210
+ lightThemeColors[name] = colorValue;
211
+ }
212
+ else if (cross.crossWith === 'color-in-foreground-dark-mode') {
213
+ const name = [
214
+ firstColor.prefix,
215
+ firstColor.colorName,
216
+ 'foreground',
217
+ cross.contrast,
218
+ ].join('-');
219
+ darkThemeOverrides[name] = colorValue;
220
+ }
221
+ else if (cross.crossWith === 'color-in-background-dark-mode') {
222
+ const name = [
223
+ firstColor.prefix,
224
+ firstColor.colorName,
225
+ 'background',
226
+ cross.contrast,
227
+ ].join('-');
228
+ darkThemeOverrides[name] = colorValue;
229
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
230
+ }
231
+ else if (cross.crossWith === 'color-on-self-dark-mode') {
232
+ const name = [
233
+ firstColor.prefix,
234
+ firstColor.colorName,
235
+ 'on',
236
+ 'self',
237
+ cross.contrast,
238
+ ].join('-');
239
+ darkThemeOverrides[name] = colorValue;
240
+ }
241
+ else {
242
+ assert.tsType(cross.crossWith).equals();
243
+ throw new Error(`crossWith not handled: ${String(cross.crossWith)}`);
244
+ }
245
+ });
246
+ });
247
+ const defaultLightTheme = defineColorTheme(defaultTheme, lightThemeColors);
248
+ return {
249
+ defaultLight: defaultLightTheme,
250
+ darkOverride: defineColorThemeOverride(defaultLightTheme, 'dark', {
251
+ defaultOverride: {
252
+ background: 'black',
253
+ foreground: 'white',
254
+ },
255
+ colorOverrides: darkThemeOverrides,
256
+ }),
257
+ };
183
258
  }
@@ -3,7 +3,7 @@ import { VirColorPair } from '@electrovir/color';
3
3
  import { defineBookPage } from 'element-book';
4
4
  import { css, html, unsafeCSS } from 'element-vir';
5
5
  import { noNativeSpacing, viraColorPalette } from 'vira';
6
- import { buildLowLevelColorTheme, groupColors, } from './build-color-theme.js';
6
+ import { buildColorTheme, groupColors, } from './build-color-theme.js';
7
7
  import { createColorThemeBookPages } from './color-theme-book-pages.js';
8
8
  const blackWhiteCells = [
9
9
  {
@@ -211,6 +211,7 @@ export function createColorPaletteBookPages({ colors, parent, title, includeCont
211
211
  };
212
212
  }));
213
213
  }
214
+ const generatedTheme = buildColorTheme(colors, options);
214
215
  return [
215
216
  topColorsPage,
216
217
  colorPalettePage,
@@ -222,10 +223,11 @@ export function createColorPaletteBookPages({ colors, parent, title, includeCont
222
223
  ? createColorThemeBookPages({
223
224
  parent: topColorsPage,
224
225
  title: 'Theme (auto)',
225
- theme: buildLowLevelColorTheme(colors, options),
226
+ theme: generatedTheme.defaultLight,
226
227
  hideInverseColors: true,
227
228
  useVerticalLayout: useVerticalTheme,
228
229
  prefixGroupByCount: 2,
230
+ overrides: [generatedTheme.darkOverride],
229
231
  })
230
232
  : []),
231
233
  ].filter(check.isTruthy);
@@ -3,13 +3,14 @@ import { groupArrayBy } from '@augment-vir/common';
3
3
  import { VirColorPair } from '@electrovir/color';
4
4
  import { BookPageControlType, defineBookPage, definePageControl, } from 'element-book';
5
5
  import { css, html, listen, nothing } from 'element-vir';
6
- import { generateThemeCode } from './color-theme.js';
6
+ import { generateThemeCode } from './color-theme-code.js';
7
+ const noneOverridesSelectionValue = 'None';
7
8
  /**
8
9
  * Create multiple element-book pages to showcase a theme its overrides (if any).
9
10
  *
10
11
  * @category Color Theme
11
12
  */
12
- export function createColorThemeBookPages({ parent, title, theme, hideInverseColors, overrides, useVerticalLayout, prefixGroupByCount = 0, }) {
13
+ export function createColorThemeBookPages({ parent, title, theme, hideInverseColors, overrides, useVerticalLayout, prefixGroupByCount = 2, }) {
13
14
  const themeControls = {
14
15
  'Show Var Names': definePageControl({
15
16
  controlType: BookPageControlType.Checkbox,
@@ -20,6 +21,21 @@ export function createColorThemeBookPages({ parent, title, theme, hideInverseCol
20
21
  initValue: true,
21
22
  }),
22
23
  };
24
+ const defaultThemeControls = {
25
+ 'Theme Override': definePageControl({
26
+ controlType: BookPageControlType.Dropdown,
27
+ initValue: noneOverridesSelectionValue,
28
+ options: [
29
+ noneOverridesSelectionValue,
30
+ ...(overrides || []).map((override) => {
31
+ if (override.name === noneOverridesSelectionValue) {
32
+ throw new Error(`Cannot have theme override named '${noneOverridesSelectionValue}'`);
33
+ }
34
+ return override.name;
35
+ }),
36
+ ],
37
+ }),
38
+ };
23
39
  const themeParentPage = defineBookPage({
24
40
  parent,
25
41
  title,
@@ -60,8 +76,8 @@ export function createColorThemeBookPages({ parent, title, theme, hideInverseCol
60
76
  <div class="with-inverse">${normalTemplate}${inverseTemplate}</div>
61
77
  `;
62
78
  }
63
- function createThemePageExamples(defineExample, theme) {
64
- const groups = groupArrayBy(Object.keys(theme.colors), (value) => {
79
+ function createThemePageExamples(defineExample, defaultTheme, overrides) {
80
+ const groups = groupArrayBy(Object.keys(defaultTheme.colors), (value) => {
65
81
  if (prefixGroupByCount) {
66
82
  return value.split('-').slice(0, prefixGroupByCount).join('-');
67
83
  }
@@ -89,9 +105,13 @@ export function createColorThemeBookPages({ parent, title, theme, hideInverseCol
89
105
  }
90
106
  `,
91
107
  render({ controls }) {
108
+ const selectedOverride = ('Theme Override' in controls &&
109
+ controls['Theme Override'] &&
110
+ overrides?.find((override) => override.name === controls['Theme Override'])) ||
111
+ undefined;
92
112
  return group.map((entry) => buildThemeColorTemplate({
93
113
  controls,
94
- theme,
114
+ theme: selectedOverride?.asTheme || defaultTheme,
95
115
  themeColorName: entry,
96
116
  }));
97
117
  },
@@ -103,7 +123,7 @@ export function createColorThemeBookPages({ parent, title, theme, hideInverseCol
103
123
  ];
104
124
  const defaultThemePage = defineBookPage({
105
125
  parent: themeParentPage,
106
- title: 'Default Theme',
126
+ title: 'Default',
107
127
  descriptionParagraphs,
108
128
  useVerticalExamples: useVerticalLayout,
109
129
  controls: {
@@ -112,7 +132,10 @@ export function createColorThemeBookPages({ parent, title, theme, hideInverseCol
112
132
  content: html `
113
133
  <button
114
134
  ${listen('click', async () => {
115
- const code = generateThemeCode(theme, 'viraColorPalette');
135
+ const code = generateThemeCode(theme, {
136
+ paletteVarName: 'viraColorPalette',
137
+ overrides,
138
+ });
116
139
  await navigator.clipboard.writeText(code);
117
140
  })}
118
141
  >
@@ -120,9 +143,10 @@ export function createColorThemeBookPages({ parent, title, theme, hideInverseCol
120
143
  </button>
121
144
  `,
122
145
  }),
146
+ ...defaultThemeControls,
123
147
  },
124
148
  defineExamples({ defineExample }) {
125
- createThemePageExamples(defineExample, theme);
149
+ createThemePageExamples(defineExample, theme, overrides);
126
150
  },
127
151
  });
128
152
  const overridePages = (overrides || []).map((override) => {
@@ -132,7 +156,7 @@ export function createColorThemeBookPages({ parent, title, theme, hideInverseCol
132
156
  useVerticalExamples: useVerticalLayout,
133
157
  descriptionParagraphs,
134
158
  defineExamples({ defineExample }) {
135
- createThemePageExamples(defineExample, override.asTheme);
159
+ createThemePageExamples(defineExample, override.asTheme, undefined);
136
160
  },
137
161
  });
138
162
  });
@@ -0,0 +1,12 @@
1
+ import { type PartialWithUndefined } from '@augment-vir/common';
2
+ import { type ColorThemeOverride } from './color-theme-override.js';
3
+ import { type ColorTheme } from './color-theme.js';
4
+ /**
5
+ * Convert a color theme into code to define that color theme.
6
+ *
7
+ * @category Color Theme
8
+ */
9
+ export declare function generateThemeCode(theme: ColorTheme, options?: Readonly<PartialWithUndefined<{
10
+ paletteVarName: string;
11
+ overrides: ReadonlyArray<Readonly<ColorThemeOverride>>;
12
+ }>>): string;
@@ -0,0 +1,150 @@
1
+ import { getObjectTypedEntries, } from '@augment-vir/common';
2
+ /**
3
+ * Convert a color theme into code to define that color theme.
4
+ *
5
+ * @category Color Theme
6
+ */
7
+ export function generateThemeCode(theme, options) {
8
+ const paletteVarName = options?.paletteVarName;
9
+ const defaultInitCode = colorInitToCode(theme.init.default, 1, undefined, paletteVarName);
10
+ const colorsInitCode = colorThemeInitToCode(theme.init.colors, 1, theme.init.default, paletteVarName);
11
+ const themeCode = `const theme = defineColorTheme(\n${defaultInitCode},\n${colorsInitCode},\n);`;
12
+ const overridesCodes = (options?.overrides || []).map((override) => {
13
+ return generateOverrideCode(override, paletteVarName);
14
+ });
15
+ return [
16
+ themeCode,
17
+ ...overridesCodes,
18
+ ].join('\n\n');
19
+ }
20
+ function generateOverrideCode(override, paletteVarName) {
21
+ const parts = [];
22
+ // Check if default colors differ
23
+ const defaultOverrideEntries = [];
24
+ if (!colorInitValuesEqual(override.asTheme.init.default.foreground, override.originalTheme.init.default.foreground)) {
25
+ defaultOverrideEntries.push(`${tab(3)}foreground: ${colorInitValueToCode(override.asTheme.init.default.foreground, 3, paletteVarName)},`);
26
+ }
27
+ if (!colorInitValuesEqual(override.asTheme.init.default.background, override.originalTheme.init.default.background)) {
28
+ defaultOverrideEntries.push(`${tab(3)}background: ${colorInitValueToCode(override.asTheme.init.default.background, 3, paletteVarName)},`);
29
+ }
30
+ if (defaultOverrideEntries.length > 0) {
31
+ parts.push(`${tab(2)}defaultOverride: {\n${defaultOverrideEntries.join('\n')}\n${tab(2)}},`);
32
+ }
33
+ // Check for color overrides
34
+ const colorOverrideEntries = [];
35
+ getObjectTypedEntries(override.asTheme.init.colors).forEach(([colorName, colorInit,]) => {
36
+ const originalColorInit = override.originalTheme.init.colors[colorName];
37
+ if (!originalColorInit) {
38
+ return;
39
+ }
40
+ const colorEntries = [];
41
+ if ('foreground' in colorInit &&
42
+ (!('foreground' in originalColorInit) ||
43
+ !colorInitValuesEqual(colorInit.foreground, originalColorInit.foreground))) {
44
+ colorEntries.push(`${tab(4)}foreground: ${colorInitValueToCode(colorInit.foreground, 4, paletteVarName)},`);
45
+ }
46
+ if ('background' in colorInit &&
47
+ (!('background' in originalColorInit) ||
48
+ !colorInitValuesEqual(colorInit.background, originalColorInit.background))) {
49
+ colorEntries.push(`${tab(4)}background: ${colorInitValueToCode(colorInit.background, 4, paletteVarName)},`);
50
+ }
51
+ if (colorEntries.length > 0) {
52
+ colorOverrideEntries.push(`${tab(3)}'${colorName}': {\n${colorEntries.join('\n')}\n${tab(3)}},`);
53
+ }
54
+ });
55
+ if (colorOverrideEntries.length > 0) {
56
+ parts.push(`${tab(2)}colorOverrides: {\n${colorOverrideEntries.join('\n')}\n${tab(2)}},`);
57
+ }
58
+ return `const ${override.name}Override = defineColorThemeOverride(\n${tab(1)}theme,\n${tab(1)}'${override.name}',\n${tab(1)}{\n${parts.join('\n')}\n${tab(1)}},\n);`;
59
+ }
60
+ function tab(level) {
61
+ return ' '.repeat(level);
62
+ }
63
+ function colorInitValuesEqual(a, b) {
64
+ if (typeof a !== typeof b) {
65
+ return false;
66
+ }
67
+ if (typeof a === 'string' || typeof a === 'number') {
68
+ return a === b;
69
+ }
70
+ if ('_$cssResult$' in a && '_$cssResult$' in b) {
71
+ return a.cssText === b.cssText;
72
+ }
73
+ // For references and SingleCssVarDefinition, compare as JSON
74
+ return JSON.stringify(a) === JSON.stringify(b);
75
+ }
76
+ function extractCssVarName(cssValue) {
77
+ const match = cssValue.match(/^var\(--([^,)]+)/);
78
+ return match ? match[1] : undefined;
79
+ }
80
+ function colorInitValueToCode(value, indentLevel, paletteVarName) {
81
+ if (typeof value === 'string') {
82
+ return `'${value}'`;
83
+ }
84
+ else if (typeof value === 'number') {
85
+ return String(value);
86
+ }
87
+ else if ('_$cssResult$' in value) {
88
+ const cssText = String(value);
89
+ if (paletteVarName) {
90
+ const varName = extractCssVarName(cssText);
91
+ if (varName) {
92
+ return `${paletteVarName}['${varName}']`;
93
+ }
94
+ }
95
+ return `css\`${cssText}\``;
96
+ }
97
+ else if ('refBackground' in value ||
98
+ 'refForeground' in value ||
99
+ 'refDefaultBackground' in value ||
100
+ 'refDefaultForeground' in value) {
101
+ const entries = [];
102
+ if ('refForeground' in value) {
103
+ entries.push(`${tab(indentLevel + 1)}refForeground: '${value.refForeground}',`);
104
+ }
105
+ if ('refBackground' in value) {
106
+ entries.push(`${tab(indentLevel + 1)}refBackground: '${value.refBackground}',`);
107
+ }
108
+ if ('refDefaultForeground' in value) {
109
+ entries.push(`${tab(indentLevel + 1)}refDefaultForeground: true,`);
110
+ }
111
+ if ('refDefaultBackground' in value) {
112
+ entries.push(`${tab(indentLevel + 1)}refDefaultBackground: true,`);
113
+ }
114
+ return `{\n${entries.join('\n')}\n${tab(indentLevel)}}`;
115
+ }
116
+ else {
117
+ // SingleCssVarDefinition
118
+ return `'${value.default}'`;
119
+ }
120
+ }
121
+ function colorInitToCode(colorInit, indentLevel, defaultInit, paletteVarName) {
122
+ const entries = [];
123
+ if ('foreground' in colorInit &&
124
+ (!defaultInit || !colorInitValuesEqual(colorInit.foreground, defaultInit.foreground))) {
125
+ // Check if foreground matches default background (use refDefaultBackground)
126
+ if (defaultInit && colorInitValuesEqual(colorInit.foreground, defaultInit.background)) {
127
+ entries.push(`${tab(indentLevel + 1)}foreground: {\n${tab(indentLevel + 2)}refDefaultBackground: true,\n${tab(indentLevel + 1)}},`);
128
+ }
129
+ else {
130
+ entries.push(`${tab(indentLevel + 1)}foreground: ${colorInitValueToCode(colorInit.foreground, indentLevel + 1, paletteVarName)},`);
131
+ }
132
+ }
133
+ if ('background' in colorInit &&
134
+ (!defaultInit || !colorInitValuesEqual(colorInit.background, defaultInit.background))) {
135
+ // Check if background matches default foreground (use refDefaultForeground)
136
+ if (defaultInit && colorInitValuesEqual(colorInit.background, defaultInit.foreground)) {
137
+ entries.push(`${tab(indentLevel + 1)}background: {\n${tab(indentLevel + 2)}refDefaultForeground: true,\n${tab(indentLevel + 1)}},`);
138
+ }
139
+ else {
140
+ entries.push(`${tab(indentLevel + 1)}background: ${colorInitValueToCode(colorInit.background, indentLevel + 1, paletteVarName)},`);
141
+ }
142
+ }
143
+ return `${tab(indentLevel)}{\n${entries.join('\n')}\n${tab(indentLevel)}}`;
144
+ }
145
+ function colorThemeInitToCode(colorsInit, indentLevel, defaultInit, paletteVarName) {
146
+ const entries = getObjectTypedEntries(colorsInit).map(([colorName, colorInit,]) => {
147
+ return `${tab(indentLevel + 1)}'${colorName}': ${colorInitToCode(colorInit, indentLevel + 1, defaultInit, paletteVarName).trimStart()},`;
148
+ });
149
+ return `${tab(indentLevel)}{\n${entries.join('\n')}\n${tab(indentLevel)}}`;
150
+ }
@@ -103,9 +103,3 @@ export declare const themeDefaultKey = "theme-default";
103
103
  * @category Color Theme
104
104
  */
105
105
  export declare function defineColorTheme<const Init extends ColorThemeInit>(defaultInit: RequiredAndNotNull<NoRefColorInit>, allColorsInit: Init): ColorTheme<Init>;
106
- /**
107
- * Convert a color theme into code to define that color theme.
108
- *
109
- * @category Color Theme
110
- */
111
- export declare function generateThemeCode(theme: ColorTheme, paletteVarName?: string | undefined): string;
@@ -175,104 +175,3 @@ function createCssVarNames(colorName) {
175
175
  ].join('-'),
176
176
  };
177
177
  }
178
- /**
179
- * Convert a color theme into code to define that color theme.
180
- *
181
- * @category Color Theme
182
- */
183
- export function generateThemeCode(theme, paletteVarName) {
184
- const defaultInitCode = colorInitToCode(theme.init.default, 1, undefined, paletteVarName);
185
- const colorsInitCode = colorThemeInitToCode(theme.init.colors, 1, theme.init.default, paletteVarName);
186
- return `defineColorTheme(\n${defaultInitCode},\n${colorsInitCode},\n)`;
187
- }
188
- function tab(level) {
189
- return ' '.repeat(level);
190
- }
191
- function colorInitValuesEqual(a, b) {
192
- if (typeof a !== typeof b) {
193
- return false;
194
- }
195
- if (typeof a === 'string' || typeof a === 'number') {
196
- return a === b;
197
- }
198
- if ('_$cssResult$' in a && '_$cssResult$' in b) {
199
- return a.cssText === b.cssText;
200
- }
201
- // For references and SingleCssVarDefinition, compare as JSON
202
- return JSON.stringify(a) === JSON.stringify(b);
203
- }
204
- function extractCssVarName(cssValue) {
205
- const match = cssValue.match(/^var\(--([^,)]+)/);
206
- return match ? match[1] : undefined;
207
- }
208
- function colorInitValueToCode(value, indentLevel, paletteVarName) {
209
- if (typeof value === 'string') {
210
- return `'${value}'`;
211
- }
212
- else if (typeof value === 'number') {
213
- return String(value);
214
- }
215
- else if ('_$cssResult$' in value) {
216
- const cssText = String(value);
217
- if (paletteVarName) {
218
- const varName = extractCssVarName(cssText);
219
- if (varName) {
220
- return `${paletteVarName}['${varName}']`;
221
- }
222
- }
223
- return `css\`${cssText}\``;
224
- }
225
- else if ('refBackground' in value ||
226
- 'refForeground' in value ||
227
- 'refDefaultBackground' in value ||
228
- 'refDefaultForeground' in value) {
229
- const entries = [];
230
- if ('refForeground' in value) {
231
- entries.push(`${tab(indentLevel + 1)}refForeground: '${value.refForeground}',`);
232
- }
233
- if ('refBackground' in value) {
234
- entries.push(`${tab(indentLevel + 1)}refBackground: '${value.refBackground}',`);
235
- }
236
- if ('refDefaultForeground' in value) {
237
- entries.push(`${tab(indentLevel + 1)}refDefaultForeground: true,`);
238
- }
239
- if ('refDefaultBackground' in value) {
240
- entries.push(`${tab(indentLevel + 1)}refDefaultBackground: true,`);
241
- }
242
- return `{\n${entries.join('\n')}\n${tab(indentLevel)}}`;
243
- }
244
- else {
245
- // SingleCssVarDefinition
246
- return `'${value.default}'`;
247
- }
248
- }
249
- function colorInitToCode(colorInit, indentLevel, defaultInit, paletteVarName) {
250
- const entries = [];
251
- if ('foreground' in colorInit &&
252
- (!defaultInit || !colorInitValuesEqual(colorInit.foreground, defaultInit.foreground))) {
253
- // Check if foreground matches default background (use refDefaultBackground)
254
- if (defaultInit && colorInitValuesEqual(colorInit.foreground, defaultInit.background)) {
255
- entries.push(`${tab(indentLevel + 1)}foreground: {\n${tab(indentLevel + 2)}refDefaultBackground: true,\n${tab(indentLevel + 1)}},`);
256
- }
257
- else {
258
- entries.push(`${tab(indentLevel + 1)}foreground: ${colorInitValueToCode(colorInit.foreground, indentLevel + 1, paletteVarName)},`);
259
- }
260
- }
261
- if ('background' in colorInit &&
262
- (!defaultInit || !colorInitValuesEqual(colorInit.background, defaultInit.background))) {
263
- // Check if background matches default foreground (use refDefaultForeground)
264
- if (defaultInit && colorInitValuesEqual(colorInit.background, defaultInit.foreground)) {
265
- entries.push(`${tab(indentLevel + 1)}background: {\n${tab(indentLevel + 2)}refDefaultForeground: true,\n${tab(indentLevel + 1)}},`);
266
- }
267
- else {
268
- entries.push(`${tab(indentLevel + 1)}background: ${colorInitValueToCode(colorInit.background, indentLevel + 1, paletteVarName)},`);
269
- }
270
- }
271
- return `${tab(indentLevel)}{\n${entries.join('\n')}\n${tab(indentLevel)}}`;
272
- }
273
- function colorThemeInitToCode(colorsInit, indentLevel, defaultInit, paletteVarName) {
274
- const entries = getObjectTypedEntries(colorsInit).map(([colorName, colorInit,]) => {
275
- return `${tab(indentLevel + 1)}'${colorName}': ${colorInitToCode(colorInit, indentLevel + 1, defaultInit, paletteVarName).trimStart()},`;
276
- });
277
- return `${tab(indentLevel)}{\n${entries.join('\n')}\n${tab(indentLevel)}}`;
278
- }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
- export * from './color/build-color-theme.js';
2
- export * from './color/color-css.js';
3
- export * from './color/color-palette-book-pages.js';
4
- export * from './color/color-theme-book-pages.js';
5
- export * from './color/color-theme-override.js';
6
- export * from './color/color-theme.js';
1
+ export * from './color-theme/build-color-theme.js';
2
+ export * from './color-theme/color-css.js';
3
+ export * from './color-theme/color-palette-book-pages.js';
4
+ export * from './color-theme/color-theme-book-pages.js';
5
+ export * from './color-theme/color-theme-code.js';
6
+ export * from './color-theme/color-theme-override.js';
7
+ export * from './color-theme/color-theme.js';
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
- export * from './color/build-color-theme.js';
2
- export * from './color/color-css.js';
3
- export * from './color/color-palette-book-pages.js';
4
- export * from './color/color-theme-book-pages.js';
5
- export * from './color/color-theme-override.js';
6
- export * from './color/color-theme.js';
1
+ export * from './color-theme/build-color-theme.js';
2
+ export * from './color-theme/color-css.js';
3
+ export * from './color-theme/color-palette-book-pages.js';
4
+ export * from './color-theme/color-theme-book-pages.js';
5
+ export * from './color-theme/color-theme-code.js';
6
+ export * from './color-theme/color-theme-override.js';
7
+ export * from './color-theme/color-theme.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "theme-vir",
3
- "version": "28.16.1",
3
+ "version": "28.17.0",
4
4
  "description": "Create an entire web theme.",
5
5
  "keywords": [
6
6
  "design",
@@ -39,7 +39,8 @@
39
39
  "start": "virmator frontend",
40
40
  "test": "virmator test web",
41
41
  "test:coverage": "npm run test coverage",
42
- "test:docs": "virmator docs check"
42
+ "test:docs": "virmator docs check",
43
+ "test:update": "virmator test web update"
43
44
  },
44
45
  "dependencies": {
45
46
  "@augment-vir/assert": "^31.57.5",
File without changes
File without changes