@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.
@@ -4,7 +4,7 @@ import { takeUntilDestroyed, toSignal, toObservable, outputFromObservable } from
4
4
  import { Subject, fromEvent, switchMap, startWith, of, defer, from, map, catchError, timer, takeUntil, tap, pairwise, debounceTime, merge, distinctUntilChanged, EMPTY, expand, skip, take, filter, BehaviorSubject, combineLatest, Observable, isObservable, firstValueFrom, defaultIfEmpty, concatMap, concat, finalize, exhaustMap, share, shareReplay, ReplaySubject } from 'rxjs';
5
5
  import { FormGroup, FormArray, FormControl } from '@angular/forms';
6
6
  import { SIGNAL, signalSetFn } from '@angular/core/primitives/signals';
7
- import { isPlatformBrowser, Location, DOCUMENT as DOCUMENT$1 } from '@angular/common';
7
+ import { isPlatformBrowser, Location, DOCUMENT as DOCUMENT$1, isPlatformServer } from '@angular/common';
8
8
  import { Router, NavigationEnd, NavigationSkipped, NavigationStart, NavigationError, RouterLink } from '@angular/router';
9
9
  import { Title, Meta, DomSanitizer } from '@angular/platform-browser';
10
10
  import { platform, offset, flip, shift, limitShift, computePosition, autoUpdate, hide, arrow, size } from '@floating-ui/dom';
@@ -4549,17 +4549,15 @@ const provideFocusVisibleTracker = /* @__PURE__ */ toProvideFn(FOCUS_VISIBLE_TRA
4549
4549
  const injectFocusVisibleTracker = /* @__PURE__ */ toInjectFn(FOCUS_VISIBLE_TRACKER_DEF);
4550
4550
  const FOCUS_VISIBLE_TRACKER_TOKEN = /* @__PURE__ */ toToken(FOCUS_VISIBLE_TRACKER_DEF);
4551
4551
 
4552
- const LOCALE_DEF = /* @__PURE__ */ defineRootProvider(() => {
4553
- const currentLocale = signal('en', /* @ts-ignore */
4554
- ...(ngDevMode ? [{ debugName: "currentLocale" }] : /* istanbul ignore next */ []));
4555
- return {
4556
- currentLocale,
4557
- };
4558
- }, {
4559
- name: 'Locale',
4552
+ const LOCALE = /* @__PURE__ */ new InjectionToken('Locale', {
4553
+ providedIn: 'root',
4554
+ factory: () => ({ currentLocale: signal('en') }),
4560
4555
  });
4561
- const provideLocale = /* @__PURE__ */ toProvideFn(LOCALE_DEF);
4562
- const injectLocale = /* @__PURE__ */ toInjectFn(LOCALE_DEF);
4556
+ /** Provides the app locale, starting at `locale` (default `'en'`). Change it later with `injectLocale().currentLocale.set(...)`. */
4557
+ const provideLocale = (locale) => [
4558
+ { provide: LOCALE, useFactory: () => ({ currentLocale: signal(locale ?? 'en') }) },
4559
+ ];
4560
+ const injectLocale = () => inject(LOCALE);
4563
4561
 
4564
4562
  const resolveSource = (source, locale) => typeof source === 'function' ? source(locale) : source;
4565
4563
  /**
@@ -4634,7 +4632,8 @@ const STYLE_MANAGER_DEF = /* @__PURE__ */ defineRootProvider(() => {
4634
4632
  const nextContainer = renderer.createElement('div');
4635
4633
  renderer.addClass(nextContainer, 'et-style-manager');
4636
4634
  renderer.setAttribute(nextContainer, 'aria-hidden', 'true');
4637
- renderer.setStyle(nextContainer, { display: 'none' });
4635
+ // A style attribute needs 'unsafe-inline' in a CSP's style-src-attr; a nonce does not cover it.
4636
+ renderer.setAttribute(nextContainer, 'hidden', '');
4638
4637
  renderer.appendChild(getContainerParent(), nextContainer);
4639
4638
  container = nextContainer;
4640
4639
  return nextContainer;
@@ -8016,6 +8015,8 @@ let middlewareExtras = null;
8016
8015
  const registerAnchoredPositionMiddlewareExtras = (extras) => {
8017
8016
  middlewareExtras = extras;
8018
8017
  };
8018
+ /** Whether `enableAnchoredOverlayPositionExtras()` has run, so `arrow`, `autoResize` and `autoHide` take effect. */
8019
+ const hasAnchoredOverlayPositionExtras = () => middlewareExtras !== null;
8019
8020
  const requireMiddlewareExtras = (feature) => {
8020
8021
  if (!middlewareExtras && isDevMode()) {
8021
8022
  console.error(`An anchored overlay uses "${feature}", but the matching floating-ui middleware is not installed. Call \`enableAnchoredOverlayPositionExtras()\` from @ethlete/core once during app setup.`);
@@ -8135,11 +8136,14 @@ const createAnchoredPositionCleanup = (strategy, paneElement, overlayRef, render
8135
8136
  if (strategy.minAvailableSpace !== undefined && !strategy.autoResize && isDevMode()) {
8136
8137
  console.error('An anchored overlay sets `minAvailableSpace` without `autoResize`, so it is kept on a side it does not fit on with nothing capping it to the space there. Enable `autoResize` or drop `minAvailableSpace`.');
8137
8138
  }
8139
+ // A width the pane declares through `--et-overlay-width` must survive positioning, and the pane
8140
+ // has to be measured at it - the variable may be set only after this runs.
8141
+ const declaredWidth = () => paneElement.style.getPropertyValue('--et-overlay-width') || null;
8138
8142
  renderer.setStyle(paneElement, {
8139
8143
  position: 'absolute',
8140
8144
  top: '0',
8141
8145
  left: '0',
8142
- width: mirrorWidthElement ? `${mirrorWidthElement.offsetWidth}px` : 'max-content',
8146
+ width: mirrorWidthElement ? `${mirrorWidthElement.offsetWidth}px` : 'var(--et-overlay-width, max-content)',
8143
8147
  });
8144
8148
  /**
8145
8149
  * What to do when the reference is not somewhere the pane can be positioned against: either removed
@@ -8253,7 +8257,7 @@ const createAnchoredPositionCleanup = (strategy, paneElement, overlayRef, render
8253
8257
  }
8254
8258
  renderer.setStyle(paneElement, {
8255
8259
  transform: `translate3d(${x}px, ${y}px, 0)`,
8256
- width: mirrorWidthElement ? `${mirrorWidthElement.offsetWidth}px` : null,
8260
+ width: mirrorWidthElement ? `${mirrorWidthElement.offsetWidth}px` : declaredWidth(),
8257
8261
  visibility: null,
8258
8262
  });
8259
8263
  // exposed so animations can compose their transforms with the anchored position
@@ -9694,6 +9698,152 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
9694
9698
  }], ctorParameters: () => [] });
9695
9699
 
9696
9700
  const COLOR_SCHEME_TYPE = new InjectionToken('ColorSchemeType');
9701
+ /** True while the scheme is only known to CSS: a server render in `system` mode with a default per surface type. */
9702
+ const COLOR_SCHEME_UNRESOLVED = new InjectionToken('ColorSchemeUnresolved');
9703
+
9704
+ const COLOR_PROVIDER = new InjectionToken('ColorProvider');
9705
+ /**
9706
+ * The color provider attached to a bootstrapped root component (e.g. `ProvideColorDirective` in
9707
+ * the app component's `hostDirectives`), if any. Detached DOM such as overlay panes can't reach
9708
+ * it through element DI, so overlay containers fall back to this when resolving the provider to
9709
+ * `syncWithProvider()` - resolve at sync time, not at injection time, since root components only
9710
+ * register with `ApplicationRef` once bootstrap completes.
9711
+ */
9712
+ const resolveAppRootColorProvider = (appRef) => {
9713
+ for (const componentRef of appRef.components) {
9714
+ const provider = componentRef.injector.get(COLOR_PROVIDER, null);
9715
+ if (provider) {
9716
+ return provider;
9717
+ }
9718
+ }
9719
+ return null;
9720
+ };
9721
+ const FORCED_COLOR_UNSET = /* @__PURE__ */ Symbol('FORCED_COLOR_UNSET');
9722
+ const appsWarnedAboutMissingThemes = /* @__PURE__ */ new WeakSet();
9723
+ class ProvideColorDirective {
9724
+ constructor() {
9725
+ this.themes = injectColorThemes({ optional: true });
9726
+ this.prefix = injectColorThemesPrefix({ optional: true });
9727
+ this.injector = inject(Injector);
9728
+ this.rootSurfaceTheme = injectRootSurfaceTheme();
9729
+ this.parentProvider = inject(COLOR_PROVIDER, { optional: true, skipSelf: true });
9730
+ this.appRef = inject(ApplicationRef);
9731
+ this.currentProviderSync = null;
9732
+ this.forcedColor = signal(FORCED_COLOR_UNSET, /* @ts-ignore */
9733
+ ...(ngDevMode ? [{ debugName: "forcedColor" }] : /* istanbul ignore next */ []));
9734
+ this.color = input(undefined, { ...(ngDevMode ? { debugName: "color" } : /* istanbul ignore next */ {}), alias: 'etProvideColor' });
9735
+ this.effectiveColor = computed(() => {
9736
+ const forcedColor = this.forcedColor();
9737
+ if (forcedColor !== FORCED_COLOR_UNSET) {
9738
+ return forcedColor;
9739
+ }
9740
+ return this.color();
9741
+ }, /* @ts-ignore */
9742
+ ...(ngDevMode ? [{ debugName: "effectiveColor" }] : /* istanbul ignore next */ []));
9743
+ /**
9744
+ * The color that actually applies at this provider's location: its own effective color, or -
9745
+ * when this provider is passive (no input, nothing forced) - the nearest ancestor provider's.
9746
+ * Mirrors the CSS cascade, which falls through a provider's `-color--inherited` scope class;
9747
+ * consumers that re-apply context across detached DOM (overlay panes) must use this instead
9748
+ * of `effectiveColor` or a passive in-between provider (e.g. a form field's) erases the theme.
9749
+ */
9750
+ this.resolvedColor = computed(() => {
9751
+ const own = this.effectiveColor();
9752
+ const ownName = typeof own === 'object' && own !== null ? own.name : own;
9753
+ if (ownName) {
9754
+ return own;
9755
+ }
9756
+ return this.parentProvider?.resolvedColor();
9757
+ }, /* @ts-ignore */
9758
+ ...(ngDevMode ? [{ debugName: "resolvedColor" }] : /* istanbul ignore next */ []));
9759
+ this.colorName = computed(() => {
9760
+ const raw = this.effectiveColor();
9761
+ const value = typeof raw === 'object' && raw !== null ? raw.name : raw;
9762
+ if (value === SURFACE_COLOR)
9763
+ return SURFACE_COLOR;
9764
+ if (!value)
9765
+ return;
9766
+ if (!this.themes) {
9767
+ if (isDevMode() && !appsWarnedAboutMissingThemes.has(this.appRef)) {
9768
+ appsWarnedAboutMissingThemes.add(this.appRef);
9769
+ console.warn(`etProvideColor="${value}" has no effect because no color themes are registered. Please make sure to add provideColorThemesWithTailwind4()`);
9770
+ }
9771
+ return;
9772
+ }
9773
+ if (isDevMode() && !this.themes.some((theme) => theme.name === value)) {
9774
+ console.error(`Theme ${value} does not exist. Please make sure to add it to provideColorThemesWithTailwind4()`);
9775
+ }
9776
+ return createCssColorThemeName(value);
9777
+ }, /* @ts-ignore */
9778
+ ...(ngDevMode ? [{ debugName: "colorName" }] : /* istanbul ignore next */ []));
9779
+ this.paintedColorName = computed(() => {
9780
+ const raw = this.effectiveColor();
9781
+ const value = typeof raw === 'object' && raw !== null ? raw.name : raw;
9782
+ if (!this.colorName() || !value)
9783
+ return;
9784
+ const surface = this.injector.get(SURFACE_PROVIDER, null)?.activeTheme() ?? this.rootSurfaceTheme();
9785
+ const variant = resolveColorThemeVariant(surface, value, this.themes);
9786
+ if (variant === value)
9787
+ return this.colorName();
9788
+ if (isDevMode() && !this.themes?.some((theme) => theme.name === variant)) {
9789
+ console.error(`Surface theme ${surface?.name} names the color theme ${variant}, which does not exist. Please make sure to add it to provideColorThemesWithTailwind4()`);
9790
+ }
9791
+ return createCssColorThemeName(variant);
9792
+ }, /* @ts-ignore */
9793
+ ...(ngDevMode ? [{ debugName: "paintedColorName" }] : /* istanbul ignore next */ []));
9794
+ this.themeClass = computed(() => {
9795
+ const prefix = this.prefix || 'et';
9796
+ const name = this.paintedColorName();
9797
+ return name ? `${prefix}-color--${name}` : `${prefix}-color--inherited`;
9798
+ }, /* @ts-ignore */
9799
+ ...(ngDevMode ? [{ debugName: "themeClass" }] : /* istanbul ignore next */ []));
9800
+ }
9801
+ syncWithProvider(provider) {
9802
+ this.currentProviderSync?.destroy();
9803
+ runInInjectionContext(this.injector, () => {
9804
+ this.currentProviderSync = effect(() => {
9805
+ const provideColor = provider.resolvedColor();
9806
+ untracked(() => {
9807
+ if (provideColor === undefined) {
9808
+ this.clearForcedColor();
9809
+ return;
9810
+ }
9811
+ this.forceColor(provideColor);
9812
+ });
9813
+ }, /* @ts-ignore */
9814
+ ...(ngDevMode ? [{ debugName: "currentProviderSync" }] : /* istanbul ignore next */ []));
9815
+ });
9816
+ }
9817
+ stopSyncWithProvider() {
9818
+ const hadProviderSync = !!this.currentProviderSync;
9819
+ this.currentProviderSync?.destroy();
9820
+ this.currentProviderSync = null;
9821
+ if (hadProviderSync) {
9822
+ this.clearForcedColor();
9823
+ }
9824
+ }
9825
+ forceColor(color) {
9826
+ this.forcedColor.set(color);
9827
+ }
9828
+ clearForcedColor() {
9829
+ if (this.forcedColor() === FORCED_COLOR_UNSET) {
9830
+ return;
9831
+ }
9832
+ this.forcedColor.set(FORCED_COLOR_UNSET);
9833
+ }
9834
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ProvideColorDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
9835
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.6", type: ProvideColorDirective, isStandalone: true, selector: "[etProvideColor]", inputs: { color: { classPropertyName: "color", publicName: "etProvideColor", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "themeClass()" } }, providers: [{ provide: COLOR_PROVIDER, useExisting: ProvideColorDirective }], ngImport: i0 }); }
9836
+ }
9837
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ProvideColorDirective, decorators: [{
9838
+ type: Directive,
9839
+ args: [{
9840
+ selector: '[etProvideColor]',
9841
+ providers: [{ provide: COLOR_PROVIDER, useExisting: ProvideColorDirective }],
9842
+ host: {
9843
+ '[class]': 'themeClass()',
9844
+ },
9845
+ }]
9846
+ }], propDecorators: { color: [{ type: i0.Input, args: [{ isSignal: true, alias: "etProvideColor", required: false }] }] } });
9697
9847
 
9698
9848
  const TOLERANCE_PX = 0.5;
9699
9849
  const readFontSizePx = (view, element) => {
@@ -9795,348 +9945,6 @@ const injectDefaultSurfaceTheme = (type) => {
9795
9945
  return defaults.length === 1 ? (defaults[0] ?? null) : null;
9796
9946
  };
9797
9947
 
9798
- const findRootSurfaceTheme = (defaults, type) => {
9799
- if (defaults.length <= 1)
9800
- return defaults[0] ?? null;
9801
- return defaults.find((theme) => theme.type === type) ?? null;
9802
- };
9803
- const COLOR_SCHEME_DEF = /* @__PURE__ */ defineProvider(() => {
9804
- const root = inject(DOCUMENT).documentElement;
9805
- const prefix = injectSurfaceThemesPrefix({ optional: true }) || 'et';
9806
- const prefersDark = injectBreakpointObserver().observeMediaQuery('(prefers-color-scheme: dark)');
9807
- const mode = signal('system', /* @ts-ignore */
9808
- ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
9809
- const surfaceDefaults = injectSurfaceThemes({ optional: true })?.filter((theme) => theme.isDefault) ?? [];
9810
- const colorThemes = injectColorThemes({ optional: true });
9811
- const colorPrefix = injectColorThemesPrefix({ optional: true }) || 'et';
9812
- const type = computed(() => {
9813
- const current = mode();
9814
- if (current !== 'system')
9815
- return current;
9816
- return prefersDark() ? 'dark' : 'light';
9817
- }, /* @ts-ignore */
9818
- ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
9819
- const rootSurface = computed(() => findRootSurfaceTheme(surfaceDefaults, type()), /* @ts-ignore */
9820
- ...(ngDevMode ? [{ debugName: "rootSurface" }] : /* istanbul ignore next */ []));
9821
- const rootColorClass = computed(() => {
9822
- const chosen = colorThemes?.find((theme) => theme.isDefault)?.name;
9823
- if (!chosen)
9824
- return null;
9825
- const variant = resolveColorThemeVariant(rootSurface(), chosen, colorThemes);
9826
- return variant === chosen ? null : `${colorPrefix}-color--${createCssColorThemeName(variant)}`;
9827
- }, /* @ts-ignore */
9828
- ...(ngDevMode ? [{ debugName: "rootColorClass" }] : /* istanbul ignore next */ []));
9829
- let paintedColorClass = null;
9830
- const clearColorClass = () => {
9831
- if (paintedColorClass)
9832
- root.classList.remove(paintedColorClass);
9833
- paintedColorClass = null;
9834
- };
9835
- effect(() => {
9836
- const next = rootColorClass();
9837
- clearColorClass();
9838
- if (next)
9839
- root.classList.add(next);
9840
- paintedColorClass = next;
9841
- });
9842
- const clearClasses = () => root.classList.remove(`${prefix}-scheme--light`, `${prefix}-scheme--dark`);
9843
- const setMode = (next) => {
9844
- clearClasses();
9845
- if (next !== 'system')
9846
- root.classList.add(`${prefix}-scheme--${next}`);
9847
- mode.set(next);
9848
- };
9849
- inject(DestroyRef).onDestroy(() => {
9850
- clearClasses();
9851
- clearColorClass();
9852
- });
9853
- return { mode: mode.asReadonly(), type, rootSurface, setMode };
9854
- }, { name: 'Color Scheme' });
9855
- const provideColorSchemeState = /* @__PURE__ */ toProvideFn(COLOR_SCHEME_DEF);
9856
- /**
9857
- * Inject the app's color scheme: `mode()` is what the app asked for, `type()` the surface type the
9858
- * root paints, `rootSurface()` the default surface theme of that type, and `setMode()` switches it.
9859
- * Needs `provideColorScheme()`.
9860
- */
9861
- const injectColorScheme = /* @__PURE__ */ toInjectFn(COLOR_SCHEME_DEF);
9862
- /**
9863
- * Lets the app switch between its default light and dark surface with a class on `<html>`, instead of
9864
- * only following `prefers-color-scheme`. It also paints the root surface's `colorThemeVariants` entry for the
9865
- * default accent on `<html>`. Add it to the application config, next to
9866
- * `provideSurfaceThemesWithTailwind4()`.
9867
- */
9868
- const provideColorScheme = (config) => makeEnvironmentProviders([
9869
- provideColorSchemeState(),
9870
- { provide: COLOR_SCHEME_TYPE, useFactory: () => injectColorScheme().type },
9871
- provideEnvironmentInitializer(() => injectColorScheme().setMode(config?.mode ?? 'system')),
9872
- ]);
9873
- /**
9874
- * Inject a signal of the default surface theme the root paints where nothing scopes one. If the app
9875
- * registers a default for both surface types, it follows `injectColorScheme()`, and is `null` without
9876
- * `provideColorScheme()`.
9877
- */
9878
- const injectRootSurfaceTheme = () => {
9879
- const defaults = injectSurfaceThemes({ optional: true })?.filter((theme) => theme.isDefault) ?? [];
9880
- const colorSchemeType = inject(COLOR_SCHEME_TYPE, { optional: true });
9881
- return computed(() => findRootSurfaceTheme(defaults, colorSchemeType?.()));
9882
- };
9883
-
9884
- /**
9885
- * Reserved color name. Resolves the color tokens from the ambient surface's neutral swatch
9886
- * (`SurfaceTheme['interactionColor']`) instead of a registered accent, so a secondary action can
9887
- * read as chrome without the app registering a neutral color theme. Apps must not register a color
9888
- * theme under this name.
9889
- */
9890
- const SURFACE_COLOR = 'surface';
9891
- const createCssColorThemeName = (name) => name.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
9892
- const COLOR_THEMES_DEF = /* @__PURE__ */ defineStaticProvider(undefined, {
9893
- name: 'Color Themes',
9894
- });
9895
- const ɵProvideColorThemes = /* @__PURE__ */ toProvideFn(COLOR_THEMES_DEF);
9896
- const injectColorThemes = /* @__PURE__ */ toInjectFn(COLOR_THEMES_DEF);
9897
- const COLOR_THEMES_PREFIX_DEF = /* @__PURE__ */ defineStaticProvider('et', {
9898
- name: 'Themes Prefix',
9899
- });
9900
- const ɵProvideColorThemesPrefix = /* @__PURE__ */ toProvideFn(COLOR_THEMES_PREFIX_DEF);
9901
- const injectColorThemesPrefix = /* @__PURE__ */ toInjectFn(COLOR_THEMES_PREFIX_DEF);
9902
- const provideColorThemesWithTailwind4 = (themes, prefix = 'et') => {
9903
- if (isDevMode() && themes.some((theme) => theme.name === SURFACE_COLOR)) {
9904
- console.error(`[provideColorThemesWithTailwind4] "${SURFACE_COLOR}" is a reserved color name that resolves to the ambient surface's neutral swatch. Rename your theme.`);
9905
- }
9906
- return [ɵProvideColorThemes(themes), ɵProvideColorThemesPrefix(prefix)];
9907
- };
9908
- const findColorThemeByType = (themes, type, caller) => {
9909
- if (!themes) {
9910
- throw new Error(`[${caller}] No color themes provided. Call provideColorThemesWithTailwind4() in your app config.`);
9911
- }
9912
- const theme = themes.find((t) => t.type === type);
9913
- if (!theme) {
9914
- throw new Error(`[${caller}] No color theme with type "${type}" found. Add a theme with type: "${type}" to provideColorThemesWithTailwind4().`);
9915
- }
9916
- if (isDevMode()) {
9917
- const duplicates = themes.filter((t) => t.type === type);
9918
- if (duplicates.length > 1) {
9919
- console.error(`[${caller}] Multiple themes with type "${type}" found: ${duplicates.map((t) => t.name).join(', ')}. Only the first one will be used.`);
9920
- }
9921
- }
9922
- return theme;
9923
- };
9924
- const injectColorThemeByType = (type) => findColorThemeByType(injectColorThemes({ optional: true }), type, 'injectColorThemeByType');
9925
- /**
9926
- * The color theme name that draws `chosenName` on `surface`: the surface's `colorThemeVariants` entry for it,
9927
- * else `chosenName` itself. Always pass the chosen accent, never an already swapped one.
9928
- */
9929
- const resolveColorThemeVariant = (surface, chosenName, themes) => {
9930
- if (!surface || chosenName === SURFACE_COLOR)
9931
- return chosenName;
9932
- const variants = surface.colorThemeVariants;
9933
- const variant = variants?.[chosenName];
9934
- if (variant)
9935
- return variant;
9936
- const chosen = themes?.find((t) => t.name === chosenName);
9937
- const semantic = chosen?.type ? surface.semanticColorThemes?.[chosen.type] : undefined;
9938
- if (semantic)
9939
- return semantic;
9940
- if (surface.colorTheme && chosen?.isDefault)
9941
- return surface.colorTheme;
9942
- return chosenName;
9943
- };
9944
- /**
9945
- * A signal of the color theme for `type` on the surface this element renders on: the first registered theme
9946
- * of that `type`, swapped for the nearest surface's `colorThemeVariants` entry. Reading it throws when the app
9947
- * registered no theme of that `type`, so read it only for a state that renders.
9948
- *
9949
- * @example
9950
- * protected successTheme = injectSemanticColorTheme('success');
9951
- * // <span [etProvideColor]="successTheme()">+12%</span>
9952
- */
9953
- const injectSemanticColorTheme = (type) => {
9954
- const themes = injectColorThemes({ optional: true });
9955
- const surfaceProvider = inject(SURFACE_PROVIDER, { optional: true });
9956
- const rootSurface = injectRootSurfaceTheme();
9957
- return computed(() => {
9958
- const chosen = findColorThemeByType(themes, type, 'injectSemanticColorTheme');
9959
- const surface = surfaceProvider?.activeTheme() ?? rootSurface();
9960
- const variantName = resolveColorThemeVariant(surface, chosen.name, themes);
9961
- if (variantName === chosen.name)
9962
- return chosen;
9963
- const variant = themes?.find((t) => t.name === variantName);
9964
- if (variant)
9965
- return variant;
9966
- if (isDevMode()) {
9967
- console.error(`[injectSemanticColorTheme] Surface theme "${surface?.name}" maps "${type}" to the color theme "${variantName}", which is not registered. Add it to provideColorThemesWithTailwind4().`);
9968
- }
9969
- return chosen;
9970
- });
9971
- };
9972
- /** @deprecated Use `injectSemanticColorTheme('error')`, which follows the surface the element renders on. */
9973
- const injectErrorTheme = () => injectColorThemeByType('error');
9974
- /** @deprecated Use `injectSemanticColorTheme('warning')`, which follows the surface the element renders on. */
9975
- const injectWarningTheme = () => injectColorThemeByType('warning');
9976
- /** @deprecated Use `injectSemanticColorTheme('success')`, which follows the surface the element renders on. */
9977
- const injectSuccessTheme = () => injectColorThemeByType('success');
9978
- const injectDefaultColorTheme = () => {
9979
- const themes = injectColorThemes({ optional: true });
9980
- if (!themes) {
9981
- throw new Error(`[injectDefaultColorTheme] No color themes provided. Call provideColorThemesWithTailwind4() in your app config.`);
9982
- }
9983
- const theme = themes.find((t) => t.isDefault);
9984
- if (!theme) {
9985
- throw new Error(`[injectDefaultColorTheme] No color theme with isDefault: true found. Mark one theme as the default in provideColorThemesWithTailwind4().`);
9986
- }
9987
- if (isDevMode()) {
9988
- const duplicates = themes.filter((t) => t.isDefault);
9989
- if (duplicates.length > 1) {
9990
- console.error(`[injectDefaultColorTheme] Multiple themes with isDefault: true found: ${duplicates.map((t) => t.name).join(', ')}. Only the first one will be used.`);
9991
- }
9992
- }
9993
- return theme;
9994
- };
9995
-
9996
- const COLOR_PROVIDER = new InjectionToken('ColorProvider');
9997
- /**
9998
- * The color provider attached to a bootstrapped root component (e.g. `ProvideColorDirective` in
9999
- * the app component's `hostDirectives`), if any. Detached DOM such as overlay panes can't reach
10000
- * it through element DI, so overlay containers fall back to this when resolving the provider to
10001
- * `syncWithProvider()` - resolve at sync time, not at injection time, since root components only
10002
- * register with `ApplicationRef` once bootstrap completes.
10003
- */
10004
- const resolveAppRootColorProvider = (appRef) => {
10005
- for (const componentRef of appRef.components) {
10006
- const provider = componentRef.injector.get(COLOR_PROVIDER, null);
10007
- if (provider) {
10008
- return provider;
10009
- }
10010
- }
10011
- return null;
10012
- };
10013
- const FORCED_COLOR_UNSET = /* @__PURE__ */ Symbol('FORCED_COLOR_UNSET');
10014
- const appsWarnedAboutMissingThemes = /* @__PURE__ */ new WeakSet();
10015
- class ProvideColorDirective {
10016
- constructor() {
10017
- this.themes = injectColorThemes({ optional: true });
10018
- this.prefix = injectColorThemesPrefix({ optional: true });
10019
- this.injector = inject(Injector);
10020
- this.rootSurfaceTheme = injectRootSurfaceTheme();
10021
- this.parentProvider = inject(COLOR_PROVIDER, { optional: true, skipSelf: true });
10022
- this.appRef = inject(ApplicationRef);
10023
- this.currentProviderSync = null;
10024
- this.forcedColor = signal(FORCED_COLOR_UNSET, /* @ts-ignore */
10025
- ...(ngDevMode ? [{ debugName: "forcedColor" }] : /* istanbul ignore next */ []));
10026
- this.color = input(undefined, { ...(ngDevMode ? { debugName: "color" } : /* istanbul ignore next */ {}), alias: 'etProvideColor' });
10027
- this.effectiveColor = computed(() => {
10028
- const forcedColor = this.forcedColor();
10029
- if (forcedColor !== FORCED_COLOR_UNSET) {
10030
- return forcedColor;
10031
- }
10032
- return this.color();
10033
- }, /* @ts-ignore */
10034
- ...(ngDevMode ? [{ debugName: "effectiveColor" }] : /* istanbul ignore next */ []));
10035
- /**
10036
- * The color that actually applies at this provider's location: its own effective color, or -
10037
- * when this provider is passive (no input, nothing forced) - the nearest ancestor provider's.
10038
- * Mirrors the CSS cascade, which falls through a provider's `-color--inherited` scope class;
10039
- * consumers that re-apply context across detached DOM (overlay panes) must use this instead
10040
- * of `effectiveColor` or a passive in-between provider (e.g. a form field's) erases the theme.
10041
- */
10042
- this.resolvedColor = computed(() => {
10043
- const own = this.effectiveColor();
10044
- const ownName = typeof own === 'object' && own !== null ? own.name : own;
10045
- if (ownName) {
10046
- return own;
10047
- }
10048
- return this.parentProvider?.resolvedColor();
10049
- }, /* @ts-ignore */
10050
- ...(ngDevMode ? [{ debugName: "resolvedColor" }] : /* istanbul ignore next */ []));
10051
- this.colorName = computed(() => {
10052
- const raw = this.effectiveColor();
10053
- const value = typeof raw === 'object' && raw !== null ? raw.name : raw;
10054
- if (value === SURFACE_COLOR)
10055
- return SURFACE_COLOR;
10056
- if (!value)
10057
- return;
10058
- if (!this.themes) {
10059
- if (isDevMode() && !appsWarnedAboutMissingThemes.has(this.appRef)) {
10060
- appsWarnedAboutMissingThemes.add(this.appRef);
10061
- console.warn(`etProvideColor="${value}" has no effect because no color themes are registered. Please make sure to add provideColorThemesWithTailwind4()`);
10062
- }
10063
- return;
10064
- }
10065
- if (isDevMode() && !this.themes.some((theme) => theme.name === value)) {
10066
- console.error(`Theme ${value} does not exist. Please make sure to add it to provideColorThemesWithTailwind4()`);
10067
- }
10068
- return createCssColorThemeName(value);
10069
- }, /* @ts-ignore */
10070
- ...(ngDevMode ? [{ debugName: "colorName" }] : /* istanbul ignore next */ []));
10071
- this.paintedColorName = computed(() => {
10072
- const raw = this.effectiveColor();
10073
- const value = typeof raw === 'object' && raw !== null ? raw.name : raw;
10074
- if (!this.colorName() || !value)
10075
- return;
10076
- const surface = this.injector.get(SURFACE_PROVIDER, null)?.activeTheme() ?? this.rootSurfaceTheme();
10077
- const variant = resolveColorThemeVariant(surface, value, this.themes);
10078
- if (variant === value)
10079
- return this.colorName();
10080
- if (isDevMode() && !this.themes?.some((theme) => theme.name === variant)) {
10081
- console.error(`Surface theme ${surface?.name} names the color theme ${variant}, which does not exist. Please make sure to add it to provideColorThemesWithTailwind4()`);
10082
- }
10083
- return createCssColorThemeName(variant);
10084
- }, /* @ts-ignore */
10085
- ...(ngDevMode ? [{ debugName: "paintedColorName" }] : /* istanbul ignore next */ []));
10086
- this.themeClass = computed(() => {
10087
- const prefix = this.prefix || 'et';
10088
- const name = this.paintedColorName();
10089
- return name ? `${prefix}-color--${name}` : `${prefix}-color--inherited`;
10090
- }, /* @ts-ignore */
10091
- ...(ngDevMode ? [{ debugName: "themeClass" }] : /* istanbul ignore next */ []));
10092
- }
10093
- syncWithProvider(provider) {
10094
- this.currentProviderSync?.destroy();
10095
- runInInjectionContext(this.injector, () => {
10096
- this.currentProviderSync = effect(() => {
10097
- const provideColor = provider.resolvedColor();
10098
- untracked(() => {
10099
- if (provideColor === undefined) {
10100
- this.clearForcedColor();
10101
- return;
10102
- }
10103
- this.forceColor(provideColor);
10104
- });
10105
- }, /* @ts-ignore */
10106
- ...(ngDevMode ? [{ debugName: "currentProviderSync" }] : /* istanbul ignore next */ []));
10107
- });
10108
- }
10109
- stopSyncWithProvider() {
10110
- const hadProviderSync = !!this.currentProviderSync;
10111
- this.currentProviderSync?.destroy();
10112
- this.currentProviderSync = null;
10113
- if (hadProviderSync) {
10114
- this.clearForcedColor();
10115
- }
10116
- }
10117
- forceColor(color) {
10118
- this.forcedColor.set(color);
10119
- }
10120
- clearForcedColor() {
10121
- if (this.forcedColor() === FORCED_COLOR_UNSET) {
10122
- return;
10123
- }
10124
- this.forcedColor.set(FORCED_COLOR_UNSET);
10125
- }
10126
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ProvideColorDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
10127
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.6", type: ProvideColorDirective, isStandalone: true, selector: "[etProvideColor]", inputs: { color: { classPropertyName: "color", publicName: "etProvideColor", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "themeClass()" } }, providers: [{ provide: COLOR_PROVIDER, useExisting: ProvideColorDirective }], ngImport: i0 }); }
10128
- }
10129
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ProvideColorDirective, decorators: [{
10130
- type: Directive,
10131
- args: [{
10132
- selector: '[etProvideColor]',
10133
- providers: [{ provide: COLOR_PROVIDER, useExisting: ProvideColorDirective }],
10134
- host: {
10135
- '[class]': 'themeClass()',
10136
- },
10137
- }]
10138
- }], propDecorators: { color: [{ type: i0.Input, args: [{ isSignal: true, alias: "etProvideColor", required: false }] }] } });
10139
-
10140
9948
  const SURFACE_PROVIDER = new InjectionToken('SurfaceProvider');
10141
9949
  const FORCED_SURFACE_UNSET = /* @__PURE__ */ Symbol('FORCED_SURFACE_UNSET');
10142
9950
  class ProvideSurfaceDirective {
@@ -10303,6 +10111,219 @@ const injectParentSurface = () => {
10303
10111
  return computed(() => provider?.activeTheme() ?? rootTheme());
10304
10112
  };
10305
10113
 
10114
+ /**
10115
+ * Reserved color name. Resolves the color tokens from the ambient surface's neutral swatch
10116
+ * (`SurfaceTheme['interactionColor']`) instead of a registered accent, so a secondary action can
10117
+ * read as chrome without the app registering a neutral color theme. Apps must not register a color
10118
+ * theme under this name.
10119
+ */
10120
+ const SURFACE_COLOR = 'surface';
10121
+ const createCssColorThemeName = (name) => name.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
10122
+ const COLOR_THEMES_DEF = /* @__PURE__ */ defineStaticProvider(undefined, {
10123
+ name: 'Color Themes',
10124
+ });
10125
+ const ɵProvideColorThemes = /* @__PURE__ */ toProvideFn(COLOR_THEMES_DEF);
10126
+ const injectColorThemes = /* @__PURE__ */ toInjectFn(COLOR_THEMES_DEF);
10127
+ const COLOR_THEMES_PREFIX_DEF = /* @__PURE__ */ defineStaticProvider('et', {
10128
+ name: 'Themes Prefix',
10129
+ });
10130
+ const ɵProvideColorThemesPrefix = /* @__PURE__ */ toProvideFn(COLOR_THEMES_PREFIX_DEF);
10131
+ const injectColorThemesPrefix = /* @__PURE__ */ toInjectFn(COLOR_THEMES_PREFIX_DEF);
10132
+ const provideColorThemesWithTailwind4 = (themes, prefix = 'et') => {
10133
+ if (isDevMode() && themes.some((theme) => theme.name === SURFACE_COLOR)) {
10134
+ console.error(`[provideColorThemesWithTailwind4] "${SURFACE_COLOR}" is a reserved color name that resolves to the ambient surface's neutral swatch. Rename your theme.`);
10135
+ }
10136
+ return [ɵProvideColorThemes(themes), ɵProvideColorThemesPrefix(prefix)];
10137
+ };
10138
+ const findColorThemeByType = (themes, type, caller) => {
10139
+ if (!themes) {
10140
+ throw new Error(`[${caller}] No color themes provided. Call provideColorThemesWithTailwind4() in your app config.`);
10141
+ }
10142
+ const theme = themes.find((t) => t.type === type);
10143
+ if (!theme) {
10144
+ throw new Error(`[${caller}] No color theme with type "${type}" found. Add a theme with type: "${type}" to provideColorThemesWithTailwind4().`);
10145
+ }
10146
+ if (isDevMode()) {
10147
+ const duplicates = themes.filter((t) => t.type === type);
10148
+ if (duplicates.length > 1) {
10149
+ console.error(`[${caller}] Multiple themes with type "${type}" found: ${duplicates.map((t) => t.name).join(', ')}. Only the first one will be used.`);
10150
+ }
10151
+ }
10152
+ return theme;
10153
+ };
10154
+ const injectColorThemeByType = (type) => findColorThemeByType(injectColorThemes({ optional: true }), type, 'injectColorThemeByType');
10155
+ /**
10156
+ * The color theme name that draws `chosenName` on `surface`: the surface's `colorThemeVariants` entry for it,
10157
+ * else `chosenName` itself. Always pass the chosen accent, never an already swapped one.
10158
+ */
10159
+ const resolveColorThemeVariant = (surface, chosenName, themes) => {
10160
+ if (!surface || chosenName === SURFACE_COLOR)
10161
+ return chosenName;
10162
+ const variants = surface.colorThemeVariants;
10163
+ const variant = variants?.[chosenName];
10164
+ if (variant)
10165
+ return variant;
10166
+ const chosen = themes?.find((t) => t.name === chosenName);
10167
+ const semantic = chosen?.type ? surface.semanticColorThemes?.[chosen.type] : undefined;
10168
+ if (semantic)
10169
+ return semantic;
10170
+ if (surface.colorTheme && chosen?.isDefault)
10171
+ return surface.colorTheme;
10172
+ return chosenName;
10173
+ };
10174
+ /**
10175
+ * A signal of the color theme for `type` on the surface this element renders on: the first registered theme
10176
+ * of that `type`, swapped for the nearest surface's `colorThemeVariants` entry. Reading it throws when the app
10177
+ * registered no theme of that `type`, so read it only for a state that renders.
10178
+ *
10179
+ * @example
10180
+ * protected successTheme = injectSemanticColorTheme('success');
10181
+ * // <span [etProvideColor]="successTheme()">+12%</span>
10182
+ */
10183
+ const injectSemanticColorTheme = (type) => {
10184
+ const themes = injectColorThemes({ optional: true });
10185
+ const surfaceProvider = inject(SURFACE_PROVIDER, { optional: true });
10186
+ const rootSurface = injectRootSurfaceTheme();
10187
+ return computed(() => {
10188
+ const chosen = findColorThemeByType(themes, type, 'injectSemanticColorTheme');
10189
+ const surface = surfaceProvider?.activeTheme() ?? rootSurface();
10190
+ const variantName = resolveColorThemeVariant(surface, chosen.name, themes);
10191
+ if (variantName === chosen.name)
10192
+ return chosen;
10193
+ const variant = themes?.find((t) => t.name === variantName);
10194
+ if (variant)
10195
+ return variant;
10196
+ if (isDevMode()) {
10197
+ console.error(`[injectSemanticColorTheme] Surface theme "${surface?.name}" maps "${type}" to the color theme "${variantName}", which is not registered. Add it to provideColorThemesWithTailwind4().`);
10198
+ }
10199
+ return chosen;
10200
+ });
10201
+ };
10202
+ /** @deprecated Use `injectSemanticColorTheme('error')`, which follows the surface the element renders on. */
10203
+ const injectErrorTheme = () => injectColorThemeByType('error');
10204
+ /** @deprecated Use `injectSemanticColorTheme('warning')`, which follows the surface the element renders on. */
10205
+ const injectWarningTheme = () => injectColorThemeByType('warning');
10206
+ /** @deprecated Use `injectSemanticColorTheme('success')`, which follows the surface the element renders on. */
10207
+ const injectSuccessTheme = () => injectColorThemeByType('success');
10208
+ const injectDefaultColorTheme = () => {
10209
+ const themes = injectColorThemes({ optional: true });
10210
+ if (!themes) {
10211
+ throw new Error(`[injectDefaultColorTheme] No color themes provided. Call provideColorThemesWithTailwind4() in your app config.`);
10212
+ }
10213
+ const theme = themes.find((t) => t.isDefault);
10214
+ if (!theme) {
10215
+ throw new Error(`[injectDefaultColorTheme] No color theme with isDefault: true found. Mark one theme as the default in provideColorThemesWithTailwind4().`);
10216
+ }
10217
+ if (isDevMode()) {
10218
+ const duplicates = themes.filter((t) => t.isDefault);
10219
+ if (duplicates.length > 1) {
10220
+ console.error(`[injectDefaultColorTheme] Multiple themes with isDefault: true found: ${duplicates.map((t) => t.name).join(', ')}. Only the first one will be used.`);
10221
+ }
10222
+ }
10223
+ return theme;
10224
+ };
10225
+
10226
+ const findRootSurfaceTheme = (defaults, type) => {
10227
+ if (defaults.length <= 1)
10228
+ return defaults[0] ?? null;
10229
+ return defaults.find((theme) => theme.type === type) ?? null;
10230
+ };
10231
+ const COLOR_SCHEME_DEF = /* @__PURE__ */ defineProvider(() => {
10232
+ const root = inject(DOCUMENT).documentElement;
10233
+ const prefix = injectSurfaceThemesPrefix({ optional: true }) || 'et';
10234
+ const prefersDark = injectBreakpointObserver().observeMediaQuery('(prefers-color-scheme: dark)');
10235
+ const mode = signal('system', /* @ts-ignore */
10236
+ ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
10237
+ const surfaceDefaults = injectSurfaceThemes({ optional: true })?.filter((theme) => theme.isDefault) ?? [];
10238
+ const colorThemes = injectColorThemes({ optional: true });
10239
+ const colorPrefix = injectColorThemesPrefix({ optional: true }) || 'et';
10240
+ const type = computed(() => {
10241
+ const current = mode();
10242
+ if (current !== 'system')
10243
+ return current;
10244
+ return prefersDark() ? 'dark' : 'light';
10245
+ }, /* @ts-ignore */
10246
+ ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
10247
+ const rootSurface = computed(() => findRootSurfaceTheme(surfaceDefaults, type()), /* @ts-ignore */
10248
+ ...(ngDevMode ? [{ debugName: "rootSurface" }] : /* istanbul ignore next */ []));
10249
+ const rootColorClass = computed(() => {
10250
+ const chosen = colorThemes?.find((theme) => theme.isDefault)?.name;
10251
+ if (!chosen)
10252
+ return null;
10253
+ const variant = resolveColorThemeVariant(rootSurface(), chosen, colorThemes);
10254
+ return variant === chosen ? null : `${colorPrefix}-color--${createCssColorThemeName(variant)}`;
10255
+ }, /* @ts-ignore */
10256
+ ...(ngDevMode ? [{ debugName: "rootColorClass" }] : /* istanbul ignore next */ []));
10257
+ const defaultColor = colorThemes?.find((theme) => theme.isDefault)?.name;
10258
+ if (defaultColor) {
10259
+ for (const surface of surfaceDefaults) {
10260
+ const variant = resolveColorThemeVariant(surface, defaultColor, colorThemes);
10261
+ if (variant !== defaultColor)
10262
+ root.classList.remove(`${colorPrefix}-color--${createCssColorThemeName(variant)}`);
10263
+ }
10264
+ }
10265
+ let paintedColorClass = null;
10266
+ const clearColorClass = () => {
10267
+ if (paintedColorClass)
10268
+ root.classList.remove(paintedColorClass);
10269
+ paintedColorClass = null;
10270
+ };
10271
+ effect(() => {
10272
+ const next = rootColorClass();
10273
+ clearColorClass();
10274
+ if (next)
10275
+ root.classList.add(next);
10276
+ paintedColorClass = next;
10277
+ });
10278
+ const clearClasses = () => root.classList.remove(`${prefix}-scheme--light`, `${prefix}-scheme--dark`);
10279
+ const setMode = (next) => {
10280
+ clearClasses();
10281
+ if (next !== 'system')
10282
+ root.classList.add(`${prefix}-scheme--${next}`);
10283
+ mode.set(next);
10284
+ };
10285
+ inject(DestroyRef).onDestroy(() => {
10286
+ clearClasses();
10287
+ clearColorClass();
10288
+ });
10289
+ return { mode: mode.asReadonly(), type, rootSurface, setMode };
10290
+ }, { name: 'Color Scheme' });
10291
+ const provideColorSchemeState = /* @__PURE__ */ toProvideFn(COLOR_SCHEME_DEF);
10292
+ /**
10293
+ * Inject the app's color scheme: `mode()` is what the app asked for, `type()` the surface type the
10294
+ * root paints, `rootSurface()` the default surface theme of that type, and `setMode()` switches it.
10295
+ * Needs `provideColorScheme()`.
10296
+ */
10297
+ const injectColorScheme = /* @__PURE__ */ toInjectFn(COLOR_SCHEME_DEF);
10298
+ const injectSchemeUnresolved = () => {
10299
+ const { mode } = injectColorScheme();
10300
+ const isServer = isPlatformServer(inject(PLATFORM_ID));
10301
+ const defaultCount = injectSurfaceThemes({ optional: true })?.filter((theme) => theme.isDefault).length ?? 0;
10302
+ return computed(() => isServer && defaultCount > 1 && mode() === 'system');
10303
+ };
10304
+ /**
10305
+ * Lets the app switch between its default light and dark surface with a class on `<html>`, instead of
10306
+ * only following `prefers-color-scheme`. It also paints the root surface's `colorThemeVariants` entry for the
10307
+ * default accent on `<html>`. Add it to the application config, next to
10308
+ * `provideSurfaceThemesWithTailwind4()`.
10309
+ */
10310
+ const provideColorScheme = (config) => makeEnvironmentProviders([
10311
+ provideColorSchemeState(),
10312
+ { provide: COLOR_SCHEME_TYPE, useFactory: () => injectColorScheme().type },
10313
+ { provide: COLOR_SCHEME_UNRESOLVED, useFactory: injectSchemeUnresolved },
10314
+ provideEnvironmentInitializer(() => injectColorScheme().setMode(config?.mode ?? 'system')),
10315
+ ]);
10316
+ /**
10317
+ * Inject a signal of the default surface theme the root paints where nothing scopes one. If the app
10318
+ * registers a default for both surface types, it follows `injectColorScheme()`, and is `null` without
10319
+ * `provideColorScheme()`.
10320
+ */
10321
+ const injectRootSurfaceTheme = () => {
10322
+ const defaults = injectSurfaceThemes({ optional: true })?.filter((theme) => theme.isDefault) ?? [];
10323
+ const colorSchemeType = inject(COLOR_SCHEME_TYPE, { optional: true });
10324
+ return computed(() => findRootSurfaceTheme(defaults, colorSchemeType?.()));
10325
+ };
10326
+
10306
10327
  let uniqueId = 0;
10307
10328
  const SURFACE_CONTEXT_TRACKER_DEF = /* @__PURE__ */ defineRootProvider(() => {
10308
10329
  const entries = signal([], /* @ts-ignore */
@@ -10350,6 +10371,8 @@ class AutoSurfaceDirective {
10350
10371
  this.surfaceContextTracker = injectSurfaceContextTracker();
10351
10372
  this.parentSurface = injectParentSurface();
10352
10373
  this.elementRef = inject(ElementRef);
10374
+ this.schemeUnresolved = inject(COLOR_SCHEME_UNRESOLVED, { optional: true });
10375
+ this.rootTheme = injectRootSurfaceTheme();
10353
10376
  /**
10354
10377
  * Explicit surface provider to resolve the surface relative to. Falls back to the
10355
10378
  * surface provider from the surrounding (trigger) context when not set.
@@ -10375,6 +10398,10 @@ class AutoSurfaceDirective {
10375
10398
  const overlaySurface = this.surfaceContextTracker.surfaceForElement(this.elementRef.nativeElement);
10376
10399
  const overlayElevation = overlaySurface?.elevation ?? null;
10377
10400
  const overlayType = overlaySurface?.type ?? null;
10401
+ // A surface derived from the root would bake the server's guessed scheme into the markup; inherit, and let CSS pick it.
10402
+ if (this.schemeUnresolved?.() && overlayElevation === null && contextTheme === this.rootTheme()) {
10403
+ return null;
10404
+ }
10378
10405
  // Must not re-derive from the declaration injector: it points at the trigger and would double-elevate the panel.
10379
10406
  if (this.isOverlaySurface()) {
10380
10407
  if (overlayElevation !== null) {
@@ -10722,11 +10749,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
10722
10749
 
10723
10750
  // Generated from package.json by tools/scripts/generate-version.js - do not edit.
10724
10751
  /** The version of `@ethlete/core` this build was cut from. */
10725
- const CORE_VERSION = '5.0.0-next.64';
10752
+ const CORE_VERSION = '5.0.0-next.65';
10726
10753
 
10727
10754
  /**
10728
10755
  * Generated bundle index. Do not edit.
10729
10756
  */
10730
10757
 
10731
- export { ANIMATABLE_TOKEN, ANIMATED_IF_TOKEN, ANIMATED_LIFECYCLE_TOKEN, ANIMATION_DEBUG_STORAGE_KEY, ANIMATION_ERROR_CODES, AT_LEAST_ONE_REQUIRED, AnimatableDirective, AnimatedIfDirective, AnimatedLifecycleDirective, AutoSurfaceDirective, BOUNDARY_ELEMENT_TOKEN, BREAKPOINT_INSTANCE_TOKEN, BREAKPOINT_ORDER, COLOR_PALETTE, COLOR_PROVIDER, CORE_VERSION, ClickOutsideDirective, ColorInteractiveContainerDirective, ColorInteractiveDirective, ColorInteractiveExcludeDirective, ColorInteractiveHasFocusDirective, DEFAULT_MULTI_INSTANCE_RELS, DEFAULT_MULTI_INSTANCE_TAGS, DEFAULT_OVERLAY_LAYER, DEFAULT_VIEWPORT_CONFIG, DISABLE_LOGGER_PARAM, DragHandleDirective, ET_DISABLE_SCROLL_TOP, ET_DISABLE_SCROLL_TOP_AS_RETURN_ROUTE, ET_DISABLE_SCROLL_TOP_ON_PATH_PARAM_CHANGE, ET_PROPERTY_REMOVED, ET_RESTORE_SCROLL, EasingTokensStylesComponent, EthleteValidators, FOCUSABLE_SELECTOR, FOCUS_VISIBLE_TRACKER_TOKEN, HtmlToMarkdownPipe, IS_ARRAY_NOT_EMPTY, IS_EMAIL, InferMimeTypePipe, InitialsPipe, IsArrayNotEmpty, IsEmail, jsonLd as JsonLD, KeyPressManager, MARKDOWN_VERBATIM_ATTR, MUST_MATCH, MarkdownToHtmlPipe, MatchStateType, MustMatch, NOTIFICATION_CLICK_MESSAGE_TYPE, NormalizeGameResultTypePipe, NormalizeMatchParticipantsPipe, NormalizeMatchScorePipe, NormalizeMatchStatePipe, NormalizeMatchTypePipe, OVERLAY_LAYER_ATTRIBUTE, ProvideColorDirective, ProvideSurfaceDirective, RUNTIME_ERROR_NO_DATA, RepeatDirective, ResizeHandlesComponent, RestoreScrollDirective, RuntimeError, SURFACE_COLOR, SURFACE_PROVIDER, SURFACE_TYPE, SWIPE_VELOCITY_WINDOW_MS, ScrollObserverDirective, ScrollObserverEndDirective, ScrollObserverStartDirective, SlugifyPipe, StructuredDataComponent, SurfaceInteractiveDirective, ToArrayPipe, TypedQueryList, UNSAVED_CHANGES_CONFIRM, UNSAVED_CHANGES_ERROR_CODES, UNSAVED_CHANGES_TITLE_MARKER, ValidateAtLeastOneRequired, VisuallyHiddenStylesComponent, anchoredOverlayPosition, animationDebugLog, applyAlternateBinding, applyAlternateLanguagesBindings, applyArticleBindings, applyAuthorBinding, applyCanonicalBinding, applyCenteredPosition, applyDescriptionBinding, applyFaviconOverlay, applyGlobalPosition, applyHeadBinding, applyHeadTitleBinding, applyHeadTitleMarker, applyHostListener, applyHostListeners, applyInitialFocus, applyKeywordsBinding, applyLinkBinding, applyMetaBinding, applyNextBinding, applyOgBinding, applyOpenGraphBindings, applyPrevBinding, applyResourceHintsBindings, applyRobotsBinding, applySocialMediaBindings, applyStructuredDataBinding, applyTwitterCardBindings, boolBreakpointTransform, boundingClientRectToElementRect, breakpointTransformBase, buildElementSignal, buildSignalEffects, canUseSessionMemory, clamp, clone, cloneFormGroup, computedTillFalsy, computedTillTruthy, controlValueSignal, controlValueSignalWithPrevious, copyToClipboard, createAnchoredPositionCleanup, createArrayPropertyBinding, createAutoSessionMemoryKey, createCanAnimateSignal, createComponentId, createCssColorThemeName, createCssSurfaceName, createDestroy, createDocumentElementSignal, createElementDimensions, createEmptyElementSignal, createFlipAnimation, createFlipAnimationGroup, createIsRenderedSignal, createLogger, createObjectUrlHandle, createPropertyBinding, createRootThemeCss, createRoute, createRouterState, createRxHostListener, createSessionMemory, createSwatchCss, createSwipeTracker, createTailwindColorThemes, createTailwindCssVar, createTailwindRgbVar, createThemeStyle, createUnsavedChangesGuard, createUnsavedChangesTabLock, createUnsavedChangesTracker, createUserConsentProvider, deferredSignal, defineLabels, defineProvider, defineRootProvider, defineStaticProvider, defineStaticRootProvider, deleteCookie, dragGestureFrom, easeElastic, easeIn, easeInOut, easeLinear, easeOut, easeOutBack, easeOutBackStrong, elementCanScroll, enableAnchoredOverlayPositionExtras, equal, fetchDeployedBuildFingerprint$, firstElementSignal, focusElement, forceReflow, formatRuntimeError, fromNextFrame, getCookie, getDomain, getElementScrollCoordinates, getFocusableElements, getFormGroupValue, getGroupMatchPoints, getGroupMatchScore, getHeadingElement, getKnockoutMatchScore, getMatchScoreSubLine, getObjectProperty, getScrollContainerTarget, getScrollItemTarget, getScrollSnapTarget, hasCookie, holdScrollRestoration, htmlToMarkdown, inferMimeType, initials, injectAngularRootElement, injectAnimatedBlockSize, injectAppUpdates, injectAppUpdatesConfig, injectBoundaryElement, injectBreakpointInput, injectBreakpointIsMatched, injectBreakpointObserver, injectCanHover, injectColorPalette, injectColorScheme, injectColorThemes, injectColorThemesPrefix, injectCurrentBreakpoint, injectDefaultColorTheme, injectDefaultSurfaceTheme, injectDeviceInputType, injectDisplayOrientation, injectErrorTheme, injectFaviconStore, injectFileDownload, injectFocusVisibleTracker, injectFragment, injectHasPrecisionInput, injectHasTouchInput, injectHostElement, injectIs2Xl, injectIsDocumentVisible, injectIsLandscape, injectIsLg, injectIsMd, injectIsPortrait, injectIsRouterInitialized, injectIsSm, injectIsXl, injectIsXs, injectLinkStore, injectLinkStoreConfig, injectLocale, injectMediaQueryIsMatched, injectMetaConfig, injectMetaStore, injectNotifications, injectObserveBreakpoint, injectObserveMediaQuery, injectOverlayRuntime, injectParentSurface, injectPathParam, injectPathParamChanges, injectPathParams, injectPrefersReducedMotion, injectQueryParam, injectQueryParamAll, injectQueryParamChanges, injectQueryParams, injectRenderer, injectRootSurfaceTheme, injectRoute, injectRouteData, injectRouteDataItem, injectRouteTitle, injectRouterEvent, injectRouterNavigationState, injectRouterState, injectScrollbarDimensions, injectSemanticColorTheme, injectStructuredDataConfig, injectStructuredDataStore, injectStyleManager, injectSuccessTheme, injectSurfaceColorPalette, injectSurfaceContextTracker, injectSurfaceThemes, injectSurfaceThemesPrefix, injectSurfaceType, injectTemplateRef, injectTitleConfig, injectTitleStore, injectUnsavedChangesCoordinator, injectUrl, injectViewportConfig, injectViewportDimensions, injectViewportSize, injectWarningTheme, isAnimationDebugEnabled, isArray, isElement, isElementSignal, isElementVisible, isFocusable, isGroupMatch, isHTMLElement, isHTMLOrSVGElement, isKnockoutMatch, isObject, isOnHigherOverlayLayer, isSafeLinkUrl, isSafeUrl, isStaleBuildError, markdownToHtml, matchesReducedMotion, maybeSignalValue, memoizeSignal, mountEasingTokens, mountVisuallyHidden, nextFrame, normalizeGameResultType, normalizeMatchParticipant, normalizeMatchParticipants, normalizeMatchScore, normalizeMatchState, normalizeMatchType, normalizeUnsavedChangesSource, numberBreakpointTransform, onOverlayViewportInsetsChange, optionalBooleanAttribute, overlayViewportInsets, overlayViewportInsetsFor, ownsActiveElement, previousSignalValue, provideAppUpdates, provideAppUpdatesConfig, provideAppUpdatesInstance, provideBoundaryElement, provideBreakpointInstance, provideBreakpointObserver, provideColorPalette, provideColorScheme, provideColorThemes, provideColorThemesWithTailwind4, provideFaviconStore, provideFocusVisibleTracker, provideLinkStore, provideLinkStoreConfig, provideLocale, provideMetaConfig, provideMetaStore, provideNotifications, provideOverlayRuntime, provideRenderer, provideStructuredDataConfig, provideStructuredDataStore, provideStyleManager, provideSurfaceContextTracker, provideSurfaceThemesWithTailwind4, provideTitleConfig, provideTitleStore, provideUnsavedChangesConfirm, provideUnsavedChangesCoordinator, provideViewportConfig, randomId, readBuildFingerprint, readFromClipboard, reserveOverlayViewportSpace, resolveAppRootColorProvider, resolveColorThemeVariant, resolveOverlayLayer, resolveSurfaceByElevation, round, routerDisableScrollTop, routerRestoreScroll, scrollToElement, setCookie, setInputSignal, setupFocusTrap, setupPositioning, setupScrollRestoration, signalAnimatedNumber, signalAttributes, signalClasses, signalCountdown, signalDeferredLoading, signalElementChildren, signalElementDimensions, signalElementIntersection, signalElementLastScrollDirection, signalElementMutations, signalElementScrollState, signalHostAttributes, signalHostClasses, signalHostElementDimensions, signalHostElementIntersection, signalHostElementLastScrollDirection, signalHostElementMutations, signalHostElementScrollState, signalHostStyles, signalIsRendered, signalStyles, slugify, suppressTextSelection, switchQueryListChanges, syncSignal, toArray, toArrayTrackByFn, toInjectFn, toProvideFn, toStringBinding, toToken, transformOrReturn, typedBreakpointTransform, useCursorDragScroll, writeScrollbarSizeToCssVariables, writeViewportSizeToCssVariables, ɵProvideColorThemes, ɵProvideColorThemesPrefix, ɵProvideSurfaceThemes, ɵProvideSurfaceThemesPrefix };
10758
+ export { ANIMATABLE_TOKEN, ANIMATED_IF_TOKEN, ANIMATED_LIFECYCLE_TOKEN, ANIMATION_DEBUG_STORAGE_KEY, ANIMATION_ERROR_CODES, AT_LEAST_ONE_REQUIRED, AnimatableDirective, AnimatedIfDirective, AnimatedLifecycleDirective, AutoSurfaceDirective, BOUNDARY_ELEMENT_TOKEN, BREAKPOINT_INSTANCE_TOKEN, BREAKPOINT_ORDER, COLOR_PALETTE, COLOR_PROVIDER, CORE_VERSION, ClickOutsideDirective, ColorInteractiveContainerDirective, ColorInteractiveDirective, ColorInteractiveExcludeDirective, ColorInteractiveHasFocusDirective, DEFAULT_MULTI_INSTANCE_RELS, DEFAULT_MULTI_INSTANCE_TAGS, DEFAULT_OVERLAY_LAYER, DEFAULT_VIEWPORT_CONFIG, DISABLE_LOGGER_PARAM, DragHandleDirective, ET_DISABLE_SCROLL_TOP, ET_DISABLE_SCROLL_TOP_AS_RETURN_ROUTE, ET_DISABLE_SCROLL_TOP_ON_PATH_PARAM_CHANGE, ET_PROPERTY_REMOVED, ET_RESTORE_SCROLL, EasingTokensStylesComponent, EthleteValidators, FOCUSABLE_SELECTOR, FOCUS_VISIBLE_TRACKER_TOKEN, HtmlToMarkdownPipe, IS_ARRAY_NOT_EMPTY, IS_EMAIL, InferMimeTypePipe, InitialsPipe, IsArrayNotEmpty, IsEmail, jsonLd as JsonLD, KeyPressManager, MARKDOWN_VERBATIM_ATTR, MUST_MATCH, MarkdownToHtmlPipe, MatchStateType, MustMatch, NOTIFICATION_CLICK_MESSAGE_TYPE, NormalizeGameResultTypePipe, NormalizeMatchParticipantsPipe, NormalizeMatchScorePipe, NormalizeMatchStatePipe, NormalizeMatchTypePipe, OVERLAY_LAYER_ATTRIBUTE, ProvideColorDirective, ProvideSurfaceDirective, RUNTIME_ERROR_NO_DATA, RepeatDirective, ResizeHandlesComponent, RestoreScrollDirective, RuntimeError, SURFACE_COLOR, SURFACE_PROVIDER, SURFACE_TYPE, SWIPE_VELOCITY_WINDOW_MS, ScrollObserverDirective, ScrollObserverEndDirective, ScrollObserverStartDirective, SlugifyPipe, StructuredDataComponent, SurfaceInteractiveDirective, ToArrayPipe, TypedQueryList, UNSAVED_CHANGES_CONFIRM, UNSAVED_CHANGES_ERROR_CODES, UNSAVED_CHANGES_TITLE_MARKER, ValidateAtLeastOneRequired, VisuallyHiddenStylesComponent, anchoredOverlayPosition, animationDebugLog, applyAlternateBinding, applyAlternateLanguagesBindings, applyArticleBindings, applyAuthorBinding, applyCanonicalBinding, applyCenteredPosition, applyDescriptionBinding, applyFaviconOverlay, applyGlobalPosition, applyHeadBinding, applyHeadTitleBinding, applyHeadTitleMarker, applyHostListener, applyHostListeners, applyInitialFocus, applyKeywordsBinding, applyLinkBinding, applyMetaBinding, applyNextBinding, applyOgBinding, applyOpenGraphBindings, applyPrevBinding, applyResourceHintsBindings, applyRobotsBinding, applySocialMediaBindings, applyStructuredDataBinding, applyTwitterCardBindings, boolBreakpointTransform, boundingClientRectToElementRect, breakpointTransformBase, buildElementSignal, buildSignalEffects, canUseSessionMemory, clamp, clone, cloneFormGroup, computedTillFalsy, computedTillTruthy, controlValueSignal, controlValueSignalWithPrevious, copyToClipboard, createAnchoredPositionCleanup, createArrayPropertyBinding, createAutoSessionMemoryKey, createCanAnimateSignal, createComponentId, createCssColorThemeName, createCssSurfaceName, createDestroy, createDocumentElementSignal, createElementDimensions, createEmptyElementSignal, createFlipAnimation, createFlipAnimationGroup, createIsRenderedSignal, createLogger, createObjectUrlHandle, createPropertyBinding, createRootThemeCss, createRoute, createRouterState, createRxHostListener, createSessionMemory, createSwatchCss, createSwipeTracker, createTailwindColorThemes, createTailwindCssVar, createTailwindRgbVar, createThemeStyle, createUnsavedChangesGuard, createUnsavedChangesTabLock, createUnsavedChangesTracker, createUserConsentProvider, deferredSignal, defineLabels, defineProvider, defineRootProvider, defineStaticProvider, defineStaticRootProvider, deleteCookie, dragGestureFrom, easeElastic, easeIn, easeInOut, easeLinear, easeOut, easeOutBack, easeOutBackStrong, elementCanScroll, enableAnchoredOverlayPositionExtras, equal, fetchDeployedBuildFingerprint$, firstElementSignal, focusElement, forceReflow, formatRuntimeError, fromNextFrame, getCookie, getDomain, getElementScrollCoordinates, getFocusableElements, getFormGroupValue, getGroupMatchPoints, getGroupMatchScore, getHeadingElement, getKnockoutMatchScore, getMatchScoreSubLine, getObjectProperty, getScrollContainerTarget, getScrollItemTarget, getScrollSnapTarget, hasAnchoredOverlayPositionExtras, hasCookie, holdScrollRestoration, htmlToMarkdown, inferMimeType, initials, injectAngularRootElement, injectAnimatedBlockSize, injectAppUpdates, injectAppUpdatesConfig, injectBoundaryElement, injectBreakpointInput, injectBreakpointIsMatched, injectBreakpointObserver, injectCanHover, injectColorPalette, injectColorScheme, injectColorThemes, injectColorThemesPrefix, injectCurrentBreakpoint, injectDefaultColorTheme, injectDefaultSurfaceTheme, injectDeviceInputType, injectDisplayOrientation, injectErrorTheme, injectFaviconStore, injectFileDownload, injectFocusVisibleTracker, injectFragment, injectHasPrecisionInput, injectHasTouchInput, injectHostElement, injectIs2Xl, injectIsDocumentVisible, injectIsLandscape, injectIsLg, injectIsMd, injectIsPortrait, injectIsRouterInitialized, injectIsSm, injectIsXl, injectIsXs, injectLinkStore, injectLinkStoreConfig, injectLocale, injectMediaQueryIsMatched, injectMetaConfig, injectMetaStore, injectNotifications, injectObserveBreakpoint, injectObserveMediaQuery, injectOverlayRuntime, injectParentSurface, injectPathParam, injectPathParamChanges, injectPathParams, injectPrefersReducedMotion, injectQueryParam, injectQueryParamAll, injectQueryParamChanges, injectQueryParams, injectRenderer, injectRootSurfaceTheme, injectRoute, injectRouteData, injectRouteDataItem, injectRouteTitle, injectRouterEvent, injectRouterNavigationState, injectRouterState, injectScrollbarDimensions, injectSemanticColorTheme, injectStructuredDataConfig, injectStructuredDataStore, injectStyleManager, injectSuccessTheme, injectSurfaceColorPalette, injectSurfaceContextTracker, injectSurfaceThemes, injectSurfaceThemesPrefix, injectSurfaceType, injectTemplateRef, injectTitleConfig, injectTitleStore, injectUnsavedChangesCoordinator, injectUrl, injectViewportConfig, injectViewportDimensions, injectViewportSize, injectWarningTheme, isAnimationDebugEnabled, isArray, isElement, isElementSignal, isElementVisible, isFocusable, isGroupMatch, isHTMLElement, isHTMLOrSVGElement, isKnockoutMatch, isObject, isOnHigherOverlayLayer, isSafeLinkUrl, isSafeUrl, isStaleBuildError, markdownToHtml, matchesReducedMotion, maybeSignalValue, memoizeSignal, mountEasingTokens, mountVisuallyHidden, nextFrame, normalizeGameResultType, normalizeMatchParticipant, normalizeMatchParticipants, normalizeMatchScore, normalizeMatchState, normalizeMatchType, normalizeUnsavedChangesSource, numberBreakpointTransform, onOverlayViewportInsetsChange, optionalBooleanAttribute, overlayViewportInsets, overlayViewportInsetsFor, ownsActiveElement, previousSignalValue, provideAppUpdates, provideAppUpdatesConfig, provideAppUpdatesInstance, provideBoundaryElement, provideBreakpointInstance, provideBreakpointObserver, provideColorPalette, provideColorScheme, provideColorThemes, provideColorThemesWithTailwind4, provideFaviconStore, provideFocusVisibleTracker, provideLinkStore, provideLinkStoreConfig, provideLocale, provideMetaConfig, provideMetaStore, provideNotifications, provideOverlayRuntime, provideRenderer, provideStructuredDataConfig, provideStructuredDataStore, provideStyleManager, provideSurfaceContextTracker, provideSurfaceThemesWithTailwind4, provideTitleConfig, provideTitleStore, provideUnsavedChangesConfirm, provideUnsavedChangesCoordinator, provideViewportConfig, randomId, readBuildFingerprint, readFromClipboard, reserveOverlayViewportSpace, resolveAppRootColorProvider, resolveColorThemeVariant, resolveOverlayLayer, resolveSurfaceByElevation, round, routerDisableScrollTop, routerRestoreScroll, scrollToElement, setCookie, setInputSignal, setupFocusTrap, setupPositioning, setupScrollRestoration, signalAnimatedNumber, signalAttributes, signalClasses, signalCountdown, signalDeferredLoading, signalElementChildren, signalElementDimensions, signalElementIntersection, signalElementLastScrollDirection, signalElementMutations, signalElementScrollState, signalHostAttributes, signalHostClasses, signalHostElementDimensions, signalHostElementIntersection, signalHostElementLastScrollDirection, signalHostElementMutations, signalHostElementScrollState, signalHostStyles, signalIsRendered, signalStyles, slugify, suppressTextSelection, switchQueryListChanges, syncSignal, toArray, toArrayTrackByFn, toInjectFn, toProvideFn, toStringBinding, toToken, transformOrReturn, typedBreakpointTransform, useCursorDragScroll, writeScrollbarSizeToCssVariables, writeViewportSizeToCssVariables, ɵProvideColorThemes, ɵProvideColorThemesPrefix, ɵProvideSurfaceThemes, ɵProvideSurfaceThemesPrefix };
10732
10759
  //# sourceMappingURL=ethlete-core.mjs.map