@ethlete/core 5.0.0-next.8 → 5.0.0-next.9

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.
@@ -167,9 +167,9 @@ function parseThemeObject(obj, sourceFile) {
167
167
  theme.isDefault = true;
168
168
  }
169
169
  break;
170
- case 'isDefaultAlt':
171
- if (initializer.isKind(SyntaxKind.TrueKeyword)) {
172
- theme.isDefaultAlt = true;
170
+ case 'type':
171
+ if (initializer.isKind(SyntaxKind.StringLiteral)) {
172
+ theme.type = initializer.getLiteralValue();
173
173
  }
174
174
  break;
175
175
  case 'primary':
@@ -188,8 +188,6 @@ function parseThemeObject(obj, sourceFile) {
188
188
  }
189
189
  function validateThemeConfiguration(themes) {
190
190
  const defaultThemes = themes.filter((t) => t.isDefault);
191
- const defaultAltThemes = themes.filter((t) => t.isDefaultAlt);
192
- const bothDefaultAndAlt = themes.filter((t) => t.isDefault && t.isDefaultAlt);
193
191
  // Error: No default theme
194
192
  if (defaultThemes.length === 0) {
195
193
  throw new Error('No default theme found. At least one theme must have isDefault: true');
@@ -198,13 +196,18 @@ function validateThemeConfiguration(themes) {
198
196
  if (defaultThemes.length > 1) {
199
197
  throw new Error(`Multiple default themes found: ${defaultThemes.map((t) => t.name).join(', ')}. Only one theme can have isDefault: true`);
200
198
  }
201
- // Error: Theme has both isDefault and isDefaultAlt
202
- if (bothDefaultAndAlt.length > 0) {
203
- throw new Error(`Theme "${bothDefaultAndAlt[0].name}" has both isDefault and isDefaultAlt set to true. A theme can only be one or the other`);
204
- }
205
- // Error: Multiple default alt themes
206
- if (defaultAltThemes.length > 1) {
207
- throw new Error(`Multiple default alt themes found: ${defaultAltThemes.map((t) => t.name).join(', ')}. Only one theme can have isDefaultAlt: true`);
199
+ // Error: Duplicate theme types
200
+ const typedThemes = themes.filter((t) => t.type);
201
+ const typeMap = new Map();
202
+ for (const theme of typedThemes) {
203
+ const existing = typeMap.get(theme.type) || [];
204
+ existing.push(theme.name);
205
+ typeMap.set(theme.type, existing);
206
+ }
207
+ for (const [type, names] of typeMap) {
208
+ if (names.length > 1) {
209
+ throw new Error(`Multiple themes with type "${type}" found: ${names.join(', ')}. Only one theme can have a given type`);
210
+ }
208
211
  }
209
212
  }
210
213
  function parseThemeSwatch(obj, sourceFile) {
@@ -312,8 +315,7 @@ function generateTailwindThemeCss(themes, prefix, schema) {
312
315
  `;
313
316
  // Validation is now done separately before this function is called
314
317
  const defaultThemes = themes.filter((t) => t.isDefault);
315
- const defaultAltThemes = themes.filter((t) => t.isDefaultAlt);
316
- const regularThemes = themes.filter((t) => !t.isDefault && !t.isDefaultAlt);
318
+ const regularThemes = themes.filter((t) => !t.isDefault);
317
319
  // Generate static Tailwind @theme block for each theme
318
320
  for (const theme of themes) {
319
321
  const name = createCssThemeName(theme.name);
@@ -344,13 +346,10 @@ function generateTailwindThemeCss(themes, prefix, schema) {
344
346
  }
345
347
  }
346
348
  tailwindVars.push('');
347
- // Generate dynamic theme variables - check main themes and alt themes separately
349
+ // Main theme dynamic colors
348
350
  const mainThemes = [...defaultThemes, ...regularThemes];
349
351
  const hasSecondary = mainThemes.some((t) => t.secondary);
350
352
  const hasTertiary = mainThemes.some((t) => t.tertiary);
351
- const hasAltSecondary = defaultAltThemes.some((t) => t.secondary);
352
- const hasAltTertiary = defaultAltThemes.some((t) => t.tertiary);
353
- // Main theme dynamic colors
354
353
  tailwindVars.push(' /* Dynamic theme colors (references runtime CSS variables) */');
355
354
  addDynamicThemeColors(tailwindVars, prefix, 'theme', 'primary', true);
356
355
  addDynamicInkColors(tailwindVars, prefix, 'theme-ink', 'primary-ink');
@@ -360,54 +359,54 @@ function generateTailwindThemeCss(themes, prefix, schema) {
360
359
  if (hasTertiary) {
361
360
  addDynamicThemeColors(tailwindVars, prefix, 'theme-tertiary', 'tertiary', false);
362
361
  }
363
- // Alt theme dynamic colors
364
- tailwindVars.push(' /* Alt theme dynamic colors */');
365
- addDynamicThemeColors(tailwindVars, prefix, 'alt-theme', 'alt-primary', true);
366
- addDynamicInkColors(tailwindVars, prefix, 'alt-theme-ink', 'alt-primary-ink');
367
- if (hasAltSecondary) {
368
- addDynamicThemeColors(tailwindVars, prefix, 'alt-theme-secondary', 'alt-secondary', false);
369
- }
370
- if (hasAltTertiary) {
371
- addDynamicThemeColors(tailwindVars, prefix, 'alt-theme-tertiary', 'alt-tertiary', false);
372
- }
373
- // Generate runtime CSS for ALL themes (both main and alt variants)
362
+ // Generate runtime CSS for all themes
374
363
  themes.forEach((theme) => {
375
364
  const name = createCssThemeName(theme.name);
376
- // Determine if this is the default or default-alt theme
365
+ // Determine if this is the default theme
377
366
  const isDefault = theme.isDefault;
378
- const isDefaultAlt = theme.isDefaultAlt;
379
- // Generate main color variant (.et-color--{name})
367
+ // Generate color variant (.et-color--{name})
380
368
  if (isDefault) {
381
369
  // Default color gets :root and .et-color--default selectors
382
370
  const selectors = [':root', `.${prefix}-color--default`, `.${prefix}-color--${name}`];
383
371
  themeVars.push(`${selectors.join(', ')} {`);
384
372
  }
385
- else if (!isDefaultAlt) {
373
+ else {
386
374
  // Regular colors just get their own class
387
375
  themeVars.push(`.${prefix}-color--${name} {`);
388
376
  }
389
- if (isDefault || !isDefaultAlt) {
390
- addThemeColorVariants(themeVars, prefix, '', theme);
391
- themeVars.push('}\n');
392
- }
393
- // Generate alt color variant (.et-color-alt--{name})
394
- if (isDefaultAlt) {
395
- // Default alt color gets :root and .et-color-alt--default selectors
396
- const selectors = [':root', `.${prefix}-color-alt--default`, `.${prefix}-color-alt--${name}`];
397
- themeVars.push(`${selectors.join(', ')} {`);
398
- }
399
- else {
400
- // All colors (including default and regular) get an alt variant
401
- themeVars.push(`.${prefix}-color-alt--${name} {`);
402
- }
403
- addThemeColorVariants(themeVars, prefix, 'alt-', theme);
377
+ addThemeColorVariants(themeVars, prefix, '', theme);
404
378
  themeVars.push('}\n');
405
379
  });
380
+ // Convenience var aliases — available on any element with a color class (or root for default)
381
+ const aliasBlock = `/* Convenience aliases (rgb + solid + opacity variants) */
382
+ @layer base {
383
+ :root, :where([class*="${prefix}-color--"]) {
384
+ --${prefix}-theme-color-primary-rgb: var(--${prefix}-color-primary);
385
+ --${prefix}-theme-color-primary-opacity: 1;
386
+ --${prefix}-theme-color-primary-solid: rgb(var(--${prefix}-theme-color-primary-rgb));
387
+ --${prefix}-theme-color-primary: rgb(var(--${prefix}-theme-color-primary-rgb) / var(--${prefix}-theme-color-primary-opacity));
388
+
389
+ --${prefix}-theme-color-on-primary-rgb: var(--${prefix}-color-on-primary);
390
+ --${prefix}-theme-color-on-primary-opacity: 1;
391
+ --${prefix}-theme-color-on-primary-solid: rgb(var(--${prefix}-theme-color-on-primary-rgb) / var(--${prefix}-theme-color-on-primary-opacity));
392
+ --${prefix}-theme-color-on-primary: rgb(var(--${prefix}-theme-color-on-primary-rgb) / var(--${prefix}-theme-color-on-primary-opacity));
393
+
394
+ --${prefix}-theme-color-ink-rgb: var(--${prefix}-color-primary-ink, var(--${prefix}-color-primary));
395
+ --${prefix}-theme-color-ink-opacity: 1;
396
+ --${prefix}-theme-color-ink-solid: rgb(var(--${prefix}-theme-color-ink-rgb) / var(--${prefix}-theme-color-ink-opacity));
397
+ --${prefix}-theme-color-ink: rgb(var(--${prefix}-theme-color-ink-rgb) / var(--${prefix}-theme-color-ink-opacity));
398
+ }
399
+ }
400
+ `;
406
401
  return `${header}@theme {
407
402
  ${tailwindVars.join('\n')}
408
403
  }
409
404
 
410
- ${themeVars.join('\n')}`;
405
+ @layer base {
406
+ ${themeVars.join('\n')}
407
+ }
408
+
409
+ ${aliasBlock}`;
411
410
  }
412
411
  function addDynamicThemeColors(vars, prefix, tailwindName, cssVarName, addSpacingBefore) {
413
412
  if (addSpacingBefore && vars.length > 0 && vars[vars.length - 1] !== '') {
@@ -143,6 +143,27 @@ function parseSurfaceThemeObject(obj) {
143
143
  }
144
144
  continue;
145
145
  }
146
+ if (propName === 'interactionColor' && initializer.isKind(SyntaxKind.ObjectLiteralExpression)) {
147
+ const interactionProps = initializer.getProperties();
148
+ const interactionColor = {};
149
+ for (const iProp of interactionProps) {
150
+ if (!iProp.isKind(SyntaxKind.PropertyAssignment))
151
+ continue;
152
+ const iPropName = iProp.getName();
153
+ const iInit = iProp.getInitializer();
154
+ if (iInit?.isKind(SyntaxKind.StringLiteral)) {
155
+ interactionColor[iPropName] = iInit.getLiteralValue();
156
+ }
157
+ }
158
+ if (interactionColor.default &&
159
+ interactionColor.hover &&
160
+ interactionColor.focus &&
161
+ interactionColor.active &&
162
+ interactionColor.disabled) {
163
+ theme.interactionColor = interactionColor;
164
+ }
165
+ continue;
166
+ }
146
167
  if (propName === 'elevation') {
147
168
  if (initializer.isKind(SyntaxKind.NumericLiteral)) {
148
169
  theme.elevation = Number(initializer.getLiteralValue());
@@ -219,6 +240,13 @@ function generateSurfaceThemeCss(themes, prefix, schema) {
219
240
  tailwindVars.push(` --color-${prefix}-surface-${name}-muted: rgb(${theme.colorMuted});`);
220
241
  tailwindVars.push(` --color-${prefix}-surface-${name}-subtle: rgb(${theme.colorSubtle});`);
221
242
  tailwindVars.push(` --color-${prefix}-surface-${name}-border: rgb(${theme.border});`);
243
+ if (theme.interactionColor) {
244
+ tailwindVars.push(` --color-${prefix}-surface-${name}-interaction: rgb(${theme.interactionColor.default});`);
245
+ tailwindVars.push(` --color-${prefix}-surface-${name}-interaction-hover: rgb(${theme.interactionColor.hover});`);
246
+ tailwindVars.push(` --color-${prefix}-surface-${name}-interaction-focus: rgb(${theme.interactionColor.focus});`);
247
+ tailwindVars.push(` --color-${prefix}-surface-${name}-interaction-active: rgb(${theme.interactionColor.active});`);
248
+ tailwindVars.push(` --color-${prefix}-surface-${name}-interaction-disabled: rgb(${theme.interactionColor.disabled});`);
249
+ }
222
250
  tailwindVars.push('');
223
251
  }
224
252
  // Dynamic surface colors (reference runtime CSS variables)
@@ -228,6 +256,12 @@ function generateSurfaceThemeCss(themes, prefix, schema) {
228
256
  tailwindVars.push(` --color-${prefix}-surface-muted: rgb(var(--${prefix}-surface-color-muted));`);
229
257
  tailwindVars.push(` --color-${prefix}-surface-subtle: rgb(var(--${prefix}-surface-color-subtle));`);
230
258
  tailwindVars.push(` --color-${prefix}-surface-border: rgb(var(--${prefix}-surface-border));`);
259
+ // Dynamic interaction colors (reference runtime CSS variables)
260
+ tailwindVars.push(` --color-${prefix}-surface-interaction: rgb(var(--${prefix}-surface-interaction));`);
261
+ tailwindVars.push(` --color-${prefix}-surface-interaction-hover: rgb(var(--${prefix}-surface-interaction-hover));`);
262
+ tailwindVars.push(` --color-${prefix}-surface-interaction-focus: rgb(var(--${prefix}-surface-interaction-focus));`);
263
+ tailwindVars.push(` --color-${prefix}-surface-interaction-active: rgb(var(--${prefix}-surface-interaction-active));`);
264
+ tailwindVars.push(` --color-${prefix}-surface-interaction-disabled: rgb(var(--${prefix}-surface-interaction-disabled));`);
231
265
  // Runtime CSS — theme selector classes
232
266
  for (const theme of themes) {
233
267
  const name = createCssSurfaceName(theme.name);
@@ -239,20 +273,87 @@ function generateSurfaceThemeCss(themes, prefix, schema) {
239
273
  else {
240
274
  themeVars.push(`.${prefix}-surface--${name} {`);
241
275
  }
242
- themeVars.push(` --${prefix}-surface-background: ${theme.background};`);
243
- themeVars.push(` --${prefix}-surface-color: ${theme.color};`);
244
- themeVars.push(` --${prefix}-surface-color-muted: ${theme.colorMuted};`);
245
- themeVars.push(` --${prefix}-surface-color-subtle: ${theme.colorSubtle};`);
246
- themeVars.push(` --${prefix}-surface-border: ${theme.border};`);
247
- themeVars.push(` --${prefix}-surface-type: ${theme.type};`);
248
- themeVars.push(` --${prefix}-surface-elevation: ${theme.elevation};`);
276
+ pushSurfaceVars(themeVars, prefix, theme, ' ');
249
277
  themeVars.push('}\n');
250
278
  }
279
+ // Media query defaults — apply surface vars to :root based on prefers-color-scheme
280
+ const defaultLight = themes.find((t) => t.isDefault && t.type === 'light');
281
+ const defaultDark = themes.find((t) => t.isDefault && t.type === 'dark');
282
+ if (defaultLight) {
283
+ themeVars.push(`@media (prefers-color-scheme: light) {`);
284
+ themeVars.push(` :root {`);
285
+ pushSurfaceVars(themeVars, prefix, defaultLight, ' ');
286
+ themeVars.push(` }`);
287
+ themeVars.push(`}\n`);
288
+ }
289
+ if (defaultDark) {
290
+ themeVars.push(`@media (prefers-color-scheme: dark) {`);
291
+ themeVars.push(` :root {`);
292
+ pushSurfaceVars(themeVars, prefix, defaultDark, ' ');
293
+ themeVars.push(` }`);
294
+ themeVars.push(`}\n`);
295
+ }
296
+ // Convenience var aliases — available on any element with a surface class or :root (via media queries)
297
+ const aliasBlock = `/* Convenience aliases (rgb + solid variants) */
298
+ @layer base {
299
+ :root, :where([class*="${prefix}-surface--"]) {
300
+ --${prefix}-surface-background-rgb: var(--${prefix}-surface-background);
301
+ --${prefix}-surface-background-solid: rgb(var(--${prefix}-surface-background-rgb));
302
+
303
+ --${prefix}-surface-color-rgb: var(--${prefix}-surface-color);
304
+ --${prefix}-surface-color-solid: rgb(var(--${prefix}-surface-color-rgb));
305
+
306
+ --${prefix}-surface-color-muted-rgb: var(--${prefix}-surface-color-muted);
307
+ --${prefix}-surface-color-muted-solid: rgb(var(--${prefix}-surface-color-muted-rgb));
308
+
309
+ --${prefix}-surface-color-subtle-rgb: var(--${prefix}-surface-color-subtle);
310
+ --${prefix}-surface-color-subtle-solid: rgb(var(--${prefix}-surface-color-subtle-rgb));
311
+
312
+ --${prefix}-surface-border-rgb: var(--${prefix}-surface-border);
313
+ --${prefix}-surface-border-solid: rgb(var(--${prefix}-surface-border-rgb));
314
+
315
+ --${prefix}-surface-interaction-rgb: var(--${prefix}-surface-interaction);
316
+ --${prefix}-surface-interaction-solid: rgb(var(--${prefix}-surface-interaction-rgb));
317
+
318
+ --${prefix}-surface-interaction-hover-rgb: var(--${prefix}-surface-interaction-hover);
319
+ --${prefix}-surface-interaction-hover-solid: rgb(var(--${prefix}-surface-interaction-hover-rgb));
320
+
321
+ --${prefix}-surface-interaction-focus-rgb: var(--${prefix}-surface-interaction-focus);
322
+ --${prefix}-surface-interaction-focus-solid: rgb(var(--${prefix}-surface-interaction-focus-rgb));
323
+
324
+ --${prefix}-surface-interaction-active-rgb: var(--${prefix}-surface-interaction-active);
325
+ --${prefix}-surface-interaction-active-solid: rgb(var(--${prefix}-surface-interaction-active-rgb));
326
+
327
+ --${prefix}-surface-interaction-disabled-rgb: var(--${prefix}-surface-interaction-disabled);
328
+ --${prefix}-surface-interaction-disabled-solid: rgb(var(--${prefix}-surface-interaction-disabled-rgb));
329
+ }
330
+ }
331
+ `;
251
332
  return `${header}@theme {
252
333
  ${tailwindVars.join('\n')}
253
334
  }
254
335
 
255
- ${themeVars.join('\n')}`;
336
+ @layer base {
337
+ ${themeVars.join('\n')}
338
+ }
339
+
340
+ ${aliasBlock}`;
341
+ }
342
+ function pushSurfaceVars(vars, prefix, theme, indent) {
343
+ vars.push(`${indent}--${prefix}-surface-background: ${theme.background};`);
344
+ vars.push(`${indent}--${prefix}-surface-color: ${theme.color};`);
345
+ vars.push(`${indent}--${prefix}-surface-color-muted: ${theme.colorMuted};`);
346
+ vars.push(`${indent}--${prefix}-surface-color-subtle: ${theme.colorSubtle};`);
347
+ vars.push(`${indent}--${prefix}-surface-border: ${theme.border};`);
348
+ vars.push(`${indent}--${prefix}-surface-type: ${theme.type};`);
349
+ vars.push(`${indent}--${prefix}-surface-elevation: ${theme.elevation};`);
350
+ if (theme.interactionColor) {
351
+ vars.push(`${indent}--${prefix}-surface-interaction: ${theme.interactionColor.default};`);
352
+ vars.push(`${indent}--${prefix}-surface-interaction-hover: ${theme.interactionColor.hover};`);
353
+ vars.push(`${indent}--${prefix}-surface-interaction-focus: ${theme.interactionColor.focus};`);
354
+ vars.push(`${indent}--${prefix}-surface-interaction-active: ${theme.interactionColor.active};`);
355
+ vars.push(`${indent}--${prefix}-surface-interaction-disabled: ${theme.interactionColor.disabled};`);
356
+ }
256
357
  }
257
358
  function findMainStylesFile(tree) {
258
359
  const potentialFiles = [];
package/package.json CHANGED
@@ -1,24 +1,24 @@
1
1
  {
2
2
  "name": "@ethlete/core",
3
- "version": "5.0.0-next.8",
3
+ "version": "5.0.0-next.9",
4
4
  "license": "MIT",
5
5
  "sideEffects": false,
6
6
  "peerDependencies": {
7
- "@analogjs/vite-plugin-angular": "2.3.1",
8
- "@angular/cdk": "21.2.1",
9
- "@angular/common": "21.2.1",
10
- "@angular/core": "21.2.1",
11
- "@angular/forms": "21.2.1",
12
- "@angular/platform-browser": "21.2.1",
13
- "@angular/router": "21.2.1",
7
+ "@analogjs/vite-plugin-angular": "2.5.1",
8
+ "@angular/cdk": "21.2.11",
9
+ "@angular/common": "21.2.13",
10
+ "@angular/core": "21.2.13",
11
+ "@angular/forms": "21.2.13",
12
+ "@angular/platform-browser": "21.2.13",
13
+ "@angular/router": "21.2.13",
14
14
  "@ethlete/types": "^2.0.0-next.0",
15
15
  "@floating-ui/dom": "1.7.6",
16
- "@nx/devkit": "22.5.4",
17
- "@nx/vite": "22.5.4",
16
+ "@nx/devkit": "22.7.2",
17
+ "@nx/vite": "22.7.2",
18
18
  "rxjs": "7.8.2",
19
19
  "ts-morph": "21.0.1",
20
20
  "typescript": "5.9.3",
21
- "vite": "^7.0.0"
21
+ "vite": "8.0.13"
22
22
  },
23
23
  "generators": "./generators/generators.json",
24
24
  "module": "fesm2022/ethlete-core.mjs",
@@ -32,6 +32,7 @@
32
32
  "default": "./fesm2022/ethlete-core.mjs"
33
33
  }
34
34
  },
35
+ "type": "module",
35
36
  "dependencies": {
36
37
  "tslib": "^2.3.0"
37
38
  }