@ethlete/core 5.0.0-next.61 → 5.0.0-next.62
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 +47 -0
- package/fesm2022/ethlete-core.mjs +657 -348
- package/fesm2022/ethlete-core.mjs.map +1 -1
- package/generators/generators.json +10 -0
- package/generators/migrate-create-destroy/create-destroy.js +317 -0
- package/generators/migrate-create-destroy/migration.js +46 -0
- package/generators/migrate-create-destroy/schema.json +26 -0
- package/generators/migrate-legacy-color-themes/legacy-color-themes.js +123 -0
- package/generators/migrate-legacy-color-themes/migration.js +93 -0
- package/generators/migrate-legacy-color-themes/schema.json +26 -0
- package/generators/migrate-to-v5/removed-exports.js +94 -6
- package/migrations/legacy-color-themes.md +38 -0
- package/migrations/seo-directive-removed.md +2 -1
- package/migrations.json +15 -0
- package/package.json +11 -11
- package/types/ethlete-core.d.ts +261 -170
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { assertInInjectionContext, inject, DestroyRef, ElementRef, TemplateRef, InjectionToken, QueryList, RendererFactory2, RendererStyleFlags2, isSignal, DOCUMENT, signal, linkedSignal, isDevMode, computed, afterNextRender, effect, untracked, ApplicationRef, runInInjectionContext, NgZone, Injector,
|
|
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, 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 } 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, BehaviorSubject, combineLatest, Observable, isObservable, firstValueFrom, defaultIfEmpty, concatMap, concat, finalize, exhaustMap, share, shareReplay, ReplaySubject } from 'rxjs';
|
|
5
5
|
import { FormGroup, FormArray, FormControl } from '@angular/forms';
|
|
6
6
|
import { SIGNAL, signalSetFn } from '@angular/core/primitives/signals';
|
|
7
|
-
import { isPlatformBrowser, DOCUMENT as DOCUMENT$1 } from '@angular/common';
|
|
7
|
+
import { isPlatformBrowser, Location, DOCUMENT as DOCUMENT$1 } from '@angular/common';
|
|
8
8
|
import { Router, NavigationEnd, NavigationSkipped, NavigationStart, NavigationError, RouterLink } from '@angular/router';
|
|
9
9
|
import { Title, Meta, DomSanitizer } from '@angular/platform-browser';
|
|
10
10
|
import { platform, offset, flip, shift, limitShift, computePosition, autoUpdate, hide, arrow, size } from '@floating-ui/dom';
|
|
@@ -63,6 +63,9 @@ const randomId = () => {
|
|
|
63
63
|
return `et-id-${(randomIdFallbackCounter++).toString(36)}-${Date.now().toString(36)}`;
|
|
64
64
|
};
|
|
65
65
|
|
|
66
|
+
/**
|
|
67
|
+
* @deprecated Use `takeUntilDestroyed()` from `@angular/core/rxjs-interop`. `yarn nx g @ethlete/core:migrate-create-destroy` rewrites the common pattern.
|
|
68
|
+
*/
|
|
66
69
|
const createDestroy = () => {
|
|
67
70
|
assertInInjectionContext(createDestroy);
|
|
68
71
|
const destroy$ = new Subject();
|
|
@@ -91,11 +94,13 @@ const getObjectProperty = (obj, prop) => {
|
|
|
91
94
|
if (!isObject(value))
|
|
92
95
|
return undefined;
|
|
93
96
|
if (prop.includes('[')) {
|
|
94
|
-
const [key,
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
const [key, ...indexes] = prop.split('[').map((part) => part.replace(']', ''));
|
|
98
|
+
value = value[key];
|
|
99
|
+
for (const index of indexes) {
|
|
100
|
+
if (!Array.isArray(value))
|
|
101
|
+
return undefined;
|
|
102
|
+
value = value[+index];
|
|
103
|
+
}
|
|
99
104
|
}
|
|
100
105
|
else {
|
|
101
106
|
value = value[prop];
|
|
@@ -187,7 +192,8 @@ const createValueProviders = (token, defaultValue, valueOverride, options) => [
|
|
|
187
192
|
];
|
|
188
193
|
const maybeMergeValues = (defaultValue, valueOverride) => {
|
|
189
194
|
if (isObject(valueOverride) && isObject(defaultValue)) {
|
|
190
|
-
|
|
195
|
+
const definedOverride = Object.fromEntries(Object.entries(valueOverride).filter(([, value]) => value !== undefined));
|
|
196
|
+
return { ...defaultValue, ...definedOverride };
|
|
191
197
|
}
|
|
192
198
|
return valueOverride ?? defaultValue;
|
|
193
199
|
};
|
|
@@ -248,6 +254,12 @@ const applyHostListeners = (listeners, options) => {
|
|
|
248
254
|
}
|
|
249
255
|
};
|
|
250
256
|
|
|
257
|
+
function optionalBooleanAttribute(value) {
|
|
258
|
+
if (value === null || value === undefined)
|
|
259
|
+
return value;
|
|
260
|
+
return booleanAttribute(value);
|
|
261
|
+
}
|
|
262
|
+
|
|
251
263
|
class TypedQueryList extends QueryList {
|
|
252
264
|
get changes() {
|
|
253
265
|
return super.changes;
|
|
@@ -540,7 +552,7 @@ const equal = (foo, bar) => {
|
|
|
540
552
|
if (!tmp)
|
|
541
553
|
return false;
|
|
542
554
|
}
|
|
543
|
-
if (!equal(len[1], bar.get(tmp))) {
|
|
555
|
+
if (!bar.has(tmp) || !equal(len[1], bar.get(tmp))) {
|
|
544
556
|
return false;
|
|
545
557
|
}
|
|
546
558
|
}
|
|
@@ -580,6 +592,9 @@ const equal = (foo, bar) => {
|
|
|
580
592
|
return foo !== foo && bar !== bar;
|
|
581
593
|
};
|
|
582
594
|
|
|
595
|
+
// Only what a cookie value cannot hold is escaped, so base64 and JWT values stay byte-identical for
|
|
596
|
+
// servers and older readers that do not decode them.
|
|
597
|
+
const encodeCookieValue = (value) => encodeURIComponent(value).replace(/%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g, decodeURIComponent);
|
|
583
598
|
const hasCookie = (name) => {
|
|
584
599
|
if (typeof document === 'undefined') {
|
|
585
600
|
return false;
|
|
@@ -593,38 +608,63 @@ const getCookie = (name) => {
|
|
|
593
608
|
return null;
|
|
594
609
|
}
|
|
595
610
|
const cookie = document.cookie.split(';').find((entry) => entry.trim().startsWith(`${name}=`));
|
|
596
|
-
|
|
611
|
+
const raw = cookie?.trim().slice(name.length + 1);
|
|
612
|
+
if (raw === undefined)
|
|
613
|
+
return null;
|
|
614
|
+
try {
|
|
615
|
+
return decodeURIComponent(raw);
|
|
616
|
+
}
|
|
617
|
+
catch {
|
|
618
|
+
return raw;
|
|
619
|
+
}
|
|
597
620
|
};
|
|
598
|
-
const setCookie = (name, data, expiresInDays, domain
|
|
621
|
+
const setCookie = (name, data, expiresInDays, domain, path = '/', sameSite = 'lax') => {
|
|
599
622
|
if (typeof document === 'undefined') {
|
|
600
623
|
return;
|
|
601
624
|
}
|
|
625
|
+
const derivedDomain = domain === undefined;
|
|
626
|
+
const resolvedDomain = derivedDomain ? getDomain() : domain;
|
|
602
627
|
const sameSiteUpper = sameSite.toUpperCase();
|
|
603
628
|
const expires = expiresInDays ?? 30;
|
|
604
|
-
let cookieString = `${name}=${data}; path=${path}`;
|
|
629
|
+
let cookieString = `${name}=${encodeCookieValue(data)}; path=${path}`;
|
|
605
630
|
if (expiresInDays !== null) {
|
|
606
631
|
const date = new Date();
|
|
607
632
|
date.setTime(date.getTime() + expires * 24 * 60 * 60 * 1000);
|
|
608
633
|
cookieString += `; expires=${date.toUTCString()}`;
|
|
609
634
|
}
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
635
|
+
const attributes = (withDomain) => {
|
|
636
|
+
let result = cookieString;
|
|
637
|
+
if (withDomain && resolvedDomain) {
|
|
638
|
+
result += `; domain=${resolvedDomain}`;
|
|
639
|
+
}
|
|
640
|
+
return result;
|
|
641
|
+
};
|
|
642
|
+
let suffix = `; SameSite=${sameSiteUpper}`;
|
|
614
643
|
if (sameSite === 'none' || (typeof window !== 'undefined' && window.location.protocol === 'https:')) {
|
|
615
|
-
|
|
644
|
+
suffix += '; Secure';
|
|
645
|
+
}
|
|
646
|
+
suffix += ';';
|
|
647
|
+
document.cookie = attributes(true) + suffix;
|
|
648
|
+
if (derivedDomain && resolvedDomain && getCookie(name) !== data) {
|
|
649
|
+
document.cookie = attributes(false) + suffix;
|
|
616
650
|
}
|
|
617
|
-
cookieString += ';';
|
|
618
|
-
document.cookie = cookieString;
|
|
619
651
|
};
|
|
620
|
-
const deleteCookie = (name, path = '/', domain
|
|
621
|
-
if (hasCookie(name))
|
|
652
|
+
const deleteCookie = (name, path = '/', domain) => {
|
|
653
|
+
if (!hasCookie(name))
|
|
654
|
+
return;
|
|
655
|
+
const derivedDomain = domain === undefined;
|
|
656
|
+
const resolvedDomain = derivedDomain ? getDomain() : domain;
|
|
657
|
+
const expire = (withDomain) => {
|
|
622
658
|
document.cookie =
|
|
623
659
|
name +
|
|
624
660
|
'=' +
|
|
625
661
|
(path ? ';path=' + path : '') +
|
|
626
|
-
(
|
|
662
|
+
(withDomain && resolvedDomain ? ';domain=' + resolvedDomain : '') +
|
|
627
663
|
';expires=Thu, 01 Jan 1970 00:00:01 GMT';
|
|
664
|
+
};
|
|
665
|
+
expire(true);
|
|
666
|
+
if (derivedDomain && hasCookie(name)) {
|
|
667
|
+
expire(false);
|
|
628
668
|
}
|
|
629
669
|
};
|
|
630
670
|
const getDomain = () => {
|
|
@@ -646,6 +686,7 @@ const getDomain = () => {
|
|
|
646
686
|
return hostname;
|
|
647
687
|
};
|
|
648
688
|
|
|
689
|
+
/** @deprecated Keyed on the deprecated `KeyboardEvent.keyCode`. Compare `KeyboardEvent.key` instead. */
|
|
649
690
|
class KeyPressManager {
|
|
650
691
|
constructor(key) {
|
|
651
692
|
this.key = key;
|
|
@@ -1493,7 +1534,7 @@ const signalAnimatedNumber = (source, options = {}) => {
|
|
|
1493
1534
|
if (destroyed)
|
|
1494
1535
|
return;
|
|
1495
1536
|
const elapsed = timestamp - startTime;
|
|
1496
|
-
const progress = Math.min(elapsed / duration, 1);
|
|
1537
|
+
const progress = duration > 0 ? Math.min(Math.max(elapsed / duration, 0), 1) : 1;
|
|
1497
1538
|
const easedProgress = easing(progress);
|
|
1498
1539
|
const value = startValue + delta * easedProgress;
|
|
1499
1540
|
currentAnimatedValue = value;
|
|
@@ -1699,19 +1740,30 @@ const breakpointTransformBase = (coerce, defaultValue) => {
|
|
|
1699
1740
|
const injector = inject(Injector);
|
|
1700
1741
|
const raw = signal(undefined, /* @ts-ignore */
|
|
1701
1742
|
...(ngDevMode ? [{ debugName: "raw" }] : /* istanbul ignore next */ []));
|
|
1743
|
+
let warnedMissingInstance = false;
|
|
1702
1744
|
let cachedSig = null;
|
|
1703
1745
|
const transformFn = (value) => {
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1746
|
+
if (isBreakpointMap(value)) {
|
|
1747
|
+
const map = value;
|
|
1748
|
+
raw.set(map);
|
|
1749
|
+
return resolveFromMap(map, currentBp(), defaultValue);
|
|
1750
|
+
}
|
|
1751
|
+
raw.set(undefined);
|
|
1752
|
+
return coerce(value);
|
|
1707
1753
|
};
|
|
1708
1754
|
effect(() => {
|
|
1709
1755
|
const bp = currentBp();
|
|
1710
1756
|
const r = raw();
|
|
1711
1757
|
if (!cachedSig) {
|
|
1712
1758
|
const instance = injector.get(BREAKPOINT_INSTANCE_TOKEN, null);
|
|
1713
|
-
if (!instance)
|
|
1759
|
+
if (!instance) {
|
|
1760
|
+
if (ngDevMode && r !== undefined && !warnedMissingInstance) {
|
|
1761
|
+
warnedMissingInstance = true;
|
|
1762
|
+
console.warn('[ethlete] A breakpoint map was bound to an input, but its component does not call ' +
|
|
1763
|
+
'provideBreakpointInstance(), so the value will not follow the breakpoint after the first render.');
|
|
1764
|
+
}
|
|
1714
1765
|
return;
|
|
1766
|
+
}
|
|
1715
1767
|
for (const key of Object.keys(instance)) {
|
|
1716
1768
|
const val = instance[key];
|
|
1717
1769
|
if (val && typeof val === 'function' && val[SIGNAL]?.transformFn === transformFn) {
|
|
@@ -1720,7 +1772,7 @@ const breakpointTransformBase = (coerce, defaultValue) => {
|
|
|
1720
1772
|
}
|
|
1721
1773
|
}
|
|
1722
1774
|
}
|
|
1723
|
-
if (!cachedSig || r === undefined
|
|
1775
|
+
if (!cachedSig || r === undefined)
|
|
1724
1776
|
return;
|
|
1725
1777
|
const resolved = resolveFromMap(r, bp, defaultValue);
|
|
1726
1778
|
untracked(() => setInputSignal(cachedSig, resolved));
|
|
@@ -1966,14 +2018,13 @@ const signalElementChildren = (el, options) => {
|
|
|
1966
2018
|
const buildSignalEffects = (el, config) => {
|
|
1967
2019
|
const elements = buildElementSignal(el);
|
|
1968
2020
|
const injector = inject(Injector);
|
|
2021
|
+
const liveTokens = new Map(Object.entries(config.tokenMap));
|
|
1969
2022
|
effect(() => {
|
|
1970
2023
|
const { currentElements, previousElements } = elements();
|
|
1971
2024
|
for (const previousEl of previousElements) {
|
|
1972
2025
|
if (currentElements.includes(previousEl))
|
|
1973
2026
|
continue;
|
|
1974
|
-
const tokens =
|
|
1975
|
-
.map((key) => key.split(' '))
|
|
1976
|
-
.flat();
|
|
2027
|
+
const tokens = [...liveTokens.keys()].flatMap((key) => key.split(' '));
|
|
1977
2028
|
if (!tokens.length)
|
|
1978
2029
|
continue;
|
|
1979
2030
|
config.cleanupFn(previousEl, tokens);
|
|
@@ -1981,7 +2032,7 @@ const buildSignalEffects = (el, config) => {
|
|
|
1981
2032
|
for (const currentEl of currentElements) {
|
|
1982
2033
|
if (previousElements.includes(currentEl))
|
|
1983
2034
|
continue;
|
|
1984
|
-
for (const [tokens, condition] of
|
|
2035
|
+
for (const [tokens, condition] of liveTokens) {
|
|
1985
2036
|
untracked(() => {
|
|
1986
2037
|
const tokenArray = tokens.split(' ');
|
|
1987
2038
|
if (!tokenArray.length)
|
|
@@ -1996,6 +2047,7 @@ const buildSignalEffects = (el, config) => {
|
|
|
1996
2047
|
const push = (tokens, signal) => {
|
|
1997
2048
|
if (has(tokens))
|
|
1998
2049
|
return;
|
|
2050
|
+
liveTokens.set(tokens, signal);
|
|
1999
2051
|
runInInjectionContext(injector, () => {
|
|
2000
2052
|
effects[tokens] = effect(() => {
|
|
2001
2053
|
const { currentElements } = untracked(() => elements());
|
|
@@ -2017,6 +2069,7 @@ const buildSignalEffects = (el, config) => {
|
|
|
2017
2069
|
const remove = (tokens) => {
|
|
2018
2070
|
effects[tokens]?.destroy();
|
|
2019
2071
|
delete effects[tokens];
|
|
2072
|
+
liveTokens.delete(tokens);
|
|
2020
2073
|
for (const el of elements().currentElements) {
|
|
2021
2074
|
const tokenArray = tokens.split(' ');
|
|
2022
2075
|
if (!tokenArray.length)
|
|
@@ -2163,9 +2216,22 @@ const isElementVisible = (options) => {
|
|
|
2163
2216
|
intersectionRatio: Math.round(Math.min(inlineIntersectionPercentage, blockIntersectionPercentage) * 100) / 100,
|
|
2164
2217
|
};
|
|
2165
2218
|
};
|
|
2219
|
+
const nearestAlignment = (elStart, elEnd, conStart, conEnd) => {
|
|
2220
|
+
const startOutside = elStart < conStart;
|
|
2221
|
+
const endOutside = elEnd > conEnd;
|
|
2222
|
+
const fits = elEnd - elStart <= conEnd - conStart;
|
|
2223
|
+
if (startOutside === endOutside)
|
|
2224
|
+
return null;
|
|
2225
|
+
if (startOutside === fits)
|
|
2226
|
+
return 'start';
|
|
2227
|
+
return 'end';
|
|
2228
|
+
};
|
|
2166
2229
|
const getElementScrollCoordinates = (options) => {
|
|
2167
2230
|
const { container, element, direction, behavior = 'smooth', origin = 'nearest', scrollBlockMargin = 0, scrollInlineMargin = 0, } = options;
|
|
2168
|
-
if (!element ||
|
|
2231
|
+
if (!element ||
|
|
2232
|
+
!container ||
|
|
2233
|
+
(container.isConnected && !container.contains(element)) ||
|
|
2234
|
+
!elementCanScroll(container)) {
|
|
2169
2235
|
return {
|
|
2170
2236
|
behavior,
|
|
2171
2237
|
left: undefined,
|
|
@@ -2193,33 +2259,33 @@ const getElementScrollCoordinates = (options) => {
|
|
|
2193
2259
|
let scrollTopTo = scrollTop;
|
|
2194
2260
|
const relativeTop = elTop - conTop;
|
|
2195
2261
|
const relativeLeft = elLeft - conLeft;
|
|
2262
|
+
const calculateInlineStart = () => (scrollLeftTo = scrollLeft + relativeLeft - scrollInlineMargin);
|
|
2263
|
+
const calculateBlockStart = () => (scrollTopTo = scrollTop + relativeTop - scrollBlockMargin);
|
|
2264
|
+
const calculateInlineEnd = () => (scrollLeftTo = scrollLeft + relativeLeft - conWidth + elWidth + scrollInlineMargin);
|
|
2265
|
+
const calculateBlockEnd = () => (scrollTopTo = scrollTop + relativeTop - conHeight + elHeight + scrollBlockMargin);
|
|
2196
2266
|
const calculateScrollToStart = () => {
|
|
2197
|
-
|
|
2198
|
-
|
|
2267
|
+
calculateInlineStart();
|
|
2268
|
+
calculateBlockStart();
|
|
2199
2269
|
};
|
|
2200
2270
|
const calculateScrollToEnd = () => {
|
|
2201
|
-
|
|
2202
|
-
|
|
2271
|
+
calculateInlineEnd();
|
|
2272
|
+
calculateBlockEnd();
|
|
2203
2273
|
};
|
|
2204
2274
|
const calculateScrollToCenter = () => {
|
|
2205
2275
|
scrollLeftTo = scrollLeft + relativeLeft - conWidth / 2 + elWidth / 2;
|
|
2206
2276
|
scrollTopTo = scrollTop + relativeTop - conHeight / 2 + elHeight / 2;
|
|
2207
2277
|
};
|
|
2208
2278
|
const calculateScrollToNearest = () => {
|
|
2209
|
-
const
|
|
2210
|
-
const
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
if (
|
|
2218
|
-
|
|
2219
|
-
}
|
|
2220
|
-
else if (isBelow || isPartialBelow || isRight || isPartialRight) {
|
|
2221
|
-
calculateScrollToEnd();
|
|
2222
|
-
}
|
|
2279
|
+
const inline = nearestAlignment(elLeft, elRight, conLeft, conRight);
|
|
2280
|
+
const block = nearestAlignment(elTop, elBottom, conTop, conBottom);
|
|
2281
|
+
if (inline === 'start')
|
|
2282
|
+
calculateInlineStart();
|
|
2283
|
+
else if (inline === 'end')
|
|
2284
|
+
calculateInlineEnd();
|
|
2285
|
+
if (block === 'start')
|
|
2286
|
+
calculateBlockStart();
|
|
2287
|
+
else if (block === 'end')
|
|
2288
|
+
calculateBlockEnd();
|
|
2223
2289
|
};
|
|
2224
2290
|
switch (origin) {
|
|
2225
2291
|
case 'start':
|
|
@@ -2403,8 +2469,10 @@ const createPositionObject = (entry) => {
|
|
|
2403
2469
|
isVisible,
|
|
2404
2470
|
};
|
|
2405
2471
|
};
|
|
2472
|
+
const unwrap = (value) => (isSignal(value) ? value() : value);
|
|
2473
|
+
const isZeroMargin = (margin) => !margin || /^(0(px|%)?\s*)+$/.test(margin.trim());
|
|
2406
2474
|
const signalElementIntersection = (el, options) => {
|
|
2407
|
-
const { root: rootBinding, enabled, ...observerOptions } = options ?? {};
|
|
2475
|
+
const { root: rootBinding, enabled, rootMargin, threshold, ...observerOptions } = options ?? {};
|
|
2408
2476
|
const destroyRef = inject(DestroyRef);
|
|
2409
2477
|
const elements = buildElementSignal(el);
|
|
2410
2478
|
const root = firstElementSignal(rootBinding ? buildElementSignal(rootBinding) : createEmptyElementSignal());
|
|
@@ -2416,6 +2484,7 @@ const signalElementIntersection = (el, options) => {
|
|
|
2416
2484
|
const observer = signal(null, /* @ts-ignore */
|
|
2417
2485
|
...(ngDevMode ? [{ debugName: "observer" }] : /* istanbul ignore next */ []));
|
|
2418
2486
|
const currentlyObservedElements = new Set();
|
|
2487
|
+
let observedRootMargin;
|
|
2419
2488
|
const updateIntersections = (entries) => {
|
|
2420
2489
|
let currentValues = [...elementIntersectionSignal()];
|
|
2421
2490
|
for (const entry of entries) {
|
|
@@ -2445,7 +2514,7 @@ const signalElementIntersection = (el, options) => {
|
|
|
2445
2514
|
}
|
|
2446
2515
|
zone.run(() => elementIntersectionSignal.set(currentValues));
|
|
2447
2516
|
};
|
|
2448
|
-
const updateIntersectionObserver = (rendered, enabled, rootEl) => {
|
|
2517
|
+
const updateIntersectionObserver = (rendered, enabled, rootEl, margin, thresholdValue) => {
|
|
2449
2518
|
observer()?.disconnect();
|
|
2450
2519
|
currentlyObservedElements.clear();
|
|
2451
2520
|
if (!rendered || !enabled) {
|
|
@@ -2455,8 +2524,11 @@ const signalElementIntersection = (el, options) => {
|
|
|
2455
2524
|
}
|
|
2456
2525
|
const newObserver = new IntersectionObserver((entries) => updateIntersections(entries), {
|
|
2457
2526
|
...observerOptions,
|
|
2527
|
+
...(margin !== undefined && { rootMargin: margin }),
|
|
2528
|
+
...(thresholdValue !== undefined && { threshold: thresholdValue }),
|
|
2458
2529
|
root: rootEl,
|
|
2459
2530
|
});
|
|
2531
|
+
observedRootMargin = margin;
|
|
2460
2532
|
observer.set(newObserver);
|
|
2461
2533
|
};
|
|
2462
2534
|
const updateObservedElements = (observer, elements) => {
|
|
@@ -2469,15 +2541,16 @@ const signalElementIntersection = (el, options) => {
|
|
|
2469
2541
|
const newIntersectionValue = [];
|
|
2470
2542
|
for (const el of elements.currentElements) {
|
|
2471
2543
|
if (currentlyObservedElements.has(el)) {
|
|
2472
|
-
const
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
console.warn('Could not find existing entry for element. The intersection observer might be broken now.', el);
|
|
2476
|
-
continue;
|
|
2477
|
-
}
|
|
2478
|
-
newIntersectionValue.push(existingEntry);
|
|
2544
|
+
const existingEntry = currIntersectionValue.find((v) => v.target === el);
|
|
2545
|
+
if (existingEntry)
|
|
2546
|
+
newIntersectionValue.push(existingEntry);
|
|
2479
2547
|
continue;
|
|
2480
2548
|
}
|
|
2549
|
+
currentlyObservedElements.add(el);
|
|
2550
|
+
observer.observe(el);
|
|
2551
|
+
// isElementVisible ignores rootMargin, so with one set the observer's own first entry is the only correct one.
|
|
2552
|
+
if (!isZeroMargin(observedRootMargin))
|
|
2553
|
+
continue;
|
|
2481
2554
|
const initialElementVisibility = isElementVisible({
|
|
2482
2555
|
container: rootEl,
|
|
2483
2556
|
element: el,
|
|
@@ -2497,8 +2570,6 @@ const signalElementIntersection = (el, options) => {
|
|
|
2497
2570
|
...intersectionEntry,
|
|
2498
2571
|
...createPositionObject(intersectionEntry),
|
|
2499
2572
|
});
|
|
2500
|
-
currentlyObservedElements.add(el);
|
|
2501
|
-
observer.observe(el);
|
|
2502
2573
|
}
|
|
2503
2574
|
for (const el of elements.previousElements) {
|
|
2504
2575
|
if (elements.currentElements.includes(el))
|
|
@@ -2512,9 +2583,13 @@ const signalElementIntersection = (el, options) => {
|
|
|
2512
2583
|
const rootEl = root().currentElement;
|
|
2513
2584
|
const rendered = isRendered();
|
|
2514
2585
|
const enabled = isEnabled();
|
|
2515
|
-
|
|
2586
|
+
const margin = rootMargin === undefined ? undefined : unwrap(rootMargin);
|
|
2587
|
+
const thresholdValue = threshold === undefined ? undefined : unwrap(threshold);
|
|
2588
|
+
untracked(() => updateIntersectionObserver(rendered, enabled, rootEl, margin, thresholdValue));
|
|
2516
2589
|
});
|
|
2517
|
-
effect
|
|
2590
|
+
// The initial entries are measured here, not in an effect: an effect runs during change detection,
|
|
2591
|
+
// before elements rendered in the same pass have their layout.
|
|
2592
|
+
afterRenderEffect(() => {
|
|
2518
2593
|
const els = elements();
|
|
2519
2594
|
const obs = observer();
|
|
2520
2595
|
untracked(() => updateObservedElements(obs, els));
|
|
@@ -2540,6 +2615,8 @@ const signalElementLastScrollDirection = (el) => {
|
|
|
2540
2615
|
lastScrollLeft = 0;
|
|
2541
2616
|
return of(null);
|
|
2542
2617
|
}
|
|
2618
|
+
lastScrollTop = currentElement.scrollTop;
|
|
2619
|
+
lastScrollLeft = currentElement.scrollLeft;
|
|
2543
2620
|
return fromEvent(currentElement, 'scroll').pipe(tap(() => {
|
|
2544
2621
|
const { scrollTop, scrollLeft } = currentElement;
|
|
2545
2622
|
const time = Date.now();
|
|
@@ -2644,11 +2721,12 @@ const writeScrollbarSizeToCssVariables = () => {
|
|
|
2644
2721
|
if (!isPlatformBrowser(inject(PLATFORM_ID))) {
|
|
2645
2722
|
return;
|
|
2646
2723
|
}
|
|
2647
|
-
|
|
2648
|
-
|
|
2724
|
+
// The app's injector, not the caller's: a writer started from a component must outlive it.
|
|
2725
|
+
const appInjector = inject(ApplicationRef).injector;
|
|
2726
|
+
if (scrollbarSizeWriters.has(appInjector)) {
|
|
2649
2727
|
return;
|
|
2650
2728
|
}
|
|
2651
|
-
scrollbarSizeWriters.add(
|
|
2729
|
+
scrollbarSizeWriters.add(appInjector);
|
|
2652
2730
|
const document = inject(DOCUMENT);
|
|
2653
2731
|
const renderer = injectRenderer();
|
|
2654
2732
|
const scrollbarDimensions = injectScrollbarDimensions();
|
|
@@ -2660,7 +2738,7 @@ const writeScrollbarSizeToCssVariables = () => {
|
|
|
2660
2738
|
'--et-sw': `${dimensions.width}px`,
|
|
2661
2739
|
'--et-sh': `${dimensions.height}px`,
|
|
2662
2740
|
});
|
|
2663
|
-
});
|
|
2741
|
+
}, { injector: appInjector });
|
|
2664
2742
|
};
|
|
2665
2743
|
const viewportSizeWriters = /* @__PURE__ */ new WeakSet();
|
|
2666
2744
|
/**
|
|
@@ -2672,11 +2750,11 @@ const writeViewportSizeToCssVariables = () => {
|
|
|
2672
2750
|
if (!isPlatformBrowser(inject(PLATFORM_ID))) {
|
|
2673
2751
|
return;
|
|
2674
2752
|
}
|
|
2675
|
-
const
|
|
2676
|
-
if (viewportSizeWriters.has(
|
|
2753
|
+
const appInjector = inject(ApplicationRef).injector;
|
|
2754
|
+
if (viewportSizeWriters.has(appInjector)) {
|
|
2677
2755
|
return;
|
|
2678
2756
|
}
|
|
2679
|
-
viewportSizeWriters.add(
|
|
2757
|
+
viewportSizeWriters.add(appInjector);
|
|
2680
2758
|
const document = inject(DOCUMENT);
|
|
2681
2759
|
const renderer = injectRenderer();
|
|
2682
2760
|
const htmlElementDimensions = injectViewportDimensions();
|
|
@@ -2688,7 +2766,7 @@ const writeViewportSizeToCssVariables = () => {
|
|
|
2688
2766
|
'--et-vw': `${dimensions.width}px`,
|
|
2689
2767
|
'--et-vh': `${dimensions.height}px`,
|
|
2690
2768
|
});
|
|
2691
|
-
});
|
|
2769
|
+
}, { injector: appInjector });
|
|
2692
2770
|
};
|
|
2693
2771
|
|
|
2694
2772
|
/** The deadzone in pixels after which the cursor drag scroll will take effect. */
|
|
@@ -2876,7 +2954,8 @@ const createInitialRoute = () => {
|
|
|
2876
2954
|
if (!isBrowser) {
|
|
2877
2955
|
return router.url;
|
|
2878
2956
|
}
|
|
2879
|
-
|
|
2957
|
+
const path = inject(Location).path(true);
|
|
2958
|
+
return path.startsWith('/') ? path : `/${path}`;
|
|
2880
2959
|
};
|
|
2881
2960
|
/** Inject the current router event */
|
|
2882
2961
|
const injectRouterEvent = /* @__PURE__ */ memoizeSignal(() => {
|
|
@@ -2943,6 +3022,7 @@ const injectRoute = /* @__PURE__ */ memoizeSignal(() => {
|
|
|
2943
3022
|
return withoutFragment;
|
|
2944
3023
|
});
|
|
2945
3024
|
});
|
|
3025
|
+
const withInjector = (config, fn) => config?.injector ? runInInjectionContext(config.injector, fn) : fn();
|
|
2946
3026
|
const createRouterState = (router) => {
|
|
2947
3027
|
let route = router.routerState.snapshot.root;
|
|
2948
3028
|
while (route.firstChild) {
|
|
@@ -2982,37 +3062,35 @@ const injectRouterState = /* @__PURE__ */ memoizeSignal(() => {
|
|
|
2982
3062
|
});
|
|
2983
3063
|
/** Inject a signal containing the current route fragment (the part after the # inside the url if present) */
|
|
2984
3064
|
const injectFragment = (config) => {
|
|
2985
|
-
const routerState = config
|
|
2986
|
-
? runInInjectionContext(config.injector, injectRouterState)
|
|
2987
|
-
: injectRouterState();
|
|
3065
|
+
const routerState = withInjector(config, injectRouterState);
|
|
2988
3066
|
const fragment = computed(() => routerState().fragment, /* @ts-ignore */
|
|
2989
3067
|
...(ngDevMode ? [{ debugName: "fragment" }] : /* istanbul ignore next */ []));
|
|
2990
3068
|
return transformOrReturn(fragment, config);
|
|
2991
3069
|
};
|
|
2992
3070
|
/** Inject all currently available query parameters as a signal */
|
|
2993
|
-
const injectQueryParams = () => {
|
|
2994
|
-
const routerState = injectRouterState
|
|
3071
|
+
const injectQueryParams = (config) => {
|
|
3072
|
+
const routerState = withInjector(config, injectRouterState);
|
|
2995
3073
|
const queryParams = computed(() => routerState().queryParams, /* @ts-ignore */
|
|
2996
3074
|
...(ngDevMode ? [{ debugName: "queryParams" }] : /* istanbul ignore next */ []));
|
|
2997
3075
|
return queryParams;
|
|
2998
3076
|
};
|
|
2999
3077
|
/** Inject all currently available route data as a signal */
|
|
3000
|
-
const injectRouteData = () => {
|
|
3001
|
-
const routerState = injectRouterState
|
|
3078
|
+
const injectRouteData = (config) => {
|
|
3079
|
+
const routerState = withInjector(config, injectRouterState);
|
|
3002
3080
|
const data = computed(() => routerState().data, /* @ts-ignore */
|
|
3003
3081
|
...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
|
|
3004
3082
|
return data;
|
|
3005
3083
|
};
|
|
3006
3084
|
/** Inject the current route title as a signal */
|
|
3007
3085
|
const injectRouteTitle = (config) => {
|
|
3008
|
-
const routerState = injectRouterState
|
|
3086
|
+
const routerState = withInjector(config, injectRouterState);
|
|
3009
3087
|
const title = computed(() => routerState().title, /* @ts-ignore */
|
|
3010
3088
|
...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
|
|
3011
3089
|
return transformOrReturn(title, config);
|
|
3012
3090
|
};
|
|
3013
3091
|
/** Inject all currently available path parameters as a signal */
|
|
3014
|
-
const injectPathParams = () => {
|
|
3015
|
-
const routerState = injectRouterState
|
|
3092
|
+
const injectPathParams = (config) => {
|
|
3093
|
+
const routerState = withInjector(config, injectRouterState);
|
|
3016
3094
|
const pathParams = computed(() => routerState().pathParams, /* @ts-ignore */
|
|
3017
3095
|
...(ngDevMode ? [{ debugName: "pathParams" }] : /* istanbul ignore next */ []));
|
|
3018
3096
|
return pathParams;
|
|
@@ -3023,21 +3101,48 @@ const getQueryParamFromUrl = (key) => {
|
|
|
3023
3101
|
const urlParams = new URLSearchParams(window.location.search);
|
|
3024
3102
|
return urlParams.get(key);
|
|
3025
3103
|
};
|
|
3026
|
-
|
|
3104
|
+
const getAllQueryParamsFromUrl = (key) => {
|
|
3105
|
+
if (typeof window === 'undefined')
|
|
3106
|
+
return [];
|
|
3107
|
+
return new URLSearchParams(window.location.search).getAll(key);
|
|
3108
|
+
};
|
|
3109
|
+
const toValues = (value) => {
|
|
3110
|
+
if (value === undefined || value === null)
|
|
3111
|
+
return [];
|
|
3112
|
+
return Array.isArray(value) ? value : [value];
|
|
3113
|
+
};
|
|
3114
|
+
/**
|
|
3115
|
+
* Inject a specific query parameter as a signal. A repeated parameter (`?tag=a&tag=b`) resolves to its first value;
|
|
3116
|
+
* use `injectQueryParamAll` to read every value.
|
|
3117
|
+
*/
|
|
3027
3118
|
const injectQueryParam = (key, config) => {
|
|
3028
|
-
const queryParams = injectQueryParams();
|
|
3029
|
-
const src = computed(() =>
|
|
3119
|
+
const queryParams = injectQueryParams(config);
|
|
3120
|
+
const src = computed(() => {
|
|
3121
|
+
const first = toValues(queryParams()[key])[0];
|
|
3122
|
+
return first ?? (config?.requireSync ? getQueryParamFromUrl(key) : null);
|
|
3123
|
+
}, /* @ts-ignore */
|
|
3124
|
+
...(ngDevMode ? [{ debugName: "src" }] : /* istanbul ignore next */ []));
|
|
3125
|
+
return transformOrReturn(src, config);
|
|
3126
|
+
};
|
|
3127
|
+
/** Inject every value of a specific query parameter as a signal. Resolves to an empty array when it is absent. */
|
|
3128
|
+
const injectQueryParamAll = (key, config) => {
|
|
3129
|
+
const queryParams = injectQueryParams(config);
|
|
3130
|
+
const src = computed(() => {
|
|
3131
|
+
const values = toValues(queryParams()[key]);
|
|
3132
|
+
return values.length || !config?.requireSync ? values : getAllQueryParamsFromUrl(key);
|
|
3133
|
+
}, /* @ts-ignore */
|
|
3134
|
+
...(ngDevMode ? [{ debugName: "src" }] : /* istanbul ignore next */ []));
|
|
3030
3135
|
return transformOrReturn(src, config);
|
|
3031
3136
|
};
|
|
3032
3137
|
/** Inject a specific route data item as a signal */
|
|
3033
3138
|
const injectRouteDataItem = (key, config) => {
|
|
3034
|
-
const data = injectRouteData();
|
|
3139
|
+
const data = injectRouteData(config);
|
|
3035
3140
|
const src = computed(() => data()[key] ?? null);
|
|
3036
3141
|
return transformOrReturn(src, config);
|
|
3037
3142
|
};
|
|
3038
3143
|
/** Inject a specific path parameter as a signal */
|
|
3039
3144
|
const injectPathParam = (key, config) => {
|
|
3040
|
-
const pathParams = injectPathParams();
|
|
3145
|
+
const pathParams = injectPathParams(config);
|
|
3041
3146
|
const src = computed(() => pathParams()[key] ?? null);
|
|
3042
3147
|
return transformOrReturn(src, config);
|
|
3043
3148
|
};
|
|
@@ -3110,9 +3215,9 @@ const injectPathParamChanges = /* @__PURE__ */ memoizeSignal(() => {
|
|
|
3110
3215
|
* protected cameFromCart = this.navState?.fromCart ?? false;
|
|
3111
3216
|
* }
|
|
3112
3217
|
*/
|
|
3113
|
-
const injectRouterNavigationState = () => {
|
|
3114
|
-
const router = inject(Router);
|
|
3115
|
-
return router.
|
|
3218
|
+
const injectRouterNavigationState = (config) => {
|
|
3219
|
+
const router = withInjector(config, () => inject(Router));
|
|
3220
|
+
return router.currentNavigation()?.extras.state ?? null;
|
|
3116
3221
|
};
|
|
3117
3222
|
|
|
3118
3223
|
const ET_DISABLE_SCROLL_TOP = /* @__PURE__ */ Symbol('ET_DISABLE_SCROLL_TOP');
|
|
@@ -3341,7 +3446,7 @@ const setupScrollRestoration = (config = {}) => {
|
|
|
3341
3446
|
// Read off the navigation rather than `history.state`: a symbol key does not survive being
|
|
3342
3447
|
// structured-cloned into the history entry, which is what keeps the mark from outliving this
|
|
3343
3448
|
// navigation and re-firing when the user later pops back to the entry it created.
|
|
3344
|
-
const navigationState = router.
|
|
3449
|
+
const navigationState = router.currentNavigation()?.extras.state;
|
|
3345
3450
|
wantsRestore = !isPopstate && navigationState?.[ET_RESTORE_SCROLL] === true;
|
|
3346
3451
|
};
|
|
3347
3452
|
const onNavigationEnd = (event) => {
|
|
@@ -3434,7 +3539,7 @@ const setupScrollRestoration = (config = {}) => {
|
|
|
3434
3539
|
const DISABLE_LOGGER_PARAM = 'et-logger-quiet';
|
|
3435
3540
|
const createLogger = (config) => {
|
|
3436
3541
|
const { scope, feature } = config;
|
|
3437
|
-
const disableLogging = injectQueryParam(DISABLE_LOGGER_PARAM);
|
|
3542
|
+
const disableLogging = injectQueryParam(DISABLE_LOGGER_PARAM, { transform: (value) => value !== null });
|
|
3438
3543
|
return {
|
|
3439
3544
|
log: (...args) => {
|
|
3440
3545
|
if (!disableLogging())
|
|
@@ -3465,9 +3570,10 @@ const escapeHtmlPreservingEntities = (str) => str
|
|
|
3465
3570
|
* text only. */
|
|
3466
3571
|
const MARKDOWN_VERBATIM_ATTR = 'data-markdown-verbatim';
|
|
3467
3572
|
const VERBATIM_RE = /* @__PURE__ */ new RegExp(`<span\\b[^>]*\\b${MARKDOWN_VERBATIM_ATTR}\\b[^>]*>([^<]*)<\\/span>`, 'gi');
|
|
3573
|
+
const codePointToString = (codePoint) => (codePoint <= 0x10ffff ? String.fromCodePoint(codePoint) : '\ufffd');
|
|
3468
3574
|
const decodeUrlCharacterReferences = (url) => url
|
|
3469
|
-
.replace(/&#(\d+);?/g, (_, value) =>
|
|
3470
|
-
.replace(/&#x([0-9a-f]+);?/gi, (_, value) =>
|
|
3575
|
+
.replace(/&#(\d+);?/g, (_, value) => codePointToString(Number(value)))
|
|
3576
|
+
.replace(/&#x([0-9a-f]+);?/gi, (_, value) => codePointToString(Number.parseInt(value, 16)))
|
|
3471
3577
|
.replace(/&(colon|tab|newline);/gi, (_, entity) => entity.toLowerCase() === 'colon' ? ':' : entity.toLowerCase() === 'tab' ? '\t' : '\n');
|
|
3472
3578
|
/** Whether `url` may be embedded as an image `src`: everything except `javascript:` and `vbscript:`
|
|
3473
3579
|
* URLs and non-image `data:` URLs, however they are cased, spaced or entity-encoded. */
|
|
@@ -3584,6 +3690,10 @@ const processInline = (text) => {
|
|
|
3584
3690
|
.replace(placeholderRe('IC'), (match, i) => inlineCodes[+i] ?? match)
|
|
3585
3691
|
.replace(placeholderRe('ESC'), (match, i) => escapes[+i] ?? match);
|
|
3586
3692
|
};
|
|
3693
|
+
const parseStartNumber = (openTag) => {
|
|
3694
|
+
const value = /\bstart\s*=\s*["']?(-?\d+)/i.exec(openTag)?.[1];
|
|
3695
|
+
return value === undefined ? 1 : Number(value);
|
|
3696
|
+
};
|
|
3587
3697
|
/** The first top-level `<ul>`/`<ol>` in `html`, matched with balanced nesting. */
|
|
3588
3698
|
const findList = (html) => {
|
|
3589
3699
|
const open = /<(ul|ol)\b[^>]*>/i.exec(html);
|
|
@@ -3602,6 +3712,7 @@ const findList = (html) => {
|
|
|
3602
3712
|
start: open.index,
|
|
3603
3713
|
end: tag.lastIndex,
|
|
3604
3714
|
ordered: openTagName.toLowerCase() === 'ol',
|
|
3715
|
+
startNumber: parseStartNumber(open[0]),
|
|
3605
3716
|
inner: html.slice(innerStart, match.index),
|
|
3606
3717
|
};
|
|
3607
3718
|
}
|
|
@@ -3701,15 +3812,15 @@ const buildBlockquoteHtml = (lines) => {
|
|
|
3701
3812
|
return `<blockquote>${html || '<br>'}</blockquote>`;
|
|
3702
3813
|
};
|
|
3703
3814
|
/** Serializes a list's inner HTML to Markdown, indenting nested lists two spaces per level. */
|
|
3704
|
-
const listToMarkdown = (inner, ordered, depth) => {
|
|
3815
|
+
const listToMarkdown = (inner, ordered, startNumber, depth) => {
|
|
3705
3816
|
const indent = ' '.repeat(depth);
|
|
3706
|
-
let n =
|
|
3817
|
+
let n = startNumber;
|
|
3707
3818
|
return findListItems(inner)
|
|
3708
3819
|
.map((itemInner) => {
|
|
3709
3820
|
let content = itemInner;
|
|
3710
3821
|
let nestedMarkdown = '';
|
|
3711
3822
|
for (let nested = findList(content); nested; nested = findList(content)) {
|
|
3712
|
-
nestedMarkdown += `\n${listToMarkdown(nested.inner, nested.ordered, depth + 1)}`;
|
|
3823
|
+
nestedMarkdown += `\n${listToMarkdown(nested.inner, nested.ordered, nested.startNumber, depth + 1)}`;
|
|
3713
3824
|
content = content.slice(0, nested.start) + content.slice(nested.end);
|
|
3714
3825
|
}
|
|
3715
3826
|
const marker = ordered ? `${n++}. ` : '- ';
|
|
@@ -3723,7 +3834,12 @@ const parseListLines = (lines) => lines
|
|
|
3723
3834
|
.map((line) => {
|
|
3724
3835
|
const match = /^(\s*)([-*+]|\d+\.)\s+(.*)$/.exec(line);
|
|
3725
3836
|
return match
|
|
3726
|
-
? {
|
|
3837
|
+
? {
|
|
3838
|
+
indent: Math.floor((match[1] ?? '').length / 2),
|
|
3839
|
+
ordered: /\d/.test(match[2] ?? ''),
|
|
3840
|
+
number: Number.parseInt(match[2] ?? '', 10),
|
|
3841
|
+
text: match[3] ?? '',
|
|
3842
|
+
}
|
|
3727
3843
|
: null;
|
|
3728
3844
|
})
|
|
3729
3845
|
.filter((line) => line !== null);
|
|
@@ -3744,7 +3860,9 @@ const buildListHtml = (lines, start, baseIndent) => {
|
|
|
3744
3860
|
items += `<li>${item}</li>`;
|
|
3745
3861
|
}
|
|
3746
3862
|
const tag = ordered ? 'ol' : 'ul';
|
|
3747
|
-
|
|
3863
|
+
const startNumber = ordered ? (lines[start]?.number ?? 1) : 1;
|
|
3864
|
+
const startAttr = startNumber === 1 ? '' : ` start="${startNumber}"`;
|
|
3865
|
+
return { html: `<${tag}${startAttr}>${items}</${tag}>`, next: i };
|
|
3748
3866
|
};
|
|
3749
3867
|
const escapeMarkdownText = (text) => text
|
|
3750
3868
|
.replace(/[\\`[\]]/g, '\\$&')
|
|
@@ -3938,7 +4056,7 @@ const htmlToMarkdown = (html) => {
|
|
|
3938
4056
|
}
|
|
3939
4057
|
// Lists - replace each top-level list with its recursively-serialized Markdown (handles nesting).
|
|
3940
4058
|
for (let list = findList(md); list; list = findList(md)) {
|
|
3941
|
-
md = `${md.slice(0, list.start)}\n${listToMarkdown(list.inner, list.ordered, 0)}\n${md.slice(list.end)}`;
|
|
4059
|
+
md = `${md.slice(0, list.start)}\n${listToMarkdown(list.inner, list.ordered, list.startNumber, 0)}\n${md.slice(list.end)}`;
|
|
3942
4060
|
}
|
|
3943
4061
|
// Tables
|
|
3944
4062
|
md = md.replace(/<table[^>]*>([\s\S]*?)<\/table>/gi, (_, tableContent) => {
|
|
@@ -4536,6 +4654,22 @@ const createUserConsentProvider = (options) => ({
|
|
|
4536
4654
|
}),
|
|
4537
4655
|
});
|
|
4538
4656
|
|
|
4657
|
+
/**
|
|
4658
|
+
* Declares the `et-visually-hidden` class as a styles-only component: content that stays in the
|
|
4659
|
+
* accessibility tree but is clipped out of the layout. Mount it from any component whose template
|
|
4660
|
+
* uses the class.
|
|
4661
|
+
*/
|
|
4662
|
+
class VisuallyHiddenStylesComponent {
|
|
4663
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: VisuallyHiddenStylesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4664
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.6", type: VisuallyHiddenStylesComponent, isStandalone: true, selector: "et-visually-hidden-styles", ngImport: i0, template: '', isInline: true, styles: ["@layer components{.et-visually-hidden{position:absolute;inline-size:1px;block-size:1px;margin:-1px;padding:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}}\n"], encapsulation: i0.ViewEncapsulation.None }); }
|
|
4665
|
+
}
|
|
4666
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: VisuallyHiddenStylesComponent, decorators: [{
|
|
4667
|
+
type: Component,
|
|
4668
|
+
args: [{ selector: 'et-visually-hidden-styles', template: '', encapsulation: ViewEncapsulation.None, styles: ["@layer components{.et-visually-hidden{position:absolute;inline-size:1px;block-size:1px;margin:-1px;padding:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}}\n"] }]
|
|
4669
|
+
}] });
|
|
4670
|
+
/** Mounts {@link VisuallyHiddenStylesComponent}. Call from an injection context. */
|
|
4671
|
+
const mountVisuallyHidden = () => injectStyleManager().mount(VisuallyHiddenStylesComponent);
|
|
4672
|
+
|
|
4539
4673
|
/**
|
|
4540
4674
|
* Declares the `--ease-*` custom properties that every animated stylesheet in the SDK
|
|
4541
4675
|
* transitions with, as a styles-only component. Mount it from any component or directive whose
|
|
@@ -4670,6 +4804,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
|
|
|
4670
4804
|
}]
|
|
4671
4805
|
}], ctorParameters: () => [] });
|
|
4672
4806
|
|
|
4807
|
+
// codes 9000-9099
|
|
4808
|
+
const ANIMATION_ERROR_CODES = {
|
|
4809
|
+
/** `*etAnimatedIf` was used without an `[etAnimatedLifecycle]` element around it. */
|
|
4810
|
+
MISSING_ANIMATED_LIFECYCLE: 9000,
|
|
4811
|
+
};
|
|
4812
|
+
|
|
4673
4813
|
/** Runs `cb` two frames from now. Returns a function that cancels it if it has not run yet. */
|
|
4674
4814
|
const nextFrame = (cb) => {
|
|
4675
4815
|
if (typeof requestAnimationFrame === 'undefined') {
|
|
@@ -4729,7 +4869,12 @@ class AnimatedLifecycleDirective {
|
|
|
4729
4869
|
this.transitionIdCounter = 0;
|
|
4730
4870
|
this.forcedThisFrame = false;
|
|
4731
4871
|
this.forcedFrameResetId = null;
|
|
4732
|
-
this.
|
|
4872
|
+
this.stateSubject$ = new BehaviorSubject('init');
|
|
4873
|
+
this._state = signal('init', /* @ts-ignore */
|
|
4874
|
+
...(ngDevMode ? [{ debugName: "_state" }] : /* istanbul ignore next */ []));
|
|
4875
|
+
this.state = this._state.asReadonly();
|
|
4876
|
+
/** Emits the current lifecycle state synchronously on subscribe, then every change. */
|
|
4877
|
+
this.state$ = this.stateSubject$.asObservable();
|
|
4733
4878
|
this.stateChange = outputFromObservable(this.state$);
|
|
4734
4879
|
this.skipNextEnter = model(false, /* @ts-ignore */
|
|
4735
4880
|
...(ngDevMode ? [{ debugName: "skipNextEnter" }] : /* istanbul ignore next */ []));
|
|
@@ -4752,7 +4897,7 @@ class AnimatedLifecycleDirective {
|
|
|
4752
4897
|
this.isConstructed = true;
|
|
4753
4898
|
}
|
|
4754
4899
|
enter() {
|
|
4755
|
-
const currentState = this.state
|
|
4900
|
+
const currentState = this.state();
|
|
4756
4901
|
if (currentState === 'entering')
|
|
4757
4902
|
return;
|
|
4758
4903
|
if ((currentState === 'init' && !this.isConstructed) || this.skipNextEnter()) {
|
|
@@ -4822,7 +4967,7 @@ class AnimatedLifecycleDirective {
|
|
|
4822
4967
|
previousCancel$.complete();
|
|
4823
4968
|
}
|
|
4824
4969
|
leave() {
|
|
4825
|
-
const currentState = this.state
|
|
4970
|
+
const currentState = this.state();
|
|
4826
4971
|
if (currentState === 'leaving')
|
|
4827
4972
|
return;
|
|
4828
4973
|
if (currentState === 'init') {
|
|
@@ -4923,11 +5068,11 @@ class AnimatedLifecycleDirective {
|
|
|
4923
5068
|
this.addClass(activeClass);
|
|
4924
5069
|
fromNextFrame()
|
|
4925
5070
|
.pipe(tap(() => {
|
|
4926
|
-
if (this.state
|
|
5071
|
+
if (this.state() === expectedState) {
|
|
4927
5072
|
this.removeClass(fromClass);
|
|
4928
5073
|
this.addClass(toClass);
|
|
4929
5074
|
}
|
|
4930
|
-
}), switchMap(() => this.whenAnimationsSettled()), tap(() => this.debugLog(`${transitionId}: settled`)), filter(() => this.state
|
|
5075
|
+
}), switchMap(() => this.whenAnimationsSettled()), tap(() => this.debugLog(`${transitionId}: settled`)), filter(() => this.state() === expectedState), tap(onComplete), take(1), takeUntil(cancelSignal), takeUntilDestroyed(this.destroyRef))
|
|
4931
5076
|
.subscribe();
|
|
4932
5077
|
}
|
|
4933
5078
|
handleInterruptedTransition(config) {
|
|
@@ -4935,7 +5080,7 @@ class AnimatedLifecycleDirective {
|
|
|
4935
5080
|
this.removeClasses(...removeClasses);
|
|
4936
5081
|
addClasses.forEach((cls) => this.addClass(cls));
|
|
4937
5082
|
this.whenAnimationsSettled()
|
|
4938
|
-
.pipe(tap(() => this.debugLog(`${transitionId}: interrupt settled`)), filter(() => this.state
|
|
5083
|
+
.pipe(tap(() => this.debugLog(`${transitionId}: interrupt settled`)), filter(() => this.state() === expectedState), tap(onComplete), take(1), takeUntil(cancelSignal), takeUntilDestroyed(this.destroyRef))
|
|
4939
5084
|
.subscribe();
|
|
4940
5085
|
}
|
|
4941
5086
|
/**
|
|
@@ -4970,8 +5115,9 @@ class AnimatedLifecycleDirective {
|
|
|
4970
5115
|
this.renderer.removeClass(this.element, ...classNames);
|
|
4971
5116
|
}
|
|
4972
5117
|
updateState(newState) {
|
|
4973
|
-
this.debugLog(`state: ${this.state
|
|
4974
|
-
this.
|
|
5118
|
+
this.debugLog(`state: ${this.state()} → ${newState}`);
|
|
5119
|
+
this._state.set(newState);
|
|
5120
|
+
this.stateSubject$.next(newState);
|
|
4975
5121
|
}
|
|
4976
5122
|
debugLog(message, data) {
|
|
4977
5123
|
const el = this.element;
|
|
@@ -5011,27 +5157,38 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
|
|
|
5011
5157
|
|
|
5012
5158
|
const ANIMATED_IF_TOKEN = new InjectionToken('ANIMATED_IF_TOKEN');
|
|
5013
5159
|
class AnimatedIfDirective {
|
|
5160
|
+
static ngTemplateContextGuard(_dir, _ctx) {
|
|
5161
|
+
return true;
|
|
5162
|
+
}
|
|
5014
5163
|
constructor() {
|
|
5015
5164
|
this.templateRef = inject(TemplateRef);
|
|
5016
5165
|
this.viewContainerRef = inject(ViewContainerRef);
|
|
5017
|
-
this.animatedLifecycle = inject(ANIMATED_LIFECYCLE_TOKEN);
|
|
5166
|
+
this.animatedLifecycle = inject(ANIMATED_LIFECYCLE_TOKEN, { optional: true });
|
|
5018
5167
|
this.hasView = false;
|
|
5168
|
+
this.context = { $implicit: null, etAnimatedIf: null };
|
|
5019
5169
|
this.ifValue = input(null, { ...(ngDevMode ? { debugName: "ifValue" } : /* istanbul ignore next */ {}), alias: 'etAnimatedIf' });
|
|
5170
|
+
const animatedLifecycle = this.animatedLifecycle;
|
|
5171
|
+
if (!animatedLifecycle) {
|
|
5172
|
+
throw new RuntimeError(ANIMATION_ERROR_CODES.MISSING_ANIMATED_LIFECYCLE, '*etAnimatedIf needs an element with [etAnimatedLifecycle] around it to animate against.');
|
|
5173
|
+
}
|
|
5020
5174
|
toObservable(this.ifValue)
|
|
5021
5175
|
.pipe(switchMap((value) => {
|
|
5022
5176
|
if (value) {
|
|
5177
|
+
this.context.$implicit = value;
|
|
5178
|
+
this.context.etAnimatedIf = value;
|
|
5023
5179
|
if (!this.hasView) {
|
|
5024
|
-
this.viewContainerRef.createEmbeddedView(this.templateRef);
|
|
5180
|
+
this.viewContainerRef.createEmbeddedView(this.templateRef, this.context);
|
|
5025
5181
|
this.hasView = true;
|
|
5026
5182
|
}
|
|
5027
|
-
|
|
5183
|
+
if (animatedLifecycle.state() !== 'entered')
|
|
5184
|
+
animatedLifecycle.enter();
|
|
5028
5185
|
return of(null);
|
|
5029
5186
|
}
|
|
5030
5187
|
if (!this.hasView) {
|
|
5031
5188
|
return of(null);
|
|
5032
5189
|
}
|
|
5033
|
-
|
|
5034
|
-
return
|
|
5190
|
+
animatedLifecycle.leave();
|
|
5191
|
+
return animatedLifecycle.state$.pipe(filter((state) => state === 'left'), take(1), tap(() => {
|
|
5035
5192
|
this.viewContainerRef.clear();
|
|
5036
5193
|
this.hasView = false;
|
|
5037
5194
|
}));
|
|
@@ -5207,6 +5364,23 @@ const createFlipAnimation = (config) => {
|
|
|
5207
5364
|
};
|
|
5208
5365
|
};
|
|
5209
5366
|
|
|
5367
|
+
/** The confirm an unsaved-changes tracker or guard runs when its own config has none. */
|
|
5368
|
+
const UNSAVED_CHANGES_CONFIRM = /* @__PURE__ */ new InjectionToken('UNSAVED_CHANGES_CONFIRM');
|
|
5369
|
+
/**
|
|
5370
|
+
* Sets the confirm every unsaved-changes tracker and guard below this injector runs when its config has no
|
|
5371
|
+
* `confirm`. `factory` runs once, in an injection context, and returns the confirm.
|
|
5372
|
+
*
|
|
5373
|
+
* @example
|
|
5374
|
+
* provideUnsavedChangesConfirm(() => {
|
|
5375
|
+
* const dialogs = inject(MyDialogs);
|
|
5376
|
+
* return () => dialogs.confirmDiscard();
|
|
5377
|
+
* });
|
|
5378
|
+
*/
|
|
5379
|
+
const provideUnsavedChangesConfirm = (factory) => ({
|
|
5380
|
+
provide: UNSAVED_CHANGES_CONFIRM,
|
|
5381
|
+
useFactory: factory,
|
|
5382
|
+
});
|
|
5383
|
+
|
|
5210
5384
|
const UNSAVED_CHANGES_COORDINATOR_DEF = /* @__PURE__ */ defineRootProvider(() => {
|
|
5211
5385
|
const _registrations = signal([], /* @ts-ignore */
|
|
5212
5386
|
...(ngDevMode ? [{ debugName: "_registrations" }] : /* istanbul ignore next */ []));
|
|
@@ -5290,6 +5464,11 @@ const UNSAVED_CHANGES_COORDINATOR_DEF = /* @__PURE__ */ defineRootProvider(() =>
|
|
|
5290
5464
|
const provideUnsavedChangesCoordinator = /* @__PURE__ */ toProvideFn(UNSAVED_CHANGES_COORDINATOR_DEF);
|
|
5291
5465
|
const injectUnsavedChangesCoordinator = /* @__PURE__ */ toInjectFn(UNSAVED_CHANGES_COORDINATOR_DEF);
|
|
5292
5466
|
|
|
5467
|
+
const UNSAVED_CHANGES_ERROR_CODES = {
|
|
5468
|
+
/** An unsaved-changes tracker or guard has no `confirm`, and no `provideUnsavedChangesConfirm()` is in scope. */
|
|
5469
|
+
MISSING_CONFIRM: 9100,
|
|
5470
|
+
};
|
|
5471
|
+
|
|
5293
5472
|
const isAbstractControl = (value) => !!value &&
|
|
5294
5473
|
typeof value === 'object' &&
|
|
5295
5474
|
typeof value.getRawValue === 'function' &&
|
|
@@ -5313,22 +5492,25 @@ const normalizeUnsavedChangesSource = (source) => {
|
|
|
5313
5492
|
const peek = untracked(source);
|
|
5314
5493
|
// A signal that currently holds a FieldTree - or nothing yet (the late/async form case).
|
|
5315
5494
|
if (peek === null || peek === undefined || isFieldTree(peek)) {
|
|
5316
|
-
const
|
|
5495
|
+
const lateSource = source;
|
|
5317
5496
|
return {
|
|
5318
5497
|
value: computed(() => {
|
|
5319
|
-
const
|
|
5320
|
-
|
|
5498
|
+
const current = lateSource();
|
|
5499
|
+
if (isFieldTree(current))
|
|
5500
|
+
return current().value();
|
|
5501
|
+
return (current ?? null);
|
|
5321
5502
|
}),
|
|
5322
5503
|
setValue: (next) => {
|
|
5323
|
-
const
|
|
5324
|
-
if (isFieldTree(
|
|
5325
|
-
|
|
5504
|
+
const current = untracked(lateSource);
|
|
5505
|
+
if (isFieldTree(current)) {
|
|
5506
|
+
current().value.set(next);
|
|
5507
|
+
}
|
|
5508
|
+
else if (current !== null && current !== undefined && 'set' in source) {
|
|
5509
|
+
source.set(next);
|
|
5326
5510
|
}
|
|
5327
5511
|
},
|
|
5328
5512
|
};
|
|
5329
5513
|
}
|
|
5330
|
-
// A plain writable value signal (escape hatch). Initialize it with a non-null value so it isn't
|
|
5331
|
-
// mistaken for a late FieldTree source above.
|
|
5332
5514
|
const writable = source;
|
|
5333
5515
|
return { value: writable, setValue: (next) => writable.set(next) };
|
|
5334
5516
|
}
|
|
@@ -5497,6 +5679,7 @@ const FAVICON_STORE_DEF = /* @__PURE__ */ defineRootProvider(() => {
|
|
|
5497
5679
|
}
|
|
5498
5680
|
return new Promise((resolve) => {
|
|
5499
5681
|
const image = new Image();
|
|
5682
|
+
image.crossOrigin = 'anonymous';
|
|
5500
5683
|
image.onload = () => {
|
|
5501
5684
|
baseImage = image;
|
|
5502
5685
|
resolve(image);
|
|
@@ -6488,12 +6671,12 @@ const createUnsavedChangesTabLock = (config) => {
|
|
|
6488
6671
|
return { destroy };
|
|
6489
6672
|
};
|
|
6490
6673
|
|
|
6491
|
-
const toBooleanPromise = (result) => {
|
|
6674
|
+
const toBooleanPromise = (result, signal) => {
|
|
6492
6675
|
if (result instanceof Promise) {
|
|
6493
6676
|
return result.then(Boolean);
|
|
6494
6677
|
}
|
|
6495
6678
|
if (isObservable(result)) {
|
|
6496
|
-
return firstValueFrom(result.pipe(take(1), map(Boolean), defaultIfEmpty(false), catchError(() => of(false))));
|
|
6679
|
+
return firstValueFrom(result.pipe(take(1), map(Boolean), takeUntil(fromEvent(signal, 'abort')), defaultIfEmpty(false), catchError(() => of(false))));
|
|
6497
6680
|
}
|
|
6498
6681
|
return Promise.resolve(Boolean(result));
|
|
6499
6682
|
};
|
|
@@ -6514,7 +6697,11 @@ const toBooleanPromise = (result) => {
|
|
|
6514
6697
|
*/
|
|
6515
6698
|
const createUnsavedChangesTracker = (config) => {
|
|
6516
6699
|
assertInInjectionContext(createUnsavedChangesTracker);
|
|
6517
|
-
const { compareFn
|
|
6700
|
+
const { compareFn } = config;
|
|
6701
|
+
const confirm = config.confirm ?? inject(UNSAVED_CHANGES_CONFIRM, { optional: true });
|
|
6702
|
+
if (!confirm && isDevMode()) {
|
|
6703
|
+
throw new RuntimeError(UNSAVED_CHANGES_ERROR_CODES.MISSING_CONFIRM, '[createUnsavedChangesTracker] No confirm: pass `confirm` or call `provideUnsavedChangesConfirm()` in a parent injector.');
|
|
6704
|
+
}
|
|
6518
6705
|
const normalized = normalizeUnsavedChangesSource(config.source);
|
|
6519
6706
|
const hasExplicitDefault = config.defaultValue !== undefined;
|
|
6520
6707
|
const initialDefault = hasExplicitDefault
|
|
@@ -6565,7 +6752,10 @@ const createUnsavedChangesTracker = (config) => {
|
|
|
6565
6752
|
if (untracked(_isAbandoned) || !untracked(hasChanges)) {
|
|
6566
6753
|
return Promise.resolve(true);
|
|
6567
6754
|
}
|
|
6568
|
-
|
|
6755
|
+
if (!confirm) {
|
|
6756
|
+
return Promise.resolve(true);
|
|
6757
|
+
}
|
|
6758
|
+
return coordinator.runCheck((context) => toBooleanPromise(confirm(untracked(normalized.value), context), context.signal));
|
|
6569
6759
|
};
|
|
6570
6760
|
const refreshDefaultValue = () => _defaultValue.set(untracked(normalized.value));
|
|
6571
6761
|
const restoreDefaultValue = () => {
|
|
@@ -6877,12 +7067,19 @@ class ClickOutsideDirective {
|
|
|
6877
7067
|
this.elementRef = inject(ElementRef);
|
|
6878
7068
|
this.document = inject(DOCUMENT);
|
|
6879
7069
|
this.didClickOutside = output({ alias: 'etClickOutside' });
|
|
7070
|
+
this.pressStartedInside = false;
|
|
7071
|
+
fromEvent(this.document.documentElement, 'pointerdown', { capture: true })
|
|
7072
|
+
.pipe(tap((event) => {
|
|
7073
|
+
this.pressStartedInside = event.composedPath().includes(this.elementRef.nativeElement);
|
|
7074
|
+
}), takeUntilDestroyed())
|
|
7075
|
+
.subscribe();
|
|
6880
7076
|
fromEvent(this.document.documentElement, 'click')
|
|
6881
7077
|
.pipe(tap((event) => {
|
|
6882
7078
|
const hostElement = this.elementRef.nativeElement;
|
|
6883
7079
|
const activeElement = event.target;
|
|
6884
|
-
const
|
|
6885
|
-
|
|
7080
|
+
const startedInside = this.pressStartedInside;
|
|
7081
|
+
this.pressStartedInside = false;
|
|
7082
|
+
if (startedInside || event.composedPath().includes(hostElement))
|
|
6886
7083
|
return;
|
|
6887
7084
|
if (isOnHigherOverlayLayer(activeElement, resolveOverlayLayer(hostElement)))
|
|
6888
7085
|
return;
|
|
@@ -6906,7 +7103,7 @@ class RepeatDirective {
|
|
|
6906
7103
|
this.viewContainerRef = inject(ViewContainerRef);
|
|
6907
7104
|
this.repeatCount = input(2, { ...(ngDevMode ? { debugName: "repeatCount" } : /* istanbul ignore next */ {}), alias: 'etRepeat', transform: numberAttribute });
|
|
6908
7105
|
effect(() => {
|
|
6909
|
-
const count = Math.max(0, this.repeatCount());
|
|
7106
|
+
const count = Math.max(0, this.repeatCount()) || 0;
|
|
6910
7107
|
while (this.viewContainerRef.length < count) {
|
|
6911
7108
|
this.viewContainerRef.createEmbeddedView(this.mainTemplateRef);
|
|
6912
7109
|
}
|
|
@@ -7036,7 +7233,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
|
|
|
7036
7233
|
|
|
7037
7234
|
// jsdom and other non-browser DOMs ship no pointer capture; the document listeners track the
|
|
7038
7235
|
// gesture either way, so a failure here only costs events over a cross-origin frame.
|
|
7039
|
-
const capturePointer = (el, pointerId) => {
|
|
7236
|
+
const capturePointer$1 = (el, pointerId) => {
|
|
7040
7237
|
try {
|
|
7041
7238
|
el.setPointerCapture(pointerId);
|
|
7042
7239
|
}
|
|
@@ -7066,7 +7263,7 @@ const setupDragObservable = (startEvent, el, commitThreshold) => {
|
|
|
7066
7263
|
return EMPTY;
|
|
7067
7264
|
}
|
|
7068
7265
|
committed = true;
|
|
7069
|
-
capturePointer(el, pointerId);
|
|
7266
|
+
capturePointer$1(el, pointerId);
|
|
7070
7267
|
lastX = e.clientX;
|
|
7071
7268
|
lastY = e.clientY;
|
|
7072
7269
|
// Emit the catch-up move together with start so consumers snap to the pointer
|
|
@@ -8065,10 +8262,10 @@ const createOverlayRuntimeRef = (id, config, elements, requestClose) => {
|
|
|
8065
8262
|
...(ngDevMode ? [{ debugName: "_componentInstance" }] : /* istanbul ignore next */ []));
|
|
8066
8263
|
let positionUpdater = null;
|
|
8067
8264
|
let backdropUpdater = null;
|
|
8068
|
-
const beforeOpenedSubject = new
|
|
8069
|
-
const afterOpenedSubject = new
|
|
8070
|
-
const beforeClosedSubject = new
|
|
8071
|
-
const afterClosedSubject = new
|
|
8265
|
+
const beforeOpenedSubject = new ReplaySubject(1);
|
|
8266
|
+
const afterOpenedSubject = new ReplaySubject(1);
|
|
8267
|
+
const beforeClosedSubject = new ReplaySubject(1);
|
|
8268
|
+
const afterClosedSubject = new ReplaySubject(1);
|
|
8072
8269
|
const closeGuards = new Set();
|
|
8073
8270
|
return {
|
|
8074
8271
|
id,
|
|
@@ -8076,7 +8273,6 @@ const createOverlayRuntimeRef = (id, config, elements, requestClose) => {
|
|
|
8076
8273
|
elements,
|
|
8077
8274
|
state: _state.asReadonly(),
|
|
8078
8275
|
componentInstance: _componentInstance.asReadonly(),
|
|
8079
|
-
beforeOpenedSubject,
|
|
8080
8276
|
close(result, source = 'api') {
|
|
8081
8277
|
if (_state() === 'closing' || _state() === 'closed') {
|
|
8082
8278
|
return;
|
|
@@ -8119,6 +8315,10 @@ const createOverlayRuntimeRef = (id, config, elements, requestClose) => {
|
|
|
8119
8315
|
attachComponentRef(componentRef) {
|
|
8120
8316
|
_componentInstance.set(componentRef.instance);
|
|
8121
8317
|
},
|
|
8318
|
+
markBeforeOpened() {
|
|
8319
|
+
beforeOpenedSubject.next();
|
|
8320
|
+
beforeOpenedSubject.complete();
|
|
8321
|
+
},
|
|
8122
8322
|
attachPositionUpdater(updater) {
|
|
8123
8323
|
positionUpdater = updater;
|
|
8124
8324
|
},
|
|
@@ -8187,6 +8387,14 @@ const OVERLAY_RUNTIME_DEF = /* @__PURE__ */ defineRootProvider(() => {
|
|
|
8187
8387
|
// Synchronous teardown for each currently-mounted overlay, run when the runtime's injector is
|
|
8188
8388
|
// destroyed (app teardown). Registered on mount, removed once the overlay is destroyed normally.
|
|
8189
8389
|
const mountedTeardowns = new Set();
|
|
8390
|
+
const armedReopenSwallows = new Set();
|
|
8391
|
+
const focusRestoreChains = new WeakMap();
|
|
8392
|
+
const resolveFocusRestoreChain = (focused) => {
|
|
8393
|
+
if (!focused)
|
|
8394
|
+
return [];
|
|
8395
|
+
const owner = openEntriesState().find((entry) => entry.elements.hostElement.contains(focused));
|
|
8396
|
+
return [focused, ...((owner && focusRestoreChains.get(owner)) ?? [])];
|
|
8397
|
+
};
|
|
8190
8398
|
const getRootElement = (targetDocument, zIndex) => {
|
|
8191
8399
|
let documentRoots = rootElements.get(targetDocument);
|
|
8192
8400
|
if (!documentRoots) {
|
|
@@ -8259,9 +8467,7 @@ const OVERLAY_RUNTIME_DEF = /* @__PURE__ */ defineRootProvider(() => {
|
|
|
8259
8467
|
const paneElement = renderer.createElement('div');
|
|
8260
8468
|
const backdropElement = signal(null, /* @ts-ignore */
|
|
8261
8469
|
...(ngDevMode ? [{ debugName: "backdropElement" }] : /* istanbul ignore next */ []));
|
|
8262
|
-
const
|
|
8263
|
-
? targetDocument.activeElement
|
|
8264
|
-
: null;
|
|
8470
|
+
const focusRestoreChain = resolveFocusRestoreChain(isHTMLOrSVGElement(targetDocument.activeElement) ? targetDocument.activeElement : null);
|
|
8265
8471
|
const autoFocus = config.autoFocus ?? 'first-tabbable';
|
|
8266
8472
|
let currentHasBackdrop = config.hasBackdrop !== false;
|
|
8267
8473
|
let currentPositionStrategy = config.positionStrategy;
|
|
@@ -8338,8 +8544,8 @@ const OVERLAY_RUNTIME_DEF = /* @__PURE__ */ defineRootProvider(() => {
|
|
|
8338
8544
|
renderer.addClass(paneElement, 'et-overlay-runtime-pane', ...(config.paneClass ?? []));
|
|
8339
8545
|
appRef.attachView(componentRef.hostView);
|
|
8340
8546
|
overlayRef.attachComponentRef(componentRef);
|
|
8341
|
-
overlayRef.
|
|
8342
|
-
|
|
8547
|
+
overlayRef.markBeforeOpened();
|
|
8548
|
+
focusRestoreChains.set(overlayRef, focusRestoreChain);
|
|
8343
8549
|
openEntriesState.update((entries) => [...entries, overlayRef]);
|
|
8344
8550
|
let positionCleanup = setupPositioning(activeConfig(), hostElement, paneElement, overlayRef, renderer);
|
|
8345
8551
|
cleanupFns.push(() => positionCleanup());
|
|
@@ -8394,8 +8600,8 @@ const OVERLAY_RUNTIME_DEF = /* @__PURE__ */ defineRootProvider(() => {
|
|
|
8394
8600
|
}
|
|
8395
8601
|
openEntriesState.update((entries) => entries.filter((entry) => entry !== overlayRef));
|
|
8396
8602
|
maybeDestroyRootElements(targetDocument);
|
|
8397
|
-
if (config.restoreFocus !== false && overlayStillOwnsFocus
|
|
8398
|
-
|
|
8603
|
+
if (config.restoreFocus !== false && overlayStillOwnsFocus) {
|
|
8604
|
+
focusRestoreChain.find((element) => element.isConnected)?.focus({ preventScroll: true });
|
|
8399
8605
|
}
|
|
8400
8606
|
overlayRef.finishClose(closeEvent);
|
|
8401
8607
|
};
|
|
@@ -8413,7 +8619,7 @@ const OVERLAY_RUNTIME_DEF = /* @__PURE__ */ defineRootProvider(() => {
|
|
|
8413
8619
|
return;
|
|
8414
8620
|
}
|
|
8415
8621
|
const lifecycle = getAnimatedLifecycle(componentRef);
|
|
8416
|
-
animationDebugLog(`runtime ${config.id}`, `close requested (source "${closeEvent.source}", lifecycle state "${lifecycle?.state
|
|
8622
|
+
animationDebugLog(`runtime ${config.id}`, `close requested (source "${closeEvent.source}", lifecycle state "${lifecycle?.state() ?? 'none'}", delegate ${config.animationDelegate?.leave ? 'yes' : 'no'})`);
|
|
8417
8623
|
// The reference element is gone - there is nothing left to animate away from, so tear the
|
|
8418
8624
|
// overlay down synchronously instead of playing a leave transition from a stale position.
|
|
8419
8625
|
if (!lifecycle || closeEvent.source === 'reference-detached') {
|
|
@@ -8470,12 +8676,22 @@ const OVERLAY_RUNTIME_DEF = /* @__PURE__ */ defineRootProvider(() => {
|
|
|
8470
8676
|
const originElement = getOriginElement();
|
|
8471
8677
|
if (originElement && originElement.contains(target)) {
|
|
8472
8678
|
const swallowReopenClick = (clickEvent) => {
|
|
8679
|
+
disarmReopenSwallow();
|
|
8473
8680
|
if (isElement(clickEvent.target) && originElement.contains(clickEvent.target)) {
|
|
8474
8681
|
clickEvent.stopImmediatePropagation();
|
|
8475
8682
|
clickEvent.preventDefault();
|
|
8476
8683
|
}
|
|
8477
8684
|
};
|
|
8478
|
-
|
|
8685
|
+
// A press that ends without a click (cancelled, dragged off) must not leave the swallow
|
|
8686
|
+
// armed for the next, unrelated click on the origin.
|
|
8687
|
+
const disarmReopenSwallow = () => {
|
|
8688
|
+
targetDocument.removeEventListener('click', swallowReopenClick, true);
|
|
8689
|
+
targetDocument.removeEventListener('pointerdown', disarmReopenSwallow, true);
|
|
8690
|
+
armedReopenSwallows.delete(disarmReopenSwallow);
|
|
8691
|
+
};
|
|
8692
|
+
targetDocument.addEventListener('click', swallowReopenClick, true);
|
|
8693
|
+
targetDocument.addEventListener('pointerdown', disarmReopenSwallow, true);
|
|
8694
|
+
armedReopenSwallows.add(disarmReopenSwallow);
|
|
8479
8695
|
}
|
|
8480
8696
|
};
|
|
8481
8697
|
targetDocument.addEventListener('pointerdown', onPointerDown, true);
|
|
@@ -8494,7 +8710,7 @@ const OVERLAY_RUNTIME_DEF = /* @__PURE__ */ defineRootProvider(() => {
|
|
|
8494
8710
|
overlayRef.markOpened();
|
|
8495
8711
|
return;
|
|
8496
8712
|
}
|
|
8497
|
-
animationDebugLog(`runtime ${config.id}`, `enter (delegate ${config.animationDelegate?.enter ? 'yes' : 'no'}, lifecycle state "${lifecycle.state
|
|
8713
|
+
animationDebugLog(`runtime ${config.id}`, `enter (delegate ${config.animationDelegate?.enter ? 'yes' : 'no'}, lifecycle state "${lifecycle.state()}")`);
|
|
8498
8714
|
const readySubscription = lifecycle.state$
|
|
8499
8715
|
.pipe(filter((state) => state === 'entering' || state === 'entered'), take(1), tap(() => {
|
|
8500
8716
|
nextFrame(() => {
|
|
@@ -8520,6 +8736,7 @@ const OVERLAY_RUNTIME_DEF = /* @__PURE__ */ defineRootProvider(() => {
|
|
|
8520
8736
|
};
|
|
8521
8737
|
destroyRef.onDestroy(() => {
|
|
8522
8738
|
[...mountedTeardowns].forEach((teardown) => teardown());
|
|
8739
|
+
[...armedReopenSwallows].forEach((disarm) => disarm());
|
|
8523
8740
|
[...rootElements.keys()].forEach((targetDocument) => maybeDestroyRootElements(targetDocument));
|
|
8524
8741
|
});
|
|
8525
8742
|
return {
|
|
@@ -9110,7 +9327,7 @@ const initials = (value, maxLength = 2) => {
|
|
|
9110
9327
|
return '';
|
|
9111
9328
|
return words
|
|
9112
9329
|
.slice(0, maxLength)
|
|
9113
|
-
.map((word) => word[0]?.toUpperCase() ?? '')
|
|
9330
|
+
.map((word) => [...word.normalize()][0]?.toUpperCase() ?? '')
|
|
9114
9331
|
.join('');
|
|
9115
9332
|
};
|
|
9116
9333
|
|
|
@@ -9189,20 +9406,38 @@ const EDGE_CURSORS = {
|
|
|
9189
9406
|
nw: 'nwse-resize',
|
|
9190
9407
|
se: 'nwse-resize',
|
|
9191
9408
|
};
|
|
9192
|
-
|
|
9409
|
+
// jsdom and other non-browser DOMs ship no pointer capture; the document listeners track the
|
|
9410
|
+
// gesture either way, so a failure here only costs events over a cross-origin frame.
|
|
9411
|
+
const capturePointer = (el, pointerId) => {
|
|
9412
|
+
try {
|
|
9413
|
+
el.setPointerCapture(pointerId);
|
|
9414
|
+
}
|
|
9415
|
+
catch {
|
|
9416
|
+
return;
|
|
9417
|
+
}
|
|
9418
|
+
};
|
|
9419
|
+
const setupResizeObservable = (startEvent, handle, edge, doc) => {
|
|
9193
9420
|
const pointerId = startEvent.pointerId;
|
|
9194
9421
|
const startX = startEvent.clientX;
|
|
9195
9422
|
const startY = startEvent.clientY;
|
|
9196
9423
|
let cancelled = false;
|
|
9424
|
+
let last = { edge, totalDx: 0, totalDy: 0, clientX: startX, clientY: startY };
|
|
9197
9425
|
const end$ = merge(fromEvent(doc, 'pointerup'), fromEvent(doc, 'pointercancel')).pipe(filter((e) => e.pointerId === pointerId), take(1),
|
|
9198
9426
|
// Read below by the terminating `defer`, which only runs once this has completed the moves.
|
|
9199
9427
|
tap((e) => (cancelled = e.type === 'pointercancel')));
|
|
9200
9428
|
return defer(() => {
|
|
9201
9429
|
const releaseSelection = suppressTextSelection(doc);
|
|
9202
|
-
|
|
9203
|
-
|
|
9204
|
-
|
|
9205
|
-
|
|
9430
|
+
capturePointer(handle, pointerId);
|
|
9431
|
+
return concat(of({ type: 'start', edge }), fromEvent(doc, 'pointermove').pipe(filter((e) => e.pointerId === pointerId), map((e) => {
|
|
9432
|
+
last = {
|
|
9433
|
+
edge,
|
|
9434
|
+
totalDx: e.clientX - startX,
|
|
9435
|
+
totalDy: e.clientY - startY,
|
|
9436
|
+
clientX: e.clientX,
|
|
9437
|
+
clientY: e.clientY,
|
|
9438
|
+
};
|
|
9439
|
+
return { type: 'move', data: last };
|
|
9440
|
+
}), takeUntil(end$)), defer(() => of(cancelled ? { type: 'cancelled' } : { type: 'end', data: last }))).pipe(finalize(releaseSelection));
|
|
9206
9441
|
});
|
|
9207
9442
|
};
|
|
9208
9443
|
class ResizeHandlesComponent {
|
|
@@ -9212,10 +9447,10 @@ class ResizeHandlesComponent {
|
|
|
9212
9447
|
...(ngDevMode ? [{ debugName: "edges" }] : /* istanbul ignore next */ []));
|
|
9213
9448
|
this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
9214
9449
|
this.gestureStart$ = new Subject();
|
|
9215
|
-
this.gesture$ = this.gestureStart$.pipe(exhaustMap(({ event, edge }) => setupResizeObservable(event, edge, this.el.nativeElement.ownerDocument)), share(), takeUntilDestroyed());
|
|
9450
|
+
this.gesture$ = this.gestureStart$.pipe(exhaustMap(({ event, handle, edge }) => setupResizeObservable(event, handle, edge, this.el.nativeElement.ownerDocument)), share(), takeUntilDestroyed());
|
|
9216
9451
|
this.resizeStarted = outputFromObservable(this.gesture$.pipe(filter((e) => e.type === 'start'), map((e) => e.edge)));
|
|
9217
9452
|
this.resizeMoved = outputFromObservable(this.gesture$.pipe(filter((e) => e.type === 'move'), map((e) => e.data)));
|
|
9218
|
-
this.resizeEnded = outputFromObservable(this.gesture$.pipe(filter((e) => e.type === 'end'), map(() =>
|
|
9453
|
+
this.resizeEnded = outputFromObservable(this.gesture$.pipe(filter((e) => e.type === 'end'), map((e) => e.data)));
|
|
9219
9454
|
/**
|
|
9220
9455
|
* The browser took the gesture away mid-resize (a system gesture, an incoming call, the tab going
|
|
9221
9456
|
* to the background). Revert to the size the resize started from - the user never let go, so there
|
|
@@ -9236,7 +9471,7 @@ class ResizeHandlesComponent {
|
|
|
9236
9471
|
if (event.button !== 0 || this.disabled())
|
|
9237
9472
|
return;
|
|
9238
9473
|
event.stopPropagation();
|
|
9239
|
-
this.gestureStart$.next({ event, edge });
|
|
9474
|
+
this.gestureStart$.next({ event, handle: event.currentTarget, edge });
|
|
9240
9475
|
}
|
|
9241
9476
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ResizeHandlesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
9242
9477
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: ResizeHandlesComponent, isStandalone: true, selector: "et-resize-handles", inputs: { edges: { classPropertyName: "edges", publicName: "edges", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { resizeStarted: "resizeStarted", resizeMoved: "resizeMoved", resizeEnded: "resizeEnded", resizeCancelled: "resizeCancelled" }, host: { properties: { "attr.inert": "disabled() ? \"\" : null", "attr.data-active-edge": "activeEdge()" }, classAttribute: "et-resize-handles" }, ngImport: i0, template: `
|
|
@@ -9498,6 +9733,226 @@ const injectDefaultSurfaceTheme = (type) => {
|
|
|
9498
9733
|
return defaults.length === 1 ? (defaults[0] ?? null) : null;
|
|
9499
9734
|
};
|
|
9500
9735
|
|
|
9736
|
+
/**
|
|
9737
|
+
* Reserved color name. Resolves the color tokens from the ambient surface's neutral swatch
|
|
9738
|
+
* (`SurfaceTheme['interactionColor']`) instead of a registered accent, so a secondary action can
|
|
9739
|
+
* read as chrome without the app registering a neutral color theme. Apps must not register a color
|
|
9740
|
+
* theme under this name.
|
|
9741
|
+
*/
|
|
9742
|
+
const SURFACE_COLOR = 'surface';
|
|
9743
|
+
const createCssColorThemeName = (name) => name.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
|
|
9744
|
+
const COLOR_THEMES_DEF = /* @__PURE__ */ defineStaticProvider(undefined, {
|
|
9745
|
+
name: 'Color Themes',
|
|
9746
|
+
});
|
|
9747
|
+
const ɵProvideColorThemes = /* @__PURE__ */ toProvideFn(COLOR_THEMES_DEF);
|
|
9748
|
+
const injectColorThemes = /* @__PURE__ */ toInjectFn(COLOR_THEMES_DEF);
|
|
9749
|
+
const COLOR_THEMES_PREFIX_DEF = /* @__PURE__ */ defineStaticProvider('et', {
|
|
9750
|
+
name: 'Themes Prefix',
|
|
9751
|
+
});
|
|
9752
|
+
const ɵProvideColorThemesPrefix = /* @__PURE__ */ toProvideFn(COLOR_THEMES_PREFIX_DEF);
|
|
9753
|
+
const injectColorThemesPrefix = /* @__PURE__ */ toInjectFn(COLOR_THEMES_PREFIX_DEF);
|
|
9754
|
+
const provideColorThemesWithTailwind4 = (themes, prefix = 'et') => {
|
|
9755
|
+
if (isDevMode() && themes.some((theme) => theme.name === SURFACE_COLOR)) {
|
|
9756
|
+
console.error(`[provideColorThemesWithTailwind4] "${SURFACE_COLOR}" is a reserved color name that resolves to the ambient surface's neutral swatch. Rename your theme.`);
|
|
9757
|
+
}
|
|
9758
|
+
return [ɵProvideColorThemes(themes), ɵProvideColorThemesPrefix(prefix)];
|
|
9759
|
+
};
|
|
9760
|
+
const findColorThemeByType = (themes, type, caller) => {
|
|
9761
|
+
if (!themes) {
|
|
9762
|
+
throw new Error(`[${caller}] No color themes provided. Call provideColorThemesWithTailwind4() in your app config.`);
|
|
9763
|
+
}
|
|
9764
|
+
const theme = themes.find((t) => t.type === type);
|
|
9765
|
+
if (!theme) {
|
|
9766
|
+
throw new Error(`[${caller}] No color theme with type "${type}" found. Add a theme with type: "${type}" to provideColorThemesWithTailwind4().`);
|
|
9767
|
+
}
|
|
9768
|
+
if (isDevMode()) {
|
|
9769
|
+
const duplicates = themes.filter((t) => t.type === type);
|
|
9770
|
+
if (duplicates.length > 1) {
|
|
9771
|
+
console.error(`[${caller}] Multiple themes with type "${type}" found: ${duplicates.map((t) => t.name).join(', ')}. Only the first one will be used.`);
|
|
9772
|
+
}
|
|
9773
|
+
}
|
|
9774
|
+
return theme;
|
|
9775
|
+
};
|
|
9776
|
+
const injectColorThemeByType = (type) => findColorThemeByType(injectColorThemes({ optional: true }), type, 'injectColorThemeByType');
|
|
9777
|
+
/**
|
|
9778
|
+
* A signal of the color theme for `type` on the surface this element renders on: the theme the nearest
|
|
9779
|
+
* surface names in `semanticColorThemes`, else the first registered theme of that `type`. Reading it throws
|
|
9780
|
+
* when the app registered no theme of that `type`, so read it only for a state that renders.
|
|
9781
|
+
*
|
|
9782
|
+
* @example
|
|
9783
|
+
* protected successTheme = injectSemanticColorTheme('success');
|
|
9784
|
+
* // <span [etProvideColor]="successTheme()">+12%</span>
|
|
9785
|
+
*/
|
|
9786
|
+
const injectSemanticColorTheme = (type) => {
|
|
9787
|
+
const themes = injectColorThemes({ optional: true });
|
|
9788
|
+
const surfaceProvider = inject(SURFACE_PROVIDER, { optional: true });
|
|
9789
|
+
const defaultSurface = injectDefaultSurfaceTheme();
|
|
9790
|
+
return computed(() => {
|
|
9791
|
+
const surface = surfaceProvider?.activeTheme() ?? defaultSurface;
|
|
9792
|
+
const mappedName = surface?.semanticColorThemes?.[type];
|
|
9793
|
+
const mapped = mappedName ? themes?.find((t) => t.name === mappedName) : undefined;
|
|
9794
|
+
if (mapped)
|
|
9795
|
+
return mapped;
|
|
9796
|
+
if (mappedName && isDevMode()) {
|
|
9797
|
+
console.error(`[injectSemanticColorTheme] Surface theme "${surface?.name}" maps "${type}" to the color theme "${mappedName}", which is not registered. Add it to provideColorThemesWithTailwind4().`);
|
|
9798
|
+
}
|
|
9799
|
+
return findColorThemeByType(themes, type, 'injectSemanticColorTheme');
|
|
9800
|
+
});
|
|
9801
|
+
};
|
|
9802
|
+
/** @deprecated Use `injectSemanticColorTheme('error')`, which follows the surface the element renders on. */
|
|
9803
|
+
const injectErrorTheme = () => injectColorThemeByType('error');
|
|
9804
|
+
/** @deprecated Use `injectSemanticColorTheme('warning')`, which follows the surface the element renders on. */
|
|
9805
|
+
const injectWarningTheme = () => injectColorThemeByType('warning');
|
|
9806
|
+
/** @deprecated Use `injectSemanticColorTheme('success')`, which follows the surface the element renders on. */
|
|
9807
|
+
const injectSuccessTheme = () => injectColorThemeByType('success');
|
|
9808
|
+
const injectDefaultColorTheme = () => {
|
|
9809
|
+
const themes = injectColorThemes({ optional: true });
|
|
9810
|
+
if (!themes) {
|
|
9811
|
+
throw new Error(`[injectDefaultColorTheme] No color themes provided. Call provideColorThemesWithTailwind4() in your app config.`);
|
|
9812
|
+
}
|
|
9813
|
+
const theme = themes.find((t) => t.isDefault);
|
|
9814
|
+
if (!theme) {
|
|
9815
|
+
throw new Error(`[injectDefaultColorTheme] No color theme with isDefault: true found. Mark one theme as the default in provideColorThemesWithTailwind4().`);
|
|
9816
|
+
}
|
|
9817
|
+
if (isDevMode()) {
|
|
9818
|
+
const duplicates = themes.filter((t) => t.isDefault);
|
|
9819
|
+
if (duplicates.length > 1) {
|
|
9820
|
+
console.error(`[injectDefaultColorTheme] Multiple themes with isDefault: true found: ${duplicates.map((t) => t.name).join(', ')}. Only the first one will be used.`);
|
|
9821
|
+
}
|
|
9822
|
+
}
|
|
9823
|
+
return theme;
|
|
9824
|
+
};
|
|
9825
|
+
|
|
9826
|
+
const COLOR_PROVIDER = new InjectionToken('ColorProvider');
|
|
9827
|
+
/**
|
|
9828
|
+
* The color provider attached to a bootstrapped root component (e.g. `ProvideColorDirective` in
|
|
9829
|
+
* the app component's `hostDirectives`), if any. Detached DOM such as overlay panes can't reach
|
|
9830
|
+
* it through element DI, so overlay containers fall back to this when resolving the provider to
|
|
9831
|
+
* `syncWithProvider()` - resolve at sync time, not at injection time, since root components only
|
|
9832
|
+
* register with `ApplicationRef` once bootstrap completes.
|
|
9833
|
+
*/
|
|
9834
|
+
const resolveAppRootColorProvider = (appRef) => {
|
|
9835
|
+
for (const componentRef of appRef.components) {
|
|
9836
|
+
const provider = componentRef.injector.get(COLOR_PROVIDER, null);
|
|
9837
|
+
if (provider) {
|
|
9838
|
+
return provider;
|
|
9839
|
+
}
|
|
9840
|
+
}
|
|
9841
|
+
return null;
|
|
9842
|
+
};
|
|
9843
|
+
const FORCED_COLOR_UNSET = /* @__PURE__ */ Symbol('FORCED_COLOR_UNSET');
|
|
9844
|
+
const appsWarnedAboutMissingThemes = /* @__PURE__ */ new WeakSet();
|
|
9845
|
+
class ProvideColorDirective {
|
|
9846
|
+
constructor() {
|
|
9847
|
+
this.themes = injectColorThemes({ optional: true });
|
|
9848
|
+
this.prefix = injectColorThemesPrefix({ optional: true });
|
|
9849
|
+
this.injector = inject(Injector);
|
|
9850
|
+
this.parentProvider = inject(COLOR_PROVIDER, { optional: true, skipSelf: true });
|
|
9851
|
+
this.appRef = inject(ApplicationRef);
|
|
9852
|
+
this.currentProviderSync = null;
|
|
9853
|
+
this.forcedColor = signal(FORCED_COLOR_UNSET, /* @ts-ignore */
|
|
9854
|
+
...(ngDevMode ? [{ debugName: "forcedColor" }] : /* istanbul ignore next */ []));
|
|
9855
|
+
this.color = input(undefined, { ...(ngDevMode ? { debugName: "color" } : /* istanbul ignore next */ {}), alias: 'etProvideColor' });
|
|
9856
|
+
this.effectiveColor = computed(() => {
|
|
9857
|
+
const forcedColor = this.forcedColor();
|
|
9858
|
+
if (forcedColor !== FORCED_COLOR_UNSET) {
|
|
9859
|
+
return forcedColor;
|
|
9860
|
+
}
|
|
9861
|
+
return this.color();
|
|
9862
|
+
}, /* @ts-ignore */
|
|
9863
|
+
...(ngDevMode ? [{ debugName: "effectiveColor" }] : /* istanbul ignore next */ []));
|
|
9864
|
+
/**
|
|
9865
|
+
* The color that actually applies at this provider's location: its own effective color, or -
|
|
9866
|
+
* when this provider is passive (no input, nothing forced) - the nearest ancestor provider's.
|
|
9867
|
+
* Mirrors the CSS cascade, which falls through a provider's `-color--inherited` scope class;
|
|
9868
|
+
* consumers that re-apply context across detached DOM (overlay panes) must use this instead
|
|
9869
|
+
* of `effectiveColor` or a passive in-between provider (e.g. a form field's) erases the theme.
|
|
9870
|
+
*/
|
|
9871
|
+
this.resolvedColor = computed(() => {
|
|
9872
|
+
const own = this.effectiveColor();
|
|
9873
|
+
const ownName = typeof own === 'object' && own !== null ? own.name : own;
|
|
9874
|
+
if (ownName) {
|
|
9875
|
+
return own;
|
|
9876
|
+
}
|
|
9877
|
+
return this.parentProvider?.resolvedColor();
|
|
9878
|
+
}, /* @ts-ignore */
|
|
9879
|
+
...(ngDevMode ? [{ debugName: "resolvedColor" }] : /* istanbul ignore next */ []));
|
|
9880
|
+
this.colorName = computed(() => {
|
|
9881
|
+
const raw = this.effectiveColor();
|
|
9882
|
+
const value = typeof raw === 'object' && raw !== null ? raw.name : raw;
|
|
9883
|
+
if (value === SURFACE_COLOR)
|
|
9884
|
+
return SURFACE_COLOR;
|
|
9885
|
+
if (!value)
|
|
9886
|
+
return;
|
|
9887
|
+
if (!this.themes) {
|
|
9888
|
+
if (isDevMode() && !appsWarnedAboutMissingThemes.has(this.appRef)) {
|
|
9889
|
+
appsWarnedAboutMissingThemes.add(this.appRef);
|
|
9890
|
+
console.warn(`etProvideColor="${value}" has no effect because no color themes are registered. Please make sure to add provideColorThemesWithTailwind4()`);
|
|
9891
|
+
}
|
|
9892
|
+
return;
|
|
9893
|
+
}
|
|
9894
|
+
if (isDevMode() && !this.themes.some((theme) => theme.name === value)) {
|
|
9895
|
+
console.error(`Theme ${value} does not exist. Please make sure to add it to provideColorThemesWithTailwind4()`);
|
|
9896
|
+
}
|
|
9897
|
+
return createCssColorThemeName(value);
|
|
9898
|
+
}, /* @ts-ignore */
|
|
9899
|
+
...(ngDevMode ? [{ debugName: "colorName" }] : /* istanbul ignore next */ []));
|
|
9900
|
+
this.themeClass = computed(() => {
|
|
9901
|
+
const prefix = this.prefix || 'et';
|
|
9902
|
+
if (this.colorName()) {
|
|
9903
|
+
return `${prefix}-color--${this.colorName()}`;
|
|
9904
|
+
}
|
|
9905
|
+
return `${prefix}-color--inherited`;
|
|
9906
|
+
}, /* @ts-ignore */
|
|
9907
|
+
...(ngDevMode ? [{ debugName: "themeClass" }] : /* istanbul ignore next */ []));
|
|
9908
|
+
}
|
|
9909
|
+
syncWithProvider(provider) {
|
|
9910
|
+
this.currentProviderSync?.destroy();
|
|
9911
|
+
runInInjectionContext(this.injector, () => {
|
|
9912
|
+
this.currentProviderSync = effect(() => {
|
|
9913
|
+
const provideColor = provider.resolvedColor();
|
|
9914
|
+
untracked(() => {
|
|
9915
|
+
if (provideColor === undefined) {
|
|
9916
|
+
this.clearForcedColor();
|
|
9917
|
+
return;
|
|
9918
|
+
}
|
|
9919
|
+
this.forceColor(provideColor);
|
|
9920
|
+
});
|
|
9921
|
+
}, /* @ts-ignore */
|
|
9922
|
+
...(ngDevMode ? [{ debugName: "currentProviderSync" }] : /* istanbul ignore next */ []));
|
|
9923
|
+
});
|
|
9924
|
+
}
|
|
9925
|
+
stopSyncWithProvider() {
|
|
9926
|
+
const hadProviderSync = !!this.currentProviderSync;
|
|
9927
|
+
this.currentProviderSync?.destroy();
|
|
9928
|
+
this.currentProviderSync = null;
|
|
9929
|
+
if (hadProviderSync) {
|
|
9930
|
+
this.clearForcedColor();
|
|
9931
|
+
}
|
|
9932
|
+
}
|
|
9933
|
+
forceColor(color) {
|
|
9934
|
+
this.forcedColor.set(color);
|
|
9935
|
+
}
|
|
9936
|
+
clearForcedColor() {
|
|
9937
|
+
if (this.forcedColor() === FORCED_COLOR_UNSET) {
|
|
9938
|
+
return;
|
|
9939
|
+
}
|
|
9940
|
+
this.forcedColor.set(FORCED_COLOR_UNSET);
|
|
9941
|
+
}
|
|
9942
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ProvideColorDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
9943
|
+
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 }); }
|
|
9944
|
+
}
|
|
9945
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ProvideColorDirective, decorators: [{
|
|
9946
|
+
type: Directive,
|
|
9947
|
+
args: [{
|
|
9948
|
+
selector: '[etProvideColor]',
|
|
9949
|
+
providers: [{ provide: COLOR_PROVIDER, useExisting: ProvideColorDirective }],
|
|
9950
|
+
host: {
|
|
9951
|
+
'[class]': 'themeClass()',
|
|
9952
|
+
},
|
|
9953
|
+
}]
|
|
9954
|
+
}], propDecorators: { color: [{ type: i0.Input, args: [{ isSignal: true, alias: "etProvideColor", required: false }] }] } });
|
|
9955
|
+
|
|
9501
9956
|
const SURFACE_PROVIDER = new InjectionToken('SurfaceProvider');
|
|
9502
9957
|
const FORCED_SURFACE_UNSET = /* @__PURE__ */ Symbol('FORCED_SURFACE_UNSET');
|
|
9503
9958
|
class ProvideSurfaceDirective {
|
|
@@ -9507,6 +9962,9 @@ class ProvideSurfaceDirective {
|
|
|
9507
9962
|
this.injector = inject(Injector);
|
|
9508
9963
|
this.parentProvider = inject(SURFACE_PROVIDER, { optional: true, skipSelf: true });
|
|
9509
9964
|
this.defaultTheme = injectDefaultSurfaceTheme();
|
|
9965
|
+
this.colorThemes = injectColorThemes({ optional: true });
|
|
9966
|
+
this.colorPrefix = injectColorThemesPrefix({ optional: true });
|
|
9967
|
+
this.colorProvider = inject(COLOR_PROVIDER, { optional: true });
|
|
9510
9968
|
this.currentProviderSync = null;
|
|
9511
9969
|
this.forcedSurface = signal(FORCED_SURFACE_UNSET, /* @ts-ignore */
|
|
9512
9970
|
...(ngDevMode ? [{ debugName: "forcedSurface" }] : /* istanbul ignore next */ []));
|
|
@@ -9552,12 +10010,23 @@ class ProvideSurfaceDirective {
|
|
|
9552
10010
|
return createCssSurfaceName(value);
|
|
9553
10011
|
}, /* @ts-ignore */
|
|
9554
10012
|
...(ngDevMode ? [{ debugName: "surfaceName" }] : /* istanbul ignore next */ []));
|
|
10013
|
+
this.colorThemeClass = computed(() => {
|
|
10014
|
+
const colorTheme = this.resolvedTheme()?.colorTheme;
|
|
10015
|
+
if (!colorTheme || this.colorProvider?.resolvedColor())
|
|
10016
|
+
return null;
|
|
10017
|
+
if (isDevMode() && !this.colorThemes?.some((theme) => theme.name === colorTheme)) {
|
|
10018
|
+
console.error(`Surface theme ${this.resolvedTheme()?.name} names the color theme ${colorTheme}, which does not exist. Please make sure to add it to provideColorThemesWithTailwind4()`);
|
|
10019
|
+
}
|
|
10020
|
+
return `${this.colorPrefix || 'et'}-color--${createCssColorThemeName(colorTheme)}`;
|
|
10021
|
+
}, /* @ts-ignore */
|
|
10022
|
+
...(ngDevMode ? [{ debugName: "colorThemeClass" }] : /* istanbul ignore next */ []));
|
|
9555
10023
|
this.surfaceClass = computed(() => {
|
|
9556
10024
|
const prefix = this.prefix || 'et';
|
|
9557
|
-
|
|
9558
|
-
|
|
9559
|
-
|
|
9560
|
-
|
|
10025
|
+
const surfaceClass = this.surfaceName()
|
|
10026
|
+
? `${prefix}-surface--${this.surfaceName()}`
|
|
10027
|
+
: `${prefix}-surface--inherited`;
|
|
10028
|
+
const colorThemeClass = this.colorThemeClass();
|
|
10029
|
+
return colorThemeClass ? `${surfaceClass} ${colorThemeClass}` : surfaceClass;
|
|
9561
10030
|
}, /* @ts-ignore */
|
|
9562
10031
|
...(ngDevMode ? [{ debugName: "surfaceClass" }] : /* istanbul ignore next */ []));
|
|
9563
10032
|
}
|
|
@@ -9766,87 +10235,48 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
|
|
|
9766
10235
|
const COLOR_PALETTE_DEF = /* @__PURE__ */ defineStaticProvider(undefined, {
|
|
9767
10236
|
name: 'Color Palette',
|
|
9768
10237
|
});
|
|
10238
|
+
const injectColorPaletteConfig = /* @__PURE__ */ toInjectFn(COLOR_PALETTE_DEF);
|
|
10239
|
+
const selectPalette = (config, surface) => {
|
|
10240
|
+
if (Array.isArray(config))
|
|
10241
|
+
return config;
|
|
10242
|
+
return (surface === null ? undefined : config[surface]) ?? config.default;
|
|
10243
|
+
};
|
|
9769
10244
|
/**
|
|
9770
10245
|
* The color themes a subtree may offer a user as pickable choices, in the order they should appear.
|
|
9771
10246
|
* A curated slice of what `provideColorThemesWithTailwind4` registered: an app registers every theme
|
|
9772
10247
|
* it renders with, including ones nobody should pick by hand (`error`, `warning`), and adds the
|
|
9773
10248
|
* user-facing label a swatch needs.
|
|
9774
10249
|
*
|
|
9775
|
-
*
|
|
9776
|
-
*
|
|
10250
|
+
* Pass one list, or one list per registered surface theme name plus a `default`. The charts draw with
|
|
10251
|
+
* the list of the surface they sit on; a color picker always offers the `default` list.
|
|
9777
10252
|
*
|
|
9778
10253
|
* @example
|
|
9779
10254
|
* provideColorPalette([
|
|
9780
10255
|
* { token: 'brand', label: 'Team green' },
|
|
9781
10256
|
* { token: 'ocean', label: 'Training blue' },
|
|
9782
10257
|
* ]);
|
|
10258
|
+
*
|
|
10259
|
+
* @example
|
|
10260
|
+
* provideColorPalette({
|
|
10261
|
+
* default: [{ token: 'ocean', label: 'Training' }],
|
|
10262
|
+
* 'dark-card': [{ token: 'ocean-bright', label: 'Training' }],
|
|
10263
|
+
* });
|
|
9783
10264
|
*/
|
|
9784
|
-
const provideColorPalette =
|
|
9785
|
-
|
|
9786
|
-
const
|
|
9787
|
-
|
|
9788
|
-
|
|
10265
|
+
const provideColorPalette = (palette) => COLOR_PALETTE_DEF.provide(palette);
|
|
10266
|
+
function injectColorPalette(options) {
|
|
10267
|
+
const config = options ? injectColorPaletteConfig(options) : injectColorPaletteConfig();
|
|
10268
|
+
return config ? selectPalette(config, null) : null;
|
|
10269
|
+
}
|
|
9789
10270
|
/**
|
|
9790
|
-
*
|
|
9791
|
-
*
|
|
9792
|
-
* read as chrome without the app registering a neutral color theme. Apps must not register a color
|
|
9793
|
-
* theme under this name.
|
|
10271
|
+
* The palette from {@link provideColorPalette} for the surface the current subtree renders on: that
|
|
10272
|
+
* surface theme's list, else the `default` list. `null` when no palette is provided.
|
|
9794
10273
|
*/
|
|
9795
|
-
const
|
|
9796
|
-
const
|
|
9797
|
-
const
|
|
9798
|
-
name:
|
|
9799
|
-
});
|
|
9800
|
-
const ɵProvideColorThemes = /* @__PURE__ */ toProvideFn(COLOR_THEMES_DEF);
|
|
9801
|
-
const injectColorThemes = /* @__PURE__ */ toInjectFn(COLOR_THEMES_DEF);
|
|
9802
|
-
const COLOR_THEMES_PREFIX_DEF = /* @__PURE__ */ defineStaticProvider('et', {
|
|
9803
|
-
name: 'Themes Prefix',
|
|
9804
|
-
});
|
|
9805
|
-
const ɵProvideColorThemesPrefix = /* @__PURE__ */ toProvideFn(COLOR_THEMES_PREFIX_DEF);
|
|
9806
|
-
const injectColorThemesPrefix = /* @__PURE__ */ toInjectFn(COLOR_THEMES_PREFIX_DEF);
|
|
9807
|
-
const provideColorThemesWithTailwind4 = (themes, prefix = 'et') => {
|
|
9808
|
-
if (isDevMode() && themes.some((theme) => theme.name === SURFACE_COLOR)) {
|
|
9809
|
-
console.error(`[provideColorThemesWithTailwind4] "${SURFACE_COLOR}" is a reserved color name that resolves to the ambient surface's neutral swatch. Rename your theme.`);
|
|
9810
|
-
}
|
|
9811
|
-
return [ɵProvideColorThemes(themes), ɵProvideColorThemesPrefix(prefix)];
|
|
9812
|
-
};
|
|
9813
|
-
const injectColorThemeByType = (type) => {
|
|
9814
|
-
const themes = injectColorThemes({ optional: true });
|
|
9815
|
-
if (!themes) {
|
|
9816
|
-
throw new Error(`[injectColorThemeByType] No color themes provided. Call provideColorThemesWithTailwind4() in your app config.`);
|
|
9817
|
-
}
|
|
9818
|
-
const theme = themes.find((t) => t.type === type);
|
|
9819
|
-
if (!theme) {
|
|
9820
|
-
throw new Error(`[injectColorThemeByType] No color theme with type "${type}" found. Add a theme with type: "${type}" to provideColorThemesWithTailwind4().`);
|
|
9821
|
-
}
|
|
9822
|
-
if (isDevMode()) {
|
|
9823
|
-
const duplicates = themes.filter((t) => t.type === type);
|
|
9824
|
-
if (duplicates.length > 1) {
|
|
9825
|
-
console.error(`[injectColorThemeByType] Multiple themes with type "${type}" found: ${duplicates.map((t) => t.name).join(', ')}. Only the first one will be used.`);
|
|
9826
|
-
}
|
|
9827
|
-
}
|
|
9828
|
-
return theme;
|
|
9829
|
-
};
|
|
9830
|
-
const injectErrorTheme = () => injectColorThemeByType('error');
|
|
9831
|
-
const injectWarningTheme = () => injectColorThemeByType('warning');
|
|
9832
|
-
const injectSuccessTheme = () => injectColorThemeByType('success');
|
|
9833
|
-
const injectDefaultColorTheme = () => {
|
|
9834
|
-
const themes = injectColorThemes({ optional: true });
|
|
9835
|
-
if (!themes) {
|
|
9836
|
-
throw new Error(`[injectDefaultColorTheme] No color themes provided. Call provideColorThemesWithTailwind4() in your app config.`);
|
|
9837
|
-
}
|
|
9838
|
-
const theme = themes.find((t) => t.isDefault);
|
|
9839
|
-
if (!theme) {
|
|
9840
|
-
throw new Error(`[injectDefaultColorTheme] No color theme with isDefault: true found. Mark one theme as the default in provideColorThemesWithTailwind4().`);
|
|
9841
|
-
}
|
|
9842
|
-
if (isDevMode()) {
|
|
9843
|
-
const duplicates = themes.filter((t) => t.isDefault);
|
|
9844
|
-
if (duplicates.length > 1) {
|
|
9845
|
-
console.error(`[injectDefaultColorTheme] Multiple themes with isDefault: true found: ${duplicates.map((t) => t.name).join(', ')}. Only the first one will be used.`);
|
|
9846
|
-
}
|
|
9847
|
-
}
|
|
9848
|
-
return theme;
|
|
10274
|
+
const injectSurfaceColorPalette = () => {
|
|
10275
|
+
const config = injectColorPaletteConfig({ optional: true });
|
|
10276
|
+
const surface = injectParentSurface();
|
|
10277
|
+
return computed(() => (config ? selectPalette(config, surface()?.name ?? null) : null));
|
|
9849
10278
|
};
|
|
10279
|
+
const COLOR_PALETTE = /* @__PURE__ */ toToken(COLOR_PALETTE_DEF);
|
|
9850
10280
|
|
|
9851
10281
|
/** Reads the nonce where Angular's default `CSP_NONCE` does, since these run outside any injector. */
|
|
9852
10282
|
const createNoncedStyle = () => {
|
|
@@ -10049,127 +10479,6 @@ const provideColorThemes = (themes) => {
|
|
|
10049
10479
|
return [ɵProvideColorThemes(themes), ɵProvideColorThemesPrefix('et')];
|
|
10050
10480
|
};
|
|
10051
10481
|
|
|
10052
|
-
const COLOR_PROVIDER = new InjectionToken('ColorProvider');
|
|
10053
|
-
/**
|
|
10054
|
-
* The color provider attached to a bootstrapped root component (e.g. `ProvideColorDirective` in
|
|
10055
|
-
* the app component's `hostDirectives`), if any. Detached DOM such as overlay panes can't reach
|
|
10056
|
-
* it through element DI, so overlay containers fall back to this when resolving the provider to
|
|
10057
|
-
* `syncWithProvider()` - resolve at sync time, not at injection time, since root components only
|
|
10058
|
-
* register with `ApplicationRef` once bootstrap completes.
|
|
10059
|
-
*/
|
|
10060
|
-
const resolveAppRootColorProvider = (appRef) => {
|
|
10061
|
-
for (const componentRef of appRef.components) {
|
|
10062
|
-
const provider = componentRef.injector.get(COLOR_PROVIDER, null);
|
|
10063
|
-
if (provider) {
|
|
10064
|
-
return provider;
|
|
10065
|
-
}
|
|
10066
|
-
}
|
|
10067
|
-
return null;
|
|
10068
|
-
};
|
|
10069
|
-
const FORCED_COLOR_UNSET = /* @__PURE__ */ Symbol('FORCED_COLOR_UNSET');
|
|
10070
|
-
class ProvideColorDirective {
|
|
10071
|
-
constructor() {
|
|
10072
|
-
this.themes = injectColorThemes({ optional: true });
|
|
10073
|
-
this.prefix = injectColorThemesPrefix({ optional: true });
|
|
10074
|
-
this.injector = inject(Injector);
|
|
10075
|
-
this.parentProvider = inject(COLOR_PROVIDER, { optional: true, skipSelf: true });
|
|
10076
|
-
this.currentProviderSync = null;
|
|
10077
|
-
this.forcedColor = signal(FORCED_COLOR_UNSET, /* @ts-ignore */
|
|
10078
|
-
...(ngDevMode ? [{ debugName: "forcedColor" }] : /* istanbul ignore next */ []));
|
|
10079
|
-
this.color = input(undefined, { ...(ngDevMode ? { debugName: "color" } : /* istanbul ignore next */ {}), alias: 'etProvideColor' });
|
|
10080
|
-
this.effectiveColor = computed(() => {
|
|
10081
|
-
const forcedColor = this.forcedColor();
|
|
10082
|
-
if (forcedColor !== FORCED_COLOR_UNSET) {
|
|
10083
|
-
return forcedColor;
|
|
10084
|
-
}
|
|
10085
|
-
return this.color();
|
|
10086
|
-
}, /* @ts-ignore */
|
|
10087
|
-
...(ngDevMode ? [{ debugName: "effectiveColor" }] : /* istanbul ignore next */ []));
|
|
10088
|
-
/**
|
|
10089
|
-
* The color that actually applies at this provider's location: its own effective color, or -
|
|
10090
|
-
* when this provider is passive (no input, nothing forced) - the nearest ancestor provider's.
|
|
10091
|
-
* Mirrors the CSS cascade, which falls through a provider's `-color--inherited` scope class;
|
|
10092
|
-
* consumers that re-apply context across detached DOM (overlay panes) must use this instead
|
|
10093
|
-
* of `effectiveColor` or a passive in-between provider (e.g. a form field's) erases the theme.
|
|
10094
|
-
*/
|
|
10095
|
-
this.resolvedColor = computed(() => {
|
|
10096
|
-
const own = this.effectiveColor();
|
|
10097
|
-
const ownName = typeof own === 'object' && own !== null ? own.name : own;
|
|
10098
|
-
if (ownName) {
|
|
10099
|
-
return own;
|
|
10100
|
-
}
|
|
10101
|
-
return this.parentProvider?.resolvedColor();
|
|
10102
|
-
}, /* @ts-ignore */
|
|
10103
|
-
...(ngDevMode ? [{ debugName: "resolvedColor" }] : /* istanbul ignore next */ []));
|
|
10104
|
-
this.colorName = computed(() => {
|
|
10105
|
-
const raw = this.effectiveColor();
|
|
10106
|
-
const value = typeof raw === 'object' && raw !== null ? raw.name : raw;
|
|
10107
|
-
if (value === SURFACE_COLOR)
|
|
10108
|
-
return SURFACE_COLOR;
|
|
10109
|
-
if (!this.themes || !value)
|
|
10110
|
-
return;
|
|
10111
|
-
if (isDevMode() && !this.themes.some((theme) => theme.name === value)) {
|
|
10112
|
-
console.error(`Theme ${value} does not exist. Please make sure to add it to provideColorThemesWithTailwind4()`);
|
|
10113
|
-
}
|
|
10114
|
-
return createCssColorThemeName(value);
|
|
10115
|
-
}, /* @ts-ignore */
|
|
10116
|
-
...(ngDevMode ? [{ debugName: "colorName" }] : /* istanbul ignore next */ []));
|
|
10117
|
-
this.themeClass = computed(() => {
|
|
10118
|
-
const prefix = this.prefix || 'et';
|
|
10119
|
-
if (this.colorName()) {
|
|
10120
|
-
return `${prefix}-color--${this.colorName()}`;
|
|
10121
|
-
}
|
|
10122
|
-
return `${prefix}-color--inherited`;
|
|
10123
|
-
}, /* @ts-ignore */
|
|
10124
|
-
...(ngDevMode ? [{ debugName: "themeClass" }] : /* istanbul ignore next */ []));
|
|
10125
|
-
}
|
|
10126
|
-
syncWithProvider(provider) {
|
|
10127
|
-
this.currentProviderSync?.destroy();
|
|
10128
|
-
runInInjectionContext(this.injector, () => {
|
|
10129
|
-
this.currentProviderSync = effect(() => {
|
|
10130
|
-
const provideColor = provider.resolvedColor();
|
|
10131
|
-
untracked(() => {
|
|
10132
|
-
if (provideColor === undefined) {
|
|
10133
|
-
this.clearForcedColor();
|
|
10134
|
-
return;
|
|
10135
|
-
}
|
|
10136
|
-
this.forceColor(provideColor);
|
|
10137
|
-
});
|
|
10138
|
-
}, /* @ts-ignore */
|
|
10139
|
-
...(ngDevMode ? [{ debugName: "currentProviderSync" }] : /* istanbul ignore next */ []));
|
|
10140
|
-
});
|
|
10141
|
-
}
|
|
10142
|
-
stopSyncWithProvider() {
|
|
10143
|
-
const hadProviderSync = !!this.currentProviderSync;
|
|
10144
|
-
this.currentProviderSync?.destroy();
|
|
10145
|
-
this.currentProviderSync = null;
|
|
10146
|
-
if (hadProviderSync) {
|
|
10147
|
-
this.clearForcedColor();
|
|
10148
|
-
}
|
|
10149
|
-
}
|
|
10150
|
-
forceColor(color) {
|
|
10151
|
-
this.forcedColor.set(color);
|
|
10152
|
-
}
|
|
10153
|
-
clearForcedColor() {
|
|
10154
|
-
if (this.forcedColor() === FORCED_COLOR_UNSET) {
|
|
10155
|
-
return;
|
|
10156
|
-
}
|
|
10157
|
-
this.forcedColor.set(FORCED_COLOR_UNSET);
|
|
10158
|
-
}
|
|
10159
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ProvideColorDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
10160
|
-
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 }); }
|
|
10161
|
-
}
|
|
10162
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ProvideColorDirective, decorators: [{
|
|
10163
|
-
type: Directive,
|
|
10164
|
-
args: [{
|
|
10165
|
-
selector: '[etProvideColor]',
|
|
10166
|
-
providers: [{ provide: COLOR_PROVIDER, useExisting: ProvideColorDirective }],
|
|
10167
|
-
host: {
|
|
10168
|
-
'[class]': 'themeClass()',
|
|
10169
|
-
},
|
|
10170
|
-
}]
|
|
10171
|
-
}], propDecorators: { color: [{ type: i0.Input, args: [{ isSignal: true, alias: "etProvideColor", required: false }] }] } });
|
|
10172
|
-
|
|
10173
10482
|
class SurfaceInteractiveStylesComponent {
|
|
10174
10483
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: SurfaceInteractiveStylesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
10175
10484
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.6", type: SurfaceInteractiveStylesComponent, isStandalone: true, selector: "et-surface-interactive-styles", ngImport: i0, template: '', isInline: true, styles: ["@layer components{:where(.et-surface-interactive){--et-surface-interaction-rgb: var(--et-surface-interaction);--et-surface-interaction-solid: rgb(var(--et-surface-interaction-rgb))}@media(hover:hover){:where(.et-surface-interactive:hover){--et-surface-interaction-rgb: var(--et-surface-interaction-hover, var(--et-surface-interaction));--et-surface-interaction-solid: rgb(var(--et-surface-interaction-rgb))}}:where(.et-surface-interactive:focus-visible){--et-surface-interaction-rgb: var( --et-surface-interaction-focus, var(--et-surface-interaction-hover, var(--et-surface-interaction)) );--et-surface-interaction-solid: rgb(var(--et-surface-interaction-rgb))}:where(.et-surface-interactive:active){--et-surface-interaction-rgb: var( --et-surface-interaction-active, var(--et-surface-interaction-focus, var(--et-surface-interaction-hover, var(--et-surface-interaction))) );--et-surface-interaction-solid: rgb(var(--et-surface-interaction-rgb))}:where(.et-surface-interactive[disabled]),:where(.et-surface-interactive[aria-disabled=true]){--et-surface-interaction-rgb: var( --et-surface-interaction-disabled, var( --et-surface-interaction-active, var(--et-surface-interaction-focus, var(--et-surface-interaction-hover, var(--et-surface-interaction))) ) );--et-surface-interaction-solid: rgb(var(--et-surface-interaction-rgb))}}\n"], encapsulation: i0.ViewEncapsulation.None }); }
|
|
@@ -10210,11 +10519,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
|
|
|
10210
10519
|
|
|
10211
10520
|
// Generated from package.json by tools/scripts/generate-version.js - do not edit.
|
|
10212
10521
|
/** The version of `@ethlete/core` this build was cut from. */
|
|
10213
|
-
const CORE_VERSION = '5.0.0-next.
|
|
10522
|
+
const CORE_VERSION = '5.0.0-next.62';
|
|
10214
10523
|
|
|
10215
10524
|
/**
|
|
10216
10525
|
* Generated bundle index. Do not edit.
|
|
10217
10526
|
*/
|
|
10218
10527
|
|
|
10219
|
-
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_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_TITLE_MARKER, ValidateAtLeastOneRequired, 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,
|
|
10528
|
+
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, 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, 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, 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, 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 };
|
|
10220
10529
|
//# sourceMappingURL=ethlete-core.mjs.map
|