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

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,11 +1,11 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { assertInInjectionContext, inject, DestroyRef, ElementRef, TemplateRef, InjectionToken, booleanAttribute, QueryList, RendererFactory2, RendererStyleFlags2, isSignal, DOCUMENT, signal, linkedSignal, isDevMode, computed, afterNextRender, effect, untracked, ApplicationRef, runInInjectionContext, NgZone, Injector, numberAttribute, PLATFORM_ID, afterRenderEffect, EnvironmentInjector, createComponent, ViewEncapsulation, Component, Directive, model, ViewContainerRef, input, CSP_NONCE, provideEnvironmentInitializer, output, createEnvironmentInjector, Pipe, makeEnvironmentProviders, afterEveryRender } from '@angular/core';
3
3
  import { takeUntilDestroyed, toSignal, toObservable, outputFromObservable } from '@angular/core/rxjs-interop';
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';
4
+ import { Subject, fromEvent, switchMap, startWith, of, defer, from, map, catchError, timer, takeUntil, tap, pairwise, debounceTime, merge, distinctUntilChanged, EMPTY, expand, skip, take, filter, isObservable, ignoreElements, BehaviorSubject, combineLatest, Observable, 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';
8
- import { Router, NavigationEnd, NavigationSkipped, NavigationStart, NavigationError, RouterLink } from '@angular/router';
7
+ import { isPlatformBrowser, Location, DOCUMENT as DOCUMENT$1, isPlatformServer } from '@angular/common';
8
+ import { Router, NavigationEnd, NavigationCancel, NavigationError, NavigationSkipped, NavigationStart, 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';
11
11
 
@@ -2980,16 +2980,17 @@ const injectRouterEvent = /* @__PURE__ */ memoizeSignal(() => {
2980
2980
  });
2981
2981
  /**
2982
2982
  * Signal that indicates whether the router has been initialized.
2983
- * The router is considered initialized once its first navigation has completed, including one that completed
2984
- * before this signal was first injected.
2983
+ * It turns true once the first navigation has ended (completed, was cancelled, failed or was skipped), so a
2984
+ * component created while the first navigation runs still sees `false`. Injected after that point, it is `true`
2985
+ * right away.
2985
2986
  */
2986
2987
  const injectIsRouterInitialized = /* @__PURE__ */ memoizeSignal(() => {
2987
- const event = injectRouterEvent();
2988
- const navigatedBefore = inject(Router).navigated;
2989
- return computed(() => {
2990
- const e = event();
2991
- return navigatedBefore || (e instanceof NavigationEnd && e.id !== -1) || e instanceof NavigationSkipped;
2992
- });
2988
+ const router = inject(Router);
2989
+ const firstNavigationRunning = router.currentNavigation()?.id === 1;
2990
+ return toSignal(router.events.pipe(filter((e) => e instanceof NavigationEnd ||
2991
+ e instanceof NavigationCancel ||
2992
+ e instanceof NavigationError ||
2993
+ e instanceof NavigationSkipped), map(() => true)), { initialValue: router.navigated && !firstNavigationRunning });
2993
2994
  });
2994
2995
  /**
2995
2996
  * Inject the current url.
@@ -3042,12 +3043,15 @@ const createRouterState = (router) => {
3042
3043
  route = route.firstChild;
3043
3044
  }
3044
3045
  const { data, params, queryParams, title, fragment } = route;
3046
+ const navigation = router.currentNavigation();
3045
3047
  return {
3046
3048
  data,
3047
3049
  pathParams: params,
3048
3050
  queryParams,
3049
3051
  title: title ?? null,
3050
3052
  fragment,
3053
+ id: navigation?.id ?? null,
3054
+ trigger: navigation?.trigger ?? null,
3051
3055
  };
3052
3056
  };
3053
3057
  /**
@@ -3069,14 +3073,20 @@ const readUncommittedUrl = (router, location) => {
3069
3073
  : window.location.pathname + window.location.search + window.location.hash;
3070
3074
  };
3071
3075
  /**
3072
- * Inject the complete router state. This includes the current route data, path params, query params, title and fragment.
3076
+ * Inject the complete router state. This includes the current route data, path params, query params, title and fragment,
3077
+ * plus the `id` and `trigger` of the current navigation (the last one once it has ended).
3073
3078
  */
3074
3079
  const injectRouterState = /* @__PURE__ */ memoizeSignal(() => {
3075
3080
  const event = injectRouterEvent();
3076
3081
  const router = inject(Router);
3082
+ const lastStart = toSignal(router.events.pipe(filter((e) => e instanceof NavigationStart), map((e) => ({ id: e.id, trigger: e.navigationTrigger ?? null }))), { initialValue: null });
3077
3083
  return computed(() => {
3078
3084
  event();
3079
- return createRouterState(router);
3085
+ const state = createRouterState(router);
3086
+ if (state.id !== null)
3087
+ return state;
3088
+ const start = lastStart();
3089
+ return { ...state, id: start?.id ?? null, trigger: start?.trigger ?? null };
3080
3090
  }, { equal });
3081
3091
  });
3082
3092
  /** Inject a signal containing the current route fragment (the part after the # inside the url if present) */
@@ -3264,7 +3274,32 @@ const ET_RESTORE_SCROLL = /* @__PURE__ */ Symbol('ET_RESTORE_SCROLL');
3264
3274
  const routerRestoreScroll = () => ({ [ET_RESTORE_SCROLL]: true });
3265
3275
  const SCROLL_RESTORATION_HOLDS_DEF = /* @__PURE__ */ defineRootProvider(() => {
3266
3276
  const holds = new Set();
3277
+ const states = new Set();
3267
3278
  return {
3279
+ addState: (state) => {
3280
+ states.add(state);
3281
+ return () => states.delete(state);
3282
+ },
3283
+ saveStates: () => {
3284
+ if (!states.size)
3285
+ return undefined;
3286
+ const values = {};
3287
+ for (const state of states) {
3288
+ values[state.key] = state.save();
3289
+ }
3290
+ return values;
3291
+ },
3292
+ restoreStates: (values) => {
3293
+ const pending = [];
3294
+ for (const state of states) {
3295
+ if (!(state.key in values))
3296
+ continue;
3297
+ const result = state.restore(values[state.key]);
3298
+ if (isObservable(result))
3299
+ pending.push(result);
3300
+ }
3301
+ return pending;
3302
+ },
3268
3303
  add: (isPending) => {
3269
3304
  holds.add(isPending);
3270
3305
  return () => holds.delete(isPending);
@@ -3299,12 +3334,55 @@ const holdScrollRestoration = (isPending) => {
3299
3334
  const remove = injectScrollRestorationHolds().add(isPending);
3300
3335
  inject(DestroyRef).onDestroy(remove);
3301
3336
  };
3337
+ /**
3338
+ * Remember a piece of page state with the scroll entry, and restore it before the offset is applied -
3339
+ * the number of loaded pages of a paged list, for instance, without which the saved offset points at
3340
+ * the wrong items. Registers for the lifetime of the current injection context.
3341
+ *
3342
+ * Needs `restore.enabled` on {@link setupScrollRestoration}.
3343
+ *
3344
+ * @example
3345
+ * // inside a route component
3346
+ * registerScrollRestorationState({
3347
+ * key: 'pages',
3348
+ * save: () => pageCount(),
3349
+ * restore: (count) => loadPages$(count),
3350
+ * });
3351
+ */
3352
+ const registerScrollRestorationState = (config) => {
3353
+ const remove = injectScrollRestorationHolds().addState(config);
3354
+ inject(DestroyRef).onDestroy(remove);
3355
+ };
3302
3356
  /** Upper bound on remembered history entries. Each entry is a single number, so this is generous. */
3303
3357
  const MAX_STORED_POSITIONS = 200;
3304
3358
  const DEFAULT_RESTORE_TIMEOUT = 1000;
3305
3359
  const DEFAULT_RESTORE_MAX_TIMEOUT = 10_000;
3306
3360
  /** Events that mean the user took over scrolling, so a pending restoration must be abandoned. */
3307
3361
  const INTERACTION_EVENTS = ['wheel', 'touchmove', 'keydown'];
3362
+ const RELOAD_STORAGE_KEY = 'et-scroll-restoration';
3363
+ const readReloadEntry = () => {
3364
+ try {
3365
+ const raw = sessionStorage.getItem(RELOAD_STORAGE_KEY);
3366
+ sessionStorage.removeItem(RELOAD_STORAGE_KEY);
3367
+ const entry = raw ? JSON.parse(raw) : null;
3368
+ return typeof entry?.top === 'number' && typeof entry.route === 'string' ? entry : null;
3369
+ }
3370
+ catch {
3371
+ return null;
3372
+ }
3373
+ };
3374
+ const writeReloadEntry = (entry) => {
3375
+ try {
3376
+ sessionStorage.setItem(RELOAD_STORAGE_KEY, JSON.stringify(entry));
3377
+ }
3378
+ catch {
3379
+ // Storage may be full or blocked (private mode); a reload then simply starts at the top.
3380
+ }
3381
+ };
3382
+ const isFreshNavigation = () => {
3383
+ const entry = performance.getEntriesByType?.('navigation')[0];
3384
+ return entry?.type === 'navigate';
3385
+ };
3308
3386
  /** Key order is navigation order, not declaration order, so two spellings of one URL compare equal. */
3309
3387
  const serializeQueryParams = (queryParams) => Object.keys(queryParams)
3310
3388
  .sort()
@@ -3334,6 +3412,8 @@ const setupScrollRestoration = (config = {}) => {
3334
3412
  const restoreTimeout = config.restore?.timeout ?? DEFAULT_RESTORE_TIMEOUT;
3335
3413
  const restoreMaxTimeout = config.restore?.maxTimeout ?? DEFAULT_RESTORE_MAX_TIMEOUT;
3336
3414
  const clampOnTimeout = config.restore?.clampOnTimeout ?? true;
3415
+ const restoreOnReload = restoreEnabled && config.restore?.restoreOnReload === true;
3416
+ let reloadEntry = restoreOnReload && !isFreshNavigation() ? readReloadEntry() : null;
3337
3417
  const resolveScrollElement = () => {
3338
3418
  const el = typeof config.scrollElement === 'function' ? config.scrollElement() : config.scrollElement;
3339
3419
  return el ?? document.documentElement;
@@ -3362,11 +3442,22 @@ const setupScrollRestoration = (config = {}) => {
3362
3442
  pendingRestore?.();
3363
3443
  pendingRestore = null;
3364
3444
  };
3365
- const scheduleRestore = (target) => {
3445
+ const captureEntry = () => ({
3446
+ top: resolveScrollElement().scrollTop,
3447
+ route: prev.route,
3448
+ search: serializeQueryParams(prev.state.queryParams),
3449
+ state: holds.saveStates(),
3450
+ });
3451
+ const scheduleRestore = (entry) => {
3366
3452
  cancelPendingRestore();
3453
+ const target = entry.top;
3367
3454
  let frame = 0;
3368
3455
  let started = false;
3369
3456
  let cancelled = false;
3457
+ let renderRef = null;
3458
+ let fallback;
3459
+ let stateSubscription = null;
3460
+ let stateDeadline;
3370
3461
  // The user scrolling always wins over a restoration we have not committed yet.
3371
3462
  const abortByUser = () => cancelPendingRestore();
3372
3463
  const hardDeadline = Date.now() + restoreMaxTimeout;
@@ -3406,8 +3497,14 @@ const setupScrollRestoration = (config = {}) => {
3406
3497
  started = true;
3407
3498
  frame = requestAnimationFrame(step);
3408
3499
  };
3409
- const renderRef = afterNextRender({ read: start }, { injector });
3410
- const fallback = setTimeout(start);
3500
+ const waitForRender = () => {
3501
+ if (cancelled)
3502
+ return;
3503
+ clearTimeout(stateDeadline);
3504
+ renderRef = afterNextRender({ read: start }, { injector });
3505
+ fallback = setTimeout(start);
3506
+ };
3507
+ const pendingStates = entry.state ? holds.restoreStates(entry.state) : [];
3411
3508
  for (const eventName of INTERACTION_EVENTS) {
3412
3509
  document.addEventListener(eventName, abortByUser, { capture: true, passive: true });
3413
3510
  }
@@ -3415,7 +3512,9 @@ const setupScrollRestoration = (config = {}) => {
3415
3512
  // `cancelled` is not redundant with destroying the render hook: a superseded restoration must
3416
3513
  // not apply its (now stale) offset even if its hook had already been queued to run.
3417
3514
  cancelled = true;
3418
- renderRef.destroy();
3515
+ renderRef?.destroy();
3516
+ stateSubscription?.unsubscribe();
3517
+ clearTimeout(stateDeadline);
3419
3518
  if (frame)
3420
3519
  cancelAnimationFrame(frame);
3421
3520
  clearTimeout(fallback);
@@ -3423,13 +3522,22 @@ const setupScrollRestoration = (config = {}) => {
3423
3522
  document.removeEventListener(eventName, abortByUser, { capture: true });
3424
3523
  }
3425
3524
  };
3525
+ if (pendingStates.length) {
3526
+ stateDeadline = setTimeout(cancelPendingRestore, restoreMaxTimeout);
3527
+ stateSubscription = merge(...pendingStates)
3528
+ .pipe(ignoreElements())
3529
+ .subscribe({ complete: waitForRender, error: waitForRender });
3530
+ }
3531
+ else {
3532
+ waitForRender();
3533
+ }
3426
3534
  };
3427
3535
  /**
3428
3536
  * The offset the most recently left entry for this page had. A target without query params means
3429
3537
  * "that page", whichever query state it was last in - the crumb linking to an overview does not
3430
3538
  * know, and should not have to reproduce, the filter the user left it under.
3431
3539
  */
3432
- const findLastVisitedOffset = (route, search) => {
3540
+ const findLastVisitedEntry = (route, search) => {
3433
3541
  const entries = [...positions.values()];
3434
3542
  for (let i = entries.length - 1; i >= 0; i--) {
3435
3543
  const entry = entries[i];
@@ -3437,7 +3545,7 @@ const setupScrollRestoration = (config = {}) => {
3437
3545
  continue;
3438
3546
  if (search && entry.search !== search)
3439
3547
  continue;
3440
- return entry.top;
3548
+ return entry;
3441
3549
  }
3442
3550
  return undefined;
3443
3551
  };
@@ -3450,11 +3558,7 @@ const setupScrollRestoration = (config = {}) => {
3450
3558
  // what `findLastVisitedOffset` walks backwards and what the cap below evicts from.
3451
3559
  if (lastNavigationId !== null) {
3452
3560
  positions.delete(lastNavigationId);
3453
- positions.set(lastNavigationId, {
3454
- top: resolveScrollElement().scrollTop,
3455
- route: prev.route,
3456
- search: serializeQueryParams(prev.state.queryParams),
3457
- });
3561
+ positions.set(lastNavigationId, captureEntry());
3458
3562
  }
3459
3563
  if (positions.size > MAX_STORED_POSITIONS) {
3460
3564
  const oldest = positions.keys().next();
@@ -3482,7 +3586,9 @@ const setupScrollRestoration = (config = {}) => {
3482
3586
  const didFragmentChange = prevState.fragment !== currState.fragment;
3483
3587
  prev = curr;
3484
3588
  const wasMarkedAsReturn = wantsRestore;
3589
+ const reloaded = reloadEntry;
3485
3590
  wantsRestore = false;
3591
+ reloadEntry = null;
3486
3592
  if (event instanceof NavigationEnd) {
3487
3593
  lastNavigationId = event.id;
3488
3594
  }
@@ -3496,17 +3602,24 @@ const setupScrollRestoration = (config = {}) => {
3496
3602
  // The saved offset wins over both scroll to top and fragment scrolling: the user may well have
3497
3603
  // scrolled away from the anchor before leaving the page.
3498
3604
  if (target !== undefined) {
3499
- scheduleRestore(target.top);
3605
+ scheduleRestore(target);
3500
3606
  return;
3501
3607
  }
3502
3608
  }
3503
3609
  if (restoreEnabled && wasMarkedAsReturn) {
3504
- const target = findLastVisitedOffset(curr.route, serializeQueryParams(currState.queryParams));
3610
+ const target = findLastVisitedEntry(curr.route, serializeQueryParams(currState.queryParams));
3505
3611
  if (target !== undefined) {
3506
3612
  scheduleRestore(target);
3507
3613
  return;
3508
3614
  }
3509
3615
  }
3616
+ if (reloaded &&
3617
+ event instanceof NavigationEnd &&
3618
+ reloaded.route === curr.route &&
3619
+ reloaded.search === serializeQueryParams(currState.queryParams)) {
3620
+ scheduleRestore(reloaded);
3621
+ return;
3622
+ }
3510
3623
  if (sameUrlNavigation) {
3511
3624
  const allQueryParams = [
3512
3625
  ...new Set(Object.keys(prevState.queryParams).concat(Object.keys(currState.queryParams))),
@@ -3548,8 +3661,13 @@ const setupScrollRestoration = (config = {}) => {
3548
3661
  onNavigationEnd(event);
3549
3662
  }), takeUntilDestroyed())
3550
3663
  .subscribe();
3664
+ const onPageHide = () => writeReloadEntry(captureEntry());
3665
+ if (restoreOnReload) {
3666
+ window.addEventListener('pagehide', onPageHide);
3667
+ }
3551
3668
  destroyRef.onDestroy(() => {
3552
3669
  cancelPendingRestore();
3670
+ window.removeEventListener('pagehide', onPageHide);
3553
3671
  if (restoreEnabled && previousScrollRestoration !== null) {
3554
3672
  history.scrollRestoration = previousScrollRestoration;
3555
3673
  }
@@ -4549,17 +4667,15 @@ const provideFocusVisibleTracker = /* @__PURE__ */ toProvideFn(FOCUS_VISIBLE_TRA
4549
4667
  const injectFocusVisibleTracker = /* @__PURE__ */ toInjectFn(FOCUS_VISIBLE_TRACKER_DEF);
4550
4668
  const FOCUS_VISIBLE_TRACKER_TOKEN = /* @__PURE__ */ toToken(FOCUS_VISIBLE_TRACKER_DEF);
4551
4669
 
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',
4670
+ const LOCALE = /* @__PURE__ */ new InjectionToken('Locale', {
4671
+ providedIn: 'root',
4672
+ factory: () => ({ currentLocale: signal('en') }),
4560
4673
  });
4561
- const provideLocale = /* @__PURE__ */ toProvideFn(LOCALE_DEF);
4562
- const injectLocale = /* @__PURE__ */ toInjectFn(LOCALE_DEF);
4674
+ /** Provides the app locale, starting at `locale` (default `'en'`). Change it later with `injectLocale().currentLocale.set(...)`. */
4675
+ const provideLocale = (locale) => [
4676
+ { provide: LOCALE, useFactory: () => ({ currentLocale: signal(locale ?? 'en') }) },
4677
+ ];
4678
+ const injectLocale = () => inject(LOCALE);
4563
4679
 
4564
4680
  const resolveSource = (source, locale) => typeof source === 'function' ? source(locale) : source;
4565
4681
  /**
@@ -4634,7 +4750,8 @@ const STYLE_MANAGER_DEF = /* @__PURE__ */ defineRootProvider(() => {
4634
4750
  const nextContainer = renderer.createElement('div');
4635
4751
  renderer.addClass(nextContainer, 'et-style-manager');
4636
4752
  renderer.setAttribute(nextContainer, 'aria-hidden', 'true');
4637
- renderer.setStyle(nextContainer, { display: 'none' });
4753
+ // A style attribute needs 'unsafe-inline' in a CSP's style-src-attr; a nonce does not cover it.
4754
+ renderer.setAttribute(nextContainer, 'hidden', '');
4638
4755
  renderer.appendChild(getContainerParent(), nextContainer);
4639
4756
  container = nextContainer;
4640
4757
  return nextContainer;
@@ -8016,6 +8133,8 @@ let middlewareExtras = null;
8016
8133
  const registerAnchoredPositionMiddlewareExtras = (extras) => {
8017
8134
  middlewareExtras = extras;
8018
8135
  };
8136
+ /** Whether `enableAnchoredOverlayPositionExtras()` has run, so `arrow`, `autoResize` and `autoHide` take effect. */
8137
+ const hasAnchoredOverlayPositionExtras = () => middlewareExtras !== null;
8019
8138
  const requireMiddlewareExtras = (feature) => {
8020
8139
  if (!middlewareExtras && isDevMode()) {
8021
8140
  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 +8254,14 @@ const createAnchoredPositionCleanup = (strategy, paneElement, overlayRef, render
8135
8254
  if (strategy.minAvailableSpace !== undefined && !strategy.autoResize && isDevMode()) {
8136
8255
  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
8256
  }
8257
+ // A width the pane declares through `--et-overlay-width` must survive positioning, and the pane
8258
+ // has to be measured at it - the variable may be set only after this runs.
8259
+ const declaredWidth = () => paneElement.style.getPropertyValue('--et-overlay-width') || null;
8138
8260
  renderer.setStyle(paneElement, {
8139
8261
  position: 'absolute',
8140
8262
  top: '0',
8141
8263
  left: '0',
8142
- width: mirrorWidthElement ? `${mirrorWidthElement.offsetWidth}px` : 'max-content',
8264
+ width: mirrorWidthElement ? `${mirrorWidthElement.offsetWidth}px` : 'var(--et-overlay-width, max-content)',
8143
8265
  });
8144
8266
  /**
8145
8267
  * What to do when the reference is not somewhere the pane can be positioned against: either removed
@@ -8253,7 +8375,7 @@ const createAnchoredPositionCleanup = (strategy, paneElement, overlayRef, render
8253
8375
  }
8254
8376
  renderer.setStyle(paneElement, {
8255
8377
  transform: `translate3d(${x}px, ${y}px, 0)`,
8256
- width: mirrorWidthElement ? `${mirrorWidthElement.offsetWidth}px` : null,
8378
+ width: mirrorWidthElement ? `${mirrorWidthElement.offsetWidth}px` : declaredWidth(),
8257
8379
  visibility: null,
8258
8380
  });
8259
8381
  // exposed so animations can compose their transforms with the anchored position
@@ -9694,6 +9816,152 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
9694
9816
  }], ctorParameters: () => [] });
9695
9817
 
9696
9818
  const COLOR_SCHEME_TYPE = new InjectionToken('ColorSchemeType');
9819
+ /** True while the scheme is only known to CSS: a server render in `system` mode with a default per surface type. */
9820
+ const COLOR_SCHEME_UNRESOLVED = new InjectionToken('ColorSchemeUnresolved');
9821
+
9822
+ const COLOR_PROVIDER = new InjectionToken('ColorProvider');
9823
+ /**
9824
+ * The color provider attached to a bootstrapped root component (e.g. `ProvideColorDirective` in
9825
+ * the app component's `hostDirectives`), if any. Detached DOM such as overlay panes can't reach
9826
+ * it through element DI, so overlay containers fall back to this when resolving the provider to
9827
+ * `syncWithProvider()` - resolve at sync time, not at injection time, since root components only
9828
+ * register with `ApplicationRef` once bootstrap completes.
9829
+ */
9830
+ const resolveAppRootColorProvider = (appRef) => {
9831
+ for (const componentRef of appRef.components) {
9832
+ const provider = componentRef.injector.get(COLOR_PROVIDER, null);
9833
+ if (provider) {
9834
+ return provider;
9835
+ }
9836
+ }
9837
+ return null;
9838
+ };
9839
+ const FORCED_COLOR_UNSET = /* @__PURE__ */ Symbol('FORCED_COLOR_UNSET');
9840
+ const appsWarnedAboutMissingThemes = /* @__PURE__ */ new WeakSet();
9841
+ class ProvideColorDirective {
9842
+ constructor() {
9843
+ this.themes = injectColorThemes({ optional: true });
9844
+ this.prefix = injectColorThemesPrefix({ optional: true });
9845
+ this.injector = inject(Injector);
9846
+ this.rootSurfaceTheme = injectRootSurfaceTheme();
9847
+ this.parentProvider = inject(COLOR_PROVIDER, { optional: true, skipSelf: true });
9848
+ this.appRef = inject(ApplicationRef);
9849
+ this.currentProviderSync = null;
9850
+ this.forcedColor = signal(FORCED_COLOR_UNSET, /* @ts-ignore */
9851
+ ...(ngDevMode ? [{ debugName: "forcedColor" }] : /* istanbul ignore next */ []));
9852
+ this.color = input(undefined, { ...(ngDevMode ? { debugName: "color" } : /* istanbul ignore next */ {}), alias: 'etProvideColor' });
9853
+ this.effectiveColor = computed(() => {
9854
+ const forcedColor = this.forcedColor();
9855
+ if (forcedColor !== FORCED_COLOR_UNSET) {
9856
+ return forcedColor;
9857
+ }
9858
+ return this.color();
9859
+ }, /* @ts-ignore */
9860
+ ...(ngDevMode ? [{ debugName: "effectiveColor" }] : /* istanbul ignore next */ []));
9861
+ /**
9862
+ * The color that actually applies at this provider's location: its own effective color, or -
9863
+ * when this provider is passive (no input, nothing forced) - the nearest ancestor provider's.
9864
+ * Mirrors the CSS cascade, which falls through a provider's `-color--inherited` scope class;
9865
+ * consumers that re-apply context across detached DOM (overlay panes) must use this instead
9866
+ * of `effectiveColor` or a passive in-between provider (e.g. a form field's) erases the theme.
9867
+ */
9868
+ this.resolvedColor = computed(() => {
9869
+ const own = this.effectiveColor();
9870
+ const ownName = typeof own === 'object' && own !== null ? own.name : own;
9871
+ if (ownName) {
9872
+ return own;
9873
+ }
9874
+ return this.parentProvider?.resolvedColor();
9875
+ }, /* @ts-ignore */
9876
+ ...(ngDevMode ? [{ debugName: "resolvedColor" }] : /* istanbul ignore next */ []));
9877
+ this.colorName = computed(() => {
9878
+ const raw = this.effectiveColor();
9879
+ const value = typeof raw === 'object' && raw !== null ? raw.name : raw;
9880
+ if (value === SURFACE_COLOR)
9881
+ return SURFACE_COLOR;
9882
+ if (!value)
9883
+ return;
9884
+ if (!this.themes) {
9885
+ if (isDevMode() && !appsWarnedAboutMissingThemes.has(this.appRef)) {
9886
+ appsWarnedAboutMissingThemes.add(this.appRef);
9887
+ console.warn(`etProvideColor="${value}" has no effect because no color themes are registered. Please make sure to add provideColorThemesWithTailwind4()`);
9888
+ }
9889
+ return;
9890
+ }
9891
+ if (isDevMode() && !this.themes.some((theme) => theme.name === value)) {
9892
+ console.error(`Theme ${value} does not exist. Please make sure to add it to provideColorThemesWithTailwind4()`);
9893
+ }
9894
+ return createCssColorThemeName(value);
9895
+ }, /* @ts-ignore */
9896
+ ...(ngDevMode ? [{ debugName: "colorName" }] : /* istanbul ignore next */ []));
9897
+ this.paintedColorName = computed(() => {
9898
+ const raw = this.effectiveColor();
9899
+ const value = typeof raw === 'object' && raw !== null ? raw.name : raw;
9900
+ if (!this.colorName() || !value)
9901
+ return;
9902
+ const surface = this.injector.get(SURFACE_PROVIDER, null)?.activeTheme() ?? this.rootSurfaceTheme();
9903
+ const variant = resolveColorThemeVariant(surface, value, this.themes);
9904
+ if (variant === value)
9905
+ return this.colorName();
9906
+ if (isDevMode() && !this.themes?.some((theme) => theme.name === variant)) {
9907
+ console.error(`Surface theme ${surface?.name} names the color theme ${variant}, which does not exist. Please make sure to add it to provideColorThemesWithTailwind4()`);
9908
+ }
9909
+ return createCssColorThemeName(variant);
9910
+ }, /* @ts-ignore */
9911
+ ...(ngDevMode ? [{ debugName: "paintedColorName" }] : /* istanbul ignore next */ []));
9912
+ this.themeClass = computed(() => {
9913
+ const prefix = this.prefix || 'et';
9914
+ const name = this.paintedColorName();
9915
+ return name ? `${prefix}-color--${name}` : `${prefix}-color--inherited`;
9916
+ }, /* @ts-ignore */
9917
+ ...(ngDevMode ? [{ debugName: "themeClass" }] : /* istanbul ignore next */ []));
9918
+ }
9919
+ syncWithProvider(provider) {
9920
+ this.currentProviderSync?.destroy();
9921
+ runInInjectionContext(this.injector, () => {
9922
+ this.currentProviderSync = effect(() => {
9923
+ const provideColor = provider.resolvedColor();
9924
+ untracked(() => {
9925
+ if (provideColor === undefined) {
9926
+ this.clearForcedColor();
9927
+ return;
9928
+ }
9929
+ this.forceColor(provideColor);
9930
+ });
9931
+ }, /* @ts-ignore */
9932
+ ...(ngDevMode ? [{ debugName: "currentProviderSync" }] : /* istanbul ignore next */ []));
9933
+ });
9934
+ }
9935
+ stopSyncWithProvider() {
9936
+ const hadProviderSync = !!this.currentProviderSync;
9937
+ this.currentProviderSync?.destroy();
9938
+ this.currentProviderSync = null;
9939
+ if (hadProviderSync) {
9940
+ this.clearForcedColor();
9941
+ }
9942
+ }
9943
+ forceColor(color) {
9944
+ this.forcedColor.set(color);
9945
+ }
9946
+ clearForcedColor() {
9947
+ if (this.forcedColor() === FORCED_COLOR_UNSET) {
9948
+ return;
9949
+ }
9950
+ this.forcedColor.set(FORCED_COLOR_UNSET);
9951
+ }
9952
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ProvideColorDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
9953
+ 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 }); }
9954
+ }
9955
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ProvideColorDirective, decorators: [{
9956
+ type: Directive,
9957
+ args: [{
9958
+ selector: '[etProvideColor]',
9959
+ providers: [{ provide: COLOR_PROVIDER, useExisting: ProvideColorDirective }],
9960
+ host: {
9961
+ '[class]': 'themeClass()',
9962
+ },
9963
+ }]
9964
+ }], propDecorators: { color: [{ type: i0.Input, args: [{ isSignal: true, alias: "etProvideColor", required: false }] }] } });
9697
9965
 
9698
9966
  const TOLERANCE_PX = 0.5;
9699
9967
  const readFontSizePx = (view, element) => {
@@ -9795,348 +10063,6 @@ const injectDefaultSurfaceTheme = (type) => {
9795
10063
  return defaults.length === 1 ? (defaults[0] ?? null) : null;
9796
10064
  };
9797
10065
 
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
10066
  const SURFACE_PROVIDER = new InjectionToken('SurfaceProvider');
10141
10067
  const FORCED_SURFACE_UNSET = /* @__PURE__ */ Symbol('FORCED_SURFACE_UNSET');
10142
10068
  class ProvideSurfaceDirective {
@@ -10303,6 +10229,219 @@ const injectParentSurface = () => {
10303
10229
  return computed(() => provider?.activeTheme() ?? rootTheme());
10304
10230
  };
10305
10231
 
10232
+ /**
10233
+ * Reserved color name. Resolves the color tokens from the ambient surface's neutral swatch
10234
+ * (`SurfaceTheme['interactionColor']`) instead of a registered accent, so a secondary action can
10235
+ * read as chrome without the app registering a neutral color theme. Apps must not register a color
10236
+ * theme under this name.
10237
+ */
10238
+ const SURFACE_COLOR = 'surface';
10239
+ const createCssColorThemeName = (name) => name.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
10240
+ const COLOR_THEMES_DEF = /* @__PURE__ */ defineStaticProvider(undefined, {
10241
+ name: 'Color Themes',
10242
+ });
10243
+ const ɵProvideColorThemes = /* @__PURE__ */ toProvideFn(COLOR_THEMES_DEF);
10244
+ const injectColorThemes = /* @__PURE__ */ toInjectFn(COLOR_THEMES_DEF);
10245
+ const COLOR_THEMES_PREFIX_DEF = /* @__PURE__ */ defineStaticProvider('et', {
10246
+ name: 'Themes Prefix',
10247
+ });
10248
+ const ɵProvideColorThemesPrefix = /* @__PURE__ */ toProvideFn(COLOR_THEMES_PREFIX_DEF);
10249
+ const injectColorThemesPrefix = /* @__PURE__ */ toInjectFn(COLOR_THEMES_PREFIX_DEF);
10250
+ const provideColorThemesWithTailwind4 = (themes, prefix = 'et') => {
10251
+ if (isDevMode() && themes.some((theme) => theme.name === SURFACE_COLOR)) {
10252
+ console.error(`[provideColorThemesWithTailwind4] "${SURFACE_COLOR}" is a reserved color name that resolves to the ambient surface's neutral swatch. Rename your theme.`);
10253
+ }
10254
+ return [ɵProvideColorThemes(themes), ɵProvideColorThemesPrefix(prefix)];
10255
+ };
10256
+ const findColorThemeByType = (themes, type, caller) => {
10257
+ if (!themes) {
10258
+ throw new Error(`[${caller}] No color themes provided. Call provideColorThemesWithTailwind4() in your app config.`);
10259
+ }
10260
+ const theme = themes.find((t) => t.type === type);
10261
+ if (!theme) {
10262
+ throw new Error(`[${caller}] No color theme with type "${type}" found. Add a theme with type: "${type}" to provideColorThemesWithTailwind4().`);
10263
+ }
10264
+ if (isDevMode()) {
10265
+ const duplicates = themes.filter((t) => t.type === type);
10266
+ if (duplicates.length > 1) {
10267
+ console.error(`[${caller}] Multiple themes with type "${type}" found: ${duplicates.map((t) => t.name).join(', ')}. Only the first one will be used.`);
10268
+ }
10269
+ }
10270
+ return theme;
10271
+ };
10272
+ const injectColorThemeByType = (type) => findColorThemeByType(injectColorThemes({ optional: true }), type, 'injectColorThemeByType');
10273
+ /**
10274
+ * The color theme name that draws `chosenName` on `surface`: the surface's `colorThemeVariants` entry for it,
10275
+ * else `chosenName` itself. Always pass the chosen accent, never an already swapped one.
10276
+ */
10277
+ const resolveColorThemeVariant = (surface, chosenName, themes) => {
10278
+ if (!surface || chosenName === SURFACE_COLOR)
10279
+ return chosenName;
10280
+ const variants = surface.colorThemeVariants;
10281
+ const variant = variants?.[chosenName];
10282
+ if (variant)
10283
+ return variant;
10284
+ const chosen = themes?.find((t) => t.name === chosenName);
10285
+ const semantic = chosen?.type ? surface.semanticColorThemes?.[chosen.type] : undefined;
10286
+ if (semantic)
10287
+ return semantic;
10288
+ if (surface.colorTheme && chosen?.isDefault)
10289
+ return surface.colorTheme;
10290
+ return chosenName;
10291
+ };
10292
+ /**
10293
+ * A signal of the color theme for `type` on the surface this element renders on: the first registered theme
10294
+ * of that `type`, swapped for the nearest surface's `colorThemeVariants` entry. Reading it throws when the app
10295
+ * registered no theme of that `type`, so read it only for a state that renders.
10296
+ *
10297
+ * @example
10298
+ * protected successTheme = injectSemanticColorTheme('success');
10299
+ * // <span [etProvideColor]="successTheme()">+12%</span>
10300
+ */
10301
+ const injectSemanticColorTheme = (type) => {
10302
+ const themes = injectColorThemes({ optional: true });
10303
+ const surfaceProvider = inject(SURFACE_PROVIDER, { optional: true });
10304
+ const rootSurface = injectRootSurfaceTheme();
10305
+ return computed(() => {
10306
+ const chosen = findColorThemeByType(themes, type, 'injectSemanticColorTheme');
10307
+ const surface = surfaceProvider?.activeTheme() ?? rootSurface();
10308
+ const variantName = resolveColorThemeVariant(surface, chosen.name, themes);
10309
+ if (variantName === chosen.name)
10310
+ return chosen;
10311
+ const variant = themes?.find((t) => t.name === variantName);
10312
+ if (variant)
10313
+ return variant;
10314
+ if (isDevMode()) {
10315
+ console.error(`[injectSemanticColorTheme] Surface theme "${surface?.name}" maps "${type}" to the color theme "${variantName}", which is not registered. Add it to provideColorThemesWithTailwind4().`);
10316
+ }
10317
+ return chosen;
10318
+ });
10319
+ };
10320
+ /** @deprecated Use `injectSemanticColorTheme('error')`, which follows the surface the element renders on. */
10321
+ const injectErrorTheme = () => injectColorThemeByType('error');
10322
+ /** @deprecated Use `injectSemanticColorTheme('warning')`, which follows the surface the element renders on. */
10323
+ const injectWarningTheme = () => injectColorThemeByType('warning');
10324
+ /** @deprecated Use `injectSemanticColorTheme('success')`, which follows the surface the element renders on. */
10325
+ const injectSuccessTheme = () => injectColorThemeByType('success');
10326
+ const injectDefaultColorTheme = () => {
10327
+ const themes = injectColorThemes({ optional: true });
10328
+ if (!themes) {
10329
+ throw new Error(`[injectDefaultColorTheme] No color themes provided. Call provideColorThemesWithTailwind4() in your app config.`);
10330
+ }
10331
+ const theme = themes.find((t) => t.isDefault);
10332
+ if (!theme) {
10333
+ throw new Error(`[injectDefaultColorTheme] No color theme with isDefault: true found. Mark one theme as the default in provideColorThemesWithTailwind4().`);
10334
+ }
10335
+ if (isDevMode()) {
10336
+ const duplicates = themes.filter((t) => t.isDefault);
10337
+ if (duplicates.length > 1) {
10338
+ console.error(`[injectDefaultColorTheme] Multiple themes with isDefault: true found: ${duplicates.map((t) => t.name).join(', ')}. Only the first one will be used.`);
10339
+ }
10340
+ }
10341
+ return theme;
10342
+ };
10343
+
10344
+ const findRootSurfaceTheme = (defaults, type) => {
10345
+ if (defaults.length <= 1)
10346
+ return defaults[0] ?? null;
10347
+ return defaults.find((theme) => theme.type === type) ?? null;
10348
+ };
10349
+ const COLOR_SCHEME_DEF = /* @__PURE__ */ defineProvider(() => {
10350
+ const root = inject(DOCUMENT).documentElement;
10351
+ const prefix = injectSurfaceThemesPrefix({ optional: true }) || 'et';
10352
+ const prefersDark = injectBreakpointObserver().observeMediaQuery('(prefers-color-scheme: dark)');
10353
+ const mode = signal('system', /* @ts-ignore */
10354
+ ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
10355
+ const surfaceDefaults = injectSurfaceThemes({ optional: true })?.filter((theme) => theme.isDefault) ?? [];
10356
+ const colorThemes = injectColorThemes({ optional: true });
10357
+ const colorPrefix = injectColorThemesPrefix({ optional: true }) || 'et';
10358
+ const type = computed(() => {
10359
+ const current = mode();
10360
+ if (current !== 'system')
10361
+ return current;
10362
+ return prefersDark() ? 'dark' : 'light';
10363
+ }, /* @ts-ignore */
10364
+ ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
10365
+ const rootSurface = computed(() => findRootSurfaceTheme(surfaceDefaults, type()), /* @ts-ignore */
10366
+ ...(ngDevMode ? [{ debugName: "rootSurface" }] : /* istanbul ignore next */ []));
10367
+ const rootColorClass = computed(() => {
10368
+ const chosen = colorThemes?.find((theme) => theme.isDefault)?.name;
10369
+ if (!chosen)
10370
+ return null;
10371
+ const variant = resolveColorThemeVariant(rootSurface(), chosen, colorThemes);
10372
+ return variant === chosen ? null : `${colorPrefix}-color--${createCssColorThemeName(variant)}`;
10373
+ }, /* @ts-ignore */
10374
+ ...(ngDevMode ? [{ debugName: "rootColorClass" }] : /* istanbul ignore next */ []));
10375
+ const defaultColor = colorThemes?.find((theme) => theme.isDefault)?.name;
10376
+ if (defaultColor) {
10377
+ for (const surface of surfaceDefaults) {
10378
+ const variant = resolveColorThemeVariant(surface, defaultColor, colorThemes);
10379
+ if (variant !== defaultColor)
10380
+ root.classList.remove(`${colorPrefix}-color--${createCssColorThemeName(variant)}`);
10381
+ }
10382
+ }
10383
+ let paintedColorClass = null;
10384
+ const clearColorClass = () => {
10385
+ if (paintedColorClass)
10386
+ root.classList.remove(paintedColorClass);
10387
+ paintedColorClass = null;
10388
+ };
10389
+ effect(() => {
10390
+ const next = rootColorClass();
10391
+ clearColorClass();
10392
+ if (next)
10393
+ root.classList.add(next);
10394
+ paintedColorClass = next;
10395
+ });
10396
+ const clearClasses = () => root.classList.remove(`${prefix}-scheme--light`, `${prefix}-scheme--dark`);
10397
+ const setMode = (next) => {
10398
+ clearClasses();
10399
+ if (next !== 'system')
10400
+ root.classList.add(`${prefix}-scheme--${next}`);
10401
+ mode.set(next);
10402
+ };
10403
+ inject(DestroyRef).onDestroy(() => {
10404
+ clearClasses();
10405
+ clearColorClass();
10406
+ });
10407
+ return { mode: mode.asReadonly(), type, rootSurface, setMode };
10408
+ }, { name: 'Color Scheme' });
10409
+ const provideColorSchemeState = /* @__PURE__ */ toProvideFn(COLOR_SCHEME_DEF);
10410
+ /**
10411
+ * Inject the app's color scheme: `mode()` is what the app asked for, `type()` the surface type the
10412
+ * root paints, `rootSurface()` the default surface theme of that type, and `setMode()` switches it.
10413
+ * Needs `provideColorScheme()`.
10414
+ */
10415
+ const injectColorScheme = /* @__PURE__ */ toInjectFn(COLOR_SCHEME_DEF);
10416
+ const injectSchemeUnresolved = () => {
10417
+ const { mode } = injectColorScheme();
10418
+ const isServer = isPlatformServer(inject(PLATFORM_ID));
10419
+ const defaultCount = injectSurfaceThemes({ optional: true })?.filter((theme) => theme.isDefault).length ?? 0;
10420
+ return computed(() => isServer && defaultCount > 1 && mode() === 'system');
10421
+ };
10422
+ /**
10423
+ * Lets the app switch between its default light and dark surface with a class on `<html>`, instead of
10424
+ * only following `prefers-color-scheme`. It also paints the root surface's `colorThemeVariants` entry for the
10425
+ * default accent on `<html>`. Add it to the application config, next to
10426
+ * `provideSurfaceThemesWithTailwind4()`.
10427
+ */
10428
+ const provideColorScheme = (config) => makeEnvironmentProviders([
10429
+ provideColorSchemeState(),
10430
+ { provide: COLOR_SCHEME_TYPE, useFactory: () => injectColorScheme().type },
10431
+ { provide: COLOR_SCHEME_UNRESOLVED, useFactory: injectSchemeUnresolved },
10432
+ provideEnvironmentInitializer(() => injectColorScheme().setMode(config?.mode ?? 'system')),
10433
+ ]);
10434
+ /**
10435
+ * Inject a signal of the default surface theme the root paints where nothing scopes one. If the app
10436
+ * registers a default for both surface types, it follows `injectColorScheme()`, and is `null` without
10437
+ * `provideColorScheme()`.
10438
+ */
10439
+ const injectRootSurfaceTheme = () => {
10440
+ const defaults = injectSurfaceThemes({ optional: true })?.filter((theme) => theme.isDefault) ?? [];
10441
+ const colorSchemeType = inject(COLOR_SCHEME_TYPE, { optional: true });
10442
+ return computed(() => findRootSurfaceTheme(defaults, colorSchemeType?.()));
10443
+ };
10444
+
10306
10445
  let uniqueId = 0;
10307
10446
  const SURFACE_CONTEXT_TRACKER_DEF = /* @__PURE__ */ defineRootProvider(() => {
10308
10447
  const entries = signal([], /* @ts-ignore */
@@ -10350,6 +10489,8 @@ class AutoSurfaceDirective {
10350
10489
  this.surfaceContextTracker = injectSurfaceContextTracker();
10351
10490
  this.parentSurface = injectParentSurface();
10352
10491
  this.elementRef = inject(ElementRef);
10492
+ this.schemeUnresolved = inject(COLOR_SCHEME_UNRESOLVED, { optional: true });
10493
+ this.rootTheme = injectRootSurfaceTheme();
10353
10494
  /**
10354
10495
  * Explicit surface provider to resolve the surface relative to. Falls back to the
10355
10496
  * surface provider from the surrounding (trigger) context when not set.
@@ -10375,6 +10516,10 @@ class AutoSurfaceDirective {
10375
10516
  const overlaySurface = this.surfaceContextTracker.surfaceForElement(this.elementRef.nativeElement);
10376
10517
  const overlayElevation = overlaySurface?.elevation ?? null;
10377
10518
  const overlayType = overlaySurface?.type ?? null;
10519
+ // A surface derived from the root would bake the server's guessed scheme into the markup; inherit, and let CSS pick it.
10520
+ if (this.schemeUnresolved?.() && overlayElevation === null && contextTheme === this.rootTheme()) {
10521
+ return null;
10522
+ }
10378
10523
  // Must not re-derive from the declaration injector: it points at the trigger and would double-elevate the panel.
10379
10524
  if (this.isOverlaySurface()) {
10380
10525
  if (overlayElevation !== null) {
@@ -10722,11 +10867,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
10722
10867
 
10723
10868
  // Generated from package.json by tools/scripts/generate-version.js - do not edit.
10724
10869
  /** The version of `@ethlete/core` this build was cut from. */
10725
- const CORE_VERSION = '5.0.0-next.64';
10870
+ const CORE_VERSION = '5.0.0-next.66';
10726
10871
 
10727
10872
  /**
10728
10873
  * Generated bundle index. Do not edit.
10729
10874
  */
10730
10875
 
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 };
10876
+ 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, registerScrollRestorationState, 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
10877
  //# sourceMappingURL=ethlete-core.mjs.map