@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 +17 -0
- package/fesm2022/ethlete-core.mjs +165 -173
- package/fesm2022/ethlete-core.mjs.map +1 -1
- package/package.json +1 -1
- package/types/ethlete-core.d.ts +53 -75
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
|
-
|
|
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(
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
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
|
-
|
|
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,
|
|
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
|