@ethlete/core 5.0.0-next.64 → 5.0.0-next.65

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,7 @@
1
1
  import { formatFiles, logger, visitNotIgnoredFiles } from '@nx/devkit';
2
2
  import { posix } from 'path';
3
3
  import { Project, SyntaxKind } from 'ts-morph';
4
+ import { colorThemeCss, cssThemeName } from '../../design/theme-css.js';
4
5
  export default async function generate(tree, schema) {
5
6
  logger.log('\nšŸ”„ Starting Tailwind 4 theme generator...\n');
6
7
  const themesPath = schema.themesPath || 'src/themes.ts';
@@ -200,8 +201,8 @@ function parseThemeObject(obj, sourceFile, context) {
200
201
  return theme;
201
202
  }
202
203
  function applyDefaultThemeOverride(themes, defaultTheme) {
203
- const wanted = createCssThemeName(defaultTheme);
204
- const target = themes.find((t) => t.name === defaultTheme || createCssThemeName(t.name) === wanted);
204
+ const wanted = cssThemeName(defaultTheme);
205
+ const target = themes.find((t) => t.name === defaultTheme || cssThemeName(t.name) === wanted);
205
206
  if (!target) {
206
207
  throw new Error(`No theme named "${defaultTheme}" found. Available themes: ${themes.map((t) => t.name).join(', ')}`);
207
208
  }
@@ -362,12 +363,6 @@ function parseColorMap(initializer, sourceFile, context) {
362
363
  }
363
364
  return null;
364
365
  }
365
- function createCssThemeName(name) {
366
- return name
367
- .toLowerCase()
368
- .replace(/\s+/g, '-')
369
- .replace(/[^a-z0-9-]/g, '');
370
- }
371
366
  function generateColorThemeNameTypes(themes, schema) {
372
367
  const themesPath = schema.themesPath || 'src/themes.ts';
373
368
  const outputPath = schema.outputPath || 'src/styles/generated-tailwind-themes.css';
@@ -391,8 +386,6 @@ export {};
391
386
  `;
392
387
  }
393
388
  function generateTailwindThemeCss(themes, utilityPrefix, runtimePrefix, schema) {
394
- const tailwindVars = [];
395
- const themeVars = [];
396
389
  const themesPath = schema.themesPath || 'src/themes.ts';
397
390
  const outputPath = schema.outputPath || 'src/styles/generated-tailwind-themes.css';
398
391
  const header = `/*
@@ -405,183 +398,7 @@ function generateTailwindThemeCss(themes, utilityPrefix, runtimePrefix, schema)
405
398
  */
406
399
 
407
400
  `;
408
- for (const theme of themes) {
409
- const name = createCssThemeName(theme.name);
410
- tailwindVars.push(` /* ${theme.name} theme */`);
411
- addTailwindColorVariants(tailwindVars, `${utilityPrefix}-${name}`, theme.primary.color);
412
- tailwindVars.push('');
413
- addTailwindColorVariants(tailwindVars, `${utilityPrefix}-on-${name}`, theme.primary.onColor);
414
- tailwindVars.push('');
415
- addTailwindColorVariants(tailwindVars, `${utilityPrefix}-${name}-ink`, theme.primary.inkColor || theme.primary.color);
416
- tailwindVars.push('');
417
- if (theme.secondary) {
418
- addTailwindColorVariants(tailwindVars, `${utilityPrefix}-${name}-secondary`, theme.secondary.color);
419
- tailwindVars.push('');
420
- addTailwindColorVariants(tailwindVars, `${utilityPrefix}-on-${name}-secondary`, theme.secondary.onColor);
421
- tailwindVars.push('');
422
- }
423
- if (theme.tertiary) {
424
- addTailwindColorVariants(tailwindVars, `${utilityPrefix}-${name}-tertiary`, theme.tertiary.color);
425
- tailwindVars.push('');
426
- addTailwindColorVariants(tailwindVars, `${utilityPrefix}-on-${name}-tertiary`, theme.tertiary.onColor);
427
- tailwindVars.push('');
428
- }
429
- }
430
- tailwindVars.push('');
431
- const hasSecondary = themes.some((t) => t.secondary);
432
- const hasTertiary = themes.some((t) => t.tertiary);
433
- // Collect the dynamic theme colors once. They are emitted in `@theme` (so Tailwind generates
434
- // the utilities) and ALSO re-declared on every color selector in the alias block below. A
435
- // Tailwind `@theme` variable only lands on `:root`, so `rgb(var(--<runtime>-color-*))` resolves
436
- // once against the root color scope and inherits that concrete color into descendants - which
437
- // means `bg-<prefix>-theme-*` utilities would ignore nested `.<runtime>-color--*` scopes.
438
- // Re-declaring them per color selector makes the utilities resolve against the nearest scope.
439
- const dynamicColorVars = [];
440
- addDynamicThemeColors(dynamicColorVars, utilityPrefix, runtimePrefix, 'theme', 'primary', false);
441
- addDynamicInkColors(dynamicColorVars, utilityPrefix, runtimePrefix, 'theme-ink', 'primary-ink');
442
- if (hasSecondary) {
443
- addDynamicThemeColors(dynamicColorVars, utilityPrefix, runtimePrefix, 'theme-secondary', 'secondary', false);
444
- }
445
- if (hasTertiary) {
446
- addDynamicThemeColors(dynamicColorVars, utilityPrefix, runtimePrefix, 'theme-tertiary', 'tertiary', false);
447
- }
448
- tailwindVars.push(' /* Dynamic theme colors (references runtime CSS variables) */');
449
- tailwindVars.push(...dynamicColorVars);
450
- themes.forEach((theme) => {
451
- const name = createCssThemeName(theme.name);
452
- const isDefault = theme.isDefault;
453
- if (isDefault) {
454
- const selectors = [':root', `.${runtimePrefix}-color--default`, `.${runtimePrefix}-color--${name}`];
455
- themeVars.push(`${selectors.join(', ')} {`);
456
- }
457
- else {
458
- themeVars.push(`.${runtimePrefix}-color--${name} {`);
459
- }
460
- addThemeColorVariants(themeVars, runtimePrefix, '', theme);
461
- themeVars.push('}\n');
462
- });
463
- // Re-indent the dynamic theme colors (from 2-space `@theme` indent to the 4-space alias-block
464
- // indent) and drop trailing blank lines so they slot cleanly into the alias selector below.
465
- const dynamicColorAliasLines = dynamicColorVars.map((line) => (line === '' ? '' : ` ${line}`));
466
- while (dynamicColorAliasLines.length && dynamicColorAliasLines[dynamicColorAliasLines.length - 1] === '') {
467
- dynamicColorAliasLines.pop();
468
- }
469
- const aliasBlock = `/* Convenience aliases (rgb + solid + opacity variants) */
470
- @layer base {
471
- :root, :where([class*="${runtimePrefix}-color--"]) {
472
- --${runtimePrefix}-theme-color-primary-rgb: var(--${runtimePrefix}-color-primary);
473
- --${runtimePrefix}-theme-color-primary-opacity: 1;
474
- --${runtimePrefix}-theme-color-primary-solid: rgb(var(--${runtimePrefix}-theme-color-primary-rgb));
475
- --${runtimePrefix}-theme-color-primary: rgb(var(--${runtimePrefix}-theme-color-primary-rgb) / var(--${runtimePrefix}-theme-color-primary-opacity));
476
-
477
- --${runtimePrefix}-theme-color-on-primary-rgb: var(--${runtimePrefix}-color-on-primary);
478
- --${runtimePrefix}-theme-color-on-primary-opacity: 1;
479
- --${runtimePrefix}-theme-color-on-primary-solid: rgb(var(--${runtimePrefix}-theme-color-on-primary-rgb) / var(--${runtimePrefix}-theme-color-on-primary-opacity));
480
- --${runtimePrefix}-theme-color-on-primary: rgb(var(--${runtimePrefix}-theme-color-on-primary-rgb) / var(--${runtimePrefix}-theme-color-on-primary-opacity));
481
-
482
- --${runtimePrefix}-theme-color-ink-rgb: var(--${runtimePrefix}-color-primary-ink, var(--${runtimePrefix}-color-primary));
483
- --${runtimePrefix}-theme-color-ink-opacity: 1;
484
- --${runtimePrefix}-theme-color-ink-solid: rgb(var(--${runtimePrefix}-theme-color-ink-rgb) / var(--${runtimePrefix}-theme-color-ink-opacity));
485
- --${runtimePrefix}-theme-color-ink: rgb(var(--${runtimePrefix}-theme-color-ink-rgb) / var(--${runtimePrefix}-theme-color-ink-opacity));
486
-
487
- /* Dynamic Tailwind theme colors - re-declared per color scope so that
488
- bg-${utilityPrefix}-theme-* utilities resolve against the nearest .${runtimePrefix}-color--*
489
- scope instead of the value computed once at :root. */
490
- ${dynamicColorAliasLines.join('\n')}
491
- }
492
- }
493
- `;
494
- return `${header}@theme {
495
- ${tailwindVars.join('\n')}
496
- }
497
-
498
- @layer base {
499
- ${themeVars.join('\n')}
500
- }
501
-
502
- ${aliasBlock}`;
503
- }
504
- function addDynamicThemeColors(vars, utilityPrefix, runtimePrefix, tailwindName, cssVarName, addSpacingBefore) {
505
- if (addSpacingBefore && vars.length > 0 && vars[vars.length - 1] !== '') {
506
- vars.push('');
507
- }
508
- vars.push(` --color-${utilityPrefix}-${tailwindName}: rgb(var(--${runtimePrefix}-color-${cssVarName}));`);
509
- vars.push(` --color-${utilityPrefix}-${tailwindName}-hover: rgb(var(--${runtimePrefix}-color-${cssVarName}-hover));`);
510
- vars.push(` --color-${utilityPrefix}-${tailwindName}-focus: rgb(var(--${runtimePrefix}-color-${cssVarName}-focus));`);
511
- vars.push(` --color-${utilityPrefix}-${tailwindName}-active: rgb(var(--${runtimePrefix}-color-${cssVarName}-active));`);
512
- vars.push(` --color-${utilityPrefix}-${tailwindName}-disabled: rgb(var(--${runtimePrefix}-color-${cssVarName}-disabled));`);
513
- vars.push('');
514
- vars.push(` --color-${utilityPrefix}-on-${tailwindName}: rgb(var(--${runtimePrefix}-color-on-${cssVarName}));`);
515
- vars.push(` --color-${utilityPrefix}-on-${tailwindName}-hover: rgb(var(--${runtimePrefix}-color-on-${cssVarName}-hover));`);
516
- vars.push(` --color-${utilityPrefix}-on-${tailwindName}-focus: rgb(var(--${runtimePrefix}-color-on-${cssVarName}-focus));`);
517
- vars.push(` --color-${utilityPrefix}-on-${tailwindName}-active: rgb(var(--${runtimePrefix}-color-on-${cssVarName}-active));`);
518
- vars.push(` --color-${utilityPrefix}-on-${tailwindName}-disabled: rgb(var(--${runtimePrefix}-color-on-${cssVarName}-disabled));`);
519
- vars.push('');
520
- }
521
- function addDynamicInkColors(vars, utilityPrefix, runtimePrefix, tailwindName, cssVarName) {
522
- vars.push(` --color-${utilityPrefix}-${tailwindName}: rgb(var(--${runtimePrefix}-color-${cssVarName}));`);
523
- vars.push(` --color-${utilityPrefix}-${tailwindName}-hover: rgb(var(--${runtimePrefix}-color-${cssVarName}-hover));`);
524
- vars.push(` --color-${utilityPrefix}-${tailwindName}-focus: rgb(var(--${runtimePrefix}-color-${cssVarName}-focus));`);
525
- vars.push(` --color-${utilityPrefix}-${tailwindName}-active: rgb(var(--${runtimePrefix}-color-${cssVarName}-active));`);
526
- vars.push(` --color-${utilityPrefix}-${tailwindName}-disabled: rgb(var(--${runtimePrefix}-color-${cssVarName}-disabled));`);
527
- vars.push('');
528
- }
529
- function addTailwindColorVariants(vars, colorName, colorSet) {
530
- vars.push(` --color-${colorName}: rgb(${colorSet.default});`);
531
- const hoverValue = 'hover' in colorSet && colorSet.hover ? colorSet.hover : colorSet.default;
532
- vars.push(` --color-${colorName}-hover: rgb(${hoverValue});`);
533
- const focusValue = 'focus' in colorSet && colorSet.focus ? colorSet.focus : hoverValue;
534
- vars.push(` --color-${colorName}-focus: rgb(${focusValue});`);
535
- const activeValue = 'active' in colorSet && colorSet.active ? colorSet.active : hoverValue;
536
- vars.push(` --color-${colorName}-active: rgb(${activeValue});`);
537
- const disabledValue = 'disabled' in colorSet && colorSet.disabled ? colorSet.disabled : colorSet.default;
538
- vars.push(` --color-${colorName}-disabled: rgb(${disabledValue});`);
539
- }
540
- function addThemeColorVariants(vars, prefix, altPrefix, theme) {
541
- const addSwatch = (level, swatch) => {
542
- const defaultColor = swatch.color.default;
543
- const hoverColor = swatch.color.hover || defaultColor;
544
- const focusColor = swatch.color.focus || hoverColor;
545
- const activeColor = swatch.color.active || hoverColor;
546
- const disabledColor = swatch.color.disabled || defaultColor;
547
- vars.push(` --${prefix}-color-${altPrefix}${level}: ${defaultColor};`);
548
- vars.push(` --${prefix}-color-${altPrefix}${level}-hover: ${hoverColor};`);
549
- vars.push(` --${prefix}-color-${altPrefix}${level}-focus: ${focusColor};`);
550
- vars.push(` --${prefix}-color-${altPrefix}${level}-active: ${activeColor};`);
551
- vars.push(` --${prefix}-color-${altPrefix}${level}-disabled: ${disabledColor};`);
552
- vars.push('');
553
- const onDefaultColor = swatch.onColor.default;
554
- const onHoverColor = swatch.onColor.hover || onDefaultColor;
555
- const onFocusColor = swatch.onColor.focus || onHoverColor;
556
- const onActiveColor = swatch.onColor.active || onDefaultColor;
557
- const onDisabledColor = swatch.onColor.disabled || onDefaultColor;
558
- vars.push(` --${prefix}-color-${altPrefix}on-${level}: ${onDefaultColor};`);
559
- vars.push(` --${prefix}-color-${altPrefix}on-${level}-hover: ${onHoverColor};`);
560
- vars.push(` --${prefix}-color-${altPrefix}on-${level}-focus: ${onFocusColor};`);
561
- vars.push(` --${prefix}-color-${altPrefix}on-${level}-active: ${onActiveColor};`);
562
- vars.push(` --${prefix}-color-${altPrefix}on-${level}-disabled: ${onDisabledColor};`);
563
- const inkDefaultColor = swatch.inkColor?.default || defaultColor;
564
- const inkHoverColor = swatch.inkColor?.hover || inkDefaultColor;
565
- const inkFocusColor = swatch.inkColor?.focus || inkHoverColor;
566
- const inkActiveColor = swatch.inkColor?.active || inkDefaultColor;
567
- const inkDisabledColor = swatch.inkColor?.disabled || inkDefaultColor;
568
- vars.push('');
569
- vars.push(` --${prefix}-color-${altPrefix}${level}-ink: ${inkDefaultColor};`);
570
- vars.push(` --${prefix}-color-${altPrefix}${level}-ink-hover: ${inkHoverColor};`);
571
- vars.push(` --${prefix}-color-${altPrefix}${level}-ink-focus: ${inkFocusColor};`);
572
- vars.push(` --${prefix}-color-${altPrefix}${level}-ink-active: ${inkActiveColor};`);
573
- vars.push(` --${prefix}-color-${altPrefix}${level}-ink-disabled: ${inkDisabledColor};`);
574
- if (theme.secondary || theme.tertiary) {
575
- vars.push('');
576
- }
577
- };
578
- addSwatch('primary', theme.primary);
579
- if (theme.secondary) {
580
- addSwatch('secondary', theme.secondary);
581
- }
582
- if (theme.tertiary) {
583
- addSwatch('tertiary', theme.tertiary);
584
- }
401
+ return `${header}${colorThemeCss(themes, { prefix: utilityPrefix, runtimePrefix })}`;
585
402
  }
586
403
  function findMainStylesFile(tree) {
587
404
  const potentialFiles = [];
@@ -1,5 +1,6 @@
1
1
  import { formatFiles, logger, visitNotIgnoredFiles } from '@nx/devkit';
2
2
  import { Project, SyntaxKind } from 'ts-morph';
3
+ import { cssThemeName, surfaceThemeCss } from '../../design/theme-css.js';
3
4
  export default async function generate(tree, schema) {
4
5
  logger.log('\nšŸ”„ Starting Tailwind 4 surface theme generator...\n');
5
6
  const themesPath = schema.themesPath || 'src/surface-themes.ts';
@@ -293,8 +294,8 @@ function parseSurfaceThemeObject(obj, sourceFile) {
293
294
  // flags on themes of that type. Matches the theme's name or its CSS-safe form. Themes of
294
295
  // the other type keep their flags. Returns the resolved name.
295
296
  function applyDefaultSurfaceThemeOverride(themes, defaultTheme, type) {
296
- const wanted = createCssSurfaceName(defaultTheme);
297
- const matches = themes.filter((t) => t.name === defaultTheme || createCssSurfaceName(t.name) === wanted);
297
+ const wanted = cssThemeName(defaultTheme);
298
+ const matches = themes.filter((t) => t.name === defaultTheme || cssThemeName(t.name) === wanted);
298
299
  const target = matches.find((t) => t.type === type);
299
300
  if (!target) {
300
301
  const [firstMatch] = matches;
@@ -329,12 +330,6 @@ function validateSurfaceThemeConfiguration(themes) {
329
330
  }
330
331
  //#endregion
331
332
  //#region CSS Generation
332
- function createCssSurfaceName(name) {
333
- return name
334
- .toLowerCase()
335
- .replace(/\s+/g, '-')
336
- .replace(/[^a-z0-9-]/g, '');
337
- }
338
333
  function generateSurfaceThemeNameTypes(themes, schema) {
339
334
  const themesPath = schema.themesPath || 'src/surface-themes.ts';
340
335
  const outputPath = schema.outputPath || 'src/styles/generated-tailwind-surface-themes.css';
@@ -358,8 +353,6 @@ export {};
358
353
  `;
359
354
  }
360
355
  function generateSurfaceThemeCss(themes, utilityPrefix, runtimePrefix, schema) {
361
- const tailwindVars = [];
362
- const themeVars = [];
363
356
  const themesPath = schema.themesPath || 'src/surface-themes.ts';
364
357
  const outputPath = schema.outputPath || 'src/styles/generated-tailwind-surface-themes.css';
365
358
  const header = `/*
@@ -372,230 +365,7 @@ function generateSurfaceThemeCss(themes, utilityPrefix, runtimePrefix, schema) {
372
365
  */
373
366
 
374
367
  `;
375
- // Static Tailwind @theme block - one color set per surface theme
376
- for (const theme of themes) {
377
- const name = createCssSurfaceName(theme.name);
378
- tailwindVars.push(` /* ${theme.name} surface */`);
379
- tailwindVars.push(` --color-${utilityPrefix}-surface-${name}-bg: rgb(${theme.background});`);
380
- tailwindVars.push(` --color-${utilityPrefix}-surface-${name}: rgb(${theme.color});`);
381
- tailwindVars.push(` --color-${utilityPrefix}-surface-${name}-muted: rgb(${theme.colorMuted});`);
382
- tailwindVars.push(` --color-${utilityPrefix}-surface-${name}-subtle: rgb(${theme.colorSubtle});`);
383
- tailwindVars.push(` --color-${utilityPrefix}-surface-${name}-border: rgb(${theme.border});`);
384
- if (theme.interactionColor) {
385
- const { color, onColor, inkColor } = theme.interactionColor;
386
- pushStaticInteractionColors(tailwindVars, `--color-${utilityPrefix}-surface-${name}-interaction`, color);
387
- if (onColor) {
388
- pushStaticInteractionColors(tailwindVars, `--color-${utilityPrefix}-surface-${name}-on-interaction`, onColor);
389
- }
390
- if (inkColor) {
391
- pushStaticInteractionColors(tailwindVars, `--color-${utilityPrefix}-surface-${name}-interaction-ink`, inkColor);
392
- }
393
- }
394
- tailwindVars.push('');
395
- }
396
- // Dynamic surface colors (reference runtime CSS variables).
397
- // These are ALSO re-declared on every surface selector in the alias block below. A Tailwind
398
- // `@theme` variable only lands on `:root`, so `rgb(var(--<runtime>-surface-*))` resolves once
399
- // against the root surface and inherits that concrete color into descendants - which means
400
- // `bg-<prefix>-surface-*` utilities would ignore nested surface scopes (e.g. an elevated
401
- // surface). Re-declaring them per surface selector makes the utilities resolve against the
402
- // nearest surface instead.
403
- const dynamicSurfaceColors = buildDynamicSurfaceColors(utilityPrefix, runtimePrefix);
404
- tailwindVars.push(' /* Dynamic surface colors (references runtime CSS variables) */');
405
- tailwindVars.push(...dynamicSurfaceColors.map((decl) => ` ${decl}`));
406
- // Runtime CSS - theme selector classes
407
- for (const theme of themes) {
408
- const name = createCssSurfaceName(theme.name);
409
- const isDefault = theme.isDefault;
410
- if (isDefault) {
411
- const selectors = [`.${runtimePrefix}-surface--default-${theme.type}`, `.${runtimePrefix}-surface--${name}`];
412
- themeVars.push(`${selectors.join(', ')} {`);
413
- }
414
- else {
415
- themeVars.push(`.${runtimePrefix}-surface--${name} {`);
416
- }
417
- pushSurfaceVars(themeVars, runtimePrefix, theme, ' ');
418
- themeVars.push('}\n');
419
- }
420
- // Root defaults - apply the default surface vars to :root
421
- const defaultLight = themes.find((t) => t.isDefault && t.type === 'light');
422
- const defaultDark = themes.find((t) => t.isDefault && t.type === 'dark');
423
- if (defaultLight && defaultDark) {
424
- pushSchemeSurfaceVars(themeVars, runtimePrefix, defaultLight);
425
- pushSchemeSurfaceVars(themeVars, runtimePrefix, defaultDark);
426
- pushForcedSchemeSurfaceVars(themeVars, runtimePrefix, defaultLight);
427
- pushForcedSchemeSurfaceVars(themeVars, runtimePrefix, defaultDark);
428
- }
429
- else {
430
- // A single registered surface type has no other scheme to switch to, so its default must
431
- // land on :root unconditionally - behind prefers-color-scheme it would leave every surface
432
- // variable undefined for users whose OS asks for the scheme the app lacks.
433
- pushRootSurfaceVars(themeVars, runtimePrefix, defaultLight ?? defaultDark);
434
- }
435
- // Convenience var aliases - available on any element with a surface class or :root (via media queries)
436
- const aliasBlock = `/* Convenience aliases (rgb + solid variants) */
437
- @layer base {
438
- :root, :where([class*="${runtimePrefix}-surface--"]) {
439
- --${runtimePrefix}-surface-background-rgb: var(--${runtimePrefix}-surface-background);
440
- --${runtimePrefix}-surface-background-solid: rgb(var(--${runtimePrefix}-surface-background-rgb));
441
-
442
- --${runtimePrefix}-surface-color-rgb: var(--${runtimePrefix}-surface-color);
443
- --${runtimePrefix}-surface-color-solid: rgb(var(--${runtimePrefix}-surface-color-rgb));
444
-
445
- --${runtimePrefix}-surface-color-muted-rgb: var(--${runtimePrefix}-surface-color-muted);
446
- --${runtimePrefix}-surface-color-muted-solid: rgb(var(--${runtimePrefix}-surface-color-muted-rgb));
447
-
448
- --${runtimePrefix}-surface-color-subtle-rgb: var(--${runtimePrefix}-surface-color-subtle);
449
- --${runtimePrefix}-surface-color-subtle-solid: rgb(var(--${runtimePrefix}-surface-color-subtle-rgb));
450
-
451
- --${runtimePrefix}-surface-border-rgb: var(--${runtimePrefix}-surface-border);
452
- --${runtimePrefix}-surface-border-solid: rgb(var(--${runtimePrefix}-surface-border-rgb));
453
-
454
- --${runtimePrefix}-surface-interaction-rgb: var(--${runtimePrefix}-surface-interaction);
455
- --${runtimePrefix}-surface-interaction-solid: rgb(var(--${runtimePrefix}-surface-interaction-rgb));
456
-
457
- --${runtimePrefix}-surface-interaction-hover-rgb: var(--${runtimePrefix}-surface-interaction-hover);
458
- --${runtimePrefix}-surface-interaction-hover-solid: rgb(var(--${runtimePrefix}-surface-interaction-hover-rgb));
459
-
460
- --${runtimePrefix}-surface-interaction-focus-rgb: var(--${runtimePrefix}-surface-interaction-focus);
461
- --${runtimePrefix}-surface-interaction-focus-solid: rgb(var(--${runtimePrefix}-surface-interaction-focus-rgb));
462
-
463
- --${runtimePrefix}-surface-interaction-active-rgb: var(--${runtimePrefix}-surface-interaction-active);
464
- --${runtimePrefix}-surface-interaction-active-solid: rgb(var(--${runtimePrefix}-surface-interaction-active-rgb));
465
-
466
- --${runtimePrefix}-surface-interaction-disabled-rgb: var(--${runtimePrefix}-surface-interaction-disabled);
467
- --${runtimePrefix}-surface-interaction-disabled-solid: rgb(var(--${runtimePrefix}-surface-interaction-disabled-rgb));
468
-
469
- /* Dynamic Tailwind surface colors - re-declared per surface scope so that
470
- bg-${utilityPrefix}-surface-* utilities resolve against the nearest surface
471
- (e.g. a nested elevated surface) instead of the value computed once at :root. */
472
- ${dynamicSurfaceColors.map((decl) => ` ${decl}`).join('\n')}
473
- }
474
- }
475
- `;
476
- return `${header}@theme {
477
- ${tailwindVars.join('\n')}
478
- }
479
-
480
- @layer base {
481
- ${themeVars.join('\n')}
482
- }
483
-
484
- ${aliasBlock}
485
- ${buildSurfaceColorScope(runtimePrefix)}`;
486
- }
487
- // The reserved `surface` color scope. It bridges the two theming systems - color variables out of
488
- // surface variables - so `[etProvideColor]="'surface'"` renders a component in the neutral of
489
- // whatever surface it sits on. It lives here rather than in the SDK's own CSS because a stylesheet
490
- // shipped with `ProvideColorDirective` would land in every bundle that themes anything, and only
491
- // apps that use the scope should pay for it.
492
- function buildSurfaceColorScope(runtimePrefix) {
493
- const tint = `var(--${runtimePrefix}-surface-interaction, var(--${runtimePrefix}-surface-color))`;
494
- const on = `var(--${runtimePrefix}-surface-on-interaction, var(--${runtimePrefix}-surface-background))`;
495
- const ink = `var(--${runtimePrefix}-surface-interaction-ink, var(--${runtimePrefix}-surface-color))`;
496
- const state = (name, source, fallback) => INTERACTION_STATE_SUFFIXES.map((suffix) => ` --${runtimePrefix}-color-${name}${suffix}: ${suffix ? `var(--${runtimePrefix}-surface-${source}${suffix}, ${fallback})` : fallback};`).join('\n');
497
- return `/* The reserved \`surface\` color: resolves the color tokens from the ambient surface's neutral swatch. */
498
- @layer base {
499
- .${runtimePrefix}-color--surface {
500
- ${state('primary', 'interaction', tint)}
501
-
502
- ${state('on-primary', 'on-interaction', on)}
503
-
504
- ${state('primary-ink', 'interaction-ink', ink)}
505
- }
506
- }
507
- `;
508
- }
509
- // Dynamic surface color declarations (unindented). Emitted in `@theme` (so Tailwind generates
510
- // the utilities) and re-declared on every surface selector (so the utilities resolve per scope).
511
- function buildDynamicSurfaceColors(utilityPrefix, runtimePrefix) {
512
- // `on-interaction` and `interaction-ink` are optional per theme, so each falls back to the
513
- // surface's own background/color - the same defaults the `.<runtimePrefix>-color--surface`
514
- // bridge applies.
515
- const onFallback = `var(--${runtimePrefix}-surface-background)`;
516
- const inkFallback = `var(--${runtimePrefix}-surface-color)`;
517
- return [
518
- `--color-${utilityPrefix}-surface-bg: rgb(var(--${runtimePrefix}-surface-background));`,
519
- `--color-${utilityPrefix}-surface: rgb(var(--${runtimePrefix}-surface-color));`,
520
- `--color-${utilityPrefix}-surface-muted: rgb(var(--${runtimePrefix}-surface-color-muted));`,
521
- `--color-${utilityPrefix}-surface-subtle: rgb(var(--${runtimePrefix}-surface-color-subtle));`,
522
- `--color-${utilityPrefix}-surface-border: rgb(var(--${runtimePrefix}-surface-border));`,
523
- `--color-${utilityPrefix}-surface-interaction: rgb(var(--${runtimePrefix}-surface-interaction));`,
524
- `--color-${utilityPrefix}-surface-interaction-hover: rgb(var(--${runtimePrefix}-surface-interaction-hover));`,
525
- `--color-${utilityPrefix}-surface-interaction-focus: rgb(var(--${runtimePrefix}-surface-interaction-focus));`,
526
- `--color-${utilityPrefix}-surface-interaction-active: rgb(var(--${runtimePrefix}-surface-interaction-active));`,
527
- `--color-${utilityPrefix}-surface-interaction-disabled: rgb(var(--${runtimePrefix}-surface-interaction-disabled));`,
528
- ...INTERACTION_STATE_SUFFIXES.map((suffix) => `--color-${utilityPrefix}-surface-on-interaction${suffix}: rgb(var(--${runtimePrefix}-surface-on-interaction${suffix}, ${onFallback}));`),
529
- ...INTERACTION_STATE_SUFFIXES.map((suffix) => `--color-${utilityPrefix}-surface-interaction-ink${suffix}: rgb(var(--${runtimePrefix}-surface-interaction-ink${suffix}, ${inkFallback}));`),
530
- ];
531
- }
532
- const INTERACTION_STATE_SUFFIXES = ['', '-hover', '-focus', '-active', '-disabled'];
533
- // Fills the optional states from the ones that are set, matching how the color theme generator
534
- // resolves a swatch: hover falls back to default, focus to hover, active and disabled to default.
535
- function resolveInteractionStates(map) {
536
- const hover = map.hover || map.default;
537
- return {
538
- '': map.default,
539
- '-hover': hover,
540
- '-focus': map.focus || hover,
541
- '-active': map.active || map.default,
542
- '-disabled': map.disabled || map.default,
543
- };
544
- }
545
- function pushStaticInteractionColors(vars, name, map) {
546
- const states = resolveInteractionStates(map);
547
- for (const suffix of INTERACTION_STATE_SUFFIXES) {
548
- vars.push(` ${name}${suffix}: rgb(${states[suffix]});`);
549
- }
550
- }
551
- function pushRuntimeInteractionVars(vars, name, map, indent) {
552
- const states = resolveInteractionStates(map);
553
- for (const suffix of INTERACTION_STATE_SUFFIXES) {
554
- vars.push(`${indent}${name}${suffix}: ${states[suffix]};`);
555
- }
556
- }
557
- function pushRootSurfaceVars(vars, runtimePrefix, theme) {
558
- if (!theme)
559
- return;
560
- vars.push(`:root {`);
561
- pushSurfaceVars(vars, runtimePrefix, theme, ' ');
562
- vars.push(` color-scheme: ${theme.type};`);
563
- vars.push(`}\n`);
564
- }
565
- function pushSchemeSurfaceVars(vars, runtimePrefix, theme) {
566
- vars.push(`@media (prefers-color-scheme: ${theme.type}) {`);
567
- vars.push(` :root {`);
568
- pushSurfaceVars(vars, runtimePrefix, theme, ' ');
569
- vars.push(` color-scheme: ${theme.type};`);
570
- vars.push(` }`);
571
- vars.push(`}\n`);
572
- }
573
- // `:root.<prefix>-scheme--<type>` must out-specify the `:root` inside the media query above, so the
574
- // class set by `provideColorScheme()` overrides the OS preference regardless of source order.
575
- function pushForcedSchemeSurfaceVars(vars, runtimePrefix, theme) {
576
- vars.push(`:root.${runtimePrefix}-scheme--${theme.type} {`);
577
- pushSurfaceVars(vars, runtimePrefix, theme, ' ');
578
- vars.push(` color-scheme: ${theme.type};`);
579
- vars.push(`}\n`);
580
- }
581
- function pushSurfaceVars(vars, runtimePrefix, theme, indent) {
582
- vars.push(`${indent}--${runtimePrefix}-surface-background: ${theme.background};`);
583
- vars.push(`${indent}--${runtimePrefix}-surface-color: ${theme.color};`);
584
- vars.push(`${indent}--${runtimePrefix}-surface-color-muted: ${theme.colorMuted};`);
585
- vars.push(`${indent}--${runtimePrefix}-surface-color-subtle: ${theme.colorSubtle};`);
586
- vars.push(`${indent}--${runtimePrefix}-surface-border: ${theme.border};`);
587
- vars.push(`${indent}--${runtimePrefix}-surface-type: ${theme.type};`);
588
- vars.push(`${indent}--${runtimePrefix}-surface-elevation: ${theme.elevation};`);
589
- if (theme.interactionColor) {
590
- const { color, onColor, inkColor } = theme.interactionColor;
591
- pushRuntimeInteractionVars(vars, `--${runtimePrefix}-surface-interaction`, color, indent);
592
- if (onColor) {
593
- pushRuntimeInteractionVars(vars, `--${runtimePrefix}-surface-on-interaction`, onColor, indent);
594
- }
595
- if (inkColor) {
596
- pushRuntimeInteractionVars(vars, `--${runtimePrefix}-surface-interaction-ink`, inkColor, indent);
597
- }
598
- }
368
+ return `${header}${surfaceThemeCss(themes, { prefix: utilityPrefix, runtimePrefix })}`;
599
369
  }
600
370
  function findMainStylesFile(tree) {
601
371
  const potentialFiles = [];
package/package.json CHANGED
@@ -1,8 +1,23 @@
1
1
  {
2
2
  "name": "@ethlete/core",
3
- "version": "5.0.0-next.64",
3
+ "version": "5.0.0-next.65",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "https://github.com/ethlete-io/ethdk",
7
+ "directory": "libs/core"
8
+ },
4
9
  "license": "MIT",
5
10
  "sideEffects": false,
11
+ "exports": {
12
+ "./design/*": "./design/*.ts",
13
+ "./package.json": {
14
+ "default": "./package.json"
15
+ },
16
+ ".": {
17
+ "types": "./types/ethlete-core.d.ts",
18
+ "default": "./fesm2022/ethlete-core.mjs"
19
+ }
20
+ },
6
21
  "peerDependencies": {
7
22
  "@angular/common": "^22.1.0",
8
23
  "@angular/core": "^22.1.0",
@@ -33,15 +48,6 @@
33
48
  "generators": "./generators/generators.json",
34
49
  "module": "fesm2022/ethlete-core.mjs",
35
50
  "typings": "types/ethlete-core.d.ts",
36
- "exports": {
37
- "./package.json": {
38
- "default": "./package.json"
39
- },
40
- ".": {
41
- "types": "./types/ethlete-core.d.ts",
42
- "default": "./fesm2022/ethlete-core.mjs"
43
- }
44
- },
45
51
  "type": "module",
46
52
  "dependencies": {
47
53
  "tslib": "^2.3.0"