@ethlete/core 5.0.0-next.40 → 5.0.0-next.42

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # @ethlete/core
2
2
 
3
+ ## 5.0.0-next.42
4
+
5
+ ### Minor Changes
6
+
7
+ - [#3047](https://github.com/ethlete-io/ethdk/pull/3047) [`309dc57`](https://github.com/ethlete-io/ethdk/commit/309dc576d296efe39d9ff85030102c10db834b9b) Thanks [@github-actions](https://github.com/apps/github-actions)! - Scroll restoration: mark a "back to the overview" link with `etRestoreScroll` (or `routerRestoreScroll()` in the navigation state) and it restores that page's last offset instead of scrolling to top.
8
+
9
+ ## 5.0.0-next.41
10
+
11
+ ### Major Changes
12
+
13
+ - [#3046](https://github.com/ethlete-io/ethdk/pull/3046) [`263dae8`](https://github.com/ethlete-io/ethdk/commit/263dae89d864db2a05541f373a2a1b7d2e75c42f) Thanks [@github-actions](https://github.com/apps/github-actions)! - Remove the deprecated, SSR-unsafe `SeoDirective` and its `SeoConfig` types - use the `apply*Binding` functions instead (the SEO guide has a per-key migration table).
14
+
15
+ ### Minor Changes
16
+
17
+ - [#3046](https://github.com/ethlete-io/ethdk/pull/3046) [`5b94adc`](https://github.com/ethlete-io/ethdk/commit/5b94adc97abb32555fb462fad71cbe27fc733a4a) Thanks [@github-actions](https://github.com/apps/github-actions)! - Select and cascader panels now stay below the field with a shorter list instead of flipping
18
+ above it or sliding over it, via the new anchored-overlay `minAvailableSpace` option.
19
+
3
20
  ## 5.0.0-next.40
4
21
 
5
22
  ### Minor Changes
@@ -5,7 +5,7 @@ import { Subject, BehaviorSubject, debounceTime, combineLatest, map, merge, from
5
5
  import { FormGroup, FormArray, FormControl } from '@angular/forms';
6
6
  import { SIGNAL, signalSetFn } from '@angular/core/primitives/signals';
7
7
  import { DOCUMENT as DOCUMENT$1, isPlatformBrowser } from '@angular/common';
8
- import { Router, NavigationEnd, NavigationSkipped, NavigationStart } from '@angular/router';
8
+ import { Router, NavigationEnd, NavigationSkipped, NavigationStart, RouterLink } from '@angular/router';
9
9
  import { autoUpdate, offset, flip, shift, limitShift, computePosition, hide, arrow, size } from '@floating-ui/dom';
10
10
  import { Title, Meta, DomSanitizer } from '@angular/platform-browser';
11
11
 
@@ -3076,6 +3076,20 @@ const routerDisableScrollTop = (config = {}) => {
3076
3076
  ...(config.onPathParamChange ? { [ET_DISABLE_SCROLL_TOP_ON_PATH_PARAM_CHANGE]: true } : {}),
3077
3077
  };
3078
3078
  };
3079
+ const ET_RESTORE_SCROLL = /* @__PURE__ */ Symbol('ET_RESTORE_SCROLL');
3080
+ /**
3081
+ * Marks a navigation as a return to a page the user has already seen, so it restores that page's last
3082
+ * scroll offset instead of scrolling to top - what a "back to the overview" link means, as opposed to
3083
+ * a link that opens the overview fresh. Spread into `NavigationExtras.state`; for a `routerLink`, use
3084
+ * {@link RestoreScrollDirective} instead.
3085
+ *
3086
+ * Needs `restore.enabled` on {@link setupScrollRestoration}, and only ever restores an offset the
3087
+ * session actually recorded - the first visit to a page has none, so it scrolls to top as usual.
3088
+ *
3089
+ * @example
3090
+ * router.navigate(['/teams'], { state: routerRestoreScroll() });
3091
+ */
3092
+ const routerRestoreScroll = () => ({ [ET_RESTORE_SCROLL]: true });
3079
3093
  const SCROLL_RESTORATION_HOLDS_DEF = /* @__PURE__ */ defineRootProvider(() => {
3080
3094
  const holds = new Set();
3081
3095
  return {
@@ -3119,6 +3133,11 @@ const DEFAULT_RESTORE_TIMEOUT = 1000;
3119
3133
  const DEFAULT_RESTORE_MAX_TIMEOUT = 10_000;
3120
3134
  /** Events that mean the user took over scrolling, so a pending restoration must be abandoned. */
3121
3135
  const INTERACTION_EVENTS = ['wheel', 'touchmove', 'keydown'];
3136
+ /** Key order is navigation order, not declaration order, so two spellings of one URL compare equal. */
3137
+ const serializeQueryParams = (queryParams) => Object.keys(queryParams)
3138
+ .sort()
3139
+ .map((key) => `${key}=${queryParams[key]}`)
3140
+ .join('&');
3122
3141
  const setupScrollRestoration = (config = {}) => {
3123
3142
  if (!isPlatformBrowser(inject(PLATFORM_ID))) {
3124
3143
  return;
@@ -3140,13 +3159,14 @@ const setupScrollRestoration = (config = {}) => {
3140
3159
  if (restoreEnabled && 'scrollRestoration' in history) {
3141
3160
  history.scrollRestoration = 'manual';
3142
3161
  }
3143
- /** Saved offsets keyed by the router's per-history-entry `navigationId`. */
3162
+ /** Saved offsets keyed by the router's per-history-entry `navigationId`, in least-recent-first order. */
3144
3163
  const positions = new Map();
3145
3164
  // Mirrors Angular's own `RouterScroller`: the offset of the currently displayed page belongs to
3146
3165
  // the navigation that produced it, and a popstate reports the id of the entry it moves to.
3147
3166
  let lastNavigationId = 0;
3148
3167
  let restoredNavigationId = 0;
3149
3168
  let isPopstate = false;
3169
+ let wantsRestore = false;
3150
3170
  let prev = { state: createRouterState(router), route: createRoute(router) };
3151
3171
  let pendingRestore = null;
3152
3172
  const cancelPendingRestore = () => {
@@ -3215,12 +3235,36 @@ const setupScrollRestoration = (config = {}) => {
3215
3235
  }
3216
3236
  };
3217
3237
  };
3238
+ /**
3239
+ * The offset the most recently left entry for this page had. A target without query params means
3240
+ * "that page", whichever query state it was last in - the crumb linking to an overview does not
3241
+ * know, and should not have to reproduce, the filter the user left it under.
3242
+ */
3243
+ const findLastVisitedOffset = (route, search) => {
3244
+ const entries = [...positions.values()];
3245
+ for (let i = entries.length - 1; i >= 0; i--) {
3246
+ const entry = entries[i];
3247
+ if (!entry || entry.route !== route)
3248
+ continue;
3249
+ if (search && entry.search !== search)
3250
+ continue;
3251
+ return entry.top;
3252
+ }
3253
+ return undefined;
3254
+ };
3218
3255
  const onNavigationStart = (event) => {
3219
3256
  // A new navigation supersedes a restoration that has not committed yet.
3220
3257
  cancelPendingRestore();
3221
3258
  if (!restoreEnabled)
3222
3259
  return;
3223
- positions.set(lastNavigationId, resolveScrollElement().scrollTop);
3260
+ // Re-inserted rather than overwritten so map order stays least-recently-left first, which is both
3261
+ // what `findLastVisitedOffset` walks backwards and what the cap below evicts from.
3262
+ positions.delete(lastNavigationId);
3263
+ positions.set(lastNavigationId, {
3264
+ top: resolveScrollElement().scrollTop,
3265
+ route: prev.route,
3266
+ search: serializeQueryParams(prev.state.queryParams),
3267
+ });
3224
3268
  if (positions.size > MAX_STORED_POSITIONS) {
3225
3269
  const oldest = positions.keys().next();
3226
3270
  if (!oldest.done)
@@ -3228,6 +3272,11 @@ const setupScrollRestoration = (config = {}) => {
3228
3272
  }
3229
3273
  isPopstate = event.navigationTrigger === 'popstate';
3230
3274
  restoredNavigationId = event.restoredState?.navigationId ?? 0;
3275
+ // Read off the navigation rather than `history.state`: a symbol key does not survive being
3276
+ // structured-cloned into the history entry, which is what keeps the mark from outliving this
3277
+ // navigation and re-firing when the user later pops back to the entry it created.
3278
+ const navigationState = router.getCurrentNavigation()?.extras.state;
3279
+ wantsRestore = !isPopstate && navigationState?.[ET_RESTORE_SCROLL] === true;
3231
3280
  };
3232
3281
  const onNavigationEnd = (event) => {
3233
3282
  const curr = { state: createRouterState(router), route: createRoute(router) };
@@ -3236,6 +3285,8 @@ const setupScrollRestoration = (config = {}) => {
3236
3285
  const sameUrlNavigation = prev.route === curr.route;
3237
3286
  const didFragmentChange = prevState.fragment !== currState.fragment;
3238
3287
  prev = curr;
3288
+ const wasMarkedAsReturn = wantsRestore;
3289
+ wantsRestore = false;
3239
3290
  if (event instanceof NavigationEnd) {
3240
3291
  lastNavigationId = event.id;
3241
3292
  }
@@ -3248,6 +3299,13 @@ const setupScrollRestoration = (config = {}) => {
3248
3299
  const target = positions.get(restoredNavigationId);
3249
3300
  // The saved offset wins over both scroll to top and fragment scrolling: the user may well have
3250
3301
  // scrolled away from the anchor before leaving the page.
3302
+ if (target !== undefined) {
3303
+ scheduleRestore(target.top);
3304
+ return;
3305
+ }
3306
+ }
3307
+ if (restoreEnabled && wasMarkedAsReturn) {
3308
+ const target = findLastVisitedOffset(curr.route, serializeQueryParams(currState.queryParams));
3251
3309
  if (target !== undefined) {
3252
3310
  scheduleRestore(target);
3253
3311
  return;
@@ -4825,6 +4883,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
4825
4883
  }]
4826
4884
  }], ctorParameters: () => [], propDecorators: { repeatCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "etRepeat", required: false }] }] } });
4827
4885
 
4886
+ /**
4887
+ * Marks a `routerLink` as a return to a page the user has already seen - a "back to the overview"
4888
+ * link - so it restores that page's last scroll offset instead of scrolling to top.
4889
+ *
4890
+ * Needs `restore.enabled` on `setupScrollRestoration`. A page the session has no offset for (the
4891
+ * first visit, or a reload since) scrolls to top as usual.
4892
+ *
4893
+ * @example
4894
+ * <a routerLink="/teams" etRestoreScroll>Teams</a>
4895
+ */
4896
+ class RestoreScrollDirective {
4897
+ constructor() {
4898
+ this.routerLink = inject(RouterLink);
4899
+ this.elementRef = inject(ElementRef);
4900
+ // Capture, so the mark is on `state` before `RouterLink`'s own click handler reads it. Applied
4901
+ // per click rather than once, because a `[state]` binding on the same element would overwrite it
4902
+ // on any later change detection run.
4903
+ this.elementRef.nativeElement.addEventListener('click', () => (this.routerLink.state = { ...this.routerLink.state, ...routerRestoreScroll() }), { capture: true });
4904
+ }
4905
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: RestoreScrollDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4906
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.7", type: RestoreScrollDirective, isStandalone: true, selector: "[routerLink][etRestoreScroll]", ngImport: i0 }); }
4907
+ }
4908
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: RestoreScrollDirective, decorators: [{
4909
+ type: Directive,
4910
+ args: [{
4911
+ selector: '[routerLink][etRestoreScroll]',
4912
+ }]
4913
+ }], ctorParameters: () => [] });
4914
+
4828
4915
  class ScrollObserverDirective {
4829
4916
  constructor() {
4830
4917
  this.elementRef = inject(ElementRef);
@@ -5443,9 +5530,65 @@ const requireMiddlewareExtras = (feature) => {
5443
5530
  }
5444
5531
  return middlewareExtras;
5445
5532
  };
5533
+ const OPPOSITE_SIDE = {
5534
+ top: 'bottom',
5535
+ bottom: 'top',
5536
+ left: 'right',
5537
+ right: 'left',
5538
+ };
5539
+ const PREFERRED_SIDE_NAME = 'etPreferredSide';
5540
+ const getAnchoredSide = (placement) => placement.split('-')[0];
5541
+ const toOppositeSidePlacement = (placement) => {
5542
+ const [side, alignment] = placement.split('-');
5543
+ const opposite = OPPOSITE_SIDE[side];
5544
+ return (alignment ? `${opposite}-${alignment}` : opposite);
5545
+ };
5546
+ /**
5547
+ * The `flip` replacement behind `minAvailableSpace` - see that option. Every decision here has to
5548
+ * stay derived from the space around the reference alone: the moment the pane's own size enters it,
5549
+ * `size`'s cap feeds back into the next placement and an open pane starts flipping on its own.
5550
+ */
5551
+ const preferredSide = (options) => ({
5552
+ name: PREFERRED_SIDE_NAME,
5553
+ options,
5554
+ async fn(state) {
5555
+ const { placement, initialPlacement, rects, middlewareData } = state;
5556
+ const side = getAnchoredSide(placement);
5557
+ // via the platform, like every built-in middleware - importing `detectOverflow` from
5558
+ // `@floating-ui/dom` instead pulls a second copy of it into the bundle
5559
+ const overflow = await state.platform.detectOverflow(state, {
5560
+ padding: options.padding,
5561
+ boundary: options.boundary,
5562
+ });
5563
+ const isYAxis = side === 'top' || side === 'bottom';
5564
+ // the pane's own size cancels out of `size - overflow[side]`: what remains is the distance from
5565
+ // its anchored edge to the boundary - the same number the `size` middleware caps the pane to
5566
+ const available = (isYAxis ? rects.floating.height : rects.floating.width) - overflow[side];
5567
+ const availableSpace = {
5568
+ ...middlewareData[PREFERRED_SIDE_NAME]?.availableSpace,
5569
+ [side]: available,
5570
+ };
5571
+ if (available >= options.minAvailableSpace) {
5572
+ return {};
5573
+ }
5574
+ const oppositeAvailable = availableSpace[OPPOSITE_SIDE[side]];
5575
+ if (oppositeAvailable === undefined) {
5576
+ return { data: { availableSpace }, reset: { placement: toOppositeSidePlacement(placement) } };
5577
+ }
5578
+ // ties go to the placement's own side, which also terminates the reset loop after at most one
5579
+ // measurement per side
5580
+ const keepSide = side === getAnchoredSide(initialPlacement) ? available >= oppositeAvailable : available > oppositeAvailable;
5581
+ return keepSide
5582
+ ? { data: { availableSpace } }
5583
+ : { data: { availableSpace }, reset: { placement: toOppositeSidePlacement(placement) } };
5584
+ },
5585
+ });
5446
5586
  const createAnchoredPositionCleanup = (strategy, paneElement, overlayRef, renderer) => {
5447
5587
  // mirrorWidth needs a real element to measure; virtual references fall back to max-content
5448
5588
  const mirrorWidthElement = strategy.mirrorWidth && isHTMLElement(strategy.referenceElement) ? strategy.referenceElement : null;
5589
+ if (strategy.minAvailableSpace !== undefined && !strategy.autoResize && isDevMode()) {
5590
+ 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`.');
5591
+ }
5449
5592
  renderer.setStyle(paneElement, {
5450
5593
  position: 'absolute',
5451
5594
  top: '0',
@@ -5456,14 +5599,26 @@ const createAnchoredPositionCleanup = (strategy, paneElement, overlayRef, render
5456
5599
  const arrowElement = paneElement.querySelector('[et-floating-arrow]');
5457
5600
  const middleware = [];
5458
5601
  middleware.push(offset(strategy.offset ?? 8));
5459
- middleware.push(flip({
5460
- fallbackPlacements: strategy.fallbackPlacements ?? undefined,
5461
- fallbackAxisSideDirection: 'start',
5462
- boundary: strategy.boundary,
5463
- }));
5602
+ middleware.push(strategy.minAvailableSpace === undefined
5603
+ ? flip({
5604
+ fallbackPlacements: strategy.fallbackPlacements ?? undefined,
5605
+ fallbackAxisSideDirection: 'start',
5606
+ boundary: strategy.boundary,
5607
+ })
5608
+ : preferredSide({
5609
+ minAvailableSpace: strategy.minAvailableSpace,
5610
+ // must stay the padding `size` measures with: the threshold is then compared against the
5611
+ // very height the pane ends up capped to
5612
+ padding: strategy.viewportPadding ?? 8,
5613
+ boundary: strategy.boundary,
5614
+ }));
5464
5615
  if (strategy.shift !== false) {
5465
5616
  middleware.push(shift({
5466
- crossAxis: typeof strategy.shift === 'object' ? (strategy.shift.crossAxis ?? false) : false,
5617
+ // floating-ui's cross axis points at the reference, so shifting on it slides the pane over
5618
+ // the reference instead of letting it shrink - and `size` then reports the whole boundary
5619
+ // as available height rather than the space on the pane's side
5620
+ crossAxis: strategy.minAvailableSpace === undefined &&
5621
+ (typeof strategy.shift === 'object' ? (strategy.shift.crossAxis ?? false) : false),
5467
5622
  limiter: limitShift(),
5468
5623
  padding: strategy.viewportPadding ?? 8,
5469
5624
  boundary: strategy.boundary,
@@ -7822,169 +7977,6 @@ const applySocialMediaBindings = (config) => {
7822
7977
  applyArticleBindings(config.article);
7823
7978
  };
7824
7979
 
7825
- const mergeSeoConfig = (config, parentConfig) => {
7826
- return {
7827
- ...parentConfig,
7828
- ...config,
7829
- };
7830
- };
7831
- const SEO_DIRECTIVE_TOKEN = new InjectionToken('SEO_DIRECTIVE_TOKEN');
7832
- /** @deprecated use binding utils instead */
7833
- class SeoDirective {
7834
- constructor() {
7835
- this._metaService = inject(Meta);
7836
- this._titleService = inject(Title);
7837
- this._onDeactivate$ = new Subject();
7838
- this._isDeactivated = false;
7839
- this.parent = inject(SEO_DIRECTIVE_TOKEN, { optional: true, skipSelf: true });
7840
- this._config = {};
7841
- }
7842
- get config() {
7843
- return this._config;
7844
- }
7845
- ngOnInit() {
7846
- this.parent?._deactivate();
7847
- }
7848
- ngOnDestroy() {
7849
- this._deactivate();
7850
- this._cleanUp();
7851
- this.parent?._activate();
7852
- }
7853
- updateConfig(config) {
7854
- this._config = mergeSeoConfig(config, this.parent?.config || {});
7855
- if (this._isDeactivated) {
7856
- return;
7857
- }
7858
- this._deactivate();
7859
- this._activate();
7860
- }
7861
- _activate() {
7862
- this._onDeactivate$.next(false);
7863
- this._isDeactivated = false;
7864
- for (const [key, value] of Object.entries(this._config)) {
7865
- if (value instanceof Observable) {
7866
- value.pipe(takeUntil(this._onDeactivate$)).subscribe((value) => this._update(key, value));
7867
- }
7868
- else if (Array.isArray(value)) {
7869
- value.forEach((value) => {
7870
- if (value instanceof Observable) {
7871
- value.pipe(takeUntil(this._onDeactivate$)).subscribe((value) => this._update(key, value));
7872
- }
7873
- else {
7874
- this._update(key, value);
7875
- }
7876
- });
7877
- }
7878
- else if (typeof value === 'object' && value !== null) {
7879
- for (const [subKey, subValue] of Object.entries(value)) {
7880
- if (subValue instanceof Observable) {
7881
- subValue.pipe(takeUntil(this._onDeactivate$)).subscribe((value) => this._update(`${key}:${subKey}`, value));
7882
- }
7883
- else {
7884
- this._update(`${key}:${subKey}`, subValue);
7885
- }
7886
- }
7887
- }
7888
- else {
7889
- this._update(key, value);
7890
- }
7891
- }
7892
- }
7893
- _deactivate() {
7894
- this._onDeactivate$.next(true);
7895
- this._isDeactivated = true;
7896
- }
7897
- _update(key, value) {
7898
- switch (key) {
7899
- case 'title':
7900
- if (value && typeof value === 'string') {
7901
- this._titleService.setTitle(value);
7902
- }
7903
- break;
7904
- case 'canonical':
7905
- {
7906
- const link = document.querySelector(`link[rel="${key}"]`);
7907
- if (link) {
7908
- link.setAttribute('href', value);
7909
- }
7910
- else {
7911
- const newLink = document.createElement('link');
7912
- newLink.setAttribute('rel', key);
7913
- newLink.setAttribute('href', value);
7914
- document.head.appendChild(newLink);
7915
- }
7916
- }
7917
- break;
7918
- case 'alternate':
7919
- {
7920
- const link = document.querySelector(`link[rel="${key}"][hreflang="${value.hreflang}"]`);
7921
- if (link) {
7922
- link.setAttribute('href', value.href);
7923
- }
7924
- else {
7925
- const newLink = document.createElement('link');
7926
- newLink.setAttribute('rel', key);
7927
- newLink.setAttribute('hreflang', value.hreflang);
7928
- newLink.setAttribute('href', value.href);
7929
- document.head.appendChild(newLink);
7930
- }
7931
- }
7932
- break;
7933
- default:
7934
- if (value !== undefined && value !== null) {
7935
- const val = Array.isArray(value) ? value.join(', ') : value;
7936
- this._metaService.updateTag({ name: key, content: val });
7937
- }
7938
- else {
7939
- this._metaService.removeTag(`name="${key}"`);
7940
- }
7941
- break;
7942
- }
7943
- }
7944
- _cleanUp() {
7945
- for (const key in this._config) {
7946
- if (key === 'alternate') {
7947
- const links = document.querySelectorAll(`link[rel="${key}"]`);
7948
- links.forEach((link) => {
7949
- link.remove();
7950
- });
7951
- continue;
7952
- }
7953
- if (key === 'canonical') {
7954
- const link = document.querySelector(`link[rel="${key}"]`);
7955
- if (link) {
7956
- link.remove();
7957
- }
7958
- continue;
7959
- }
7960
- if (typeof this._config[key] === 'object' &&
7961
- this._config[key] !== null &&
7962
- !(this._config[key] instanceof Observable)) {
7963
- for (const subKey in this._config[key]) {
7964
- const parentValue = this.parent?.config?.[key]?.[subKey];
7965
- if (parentValue === undefined) {
7966
- this._update(`${key}:${subKey}`, undefined);
7967
- }
7968
- }
7969
- }
7970
- else {
7971
- const parentValue = this.parent?.config?.[key];
7972
- if (parentValue === undefined) {
7973
- this._update(key, null);
7974
- }
7975
- }
7976
- }
7977
- }
7978
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: SeoDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
7979
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.7", type: SeoDirective, isStandalone: true, providers: [{ provide: SEO_DIRECTIVE_TOKEN, useExisting: SeoDirective }], ngImport: i0 }); }
7980
- }
7981
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: SeoDirective, decorators: [{
7982
- type: Directive,
7983
- args: [{
7984
- providers: [{ provide: SEO_DIRECTIVE_TOKEN, useExisting: SeoDirective }],
7985
- }]
7986
- }] });
7987
-
7988
7980
  const STRUCTURED_DATA_CONFIG_DEF = /* @__PURE__ */ defineStaticRootProvider({
7989
7981
  placement: 'body',
7990
7982
  }, { name: 'Structured Data Config' });
@@ -9298,5 +9290,5 @@ const createUnsavedChangesGuard = (config) => {
9298
9290
  * Generated bundle index. Do not edit.
9299
9291
  */
9300
9292
 
9301
- export { ANIMATABLE_TOKEN, ANIMATED_IF_TOKEN, ANIMATED_LIFECYCLE_TOKEN, ANIMATION_DEBUG_STORAGE_KEY, AT_LEAST_ONE_REQUIRED, AnimatableDirective, AnimatedIfDirective, AnimatedLifecycleDirective, AutoSurfaceDirective, BOUNDARY_ELEMENT_TOKEN, BREAKPOINT_INSTANCE_TOKEN, BREAKPOINT_ORDER, COLOR_PROVIDER, ClickOutsideDirective, ColorInteractiveContainerDirective, ColorInteractiveDirective, ColorInteractiveExcludeDirective, ColorInteractiveHasFocusDirective, DEFAULT_MULTI_INSTANCE_RELS, DEFAULT_MULTI_INSTANCE_TAGS, 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, FOCUSABLE_SELECTOR, FOCUS_VISIBLE_TRACKER_TOKEN, HtmlToMarkdownPipe, IS_ARRAY_NOT_EMPTY, IS_EMAIL, InferMimeTypePipe, InitialsPipe, IsArrayNotEmpty, IsEmail, jsonLd as JsonLD, KeyPressManager, MUST_MATCH, MarkdownToHtmlPipe, MustMatch, NOTIFICATION_CLICK_MESSAGE_TYPE, NormalizeGameResultTypePipe, NormalizeMatchParticipantsPipe, NormalizeMatchScorePipe, NormalizeMatchStatePipe, NormalizeMatchTypePipe, PropsDirective, ProvideColorDirective, ProvideSurfaceDirective, RUNTIME_ERROR_NO_DATA, RepeatDirective, ResizeHandlesComponent, RuntimeError, SEO_DIRECTIVE_TOKEN, SURFACE_PROVIDER, SURFACE_TYPE, SWIPE_VELOCITY_WINDOW_MS, ScrollObserverDirective, ScrollObserverEndDirective, ScrollObserverStartDirective, SeoDirective, SlugifyPipe, StructuredDataComponent, SurfaceInteractiveDirective, ToArrayPipe, TypedQueryList, UNSAVED_CHANGES_TITLE_MARKER, ValidateAtLeastOneRequired, Validators, 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, areScrollStatesEqual, bindProps, boolBreakpointTransform, booleanBreakpointAttribute, boundingClientRectToElementRect, breakpointTransformBase, buildElementSignal, buildSignalEffects, canUseSessionMemory, clamp, clone, cloneFormGroup, computedTillFalsy, computedTillTruthy, controlValueSignal, controlValueSignalWithPrevious, copyToClipboard, createAnchoredPositionCleanup, createArrayPropertyBinding, createAutoSessionMemoryKey, createBulkPropertyBinding, createCanAnimateSignal, createComponentId, createCssColorThemeName, createCssSurfaceName, createDependencyStash, createDestroy, createDocumentElementSignal, createElementDictionary, createElementDimensions, createEmptyElementSignal, createFlipAnimation, createFlipAnimationGroup, createHostProps, createIsRenderedSignal, createLogger, createOverlayRuntimeRef, createPropHandlers, createPropertyBinding, createProps, createRootThemeCss, createRoute, createRouterState, createRxHostListener, createSessionMemory, createSetup, 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, 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, injectBoundaryElement, injectBreakpointInput, injectBreakpointIsMatched, injectBreakpointObserver, injectCanHover, injectColorThemes, injectColorThemesPrefix, injectCurrentBreakpoint, injectDefaultColorTheme, injectDeviceInputType, injectDisplayOrientation, injectErrorTheme, injectFaviconStore, 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, injectPathParam, injectPathParamChanges, injectPathParams, injectPrefersReducedMotion, injectQueryParam, injectQueryParamChanges, injectQueryParams, injectRenderer, injectRoute, injectRouteData, injectRouteDataItem, injectRouteTitle, injectRouterEvent, injectRouterNavigationState, injectRouterState, injectScrollbarDimensions, injectStructuredDataConfig, injectStructuredDataStore, injectStyleManager, injectSuccessTheme, injectSurfaceContextTracker, injectSurfaceThemes, injectSurfaceThemesPrefix, injectTemplateRef, injectTitleConfig, injectTitleStore, injectUnsavedChangesCoordinator, injectUrl, injectViewportConfig, injectViewportDimensions, injectViewportSize, injectWarningTheme, isAnimationDebugEnabled, isArray, isElementSignal, isElementVisible, isFocusable, isGroupMatch, isHTMLElement, isKnockoutMatch, isObject, markdownToHtml, matchesReducedMotion, maybeSignalValue, memoizeSignal, nextFrame, normalizeGameResultType, normalizeMatchParticipant, normalizeMatchParticipants, normalizeMatchScore, normalizeMatchState, normalizeMatchType, normalizeUnsavedChangesSource, numberBreakpointAttribute, numberBreakpointTransform, previousSignalValue, provideBoundaryElement, provideBreakpointInstance, provideBreakpointObserver, provideColorThemes, provideColorThemesWithTailwind4, provideFaviconStore, provideFocusVisibleTracker, provideLinkStore, provideLinkStoreConfig, provideLocale, provideMetaConfig, provideMetaStore, provideNotifications, provideOverlayRuntime, provideRenderer, provideStructuredDataConfig, provideStructuredDataStore, provideStyleManager, provideSurfaceContextTracker, provideSurfaceThemesWithTailwind4, provideTitleConfig, provideTitleStore, provideUnsavedChangesCoordinator, provideViewportConfig, randomId, readFromClipboard, registerAnchoredPositionMiddlewareExtras, registerAnchoredPositionSetup, resetPositioningStyles, resolveAppRootColorProvider, resolveSurfaceByElevation, round, routerDisableScrollTop, scrollToElement, setBackdropStyles, setBaseElementStyles, setCookie, setInputSignal, setupFocusTrap, setupPositioning, setupScrollRestoration, signalAnimatedNumber, signalAttributes, signalClasses, signalElementChildren, signalElementDimensions, signalElementIntersection, signalElementLastScrollDirection, signalElementMutations, signalElementScrollState, signalHostAttributes, signalHostClasses, signalHostElementDimensions, signalHostElementIntersection, signalHostElementLastScrollDirection, signalHostElementMutations, signalHostElementScrollState, signalHostStyles, signalIsRendered, signalStyles, slugify, switchQueryListChanges, syncSignal, templateComputed, toArray, toArrayTrackByFn, toInjectFn, toProvideFn, toStringBinding, toToken, transformOrReturn, typedBreakpointTransform, unbindProps, useCursorDragScroll, writeScrollbarSizeToCssVariables, writeViewportSizeToCssVariables, ɵProvideColorThemes, ɵProvideColorThemesPrefix, ɵProvideSurfaceThemes, ɵProvideSurfaceThemesPrefix };
9293
+ export { ANIMATABLE_TOKEN, ANIMATED_IF_TOKEN, ANIMATED_LIFECYCLE_TOKEN, ANIMATION_DEBUG_STORAGE_KEY, AT_LEAST_ONE_REQUIRED, AnimatableDirective, AnimatedIfDirective, AnimatedLifecycleDirective, AutoSurfaceDirective, BOUNDARY_ELEMENT_TOKEN, BREAKPOINT_INSTANCE_TOKEN, BREAKPOINT_ORDER, COLOR_PROVIDER, ClickOutsideDirective, ColorInteractiveContainerDirective, ColorInteractiveDirective, ColorInteractiveExcludeDirective, ColorInteractiveHasFocusDirective, DEFAULT_MULTI_INSTANCE_RELS, DEFAULT_MULTI_INSTANCE_TAGS, 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, FOCUSABLE_SELECTOR, FOCUS_VISIBLE_TRACKER_TOKEN, HtmlToMarkdownPipe, IS_ARRAY_NOT_EMPTY, IS_EMAIL, InferMimeTypePipe, InitialsPipe, IsArrayNotEmpty, IsEmail, jsonLd as JsonLD, KeyPressManager, MUST_MATCH, MarkdownToHtmlPipe, MustMatch, NOTIFICATION_CLICK_MESSAGE_TYPE, NormalizeGameResultTypePipe, NormalizeMatchParticipantsPipe, NormalizeMatchScorePipe, NormalizeMatchStatePipe, NormalizeMatchTypePipe, PropsDirective, ProvideColorDirective, ProvideSurfaceDirective, RUNTIME_ERROR_NO_DATA, RepeatDirective, ResizeHandlesComponent, RestoreScrollDirective, RuntimeError, SURFACE_PROVIDER, SURFACE_TYPE, SWIPE_VELOCITY_WINDOW_MS, ScrollObserverDirective, ScrollObserverEndDirective, ScrollObserverStartDirective, SlugifyPipe, StructuredDataComponent, SurfaceInteractiveDirective, ToArrayPipe, TypedQueryList, UNSAVED_CHANGES_TITLE_MARKER, ValidateAtLeastOneRequired, Validators, 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, areScrollStatesEqual, bindProps, boolBreakpointTransform, booleanBreakpointAttribute, boundingClientRectToElementRect, breakpointTransformBase, buildElementSignal, buildSignalEffects, canUseSessionMemory, clamp, clone, cloneFormGroup, computedTillFalsy, computedTillTruthy, controlValueSignal, controlValueSignalWithPrevious, copyToClipboard, createAnchoredPositionCleanup, createArrayPropertyBinding, createAutoSessionMemoryKey, createBulkPropertyBinding, createCanAnimateSignal, createComponentId, createCssColorThemeName, createCssSurfaceName, createDependencyStash, createDestroy, createDocumentElementSignal, createElementDictionary, createElementDimensions, createEmptyElementSignal, createFlipAnimation, createFlipAnimationGroup, createHostProps, createIsRenderedSignal, createLogger, createOverlayRuntimeRef, createPropHandlers, createPropertyBinding, createProps, createRootThemeCss, createRoute, createRouterState, createRxHostListener, createSessionMemory, createSetup, 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, 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, injectBoundaryElement, injectBreakpointInput, injectBreakpointIsMatched, injectBreakpointObserver, injectCanHover, injectColorThemes, injectColorThemesPrefix, injectCurrentBreakpoint, injectDefaultColorTheme, injectDeviceInputType, injectDisplayOrientation, injectErrorTheme, injectFaviconStore, 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, injectPathParam, injectPathParamChanges, injectPathParams, injectPrefersReducedMotion, injectQueryParam, injectQueryParamChanges, injectQueryParams, injectRenderer, injectRoute, injectRouteData, injectRouteDataItem, injectRouteTitle, injectRouterEvent, injectRouterNavigationState, injectRouterState, injectScrollbarDimensions, injectStructuredDataConfig, injectStructuredDataStore, injectStyleManager, injectSuccessTheme, injectSurfaceContextTracker, injectSurfaceThemes, injectSurfaceThemesPrefix, injectTemplateRef, injectTitleConfig, injectTitleStore, injectUnsavedChangesCoordinator, injectUrl, injectViewportConfig, injectViewportDimensions, injectViewportSize, injectWarningTheme, isAnimationDebugEnabled, isArray, isElementSignal, isElementVisible, isFocusable, isGroupMatch, isHTMLElement, isKnockoutMatch, isObject, markdownToHtml, matchesReducedMotion, maybeSignalValue, memoizeSignal, nextFrame, normalizeGameResultType, normalizeMatchParticipant, normalizeMatchParticipants, normalizeMatchScore, normalizeMatchState, normalizeMatchType, normalizeUnsavedChangesSource, numberBreakpointAttribute, numberBreakpointTransform, previousSignalValue, provideBoundaryElement, provideBreakpointInstance, provideBreakpointObserver, provideColorThemes, provideColorThemesWithTailwind4, provideFaviconStore, provideFocusVisibleTracker, provideLinkStore, provideLinkStoreConfig, provideLocale, provideMetaConfig, provideMetaStore, provideNotifications, provideOverlayRuntime, provideRenderer, provideStructuredDataConfig, provideStructuredDataStore, provideStyleManager, provideSurfaceContextTracker, provideSurfaceThemesWithTailwind4, provideTitleConfig, provideTitleStore, provideUnsavedChangesCoordinator, provideViewportConfig, randomId, readFromClipboard, registerAnchoredPositionMiddlewareExtras, registerAnchoredPositionSetup, resetPositioningStyles, resolveAppRootColorProvider, resolveSurfaceByElevation, round, routerDisableScrollTop, routerRestoreScroll, scrollToElement, setBackdropStyles, setBaseElementStyles, setCookie, setInputSignal, setupFocusTrap, setupPositioning, setupScrollRestoration, signalAnimatedNumber, signalAttributes, signalClasses, signalElementChildren, signalElementDimensions, signalElementIntersection, signalElementLastScrollDirection, signalElementMutations, signalElementScrollState, signalHostAttributes, signalHostClasses, signalHostElementDimensions, signalHostElementIntersection, signalHostElementLastScrollDirection, signalHostElementMutations, signalHostElementScrollState, signalHostStyles, signalIsRendered, signalStyles, slugify, switchQueryListChanges, syncSignal, templateComputed, toArray, toArrayTrackByFn, toInjectFn, toProvideFn, toStringBinding, toToken, transformOrReturn, typedBreakpointTransform, unbindProps, useCursorDragScroll, writeScrollbarSizeToCssVariables, writeViewportSizeToCssVariables, ɵProvideColorThemes, ɵProvideColorThemesPrefix, ɵProvideSurfaceThemes, ɵProvideSurfaceThemesPrefix };
9302
9294
  //# sourceMappingURL=ethlete-core.mjs.map