@ethlete/core 5.0.0-next.2 → 5.0.0-next.20
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 +131 -0
- package/fesm2022/ethlete-core.mjs +2903 -846
- package/fesm2022/ethlete-core.mjs.map +1 -1
- package/generators/generators.json +9 -4
- package/generators/migrate-to-v5/color-naming.js +175 -0
- package/generators/migrate-to-v5/migration.js +6 -0
- package/generators/migrate-to-v5/schema.json +5 -0
- package/generators/{tailwind-4-theme → tailwind-4-color-theme}/generator.js +141 -87
- package/generators/tailwind-4-color-theme/schema.json +40 -0
- package/generators/tailwind-4-surface-theme/generator.js +402 -0
- package/generators/tailwind-4-surface-theme/schema.json +40 -0
- package/package.json +14 -13
- package/types/ethlete-core.d.ts +1700 -1031
- package/generators/tailwind-4-theme/schema.json +0 -32
|
@@ -1,18 +1,42 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, inject, ElementRef, Directive, assertInInjectionContext, DestroyRef, TemplateRef, QueryList, NgZone, signal, isSignal, untracked,
|
|
3
|
-
import { takeUntilDestroyed,
|
|
4
|
-
import { Subject, BehaviorSubject, debounceTime, combineLatest, map, merge, fromEvent, filter, tap, switchMap, startWith, of, timer, takeUntil,
|
|
2
|
+
import { InjectionToken, inject, ElementRef, Directive, assertInInjectionContext, DestroyRef, TemplateRef, QueryList, NgZone, signal, isSignal, untracked, DOCUMENT, linkedSignal, isDevMode, computed, afterNextRender, effect, EnvironmentInjector, runInInjectionContext, Injector, booleanAttribute, numberAttribute, RendererStyleFlags2, PLATFORM_ID, ApplicationRef, RendererFactory2, createComponent, model, ViewContainerRef, input, output, inputBinding, outputBinding, Pipe, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import { takeUntilDestroyed, toSignal, toObservable, outputFromObservable } from '@angular/core/rxjs-interop';
|
|
4
|
+
import { Subject, BehaviorSubject, debounceTime, combineLatest, map, merge, fromEvent, filter, tap, switchMap, startWith, of, timer, takeUntil, pairwise, distinctUntilChanged, take, Observable, concatMap, EMPTY, concat, defer, exhaustMap, share } from 'rxjs';
|
|
5
5
|
import { FormGroup, FormArray, FormControl } from '@angular/forms';
|
|
6
6
|
import { SIGNAL, signalSetFn } from '@angular/core/primitives/signals';
|
|
7
|
-
import { coerceElement } from '@angular/cdk/coercion';
|
|
8
7
|
import { BreakpointObserver } from '@angular/cdk/layout';
|
|
9
|
-
import {
|
|
8
|
+
import { coerceElement } from '@angular/cdk/coercion';
|
|
9
|
+
import { DOCUMENT as DOCUMENT$1, isPlatformBrowser } from '@angular/common';
|
|
10
10
|
import { Router, NavigationEnd, NavigationSkipped } from '@angular/router';
|
|
11
11
|
import { Overlay } from '@angular/cdk/overlay';
|
|
12
12
|
import { ComponentPortal } from '@angular/cdk/portal';
|
|
13
13
|
import { autoUpdate, computePosition, offset, flip, size, shift, limitShift, arrow, hide } from '@floating-ui/dom';
|
|
14
14
|
import { Title, Meta, DomSanitizer } from '@angular/platform-browser';
|
|
15
15
|
|
|
16
|
+
const ANIMATION_DEBUG_STORAGE_KEY = 'et-overlay-debug';
|
|
17
|
+
let cachedEnabled = null;
|
|
18
|
+
/**
|
|
19
|
+
* Debug logging for overlay and animation lifecycle internals.
|
|
20
|
+
* Enable via `localStorage.setItem('et-overlay-debug', 'true')` and reload.
|
|
21
|
+
*/
|
|
22
|
+
const isAnimationDebugEnabled = () => {
|
|
23
|
+
if (cachedEnabled === null) {
|
|
24
|
+
try {
|
|
25
|
+
cachedEnabled = globalThis.localStorage?.getItem(ANIMATION_DEBUG_STORAGE_KEY) === 'true';
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
cachedEnabled = false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return cachedEnabled;
|
|
32
|
+
};
|
|
33
|
+
const animationDebugLog = (scope, ...args) => {
|
|
34
|
+
if (!isAnimationDebugEnabled())
|
|
35
|
+
return;
|
|
36
|
+
const timestamp = (globalThis.performance?.now() ?? 0).toFixed(1);
|
|
37
|
+
console.log(`\x1B[36m[et-overlay-debug ${timestamp}ms | ${scope}]\x1B[m`, ...args);
|
|
38
|
+
};
|
|
39
|
+
|
|
16
40
|
const ANIMATABLE_TOKEN = new InjectionToken('ANIMATABLE_DIRECTIVE_TOKEN');
|
|
17
41
|
class AnimatableDirective {
|
|
18
42
|
constructor() {
|
|
@@ -31,7 +55,7 @@ class AnimatableDirective {
|
|
|
31
55
|
this.isAnimating$ = this.totalActiveAnimationCount$.pipe(map((count) => count > 0));
|
|
32
56
|
let didEmitStart = false;
|
|
33
57
|
const el = this.elementRef.nativeElement;
|
|
34
|
-
merge(merge(fromEvent(el, 'animationstart'), fromEvent(el, '
|
|
58
|
+
merge(merge(fromEvent(el, 'animationstart'), fromEvent(el, 'transitionrun')).pipe(filter((e) => e.target === el && !e.pseudoElement), map(() => 'start')), merge(fromEvent(el, 'animationend'), fromEvent(el, 'transitionend')).pipe(filter((e) => e.target === el && !e.pseudoElement), map(() => 'end')), merge(fromEvent(el, 'animationcancel'), fromEvent(el, 'transitioncancel')).pipe(filter((e) => e.target === el && !e.pseudoElement), map(() => 'cancel')))
|
|
35
59
|
.pipe(tap((eventType) => {
|
|
36
60
|
switch (eventType) {
|
|
37
61
|
case 'start': {
|
|
@@ -40,6 +64,7 @@ class AnimatableDirective {
|
|
|
40
64
|
if (startingNewBatch) {
|
|
41
65
|
this.activeBatchTransitionId = this.pendingTransitionIds.shift();
|
|
42
66
|
}
|
|
67
|
+
animationDebugLog(`animatable ${el.tagName.toLowerCase()}`, `start (count ${this.activeAnimationCount}, batch "${this.activeBatchTransitionId}", pending [${this.pendingTransitionIds.join(', ')}])`);
|
|
43
68
|
if (!didEmitStart) {
|
|
44
69
|
didEmitStart = true;
|
|
45
70
|
this.animationStartSubject$.next();
|
|
@@ -50,6 +75,7 @@ class AnimatableDirective {
|
|
|
50
75
|
case 'cancel': {
|
|
51
76
|
if (this.activeAnimationCount > 0) {
|
|
52
77
|
this.updateActiveAnimationCount(-1);
|
|
78
|
+
animationDebugLog(`animatable ${el.tagName.toLowerCase()}`, `${eventType} (count ${this.activeAnimationCount}, batch "${this.activeBatchTransitionId}")`);
|
|
53
79
|
if (this.activeAnimationCount === 0 && didEmitStart) {
|
|
54
80
|
didEmitStart = false;
|
|
55
81
|
this.animationEndSubject$.next({
|
|
@@ -60,6 +86,7 @@ class AnimatableDirective {
|
|
|
60
86
|
}
|
|
61
87
|
}
|
|
62
88
|
else {
|
|
89
|
+
animationDebugLog(`animatable ${el.tagName.toLowerCase()}`, `${eventType} ignored — count already 0 (start ${didEmitStart ? '' : 'not '}emitted)`);
|
|
63
90
|
console.warn(`${el.tagName} received animation end/cancel event but activeAnimationCount is already 0. Start was ${didEmitStart ? '' : 'not '}emitted.`);
|
|
64
91
|
}
|
|
65
92
|
break;
|
|
@@ -77,15 +104,15 @@ class AnimatableDirective {
|
|
|
77
104
|
this.activeAnimationCount = clampedVal;
|
|
78
105
|
this.hostActiveAnimationCount$.next(clampedVal);
|
|
79
106
|
}
|
|
80
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
81
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "
|
|
107
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: AnimatableDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
108
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.5", type: AnimatableDirective, isStandalone: true, selector: "[etAnimatable]", providers: [
|
|
82
109
|
{
|
|
83
110
|
provide: ANIMATABLE_TOKEN,
|
|
84
111
|
useExisting: AnimatableDirective,
|
|
85
112
|
},
|
|
86
113
|
], exportAs: ["etAnimatable"], ngImport: i0 }); }
|
|
87
114
|
}
|
|
88
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
115
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: AnimatableDirective, decorators: [{
|
|
89
116
|
type: Directive,
|
|
90
117
|
args: [{
|
|
91
118
|
selector: '[etAnimatable]',
|
|
@@ -623,7 +650,8 @@ const signalAnimatedNumber = (source, options = {}) => {
|
|
|
623
650
|
const easing = options.easing ?? easeOut;
|
|
624
651
|
const round = options.round ?? ((v) => Math.round(v));
|
|
625
652
|
const initialValue = options.initialValue ?? 0;
|
|
626
|
-
const animatedValue = signal(initialValue,
|
|
653
|
+
const animatedValue = signal(initialValue, /* @ts-ignore */
|
|
654
|
+
...(ngDevMode ? [{ debugName: "animatedValue" }] : /* istanbul ignore next */ []));
|
|
627
655
|
let rafId = null;
|
|
628
656
|
let currentAnimatedValue = initialValue;
|
|
629
657
|
const cancelAnimation = () => {
|
|
@@ -710,41 +738,82 @@ const easeOutBackStrong = (t) => {
|
|
|
710
738
|
return 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2);
|
|
711
739
|
};
|
|
712
740
|
|
|
713
|
-
const
|
|
714
|
-
const getRawValueSafe = (ctrl) => {
|
|
715
|
-
try {
|
|
716
|
-
return isSignal(ctrl) ? (ctrl()?.getRawValue() ?? null) : (ctrl?.getRawValue() ?? null);
|
|
717
|
-
}
|
|
718
|
-
catch {
|
|
719
|
-
// Ignore errors. This can happen if the passed control is a required input and is not yet initialized.
|
|
720
|
-
return null;
|
|
721
|
-
}
|
|
722
|
-
};
|
|
723
|
-
const initialValue = getRawValueSafe(control);
|
|
724
|
-
const controlStream = isSignal(control)
|
|
725
|
-
? toObservable(control)
|
|
726
|
-
: of(control);
|
|
727
|
-
const controlObs = controlStream.pipe(switchMap((ctrl) => {
|
|
728
|
-
if (!ctrl)
|
|
729
|
-
return of(null);
|
|
730
|
-
const vcsObs = options?.debounceTime
|
|
731
|
-
? ctrl.valueChanges.pipe(debounceTime(options.debounceTime))
|
|
732
|
-
: ctrl.valueChanges;
|
|
733
|
-
return vcsObs.pipe(startWith(ctrl.getRawValue()), map(() => ctrl.getRawValue()));
|
|
734
|
-
}));
|
|
735
|
-
const obs = !options?.debounceFirst ? merge(of(initialValue), controlObs) : controlObs;
|
|
736
|
-
return toSignal(obs.pipe(distinctUntilChanged((a, b) => equal(a, b))), {
|
|
737
|
-
initialValue,
|
|
738
|
-
});
|
|
739
|
-
};
|
|
741
|
+
const BREAKPOINT_ORDER = ['xs', 'sm', 'md', 'lg', 'xl', '2xl'];
|
|
740
742
|
/**
|
|
741
|
-
*
|
|
743
|
+
* Default viewport config based on Tailwind CSS.
|
|
744
|
+
* @see https://tailwindcss.com/docs/screens
|
|
742
745
|
*/
|
|
743
|
-
const
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
746
|
+
const DEFAULT_VIEWPORT_CONFIG = {
|
|
747
|
+
breakpoints: {
|
|
748
|
+
xs: [0, 639],
|
|
749
|
+
sm: [640, 767],
|
|
750
|
+
md: [768, 1023],
|
|
751
|
+
lg: [1024, 1279],
|
|
752
|
+
xl: [1280, 1535],
|
|
753
|
+
'2xl': [1536, Infinity],
|
|
754
|
+
},
|
|
747
755
|
};
|
|
756
|
+
const [provideViewportConfig, injectViewportConfig] = createStaticRootProvider(DEFAULT_VIEWPORT_CONFIG, {
|
|
757
|
+
name: 'Viewport Config',
|
|
758
|
+
});
|
|
759
|
+
const [provideBreakpointObserver, injectBreakpointObserver] = createRootProvider(() => {
|
|
760
|
+
const breakpointObserver = inject(BreakpointObserver);
|
|
761
|
+
const viewportConfig = injectViewportConfig();
|
|
762
|
+
const isMediaQueryMatched = (mediaQuery) => breakpointObserver.isMatched(mediaQuery);
|
|
763
|
+
const observeMediaQuery = (mediaQuery) => {
|
|
764
|
+
return toSignal(breakpointObserver.observe(mediaQuery).pipe(map((x) => x.matches), startWith(isMediaQueryMatched(mediaQuery))), { requireSync: true });
|
|
765
|
+
};
|
|
766
|
+
const observeBreakpoint = (options) => observeMediaQuery(buildMediaQueryString(options));
|
|
767
|
+
const isBreakpointMatched = (options) => isMediaQueryMatched(buildMediaQueryString(options));
|
|
768
|
+
const getBreakpointSize = (type, option) => {
|
|
769
|
+
const index = option === 'min' ? 0 : 1;
|
|
770
|
+
const size = viewportConfig.breakpoints[type][index];
|
|
771
|
+
if (size === Infinity || size === 0) {
|
|
772
|
+
return size;
|
|
773
|
+
}
|
|
774
|
+
if (option === 'min') {
|
|
775
|
+
return size;
|
|
776
|
+
}
|
|
777
|
+
// Due to scaling, the actual size of the viewport may be a decimal number.
|
|
778
|
+
// Eg. on Windows 11 with 150% scaling, the viewport size may be 1535.33px
|
|
779
|
+
// and thus not matching any of the default breakpoints.
|
|
780
|
+
return size + 0.9;
|
|
781
|
+
};
|
|
782
|
+
const buildMediaQueryString = (options) => {
|
|
783
|
+
if (!options.min && !options.max) {
|
|
784
|
+
throw new Error('At least one of min or max must be defined');
|
|
785
|
+
}
|
|
786
|
+
const mediaQueryParts = [];
|
|
787
|
+
if (options.min) {
|
|
788
|
+
if (typeof options.min === 'number') {
|
|
789
|
+
mediaQueryParts.push(`(min-width: ${options.min}px)`);
|
|
790
|
+
}
|
|
791
|
+
else {
|
|
792
|
+
mediaQueryParts.push(`(min-width: ${getBreakpointSize(options.min, 'min')}px)`);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
if (options.min && options.max) {
|
|
796
|
+
mediaQueryParts.push('and');
|
|
797
|
+
}
|
|
798
|
+
if (options.max) {
|
|
799
|
+
if (typeof options.max === 'number') {
|
|
800
|
+
mediaQueryParts.push(`(max-width: ${options.max}px)`);
|
|
801
|
+
}
|
|
802
|
+
else {
|
|
803
|
+
mediaQueryParts.push(`(max-width: ${getBreakpointSize(options.max, 'max')}px)`);
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
return mediaQueryParts.join(' ');
|
|
807
|
+
};
|
|
808
|
+
return {
|
|
809
|
+
observeBreakpoint,
|
|
810
|
+
isBreakpointMatched,
|
|
811
|
+
getBreakpointSize,
|
|
812
|
+
buildMediaQueryString,
|
|
813
|
+
observeMediaQuery,
|
|
814
|
+
isMediaQueryMatched,
|
|
815
|
+
};
|
|
816
|
+
}, { name: 'Breakpoint Observer' });
|
|
748
817
|
|
|
749
818
|
const isElementSignal = (el) => {
|
|
750
819
|
if (!isSignal(el))
|
|
@@ -860,12 +929,14 @@ const firstElementSignal = (el) => computed(() => {
|
|
|
860
929
|
});
|
|
861
930
|
|
|
862
931
|
const signalIsRendered = () => {
|
|
863
|
-
const isRendered = signal(false,
|
|
932
|
+
const isRendered = signal(false, /* @ts-ignore */
|
|
933
|
+
...(ngDevMode ? [{ debugName: "isRendered" }] : /* istanbul ignore next */ []));
|
|
864
934
|
afterNextRender(() => isRendered.set(true));
|
|
865
935
|
return isRendered.asReadonly();
|
|
866
936
|
};
|
|
867
937
|
const createIsRenderedSignal = () => {
|
|
868
|
-
const value = signal(false,
|
|
938
|
+
const value = signal(false, /* @ts-ignore */
|
|
939
|
+
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
869
940
|
nextFrame(() => {
|
|
870
941
|
if (!value()) {
|
|
871
942
|
console.error('Render signal was not set to true. This can cause unexpected behavior. Make sure to .bind() the render signal at the end of the constructor.');
|
|
@@ -877,7 +948,8 @@ const createIsRenderedSignal = () => {
|
|
|
877
948
|
};
|
|
878
949
|
};
|
|
879
950
|
const createCanAnimateSignal = () => {
|
|
880
|
-
const value = signal(false,
|
|
951
|
+
const value = signal(false, /* @ts-ignore */
|
|
952
|
+
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
881
953
|
nextFrame(() => {
|
|
882
954
|
value.set(true);
|
|
883
955
|
});
|
|
@@ -886,95 +958,542 @@ const createCanAnimateSignal = () => {
|
|
|
886
958
|
};
|
|
887
959
|
};
|
|
888
960
|
|
|
889
|
-
const
|
|
961
|
+
const boundingClientRectToElementRect = (rect) => ({
|
|
962
|
+
bottom: rect.bottom,
|
|
963
|
+
height: rect.height,
|
|
964
|
+
left: rect.left,
|
|
965
|
+
right: rect.right,
|
|
966
|
+
top: rect.top,
|
|
967
|
+
width: rect.width,
|
|
968
|
+
x: rect.x,
|
|
969
|
+
y: rect.y,
|
|
970
|
+
});
|
|
971
|
+
const createElementDimensions = (el, rect) => {
|
|
972
|
+
if (!el) {
|
|
973
|
+
return {
|
|
974
|
+
rect: null,
|
|
975
|
+
client: null,
|
|
976
|
+
scroll: null,
|
|
977
|
+
offset: null,
|
|
978
|
+
};
|
|
979
|
+
}
|
|
980
|
+
const cachedNormalizedRect = rect ? boundingClientRectToElementRect(rect) : null;
|
|
981
|
+
const rectFn = () => cachedNormalizedRect ? cachedNormalizedRect : boundingClientRectToElementRect(el.getBoundingClientRect());
|
|
982
|
+
return {
|
|
983
|
+
rect: rectFn,
|
|
984
|
+
client: { width: el.clientWidth, height: el.clientHeight },
|
|
985
|
+
scroll: { width: el.scrollWidth, height: el.scrollHeight },
|
|
986
|
+
offset: { width: el.offsetWidth, height: el.offsetHeight },
|
|
987
|
+
};
|
|
988
|
+
};
|
|
989
|
+
const signalElementDimensions = (el) => {
|
|
890
990
|
const destroyRef = inject(DestroyRef);
|
|
891
991
|
const elements = buildElementSignal(el);
|
|
892
992
|
const firstEl = firstElementSignal(elements);
|
|
893
993
|
const zone = inject(NgZone);
|
|
894
994
|
const isRendered = signalIsRendered();
|
|
895
|
-
const
|
|
896
|
-
const
|
|
995
|
+
const initialValue = () => createElementDimensions(firstEl().currentElement);
|
|
996
|
+
const elementDimensionsSignal = signal(initialValue(), /* @ts-ignore */
|
|
997
|
+
...(ngDevMode ? [{ debugName: "elementDimensionsSignal" }] : /* istanbul ignore next */ []));
|
|
998
|
+
const observer = new ResizeObserver((e) => {
|
|
897
999
|
if (!isRendered())
|
|
898
1000
|
return;
|
|
899
1001
|
const entry = e[0];
|
|
900
1002
|
if (entry) {
|
|
901
|
-
|
|
1003
|
+
const target = entry.target;
|
|
1004
|
+
const newDimensions = createElementDimensions(target);
|
|
1005
|
+
zone.run(() => elementDimensionsSignal.set(newDimensions));
|
|
902
1006
|
}
|
|
903
1007
|
});
|
|
904
1008
|
effect(() => {
|
|
905
1009
|
const els = firstEl();
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
1010
|
+
untracked(() => {
|
|
1011
|
+
elementDimensionsSignal.set(initialValue());
|
|
1012
|
+
if (els.previousElement) {
|
|
1013
|
+
observer.disconnect();
|
|
1014
|
+
}
|
|
1015
|
+
if (els.currentElement) {
|
|
1016
|
+
const computedDisplay = getComputedStyle(els.currentElement).display;
|
|
1017
|
+
const currentElIsAngularComponent = els.currentElement?.tagName.toLowerCase().includes('-');
|
|
1018
|
+
if (computedDisplay === 'inline' && isDevMode() && currentElIsAngularComponent) {
|
|
1019
|
+
console.error(`Element <${els.currentElement?.tagName.toLowerCase()}> is an Angular component and has a display of 'inline'. Inline elements cannot be observed for dimensions. Please change it to 'block' or something else.`);
|
|
1020
|
+
}
|
|
1021
|
+
observer.observe(els.currentElement);
|
|
1022
|
+
}
|
|
1023
|
+
});
|
|
913
1024
|
});
|
|
914
1025
|
destroyRef.onDestroy(() => observer.disconnect());
|
|
915
|
-
return
|
|
1026
|
+
return computed(() => elementDimensionsSignal(), {
|
|
1027
|
+
equal: (a, b) => equal(a, b),
|
|
1028
|
+
});
|
|
916
1029
|
};
|
|
917
|
-
const
|
|
918
|
-
|
|
919
|
-
const
|
|
920
|
-
const
|
|
921
|
-
const
|
|
922
|
-
const
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
}
|
|
1030
|
+
const signalHostElementDimensions = () => signalElementDimensions(inject(ElementRef));
|
|
1031
|
+
const injectViewportSize = () => {
|
|
1032
|
+
const document = inject(DOCUMENT$1);
|
|
1033
|
+
const zone = inject(NgZone);
|
|
1034
|
+
const destroyRef = inject(DestroyRef);
|
|
1035
|
+
const getSize = () => {
|
|
1036
|
+
const vv = document.defaultView?.visualViewport;
|
|
1037
|
+
if (vv)
|
|
1038
|
+
return { width: vv.width, height: vv.height };
|
|
1039
|
+
const win = document.defaultView;
|
|
1040
|
+
return { width: win?.innerWidth ?? 0, height: win?.innerHeight ?? 0 };
|
|
1041
|
+
};
|
|
1042
|
+
const size = signal(getSize(), /* @ts-ignore */
|
|
1043
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
1044
|
+
const onResize = () => zone.run(() => size.set(getSize()));
|
|
1045
|
+
const vv = document.defaultView?.visualViewport;
|
|
1046
|
+
if (vv) {
|
|
1047
|
+
vv.addEventListener('resize', onResize);
|
|
1048
|
+
destroyRef.onDestroy(() => vv.removeEventListener('resize', onResize));
|
|
1049
|
+
}
|
|
1050
|
+
else {
|
|
1051
|
+
const win = document.defaultView;
|
|
1052
|
+
win?.addEventListener('resize', onResize);
|
|
1053
|
+
destroyRef.onDestroy(() => win?.removeEventListener('resize', onResize));
|
|
1054
|
+
}
|
|
1055
|
+
return size;
|
|
942
1056
|
};
|
|
943
1057
|
|
|
944
|
-
const
|
|
945
|
-
const
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
if (!tokens.length)
|
|
956
|
-
continue;
|
|
957
|
-
config.cleanupFn(previousEl, tokens);
|
|
1058
|
+
const previousSignalValue = (signal) => {
|
|
1059
|
+
const obs = toObservable(signal).pipe(pairwise(), map(([prev]) => prev));
|
|
1060
|
+
return toSignal(obs);
|
|
1061
|
+
};
|
|
1062
|
+
const syncSignal = (from, to, options) => {
|
|
1063
|
+
let isFirstRun = options?.skipSyncRead ? false : true;
|
|
1064
|
+
if (!options?.skipSyncRead) {
|
|
1065
|
+
try {
|
|
1066
|
+
// this might throw if the signal is not yet initialized (eg. a required signal input inside the constructor)
|
|
1067
|
+
// in that case we just skip the initial sync
|
|
1068
|
+
to.set(from());
|
|
958
1069
|
}
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
untracked(() => {
|
|
964
|
-
const tokenArray = tokens.split(' ');
|
|
965
|
-
if (!tokenArray.length)
|
|
966
|
-
return;
|
|
967
|
-
config.updateFn(currentEl, tokenArray, condition());
|
|
968
|
-
});
|
|
1070
|
+
catch {
|
|
1071
|
+
isFirstRun = false;
|
|
1072
|
+
if (isDevMode()) {
|
|
1073
|
+
console.warn('Failed to sync signals. The target signal is not yet initialized.', { from, to });
|
|
969
1074
|
}
|
|
970
1075
|
}
|
|
971
|
-
}
|
|
972
|
-
const
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
return;
|
|
977
|
-
|
|
1076
|
+
}
|
|
1077
|
+
const ref = effect(() => {
|
|
1078
|
+
const formVal = from();
|
|
1079
|
+
if (options?.skipFirstRun && isFirstRun) {
|
|
1080
|
+
isFirstRun = false;
|
|
1081
|
+
return;
|
|
1082
|
+
}
|
|
1083
|
+
untracked(() => {
|
|
1084
|
+
to.set(formVal);
|
|
1085
|
+
});
|
|
1086
|
+
}, /* @ts-ignore */
|
|
1087
|
+
...(ngDevMode ? [{ debugName: "ref" }] : /* istanbul ignore next */ []));
|
|
1088
|
+
return ref;
|
|
1089
|
+
};
|
|
1090
|
+
const maybeSignalValue = (value) => {
|
|
1091
|
+
if (isSignal(value)) {
|
|
1092
|
+
return value();
|
|
1093
|
+
}
|
|
1094
|
+
return value;
|
|
1095
|
+
};
|
|
1096
|
+
/**
|
|
1097
|
+
* A computed that will only be reactive until the source signal contains a truthy value.
|
|
1098
|
+
* All subsequent changes inside the computation will be ignored.
|
|
1099
|
+
*/
|
|
1100
|
+
const computedTillTruthy = (source) => {
|
|
1101
|
+
const value = signal(null, /* @ts-ignore */
|
|
1102
|
+
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
1103
|
+
const ref = effect(() => {
|
|
1104
|
+
const val = source();
|
|
1105
|
+
if (val) {
|
|
1106
|
+
value.set(val);
|
|
1107
|
+
ref.destroy();
|
|
1108
|
+
}
|
|
1109
|
+
}, /* @ts-ignore */
|
|
1110
|
+
...(ngDevMode ? [{ debugName: "ref" }] : /* istanbul ignore next */ []));
|
|
1111
|
+
return value.asReadonly();
|
|
1112
|
+
};
|
|
1113
|
+
/**
|
|
1114
|
+
* A computed that will only be reactive until the source signal contains a falsy value.
|
|
1115
|
+
* All subsequent changes inside the computation will be ignored.
|
|
1116
|
+
*/
|
|
1117
|
+
const computedTillFalsy = (source) => {
|
|
1118
|
+
const value = signal(null, /* @ts-ignore */
|
|
1119
|
+
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
1120
|
+
const ref = effect(() => {
|
|
1121
|
+
const val = source();
|
|
1122
|
+
if (!val) {
|
|
1123
|
+
value.set(val);
|
|
1124
|
+
ref.destroy();
|
|
1125
|
+
}
|
|
1126
|
+
}, /* @ts-ignore */
|
|
1127
|
+
...(ngDevMode ? [{ debugName: "ref" }] : /* istanbul ignore next */ []));
|
|
1128
|
+
return value.asReadonly();
|
|
1129
|
+
};
|
|
1130
|
+
/**
|
|
1131
|
+
* A writeable signal that will be set to the provided value once all inputs are set.
|
|
1132
|
+
* During that time, the signal will be set to `null`.
|
|
1133
|
+
*/
|
|
1134
|
+
const deferredSignal = (valueFn) => {
|
|
1135
|
+
const valueSignal = signal(null, /* @ts-ignore */
|
|
1136
|
+
...(ngDevMode ? [{ debugName: "valueSignal" }] : /* istanbul ignore next */ []));
|
|
1137
|
+
afterNextRender(() => {
|
|
1138
|
+
valueSignal.set(valueFn());
|
|
1139
|
+
});
|
|
1140
|
+
return valueSignal;
|
|
1141
|
+
};
|
|
1142
|
+
const memoizeSignal = (factory) => {
|
|
1143
|
+
const cache = new WeakMap();
|
|
1144
|
+
return () => {
|
|
1145
|
+
const envInjector = inject(EnvironmentInjector);
|
|
1146
|
+
let cached = cache.get(envInjector);
|
|
1147
|
+
if (!cached) {
|
|
1148
|
+
cached = runInInjectionContext(envInjector, factory);
|
|
1149
|
+
cache.set(envInjector, cached);
|
|
1150
|
+
}
|
|
1151
|
+
return cached;
|
|
1152
|
+
};
|
|
1153
|
+
};
|
|
1154
|
+
|
|
1155
|
+
/** Inject a signal containing a boolean value indicating if the viewport is xs */
|
|
1156
|
+
const injectIsXs = memoizeSignal(() => injectObserveBreakpoint({ max: 'xs' }));
|
|
1157
|
+
/** Inject a signal containing a boolean value indicating if the viewport is sm */
|
|
1158
|
+
const injectIsSm = memoizeSignal(() => injectObserveBreakpoint({ min: 'sm', max: 'sm' }));
|
|
1159
|
+
/** Inject a signal containing a boolean value indicating if the viewport is md */
|
|
1160
|
+
const injectIsMd = memoizeSignal(() => injectObserveBreakpoint({ min: 'md', max: 'md' }));
|
|
1161
|
+
/** Inject a signal containing a boolean value indicating if the viewport is lg */
|
|
1162
|
+
const injectIsLg = memoizeSignal(() => injectObserveBreakpoint({ min: 'lg', max: 'lg' }));
|
|
1163
|
+
/** Inject a signal containing a boolean value indicating if the viewport is xl */
|
|
1164
|
+
const injectIsXl = memoizeSignal(() => injectObserveBreakpoint({ min: 'xl', max: 'xl' }));
|
|
1165
|
+
/** Inject a signal containing a boolean value indicating if the viewport is 2xl */
|
|
1166
|
+
const injectIs2Xl = memoizeSignal(() => injectObserveBreakpoint({ min: '2xl' }));
|
|
1167
|
+
/**
|
|
1168
|
+
* Inject a boolean value indicating if the viewport is matching the provided options.
|
|
1169
|
+
* This value is not reactive. If you want to react to changes, use the {@link injectObserveBreakpoint} function instead.
|
|
1170
|
+
*/
|
|
1171
|
+
const injectBreakpointIsMatched = (options) => injectBreakpointObserver().isBreakpointMatched(options);
|
|
1172
|
+
/**
|
|
1173
|
+
* Inject a boolean value indicating if the media query is matched.
|
|
1174
|
+
* This value is not reactive. If you want to react to changes, use the {@link injectObserveMediaQuery} function instead.
|
|
1175
|
+
*/
|
|
1176
|
+
const injectMediaQueryIsMatched = (mediaQuery) => injectBreakpointObserver().isMediaQueryMatched(mediaQuery);
|
|
1177
|
+
/**
|
|
1178
|
+
* Inject a signal containing a boolean value indicating if the viewport is matching the provided options.
|
|
1179
|
+
*/
|
|
1180
|
+
const injectObserveBreakpoint = (options) => injectBreakpointObserver().observeBreakpoint(options);
|
|
1181
|
+
/**
|
|
1182
|
+
* Inject a signal containing a boolean value indicating if the media query is matched.
|
|
1183
|
+
*/
|
|
1184
|
+
const injectObserveMediaQuery = (mediaQuery) => injectBreakpointObserver().observeMediaQuery(mediaQuery);
|
|
1185
|
+
/** Inject a signal containing the current breakpoint. */
|
|
1186
|
+
const injectCurrentBreakpoint = memoizeSignal(() => {
|
|
1187
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1188
|
+
const first = BREAKPOINT_ORDER[0];
|
|
1189
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1190
|
+
const last = BREAKPOINT_ORDER[BREAKPOINT_ORDER.length - 1];
|
|
1191
|
+
const highToLow = [...BREAKPOINT_ORDER].reverse();
|
|
1192
|
+
const signals = highToLow.map((bp) => injectObserveBreakpoint(bp === first ? { max: bp } : bp === last ? { min: bp } : { min: bp, max: bp }));
|
|
1193
|
+
return computed(() => {
|
|
1194
|
+
for (let i = 0; i < highToLow.length; i++) {
|
|
1195
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1196
|
+
if (signals[i]())
|
|
1197
|
+
return highToLow[i];
|
|
1198
|
+
}
|
|
1199
|
+
return first;
|
|
1200
|
+
});
|
|
1201
|
+
});
|
|
1202
|
+
/** Inject a signal that indicates if the user is using a portrait display */
|
|
1203
|
+
const injectIsPortrait = memoizeSignal(() => injectObserveMediaQuery('(orientation: portrait)'));
|
|
1204
|
+
/** Inject a signal that indicates if the user is using a landscape display */
|
|
1205
|
+
const injectIsLandscape = memoizeSignal(() => injectObserveMediaQuery('(orientation: landscape)'));
|
|
1206
|
+
/** Inject a signal containing the current display orientation */
|
|
1207
|
+
const injectDisplayOrientation = memoizeSignal(() => {
|
|
1208
|
+
const isPortrait = injectIsPortrait();
|
|
1209
|
+
return computed(() => {
|
|
1210
|
+
if (isPortrait())
|
|
1211
|
+
return 'portrait';
|
|
1212
|
+
return 'landscape';
|
|
1213
|
+
});
|
|
1214
|
+
});
|
|
1215
|
+
/** Inject a signal that indicates if the device has a touch input */
|
|
1216
|
+
const injectHasTouchInput = memoizeSignal(() => injectObserveMediaQuery('(pointer: coarse)'));
|
|
1217
|
+
/** Inject a signal that indicates if the device has a fine input (mouse or stylus) */
|
|
1218
|
+
const injectHasPrecisionInput = memoizeSignal(() => injectObserveMediaQuery('(pointer: fine)'));
|
|
1219
|
+
/** Inject a signal containing the current device input type */
|
|
1220
|
+
const injectDeviceInputType = memoizeSignal(() => {
|
|
1221
|
+
const isTouch = injectHasTouchInput();
|
|
1222
|
+
return computed(() => {
|
|
1223
|
+
if (isTouch())
|
|
1224
|
+
return 'touch';
|
|
1225
|
+
return 'mouse';
|
|
1226
|
+
});
|
|
1227
|
+
});
|
|
1228
|
+
/** Inject a signal containing a boolean value indicating if the user can hover (eg. using a mouse) */
|
|
1229
|
+
const injectCanHover = memoizeSignal(() => injectObserveMediaQuery('(hover: hover)'));
|
|
1230
|
+
/** Inject a signal containing the viewport dimensions */
|
|
1231
|
+
const injectViewportDimensions = memoizeSignal(() => signalElementDimensions(createDocumentElementSignal()));
|
|
1232
|
+
/** Inject a signal containing the scrollbar dimensions. Dimensions will be 0 if scrollbars overlap the page contents (like on mobile). */
|
|
1233
|
+
const injectScrollbarDimensions = memoizeSignal(() => {
|
|
1234
|
+
const document = inject(DOCUMENT);
|
|
1235
|
+
const renderer = injectRenderer();
|
|
1236
|
+
const scrollbarRuler = renderer.createElement('div');
|
|
1237
|
+
scrollbarRuler.style.width = '100px';
|
|
1238
|
+
scrollbarRuler.style.height = '100px';
|
|
1239
|
+
scrollbarRuler.style.overflow = 'scroll';
|
|
1240
|
+
scrollbarRuler.style.position = 'absolute';
|
|
1241
|
+
scrollbarRuler.style.top = '-9999px';
|
|
1242
|
+
scrollbarRuler.style.scrollbarWidth = getComputedStyle(document.documentElement).scrollbarWidth;
|
|
1243
|
+
renderer.appendChild(document.body, scrollbarRuler);
|
|
1244
|
+
const scrollContainerDimensions = signalElementDimensions(scrollbarRuler);
|
|
1245
|
+
return computed(() => {
|
|
1246
|
+
const client = scrollContainerDimensions().client;
|
|
1247
|
+
if (!client)
|
|
1248
|
+
return null;
|
|
1249
|
+
return {
|
|
1250
|
+
width: Math.max(0, 100 - client.width),
|
|
1251
|
+
height: Math.max(0, 100 - client.height),
|
|
1252
|
+
};
|
|
1253
|
+
});
|
|
1254
|
+
});
|
|
1255
|
+
|
|
1256
|
+
const BREAKPOINT_KEY_SET = new Set(BREAKPOINT_ORDER);
|
|
1257
|
+
const isBreakpointMap = (value) => {
|
|
1258
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value))
|
|
1259
|
+
return false;
|
|
1260
|
+
const keys = Object.keys(value);
|
|
1261
|
+
return keys.length > 0 && keys.every((k) => BREAKPOINT_KEY_SET.has(k));
|
|
1262
|
+
};
|
|
1263
|
+
const resolveFromMap = (map, bp, defaultValue) => {
|
|
1264
|
+
const idx = BREAKPOINT_ORDER.indexOf(bp);
|
|
1265
|
+
for (let i = idx; i >= 0; i--) {
|
|
1266
|
+
const v = map[BREAKPOINT_ORDER[i]];
|
|
1267
|
+
if (v !== undefined)
|
|
1268
|
+
return v;
|
|
1269
|
+
}
|
|
1270
|
+
return defaultValue;
|
|
1271
|
+
};
|
|
1272
|
+
const breakpointTransformBase = (coerce) => {
|
|
1273
|
+
const currentBp = injectCurrentBreakpoint();
|
|
1274
|
+
const injector = inject(Injector);
|
|
1275
|
+
const raw = signal(undefined, /* @ts-ignore */
|
|
1276
|
+
...(ngDevMode ? [{ debugName: "raw" }] : /* istanbul ignore next */ []));
|
|
1277
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1278
|
+
let capturedDefault = undefined;
|
|
1279
|
+
let initialized = false;
|
|
1280
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1281
|
+
let cachedSig = null;
|
|
1282
|
+
const transformFn = (value) => {
|
|
1283
|
+
const coerced = isBreakpointMap(value) ? value : coerce(value);
|
|
1284
|
+
if (!initialized) {
|
|
1285
|
+
capturedDefault = coerced;
|
|
1286
|
+
initialized = true;
|
|
1287
|
+
}
|
|
1288
|
+
raw.set(coerced);
|
|
1289
|
+
return isBreakpointMap(coerced)
|
|
1290
|
+
? resolveFromMap(coerced, currentBp(), capturedDefault)
|
|
1291
|
+
: coerced;
|
|
1292
|
+
};
|
|
1293
|
+
effect(() => {
|
|
1294
|
+
const bp = currentBp();
|
|
1295
|
+
const r = raw();
|
|
1296
|
+
if (!cachedSig) {
|
|
1297
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1298
|
+
const instance = injector.get(BREAKPOINT_INSTANCE_TOKEN);
|
|
1299
|
+
for (const key of Object.keys(instance)) {
|
|
1300
|
+
const val = instance[key];
|
|
1301
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1302
|
+
if (val && typeof val === 'function' && val[SIGNAL]?.transformFn === transformFn) {
|
|
1303
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1304
|
+
cachedSig = val;
|
|
1305
|
+
break;
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
if (!cachedSig || r === undefined || !isBreakpointMap(r))
|
|
1310
|
+
return;
|
|
1311
|
+
const resolved = resolveFromMap(r, bp, capturedDefault);
|
|
1312
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1313
|
+
untracked(() => setInputSignal(cachedSig, resolved));
|
|
1314
|
+
});
|
|
1315
|
+
return transformFn;
|
|
1316
|
+
};
|
|
1317
|
+
/**
|
|
1318
|
+
* Transform factory for boolean inputs.
|
|
1319
|
+
* Coerces plain values with `booleanAttribute`; resolves {@link BreakpointMap} mobile-first.
|
|
1320
|
+
*
|
|
1321
|
+
* @example
|
|
1322
|
+
* snap = input(false, { transform: boolBreakpointTransform() });
|
|
1323
|
+
* // Template: `snap` | `[snap]="true"` | `[snap]="{ xs: false, md: true }"`
|
|
1324
|
+
*/
|
|
1325
|
+
const boolBreakpointTransform = () => breakpointTransformBase(booleanAttribute);
|
|
1326
|
+
/**
|
|
1327
|
+
* Transform factory for number inputs.
|
|
1328
|
+
* Coerces plain values with `numberAttribute`; resolves {@link BreakpointMap} mobile-first.
|
|
1329
|
+
*
|
|
1330
|
+
* @example
|
|
1331
|
+
* scrollMargin = input(0, { transform: numberBreakpointTransform() });
|
|
1332
|
+
* // Template: `[scrollMargin]="16"` | `[scrollMargin]="{ xs: 0, md: 16 }"`
|
|
1333
|
+
*/
|
|
1334
|
+
const numberBreakpointTransform = () => breakpointTransformBase((v) => numberAttribute(v));
|
|
1335
|
+
/**
|
|
1336
|
+
* Transform factory for any typed input (string unions, arrays, objects, etc.).
|
|
1337
|
+
* Passes plain values through as-is; resolves {@link BreakpointMap} mobile-first.
|
|
1338
|
+
* A value is treated as a {@link BreakpointMap} only when all its keys are valid breakpoint names.
|
|
1339
|
+
*
|
|
1340
|
+
* @example
|
|
1341
|
+
* itemSize = input('auto', { transform: typedBreakpointTransform<ScrollableItemSize>() });
|
|
1342
|
+
* tags = input([], { transform: typedBreakpointTransform<string[]>() });
|
|
1343
|
+
* // Template: `[itemSize]="'third'"` | `[itemSize]="{ xs: 'full', md: 'third' }"`
|
|
1344
|
+
*/
|
|
1345
|
+
const typedBreakpointTransform = () => breakpointTransformBase((v) => v);
|
|
1346
|
+
const injectBreakpointInput = (inputSignal, defaultValue) => {
|
|
1347
|
+
const currentBreakpoint = injectCurrentBreakpoint();
|
|
1348
|
+
return computed(() => {
|
|
1349
|
+
const value = inputSignal();
|
|
1350
|
+
if (!isBreakpointMap(value))
|
|
1351
|
+
return value;
|
|
1352
|
+
return resolveFromMap(value, currentBreakpoint(), defaultValue);
|
|
1353
|
+
});
|
|
1354
|
+
};
|
|
1355
|
+
const booleanBreakpointAttribute = (value) => {
|
|
1356
|
+
if (isBreakpointMap(value))
|
|
1357
|
+
return value;
|
|
1358
|
+
return booleanAttribute(value);
|
|
1359
|
+
};
|
|
1360
|
+
const numberBreakpointAttribute = (value) => {
|
|
1361
|
+
if (isBreakpointMap(value))
|
|
1362
|
+
return value;
|
|
1363
|
+
return numberAttribute(value);
|
|
1364
|
+
};
|
|
1365
|
+
const BREAKPOINT_INSTANCE_TOKEN = new InjectionToken('BREAKPOINT_INSTANCE_TOKEN');
|
|
1366
|
+
const provideBreakpointInstance = (componentClass) => ({
|
|
1367
|
+
provide: BREAKPOINT_INSTANCE_TOKEN,
|
|
1368
|
+
useExisting: componentClass,
|
|
1369
|
+
});
|
|
1370
|
+
|
|
1371
|
+
const controlValueSignal = (control, options) => {
|
|
1372
|
+
const getRawValueSafe = (ctrl) => {
|
|
1373
|
+
try {
|
|
1374
|
+
return isSignal(ctrl) ? (ctrl()?.getRawValue() ?? null) : (ctrl?.getRawValue() ?? null);
|
|
1375
|
+
}
|
|
1376
|
+
catch {
|
|
1377
|
+
// Ignore errors. This can happen if the passed control is a required input and is not yet initialized.
|
|
1378
|
+
return null;
|
|
1379
|
+
}
|
|
1380
|
+
};
|
|
1381
|
+
const initialValue = getRawValueSafe(control);
|
|
1382
|
+
const controlStream = isSignal(control)
|
|
1383
|
+
? toObservable(control)
|
|
1384
|
+
: of(control);
|
|
1385
|
+
const controlObs = controlStream.pipe(switchMap((ctrl) => {
|
|
1386
|
+
if (!ctrl)
|
|
1387
|
+
return of(null);
|
|
1388
|
+
const vcsObs = options?.debounceTime
|
|
1389
|
+
? ctrl.valueChanges.pipe(debounceTime(options.debounceTime))
|
|
1390
|
+
: ctrl.valueChanges;
|
|
1391
|
+
return vcsObs.pipe(startWith(ctrl.getRawValue()), map(() => ctrl.getRawValue()));
|
|
1392
|
+
}));
|
|
1393
|
+
const obs = !options?.debounceFirst ? merge(of(initialValue), controlObs) : controlObs;
|
|
1394
|
+
return toSignal(obs.pipe(distinctUntilChanged((a, b) => equal(a, b))), {
|
|
1395
|
+
initialValue,
|
|
1396
|
+
});
|
|
1397
|
+
};
|
|
1398
|
+
/**
|
|
1399
|
+
* The first item in the pair is the previous value and the second item is the current value.
|
|
1400
|
+
*/
|
|
1401
|
+
const controlValueSignalWithPrevious = (control, options) => {
|
|
1402
|
+
const data = linkedSignal({ ...(ngDevMode ? { debugName: "data" } : /* istanbul ignore next */ {}), source: controlValueSignal(control, options),
|
|
1403
|
+
computation: (curr, prev) => [prev?.source ?? null, curr] });
|
|
1404
|
+
return data.asReadonly();
|
|
1405
|
+
};
|
|
1406
|
+
|
|
1407
|
+
const signalElementMutations = (el, options) => {
|
|
1408
|
+
const destroyRef = inject(DestroyRef);
|
|
1409
|
+
const elements = buildElementSignal(el);
|
|
1410
|
+
const firstEl = firstElementSignal(elements);
|
|
1411
|
+
const zone = inject(NgZone);
|
|
1412
|
+
const isRendered = signalIsRendered();
|
|
1413
|
+
const elementMutationsSignal = signal(null, /* @ts-ignore */
|
|
1414
|
+
...(ngDevMode ? [{ debugName: "elementMutationsSignal" }] : /* istanbul ignore next */ []));
|
|
1415
|
+
const observer = new MutationObserver((e) => {
|
|
1416
|
+
if (!isRendered())
|
|
1417
|
+
return;
|
|
1418
|
+
const entry = e[0];
|
|
1419
|
+
if (entry) {
|
|
1420
|
+
zone.run(() => elementMutationsSignal.set(entry));
|
|
1421
|
+
}
|
|
1422
|
+
});
|
|
1423
|
+
effect(() => {
|
|
1424
|
+
const els = firstEl();
|
|
1425
|
+
elementMutationsSignal.set(null);
|
|
1426
|
+
if (els.previousElement) {
|
|
1427
|
+
observer.disconnect();
|
|
1428
|
+
}
|
|
1429
|
+
if (els.currentElement) {
|
|
1430
|
+
observer.observe(els.currentElement, options);
|
|
1431
|
+
}
|
|
1432
|
+
});
|
|
1433
|
+
destroyRef.onDestroy(() => observer.disconnect());
|
|
1434
|
+
return elementMutationsSignal.asReadonly();
|
|
1435
|
+
};
|
|
1436
|
+
const signalHostElementMutations = (options) => signalElementMutations(inject(ElementRef), options);
|
|
1437
|
+
|
|
1438
|
+
const signalElementChildren = (el) => {
|
|
1439
|
+
const elements = buildElementSignal(el);
|
|
1440
|
+
const firstEl = firstElementSignal(elements);
|
|
1441
|
+
const isRendered = signalIsRendered();
|
|
1442
|
+
const elementMutations = signalElementMutations(elements, { childList: true, subtree: true, attributes: true });
|
|
1443
|
+
return computed(() => {
|
|
1444
|
+
if (!isRendered())
|
|
1445
|
+
return [];
|
|
1446
|
+
const els = firstEl();
|
|
1447
|
+
// We are not interested what the mutation is, just that there is one.
|
|
1448
|
+
// Changes to the DOM may affect the children of the element.
|
|
1449
|
+
elementMutations();
|
|
1450
|
+
if (!els.currentElement)
|
|
1451
|
+
return [];
|
|
1452
|
+
const children = [];
|
|
1453
|
+
for (let index = 0; index < els.currentElement.children.length; index++) {
|
|
1454
|
+
const element = els.currentElement.children[index];
|
|
1455
|
+
if (element instanceof HTMLElement) {
|
|
1456
|
+
children.push(element);
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
return children;
|
|
1460
|
+
}, { equal: (a, b) => a.length === b.length && a.every((v, i) => v === b[i]) });
|
|
1461
|
+
};
|
|
1462
|
+
|
|
1463
|
+
const buildSignalEffects = (el, config) => {
|
|
1464
|
+
const elements = buildElementSignal(el);
|
|
1465
|
+
const injector = inject(Injector);
|
|
1466
|
+
effect(() => {
|
|
1467
|
+
const { currentElements, previousElements } = elements();
|
|
1468
|
+
for (const previousEl of previousElements) {
|
|
1469
|
+
if (currentElements.includes(previousEl))
|
|
1470
|
+
continue;
|
|
1471
|
+
const tokens = Object.keys(config.tokenMap)
|
|
1472
|
+
.map((key) => key.split(' '))
|
|
1473
|
+
.flat();
|
|
1474
|
+
if (!tokens.length)
|
|
1475
|
+
continue;
|
|
1476
|
+
config.cleanupFn(previousEl, tokens);
|
|
1477
|
+
}
|
|
1478
|
+
for (const currentEl of currentElements) {
|
|
1479
|
+
if (previousElements.includes(currentEl))
|
|
1480
|
+
continue;
|
|
1481
|
+
for (const [tokens, condition] of Object.entries(config.tokenMap)) {
|
|
1482
|
+
untracked(() => {
|
|
1483
|
+
const tokenArray = tokens.split(' ');
|
|
1484
|
+
if (!tokenArray.length)
|
|
1485
|
+
return;
|
|
1486
|
+
config.updateFn(currentEl, tokenArray, condition());
|
|
1487
|
+
});
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
});
|
|
1491
|
+
const effects = {};
|
|
1492
|
+
const has = (tokens) => tokens in effects;
|
|
1493
|
+
const push = (tokens, signal) => {
|
|
1494
|
+
if (has(tokens))
|
|
1495
|
+
return;
|
|
1496
|
+
runInInjectionContext(injector, () => {
|
|
978
1497
|
effects[tokens] = effect(() => {
|
|
979
1498
|
const { currentElements } = untracked(() => elements());
|
|
980
1499
|
const value = signal();
|
|
@@ -1075,75 +1594,293 @@ const signalStyles = (el, styleMap) => {
|
|
|
1075
1594
|
};
|
|
1076
1595
|
const signalHostStyles = (styleMap) => signalStyles(inject(ElementRef), styleMap);
|
|
1077
1596
|
|
|
1078
|
-
const
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1597
|
+
const elementCanScroll = (element, direction) => {
|
|
1598
|
+
const el = element || document.documentElement;
|
|
1599
|
+
const { scrollHeight, clientHeight, scrollWidth, clientWidth } = el;
|
|
1600
|
+
if (direction === 'x') {
|
|
1601
|
+
return scrollWidth > clientWidth;
|
|
1602
|
+
}
|
|
1603
|
+
else if (direction === 'y') {
|
|
1604
|
+
return scrollHeight > clientHeight;
|
|
1605
|
+
}
|
|
1606
|
+
return scrollHeight > clientHeight || scrollWidth > clientWidth;
|
|
1607
|
+
};
|
|
1608
|
+
const createViewportRect = () => ({
|
|
1609
|
+
left: 0,
|
|
1610
|
+
top: 0,
|
|
1611
|
+
right: window.innerWidth,
|
|
1612
|
+
bottom: window.innerHeight,
|
|
1613
|
+
width: window.innerWidth,
|
|
1614
|
+
height: window.innerHeight,
|
|
1615
|
+
x: 0,
|
|
1616
|
+
y: 0,
|
|
1617
|
+
toJSON: () => ({}),
|
|
1087
1618
|
});
|
|
1088
|
-
const
|
|
1089
|
-
|
|
1619
|
+
const isElementVisible = (options) => {
|
|
1620
|
+
const { container, element } = options;
|
|
1621
|
+
if (!element) {
|
|
1622
|
+
return null;
|
|
1623
|
+
}
|
|
1624
|
+
const elementRect = options.elementRect || element.getBoundingClientRect();
|
|
1625
|
+
const containerRect = container ? options.containerRect || container.getBoundingClientRect() : createViewportRect();
|
|
1626
|
+
const canScroll = elementCanScroll(container);
|
|
1627
|
+
if (!canScroll) {
|
|
1090
1628
|
return {
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1629
|
+
inline: true,
|
|
1630
|
+
block: true,
|
|
1631
|
+
blockIntersection: 1,
|
|
1632
|
+
inlineIntersection: 1,
|
|
1633
|
+
intersectionRatio: 1,
|
|
1634
|
+
isIntersecting: true,
|
|
1635
|
+
element,
|
|
1636
|
+
containerRect,
|
|
1637
|
+
elementRect,
|
|
1095
1638
|
};
|
|
1096
1639
|
}
|
|
1097
|
-
const
|
|
1098
|
-
const
|
|
1640
|
+
const elLeft = elementRect.left;
|
|
1641
|
+
const elTop = elementRect.top;
|
|
1642
|
+
const elWidth = elementRect.width || 1;
|
|
1643
|
+
const elHeight = elementRect.height || 1;
|
|
1644
|
+
const elRight = elLeft + elWidth;
|
|
1645
|
+
const elBottom = elTop + elHeight;
|
|
1646
|
+
const conLeft = containerRect.left;
|
|
1647
|
+
const conTop = containerRect.top;
|
|
1648
|
+
const conRight = conLeft + containerRect.width;
|
|
1649
|
+
const conBottom = conTop + containerRect.height;
|
|
1650
|
+
const isElementInlineVisible = elLeft >= conLeft && elRight <= conRight;
|
|
1651
|
+
const isElementBlockVisible = elTop >= conTop && elBottom <= conBottom;
|
|
1652
|
+
const inlineIntersection = Math.min(elRight, conRight) - Math.max(elLeft, conLeft);
|
|
1653
|
+
const blockIntersection = Math.min(elBottom, conBottom) - Math.max(elTop, conTop);
|
|
1654
|
+
const inlineIntersectionPercentage = clamp(inlineIntersection / elWidth, 0, 1);
|
|
1655
|
+
const blockIntersectionPercentage = clamp(blockIntersection / elHeight, 0, 1);
|
|
1099
1656
|
return {
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1657
|
+
inline: isElementInlineVisible,
|
|
1658
|
+
block: isElementBlockVisible,
|
|
1659
|
+
inlineIntersection: inlineIntersectionPercentage,
|
|
1660
|
+
blockIntersection: blockIntersectionPercentage,
|
|
1661
|
+
isIntersecting: isElementInlineVisible && isElementBlockVisible,
|
|
1662
|
+
element,
|
|
1663
|
+
containerRect,
|
|
1664
|
+
elementRect,
|
|
1665
|
+
// Round the intersection ratio to the nearest 0.01 to avoid floating point errors and system scaling issues.
|
|
1666
|
+
intersectionRatio: Math.round(Math.min(inlineIntersectionPercentage, blockIntersectionPercentage) * 100) / 100,
|
|
1104
1667
|
};
|
|
1105
1668
|
};
|
|
1106
|
-
const
|
|
1107
|
-
const
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1669
|
+
const getElementScrollCoordinates = (options) => {
|
|
1670
|
+
const { container, element, direction, behavior = 'smooth', origin = 'nearest', scrollBlockMargin = 0, scrollInlineMargin = 0, } = options;
|
|
1671
|
+
if (!element || !container || !elementCanScroll(container)) {
|
|
1672
|
+
return {
|
|
1673
|
+
behavior,
|
|
1674
|
+
left: undefined,
|
|
1675
|
+
top: undefined,
|
|
1676
|
+
};
|
|
1677
|
+
}
|
|
1678
|
+
const elementRect = element.getBoundingClientRect();
|
|
1679
|
+
const containerRect = container.getBoundingClientRect();
|
|
1680
|
+
const { scrollLeft, scrollTop } = container;
|
|
1681
|
+
const elWidth = elementRect.width;
|
|
1682
|
+
const elHeight = elementRect.height;
|
|
1683
|
+
const elLeft = elementRect.left;
|
|
1684
|
+
const elTop = elementRect.top;
|
|
1685
|
+
const elRight = elementRect.right;
|
|
1686
|
+
const elBottom = elementRect.bottom;
|
|
1687
|
+
const conWidth = containerRect.width;
|
|
1688
|
+
const conHeight = containerRect.height;
|
|
1689
|
+
const conLeft = containerRect.left;
|
|
1690
|
+
const conTop = containerRect.top;
|
|
1691
|
+
const conRight = containerRect.right;
|
|
1692
|
+
const conBottom = containerRect.bottom;
|
|
1693
|
+
const shouldScrollLeft = direction === 'inline' || direction === 'both' || !direction;
|
|
1694
|
+
const shouldScrollTop = direction === 'block' || direction === 'both' || !direction;
|
|
1695
|
+
let scrollLeftTo = scrollLeft;
|
|
1696
|
+
let scrollTopTo = scrollTop;
|
|
1697
|
+
const relativeTop = elTop - conTop;
|
|
1698
|
+
const relativeLeft = elLeft - conLeft;
|
|
1699
|
+
const calculateScrollToStart = () => {
|
|
1700
|
+
scrollLeftTo = scrollLeft + relativeLeft - scrollInlineMargin;
|
|
1701
|
+
scrollTopTo = scrollTop + relativeTop - scrollBlockMargin;
|
|
1702
|
+
};
|
|
1703
|
+
const calculateScrollToEnd = () => {
|
|
1704
|
+
scrollLeftTo = scrollLeft + relativeLeft - conWidth + elWidth + scrollInlineMargin;
|
|
1705
|
+
scrollTopTo = scrollTop + relativeTop - conHeight + elHeight + scrollBlockMargin;
|
|
1706
|
+
};
|
|
1707
|
+
const calculateScrollToCenter = () => {
|
|
1708
|
+
scrollLeftTo = scrollLeft + relativeLeft - conWidth / 2 + elWidth / 2;
|
|
1709
|
+
scrollTopTo = scrollTop + relativeTop - conHeight / 2 + elHeight / 2;
|
|
1710
|
+
};
|
|
1711
|
+
const calculateScrollToNearest = () => {
|
|
1712
|
+
const isAbove = elBottom < conTop;
|
|
1713
|
+
const isPartialAbove = elTop < conTop && elBottom > conTop;
|
|
1714
|
+
const isBelow = elTop > conBottom;
|
|
1715
|
+
const isPartialBelow = elTop < conBottom && elBottom > conBottom;
|
|
1716
|
+
const isLeft = elRight < conLeft;
|
|
1717
|
+
const isPartialLeft = elLeft < conLeft && elRight > conLeft;
|
|
1718
|
+
const isRight = elLeft > conRight;
|
|
1719
|
+
const isPartialRight = elLeft < conRight && elRight > conRight;
|
|
1720
|
+
if (isAbove || isPartialAbove || isLeft || isPartialLeft) {
|
|
1721
|
+
calculateScrollToStart();
|
|
1722
|
+
}
|
|
1723
|
+
else if (isBelow || isPartialBelow || isRight || isPartialRight) {
|
|
1724
|
+
calculateScrollToEnd();
|
|
1725
|
+
}
|
|
1726
|
+
};
|
|
1727
|
+
switch (origin) {
|
|
1728
|
+
case 'start':
|
|
1729
|
+
calculateScrollToStart();
|
|
1730
|
+
break;
|
|
1731
|
+
case 'end':
|
|
1732
|
+
calculateScrollToEnd();
|
|
1733
|
+
break;
|
|
1734
|
+
case 'center':
|
|
1735
|
+
calculateScrollToCenter();
|
|
1736
|
+
break;
|
|
1737
|
+
case 'nearest':
|
|
1738
|
+
calculateScrollToNearest();
|
|
1739
|
+
break;
|
|
1740
|
+
}
|
|
1741
|
+
return {
|
|
1742
|
+
behavior,
|
|
1743
|
+
left: shouldScrollLeft ? scrollLeftTo : undefined,
|
|
1744
|
+
top: shouldScrollTop ? scrollTopTo : undefined,
|
|
1745
|
+
};
|
|
1746
|
+
};
|
|
1747
|
+
const scrollToElement = (options) => {
|
|
1748
|
+
options.container?.scrollTo(getElementScrollCoordinates(options));
|
|
1749
|
+
};
|
|
1750
|
+
|
|
1751
|
+
const MIN_SNAP_DELTA_PX = 1;
|
|
1752
|
+
const getScrollSnapTarget = (items, container, direction, origin, margin = 0) => {
|
|
1753
|
+
if (!items.length)
|
|
1754
|
+
return null;
|
|
1755
|
+
const containerRect = container.getBoundingClientRect();
|
|
1756
|
+
const containerSize = direction === 'horizontal' ? containerRect.width : containerRect.height;
|
|
1757
|
+
let bestElement = null;
|
|
1758
|
+
let bestOrigin = 'start';
|
|
1759
|
+
let bestAbsDelta = Infinity;
|
|
1760
|
+
const updateBest = (element, o, delta) => {
|
|
1761
|
+
const abs = Math.abs(delta);
|
|
1762
|
+
if (abs < bestAbsDelta) {
|
|
1763
|
+
bestAbsDelta = abs;
|
|
1764
|
+
bestElement = element;
|
|
1765
|
+
bestOrigin = o;
|
|
1122
1766
|
}
|
|
1123
|
-
}
|
|
1124
|
-
|
|
1125
|
-
const
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1767
|
+
};
|
|
1768
|
+
for (const item of items) {
|
|
1769
|
+
const itemRect = item.getBoundingClientRect();
|
|
1770
|
+
const itemSize = direction === 'horizontal' ? itemRect.width : itemRect.height;
|
|
1771
|
+
const relativeStart = direction === 'horizontal' ? itemRect.left - containerRect.left : itemRect.top - containerRect.top;
|
|
1772
|
+
const relativeEnd = relativeStart + itemSize;
|
|
1773
|
+
if (itemSize > containerSize) {
|
|
1774
|
+
const isStartEdgeVisible = relativeStart >= 0;
|
|
1775
|
+
const isEndEdgeVisible = relativeEnd <= containerSize;
|
|
1776
|
+
if (!isStartEdgeVisible && !isEndEdgeVisible)
|
|
1777
|
+
continue;
|
|
1778
|
+
if (isStartEdgeVisible) {
|
|
1779
|
+
updateBest(item, 'start', relativeStart - margin);
|
|
1130
1780
|
}
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1781
|
+
else {
|
|
1782
|
+
updateBest(item, 'end', relativeEnd - containerSize + margin);
|
|
1783
|
+
}
|
|
1784
|
+
continue;
|
|
1785
|
+
}
|
|
1786
|
+
const computeDelta = (o) => {
|
|
1787
|
+
switch (o) {
|
|
1788
|
+
case 'start':
|
|
1789
|
+
return relativeStart - margin;
|
|
1790
|
+
case 'end':
|
|
1791
|
+
return relativeEnd - containerSize + margin;
|
|
1792
|
+
case 'center':
|
|
1793
|
+
return relativeStart + itemSize / 2 - containerSize / 2;
|
|
1794
|
+
}
|
|
1795
|
+
};
|
|
1796
|
+
if (origin === 'auto') {
|
|
1797
|
+
for (const o of ['start', 'center', 'end']) {
|
|
1798
|
+
updateBest(item, o, computeDelta(o));
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
else {
|
|
1802
|
+
updateBest(item, origin, computeDelta(origin));
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1805
|
+
if (!bestElement || bestAbsDelta < MIN_SNAP_DELTA_PX)
|
|
1806
|
+
return null;
|
|
1807
|
+
return { element: bestElement, origin: bestOrigin };
|
|
1808
|
+
};
|
|
1809
|
+
const getScrollContainerTarget = (entries, direction) => {
|
|
1810
|
+
const firstVisible = entries.find((i) => i.intersectionRatio > 0);
|
|
1811
|
+
const lastVisible = [...entries].reverse().find((i) => i.intersectionRatio > 0);
|
|
1812
|
+
const relevantEntry = direction === 'start' ? firstVisible : lastVisible;
|
|
1813
|
+
if (!relevantEntry)
|
|
1814
|
+
return null;
|
|
1815
|
+
const relevantIndex = entries.indexOf(relevantEntry);
|
|
1816
|
+
const nextIndex = relevantEntry.intersectionRatio !== 1
|
|
1817
|
+
? relevantIndex
|
|
1818
|
+
: direction === 'start'
|
|
1819
|
+
? relevantIndex - 1
|
|
1820
|
+
: relevantIndex + 1;
|
|
1821
|
+
const element = entries[nextIndex]?.target ?? relevantEntry.target;
|
|
1822
|
+
return { element, origin: direction === 'end' ? 'start' : 'end' };
|
|
1823
|
+
};
|
|
1824
|
+
const getScrollItemTarget = (entries, container, direction, scrollOrigin, axisDirection) => {
|
|
1825
|
+
const firstVisible = entries.find((i) => i.intersectionRatio > 0);
|
|
1826
|
+
const lastVisible = [...entries].reverse().find((i) => i.intersectionRatio > 0);
|
|
1827
|
+
if (!firstVisible || !lastVisible)
|
|
1828
|
+
return null;
|
|
1829
|
+
const firstIndex = entries.indexOf(firstVisible);
|
|
1830
|
+
const lastIndex = entries.indexOf(lastVisible);
|
|
1831
|
+
const containerRect = container.getBoundingClientRect();
|
|
1832
|
+
// Only a single item is visible — it must be oversized (wider/taller than the container).
|
|
1833
|
+
if (firstVisible === lastVisible) {
|
|
1834
|
+
const itemRect = firstVisible.target.getBoundingClientRect();
|
|
1835
|
+
const isStartEdgeVisible = axisDirection === 'horizontal'
|
|
1836
|
+
? Math.round(itemRect.left) >= Math.round(containerRect.left)
|
|
1837
|
+
: Math.round(itemRect.top) >= Math.round(containerRect.top);
|
|
1838
|
+
const isEndEdgeVisible = axisDirection === 'horizontal'
|
|
1839
|
+
? Math.round(itemRect.right) <= Math.round(containerRect.right)
|
|
1840
|
+
: Math.round(itemRect.bottom) <= Math.round(containerRect.bottom);
|
|
1841
|
+
if (!isStartEdgeVisible || !isEndEdgeVisible) {
|
|
1842
|
+
if (direction === 'start') {
|
|
1843
|
+
if (isStartEdgeVisible) {
|
|
1844
|
+
const prevIndex = firstIndex - 1;
|
|
1845
|
+
const element = entries[prevIndex]?.target;
|
|
1846
|
+
if (!element)
|
|
1847
|
+
return null;
|
|
1848
|
+
return { element, index: prevIndex, origin: 'end' };
|
|
1136
1849
|
}
|
|
1137
|
-
|
|
1850
|
+
return { element: firstVisible.target, index: firstIndex, origin: 'start' };
|
|
1138
1851
|
}
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1852
|
+
else {
|
|
1853
|
+
if (isEndEdgeVisible) {
|
|
1854
|
+
const nextIndex = lastIndex + 1;
|
|
1855
|
+
const element = entries[nextIndex]?.target;
|
|
1856
|
+
if (!element)
|
|
1857
|
+
return null;
|
|
1858
|
+
return { element, index: nextIndex, origin: 'start' };
|
|
1859
|
+
}
|
|
1860
|
+
return { element: lastVisible.target, index: lastIndex, origin: 'end' };
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
}
|
|
1864
|
+
else if (scrollOrigin === 'center') {
|
|
1865
|
+
const entry = direction === 'start' ? firstVisible : lastVisible;
|
|
1866
|
+
const index = direction === 'start' ? firstIndex : lastIndex;
|
|
1867
|
+
return { element: entry.target, index, origin: 'center' };
|
|
1868
|
+
}
|
|
1869
|
+
const entry = direction === 'start' ? firstVisible : lastVisible;
|
|
1870
|
+
const entryIndex = direction === 'start' ? firstIndex : lastIndex;
|
|
1871
|
+
if (Math.round(entry.intersectionRatio) === 1) {
|
|
1872
|
+
if (direction === 'start' && entryIndex === 0)
|
|
1873
|
+
return null;
|
|
1874
|
+
if (direction === 'end' && entryIndex === entries.length - 1)
|
|
1875
|
+
return null;
|
|
1876
|
+
const nextIndex = direction === 'start' ? entryIndex - 1 : entryIndex + 1;
|
|
1877
|
+
const element = entries[nextIndex]?.target;
|
|
1878
|
+
if (!element)
|
|
1879
|
+
return null;
|
|
1880
|
+
return { element, index: nextIndex, origin: direction };
|
|
1881
|
+
}
|
|
1882
|
+
return { element: entry.target, index: entryIndex, origin: direction };
|
|
1145
1883
|
};
|
|
1146
|
-
const signalHostElementDimensions = () => signalElementDimensions(inject(ElementRef));
|
|
1147
1884
|
|
|
1148
1885
|
const createPositionObject = (entry) => {
|
|
1149
1886
|
const boundingRect = entry.boundingClientRect;
|
|
@@ -1175,8 +1912,10 @@ const signalElementIntersection = (el, options) => {
|
|
|
1175
1912
|
const zone = inject(NgZone);
|
|
1176
1913
|
const isRendered = signalIsRendered();
|
|
1177
1914
|
const isEnabled = options?.enabled ?? signal(true);
|
|
1178
|
-
const elementIntersectionSignal = signal([],
|
|
1179
|
-
|
|
1915
|
+
const elementIntersectionSignal = signal([], /* @ts-ignore */
|
|
1916
|
+
...(ngDevMode ? [{ debugName: "elementIntersectionSignal" }] : /* istanbul ignore next */ []));
|
|
1917
|
+
const observer = signal(null, /* @ts-ignore */
|
|
1918
|
+
...(ngDevMode ? [{ debugName: "observer" }] : /* istanbul ignore next */ []));
|
|
1180
1919
|
const currentlyObservedElements = new Set();
|
|
1181
1920
|
const updateIntersections = (entries) => {
|
|
1182
1921
|
let currentValues = [...elementIntersectionSignal()];
|
|
@@ -1292,7 +2031,8 @@ const signalElementLastScrollDirection = (el) => {
|
|
|
1292
2031
|
const elements = buildElementSignal(el);
|
|
1293
2032
|
const element = firstElementSignal(elements);
|
|
1294
2033
|
const destroyRef = inject(DestroyRef);
|
|
1295
|
-
const lastScrollDirection = signal(null,
|
|
2034
|
+
const lastScrollDirection = signal(null, /* @ts-ignore */
|
|
2035
|
+
...(ngDevMode ? [{ debugName: "lastScrollDirection" }] : /* istanbul ignore next */ []));
|
|
1296
2036
|
let lastScrollTop = 0;
|
|
1297
2037
|
let lastScrollLeft = 0;
|
|
1298
2038
|
toObservable(element)
|
|
@@ -1353,7 +2093,8 @@ const signalElementScrollState = (el, options) => {
|
|
|
1353
2093
|
element.scrollTop = scrollPosition.top;
|
|
1354
2094
|
ref.destroy();
|
|
1355
2095
|
}
|
|
1356
|
-
},
|
|
2096
|
+
}, /* @ts-ignore */
|
|
2097
|
+
...(ngDevMode ? [{ debugName: "ref" }] : /* istanbul ignore next */ []));
|
|
1357
2098
|
}
|
|
1358
2099
|
const notScrollable = (dimensions) => ({
|
|
1359
2100
|
canScroll: false,
|
|
@@ -1382,203 +2123,6 @@ const signalElementScrollState = (el, options) => {
|
|
|
1382
2123
|
};
|
|
1383
2124
|
const signalHostElementScrollState = () => signalElementScrollState(inject(ElementRef));
|
|
1384
2125
|
|
|
1385
|
-
const previousSignalValue = (signal) => {
|
|
1386
|
-
const obs = toObservable(signal).pipe(pairwise(), map(([prev]) => prev));
|
|
1387
|
-
return toSignal(obs);
|
|
1388
|
-
};
|
|
1389
|
-
const syncSignal = (from, to, options) => {
|
|
1390
|
-
let isFirstRun = options?.skipSyncRead ? false : true;
|
|
1391
|
-
if (!options?.skipSyncRead) {
|
|
1392
|
-
try {
|
|
1393
|
-
// this might throw if the signal is not yet initialized (eg. a required signal input inside the constructor)
|
|
1394
|
-
// in that case we just skip the initial sync
|
|
1395
|
-
to.set(from());
|
|
1396
|
-
}
|
|
1397
|
-
catch {
|
|
1398
|
-
isFirstRun = false;
|
|
1399
|
-
if (isDevMode()) {
|
|
1400
|
-
console.warn('Failed to sync signals. The target signal is not yet initialized.', { from, to });
|
|
1401
|
-
}
|
|
1402
|
-
}
|
|
1403
|
-
}
|
|
1404
|
-
const ref = effect(() => {
|
|
1405
|
-
const formVal = from();
|
|
1406
|
-
if (options?.skipFirstRun && isFirstRun) {
|
|
1407
|
-
isFirstRun = false;
|
|
1408
|
-
return;
|
|
1409
|
-
}
|
|
1410
|
-
untracked(() => {
|
|
1411
|
-
to.set(formVal);
|
|
1412
|
-
});
|
|
1413
|
-
}, ...(ngDevMode ? [{ debugName: "ref" }] : []));
|
|
1414
|
-
return ref;
|
|
1415
|
-
};
|
|
1416
|
-
const maybeSignalValue = (value) => {
|
|
1417
|
-
if (isSignal(value)) {
|
|
1418
|
-
return value();
|
|
1419
|
-
}
|
|
1420
|
-
return value;
|
|
1421
|
-
};
|
|
1422
|
-
/**
|
|
1423
|
-
* A computed that will only be reactive until the source signal contains a truthy value.
|
|
1424
|
-
* All subsequent changes inside the computation will be ignored.
|
|
1425
|
-
*/
|
|
1426
|
-
const computedTillTruthy = (source) => {
|
|
1427
|
-
const value = signal(null, ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
1428
|
-
const ref = effect(() => {
|
|
1429
|
-
const val = source();
|
|
1430
|
-
if (val) {
|
|
1431
|
-
value.set(val);
|
|
1432
|
-
ref.destroy();
|
|
1433
|
-
}
|
|
1434
|
-
}, ...(ngDevMode ? [{ debugName: "ref" }] : []));
|
|
1435
|
-
return value.asReadonly();
|
|
1436
|
-
};
|
|
1437
|
-
/**
|
|
1438
|
-
* A computed that will only be reactive until the source signal contains a falsy value.
|
|
1439
|
-
* All subsequent changes inside the computation will be ignored.
|
|
1440
|
-
*/
|
|
1441
|
-
const computedTillFalsy = (source) => {
|
|
1442
|
-
const value = signal(null, ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
1443
|
-
const ref = effect(() => {
|
|
1444
|
-
const val = source();
|
|
1445
|
-
if (!val) {
|
|
1446
|
-
value.set(val);
|
|
1447
|
-
ref.destroy();
|
|
1448
|
-
}
|
|
1449
|
-
}, ...(ngDevMode ? [{ debugName: "ref" }] : []));
|
|
1450
|
-
return value.asReadonly();
|
|
1451
|
-
};
|
|
1452
|
-
/**
|
|
1453
|
-
* A writeable signal that will be set to the provided value once all inputs are set.
|
|
1454
|
-
* During that time, the signal will be set to `null`.
|
|
1455
|
-
*/
|
|
1456
|
-
const deferredSignal = (valueFn) => {
|
|
1457
|
-
const valueSignal = signal(null, ...(ngDevMode ? [{ debugName: "valueSignal" }] : []));
|
|
1458
|
-
afterNextRender(() => {
|
|
1459
|
-
valueSignal.set(valueFn());
|
|
1460
|
-
});
|
|
1461
|
-
return valueSignal;
|
|
1462
|
-
};
|
|
1463
|
-
const memoizeSignal = (factory) => {
|
|
1464
|
-
let cached = null;
|
|
1465
|
-
return () => {
|
|
1466
|
-
if (!cached)
|
|
1467
|
-
cached = factory();
|
|
1468
|
-
return cached;
|
|
1469
|
-
};
|
|
1470
|
-
};
|
|
1471
|
-
|
|
1472
|
-
/** Inject a signal containing a boolean value indicating if the viewport is xs */
|
|
1473
|
-
const injectIsXs = memoizeSignal(() => injectObserveBreakpoint({ max: 'xs' }));
|
|
1474
|
-
/** Inject a signal containing a boolean value indicating if the viewport is sm */
|
|
1475
|
-
const injectIsSm = memoizeSignal(() => injectObserveBreakpoint({ min: 'sm', max: 'sm' }));
|
|
1476
|
-
/** Inject a signal containing a boolean value indicating if the viewport is md */
|
|
1477
|
-
const injectIsMd = memoizeSignal(() => injectObserveBreakpoint({ min: 'md', max: 'md' }));
|
|
1478
|
-
/** Inject a signal containing a boolean value indicating if the viewport is lg */
|
|
1479
|
-
const injectIsLg = memoizeSignal(() => injectObserveBreakpoint({ min: 'lg', max: 'lg' }));
|
|
1480
|
-
/** Inject a signal containing a boolean value indicating if the viewport is xl */
|
|
1481
|
-
const injectIsXl = memoizeSignal(() => injectObserveBreakpoint({ min: 'xl', max: 'xl' }));
|
|
1482
|
-
/** Inject a signal containing a boolean value indicating if the viewport is 2xl */
|
|
1483
|
-
const injectIs2Xl = memoizeSignal(() => injectObserveBreakpoint({ min: '2xl' }));
|
|
1484
|
-
/**
|
|
1485
|
-
* Inject a boolean value indicating if the viewport is matching the provided options.
|
|
1486
|
-
* This value is not reactive. If you want to react to changes, use the {@link injectObserveBreakpoint} function instead.
|
|
1487
|
-
*/
|
|
1488
|
-
const injectBreakpointIsMatched = (options) => injectBreakpointObserver().isBreakpointMatched(options);
|
|
1489
|
-
/**
|
|
1490
|
-
* Inject a boolean value indicating if the media query is matched.
|
|
1491
|
-
* This value is not reactive. If you want to react to changes, use the {@link injectObserveMediaQuery} function instead.
|
|
1492
|
-
*/
|
|
1493
|
-
const injectMediaQueryIsMatched = (mediaQuery) => injectBreakpointObserver().isMediaQueryMatched(mediaQuery);
|
|
1494
|
-
/**
|
|
1495
|
-
* Inject a signal containing a boolean value indicating if the viewport is matching the provided options.
|
|
1496
|
-
*/
|
|
1497
|
-
const injectObserveBreakpoint = (options) => injectBreakpointObserver().observeBreakpoint(options);
|
|
1498
|
-
/**
|
|
1499
|
-
* Inject a signal containing a boolean value indicating if the media query is matched.
|
|
1500
|
-
*/
|
|
1501
|
-
const injectObserveMediaQuery = (mediaQuery) => injectBreakpointObserver().observeMediaQuery(mediaQuery);
|
|
1502
|
-
/** Inject a signal containing the current breakpoint. */
|
|
1503
|
-
const injectCurrentBreakpoint = memoizeSignal(() => {
|
|
1504
|
-
const isXs = injectIsXs();
|
|
1505
|
-
const isSm = injectIsSm();
|
|
1506
|
-
const isMd = injectIsMd();
|
|
1507
|
-
const isLg = injectIsLg();
|
|
1508
|
-
const isXl = injectIsXl();
|
|
1509
|
-
const is2Xl = injectIs2Xl();
|
|
1510
|
-
return computed(() => {
|
|
1511
|
-
switch (true) {
|
|
1512
|
-
case is2Xl():
|
|
1513
|
-
return '2xl';
|
|
1514
|
-
case isXl():
|
|
1515
|
-
return 'xl';
|
|
1516
|
-
case isLg():
|
|
1517
|
-
return 'lg';
|
|
1518
|
-
case isMd():
|
|
1519
|
-
return 'md';
|
|
1520
|
-
case isSm():
|
|
1521
|
-
return 'sm';
|
|
1522
|
-
case isXs():
|
|
1523
|
-
default:
|
|
1524
|
-
return 'xs';
|
|
1525
|
-
}
|
|
1526
|
-
});
|
|
1527
|
-
});
|
|
1528
|
-
/** Inject a signal that indicates if the user is using a portrait display */
|
|
1529
|
-
const injectIsPortrait = memoizeSignal(() => injectObserveMediaQuery('(orientation: portrait)'));
|
|
1530
|
-
/** Inject a signal that indicates if the user is using a landscape display */
|
|
1531
|
-
const injectIsLandscape = memoizeSignal(() => injectObserveMediaQuery('(orientation: landscape)'));
|
|
1532
|
-
/** Inject a signal containing the current display orientation */
|
|
1533
|
-
const injectDisplayOrientation = memoizeSignal(() => {
|
|
1534
|
-
const isPortrait = injectIsPortrait();
|
|
1535
|
-
return computed(() => {
|
|
1536
|
-
if (isPortrait())
|
|
1537
|
-
return 'portrait';
|
|
1538
|
-
return 'landscape';
|
|
1539
|
-
});
|
|
1540
|
-
});
|
|
1541
|
-
/** Inject a signal that indicates if the device has a touch input */
|
|
1542
|
-
const injectHasTouchInput = memoizeSignal(() => injectObserveMediaQuery('(pointer: coarse)'));
|
|
1543
|
-
/** Inject a signal that indicates if the device has a fine input (mouse or stylus) */
|
|
1544
|
-
const injectHasPrecisionInput = memoizeSignal(() => injectObserveMediaQuery('(pointer: fine)'));
|
|
1545
|
-
/** Inject a signal containing the current device input type */
|
|
1546
|
-
const injectDeviceInputType = memoizeSignal(() => {
|
|
1547
|
-
const isTouch = injectHasTouchInput();
|
|
1548
|
-
return computed(() => {
|
|
1549
|
-
if (isTouch())
|
|
1550
|
-
return 'touch';
|
|
1551
|
-
return 'mouse';
|
|
1552
|
-
});
|
|
1553
|
-
});
|
|
1554
|
-
/** Inject a signal containing a boolean value indicating if the user can hover (eg. using a mouse) */
|
|
1555
|
-
const injectCanHover = memoizeSignal(() => injectObserveMediaQuery('(hover: hover)'));
|
|
1556
|
-
/** Inject a signal containing the viewport dimensions */
|
|
1557
|
-
const injectViewportDimensions = memoizeSignal(() => signalElementDimensions(createDocumentElementSignal()));
|
|
1558
|
-
/** Inject a signal containing the scrollbar dimensions. Dimensions will be 0 if scrollbars overlap the page contents (like on mobile). */
|
|
1559
|
-
const injectScrollbarDimensions = memoizeSignal(() => {
|
|
1560
|
-
const document = inject(DOCUMENT);
|
|
1561
|
-
const renderer = injectRenderer();
|
|
1562
|
-
const scrollbarRuler = renderer.createElement('div');
|
|
1563
|
-
scrollbarRuler.style.width = '100px';
|
|
1564
|
-
scrollbarRuler.style.height = '100px';
|
|
1565
|
-
scrollbarRuler.style.overflow = 'scroll';
|
|
1566
|
-
scrollbarRuler.style.position = 'absolute';
|
|
1567
|
-
scrollbarRuler.style.top = '-9999px';
|
|
1568
|
-
scrollbarRuler.style.scrollbarWidth = getComputedStyle(document.documentElement).scrollbarWidth;
|
|
1569
|
-
renderer.appendChild(document.body, scrollbarRuler);
|
|
1570
|
-
const scrollContainerDimensions = signalElementDimensions(scrollbarRuler);
|
|
1571
|
-
return computed(() => {
|
|
1572
|
-
const client = scrollContainerDimensions().client;
|
|
1573
|
-
if (!client)
|
|
1574
|
-
return null;
|
|
1575
|
-
return {
|
|
1576
|
-
width: Math.max(0, 100 - client.width),
|
|
1577
|
-
height: Math.max(0, 100 - client.height),
|
|
1578
|
-
};
|
|
1579
|
-
});
|
|
1580
|
-
});
|
|
1581
|
-
|
|
1582
2126
|
let hasWrittenScrollbarSizes = false;
|
|
1583
2127
|
/**
|
|
1584
2128
|
* Applies scrollbar size CSS variables to the documentElement (html tag) in pixels.
|
|
@@ -1647,11 +2191,16 @@ const useCursorDragScroll = (el, options) => {
|
|
|
1647
2191
|
const { enabled = signal(true), allowedDirection = 'both' } = options ?? {};
|
|
1648
2192
|
const scrollState = signalElementScrollState(elements);
|
|
1649
2193
|
const renderer = injectRenderer();
|
|
1650
|
-
const isDragging = signal(false,
|
|
1651
|
-
|
|
1652
|
-
const
|
|
1653
|
-
|
|
1654
|
-
const
|
|
2194
|
+
const isDragging = signal(false, /* @ts-ignore */
|
|
2195
|
+
...(ngDevMode ? [{ debugName: "isDragging" }] : /* istanbul ignore next */ []));
|
|
2196
|
+
const isInitDragging = signal(false, /* @ts-ignore */
|
|
2197
|
+
...(ngDevMode ? [{ debugName: "isInitDragging" }] : /* istanbul ignore next */ []));
|
|
2198
|
+
const initialDragPosition = signal({ x: 0, y: 0 }, /* @ts-ignore */
|
|
2199
|
+
...(ngDevMode ? [{ debugName: "initialDragPosition" }] : /* istanbul ignore next */ []));
|
|
2200
|
+
const initialScrollPosition = signal({ x: 0, y: 0 }, /* @ts-ignore */
|
|
2201
|
+
...(ngDevMode ? [{ debugName: "initialScrollPosition" }] : /* istanbul ignore next */ []));
|
|
2202
|
+
const dragAmount = signal({ x: 0, y: 0 }, /* @ts-ignore */
|
|
2203
|
+
...(ngDevMode ? [{ debugName: "dragAmount" }] : /* istanbul ignore next */ []));
|
|
1655
2204
|
const document = inject(DOCUMENT);
|
|
1656
2205
|
const canScroll = computed(() => {
|
|
1657
2206
|
const currentScrollState = scrollState();
|
|
@@ -1664,7 +2213,8 @@ const useCursorDragScroll = (el, options) => {
|
|
|
1664
2213
|
case 'vertical':
|
|
1665
2214
|
return currentScrollState.canScrollVertically;
|
|
1666
2215
|
}
|
|
1667
|
-
},
|
|
2216
|
+
}, /* @ts-ignore */
|
|
2217
|
+
...(ngDevMode ? [{ debugName: "canScroll" }] : /* istanbul ignore next */ []));
|
|
1668
2218
|
// Cleanup if the element the cursor drag scroll is bound to gets changed
|
|
1669
2219
|
effect(() => {
|
|
1670
2220
|
const { previousElement } = element();
|
|
@@ -1831,21 +2381,29 @@ const injectIsRouterInitialized = memoizeSignal(() => {
|
|
|
1831
2381
|
*/
|
|
1832
2382
|
const injectUrl = memoizeSignal(() => {
|
|
1833
2383
|
const event = injectRouterEvent();
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
2384
|
+
const router = inject(Router);
|
|
2385
|
+
// Captured once for reads that happen before the router has committed any
|
|
2386
|
+
// navigation (SSR / initial load), where `router.url` isn't reliable yet.
|
|
2387
|
+
const initialRoute = createInitialRoute();
|
|
2388
|
+
return computed(() => {
|
|
2389
|
+
// We depend on `event` and `currentNavigation` only to get re-evaluated
|
|
2390
|
+
// around each navigation, but we read the *committed* url straight from the
|
|
2391
|
+
// router. The router commits `currentUrlTree` before it activates components,
|
|
2392
|
+
// so `router.url` is already correct inside a child component's constructor —
|
|
2393
|
+
// unlike the NavigationEnd event, which only reaches this signal *after*
|
|
2394
|
+
// activation.
|
|
2395
|
+
event();
|
|
2396
|
+
const currentNavigation = router.currentNavigation();
|
|
2397
|
+
// Before the very first navigation the router url isn't populated yet (e.g.
|
|
2398
|
+
// SSR / a deep link read before the initial navigation runs), so fall back
|
|
2399
|
+
// to the browser location captured at startup. `navigated` flips only at
|
|
2400
|
+
// NavigationEnd, so we also check for an in-flight navigation to stay correct
|
|
2401
|
+
// during the initial navigation's component construction.
|
|
2402
|
+
if (router.navigated || currentNavigation !== null) {
|
|
2403
|
+
return router.url;
|
|
2404
|
+
}
|
|
2405
|
+
return initialRoute;
|
|
2406
|
+
});
|
|
1849
2407
|
});
|
|
1850
2408
|
/**
|
|
1851
2409
|
* Inject the current route
|
|
@@ -1874,54 +2432,64 @@ const createRouterState = (router) => {
|
|
|
1874
2432
|
fragment,
|
|
1875
2433
|
};
|
|
1876
2434
|
};
|
|
2435
|
+
/**
|
|
2436
|
+
* Read the current route (the committed url without query params and fragment) straight from the router.
|
|
2437
|
+
* Unlike the `injectRoute` signal this reads synchronously, so it can be used inside a `router.events` handler
|
|
2438
|
+
* where `router.url` is already committed. Falls back to the browser location before the first navigation commits.
|
|
2439
|
+
*/
|
|
2440
|
+
const createRoute = (router) => {
|
|
2441
|
+
const url = router.navigated ? router.url : window.location.pathname + window.location.search + window.location.hash;
|
|
2442
|
+
return url.split('?')[0]?.split('#')[0] ?? '';
|
|
2443
|
+
};
|
|
1877
2444
|
/**
|
|
1878
2445
|
* Inject the complete router state. This includes the current route data, path params, query params, title and fragment.
|
|
1879
2446
|
*/
|
|
1880
2447
|
const injectRouterState = memoizeSignal(() => {
|
|
1881
2448
|
const event = injectRouterEvent();
|
|
1882
2449
|
const router = inject(Router);
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
}
|
|
1893
|
-
});
|
|
1894
|
-
});
|
|
1895
|
-
return computed(() => routerState(), { equal });
|
|
2450
|
+
// We only depend on `event` to get re-evaluated on every router event, but we
|
|
2451
|
+
// read the *committed* snapshot straight from the router. The router commits
|
|
2452
|
+
// `routerState` before it activates components (and emits ActivationStart
|
|
2453
|
+
// before NavigationEnd), so this is already correct inside a child component's
|
|
2454
|
+
// constructor — unlike an effect, which only flushes after construction.
|
|
2455
|
+
return computed(() => {
|
|
2456
|
+
event();
|
|
2457
|
+
return createRouterState(router);
|
|
2458
|
+
}, { equal });
|
|
1896
2459
|
});
|
|
1897
2460
|
/** Inject a signal containing the current route fragment (the part after the # inside the url if present) */
|
|
1898
2461
|
const injectFragment = (config) => {
|
|
1899
2462
|
const routerState = injectRouterState();
|
|
1900
|
-
const fragment = computed(() => routerState().fragment,
|
|
2463
|
+
const fragment = computed(() => routerState().fragment, /* @ts-ignore */
|
|
2464
|
+
...(ngDevMode ? [{ debugName: "fragment" }] : /* istanbul ignore next */ []));
|
|
1901
2465
|
return transformOrReturn(fragment, config);
|
|
1902
2466
|
};
|
|
1903
2467
|
/** Inject all currently available query parameters as a signal */
|
|
1904
2468
|
const injectQueryParams = () => {
|
|
1905
2469
|
const routerState = injectRouterState();
|
|
1906
|
-
const queryParams = computed(() => routerState().queryParams,
|
|
2470
|
+
const queryParams = computed(() => routerState().queryParams, /* @ts-ignore */
|
|
2471
|
+
...(ngDevMode ? [{ debugName: "queryParams" }] : /* istanbul ignore next */ []));
|
|
1907
2472
|
return queryParams;
|
|
1908
2473
|
};
|
|
1909
2474
|
/** Inject all currently available route data as a signal */
|
|
1910
2475
|
const injectRouteData = () => {
|
|
1911
2476
|
const routerState = injectRouterState();
|
|
1912
|
-
const data = computed(() => routerState().data,
|
|
2477
|
+
const data = computed(() => routerState().data, /* @ts-ignore */
|
|
2478
|
+
...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
|
|
1913
2479
|
return data;
|
|
1914
2480
|
};
|
|
1915
2481
|
/** Inject the current route title as a signal */
|
|
1916
2482
|
const injectRouteTitle = (config) => {
|
|
1917
2483
|
const routerState = injectRouterState();
|
|
1918
|
-
const title = computed(() => routerState().title,
|
|
2484
|
+
const title = computed(() => routerState().title, /* @ts-ignore */
|
|
2485
|
+
...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
|
|
1919
2486
|
return transformOrReturn(title, config);
|
|
1920
2487
|
};
|
|
1921
2488
|
/** Inject all currently available path parameters as a signal */
|
|
1922
2489
|
const injectPathParams = () => {
|
|
1923
2490
|
const routerState = injectRouterState();
|
|
1924
|
-
const pathParams = computed(() => routerState().pathParams,
|
|
2491
|
+
const pathParams = computed(() => routerState().pathParams, /* @ts-ignore */
|
|
2492
|
+
...(ngDevMode ? [{ debugName: "pathParams" }] : /* istanbul ignore next */ []));
|
|
1925
2493
|
return pathParams;
|
|
1926
2494
|
};
|
|
1927
2495
|
const getQueryParamFromUrl = (key) => {
|
|
@@ -2010,14 +2578,18 @@ const setupScrollRestoration = (config = {}) => {
|
|
|
2010
2578
|
if (!isPlatformBrowser(inject(PLATFORM_ID))) {
|
|
2011
2579
|
return;
|
|
2012
2580
|
}
|
|
2013
|
-
const
|
|
2014
|
-
const route = injectRoute();
|
|
2581
|
+
const router = inject(Router);
|
|
2015
2582
|
const document = inject(DOCUMENT);
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
.
|
|
2019
|
-
|
|
2583
|
+
let prev = { state: createRouterState(router), route: createRoute(router) };
|
|
2584
|
+
router.events
|
|
2585
|
+
.pipe(filter((e) => e instanceof NavigationEnd || e instanceof NavigationSkipped), takeUntilDestroyed())
|
|
2586
|
+
.subscribe(() => {
|
|
2587
|
+
const curr = { state: createRouterState(router), route: createRoute(router) };
|
|
2588
|
+
const prevState = prev.state;
|
|
2589
|
+
const currState = curr.state;
|
|
2590
|
+
const sameUrlNavigation = prev.route === curr.route;
|
|
2020
2591
|
const didFragmentChange = prevState.fragment !== currState.fragment;
|
|
2592
|
+
prev = curr;
|
|
2021
2593
|
if (sameUrlNavigation) {
|
|
2022
2594
|
const allQueryParams = [
|
|
2023
2595
|
...new Set(Object.keys(prevState.queryParams).concat(Object.keys(currState.queryParams))),
|
|
@@ -2068,6 +2640,206 @@ const createLogger = (config) => {
|
|
|
2068
2640
|
};
|
|
2069
2641
|
};
|
|
2070
2642
|
|
|
2643
|
+
const escapeHtml = (str) => str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
2644
|
+
const unescapeHtml = (str) => str
|
|
2645
|
+
.replace(/&/g, '&')
|
|
2646
|
+
.replace(/</g, '<')
|
|
2647
|
+
.replace(/>/g, '>')
|
|
2648
|
+
.replace(/"/g, '"')
|
|
2649
|
+
.replace(/'/g, "'")
|
|
2650
|
+
.replace(/ /g, ' ');
|
|
2651
|
+
const stripTags = (str) => str.replace(/<[^>]+>/g, '');
|
|
2652
|
+
const parseTableRow = (line) => line
|
|
2653
|
+
.split('|')
|
|
2654
|
+
.slice(1, -1)
|
|
2655
|
+
.map((cell) => cell.trim());
|
|
2656
|
+
const isTableSeparatorLine = (line) => /^\|?(\s*:?-+:?\s*\|)+\s*$/.test(line);
|
|
2657
|
+
const makePlaceholder = (kind, idx) => `\u{E000}${kind}${idx}\u{E001}`;
|
|
2658
|
+
const placeholderRe = (kind) => new RegExp(`\u{E000}${kind}(\\d+)\u{E001}`, 'gu');
|
|
2659
|
+
const isPlaceholder = (kind, str) => new RegExp(`^\u{E000}${kind}\\d+\u{E001}$`, 'u').test(str);
|
|
2660
|
+
const processInline = (text) => {
|
|
2661
|
+
const inlineCodes = [];
|
|
2662
|
+
text = text.replace(/`([^`]+)`/g, (_, code) => {
|
|
2663
|
+
const idx = inlineCodes.push(`<code>${escapeHtml(code)}</code>`) - 1;
|
|
2664
|
+
return makePlaceholder('IC', idx);
|
|
2665
|
+
});
|
|
2666
|
+
// Bold + italic — *** before ** before *
|
|
2667
|
+
text = text.replace(/\*\*\*(.+?)\*\*\*/g, '<strong><em>$1</em></strong>');
|
|
2668
|
+
text = text.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
|
|
2669
|
+
text = text.replace(/__(.+?)__/g, '<strong>$1</strong>');
|
|
2670
|
+
text = text.replace(/\*(.+?)\*/g, '<em>$1</em>');
|
|
2671
|
+
text = text.replace(/~~(.+?)~~/g, '<del>$1</del>');
|
|
2672
|
+
// Images before links (order matters)
|
|
2673
|
+
text = text.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '<img src="$2" alt="$1">');
|
|
2674
|
+
text = text.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2">$1</a>');
|
|
2675
|
+
return text.replace(placeholderRe('IC'), (_, i) => inlineCodes[+i] ?? '');
|
|
2676
|
+
};
|
|
2677
|
+
/**
|
|
2678
|
+
* Converts a markdown string to HTML.
|
|
2679
|
+
* Covers headings, bold, italic, strikethrough, inline code, fenced code blocks,
|
|
2680
|
+
* links, images, block quotes, unordered/ordered lists, tables, horizontal rules, and paragraphs.
|
|
2681
|
+
*/
|
|
2682
|
+
const markdownToHtml = (markdown) => {
|
|
2683
|
+
if (!markdown)
|
|
2684
|
+
return '';
|
|
2685
|
+
let text = markdown.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
2686
|
+
// Extract fenced code blocks before any other processing
|
|
2687
|
+
const codeBlocks = [];
|
|
2688
|
+
text = text.replace(/```(\w*)\n([\s\S]*?)```/g, (_, lang, code) => {
|
|
2689
|
+
const langAttr = lang ? ` class="language-${lang}"` : '';
|
|
2690
|
+
const idx = codeBlocks.push(`<pre><code${langAttr}>${escapeHtml(code.trim())}</code></pre>`) - 1;
|
|
2691
|
+
return makePlaceholder('CODE', idx);
|
|
2692
|
+
});
|
|
2693
|
+
// Markdown headings don't require blank lines around them, but blocks are
|
|
2694
|
+
// split on blank lines below. Isolate each heading line into its own block so
|
|
2695
|
+
// a heading directly followed by a list/paragraph isn't swallowed into it.
|
|
2696
|
+
text = text.replace(/^(#{1,6}\s+.+)$/gm, '\n\n$1\n\n');
|
|
2697
|
+
const html = text
|
|
2698
|
+
.split(/\n\n+/)
|
|
2699
|
+
.map((block) => {
|
|
2700
|
+
const trimmed = block.trim();
|
|
2701
|
+
if (!trimmed)
|
|
2702
|
+
return '';
|
|
2703
|
+
if (isPlaceholder('CODE', trimmed))
|
|
2704
|
+
return trimmed;
|
|
2705
|
+
// Heading
|
|
2706
|
+
const headingMatch = trimmed.match(/^(#{1,6})\s+(.+)$/);
|
|
2707
|
+
if (headingMatch?.[1] && headingMatch?.[2]) {
|
|
2708
|
+
const level = headingMatch[1].length;
|
|
2709
|
+
return `<h${level}>${processInline(headingMatch[2].trim())}</h${level}>`;
|
|
2710
|
+
}
|
|
2711
|
+
// Horizontal rule
|
|
2712
|
+
if (/^(---|\*\*\*|___)\s*$/.test(trimmed))
|
|
2713
|
+
return '<hr>';
|
|
2714
|
+
// Table (GFM)
|
|
2715
|
+
const tableLines = trimmed.split('\n');
|
|
2716
|
+
if (tableLines.length >= 2 && /\|/.test(tableLines[0] ?? '') && isTableSeparatorLine(tableLines[1] ?? '')) {
|
|
2717
|
+
const headers = parseTableRow(tableLines[0] ?? '');
|
|
2718
|
+
const thead = `<thead><tr>${headers.map((h) => `<th>${processInline(h)}</th>`).join('')}</tr></thead>`;
|
|
2719
|
+
const bodyRows = tableLines.slice(2);
|
|
2720
|
+
const tbody = bodyRows.length > 0
|
|
2721
|
+
? `<tbody>${bodyRows
|
|
2722
|
+
.map((row) => `<tr>${parseTableRow(row)
|
|
2723
|
+
.map((cell) => `<td>${processInline(cell)}</td>`)
|
|
2724
|
+
.join('')}</tr>`)
|
|
2725
|
+
.join('')}</tbody>`
|
|
2726
|
+
: '';
|
|
2727
|
+
return `<table>${thead}${tbody}</table>`;
|
|
2728
|
+
}
|
|
2729
|
+
// Blockquote
|
|
2730
|
+
if (/^> /.test(trimmed)) {
|
|
2731
|
+
const content = trimmed
|
|
2732
|
+
.split('\n')
|
|
2733
|
+
.map((l) => l.replace(/^>\s?/, ''))
|
|
2734
|
+
.join('<br>');
|
|
2735
|
+
return `<blockquote>${processInline(content)}</blockquote>`;
|
|
2736
|
+
}
|
|
2737
|
+
// Unordered list
|
|
2738
|
+
if (/^[-*+]\s/.test(trimmed)) {
|
|
2739
|
+
const items = trimmed
|
|
2740
|
+
.split('\n')
|
|
2741
|
+
.filter((l) => /^[-*+]\s/.test(l))
|
|
2742
|
+
.map((l) => `<li>${processInline(l.replace(/^[-*+]\s+/, '').trim())}</li>`)
|
|
2743
|
+
.join('');
|
|
2744
|
+
return `<ul>${items}</ul>`;
|
|
2745
|
+
}
|
|
2746
|
+
// Ordered list
|
|
2747
|
+
if (/^\d+\.\s/.test(trimmed)) {
|
|
2748
|
+
const items = trimmed
|
|
2749
|
+
.split('\n')
|
|
2750
|
+
.filter((l) => /^\d+\.\s/.test(l))
|
|
2751
|
+
.map((l) => `<li>${processInline(l.replace(/^\d+\.\s+/, '').trim())}</li>`)
|
|
2752
|
+
.join('');
|
|
2753
|
+
return `<ol>${items}</ol>`;
|
|
2754
|
+
}
|
|
2755
|
+
// Paragraph — single newlines within a block become <br>
|
|
2756
|
+
return `<p>${trimmed
|
|
2757
|
+
.split('\n')
|
|
2758
|
+
.map((l) => processInline(l))
|
|
2759
|
+
.join('<br>')}</p>`;
|
|
2760
|
+
})
|
|
2761
|
+
.filter(Boolean)
|
|
2762
|
+
.join('\n');
|
|
2763
|
+
return html.replace(placeholderRe('CODE'), (_, i) => codeBlocks[+i] ?? '');
|
|
2764
|
+
};
|
|
2765
|
+
/**
|
|
2766
|
+
* Converts an HTML string to markdown.
|
|
2767
|
+
* Covers headings, bold, italic, strikethrough, inline code, fenced code blocks,
|
|
2768
|
+
* links, images, block quotes, unordered/ordered lists, tables, horizontal rules, and paragraphs.
|
|
2769
|
+
*/
|
|
2770
|
+
const htmlToMarkdown = (html) => {
|
|
2771
|
+
if (!html)
|
|
2772
|
+
return '';
|
|
2773
|
+
let md = html;
|
|
2774
|
+
// Code blocks — process before inline code
|
|
2775
|
+
md = md.replace(/<pre[^>]*><code[^>]*class="language-([^"]+)"[^>]*>([\s\S]*?)<\/code><\/pre>/gi, (_, lang, code) => `\n\`\`\`${lang}\n${unescapeHtml(code.trim())}\n\`\`\`\n`);
|
|
2776
|
+
md = md.replace(/<pre[^>]*><code[^>]*>([\s\S]*?)<\/code><\/pre>/gi, (_, code) => `\n\`\`\`\n${unescapeHtml(code.trim())}\n\`\`\`\n`);
|
|
2777
|
+
md = md.replace(/<pre[^>]*>([\s\S]*?)<\/pre>/gi, (_, code) => `\n\`\`\`\n${unescapeHtml(code.trim())}\n\`\`\`\n`);
|
|
2778
|
+
// Headings — keep the inner markup so the inline passes below turn any nested
|
|
2779
|
+
// bold/italic/link/code into markdown; leftover tags are stripped at the end.
|
|
2780
|
+
for (let i = 6; i >= 1; i--) {
|
|
2781
|
+
md = md.replace(new RegExp(`<h${i}[^>]*>([\\s\\S]*?)<\\/h${i}>`, 'gi'), (_, content) => `\n${'#'.repeat(i)} ${content.trim()}\n`);
|
|
2782
|
+
}
|
|
2783
|
+
// Bold + italic (combined before individual)
|
|
2784
|
+
md = md.replace(/<strong[^>]*><em[^>]*>([\s\S]*?)<\/em><\/strong>/gi, '***$1***');
|
|
2785
|
+
md = md.replace(/<em[^>]*><strong[^>]*>([\s\S]*?)<\/strong><\/em>/gi, '***$1***');
|
|
2786
|
+
md = md.replace(/<(strong|b)[^>]*>([\s\S]*?)<\/\1>/gi, '**$2**');
|
|
2787
|
+
md = md.replace(/<(em|i)[^>]*>([\s\S]*?)<\/\1>/gi, '*$2*');
|
|
2788
|
+
md = md.replace(/<(del|s|strike)[^>]*>([\s\S]*?)<\/\1>/gi, '~~$2~~');
|
|
2789
|
+
// Inline code
|
|
2790
|
+
md = md.replace(/<code[^>]*>([\s\S]*?)<\/code>/gi, (_, code) => `\`${unescapeHtml(code)}\``);
|
|
2791
|
+
// Links and images
|
|
2792
|
+
md = md.replace(/<a[^>]+href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/gi, '[$2]($1)');
|
|
2793
|
+
md = md.replace(/<img[^>]+src="([^"]*)"[^>]*alt="([^"]*)"[^>]*\/?>/gi, '');
|
|
2794
|
+
md = md.replace(/<img[^>]+alt="([^"]*)"[^>]*src="([^"]*)"[^>]*\/?>/gi, '');
|
|
2795
|
+
md = md.replace(/<img[^>]+src="([^"]*)"[^>]*\/?>/gi, '');
|
|
2796
|
+
// Block quotes
|
|
2797
|
+
md = md.replace(/<blockquote[^>]*>([\s\S]*?)<\/blockquote>/gi, (_, content) => {
|
|
2798
|
+
return (stripTags(content)
|
|
2799
|
+
.trim()
|
|
2800
|
+
.split('\n')
|
|
2801
|
+
.map((line) => `> ${line.trim()}`)
|
|
2802
|
+
.join('\n') + '\n');
|
|
2803
|
+
});
|
|
2804
|
+
// Lists
|
|
2805
|
+
md = md.replace(/<ul[^>]*>([\s\S]*?)<\/ul>/gi, (_, content) => {
|
|
2806
|
+
return ('\n' +
|
|
2807
|
+
content.replace(/<li[^>]*>([\s\S]*?)<\/li>/gi, (_m, item) => `- ${stripTags(item).trim()}\n`));
|
|
2808
|
+
});
|
|
2809
|
+
md = md.replace(/<ol[^>]*>([\s\S]*?)<\/ol>/gi, (_, content) => {
|
|
2810
|
+
let n = 1;
|
|
2811
|
+
return ('\n' +
|
|
2812
|
+
content.replace(/<li[^>]*>([\s\S]*?)<\/li>/gi, (_m, item) => `${n++}. ${stripTags(item).trim()}\n`));
|
|
2813
|
+
});
|
|
2814
|
+
// Tables
|
|
2815
|
+
md = md.replace(/<table[^>]*>([\s\S]*?)<\/table>/gi, (_, tableContent) => {
|
|
2816
|
+
const extractCells = (row) => [...row.matchAll(/<t[hd][^>]*>([\s\S]*?)<\/t[hd]>/gi)].map((m) => stripTags(m[1] ?? '').trim());
|
|
2817
|
+
const theadMatch = tableContent.match(/<thead[^>]*>([\s\S]*?)<\/thead>/i);
|
|
2818
|
+
const firstTrMatch = tableContent.match(/<tr[^>]*>([\s\S]*?)<\/tr>/i);
|
|
2819
|
+
const headerCells = theadMatch
|
|
2820
|
+
? extractCells(theadMatch[1] ?? '')
|
|
2821
|
+
: firstTrMatch
|
|
2822
|
+
? extractCells(firstTrMatch[1] ?? '')
|
|
2823
|
+
: [];
|
|
2824
|
+
if (headerCells.length === 0)
|
|
2825
|
+
return '';
|
|
2826
|
+
const separator = headerCells.map(() => '---').join(' | ');
|
|
2827
|
+
const bodySource = theadMatch
|
|
2828
|
+
? tableContent.replace(theadMatch[0], '')
|
|
2829
|
+
: tableContent.replace(firstTrMatch?.[0] ?? '', '');
|
|
2830
|
+
const bodyRows = [...bodySource.matchAll(/<tr[^>]*>([\s\S]*?)<\/tr>/gi)].map((m) => extractCells(m[1] ?? '').join(' | '));
|
|
2831
|
+
const lines = [`| ${headerCells.join(' | ')} |`, `| ${separator} |`, ...bodyRows.map((r) => `| ${r} |`)];
|
|
2832
|
+
return `\n${lines.join('\n')}\n`;
|
|
2833
|
+
});
|
|
2834
|
+
// Block elements
|
|
2835
|
+
md = md.replace(/<p[^>]*>([\s\S]*?)<\/p>/gi, (_, content) => `\n${stripTags(content).trim()}\n`);
|
|
2836
|
+
md = md.replace(/<br\s*\/?>/gi, '\n');
|
|
2837
|
+
md = md.replace(/<hr\s*\/?>/gi, '\n---\n');
|
|
2838
|
+
return unescapeHtml(stripTags(md))
|
|
2839
|
+
.replace(/\n{3,}/g, '\n\n')
|
|
2840
|
+
.trim();
|
|
2841
|
+
};
|
|
2842
|
+
|
|
2071
2843
|
const clamp = (value, min = 0, max = 100) => {
|
|
2072
2844
|
return Math.max(min, Math.min(max, value));
|
|
2073
2845
|
};
|
|
@@ -2108,10 +2880,9 @@ const getObjectProperty = (obj, prop) => {
|
|
|
2108
2880
|
|
|
2109
2881
|
const RUNTIME_ERROR_NO_DATA = '__ET_NO_DATA__';
|
|
2110
2882
|
class RuntimeError extends Error {
|
|
2111
|
-
constructor(code, message,
|
|
2112
|
-
super(formatRuntimeError(code, message
|
|
2883
|
+
constructor(code, message, data = RUNTIME_ERROR_NO_DATA) {
|
|
2884
|
+
super(formatRuntimeError(code, message));
|
|
2113
2885
|
this.code = code;
|
|
2114
|
-
this.devOnly = devOnly;
|
|
2115
2886
|
this.data = data;
|
|
2116
2887
|
if (data !== RUNTIME_ERROR_NO_DATA) {
|
|
2117
2888
|
try {
|
|
@@ -2128,299 +2899,220 @@ class RuntimeError extends Error {
|
|
|
2128
2899
|
}
|
|
2129
2900
|
}
|
|
2130
2901
|
}
|
|
2131
|
-
function formatRuntimeError(code, message
|
|
2902
|
+
function formatRuntimeError(code, message) {
|
|
2132
2903
|
// prefix code with zeros if it's less than 100
|
|
2133
2904
|
const codeWithZeros = code < 10 ? `00${code}` : code < 100 ? `0${code}` : code;
|
|
2134
2905
|
const fullCode = `ET${codeWithZeros}`;
|
|
2135
|
-
|
|
2136
|
-
return `${devOnlyText}${fullCode}${message ? ': ' + message : ''}`;
|
|
2906
|
+
return `${fullCode}${message ? ': ' + message : ''}`;
|
|
2137
2907
|
}
|
|
2138
2908
|
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2909
|
+
const createAutoSessionMemoryKey = ({ element, prefix }) => {
|
|
2910
|
+
const pathSegments = [];
|
|
2911
|
+
let currentElement = element;
|
|
2912
|
+
while (currentElement) {
|
|
2913
|
+
const currentElementName = currentElement.localName;
|
|
2914
|
+
const parentElement = currentElement.parentElement;
|
|
2915
|
+
if (!parentElement) {
|
|
2916
|
+
pathSegments.unshift(currentElementName);
|
|
2917
|
+
break;
|
|
2918
|
+
}
|
|
2919
|
+
const siblingElements = Array.from(parentElement.children);
|
|
2920
|
+
const siblingIndex = siblingElements.indexOf(currentElement);
|
|
2921
|
+
pathSegments.unshift(`${currentElementName}[${siblingIndex}]`);
|
|
2922
|
+
currentElement = parentElement;
|
|
2153
2923
|
}
|
|
2154
|
-
|
|
2924
|
+
const locationPath = element.ownerDocument.defaultView?.location.pathname ?? 'root';
|
|
2925
|
+
return `${prefix}:${locationPath}:${pathSegments.join('/')}`;
|
|
2155
2926
|
};
|
|
2156
|
-
const
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
toJSON: () => ({}),
|
|
2166
|
-
});
|
|
2167
|
-
const isElementVisible = (options) => {
|
|
2168
|
-
const { container, element } = options;
|
|
2169
|
-
if (!element) {
|
|
2170
|
-
return null;
|
|
2927
|
+
const canUseSessionMemory = () => {
|
|
2928
|
+
try {
|
|
2929
|
+
if (typeof globalThis.window === 'undefined') {
|
|
2930
|
+
return false;
|
|
2931
|
+
}
|
|
2932
|
+
if (typeof globalThis.document === 'undefined') {
|
|
2933
|
+
return false;
|
|
2934
|
+
}
|
|
2935
|
+
return globalThis.sessionStorage != null;
|
|
2171
2936
|
}
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
const canScroll = elementCanScroll(container);
|
|
2175
|
-
if (!canScroll) {
|
|
2176
|
-
return {
|
|
2177
|
-
inline: true,
|
|
2178
|
-
block: true,
|
|
2179
|
-
blockIntersection: 1,
|
|
2180
|
-
inlineIntersection: 1,
|
|
2181
|
-
intersectionRatio: 1,
|
|
2182
|
-
isIntersecting: true,
|
|
2183
|
-
element,
|
|
2184
|
-
containerRect,
|
|
2185
|
-
elementRect,
|
|
2186
|
-
};
|
|
2937
|
+
catch {
|
|
2938
|
+
return false;
|
|
2187
2939
|
}
|
|
2188
|
-
const elLeft = elementRect.left;
|
|
2189
|
-
const elTop = elementRect.top;
|
|
2190
|
-
const elWidth = elementRect.width || 1;
|
|
2191
|
-
const elHeight = elementRect.height || 1;
|
|
2192
|
-
const elRight = elLeft + elWidth;
|
|
2193
|
-
const elBottom = elTop + elHeight;
|
|
2194
|
-
const conLeft = containerRect.left;
|
|
2195
|
-
const conTop = containerRect.top;
|
|
2196
|
-
const conRight = conLeft + containerRect.width;
|
|
2197
|
-
const conBottom = conTop + containerRect.height;
|
|
2198
|
-
const isElementInlineVisible = elLeft >= conLeft && elRight <= conRight;
|
|
2199
|
-
const isElementBlockVisible = elTop >= conTop && elBottom <= conBottom;
|
|
2200
|
-
const inlineIntersection = Math.min(elRight, conRight) - Math.max(elLeft, conLeft);
|
|
2201
|
-
const blockIntersection = Math.min(elBottom, conBottom) - Math.max(elTop, conTop);
|
|
2202
|
-
const inlineIntersectionPercentage = clamp(inlineIntersection / elWidth, 0, 1);
|
|
2203
|
-
const blockIntersectionPercentage = clamp(blockIntersection / elHeight, 0, 1);
|
|
2204
|
-
return {
|
|
2205
|
-
inline: isElementInlineVisible,
|
|
2206
|
-
block: isElementBlockVisible,
|
|
2207
|
-
inlineIntersection: inlineIntersectionPercentage,
|
|
2208
|
-
blockIntersection: blockIntersectionPercentage,
|
|
2209
|
-
isIntersecting: isElementInlineVisible && isElementBlockVisible,
|
|
2210
|
-
element,
|
|
2211
|
-
containerRect,
|
|
2212
|
-
elementRect,
|
|
2213
|
-
// Round the intersection ratio to the nearest 0.01 to avoid floating point errors and system scaling issues.
|
|
2214
|
-
intersectionRatio: Math.round(Math.min(inlineIntersectionPercentage, blockIntersectionPercentage) * 100) / 100,
|
|
2215
|
-
};
|
|
2216
2940
|
};
|
|
2217
|
-
const
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
return {
|
|
2221
|
-
behavior,
|
|
2222
|
-
left: undefined,
|
|
2223
|
-
top: undefined,
|
|
2224
|
-
};
|
|
2941
|
+
const getSessionStorage = () => {
|
|
2942
|
+
if (!canUseSessionMemory()) {
|
|
2943
|
+
return null;
|
|
2225
2944
|
}
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
const
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
const elRight = elementRect.right;
|
|
2234
|
-
const elBottom = elementRect.bottom;
|
|
2235
|
-
const conWidth = containerRect.width;
|
|
2236
|
-
const conHeight = containerRect.height;
|
|
2237
|
-
const conLeft = containerRect.left;
|
|
2238
|
-
const conTop = containerRect.top;
|
|
2239
|
-
const conRight = containerRect.right;
|
|
2240
|
-
const conBottom = containerRect.bottom;
|
|
2241
|
-
const shouldScrollLeft = direction === 'inline' || direction === 'both' || !direction;
|
|
2242
|
-
const shouldScrollTop = direction === 'block' || direction === 'both' || !direction;
|
|
2243
|
-
let scrollLeftTo = scrollLeft;
|
|
2244
|
-
let scrollTopTo = scrollTop;
|
|
2245
|
-
const relativeTop = elTop - conTop;
|
|
2246
|
-
const relativeLeft = elLeft - conLeft;
|
|
2247
|
-
const calculateScrollToStart = () => {
|
|
2248
|
-
scrollLeftTo = scrollLeft + relativeLeft - scrollInlineMargin;
|
|
2249
|
-
scrollTopTo = scrollTop + relativeTop - scrollBlockMargin;
|
|
2250
|
-
};
|
|
2251
|
-
const calculateScrollToEnd = () => {
|
|
2252
|
-
scrollLeftTo = scrollLeft + relativeLeft - conWidth + elWidth + scrollInlineMargin;
|
|
2253
|
-
scrollTopTo = scrollTop + relativeTop - conHeight + elHeight + scrollBlockMargin;
|
|
2254
|
-
};
|
|
2255
|
-
const calculateScrollToCenter = () => {
|
|
2256
|
-
scrollLeftTo = scrollLeft + relativeLeft - conWidth / 2 + elWidth / 2;
|
|
2257
|
-
scrollTopTo = scrollTop + relativeTop - conHeight / 2 + elHeight / 2;
|
|
2258
|
-
};
|
|
2259
|
-
const calculateScrollToNearest = () => {
|
|
2260
|
-
const isAbove = elBottom < conTop;
|
|
2261
|
-
const isPartialAbove = elTop < conTop && elBottom > conTop;
|
|
2262
|
-
const isBelow = elTop > conBottom;
|
|
2263
|
-
const isPartialBelow = elTop < conBottom && elBottom > conBottom;
|
|
2264
|
-
const isLeft = elRight < conLeft;
|
|
2265
|
-
const isPartialLeft = elLeft < conLeft && elRight > conLeft;
|
|
2266
|
-
const isRight = elLeft > conRight;
|
|
2267
|
-
const isPartialRight = elLeft < conRight && elRight > conRight;
|
|
2268
|
-
if (isAbove || isPartialAbove || isLeft || isPartialLeft) {
|
|
2269
|
-
calculateScrollToStart();
|
|
2945
|
+
return globalThis.sessionStorage;
|
|
2946
|
+
};
|
|
2947
|
+
const createSessionMemory = ({ key, parse, serialize }) => {
|
|
2948
|
+
const read = () => {
|
|
2949
|
+
const sessionStorage = getSessionStorage();
|
|
2950
|
+
if (!sessionStorage) {
|
|
2951
|
+
return null;
|
|
2270
2952
|
}
|
|
2271
|
-
|
|
2272
|
-
|
|
2953
|
+
try {
|
|
2954
|
+
const storedValue = sessionStorage.getItem(key);
|
|
2955
|
+
if (storedValue === null) {
|
|
2956
|
+
return null;
|
|
2957
|
+
}
|
|
2958
|
+
return parse(storedValue);
|
|
2959
|
+
}
|
|
2960
|
+
catch {
|
|
2961
|
+
return null;
|
|
2273
2962
|
}
|
|
2274
2963
|
};
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
break;
|
|
2288
|
-
}
|
|
2289
|
-
return {
|
|
2290
|
-
behavior,
|
|
2291
|
-
left: shouldScrollLeft ? scrollLeftTo : undefined,
|
|
2292
|
-
top: shouldScrollTop ? scrollTopTo : undefined,
|
|
2964
|
+
const write = (value) => {
|
|
2965
|
+
const sessionStorage = getSessionStorage();
|
|
2966
|
+
if (!sessionStorage) {
|
|
2967
|
+
return false;
|
|
2968
|
+
}
|
|
2969
|
+
try {
|
|
2970
|
+
sessionStorage.setItem(key, serialize(value));
|
|
2971
|
+
return true;
|
|
2972
|
+
}
|
|
2973
|
+
catch {
|
|
2974
|
+
return false;
|
|
2975
|
+
}
|
|
2293
2976
|
};
|
|
2294
|
-
|
|
2295
|
-
const
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
const [, injectAngularRootElement] = createRootProvider(() => {
|
|
2300
|
-
const appRef = inject(ApplicationRef);
|
|
2301
|
-
const rootElement = signal(null, ...(ngDevMode ? [{ debugName: "rootElement" }] : []));
|
|
2302
|
-
const poll = () => {
|
|
2303
|
-
const appComponents = appRef.components;
|
|
2304
|
-
if (appComponents.length > 0) {
|
|
2305
|
-
rootElement.set(appComponents[0]?.location.nativeElement);
|
|
2977
|
+
const remove = () => {
|
|
2978
|
+
const sessionStorage = getSessionStorage();
|
|
2979
|
+
if (!sessionStorage) {
|
|
2980
|
+
return false;
|
|
2306
2981
|
}
|
|
2307
|
-
|
|
2308
|
-
|
|
2982
|
+
try {
|
|
2983
|
+
sessionStorage.removeItem(key);
|
|
2984
|
+
return true;
|
|
2985
|
+
}
|
|
2986
|
+
catch {
|
|
2987
|
+
return false;
|
|
2309
2988
|
}
|
|
2310
2989
|
};
|
|
2311
|
-
setTimeout(poll);
|
|
2312
|
-
return rootElement;
|
|
2313
|
-
});
|
|
2314
|
-
|
|
2315
|
-
const [provideBoundaryElement, injectBoundaryElement, BOUNDARY_ELEMENT_TOKEN] = createProvider(() => {
|
|
2316
|
-
const hostElement = inject(ElementRef, { optional: true });
|
|
2317
|
-
const document = inject(DOCUMENT);
|
|
2318
|
-
const override = signal(null, ...(ngDevMode ? [{ debugName: "override" }] : []));
|
|
2319
|
-
const value = computed(() => override() ?? hostElement?.nativeElement ?? document.documentElement, ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
2320
2990
|
return {
|
|
2321
|
-
|
|
2322
|
-
|
|
2991
|
+
read,
|
|
2992
|
+
write,
|
|
2993
|
+
remove,
|
|
2323
2994
|
};
|
|
2324
|
-
}, { name: 'Boundary Element' });
|
|
2325
|
-
|
|
2326
|
-
/**
|
|
2327
|
-
* Default viewport config based on Tailwind CSS.
|
|
2328
|
-
* @see https://tailwindcss.com/docs/screens
|
|
2329
|
-
*/
|
|
2330
|
-
const DEFAULT_VIEWPORT_CONFIG = {
|
|
2331
|
-
breakpoints: {
|
|
2332
|
-
xs: [0, 639],
|
|
2333
|
-
sm: [640, 767],
|
|
2334
|
-
md: [768, 1023],
|
|
2335
|
-
lg: [1024, 1279],
|
|
2336
|
-
xl: [1280, 1535],
|
|
2337
|
-
'2xl': [1536, Infinity],
|
|
2338
|
-
},
|
|
2339
2995
|
};
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
const
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
};
|
|
2350
|
-
const
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
return size + 0.9;
|
|
2365
|
-
};
|
|
2366
|
-
const buildMediaQueryString = (options) => {
|
|
2367
|
-
if (!options.min && !options.max) {
|
|
2368
|
-
throw new Error('At least one of min or max must be defined');
|
|
2369
|
-
}
|
|
2370
|
-
const mediaQueryParts = [];
|
|
2371
|
-
if (options.min) {
|
|
2372
|
-
if (typeof options.min === 'number') {
|
|
2373
|
-
mediaQueryParts.push(`(min-width: ${options.min}px)`);
|
|
2996
|
+
|
|
2997
|
+
const getClientXY = (event) => {
|
|
2998
|
+
if (event.type[0] === 't') {
|
|
2999
|
+
const touch = event.targetTouches[0] ?? event.changedTouches[0];
|
|
3000
|
+
return touch ? { clientX: touch.clientX, clientY: touch.clientY } : { clientX: 0, clientY: 0 };
|
|
3001
|
+
}
|
|
3002
|
+
return { clientX: event.clientX, clientY: event.clientY };
|
|
3003
|
+
};
|
|
3004
|
+
const createSwipeTracker = (startEvent) => {
|
|
3005
|
+
const { clientX: originClientX, clientY: originClientY } = getClientXY(startEvent);
|
|
3006
|
+
const startTime = Date.now();
|
|
3007
|
+
let movementX = 0;
|
|
3008
|
+
let movementY = 0;
|
|
3009
|
+
let isSwiping = false;
|
|
3010
|
+
let isScrolling = false;
|
|
3011
|
+
const update = (event) => {
|
|
3012
|
+
const { clientX, clientY } = getClientXY(event);
|
|
3013
|
+
movementX = clientX - originClientX;
|
|
3014
|
+
movementY = clientY - originClientY;
|
|
3015
|
+
const positiveMovementX = Math.abs(movementX);
|
|
3016
|
+
const positiveMovementY = Math.abs(movementY);
|
|
3017
|
+
if (!isSwiping && !isScrolling) {
|
|
3018
|
+
if (positiveMovementY > positiveMovementX) {
|
|
3019
|
+
isScrolling = true;
|
|
2374
3020
|
}
|
|
2375
3021
|
else {
|
|
2376
|
-
|
|
3022
|
+
isSwiping = true;
|
|
2377
3023
|
}
|
|
2378
3024
|
}
|
|
2379
|
-
|
|
2380
|
-
|
|
3025
|
+
return {
|
|
3026
|
+
originClientX,
|
|
3027
|
+
originClientY,
|
|
3028
|
+
timestamp: startTime,
|
|
3029
|
+
movementX,
|
|
3030
|
+
movementY,
|
|
3031
|
+
positiveMovementX,
|
|
3032
|
+
positiveMovementY,
|
|
3033
|
+
isScrolling,
|
|
3034
|
+
isSwiping,
|
|
3035
|
+
};
|
|
3036
|
+
};
|
|
3037
|
+
const end = () => {
|
|
3038
|
+
const swipeTime = Math.max(1, Date.now() - startTime);
|
|
3039
|
+
const positiveMovementX = Math.abs(movementX);
|
|
3040
|
+
const positiveMovementY = Math.abs(movementY);
|
|
3041
|
+
const pixelPerSecondX = (movementX / swipeTime) * 1000;
|
|
3042
|
+
const pixelPerSecondY = (movementY / swipeTime) * 1000;
|
|
3043
|
+
return {
|
|
3044
|
+
movementX,
|
|
3045
|
+
movementY,
|
|
3046
|
+
positiveMovementX,
|
|
3047
|
+
positiveMovementY,
|
|
3048
|
+
pixelPerSecondX,
|
|
3049
|
+
pixelPerSecondY,
|
|
3050
|
+
positivePixelPerSecondX: Math.abs(pixelPerSecondX),
|
|
3051
|
+
positivePixelPerSecondY: Math.abs(pixelPerSecondY),
|
|
3052
|
+
originClientX,
|
|
3053
|
+
originClientY,
|
|
3054
|
+
};
|
|
3055
|
+
};
|
|
3056
|
+
const cancel = () => {
|
|
3057
|
+
movementX = 0;
|
|
3058
|
+
movementY = 0;
|
|
3059
|
+
};
|
|
3060
|
+
return { update, end, cancel };
|
|
3061
|
+
};
|
|
3062
|
+
|
|
3063
|
+
const [, injectAngularRootElement] = createRootProvider(() => {
|
|
3064
|
+
const appRef = inject(ApplicationRef);
|
|
3065
|
+
const rootElement = signal(null, /* @ts-ignore */
|
|
3066
|
+
...(ngDevMode ? [{ debugName: "rootElement" }] : /* istanbul ignore next */ []));
|
|
3067
|
+
const poll = () => {
|
|
3068
|
+
const appComponents = appRef.components;
|
|
3069
|
+
if (appComponents.length > 0) {
|
|
3070
|
+
rootElement.set(appComponents[0]?.location.nativeElement);
|
|
2381
3071
|
}
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
mediaQueryParts.push(`(max-width: ${options.max}px)`);
|
|
2385
|
-
}
|
|
2386
|
-
else {
|
|
2387
|
-
mediaQueryParts.push(`(max-width: ${getBreakpointSize(options.max, 'max')}px)`);
|
|
2388
|
-
}
|
|
3072
|
+
else {
|
|
3073
|
+
setTimeout(poll, 25);
|
|
2389
3074
|
}
|
|
2390
|
-
return mediaQueryParts.join(' ');
|
|
2391
3075
|
};
|
|
3076
|
+
setTimeout(poll);
|
|
3077
|
+
return rootElement;
|
|
3078
|
+
});
|
|
3079
|
+
|
|
3080
|
+
const [provideBoundaryElement, injectBoundaryElement, BOUNDARY_ELEMENT_TOKEN] = createProvider(() => {
|
|
3081
|
+
const hostElement = inject(ElementRef, { optional: true });
|
|
3082
|
+
const document = inject(DOCUMENT);
|
|
3083
|
+
const override = signal(null, /* @ts-ignore */
|
|
3084
|
+
...(ngDevMode ? [{ debugName: "override" }] : /* istanbul ignore next */ []));
|
|
3085
|
+
const value = computed(() => override() ?? hostElement?.nativeElement ?? document.documentElement, /* @ts-ignore */
|
|
3086
|
+
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
2392
3087
|
return {
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
getBreakpointSize,
|
|
2396
|
-
buildMediaQueryString,
|
|
2397
|
-
observeMediaQuery,
|
|
2398
|
-
isMediaQueryMatched,
|
|
3088
|
+
value,
|
|
3089
|
+
override,
|
|
2399
3090
|
};
|
|
2400
|
-
}, { name: '
|
|
3091
|
+
}, { name: 'Boundary Element' });
|
|
2401
3092
|
|
|
2402
3093
|
const [provideFocusVisibleTracker, injectFocusVisibleTracker, FOCUS_VISIBLE_TRACKER_TOKEN] = createRootProvider(() => {
|
|
2403
3094
|
const document = inject(DOCUMENT);
|
|
2404
3095
|
const destroyRef = inject(DestroyRef);
|
|
2405
|
-
const isFocusVisible = signal(false,
|
|
3096
|
+
const isFocusVisible = signal(false, /* @ts-ignore */
|
|
3097
|
+
...(ngDevMode ? [{ debugName: "isFocusVisible" }] : /* istanbul ignore next */ []));
|
|
2406
3098
|
let hadKeyboardEvent = false;
|
|
2407
3099
|
const onKeyDown = (e) => {
|
|
2408
3100
|
if (e.key === 'Tab' || e.key === 'Shift' || e.key === 'Meta' || e.key === 'Alt' || e.key === 'Control') {
|
|
2409
3101
|
hadKeyboardEvent = true;
|
|
2410
|
-
isFocusVisible.set(true);
|
|
3102
|
+
queueMicrotask(() => isFocusVisible.set(true));
|
|
2411
3103
|
}
|
|
2412
3104
|
};
|
|
2413
3105
|
const onPointerDown = () => {
|
|
2414
3106
|
hadKeyboardEvent = false;
|
|
2415
|
-
isFocusVisible.set(false);
|
|
3107
|
+
queueMicrotask(() => isFocusVisible.set(false));
|
|
2416
3108
|
};
|
|
2417
3109
|
const onFocus = () => {
|
|
2418
3110
|
if (hadKeyboardEvent) {
|
|
2419
|
-
isFocusVisible.set(true);
|
|
3111
|
+
queueMicrotask(() => isFocusVisible.set(true));
|
|
2420
3112
|
}
|
|
2421
3113
|
};
|
|
2422
3114
|
const onBlur = () => {
|
|
2423
|
-
isFocusVisible.set(false);
|
|
3115
|
+
queueMicrotask(() => isFocusVisible.set(false));
|
|
2424
3116
|
};
|
|
2425
3117
|
document.addEventListener('keydown', onKeyDown, true);
|
|
2426
3118
|
document.addEventListener('mousedown', onPointerDown, true);
|
|
@@ -2442,7 +3134,8 @@ const [provideFocusVisibleTracker, injectFocusVisibleTracker, FOCUS_VISIBLE_TRAC
|
|
|
2442
3134
|
}, { name: 'Focus Visible Tracker' });
|
|
2443
3135
|
|
|
2444
3136
|
const [provideLocale, injectLocale] = createRootProvider(() => {
|
|
2445
|
-
const currentLocale = signal('en',
|
|
3137
|
+
const currentLocale = signal('en', /* @ts-ignore */
|
|
3138
|
+
...(ngDevMode ? [{ debugName: "currentLocale" }] : /* istanbul ignore next */ []));
|
|
2446
3139
|
return {
|
|
2447
3140
|
currentLocale,
|
|
2448
3141
|
};
|
|
@@ -2584,6 +3277,20 @@ const [provideRenderer, injectRenderer] = createRootProvider(() => {
|
|
|
2584
3277
|
setAttribute(element, `data-${key}`, value);
|
|
2585
3278
|
});
|
|
2586
3279
|
};
|
|
3280
|
+
const moveBefore = (config) => {
|
|
3281
|
+
const { newParent, child, before = null } = config;
|
|
3282
|
+
if ('moveBefore' in newParent) {
|
|
3283
|
+
try {
|
|
3284
|
+
newParent.moveBefore(child, before);
|
|
3285
|
+
}
|
|
3286
|
+
catch {
|
|
3287
|
+
newParent.insertBefore(child, before);
|
|
3288
|
+
}
|
|
3289
|
+
}
|
|
3290
|
+
else {
|
|
3291
|
+
newParent.insertBefore(child, before);
|
|
3292
|
+
}
|
|
3293
|
+
};
|
|
2587
3294
|
return {
|
|
2588
3295
|
addClass,
|
|
2589
3296
|
removeClass,
|
|
@@ -2615,10 +3322,80 @@ const [provideRenderer, injectRenderer] = createRootProvider(() => {
|
|
|
2615
3322
|
setDataAttributes,
|
|
2616
3323
|
setCssProperty,
|
|
2617
3324
|
setCssProperties,
|
|
3325
|
+
moveBefore,
|
|
2618
3326
|
renderer,
|
|
2619
3327
|
};
|
|
2620
3328
|
}, { name: 'Angular Renderer' });
|
|
2621
3329
|
|
|
3330
|
+
const [provideStyleManager, injectStyleManager] = createRootProvider(() => {
|
|
3331
|
+
const appRef = inject(ApplicationRef);
|
|
3332
|
+
const destroyRef = inject(DestroyRef);
|
|
3333
|
+
const document = inject(DOCUMENT);
|
|
3334
|
+
const envInjector = inject(EnvironmentInjector);
|
|
3335
|
+
const renderer = injectRenderer();
|
|
3336
|
+
let container = null;
|
|
3337
|
+
const mountedComponents = new Map();
|
|
3338
|
+
const getContainerParent = () => {
|
|
3339
|
+
return document.body ?? document.documentElement;
|
|
3340
|
+
};
|
|
3341
|
+
const ensureContainer = () => {
|
|
3342
|
+
if (container) {
|
|
3343
|
+
return container;
|
|
3344
|
+
}
|
|
3345
|
+
const nextContainer = renderer.createElement('div');
|
|
3346
|
+
renderer.addClass(nextContainer, 'et-style-manager');
|
|
3347
|
+
renderer.setAttribute(nextContainer, 'aria-hidden', 'true');
|
|
3348
|
+
renderer.setStyle(nextContainer, { display: 'none' });
|
|
3349
|
+
renderer.appendChild(getContainerParent(), nextContainer);
|
|
3350
|
+
container = nextContainer;
|
|
3351
|
+
return nextContainer;
|
|
3352
|
+
};
|
|
3353
|
+
const cleanupContainer = () => {
|
|
3354
|
+
if (!container) {
|
|
3355
|
+
return;
|
|
3356
|
+
}
|
|
3357
|
+
const parent = renderer.parentNode(container);
|
|
3358
|
+
if (parent) {
|
|
3359
|
+
renderer.removeChild(parent, container);
|
|
3360
|
+
}
|
|
3361
|
+
container = null;
|
|
3362
|
+
};
|
|
3363
|
+
const mount = (component) => {
|
|
3364
|
+
const existingComponent = mountedComponents.get(component);
|
|
3365
|
+
if (existingComponent) {
|
|
3366
|
+
return existingComponent;
|
|
3367
|
+
}
|
|
3368
|
+
const componentRef = createComponent(component, { environmentInjector: envInjector });
|
|
3369
|
+
appRef.attachView(componentRef.hostView);
|
|
3370
|
+
renderer.appendChild(ensureContainer(), componentRef.location.nativeElement);
|
|
3371
|
+
mountedComponents.set(component, componentRef);
|
|
3372
|
+
return componentRef;
|
|
3373
|
+
};
|
|
3374
|
+
destroyRef.onDestroy(() => {
|
|
3375
|
+
if (appRef.destroyed) {
|
|
3376
|
+
mountedComponents.clear();
|
|
3377
|
+
cleanupContainer();
|
|
3378
|
+
return;
|
|
3379
|
+
}
|
|
3380
|
+
mountedComponents.forEach((componentRef) => {
|
|
3381
|
+
appRef.detachView(componentRef.hostView);
|
|
3382
|
+
componentRef.destroy();
|
|
3383
|
+
});
|
|
3384
|
+
mountedComponents.clear();
|
|
3385
|
+
cleanupContainer();
|
|
3386
|
+
});
|
|
3387
|
+
return { mount };
|
|
3388
|
+
}, { name: 'StyleManager' });
|
|
3389
|
+
|
|
3390
|
+
const createUserConsentProvider = (options) => ({
|
|
3391
|
+
provide: options.for,
|
|
3392
|
+
useFactory: () => ({
|
|
3393
|
+
isGranted: options.isGranted(),
|
|
3394
|
+
grant: options.grant(),
|
|
3395
|
+
...(options.revoke ? { revoke: options.revoke() } : {}),
|
|
3396
|
+
}),
|
|
3397
|
+
});
|
|
3398
|
+
|
|
2622
3399
|
const nextFrame = (cb) => {
|
|
2623
3400
|
requestAnimationFrame(() => {
|
|
2624
3401
|
requestAnimationFrame(cb);
|
|
@@ -2664,7 +3441,8 @@ class AnimatedLifecycleDirective {
|
|
|
2664
3441
|
this.currentFrameId = 0;
|
|
2665
3442
|
this.state$ = new BehaviorSubject('init');
|
|
2666
3443
|
this.stateChange = outputFromObservable(this.state$);
|
|
2667
|
-
this.skipNextEnter = model(false,
|
|
3444
|
+
this.skipNextEnter = model(false, /* @ts-ignore */
|
|
3445
|
+
...(ngDevMode ? [{ debugName: "skipNextEnter" }] : /* istanbul ignore next */ []));
|
|
2668
3446
|
this.state$
|
|
2669
3447
|
.pipe(tap((state) => {
|
|
2670
3448
|
if (state !== 'init') {
|
|
@@ -2694,6 +3472,7 @@ class AnimatedLifecycleDirective {
|
|
|
2694
3472
|
if (currentState === 'entering')
|
|
2695
3473
|
return;
|
|
2696
3474
|
if ((currentState === 'init' && !this.isConstructed) || this.skipNextEnter()) {
|
|
3475
|
+
this.debugLog('enter: instant (not constructed or skipNextEnter)', { currentState });
|
|
2697
3476
|
this.updateState('entered');
|
|
2698
3477
|
this.skipNextEnter.set(false);
|
|
2699
3478
|
this.addClass(ANIMATION_CLASSES.enterDone);
|
|
@@ -2709,6 +3488,10 @@ class AnimatedLifecycleDirective {
|
|
|
2709
3488
|
this.animatable.setTransitionId(transitionId);
|
|
2710
3489
|
const skipAnimation = this.forcedAtFrameId !== null && this.forcedAtFrameId === this.currentFrameId;
|
|
2711
3490
|
this.forcedAtFrameId = null;
|
|
3491
|
+
this.debugLog(`enter: ${skipAnimation ? 'skip (forced this frame)' : isInterrupting ? 'interrupting leave' : 'normal'}`, {
|
|
3492
|
+
currentState,
|
|
3493
|
+
transitionId,
|
|
3494
|
+
});
|
|
2712
3495
|
if (skipAnimation) {
|
|
2713
3496
|
this.removeClasses(ANIMATION_CLASSES.leaveFrom, ANIMATION_CLASSES.leaveActive, ANIMATION_CLASSES.leaveTo, ANIMATION_CLASSES.leaveInterrupt);
|
|
2714
3497
|
this.updateState('entered');
|
|
@@ -2759,6 +3542,7 @@ class AnimatedLifecycleDirective {
|
|
|
2759
3542
|
if (currentState === 'leaving')
|
|
2760
3543
|
return;
|
|
2761
3544
|
if (currentState === 'init') {
|
|
3545
|
+
this.debugLog('leave: instant (state is init, enter never ran)');
|
|
2762
3546
|
this.updateState('left');
|
|
2763
3547
|
this.addClass(ANIMATION_CLASSES.leaveDone);
|
|
2764
3548
|
this.forcedAtFrameId = null;
|
|
@@ -2773,6 +3557,10 @@ class AnimatedLifecycleDirective {
|
|
|
2773
3557
|
this.animatable.setTransitionId(transitionId);
|
|
2774
3558
|
const skipAnimation = this.forcedAtFrameId !== null && this.forcedAtFrameId === this.currentFrameId;
|
|
2775
3559
|
this.forcedAtFrameId = null;
|
|
3560
|
+
this.debugLog(`leave: ${skipAnimation ? 'skip (forced this frame)' : isInterrupting ? 'interrupting enter' : 'normal'}`, {
|
|
3561
|
+
currentState,
|
|
3562
|
+
transitionId,
|
|
3563
|
+
});
|
|
2776
3564
|
if (skipAnimation) {
|
|
2777
3565
|
this.removeClasses(ANIMATION_CLASSES.enterFrom, ANIMATION_CLASSES.enterActive, ANIMATION_CLASSES.enterTo, ANIMATION_CLASSES.enterInterrupt);
|
|
2778
3566
|
this.updateState('left');
|
|
@@ -2853,21 +3641,33 @@ class AnimatedLifecycleDirective {
|
|
|
2853
3641
|
addClasses.forEach((cls) => this.addClass(cls));
|
|
2854
3642
|
fromNextFrame()
|
|
2855
3643
|
.pipe(switchMap(() => this.animatable.isAnimating$), take(1), switchMap((isAnimating) => {
|
|
3644
|
+
if (isAnimating) {
|
|
3645
|
+
return of(true);
|
|
3646
|
+
}
|
|
3647
|
+
this.debugLog(`${transitionId}: interrupt found no running transition, re-checking next frame`);
|
|
3648
|
+
return fromNextFrame().pipe(switchMap(() => this.animatable.isAnimating$), take(1));
|
|
3649
|
+
}), take(1), switchMap((isAnimating) => {
|
|
2856
3650
|
if (!isAnimating && this.state$.value === expectedState) {
|
|
3651
|
+
this.debugLog(`${transitionId}: interrupt completes INSTANTLY (no transition running after class swap)`);
|
|
2857
3652
|
return of({ cancelled: false, transitionId });
|
|
2858
3653
|
}
|
|
3654
|
+
this.debugLog(`${transitionId}: interrupt waiting for animation end`, { isAnimating });
|
|
2859
3655
|
return this.animatable.animationEnd$.pipe(switchMap((e) => {
|
|
2860
3656
|
if (e.transitionId === transitionId) {
|
|
2861
3657
|
return of(e);
|
|
2862
3658
|
}
|
|
2863
3659
|
return this.animatable.isAnimating$.pipe(take(1), switchMap((stillAnimating) => {
|
|
2864
3660
|
if (!stillAnimating && this.state$.value === expectedState) {
|
|
3661
|
+
this.debugLog(`${transitionId}: interrupt completes via foreign animation end (batch id was "${e.transitionId}")`, { stillAnimating });
|
|
2865
3662
|
return of({ cancelled: false, transitionId });
|
|
2866
3663
|
}
|
|
2867
3664
|
return of(null);
|
|
2868
3665
|
}));
|
|
2869
3666
|
}), filter((e) => e !== null && e.transitionId === transitionId));
|
|
2870
|
-
}), filter((e) => this.state$.value === expectedState && !e.cancelled), tap(() =>
|
|
3667
|
+
}), filter((e) => this.state$.value === expectedState && !e.cancelled), tap(() => {
|
|
3668
|
+
this.debugLog(`${transitionId}: interrupt complete`);
|
|
3669
|
+
onComplete();
|
|
3670
|
+
}), take(1), takeUntil(cancelSignal), takeUntilDestroyed(this.destroyRef))
|
|
2871
3671
|
.subscribe();
|
|
2872
3672
|
}
|
|
2873
3673
|
addClass(className) {
|
|
@@ -2880,17 +3680,28 @@ class AnimatedLifecycleDirective {
|
|
|
2880
3680
|
this.renderer.removeClass(this.element, ...classNames);
|
|
2881
3681
|
}
|
|
2882
3682
|
updateState(newState) {
|
|
3683
|
+
this.debugLog(`state: ${this.state$.value} → ${newState}`);
|
|
2883
3684
|
this.state$.next(newState);
|
|
2884
3685
|
}
|
|
2885
|
-
|
|
2886
|
-
|
|
3686
|
+
debugLog(message, data) {
|
|
3687
|
+
const el = this.element;
|
|
3688
|
+
const scope = `lifecycle ${el.tagName.toLowerCase()}${el.classList.contains('et-overlay') ? '.et-overlay' : ''}`;
|
|
3689
|
+
if (data) {
|
|
3690
|
+
animationDebugLog(scope, message, data);
|
|
3691
|
+
}
|
|
3692
|
+
else {
|
|
3693
|
+
animationDebugLog(scope, message);
|
|
3694
|
+
}
|
|
3695
|
+
}
|
|
3696
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: AnimatedLifecycleDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
3697
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.5", type: AnimatedLifecycleDirective, isStandalone: true, selector: "[etAnimatedLifecycle]", inputs: { skipNextEnter: { classPropertyName: "skipNextEnter", publicName: "skipNextEnter", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { stateChange: "stateChange", skipNextEnter: "skipNextEnterChange" }, host: { classAttribute: "et-force-invisible" }, providers: [
|
|
2887
3698
|
{
|
|
2888
3699
|
provide: ANIMATED_LIFECYCLE_TOKEN,
|
|
2889
3700
|
useExisting: AnimatedLifecycleDirective,
|
|
2890
3701
|
},
|
|
2891
3702
|
], exportAs: ["etAnimatedLifecycle"], hostDirectives: [{ directive: AnimatableDirective }], ngImport: i0 }); }
|
|
2892
3703
|
}
|
|
2893
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
3704
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: AnimatedLifecycleDirective, decorators: [{
|
|
2894
3705
|
type: Directive,
|
|
2895
3706
|
args: [{
|
|
2896
3707
|
selector: '[etAnimatedLifecycle]',
|
|
@@ -2915,7 +3726,7 @@ class AnimatedIfDirective {
|
|
|
2915
3726
|
this.viewContainerRef = inject(ViewContainerRef);
|
|
2916
3727
|
this.animatedLifecycle = inject(ANIMATED_LIFECYCLE_TOKEN);
|
|
2917
3728
|
this.hasView = false;
|
|
2918
|
-
this.ifValue = input(null, { ...(ngDevMode ? { debugName: "ifValue" } : {}), alias: 'etAnimatedIf' });
|
|
3729
|
+
this.ifValue = input(null, { ...(ngDevMode ? { debugName: "ifValue" } : /* istanbul ignore next */ {}), alias: 'etAnimatedIf' });
|
|
2919
3730
|
toObservable(this.ifValue)
|
|
2920
3731
|
.pipe(switchMap((value) => {
|
|
2921
3732
|
if (value) {
|
|
@@ -2937,15 +3748,15 @@ class AnimatedIfDirective {
|
|
|
2937
3748
|
}), takeUntilDestroyed())
|
|
2938
3749
|
.subscribe();
|
|
2939
3750
|
}
|
|
2940
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
2941
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "
|
|
3751
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: AnimatedIfDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
3752
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.5", type: AnimatedIfDirective, isStandalone: true, selector: "[etAnimatedIf]", inputs: { ifValue: { classPropertyName: "ifValue", publicName: "etAnimatedIf", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
|
|
2942
3753
|
{
|
|
2943
3754
|
provide: ANIMATED_IF_TOKEN,
|
|
2944
3755
|
useExisting: AnimatedIfDirective,
|
|
2945
3756
|
},
|
|
2946
3757
|
], ngImport: i0 }); }
|
|
2947
3758
|
}
|
|
2948
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
3759
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: AnimatedIfDirective, decorators: [{
|
|
2949
3760
|
type: Directive,
|
|
2950
3761
|
args: [{
|
|
2951
3762
|
selector: '[etAnimatedIf]',
|
|
@@ -2969,17 +3780,23 @@ class AnimatedOverlayDirective {
|
|
|
2969
3780
|
this.destroyRef = inject(DestroyRef);
|
|
2970
3781
|
this.floatingElCleanupFn = null;
|
|
2971
3782
|
this.unmountSubscription = null;
|
|
2972
|
-
this.placement = input('bottom',
|
|
2973
|
-
|
|
2974
|
-
this.
|
|
2975
|
-
|
|
2976
|
-
this.
|
|
2977
|
-
|
|
2978
|
-
this.
|
|
2979
|
-
|
|
2980
|
-
this.
|
|
2981
|
-
|
|
2982
|
-
this.
|
|
3783
|
+
this.placement = input('bottom', /* @ts-ignore */
|
|
3784
|
+
...(ngDevMode ? [{ debugName: "placement" }] : /* istanbul ignore next */ []));
|
|
3785
|
+
this.fallbackPlacements = input(/* @ts-ignore */
|
|
3786
|
+
...(ngDevMode ? [undefined, { debugName: "fallbackPlacements" }] : /* istanbul ignore next */ []));
|
|
3787
|
+
this.offset = input(null, /* @ts-ignore */
|
|
3788
|
+
...(ngDevMode ? [{ debugName: "offset" }] : /* istanbul ignore next */ []));
|
|
3789
|
+
this.arrowPadding = input(4, /* @ts-ignore */
|
|
3790
|
+
...(ngDevMode ? [{ debugName: "arrowPadding" }] : /* istanbul ignore next */ []));
|
|
3791
|
+
this.viewportPadding = input(8, /* @ts-ignore */
|
|
3792
|
+
...(ngDevMode ? [{ debugName: "viewportPadding" }] : /* istanbul ignore next */ []));
|
|
3793
|
+
this.autoResize = input(false, { ...(ngDevMode ? { debugName: "autoResize" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3794
|
+
this.shift = input(true, { ...(ngDevMode ? { debugName: "shift" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3795
|
+
this.autoHide = input(false, { ...(ngDevMode ? { debugName: "autoHide" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3796
|
+
this.autoCloseIfReferenceHidden = input(false, { ...(ngDevMode ? { debugName: "autoCloseIfReferenceHidden" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3797
|
+
this.referenceElement = input(this.elementRef.nativeElement, /* @ts-ignore */
|
|
3798
|
+
...(ngDevMode ? [{ debugName: "referenceElement" }] : /* istanbul ignore next */ []));
|
|
3799
|
+
this.mirrorWidth = input(false, { ...(ngDevMode ? { debugName: "mirrorWidth" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
2983
3800
|
this.portal = null;
|
|
2984
3801
|
this.overlayRef = null;
|
|
2985
3802
|
this.componentRef = null;
|
|
@@ -2987,14 +3804,22 @@ class AnimatedOverlayDirective {
|
|
|
2987
3804
|
this.afterOpened$ = new Subject();
|
|
2988
3805
|
this.beforeClosed$ = new Subject();
|
|
2989
3806
|
this.afterClosed$ = new Subject();
|
|
2990
|
-
this.state = signal('init',
|
|
2991
|
-
|
|
2992
|
-
this.
|
|
2993
|
-
|
|
2994
|
-
this.
|
|
2995
|
-
|
|
2996
|
-
this.
|
|
2997
|
-
|
|
3807
|
+
this.state = signal('init', /* @ts-ignore */
|
|
3808
|
+
...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
|
|
3809
|
+
this.isMounted = computed(() => this.state() === 'mounted', /* @ts-ignore */
|
|
3810
|
+
...(ngDevMode ? [{ debugName: "isMounted" }] : /* istanbul ignore next */ []));
|
|
3811
|
+
this.isMounting = computed(() => this.state() === 'mounting', /* @ts-ignore */
|
|
3812
|
+
...(ngDevMode ? [{ debugName: "isMounting" }] : /* istanbul ignore next */ []));
|
|
3813
|
+
this.isUnmounted = computed(() => this.state() === 'unmounted', /* @ts-ignore */
|
|
3814
|
+
...(ngDevMode ? [{ debugName: "isUnmounted" }] : /* istanbul ignore next */ []));
|
|
3815
|
+
this.isUnmounting = computed(() => this.state() === 'unmounting', /* @ts-ignore */
|
|
3816
|
+
...(ngDevMode ? [{ debugName: "isUnmounting" }] : /* istanbul ignore next */ []));
|
|
3817
|
+
this.canMount = computed(() => !this.isMounted() && !this.isMounting(), /* @ts-ignore */
|
|
3818
|
+
...(ngDevMode ? [{ debugName: "canMount" }] : /* istanbul ignore next */ []));
|
|
3819
|
+
this.canUnmount = computed(() => (this.isMounted() || this.isMounting()) && !this.isUnmounting(), /* @ts-ignore */
|
|
3820
|
+
...(ngDevMode ? [{ debugName: "canUnmount" }] : /* istanbul ignore next */ []));
|
|
3821
|
+
this.isHidden = signal(false, /* @ts-ignore */
|
|
3822
|
+
...(ngDevMode ? [{ debugName: "isHidden" }] : /* istanbul ignore next */ []));
|
|
2998
3823
|
this.isMounted$ = toObservable(this.isMounted);
|
|
2999
3824
|
this.isMounting$ = toObservable(this.isMounting);
|
|
3000
3825
|
this.isUnmounted$ = toObservable(this.isUnmounted);
|
|
@@ -3024,7 +3849,7 @@ class AnimatedOverlayDirective {
|
|
|
3024
3849
|
this.unmountSubscription?.unsubscribe();
|
|
3025
3850
|
this.unmountSubscription = null;
|
|
3026
3851
|
this.applyComponentData(config.data);
|
|
3027
|
-
this.
|
|
3852
|
+
this.applyColorProvider(config.colorProvider);
|
|
3028
3853
|
const lifecycle = this.componentRef.instance.animatedLifecycle();
|
|
3029
3854
|
if (lifecycle) {
|
|
3030
3855
|
this.state.set('mounting');
|
|
@@ -3047,7 +3872,7 @@ class AnimatedOverlayDirective {
|
|
|
3047
3872
|
}
|
|
3048
3873
|
return;
|
|
3049
3874
|
}
|
|
3050
|
-
const { component, providers, data,
|
|
3875
|
+
const { component, providers, data, colorProvider } = config;
|
|
3051
3876
|
this.state.set('mounting');
|
|
3052
3877
|
this.beforeOpened$.next();
|
|
3053
3878
|
const injector = Injector.create({
|
|
@@ -3058,7 +3883,7 @@ class AnimatedOverlayDirective {
|
|
|
3058
3883
|
this.portal = new ComponentPortal(component, this.viewContainerRef, injector);
|
|
3059
3884
|
this.componentRef = this.overlayRef.attach(this.portal);
|
|
3060
3885
|
this.applyComponentData(data);
|
|
3061
|
-
this.
|
|
3886
|
+
this.applyColorProvider(colorProvider);
|
|
3062
3887
|
this.updateOverlaySize();
|
|
3063
3888
|
this.setupFloatingUI();
|
|
3064
3889
|
return this.componentRef.instance;
|
|
@@ -3104,10 +3929,10 @@ class AnimatedOverlayDirective {
|
|
|
3104
3929
|
Object.assign(this.componentRef.instance, data);
|
|
3105
3930
|
this.componentRef.changeDetectorRef.markForCheck();
|
|
3106
3931
|
}
|
|
3107
|
-
|
|
3108
|
-
if (!this.componentRef || !
|
|
3932
|
+
applyColorProvider(colorProvider) {
|
|
3933
|
+
if (!this.componentRef || !colorProvider)
|
|
3109
3934
|
return;
|
|
3110
|
-
this.componentRef.instance.
|
|
3935
|
+
this.componentRef.instance.setColorFromProvider(colorProvider);
|
|
3111
3936
|
}
|
|
3112
3937
|
updateOverlaySize() {
|
|
3113
3938
|
if (!this.overlayRef || !this.mirrorWidth())
|
|
@@ -3245,10 +4070,10 @@ class AnimatedOverlayDirective {
|
|
|
3245
4070
|
this.state.set('unmounted');
|
|
3246
4071
|
this.afterClosed$.next();
|
|
3247
4072
|
}
|
|
3248
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
3249
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "
|
|
4073
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: AnimatedOverlayDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
4074
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.5", type: AnimatedOverlayDirective, isStandalone: true, selector: "[etAnimatedOverlay]", inputs: { placement: { classPropertyName: "placement", publicName: "placement", isSignal: true, isRequired: false, transformFunction: null }, fallbackPlacements: { classPropertyName: "fallbackPlacements", publicName: "fallbackPlacements", isSignal: true, isRequired: false, transformFunction: null }, offset: { classPropertyName: "offset", publicName: "offset", isSignal: true, isRequired: false, transformFunction: null }, arrowPadding: { classPropertyName: "arrowPadding", publicName: "arrowPadding", isSignal: true, isRequired: false, transformFunction: null }, viewportPadding: { classPropertyName: "viewportPadding", publicName: "viewportPadding", isSignal: true, isRequired: false, transformFunction: null }, autoResize: { classPropertyName: "autoResize", publicName: "autoResize", isSignal: true, isRequired: false, transformFunction: null }, shift: { classPropertyName: "shift", publicName: "shift", isSignal: true, isRequired: false, transformFunction: null }, autoHide: { classPropertyName: "autoHide", publicName: "autoHide", isSignal: true, isRequired: false, transformFunction: null }, autoCloseIfReferenceHidden: { classPropertyName: "autoCloseIfReferenceHidden", publicName: "autoCloseIfReferenceHidden", isSignal: true, isRequired: false, transformFunction: null }, referenceElement: { classPropertyName: "referenceElement", publicName: "referenceElement", isSignal: true, isRequired: false, transformFunction: null }, mirrorWidth: { classPropertyName: "mirrorWidth", publicName: "mirrorWidth", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "et-animated-overlay" }, exportAs: ["etAnimatedOverlay"], ngImport: i0 }); }
|
|
3250
4075
|
}
|
|
3251
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
4076
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: AnimatedOverlayDirective, decorators: [{
|
|
3252
4077
|
type: Directive,
|
|
3253
4078
|
args: [{
|
|
3254
4079
|
selector: '[etAnimatedOverlay]',
|
|
@@ -3367,68 +4192,800 @@ class ClickOutsideDirective {
|
|
|
3367
4192
|
const isInside = this.elementRef.nativeElement.contains(activeElement);
|
|
3368
4193
|
if (isInside)
|
|
3369
4194
|
return;
|
|
3370
|
-
this.didClickOutside.emit(event);
|
|
3371
|
-
}), takeUntilDestroyed())
|
|
3372
|
-
.subscribe();
|
|
3373
|
-
}
|
|
3374
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
3375
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "
|
|
3376
|
-
}
|
|
3377
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
3378
|
-
type: Directive,
|
|
3379
|
-
args: [{
|
|
3380
|
-
selector: '[etClickOutside]',
|
|
3381
|
-
}]
|
|
3382
|
-
}], ctorParameters: () => [], propDecorators: { didClickOutside: [{ type: i0.Output, args: ["etClickOutside"] }] } });
|
|
4195
|
+
this.didClickOutside.emit(event);
|
|
4196
|
+
}), takeUntilDestroyed())
|
|
4197
|
+
.subscribe();
|
|
4198
|
+
}
|
|
4199
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ClickOutsideDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
4200
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.5", type: ClickOutsideDirective, isStandalone: true, selector: "[etClickOutside]", outputs: { didClickOutside: "etClickOutside" }, ngImport: i0 }); }
|
|
4201
|
+
}
|
|
4202
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ClickOutsideDirective, decorators: [{
|
|
4203
|
+
type: Directive,
|
|
4204
|
+
args: [{
|
|
4205
|
+
selector: '[etClickOutside]',
|
|
4206
|
+
}]
|
|
4207
|
+
}], ctorParameters: () => [], propDecorators: { didClickOutside: [{ type: i0.Output, args: ["etClickOutside"] }] } });
|
|
4208
|
+
|
|
4209
|
+
class RepeatDirective {
|
|
4210
|
+
constructor() {
|
|
4211
|
+
this.mainTemplateRef = inject(TemplateRef);
|
|
4212
|
+
this.viewContainerRef = inject(ViewContainerRef);
|
|
4213
|
+
this.repeatCount = input(2, { ...(ngDevMode ? { debugName: "repeatCount" } : /* istanbul ignore next */ {}), alias: 'etRepeat', transform: numberAttribute });
|
|
4214
|
+
this.views = linkedSignal({ ...(ngDevMode ? { debugName: "views" } : /* istanbul ignore next */ {}), source: this.repeatCount,
|
|
4215
|
+
computation: (count, previous) => {
|
|
4216
|
+
const prevCount = previous?.source ?? 0;
|
|
4217
|
+
const views = previous?.value ?? [];
|
|
4218
|
+
if (count === prevCount && previous?.value) {
|
|
4219
|
+
return previous.value;
|
|
4220
|
+
}
|
|
4221
|
+
const viewsToCreate = count - prevCount;
|
|
4222
|
+
if (viewsToCreate > 0) {
|
|
4223
|
+
for (let i = 0; i < viewsToCreate; i++) {
|
|
4224
|
+
views.push(this.viewContainerRef.createEmbeddedView(this.mainTemplateRef));
|
|
4225
|
+
}
|
|
4226
|
+
}
|
|
4227
|
+
else if (viewsToCreate < 0) {
|
|
4228
|
+
for (let i = 0; i < -viewsToCreate; i++) {
|
|
4229
|
+
this.viewContainerRef.remove(this.viewContainerRef.length - 1);
|
|
4230
|
+
}
|
|
4231
|
+
views.splice(viewsToCreate);
|
|
4232
|
+
}
|
|
4233
|
+
return views;
|
|
4234
|
+
} });
|
|
4235
|
+
// Ugly but needed to trigger the linked signal.
|
|
4236
|
+
// Otherwise it has no consumers and won't run.
|
|
4237
|
+
effect(() => this.views());
|
|
4238
|
+
}
|
|
4239
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: RepeatDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
4240
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.5", type: RepeatDirective, isStandalone: true, selector: "[etRepeat]", inputs: { repeatCount: { classPropertyName: "repeatCount", publicName: "etRepeat", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); }
|
|
4241
|
+
}
|
|
4242
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: RepeatDirective, decorators: [{
|
|
4243
|
+
type: Directive,
|
|
4244
|
+
args: [{
|
|
4245
|
+
selector: '[etRepeat]',
|
|
4246
|
+
}]
|
|
4247
|
+
}], ctorParameters: () => [], propDecorators: { repeatCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "etRepeat", required: false }] }] } });
|
|
4248
|
+
|
|
4249
|
+
class ScrollObserverDirective {
|
|
4250
|
+
constructor() {
|
|
4251
|
+
this.elementRef = inject(ElementRef);
|
|
4252
|
+
this.enabled = model(true, /* @ts-ignore */
|
|
4253
|
+
...(ngDevMode ? [{ debugName: "enabled" }] : /* istanbul ignore next */ []));
|
|
4254
|
+
this.enabledValue = computed(() => {
|
|
4255
|
+
const enabled = this.enabled();
|
|
4256
|
+
if (isSignal(enabled))
|
|
4257
|
+
return enabled();
|
|
4258
|
+
return enabled;
|
|
4259
|
+
}, /* @ts-ignore */
|
|
4260
|
+
...(ngDevMode ? [{ debugName: "enabledValue" }] : /* istanbul ignore next */ []));
|
|
4261
|
+
this._startEl = signal(null, /* @ts-ignore */
|
|
4262
|
+
...(ngDevMode ? [{ debugName: "_startEl" }] : /* istanbul ignore next */ []));
|
|
4263
|
+
this._endEl = signal(null, /* @ts-ignore */
|
|
4264
|
+
...(ngDevMode ? [{ debugName: "_endEl" }] : /* istanbul ignore next */ []));
|
|
4265
|
+
this._startIntersection = signalElementIntersection(this._startEl, {
|
|
4266
|
+
root: this.elementRef,
|
|
4267
|
+
enabled: this.enabledValue,
|
|
4268
|
+
});
|
|
4269
|
+
this._endIntersection = signalElementIntersection(this._endEl, {
|
|
4270
|
+
root: this.elementRef,
|
|
4271
|
+
enabled: this.enabledValue,
|
|
4272
|
+
});
|
|
4273
|
+
this.isAtStart = computed(() => this._startIntersection()[0]?.isIntersecting ?? false, /* @ts-ignore */
|
|
4274
|
+
...(ngDevMode ? [{ debugName: "isAtStart" }] : /* istanbul ignore next */ []));
|
|
4275
|
+
this.isAtEnd = computed(() => this._endIntersection()[0]?.isIntersecting ?? false, /* @ts-ignore */
|
|
4276
|
+
...(ngDevMode ? [{ debugName: "isAtEnd" }] : /* istanbul ignore next */ []));
|
|
4277
|
+
}
|
|
4278
|
+
_registerStart(el) {
|
|
4279
|
+
this._startEl.set(el);
|
|
4280
|
+
}
|
|
4281
|
+
_registerEnd(el) {
|
|
4282
|
+
this._endEl.set(el);
|
|
4283
|
+
}
|
|
4284
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ScrollObserverDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
4285
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.5", type: ScrollObserverDirective, isStandalone: true, selector: "[etScrollObserver]", inputs: { enabled: { classPropertyName: "enabled", publicName: "enabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { enabled: "enabledChange" }, exportAs: ["etScrollObserver"], ngImport: i0 }); }
|
|
4286
|
+
}
|
|
4287
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ScrollObserverDirective, decorators: [{
|
|
4288
|
+
type: Directive,
|
|
4289
|
+
args: [{
|
|
4290
|
+
selector: '[etScrollObserver]',
|
|
4291
|
+
exportAs: 'etScrollObserver',
|
|
4292
|
+
}]
|
|
4293
|
+
}], propDecorators: { enabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "enabled", required: false }] }, { type: i0.Output, args: ["enabledChange"] }] } });
|
|
4294
|
+
|
|
4295
|
+
class ScrollObserverEndDirective {
|
|
4296
|
+
constructor() {
|
|
4297
|
+
this.elementRef = inject(ElementRef);
|
|
4298
|
+
this.host = inject(ScrollObserverDirective);
|
|
4299
|
+
this.host._registerEnd(this.elementRef);
|
|
4300
|
+
}
|
|
4301
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ScrollObserverEndDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
4302
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.5", type: ScrollObserverEndDirective, isStandalone: true, selector: "[etScrollObserverEnd]", ngImport: i0 }); }
|
|
4303
|
+
}
|
|
4304
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ScrollObserverEndDirective, decorators: [{
|
|
4305
|
+
type: Directive,
|
|
4306
|
+
args: [{
|
|
4307
|
+
selector: '[etScrollObserverEnd]',
|
|
4308
|
+
}]
|
|
4309
|
+
}], ctorParameters: () => [] });
|
|
4310
|
+
|
|
4311
|
+
class ScrollObserverStartDirective {
|
|
4312
|
+
constructor() {
|
|
4313
|
+
this.elementRef = inject(ElementRef);
|
|
4314
|
+
this.host = inject(ScrollObserverDirective);
|
|
4315
|
+
this.host._registerStart(this.elementRef);
|
|
4316
|
+
}
|
|
4317
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ScrollObserverStartDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
4318
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.5", type: ScrollObserverStartDirective, isStandalone: true, selector: "[etScrollObserverStart]", ngImport: i0 }); }
|
|
4319
|
+
}
|
|
4320
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ScrollObserverStartDirective, decorators: [{
|
|
4321
|
+
type: Directive,
|
|
4322
|
+
args: [{
|
|
4323
|
+
selector: '[etScrollObserverStart]',
|
|
4324
|
+
}]
|
|
4325
|
+
}], ctorParameters: () => [] });
|
|
4326
|
+
|
|
4327
|
+
const setupDragObservable = (startEvent, el, commitThreshold) => {
|
|
4328
|
+
const { pointerId, clientX: startX, clientY: startY } = startEvent;
|
|
4329
|
+
const end$ = merge(fromEvent(document, 'pointerup'), fromEvent(document, 'pointercancel')).pipe(filter((e) => e.pointerId === pointerId), take(1));
|
|
4330
|
+
let lastX = startX;
|
|
4331
|
+
let lastY = startY;
|
|
4332
|
+
let committed = false;
|
|
4333
|
+
const moves$ = fromEvent(document, 'pointermove').pipe(filter((e) => e.pointerId === pointerId), concatMap((e) => {
|
|
4334
|
+
if (!committed) {
|
|
4335
|
+
if (Math.abs(e.clientX - startX) < commitThreshold && Math.abs(e.clientY - startY) < commitThreshold) {
|
|
4336
|
+
return EMPTY;
|
|
4337
|
+
}
|
|
4338
|
+
committed = true;
|
|
4339
|
+
el.setPointerCapture(pointerId);
|
|
4340
|
+
lastX = e.clientX;
|
|
4341
|
+
lastY = e.clientY;
|
|
4342
|
+
return of({ type: 'start' });
|
|
4343
|
+
}
|
|
4344
|
+
const stepX = e.clientX - lastX;
|
|
4345
|
+
const stepY = e.clientY - lastY;
|
|
4346
|
+
lastX = e.clientX;
|
|
4347
|
+
lastY = e.clientY;
|
|
4348
|
+
return of({ type: 'move', data: { stepX, stepY, clientX: e.clientX, clientY: e.clientY } });
|
|
4349
|
+
}), takeUntil(end$));
|
|
4350
|
+
return concat(moves$, defer(() => of(committed ? { type: 'end' } : { type: 'tapped' })));
|
|
4351
|
+
};
|
|
4352
|
+
class DragHandleDirective {
|
|
4353
|
+
constructor() {
|
|
4354
|
+
this.el = inject(ElementRef);
|
|
4355
|
+
this.commitThreshold = input(8, /* @ts-ignore */
|
|
4356
|
+
...(ngDevMode ? [{ debugName: "commitThreshold" }] : /* istanbul ignore next */ []));
|
|
4357
|
+
this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
4358
|
+
this.gestureStart$ = new Subject();
|
|
4359
|
+
this.gesture$ = this.gestureStart$.pipe(exhaustMap((event) => setupDragObservable(event, this.el.nativeElement, this.commitThreshold())), takeUntilDestroyed(), share());
|
|
4360
|
+
this.dragTapped = outputFromObservable(this.gesture$.pipe(filter((e) => e.type === 'tapped'), map(() => undefined)));
|
|
4361
|
+
this.dragStarted = outputFromObservable(this.gesture$.pipe(filter((e) => e.type === 'start'), map(() => undefined)));
|
|
4362
|
+
this.dragMoved = outputFromObservable(this.gesture$.pipe(filter((e) => e.type === 'move'), map((e) => e.data)));
|
|
4363
|
+
this.dragEnded = outputFromObservable(this.gesture$.pipe(filter((e) => e.type === 'end'), map(() => undefined)));
|
|
4364
|
+
this.isDragging = toSignal(this.gesture$.pipe(map((e) => e.type === 'start' || e.type === 'move'), distinctUntilChanged()), { initialValue: false });
|
|
4365
|
+
applyHostListener('pointerdown', (e) => this.startGesture(e));
|
|
4366
|
+
}
|
|
4367
|
+
startGesture(event) {
|
|
4368
|
+
if (event.button !== 0 || this.disabled())
|
|
4369
|
+
return;
|
|
4370
|
+
event.stopPropagation();
|
|
4371
|
+
this.gestureStart$.next(event);
|
|
4372
|
+
}
|
|
4373
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: DragHandleDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
4374
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.5", type: DragHandleDirective, isStandalone: true, selector: "[etDragHandle]", inputs: { commitThreshold: { classPropertyName: "commitThreshold", publicName: "commitThreshold", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dragTapped: "dragTapped", dragStarted: "dragStarted", dragMoved: "dragMoved", dragEnded: "dragEnded" }, ngImport: i0 }); }
|
|
4375
|
+
}
|
|
4376
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: DragHandleDirective, decorators: [{
|
|
4377
|
+
type: Directive,
|
|
4378
|
+
args: [{
|
|
4379
|
+
selector: '[etDragHandle]',
|
|
4380
|
+
}]
|
|
4381
|
+
}], ctorParameters: () => [], propDecorators: { commitThreshold: [{ type: i0.Input, args: [{ isSignal: true, alias: "commitThreshold", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], dragTapped: [{ type: i0.Output, args: ["dragTapped"] }], dragStarted: [{ type: i0.Output, args: ["dragStarted"] }], dragMoved: [{ type: i0.Output, args: ["dragMoved"] }], dragEnded: [{ type: i0.Output, args: ["dragEnded"] }] } });
|
|
4382
|
+
|
|
4383
|
+
const FOCUSABLE_SELECTOR = [
|
|
4384
|
+
'a[href]',
|
|
4385
|
+
'area[href]',
|
|
4386
|
+
'button:not([disabled])',
|
|
4387
|
+
'input:not([disabled]):not([type="hidden"])',
|
|
4388
|
+
'select:not([disabled])',
|
|
4389
|
+
'textarea:not([disabled])',
|
|
4390
|
+
'iframe',
|
|
4391
|
+
'[tabindex]:not([tabindex="-1"])',
|
|
4392
|
+
'[contenteditable="true"]',
|
|
4393
|
+
].join(',');
|
|
4394
|
+
const isHTMLElement = (value) => {
|
|
4395
|
+
return value instanceof HTMLElement;
|
|
4396
|
+
};
|
|
4397
|
+
const isFocusable = (element, document) => {
|
|
4398
|
+
const view = document.defaultView;
|
|
4399
|
+
const style = view?.getComputedStyle(element);
|
|
4400
|
+
const isVisible = style?.display !== 'none' && style?.visibility !== 'hidden' && element.getClientRects().length > 0;
|
|
4401
|
+
return isVisible && !element.hasAttribute('disabled') && element.tabIndex >= 0;
|
|
4402
|
+
};
|
|
4403
|
+
const getFocusableElements = (container, document) => {
|
|
4404
|
+
return Array.from(container.querySelectorAll(FOCUSABLE_SELECTOR)).filter((el) => isFocusable(el, document));
|
|
4405
|
+
};
|
|
4406
|
+
const getHeadingElement = (container) => {
|
|
4407
|
+
return container.querySelector('h1, h2, h3, h4, h5, h6, [role="heading"]');
|
|
4408
|
+
};
|
|
4409
|
+
const focusElement = (element) => {
|
|
4410
|
+
if (!element) {
|
|
4411
|
+
return;
|
|
4412
|
+
}
|
|
4413
|
+
element.focus({ preventScroll: true });
|
|
4414
|
+
};
|
|
4415
|
+
const applyInitialFocus = (paneElement, autoFocus, document) => {
|
|
4416
|
+
if (autoFocus === false) {
|
|
4417
|
+
return;
|
|
4418
|
+
}
|
|
4419
|
+
if (autoFocus === 'container') {
|
|
4420
|
+
focusElement(paneElement);
|
|
4421
|
+
return;
|
|
4422
|
+
}
|
|
4423
|
+
if (autoFocus === 'first-heading') {
|
|
4424
|
+
focusElement(getHeadingElement(paneElement) ?? paneElement);
|
|
4425
|
+
return;
|
|
4426
|
+
}
|
|
4427
|
+
if (autoFocus === 'first-tabbable') {
|
|
4428
|
+
focusElement(getFocusableElements(paneElement, document)[0] ?? paneElement);
|
|
4429
|
+
return;
|
|
4430
|
+
}
|
|
4431
|
+
focusElement(paneElement.querySelector(autoFocus) ?? paneElement);
|
|
4432
|
+
};
|
|
4433
|
+
const setupFocusTrap = (paneElement, overlayRef, enabled, isTopMost, document) => {
|
|
4434
|
+
if (!enabled) {
|
|
4435
|
+
return () => undefined;
|
|
4436
|
+
}
|
|
4437
|
+
const onKeyDown = (event) => {
|
|
4438
|
+
if (event.key !== 'Tab' || !isTopMost(overlayRef)) {
|
|
4439
|
+
return;
|
|
4440
|
+
}
|
|
4441
|
+
const focusableElements = getFocusableElements(paneElement, document);
|
|
4442
|
+
if (focusableElements.length === 0) {
|
|
4443
|
+
event.preventDefault();
|
|
4444
|
+
focusElement(paneElement);
|
|
4445
|
+
return;
|
|
4446
|
+
}
|
|
4447
|
+
const firstElement = focusableElements[0];
|
|
4448
|
+
const lastElement = focusableElements[focusableElements.length - 1];
|
|
4449
|
+
const activeElement = document.activeElement;
|
|
4450
|
+
if (event.shiftKey && activeElement === firstElement) {
|
|
4451
|
+
event.preventDefault();
|
|
4452
|
+
focusElement(lastElement ?? null);
|
|
4453
|
+
return;
|
|
4454
|
+
}
|
|
4455
|
+
if (!event.shiftKey && activeElement === lastElement) {
|
|
4456
|
+
event.preventDefault();
|
|
4457
|
+
focusElement(firstElement ?? null);
|
|
4458
|
+
}
|
|
4459
|
+
};
|
|
4460
|
+
paneElement.addEventListener('keydown', onKeyDown);
|
|
4461
|
+
return () => {
|
|
4462
|
+
paneElement.removeEventListener('keydown', onKeyDown);
|
|
4463
|
+
};
|
|
4464
|
+
};
|
|
4465
|
+
|
|
4466
|
+
const setBaseElementStyles = (config, hostElement, paneElement, renderer) => {
|
|
4467
|
+
renderer.setStyle(hostElement, {
|
|
4468
|
+
position: 'fixed',
|
|
4469
|
+
top: '0',
|
|
4470
|
+
left: '0',
|
|
4471
|
+
right: '0',
|
|
4472
|
+
bottom: '0',
|
|
4473
|
+
display: 'block',
|
|
4474
|
+
pointerEvents: config.hasBackdrop === false ? 'none' : 'auto',
|
|
4475
|
+
});
|
|
4476
|
+
renderer.setStyle(paneElement, {
|
|
4477
|
+
pointerEvents: 'auto',
|
|
4478
|
+
outline: 'none',
|
|
4479
|
+
});
|
|
4480
|
+
};
|
|
4481
|
+
const setBackdropStyles = (backdropElement, renderer) => {
|
|
4482
|
+
renderer.setStyle(backdropElement, {
|
|
4483
|
+
position: 'absolute',
|
|
4484
|
+
top: '0',
|
|
4485
|
+
left: '0',
|
|
4486
|
+
right: '0',
|
|
4487
|
+
bottom: '0',
|
|
4488
|
+
});
|
|
4489
|
+
};
|
|
4490
|
+
const applyCenteredPosition = (hostElement, paneElement, renderer, _config) => {
|
|
4491
|
+
renderer.setStyle(hostElement, {
|
|
4492
|
+
display: 'grid',
|
|
4493
|
+
placeItems: 'center',
|
|
4494
|
+
padding: '16px',
|
|
4495
|
+
overflow: 'auto',
|
|
4496
|
+
});
|
|
4497
|
+
renderer.setStyle(paneElement, {
|
|
4498
|
+
position: 'relative',
|
|
4499
|
+
});
|
|
4500
|
+
};
|
|
4501
|
+
const applyGlobalPosition = (hostElement, paneElement, renderer, config) => {
|
|
4502
|
+
renderer.setStyle(hostElement, {
|
|
4503
|
+
display: 'grid',
|
|
4504
|
+
// an explicit full-size cell keeps the grid area definite so percentage
|
|
4505
|
+
// based pane sizes (e.g. max-height: calc(100% - 72px)) can resolve
|
|
4506
|
+
gridTemplateRows: '100%',
|
|
4507
|
+
gridTemplateColumns: '100%',
|
|
4508
|
+
placeItems: `${config.vertical ?? 'center'} ${config.horizontal ?? 'center'}`,
|
|
4509
|
+
padding: config.padding ?? '0',
|
|
4510
|
+
});
|
|
4511
|
+
renderer.setStyle(paneElement, {
|
|
4512
|
+
position: 'relative',
|
|
4513
|
+
});
|
|
4514
|
+
};
|
|
4515
|
+
/**
|
|
4516
|
+
* Clears every inline style any position strategy kind may have set and
|
|
4517
|
+
* restores the base element styles, so a different strategy can be applied afterwards.
|
|
4518
|
+
*/
|
|
4519
|
+
const resetPositioningStyles = (config, hostElement, paneElement, renderer) => {
|
|
4520
|
+
renderer.setStyle(hostElement, {
|
|
4521
|
+
gridTemplateRows: null,
|
|
4522
|
+
gridTemplateColumns: null,
|
|
4523
|
+
placeItems: null,
|
|
4524
|
+
padding: null,
|
|
4525
|
+
overflow: null,
|
|
4526
|
+
});
|
|
4527
|
+
renderer.setStyle(paneElement, {
|
|
4528
|
+
position: null,
|
|
4529
|
+
top: null,
|
|
4530
|
+
left: null,
|
|
4531
|
+
width: null,
|
|
4532
|
+
transform: null,
|
|
4533
|
+
visibility: null,
|
|
4534
|
+
});
|
|
4535
|
+
renderer.setCssProperties(paneElement, {
|
|
4536
|
+
'--et-overlay-max-width': null,
|
|
4537
|
+
'--et-overlay-max-height': null,
|
|
4538
|
+
'--et-overlay-anchored-x': null,
|
|
4539
|
+
'--et-overlay-anchored-y': null,
|
|
4540
|
+
});
|
|
4541
|
+
renderer.removeAttribute(paneElement, 'data-overlay-placement');
|
|
4542
|
+
setBaseElementStyles(config, hostElement, paneElement, renderer);
|
|
4543
|
+
};
|
|
4544
|
+
const createAnchoredPositionCleanup = (strategy, paneElement, overlayRef, renderer) => {
|
|
4545
|
+
renderer.setStyle(paneElement, {
|
|
4546
|
+
position: 'absolute',
|
|
4547
|
+
top: '0',
|
|
4548
|
+
left: '0',
|
|
4549
|
+
width: strategy.mirrorWidth ? `${strategy.referenceElement.offsetWidth}px` : 'max-content',
|
|
4550
|
+
});
|
|
4551
|
+
const cleanup = autoUpdate(strategy.referenceElement, paneElement, () => {
|
|
4552
|
+
const arrowElement = paneElement.querySelector('[et-floating-arrow]');
|
|
4553
|
+
const middleware = [];
|
|
4554
|
+
middleware.push(offset(strategy.offset ?? 8));
|
|
4555
|
+
middleware.push(flip({
|
|
4556
|
+
fallbackPlacements: strategy.fallbackPlacements ?? undefined,
|
|
4557
|
+
fallbackAxisSideDirection: 'start',
|
|
4558
|
+
}));
|
|
4559
|
+
if (strategy.autoResize) {
|
|
4560
|
+
middleware.push(size({
|
|
4561
|
+
padding: strategy.viewportPadding ?? 8,
|
|
4562
|
+
apply({ availableHeight, availableWidth }) {
|
|
4563
|
+
renderer.setCssProperties(paneElement, {
|
|
4564
|
+
'--et-overlay-max-width': `${availableWidth}px`,
|
|
4565
|
+
'--et-overlay-max-height': `${availableHeight}px`,
|
|
4566
|
+
});
|
|
4567
|
+
},
|
|
4568
|
+
}));
|
|
4569
|
+
}
|
|
4570
|
+
if (strategy.shift !== false) {
|
|
4571
|
+
middleware.push(shift({
|
|
4572
|
+
limiter: limitShift(),
|
|
4573
|
+
padding: strategy.viewportPadding ?? 8,
|
|
4574
|
+
}));
|
|
4575
|
+
}
|
|
4576
|
+
if (arrowElement) {
|
|
4577
|
+
middleware.push(arrow({
|
|
4578
|
+
element: arrowElement,
|
|
4579
|
+
padding: strategy.arrowPadding ?? 4,
|
|
4580
|
+
}));
|
|
4581
|
+
}
|
|
4582
|
+
if (strategy.autoHide || strategy.autoCloseIfReferenceHidden) {
|
|
4583
|
+
middleware.push(hide({
|
|
4584
|
+
strategy: 'referenceHidden',
|
|
4585
|
+
}));
|
|
4586
|
+
}
|
|
4587
|
+
computePosition(strategy.referenceElement, paneElement, {
|
|
4588
|
+
placement: strategy.placement ?? 'bottom',
|
|
4589
|
+
strategy: 'absolute',
|
|
4590
|
+
middleware,
|
|
4591
|
+
}).then(({ x, y, placement, middlewareData }) => {
|
|
4592
|
+
renderer.setStyle(paneElement, {
|
|
4593
|
+
transform: `translate3d(${x}px, ${y}px, 0)`,
|
|
4594
|
+
width: strategy.mirrorWidth ? `${strategy.referenceElement.offsetWidth}px` : null,
|
|
4595
|
+
});
|
|
4596
|
+
// exposed so animations can compose their transforms with the anchored position
|
|
4597
|
+
renderer.setCssProperties(paneElement, {
|
|
4598
|
+
'--et-overlay-anchored-x': `${x}px`,
|
|
4599
|
+
'--et-overlay-anchored-y': `${y}px`,
|
|
4600
|
+
});
|
|
4601
|
+
renderer.setAttribute(paneElement, 'data-overlay-placement', placement);
|
|
4602
|
+
if (arrowElement && middlewareData.arrow) {
|
|
4603
|
+
renderer.setCssProperty(arrowElement, '--et-floating-arrow-translate', `translate3d(${middlewareData.arrow.x ?? 0}px, ${middlewareData.arrow.y ?? 0}px, 0)`);
|
|
4604
|
+
}
|
|
4605
|
+
if (middlewareData.hide?.referenceHidden) {
|
|
4606
|
+
if (strategy.autoCloseIfReferenceHidden) {
|
|
4607
|
+
overlayRef.close(undefined, 'api');
|
|
4608
|
+
return;
|
|
4609
|
+
}
|
|
4610
|
+
renderer.setStyle(paneElement, {
|
|
4611
|
+
visibility: strategy.autoHide ? 'hidden' : null,
|
|
4612
|
+
});
|
|
4613
|
+
return;
|
|
4614
|
+
}
|
|
4615
|
+
renderer.setStyle(paneElement, {
|
|
4616
|
+
visibility: null,
|
|
4617
|
+
});
|
|
4618
|
+
});
|
|
4619
|
+
});
|
|
4620
|
+
return () => {
|
|
4621
|
+
cleanup();
|
|
4622
|
+
};
|
|
4623
|
+
};
|
|
4624
|
+
const setupPositioning = (config, hostElement, paneElement, overlayRef, renderer) => {
|
|
4625
|
+
const strategy = config.positionStrategy ?? { kind: 'center' };
|
|
4626
|
+
if (strategy.kind === 'anchored') {
|
|
4627
|
+
renderer.setStyle(hostElement, {
|
|
4628
|
+
pointerEvents: config.hasBackdrop === false ? 'none' : 'auto',
|
|
4629
|
+
});
|
|
4630
|
+
return createAnchoredPositionCleanup(strategy, paneElement, overlayRef, renderer);
|
|
4631
|
+
}
|
|
4632
|
+
if (strategy.kind === 'global') {
|
|
4633
|
+
applyGlobalPosition(hostElement, paneElement, renderer, strategy);
|
|
4634
|
+
return () => undefined;
|
|
4635
|
+
}
|
|
4636
|
+
applyCenteredPosition(hostElement, paneElement, renderer, strategy);
|
|
4637
|
+
return () => undefined;
|
|
4638
|
+
};
|
|
4639
|
+
|
|
4640
|
+
const createOverlayRuntimeRef = (id, config, elements, requestClose) => {
|
|
4641
|
+
const _state = signal('mounting', /* @ts-ignore */
|
|
4642
|
+
...(ngDevMode ? [{ debugName: "_state" }] : /* istanbul ignore next */ []));
|
|
4643
|
+
const _componentInstance = signal(null, /* @ts-ignore */
|
|
4644
|
+
...(ngDevMode ? [{ debugName: "_componentInstance" }] : /* istanbul ignore next */ []));
|
|
4645
|
+
let positionUpdater = null;
|
|
4646
|
+
const beforeOpenedSubject = new Subject();
|
|
4647
|
+
const afterOpenedSubject = new Subject();
|
|
4648
|
+
const beforeClosedSubject = new Subject();
|
|
4649
|
+
const afterClosedSubject = new Subject();
|
|
4650
|
+
return {
|
|
4651
|
+
id,
|
|
4652
|
+
config,
|
|
4653
|
+
elements,
|
|
4654
|
+
state: _state.asReadonly(),
|
|
4655
|
+
componentInstance: _componentInstance.asReadonly(),
|
|
4656
|
+
// Internal — driven by overlay-runtime.ts
|
|
4657
|
+
beforeOpenedSubject,
|
|
4658
|
+
close(result, source = 'api') {
|
|
4659
|
+
if (_state() === 'closing' || _state() === 'closed') {
|
|
4660
|
+
return;
|
|
4661
|
+
}
|
|
4662
|
+
requestClose(result, source);
|
|
4663
|
+
},
|
|
4664
|
+
beforeOpened() {
|
|
4665
|
+
return beforeOpenedSubject.asObservable();
|
|
4666
|
+
},
|
|
4667
|
+
afterOpened() {
|
|
4668
|
+
return afterOpenedSubject.asObservable();
|
|
4669
|
+
},
|
|
4670
|
+
beforeClosed() {
|
|
4671
|
+
return beforeClosedSubject.asObservable();
|
|
4672
|
+
},
|
|
4673
|
+
afterClosed() {
|
|
4674
|
+
return afterClosedSubject.asObservable();
|
|
4675
|
+
},
|
|
4676
|
+
attachComponentRef(componentRef) {
|
|
4677
|
+
_componentInstance.set(componentRef.instance);
|
|
4678
|
+
},
|
|
4679
|
+
/** @internal */
|
|
4680
|
+
attachPositionUpdater(updater) {
|
|
4681
|
+
positionUpdater = updater;
|
|
4682
|
+
},
|
|
4683
|
+
updatePositionStrategy(strategy) {
|
|
4684
|
+
if (_state() === 'closing' || _state() === 'closed') {
|
|
4685
|
+
return;
|
|
4686
|
+
}
|
|
4687
|
+
positionUpdater?.(strategy);
|
|
4688
|
+
},
|
|
4689
|
+
markOpened() {
|
|
4690
|
+
if (_state() !== 'mounting') {
|
|
4691
|
+
return;
|
|
4692
|
+
}
|
|
4693
|
+
_state.set('mounted');
|
|
4694
|
+
afterOpenedSubject.next();
|
|
4695
|
+
afterOpenedSubject.complete();
|
|
4696
|
+
},
|
|
4697
|
+
beginClose(closeEvent) {
|
|
4698
|
+
if (_state() === 'closing' || _state() === 'closed') {
|
|
4699
|
+
return false;
|
|
4700
|
+
}
|
|
4701
|
+
_state.set('closing');
|
|
4702
|
+
beforeClosedSubject.next(closeEvent);
|
|
4703
|
+
beforeClosedSubject.complete();
|
|
4704
|
+
return true;
|
|
4705
|
+
},
|
|
4706
|
+
finishClose(closeEvent) {
|
|
4707
|
+
if (_state() === 'closed') {
|
|
4708
|
+
return;
|
|
4709
|
+
}
|
|
4710
|
+
_state.set('closed');
|
|
4711
|
+
_componentInstance.set(null);
|
|
4712
|
+
afterClosedSubject.next(closeEvent);
|
|
4713
|
+
afterClosedSubject.complete();
|
|
4714
|
+
},
|
|
4715
|
+
};
|
|
4716
|
+
};
|
|
3383
4717
|
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
4718
|
+
const [provideOverlayRuntime, injectOverlayRuntime] = createRootProvider(() => {
|
|
4719
|
+
const appRef = inject(ApplicationRef);
|
|
4720
|
+
const destroyRef = inject(DestroyRef);
|
|
4721
|
+
const document = inject(DOCUMENT);
|
|
4722
|
+
const environmentInjector = inject(EnvironmentInjector);
|
|
4723
|
+
const renderer = injectRenderer();
|
|
4724
|
+
const openEntriesState = signal([], /* @ts-ignore */
|
|
4725
|
+
...(ngDevMode ? [{ debugName: "openEntriesState" }] : /* istanbul ignore next */ []));
|
|
4726
|
+
const openEntries = computed(() => openEntriesState(), /* @ts-ignore */
|
|
4727
|
+
...(ngDevMode ? [{ debugName: "openEntries" }] : /* istanbul ignore next */ []));
|
|
4728
|
+
let rootElement = null;
|
|
4729
|
+
// Synchronous teardown for each currently-mounted overlay, run when the runtime's injector is
|
|
4730
|
+
// destroyed (app teardown). Registered on mount, removed once the overlay is destroyed normally.
|
|
4731
|
+
const mountedTeardowns = new Set();
|
|
4732
|
+
const getRootElement = () => {
|
|
4733
|
+
if (rootElement) {
|
|
4734
|
+
return rootElement;
|
|
4735
|
+
}
|
|
4736
|
+
// A previous Angular app (e.g. the one that existed before a Storybook HMR update or story
|
|
4737
|
+
// switch) may have left its runtime root orphaned in <body> if it was torn down mid-animation.
|
|
4738
|
+
// Such a node keeps a backdrop/pane on screen and blocks pointer events, so clear any stragglers
|
|
4739
|
+
// before creating ours.
|
|
4740
|
+
document.querySelectorAll('.et-overlay-runtime-root').forEach((el) => el.remove());
|
|
4741
|
+
rootElement = renderer.createElement('div');
|
|
4742
|
+
renderer.addClass(rootElement, 'et-overlay-runtime-root');
|
|
4743
|
+
renderer.setStyle(rootElement, {
|
|
4744
|
+
position: 'fixed',
|
|
4745
|
+
top: '0',
|
|
4746
|
+
left: '0',
|
|
4747
|
+
right: '0',
|
|
4748
|
+
bottom: '0',
|
|
4749
|
+
pointerEvents: 'none',
|
|
4750
|
+
zIndex: '1000',
|
|
4751
|
+
});
|
|
4752
|
+
renderer.appendChild(document.body, rootElement);
|
|
4753
|
+
return rootElement;
|
|
4754
|
+
};
|
|
4755
|
+
const maybeDestroyRootElement = () => {
|
|
4756
|
+
if (!rootElement || openEntriesState().length > 0) {
|
|
4757
|
+
return;
|
|
4758
|
+
}
|
|
4759
|
+
const parentNode = renderer.parentNode(rootElement);
|
|
4760
|
+
if (parentNode) {
|
|
4761
|
+
renderer.removeChild(parentNode, rootElement);
|
|
4762
|
+
}
|
|
4763
|
+
rootElement = null;
|
|
4764
|
+
};
|
|
4765
|
+
const isTopMost = (overlayRef) => {
|
|
4766
|
+
return openEntriesState().at(-1) === overlayRef;
|
|
4767
|
+
};
|
|
4768
|
+
const getAnimatedLifecycle = (componentRef) => {
|
|
4769
|
+
const componentLifecycle = componentRef.instance.animatedLifecycle?.();
|
|
4770
|
+
if (componentLifecycle) {
|
|
4771
|
+
return componentLifecycle;
|
|
4772
|
+
}
|
|
4773
|
+
return componentRef.injector.get(ANIMATED_LIFECYCLE_TOKEN, null);
|
|
4774
|
+
};
|
|
4775
|
+
const mount = (config) => {
|
|
4776
|
+
const root = getRootElement();
|
|
4777
|
+
const hostElement = renderer.createElement('div');
|
|
4778
|
+
const paneElement = renderer.createElement('div');
|
|
4779
|
+
const backdropElement = config.hasBackdrop === false ? null : renderer.createElement('div');
|
|
4780
|
+
const previousFocusedElement = isHTMLElement(document.activeElement) ? document.activeElement : null;
|
|
4781
|
+
const autoFocus = config.autoFocus ?? 'first-tabbable';
|
|
4782
|
+
renderer.addClass(hostElement, 'et-overlay-runtime-entry');
|
|
4783
|
+
setBaseElementStyles(config, hostElement, paneElement, renderer);
|
|
4784
|
+
renderer.setAttributes(hostElement, {
|
|
4785
|
+
'data-overlay-id': config.id,
|
|
4786
|
+
role: config.role ?? null,
|
|
4787
|
+
tabindex: '-1',
|
|
4788
|
+
'aria-modal': config.role ? `${config.modal !== false}` : null,
|
|
4789
|
+
'aria-describedby': config.ariaDescribedBy ?? null,
|
|
4790
|
+
'aria-labelledby': config.ariaLabelledBy ?? null,
|
|
4791
|
+
'aria-label': config.ariaLabel ?? null,
|
|
4792
|
+
});
|
|
4793
|
+
renderer.addClass(hostElement, ...(config.hostClass ?? []));
|
|
4794
|
+
if (backdropElement) {
|
|
4795
|
+
renderer.addClass(backdropElement, 'et-overlay-runtime-backdrop');
|
|
4796
|
+
setBackdropStyles(backdropElement, renderer);
|
|
4797
|
+
renderer.setAttribute(backdropElement, 'data-overlay-id', config.id);
|
|
4798
|
+
(config.backdropClass ?? []).forEach((className) => renderer.addClass(backdropElement, className));
|
|
4799
|
+
renderer.appendChild(hostElement, backdropElement);
|
|
4800
|
+
}
|
|
4801
|
+
renderer.appendChild(hostElement, paneElement);
|
|
4802
|
+
renderer.appendChild(root, hostElement);
|
|
4803
|
+
const overlayRef = createOverlayRuntimeRef(config.id, { ...config }, {
|
|
4804
|
+
rootElement: root,
|
|
4805
|
+
hostElement,
|
|
4806
|
+
backdropElement,
|
|
4807
|
+
paneElement,
|
|
4808
|
+
}, (result, source) => beginClose({ result, source }));
|
|
4809
|
+
animationDebugLog(`runtime ${config.id}`, 'mount');
|
|
4810
|
+
// matches the previous overlay behavior: escape/outside-pointer closes are
|
|
4811
|
+
// ignored until the enter transition has started plus one frame
|
|
4812
|
+
let interactiveCloseReady = false;
|
|
4813
|
+
const cleanupFns = [];
|
|
4814
|
+
const parentInjector = config.injector ?? config.viewContainerRef?.injector ?? environmentInjector;
|
|
4815
|
+
const elementInjector = Injector.create({
|
|
4816
|
+
parent: parentInjector,
|
|
4817
|
+
providers: config.providers ?? [],
|
|
4818
|
+
});
|
|
4819
|
+
const componentRef = createComponent(config.component, {
|
|
4820
|
+
environmentInjector,
|
|
4821
|
+
elementInjector,
|
|
4822
|
+
hostElement: paneElement,
|
|
4823
|
+
bindings: [
|
|
4824
|
+
...Object.entries(config.inputBindings ?? {}).map(([key, value]) => inputBinding(key, () => value)),
|
|
4825
|
+
...Object.entries(config.outputBindings ?? {}).map(([key, listener]) => outputBinding(key, listener)),
|
|
4826
|
+
],
|
|
4827
|
+
});
|
|
4828
|
+
// pane classes are applied after component creation — Angular replaces the host
|
|
4829
|
+
// element's class attribute with the component's static host class on creation
|
|
4830
|
+
renderer.addClass(paneElement, 'et-overlay-runtime-pane', ...(config.paneClass ?? []));
|
|
4831
|
+
appRef.attachView(componentRef.hostView);
|
|
4832
|
+
overlayRef.attachComponentRef(componentRef);
|
|
4833
|
+
overlayRef.beforeOpenedSubject.next();
|
|
4834
|
+
overlayRef.beforeOpenedSubject.complete();
|
|
4835
|
+
openEntriesState.update((entries) => [...entries, overlayRef]);
|
|
4836
|
+
let positionCleanup = setupPositioning(config, hostElement, paneElement, overlayRef, renderer);
|
|
4837
|
+
cleanupFns.push(() => positionCleanup());
|
|
4838
|
+
let currentPositionStrategy = config.positionStrategy;
|
|
4839
|
+
const getOriginElement = () => currentPositionStrategy?.kind === 'anchored' ? currentPositionStrategy.referenceElement : null;
|
|
4840
|
+
overlayRef.attachPositionUpdater((strategy) => {
|
|
4841
|
+
currentPositionStrategy = strategy;
|
|
4842
|
+
positionCleanup();
|
|
4843
|
+
resetPositioningStyles(config, hostElement, paneElement, renderer);
|
|
4844
|
+
positionCleanup = setupPositioning({ ...config, positionStrategy: strategy }, hostElement, paneElement, overlayRef, renderer);
|
|
4845
|
+
});
|
|
4846
|
+
const destroyMountedOverlay = (closeEvent) => {
|
|
4847
|
+
animationDebugLog(`runtime ${config.id}`, `destroy (source "${closeEvent.source}")`);
|
|
4848
|
+
cleanupFns.forEach((cleanup) => cleanup());
|
|
4849
|
+
appRef.detachView(componentRef.hostView);
|
|
4850
|
+
componentRef.destroy();
|
|
4851
|
+
const parentNode = renderer.parentNode(hostElement);
|
|
4852
|
+
if (parentNode) {
|
|
4853
|
+
renderer.removeChild(parentNode, hostElement);
|
|
4854
|
+
}
|
|
4855
|
+
openEntriesState.update((entries) => entries.filter((entry) => entry !== overlayRef));
|
|
4856
|
+
maybeDestroyRootElement();
|
|
4857
|
+
if (config.restoreFocus !== false && previousFocusedElement?.isConnected) {
|
|
4858
|
+
previousFocusedElement.focus({ preventScroll: true });
|
|
4859
|
+
}
|
|
4860
|
+
overlayRef.finishClose(closeEvent);
|
|
4861
|
+
};
|
|
4862
|
+
// Allows the runtime to synchronously destroy this overlay on app teardown, bypassing the
|
|
4863
|
+
// async leave animation (whose completion callback would never fire once the app is gone).
|
|
4864
|
+
const forceTeardown = () => destroyMountedOverlay({ result: undefined, source: 'api' });
|
|
4865
|
+
mountedTeardowns.add(forceTeardown);
|
|
4866
|
+
cleanupFns.push(() => mountedTeardowns.delete(forceTeardown));
|
|
4867
|
+
const beginClose = (closeEvent) => {
|
|
4868
|
+
if (!overlayRef.beginClose(closeEvent)) {
|
|
4869
|
+
return;
|
|
4870
|
+
}
|
|
4871
|
+
const lifecycle = getAnimatedLifecycle(componentRef);
|
|
4872
|
+
animationDebugLog(`runtime ${config.id}`, `close requested (source "${closeEvent.source}", lifecycle state "${lifecycle?.state$.value ?? 'none'}", delegate ${config.animationDelegate?.leave ? 'yes' : 'no'})`);
|
|
4873
|
+
if (!lifecycle) {
|
|
4874
|
+
destroyMountedOverlay(closeEvent);
|
|
4875
|
+
return;
|
|
4876
|
+
}
|
|
4877
|
+
if (config.animationDelegate?.leave) {
|
|
4878
|
+
config.animationDelegate.leave({ lifecycle, elements: overlayRef.elements, closeEvent });
|
|
4879
|
+
}
|
|
4880
|
+
else {
|
|
4881
|
+
lifecycle.leave();
|
|
4882
|
+
}
|
|
4883
|
+
lifecycle.state$
|
|
4884
|
+
.pipe(filter((state) => state === 'left'), take(1))
|
|
4885
|
+
.subscribe(() => {
|
|
4886
|
+
destroyMountedOverlay(closeEvent);
|
|
4887
|
+
});
|
|
4888
|
+
};
|
|
4889
|
+
const closeOnEscape = config.closeOnEscape ?? true;
|
|
4890
|
+
if (closeOnEscape) {
|
|
4891
|
+
const onKeyDown = (event) => {
|
|
4892
|
+
if (event.key !== 'Escape' || !isTopMost(overlayRef)) {
|
|
4893
|
+
return;
|
|
3395
4894
|
}
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
views.push(this.viewContainerRef.createEmbeddedView(this.mainTemplateRef));
|
|
3400
|
-
}
|
|
4895
|
+
if (!interactiveCloseReady) {
|
|
4896
|
+
animationDebugLog(`runtime ${config.id}`, 'escape ignored (enter transition has not started yet)');
|
|
4897
|
+
return;
|
|
3401
4898
|
}
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
4899
|
+
event.preventDefault();
|
|
4900
|
+
overlayRef.close(undefined, 'escape');
|
|
4901
|
+
};
|
|
4902
|
+
document.addEventListener('keydown', onKeyDown, true);
|
|
4903
|
+
cleanupFns.push(() => document.removeEventListener('keydown', onKeyDown, true));
|
|
4904
|
+
}
|
|
4905
|
+
const closeOnOutsidePointer = config.closeOnOutsidePointer ?? config.modal === false;
|
|
4906
|
+
if (closeOnOutsidePointer) {
|
|
4907
|
+
const onPointerDown = (event) => {
|
|
4908
|
+
if (!isTopMost(overlayRef)) {
|
|
4909
|
+
return;
|
|
3407
4910
|
}
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
4911
|
+
const target = event.target;
|
|
4912
|
+
if (!isHTMLElement(target) || paneElement.contains(target)) {
|
|
4913
|
+
return;
|
|
4914
|
+
}
|
|
4915
|
+
if (!interactiveCloseReady) {
|
|
4916
|
+
animationDebugLog(`runtime ${config.id}`, 'outside pointer ignored (enter transition has not started yet)');
|
|
4917
|
+
return;
|
|
4918
|
+
}
|
|
4919
|
+
overlayRef.close(undefined, 'outside-pointer');
|
|
4920
|
+
const originElement = getOriginElement();
|
|
4921
|
+
if (originElement && originElement.contains(target)) {
|
|
4922
|
+
const swallowReopenClick = (clickEvent) => {
|
|
4923
|
+
if (isHTMLElement(clickEvent.target) && originElement.contains(clickEvent.target)) {
|
|
4924
|
+
clickEvent.stopImmediatePropagation();
|
|
4925
|
+
clickEvent.preventDefault();
|
|
4926
|
+
}
|
|
4927
|
+
};
|
|
4928
|
+
document.addEventListener('click', swallowReopenClick, { capture: true, once: true });
|
|
4929
|
+
}
|
|
4930
|
+
};
|
|
4931
|
+
document.addEventListener('pointerdown', onPointerDown, true);
|
|
4932
|
+
cleanupFns.push(() => document.removeEventListener('pointerdown', onPointerDown, true));
|
|
4933
|
+
}
|
|
4934
|
+
cleanupFns.push(setupFocusTrap(paneElement, overlayRef, config.modal !== false, isTopMost, document));
|
|
4935
|
+
nextFrame(() => {
|
|
4936
|
+
if (overlayRef.state() !== 'mounting') {
|
|
4937
|
+
animationDebugLog(`runtime ${config.id}`, `enter skipped (state "${overlayRef.state()}" before enter frame)`);
|
|
4938
|
+
return;
|
|
4939
|
+
}
|
|
4940
|
+
const lifecycle = getAnimatedLifecycle(componentRef);
|
|
4941
|
+
if (!lifecycle) {
|
|
4942
|
+
interactiveCloseReady = true;
|
|
4943
|
+
applyInitialFocus(paneElement, autoFocus, document);
|
|
4944
|
+
overlayRef.markOpened();
|
|
4945
|
+
return;
|
|
4946
|
+
}
|
|
4947
|
+
animationDebugLog(`runtime ${config.id}`, `enter (delegate ${config.animationDelegate?.enter ? 'yes' : 'no'}, lifecycle state "${lifecycle.state$.value}")`);
|
|
4948
|
+
const readySubscription = lifecycle.state$
|
|
4949
|
+
.pipe(filter((state) => state === 'entering' || state === 'entered'), take(1))
|
|
4950
|
+
.subscribe(() => {
|
|
4951
|
+
nextFrame(() => {
|
|
4952
|
+
interactiveCloseReady = true;
|
|
4953
|
+
});
|
|
4954
|
+
});
|
|
4955
|
+
cleanupFns.push(() => readySubscription.unsubscribe());
|
|
4956
|
+
if (config.animationDelegate?.enter) {
|
|
4957
|
+
config.animationDelegate.enter({ lifecycle, elements: overlayRef.elements });
|
|
4958
|
+
}
|
|
4959
|
+
else {
|
|
4960
|
+
lifecycle.enter();
|
|
4961
|
+
}
|
|
4962
|
+
lifecycle.state$
|
|
4963
|
+
.pipe(filter((state) => state === 'entered'), take(1))
|
|
4964
|
+
.subscribe(() => {
|
|
4965
|
+
applyInitialFocus(paneElement, autoFocus, document);
|
|
4966
|
+
overlayRef.markOpened();
|
|
4967
|
+
});
|
|
4968
|
+
});
|
|
4969
|
+
return overlayRef;
|
|
4970
|
+
};
|
|
4971
|
+
destroyRef.onDestroy(() => {
|
|
4972
|
+
[...mountedTeardowns].forEach((teardown) => teardown());
|
|
4973
|
+
maybeDestroyRootElement();
|
|
4974
|
+
});
|
|
4975
|
+
return {
|
|
4976
|
+
mount,
|
|
4977
|
+
openEntries,
|
|
4978
|
+
};
|
|
4979
|
+
}, { name: 'OverlayRuntime' });
|
|
3423
4980
|
|
|
3424
4981
|
class NormalizeGameResultTypePipe {
|
|
3425
4982
|
constructor() {
|
|
3426
4983
|
this.transform = normalizeGameResultType;
|
|
3427
4984
|
}
|
|
3428
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
3429
|
-
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "
|
|
4985
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NormalizeGameResultTypePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
4986
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.0.5", ngImport: i0, type: NormalizeGameResultTypePipe, isStandalone: true, name: "etNormalizeGameResultType" }); }
|
|
3430
4987
|
}
|
|
3431
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
4988
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NormalizeGameResultTypePipe, decorators: [{
|
|
3432
4989
|
type: Pipe,
|
|
3433
4990
|
args: [{ name: 'etNormalizeGameResultType' }]
|
|
3434
4991
|
}] });
|
|
@@ -3470,10 +5027,10 @@ class NormalizeMatchStatePipe {
|
|
|
3470
5027
|
constructor() {
|
|
3471
5028
|
this.transform = normalizeMatchState;
|
|
3472
5029
|
}
|
|
3473
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
3474
|
-
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "
|
|
5030
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NormalizeMatchStatePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
5031
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.0.5", ngImport: i0, type: NormalizeMatchStatePipe, isStandalone: true, name: "etNormalizeMatchState" }); }
|
|
3475
5032
|
}
|
|
3476
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
5033
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NormalizeMatchStatePipe, decorators: [{
|
|
3477
5034
|
type: Pipe,
|
|
3478
5035
|
args: [{ name: 'etNormalizeMatchState' }]
|
|
3479
5036
|
}] });
|
|
@@ -3500,10 +5057,10 @@ class NormalizeMatchParticipantsPipe {
|
|
|
3500
5057
|
constructor() {
|
|
3501
5058
|
this.transform = normalizeMatchParticipants;
|
|
3502
5059
|
}
|
|
3503
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
3504
|
-
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "
|
|
5060
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NormalizeMatchParticipantsPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
5061
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.0.5", ngImport: i0, type: NormalizeMatchParticipantsPipe, isStandalone: true, name: "etNormalizeMatchParticipants" }); }
|
|
3505
5062
|
}
|
|
3506
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
5063
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NormalizeMatchParticipantsPipe, decorators: [{
|
|
3507
5064
|
type: Pipe,
|
|
3508
5065
|
args: [{ name: 'etNormalizeMatchParticipants' }]
|
|
3509
5066
|
}] });
|
|
@@ -3557,10 +5114,10 @@ class NormalizeMatchScorePipe {
|
|
|
3557
5114
|
constructor() {
|
|
3558
5115
|
this.transform = normalizeMatchScore;
|
|
3559
5116
|
}
|
|
3560
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
3561
|
-
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "
|
|
5117
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NormalizeMatchScorePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
5118
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.0.5", ngImport: i0, type: NormalizeMatchScorePipe, isStandalone: true, name: "etNormalizeMatchScore" }); }
|
|
3562
5119
|
}
|
|
3563
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
5120
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NormalizeMatchScorePipe, decorators: [{
|
|
3564
5121
|
type: Pipe,
|
|
3565
5122
|
args: [{ name: 'etNormalizeMatchScore' }]
|
|
3566
5123
|
}] });
|
|
@@ -3693,10 +5250,10 @@ class NormalizeMatchTypePipe {
|
|
|
3693
5250
|
constructor() {
|
|
3694
5251
|
this.transform = normalizeMatchType;
|
|
3695
5252
|
}
|
|
3696
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
3697
|
-
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "
|
|
5253
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NormalizeMatchTypePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
5254
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.0.5", ngImport: i0, type: NormalizeMatchTypePipe, isStandalone: true, name: "etNormalizeMatchType" }); }
|
|
3698
5255
|
}
|
|
3699
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
5256
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NormalizeMatchTypePipe, decorators: [{
|
|
3700
5257
|
type: Pipe,
|
|
3701
5258
|
args: [{ name: 'etNormalizeMatchType' }]
|
|
3702
5259
|
}] });
|
|
@@ -3735,17 +5292,31 @@ const normalizeMatchType = (matchType) => {
|
|
|
3735
5292
|
i18n: 'match-type.pools',
|
|
3736
5293
|
text: 'Pools',
|
|
3737
5294
|
};
|
|
5295
|
+
default:
|
|
5296
|
+
return null;
|
|
3738
5297
|
}
|
|
3739
5298
|
};
|
|
3740
5299
|
|
|
5300
|
+
class HtmlToMarkdownPipe {
|
|
5301
|
+
constructor() {
|
|
5302
|
+
this.transform = htmlToMarkdown;
|
|
5303
|
+
}
|
|
5304
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: HtmlToMarkdownPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
5305
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.0.5", ngImport: i0, type: HtmlToMarkdownPipe, isStandalone: true, name: "htmlToMarkdown" }); }
|
|
5306
|
+
}
|
|
5307
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: HtmlToMarkdownPipe, decorators: [{
|
|
5308
|
+
type: Pipe,
|
|
5309
|
+
args: [{ name: 'htmlToMarkdown' }]
|
|
5310
|
+
}] });
|
|
5311
|
+
|
|
3741
5312
|
class InferMimeTypePipe {
|
|
3742
5313
|
constructor() {
|
|
3743
5314
|
this.transform = inferMimeType;
|
|
3744
5315
|
}
|
|
3745
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
3746
|
-
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "
|
|
5316
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: InferMimeTypePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
5317
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.0.5", ngImport: i0, type: InferMimeTypePipe, isStandalone: true, name: "inferMimeType" }); }
|
|
3747
5318
|
}
|
|
3748
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
5319
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: InferMimeTypePipe, decorators: [{
|
|
3749
5320
|
type: Pipe,
|
|
3750
5321
|
args: [{
|
|
3751
5322
|
name: 'inferMimeType',
|
|
@@ -3759,6 +5330,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
|
|
|
3759
5330
|
const inferMimeType = (srcset) => {
|
|
3760
5331
|
if (!srcset)
|
|
3761
5332
|
return null;
|
|
5333
|
+
if (srcset.startsWith('data:')) {
|
|
5334
|
+
const match = /^data:([^;,]+)/.exec(srcset);
|
|
5335
|
+
return match?.[1] ?? null;
|
|
5336
|
+
}
|
|
3762
5337
|
const urls = srcset.split(',');
|
|
3763
5338
|
const firstUrl = urls[0];
|
|
3764
5339
|
if (!firstUrl)
|
|
@@ -3947,14 +5522,26 @@ const inferMimeType = (srcset) => {
|
|
|
3947
5522
|
return null;
|
|
3948
5523
|
};
|
|
3949
5524
|
|
|
5525
|
+
class MarkdownToHtmlPipe {
|
|
5526
|
+
constructor() {
|
|
5527
|
+
this.transform = markdownToHtml;
|
|
5528
|
+
}
|
|
5529
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: MarkdownToHtmlPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
5530
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.0.5", ngImport: i0, type: MarkdownToHtmlPipe, isStandalone: true, name: "markdownToHtml" }); }
|
|
5531
|
+
}
|
|
5532
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: MarkdownToHtmlPipe, decorators: [{
|
|
5533
|
+
type: Pipe,
|
|
5534
|
+
args: [{ name: 'markdownToHtml' }]
|
|
5535
|
+
}] });
|
|
5536
|
+
|
|
3950
5537
|
class ToArrayPipe {
|
|
3951
5538
|
constructor() {
|
|
3952
5539
|
this.transform = toArray;
|
|
3953
5540
|
}
|
|
3954
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
3955
|
-
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "
|
|
5541
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ToArrayPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
5542
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.0.5", ngImport: i0, type: ToArrayPipe, isStandalone: true, name: "toArray" }); }
|
|
3956
5543
|
}
|
|
3957
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
5544
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ToArrayPipe, decorators: [{
|
|
3958
5545
|
type: Pipe,
|
|
3959
5546
|
args: [{ name: 'toArray' }]
|
|
3960
5547
|
}] });
|
|
@@ -3986,14 +5573,19 @@ const createElementDictionary = () => {
|
|
|
3986
5573
|
const firstElement = computed(() => {
|
|
3987
5574
|
const id = dictionary.ids()[0];
|
|
3988
5575
|
return id ? (dictionary.elements()[id] ?? null) : null;
|
|
3989
|
-
},
|
|
5576
|
+
}, /* @ts-ignore */
|
|
5577
|
+
...(ngDevMode ? [{ debugName: "firstElement" }] : /* istanbul ignore next */ []));
|
|
3990
5578
|
const firstId = computed(() => {
|
|
3991
5579
|
const id = dictionary.ids()[0];
|
|
3992
5580
|
return id ?? null;
|
|
3993
|
-
},
|
|
3994
|
-
|
|
3995
|
-
const
|
|
3996
|
-
|
|
5581
|
+
}, /* @ts-ignore */
|
|
5582
|
+
...(ngDevMode ? [{ debugName: "firstId" }] : /* istanbul ignore next */ []));
|
|
5583
|
+
const ids = computed(() => dictionary.ids(), /* @ts-ignore */
|
|
5584
|
+
...(ngDevMode ? [{ debugName: "ids" }] : /* istanbul ignore next */ []));
|
|
5585
|
+
const elements = computed(() => ids().map((id) => dictionary.elements()[id]), /* @ts-ignore */
|
|
5586
|
+
...(ngDevMode ? [{ debugName: "elements" }] : /* istanbul ignore next */ []));
|
|
5587
|
+
const isEmpty = computed(() => dictionary.ids().length === 0, /* @ts-ignore */
|
|
5588
|
+
...(ngDevMode ? [{ debugName: "isEmpty" }] : /* istanbul ignore next */ []));
|
|
3997
5589
|
const has = (id) => {
|
|
3998
5590
|
return dictionary.ids().includes(id);
|
|
3999
5591
|
};
|
|
@@ -4077,7 +5669,8 @@ const unbindProps = (config) => {
|
|
|
4077
5669
|
const createProps = (props) => {
|
|
4078
5670
|
const { bindId = false, single = true, classes: classBindings, attributes: attributeBindings, styles: styleBindings, staticAttributes: staticAttributeBindings = null, staticClasses: staticClassBindings = null, staticStyles: staticStyleBindings = null, listeners, name, } = props;
|
|
4079
5671
|
const dictionary = createElementDictionary();
|
|
4080
|
-
const attached = computed(() => !dictionary.isEmpty(),
|
|
5672
|
+
const attached = computed(() => !dictionary.isEmpty(), /* @ts-ignore */
|
|
5673
|
+
...(ngDevMode ? [{ debugName: "attached" }] : /* istanbul ignore next */ []));
|
|
4081
5674
|
const attachedElements = {
|
|
4082
5675
|
first: dictionary.firstElement,
|
|
4083
5676
|
firstId: dictionary.firstId,
|
|
@@ -4163,7 +5756,7 @@ const createDependencyStash = (stash) => {
|
|
|
4163
5756
|
class PropsDirective {
|
|
4164
5757
|
constructor() {
|
|
4165
5758
|
this.destroyRef = inject(DestroyRef);
|
|
4166
|
-
this.props = input.required({ ...(ngDevMode ? { debugName: "props" } : {}), alias: 'etProps', transform: (d) => d });
|
|
5759
|
+
this.props = input.required({ ...(ngDevMode ? { debugName: "props" } : /* istanbul ignore next */ {}), alias: 'etProps', transform: (d) => d });
|
|
4167
5760
|
this.propHandlers = createPropHandlers();
|
|
4168
5761
|
afterNextRender({
|
|
4169
5762
|
write: () => {
|
|
@@ -4180,10 +5773,10 @@ class PropsDirective {
|
|
|
4180
5773
|
});
|
|
4181
5774
|
});
|
|
4182
5775
|
}
|
|
4183
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
4184
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "
|
|
5776
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: PropsDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
5777
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.5", type: PropsDirective, isStandalone: true, selector: "[etProps]", inputs: { props: { classPropertyName: "props", publicName: "etProps", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 }); }
|
|
4185
5778
|
}
|
|
4186
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
5779
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: PropsDirective, decorators: [{
|
|
4187
5780
|
type: Directive,
|
|
4188
5781
|
args: [{
|
|
4189
5782
|
selector: '[etProps]',
|
|
@@ -4230,6 +5823,77 @@ const templateComputed = (templateSignal) => computed(() => {
|
|
|
4230
5823
|
};
|
|
4231
5824
|
});
|
|
4232
5825
|
|
|
5826
|
+
const EDGE_CURSORS = {
|
|
5827
|
+
n: 'ns-resize',
|
|
5828
|
+
s: 'ns-resize',
|
|
5829
|
+
e: 'ew-resize',
|
|
5830
|
+
w: 'ew-resize',
|
|
5831
|
+
ne: 'nesw-resize',
|
|
5832
|
+
sw: 'nesw-resize',
|
|
5833
|
+
nw: 'nwse-resize',
|
|
5834
|
+
se: 'nwse-resize',
|
|
5835
|
+
};
|
|
5836
|
+
const setupResizeObservable = (startEvent, edge) => {
|
|
5837
|
+
const pointerId = startEvent.pointerId;
|
|
5838
|
+
const startX = startEvent.clientX;
|
|
5839
|
+
const startY = startEvent.clientY;
|
|
5840
|
+
const end$ = merge(fromEvent(document, 'pointerup'), fromEvent(document, 'pointercancel')).pipe(filter((e) => e.pointerId === pointerId), take(1));
|
|
5841
|
+
return concat(of({ type: 'start', edge }), fromEvent(document, 'pointermove').pipe(filter((e) => e.pointerId === pointerId), map((e) => ({ type: 'move', data: { edge, dx: e.clientX - startX, dy: e.clientY - startY } })), takeUntil(end$)), of({ type: 'end' }));
|
|
5842
|
+
};
|
|
5843
|
+
class ResizeHandlesComponent {
|
|
5844
|
+
constructor() {
|
|
5845
|
+
this.edges = input(['n', 's', 'e', 'w', 'ne', 'nw', 'se', 'sw'], /* @ts-ignore */
|
|
5846
|
+
...(ngDevMode ? [{ debugName: "edges" }] : /* istanbul ignore next */ []));
|
|
5847
|
+
this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
5848
|
+
this.gestureStart$ = new Subject();
|
|
5849
|
+
this.gesture$ = this.gestureStart$.pipe(exhaustMap(({ event, edge }) => setupResizeObservable(event, edge)), takeUntilDestroyed(), share());
|
|
5850
|
+
this.resizeStarted = outputFromObservable(this.gesture$.pipe(filter((e) => e.type === 'start'), map((e) => e.edge)));
|
|
5851
|
+
this.resizeMoved = outputFromObservable(this.gesture$.pipe(filter((e) => e.type === 'move'), map((e) => e.data)));
|
|
5852
|
+
this.resizeEnded = outputFromObservable(this.gesture$.pipe(filter((e) => e.type === 'end'), map(() => undefined)));
|
|
5853
|
+
this.isResizing = toSignal(this.gesture$.pipe(map((e) => e.type !== 'end'), distinctUntilChanged()), { initialValue: false });
|
|
5854
|
+
this.activeEdge = toSignal(this.gesture$.pipe(map((e) => {
|
|
5855
|
+
if (e.type === 'end')
|
|
5856
|
+
return null;
|
|
5857
|
+
if (e.type === 'start')
|
|
5858
|
+
return e.edge;
|
|
5859
|
+
return e.data.edge;
|
|
5860
|
+
}), distinctUntilChanged()), { initialValue: null });
|
|
5861
|
+
this.edgeCursors = EDGE_CURSORS;
|
|
5862
|
+
}
|
|
5863
|
+
startResizeGesture(event, edge) {
|
|
5864
|
+
if (event.button !== 0 || this.disabled())
|
|
5865
|
+
return;
|
|
5866
|
+
event.stopPropagation();
|
|
5867
|
+
this.gestureStart$.next({ event, edge });
|
|
5868
|
+
}
|
|
5869
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ResizeHandlesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5870
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", 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" }, host: { properties: { "attr.inert": "disabled() ? \"\" : null", "attr.data-active-edge": "activeEdge()" }, classAttribute: "et-resize-handles" }, ngImport: i0, template: `
|
|
5871
|
+
@for (edge of edges(); track edge) {
|
|
5872
|
+
<div
|
|
5873
|
+
[style.cursor]="edgeCursors[edge]"
|
|
5874
|
+
(pointerdown)="startResizeGesture($event, edge)"
|
|
5875
|
+
class="et-resize-handle et-resize-handle--{{ edge }}"
|
|
5876
|
+
></div>
|
|
5877
|
+
}
|
|
5878
|
+
`, isInline: true, styles: ["@property --et-resize-handles-z-index{syntax: \"<integer>\"; inherits: true; initial-value: 10;}@property --et-resize-handles-edge-size{syntax: \"<length>\"; inherits: true; initial-value: 6px;}@property --et-resize-handles-corner-size{syntax: \"<length>\"; inherits: true; initial-value: 12px;}@property --et-resize-handles-edge-inset{syntax: \"<length>\"; inherits: true; initial-value: 8px;}@property --et-resize-handles-side-top{syntax: \"<length>\"; inherits: true; initial-value: 0px;}@property --et-resize-handles-side-bottom{syntax: \"<length>\"; inherits: true; initial-value: 8px;}@property --et-resize-handles-touch-edge-size{syntax: \"<length>\"; inherits: true; initial-value: 20px;}@property --et-resize-handles-touch-corner-size{syntax: \"<length>\"; inherits: true; initial-value: 28px;}et-resize-handles{position:absolute;inset:0;pointer-events:none}.et-resize-handle{position:absolute;z-index:var(--et-resize-handles-z-index);touch-action:none;pointer-events:auto}.et-resize-handle--n{left:var(--et-resize-handles-edge-inset);right:var(--et-resize-handles-edge-inset);height:var(--et-resize-handles-edge-size);top:0}.et-resize-handle--s{left:var(--et-resize-handles-edge-inset);right:var(--et-resize-handles-edge-inset);height:var(--et-resize-handles-edge-size);bottom:0}.et-resize-handle--e,.et-resize-handle--w{top:var(--et-resize-handles-side-top);bottom:var(--et-resize-handles-side-bottom);width:var(--et-resize-handles-edge-size)}.et-resize-handle--e{right:0}.et-resize-handle--w{left:0}.et-resize-handle--ne,.et-resize-handle--nw{top:0;width:var(--et-resize-handles-corner-size);height:var(--et-resize-handles-corner-size)}.et-resize-handle--ne{right:0}.et-resize-handle--nw{left:0}.et-resize-handle--se,.et-resize-handle--sw{bottom:0;width:var(--et-resize-handles-corner-size);height:var(--et-resize-handles-corner-size)}.et-resize-handle--se{right:0}.et-resize-handle--sw{left:0}@media(hover:none){.et-resize-handle--n,.et-resize-handle--s{height:var(--et-resize-handles-touch-edge-size)}.et-resize-handle--e,.et-resize-handle--w{width:var(--et-resize-handles-touch-edge-size)}.et-resize-handle--ne,.et-resize-handle--nw,.et-resize-handle--se,.et-resize-handle--sw{width:var(--et-resize-handles-touch-corner-size);height:var(--et-resize-handles-touch-corner-size)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
5879
|
+
}
|
|
5880
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ResizeHandlesComponent, decorators: [{
|
|
5881
|
+
type: Component,
|
|
5882
|
+
args: [{ selector: 'et-resize-handles', template: `
|
|
5883
|
+
@for (edge of edges(); track edge) {
|
|
5884
|
+
<div
|
|
5885
|
+
[style.cursor]="edgeCursors[edge]"
|
|
5886
|
+
(pointerdown)="startResizeGesture($event, edge)"
|
|
5887
|
+
class="et-resize-handle et-resize-handle--{{ edge }}"
|
|
5888
|
+
></div>
|
|
5889
|
+
}
|
|
5890
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
|
|
5891
|
+
class: 'et-resize-handles',
|
|
5892
|
+
'[attr.inert]': 'disabled() ? "" : null',
|
|
5893
|
+
'[attr.data-active-edge]': 'activeEdge()',
|
|
5894
|
+
}, styles: ["@property --et-resize-handles-z-index{syntax: \"<integer>\"; inherits: true; initial-value: 10;}@property --et-resize-handles-edge-size{syntax: \"<length>\"; inherits: true; initial-value: 6px;}@property --et-resize-handles-corner-size{syntax: \"<length>\"; inherits: true; initial-value: 12px;}@property --et-resize-handles-edge-inset{syntax: \"<length>\"; inherits: true; initial-value: 8px;}@property --et-resize-handles-side-top{syntax: \"<length>\"; inherits: true; initial-value: 0px;}@property --et-resize-handles-side-bottom{syntax: \"<length>\"; inherits: true; initial-value: 8px;}@property --et-resize-handles-touch-edge-size{syntax: \"<length>\"; inherits: true; initial-value: 20px;}@property --et-resize-handles-touch-corner-size{syntax: \"<length>\"; inherits: true; initial-value: 28px;}et-resize-handles{position:absolute;inset:0;pointer-events:none}.et-resize-handle{position:absolute;z-index:var(--et-resize-handles-z-index);touch-action:none;pointer-events:auto}.et-resize-handle--n{left:var(--et-resize-handles-edge-inset);right:var(--et-resize-handles-edge-inset);height:var(--et-resize-handles-edge-size);top:0}.et-resize-handle--s{left:var(--et-resize-handles-edge-inset);right:var(--et-resize-handles-edge-inset);height:var(--et-resize-handles-edge-size);bottom:0}.et-resize-handle--e,.et-resize-handle--w{top:var(--et-resize-handles-side-top);bottom:var(--et-resize-handles-side-bottom);width:var(--et-resize-handles-edge-size)}.et-resize-handle--e{right:0}.et-resize-handle--w{left:0}.et-resize-handle--ne,.et-resize-handle--nw{top:0;width:var(--et-resize-handles-corner-size);height:var(--et-resize-handles-corner-size)}.et-resize-handle--ne{right:0}.et-resize-handle--nw{left:0}.et-resize-handle--se,.et-resize-handle--sw{bottom:0;width:var(--et-resize-handles-corner-size);height:var(--et-resize-handles-corner-size)}.et-resize-handle--se{right:0}.et-resize-handle--sw{left:0}@media(hover:none){.et-resize-handle--n,.et-resize-handle--s{height:var(--et-resize-handles-touch-edge-size)}.et-resize-handle--e,.et-resize-handle--w{width:var(--et-resize-handles-touch-edge-size)}.et-resize-handle--ne,.et-resize-handle--nw,.et-resize-handle--se,.et-resize-handle--sw{width:var(--et-resize-handles-touch-corner-size);height:var(--et-resize-handles-touch-corner-size)}}\n"] }]
|
|
5895
|
+
}], propDecorators: { edges: [{ type: i0.Input, args: [{ isSignal: true, alias: "edges", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], resizeStarted: [{ type: i0.Output, args: ["resizeStarted"] }], resizeMoved: [{ type: i0.Output, args: ["resizeMoved"] }], resizeEnded: [{ type: i0.Output, args: ["resizeEnded"] }] } });
|
|
5896
|
+
|
|
4233
5897
|
const applyHeadBinding = (binding, applyFn, removeFn, isValid) => {
|
|
4234
5898
|
const destroyRef = inject(DestroyRef);
|
|
4235
5899
|
const signalBinding = isSignal(binding) ? binding : signal(binding);
|
|
@@ -4263,7 +5927,8 @@ const createPropertyBinding = (configBuilder, applyConfigFn) => {
|
|
|
4263
5927
|
const createArrayPropertyBinding = (configBuilder, applyConfigFn) => {
|
|
4264
5928
|
return (binding) => {
|
|
4265
5929
|
const valuesSignal = isSignal(binding) ? binding : signal(binding);
|
|
4266
|
-
const valuesList = computed(() => untracked(() => valuesSignal()) ?? [],
|
|
5930
|
+
const valuesList = computed(() => untracked(() => valuesSignal()) ?? [], /* @ts-ignore */
|
|
5931
|
+
...(ngDevMode ? [{ debugName: "valuesList" }] : /* istanbul ignore next */ []));
|
|
4267
5932
|
valuesList().forEach((value, index) => {
|
|
4268
5933
|
applyConfigFn(computed(() => configBuilder(value, index)));
|
|
4269
5934
|
});
|
|
@@ -4308,7 +5973,8 @@ const [provideLinkStoreConfig, injectLinkStoreConfig] = createStaticRootProvider
|
|
|
4308
5973
|
const [provideLinkStore, injectLinkStore] = createRootProvider(() => {
|
|
4309
5974
|
const document = inject(DOCUMENT$1);
|
|
4310
5975
|
const config = injectLinkStoreConfig();
|
|
4311
|
-
const linksByKey = signal(new Map(),
|
|
5976
|
+
const linksByKey = signal(new Map(), /* @ts-ignore */
|
|
5977
|
+
...(ngDevMode ? [{ debugName: "linksByKey" }] : /* istanbul ignore next */ []));
|
|
4312
5978
|
let priorityCounter = 0;
|
|
4313
5979
|
const getLinkKey = (linkConfig) => {
|
|
4314
5980
|
const isMultiInstance = config.multiInstanceRels.has(linkConfig.rel) || linkConfig.allowMultiple;
|
|
@@ -4470,7 +6136,8 @@ const [provideTitleConfig, injectTitleConfig] = createStaticRootProvider({
|
|
|
4470
6136
|
}, { name: 'Title Config' });
|
|
4471
6137
|
const [provideTitleStore, injectTitleStore] = createRootProvider(() => {
|
|
4472
6138
|
const config = injectTitleConfig();
|
|
4473
|
-
const titleParts = signal(new Map(),
|
|
6139
|
+
const titleParts = signal(new Map(), /* @ts-ignore */
|
|
6140
|
+
...(ngDevMode ? [{ debugName: "titleParts" }] : /* istanbul ignore next */ []));
|
|
4474
6141
|
const { currentLocale } = injectLocale();
|
|
4475
6142
|
const titleService = inject(Title);
|
|
4476
6143
|
const isRouterInitialized = injectIsRouterInitialized();
|
|
@@ -4498,7 +6165,8 @@ const [provideTitleStore, injectTitleStore] = createRootProvider(() => {
|
|
|
4498
6165
|
finalTextParts.push(config.transformer(config.suffixPart.text, currentLocale()));
|
|
4499
6166
|
}
|
|
4500
6167
|
return finalTextParts.join(` ${config.divider} `);
|
|
4501
|
-
},
|
|
6168
|
+
}, /* @ts-ignore */
|
|
6169
|
+
...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
|
|
4502
6170
|
const addPart = (id, part) => {
|
|
4503
6171
|
titleParts.update((parts) => new Map(parts).set(id, part));
|
|
4504
6172
|
};
|
|
@@ -4598,7 +6266,8 @@ const [provideMetaStore, injectMetaStore] = createRootProvider(() => {
|
|
|
4598
6266
|
const metaService = inject(Meta);
|
|
4599
6267
|
const config = injectMetaConfig();
|
|
4600
6268
|
const { currentLocale } = injectLocale();
|
|
4601
|
-
const metaTagsBySelector = signal(new Map(),
|
|
6269
|
+
const metaTagsBySelector = signal(new Map(), /* @ts-ignore */
|
|
6270
|
+
...(ngDevMode ? [{ debugName: "metaTagsBySelector" }] : /* istanbul ignore next */ []));
|
|
4602
6271
|
let priorityCounter = 0;
|
|
4603
6272
|
const getSelector = (config) => {
|
|
4604
6273
|
if (config.name)
|
|
@@ -5025,10 +6694,10 @@ class SeoDirective {
|
|
|
5025
6694
|
}
|
|
5026
6695
|
}
|
|
5027
6696
|
}
|
|
5028
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
5029
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "
|
|
6697
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: SeoDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
6698
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.5", type: SeoDirective, isStandalone: true, providers: [{ provide: SEO_DIRECTIVE_TOKEN, useExisting: SeoDirective }], ngImport: i0 }); }
|
|
5030
6699
|
}
|
|
5031
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
6700
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: SeoDirective, decorators: [{
|
|
5032
6701
|
type: Directive,
|
|
5033
6702
|
args: [{
|
|
5034
6703
|
providers: [{ provide: SEO_DIRECTIVE_TOKEN, useExisting: SeoDirective }],
|
|
@@ -5042,7 +6711,8 @@ const [provideStructuredDataStore, injectStructuredDataStore] = createRootProvid
|
|
|
5042
6711
|
const document = inject(DOCUMENT$1);
|
|
5043
6712
|
const renderer = injectRenderer();
|
|
5044
6713
|
const config = injectStructuredDataConfig();
|
|
5045
|
-
const scripts = signal(new Map(),
|
|
6714
|
+
const scripts = signal(new Map(), /* @ts-ignore */
|
|
6715
|
+
...(ngDevMode ? [{ debugName: "scripts" }] : /* istanbul ignore next */ []));
|
|
5046
6716
|
const getTargetElement = () => {
|
|
5047
6717
|
return config.placement === 'head' ? document.head : document.body;
|
|
5048
6718
|
};
|
|
@@ -5083,7 +6753,8 @@ const applyStructuredDataBinding = (binding) => {
|
|
|
5083
6753
|
class StructuredDataComponent {
|
|
5084
6754
|
constructor() {
|
|
5085
6755
|
this.sanitizer = inject(DomSanitizer);
|
|
5086
|
-
this.data = input(null,
|
|
6756
|
+
this.data = input(null, /* @ts-ignore */
|
|
6757
|
+
...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
|
|
5087
6758
|
this.jsonLD = computed(() => {
|
|
5088
6759
|
const data = this.data();
|
|
5089
6760
|
if (!data) {
|
|
@@ -5092,12 +6763,13 @@ class StructuredDataComponent {
|
|
|
5092
6763
|
const json = data ? JSON.stringify(data, null, 2).replace(/<\/script>/g, '<\\/script>') : '';
|
|
5093
6764
|
const html = `<script type="application/ld+json">${json}</script>`;
|
|
5094
6765
|
return this.sanitizer.bypassSecurityTrustHtml(html);
|
|
5095
|
-
},
|
|
6766
|
+
}, /* @ts-ignore */
|
|
6767
|
+
...(ngDevMode ? [{ debugName: "jsonLD" }] : /* istanbul ignore next */ []));
|
|
5096
6768
|
}
|
|
5097
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
5098
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "
|
|
6769
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: StructuredDataComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6770
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.5", type: StructuredDataComponent, isStandalone: true, selector: "et-structured-data", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "innerHTML": "jsonLD()" }, styleAttribute: "display: none" }, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
5099
6771
|
}
|
|
5100
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
6772
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: StructuredDataComponent, decorators: [{
|
|
5101
6773
|
type: Component,
|
|
5102
6774
|
args: [{
|
|
5103
6775
|
selector: 'et-structured-data',
|
|
@@ -5111,15 +6783,165 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
|
|
|
5111
6783
|
}]
|
|
5112
6784
|
}], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }] } });
|
|
5113
6785
|
|
|
5114
|
-
|
|
6786
|
+
class ColorInteractiveStylesComponent {
|
|
6787
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ColorInteractiveStylesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6788
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.5", type: ColorInteractiveStylesComponent, isStandalone: true, selector: "et-color-interactive-styles", ngImport: i0, template: '', isInline: true, styles: [":where(.et-color-interactive){--et-theme-color-primary-rgb: var(--et-color-primary);--et-theme-color-primary-solid: rgb(var(--et-theme-color-primary-rgb));--et-theme-color-on-primary-rgb: var(--et-color-on-primary);--et-theme-color-on-primary-solid: rgb(var(--et-theme-color-on-primary-rgb));--et-theme-color-ink-rgb: var(--et-color-primary-ink, var(--et-color-primary));--et-theme-color-ink-solid: rgb(var(--et-theme-color-ink-rgb))}:where(.et-color-interactive:hover:not(:has(.et-color-interactive-exclude:hover))),:where(.et-color-interactive-container:hover) :where(.et-color-interactive){--et-theme-color-primary-rgb: var(--et-color-primary-hover, var(--et-color-primary));--et-theme-color-primary-solid: rgb(var(--et-theme-color-primary-rgb));--et-theme-color-on-primary-rgb: var(--et-color-on-primary-hover, var(--et-color-on-primary));--et-theme-color-on-primary-solid: rgb(var(--et-theme-color-on-primary-rgb));--et-theme-color-ink-rgb: var( --et-color-primary-ink-hover, var(--et-color-primary-ink, var(--et-color-primary-hover, var(--et-color-primary))) );--et-theme-color-ink-solid: rgb(var(--et-theme-color-ink-rgb))}:where(.et-color-interactive:focus-visible){--et-theme-color-primary-rgb: var(--et-color-primary-focus, var(--et-color-primary-hover, var(--et-color-primary)));--et-theme-color-primary-solid: rgb(var(--et-theme-color-primary-rgb));--et-theme-color-on-primary-rgb: var( --et-color-on-primary-focus, var(--et-color-on-primary-hover, var(--et-color-on-primary)) );--et-theme-color-on-primary-solid: rgb(var(--et-theme-color-on-primary-rgb));--et-theme-color-ink-rgb: var( --et-color-primary-ink-focus, var( --et-color-primary-ink-hover, var(--et-color-primary-ink, var(--et-color-primary-focus, var(--et-color-primary-hover, var(--et-color-primary)))) ) );--et-theme-color-ink-solid: rgb(var(--et-theme-color-ink-rgb))}:where(.et-color-interactive:active:not(:has(.et-color-interactive-exclude:hover))),:where(.et-color-interactive-container:active) :where(.et-color-interactive){--et-theme-color-primary-rgb: var( --et-color-primary-active, var(--et-color-primary-focus, var(--et-color-primary-hover, var(--et-color-primary))) );--et-theme-color-primary-solid: rgb(var(--et-theme-color-primary-rgb));--et-theme-color-on-primary-rgb: var( --et-color-on-primary-active, var(--et-color-on-primary-focus, var(--et-color-on-primary-hover, var(--et-color-on-primary))) );--et-theme-color-on-primary-solid: rgb(var(--et-theme-color-on-primary-rgb));--et-theme-color-ink-rgb: var( --et-color-primary-ink-active, var( --et-color-primary-ink-focus, var( --et-color-primary-ink-hover, var( --et-color-primary-ink, var( --et-color-primary-active, var(--et-color-primary-focus, var(--et-color-primary-hover, var(--et-color-primary))) ) ) ) ) );--et-theme-color-ink-solid: rgb(var(--et-theme-color-ink-rgb))}:where(.et-color-interactive--has-focus:has(:focus-visible)){--et-theme-color-primary-rgb: var(--et-color-primary-focus, var(--et-color-primary-hover, var(--et-color-primary)));--et-theme-color-primary-solid: rgb(var(--et-theme-color-primary-rgb));--et-theme-color-on-primary-rgb: var( --et-color-on-primary-focus, var(--et-color-on-primary-hover, var(--et-color-on-primary)) );--et-theme-color-on-primary-solid: rgb(var(--et-theme-color-on-primary-rgb));--et-theme-color-ink-rgb: var( --et-color-primary-ink-focus, var( --et-color-primary-ink-hover, var(--et-color-primary-ink, var(--et-color-primary-focus, var(--et-color-primary-hover, var(--et-color-primary)))) ) );--et-theme-color-ink-solid: rgb(var(--et-theme-color-ink-rgb))}:where(.et-color-interactive[disabled]),:where(.et-color-interactive[aria-disabled=true]){--et-theme-color-primary-rgb: var( --et-color-primary-disabled, var( --et-color-primary-active, var(--et-color-primary-focus, var(--et-color-primary-hover, var(--et-color-primary))) ) );--et-theme-color-primary-solid: rgb(var(--et-theme-color-primary-rgb));--et-theme-color-on-primary-rgb: var( --et-color-on-primary-disabled, var( --et-color-on-primary-active, var(--et-color-on-primary-focus, var(--et-color-on-primary-hover, var(--et-color-on-primary))) ) );--et-theme-color-on-primary-solid: rgb(var(--et-theme-color-on-primary-rgb));--et-theme-color-ink-rgb: var( --et-color-primary-ink-disabled, var( --et-color-primary-ink-active, var( --et-color-primary-ink-focus, var( --et-color-primary-ink-hover, var( --et-color-primary-ink, var( --et-color-primary-disabled, var( --et-color-primary-active, var(--et-color-primary-focus, var(--et-color-primary-hover, var(--et-color-primary))) ) ) ) ) ) ) );--et-theme-color-ink-solid: rgb(var(--et-theme-color-ink-rgb))}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
6789
|
+
}
|
|
6790
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ColorInteractiveStylesComponent, decorators: [{
|
|
6791
|
+
type: Component,
|
|
6792
|
+
args: [{ selector: 'et-color-interactive-styles', template: '', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":where(.et-color-interactive){--et-theme-color-primary-rgb: var(--et-color-primary);--et-theme-color-primary-solid: rgb(var(--et-theme-color-primary-rgb));--et-theme-color-on-primary-rgb: var(--et-color-on-primary);--et-theme-color-on-primary-solid: rgb(var(--et-theme-color-on-primary-rgb));--et-theme-color-ink-rgb: var(--et-color-primary-ink, var(--et-color-primary));--et-theme-color-ink-solid: rgb(var(--et-theme-color-ink-rgb))}:where(.et-color-interactive:hover:not(:has(.et-color-interactive-exclude:hover))),:where(.et-color-interactive-container:hover) :where(.et-color-interactive){--et-theme-color-primary-rgb: var(--et-color-primary-hover, var(--et-color-primary));--et-theme-color-primary-solid: rgb(var(--et-theme-color-primary-rgb));--et-theme-color-on-primary-rgb: var(--et-color-on-primary-hover, var(--et-color-on-primary));--et-theme-color-on-primary-solid: rgb(var(--et-theme-color-on-primary-rgb));--et-theme-color-ink-rgb: var( --et-color-primary-ink-hover, var(--et-color-primary-ink, var(--et-color-primary-hover, var(--et-color-primary))) );--et-theme-color-ink-solid: rgb(var(--et-theme-color-ink-rgb))}:where(.et-color-interactive:focus-visible){--et-theme-color-primary-rgb: var(--et-color-primary-focus, var(--et-color-primary-hover, var(--et-color-primary)));--et-theme-color-primary-solid: rgb(var(--et-theme-color-primary-rgb));--et-theme-color-on-primary-rgb: var( --et-color-on-primary-focus, var(--et-color-on-primary-hover, var(--et-color-on-primary)) );--et-theme-color-on-primary-solid: rgb(var(--et-theme-color-on-primary-rgb));--et-theme-color-ink-rgb: var( --et-color-primary-ink-focus, var( --et-color-primary-ink-hover, var(--et-color-primary-ink, var(--et-color-primary-focus, var(--et-color-primary-hover, var(--et-color-primary)))) ) );--et-theme-color-ink-solid: rgb(var(--et-theme-color-ink-rgb))}:where(.et-color-interactive:active:not(:has(.et-color-interactive-exclude:hover))),:where(.et-color-interactive-container:active) :where(.et-color-interactive){--et-theme-color-primary-rgb: var( --et-color-primary-active, var(--et-color-primary-focus, var(--et-color-primary-hover, var(--et-color-primary))) );--et-theme-color-primary-solid: rgb(var(--et-theme-color-primary-rgb));--et-theme-color-on-primary-rgb: var( --et-color-on-primary-active, var(--et-color-on-primary-focus, var(--et-color-on-primary-hover, var(--et-color-on-primary))) );--et-theme-color-on-primary-solid: rgb(var(--et-theme-color-on-primary-rgb));--et-theme-color-ink-rgb: var( --et-color-primary-ink-active, var( --et-color-primary-ink-focus, var( --et-color-primary-ink-hover, var( --et-color-primary-ink, var( --et-color-primary-active, var(--et-color-primary-focus, var(--et-color-primary-hover, var(--et-color-primary))) ) ) ) ) );--et-theme-color-ink-solid: rgb(var(--et-theme-color-ink-rgb))}:where(.et-color-interactive--has-focus:has(:focus-visible)){--et-theme-color-primary-rgb: var(--et-color-primary-focus, var(--et-color-primary-hover, var(--et-color-primary)));--et-theme-color-primary-solid: rgb(var(--et-theme-color-primary-rgb));--et-theme-color-on-primary-rgb: var( --et-color-on-primary-focus, var(--et-color-on-primary-hover, var(--et-color-on-primary)) );--et-theme-color-on-primary-solid: rgb(var(--et-theme-color-on-primary-rgb));--et-theme-color-ink-rgb: var( --et-color-primary-ink-focus, var( --et-color-primary-ink-hover, var(--et-color-primary-ink, var(--et-color-primary-focus, var(--et-color-primary-hover, var(--et-color-primary)))) ) );--et-theme-color-ink-solid: rgb(var(--et-theme-color-ink-rgb))}:where(.et-color-interactive[disabled]),:where(.et-color-interactive[aria-disabled=true]){--et-theme-color-primary-rgb: var( --et-color-primary-disabled, var( --et-color-primary-active, var(--et-color-primary-focus, var(--et-color-primary-hover, var(--et-color-primary))) ) );--et-theme-color-primary-solid: rgb(var(--et-theme-color-primary-rgb));--et-theme-color-on-primary-rgb: var( --et-color-on-primary-disabled, var( --et-color-on-primary-active, var(--et-color-on-primary-focus, var(--et-color-on-primary-hover, var(--et-color-on-primary))) ) );--et-theme-color-on-primary-solid: rgb(var(--et-theme-color-on-primary-rgb));--et-theme-color-ink-rgb: var( --et-color-primary-ink-disabled, var( --et-color-primary-ink-active, var( --et-color-primary-ink-focus, var( --et-color-primary-ink-hover, var( --et-color-primary-ink, var( --et-color-primary-disabled, var( --et-color-primary-active, var(--et-color-primary-focus, var(--et-color-primary-hover, var(--et-color-primary))) ) ) ) ) ) ) );--et-theme-color-ink-solid: rgb(var(--et-theme-color-ink-rgb))}\n"] }]
|
|
6793
|
+
}] });
|
|
6794
|
+
|
|
6795
|
+
/**
|
|
6796
|
+
* Cascades hover/active-driven color DOWN to descendants explicitly marked with
|
|
6797
|
+
* `ColorInteractiveDirective` — this element does not color itself. Use it when a wrapper should
|
|
6798
|
+
* expand a nested control's hit/visual area (e.g. clicking a checkbox's label should light up the
|
|
6799
|
+
* checkbox itself), never to give a wrapper its own interactive coloring — that's
|
|
6800
|
+
* `ColorInteractiveDirective`.
|
|
6801
|
+
*
|
|
6802
|
+
* Does nothing unless at least one descendant carries `ColorInteractiveDirective` — check for
|
|
6803
|
+
* that before adding this. It was mistakenly added to a component with no such descendant once
|
|
6804
|
+
* already, where it did nothing but was confusing to read.
|
|
6805
|
+
*/
|
|
6806
|
+
class ColorInteractiveContainerDirective {
|
|
6807
|
+
constructor() {
|
|
6808
|
+
this.styleManager = injectStyleManager();
|
|
6809
|
+
this.styleManager.mount(ColorInteractiveStylesComponent);
|
|
6810
|
+
}
|
|
6811
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ColorInteractiveContainerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
6812
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.5", type: ColorInteractiveContainerDirective, isStandalone: true, selector: "[etColorInteractiveContainer]", host: { classAttribute: "et-color-interactive-container" }, ngImport: i0 }); }
|
|
6813
|
+
}
|
|
6814
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ColorInteractiveContainerDirective, decorators: [{
|
|
6815
|
+
type: Directive,
|
|
6816
|
+
args: [{
|
|
6817
|
+
selector: '[etColorInteractiveContainer]',
|
|
6818
|
+
host: {
|
|
6819
|
+
class: 'et-color-interactive-container',
|
|
6820
|
+
},
|
|
6821
|
+
}]
|
|
6822
|
+
}], ctorParameters: () => [] });
|
|
6823
|
+
|
|
6824
|
+
/**
|
|
6825
|
+
* Marks a descendant as NOT counting toward an ancestor's `ColorInteractiveDirective`
|
|
6826
|
+
* `:hover`/`:active` reaction (via the `:has()` guard in color-interactive-styles.component.css).
|
|
6827
|
+
* Use it for content that's incidentally inside an interactive ancestor but isn't part of what
|
|
6828
|
+
* makes that ancestor interactive — e.g. a hint/error block sitting inside a form field's frame.
|
|
6829
|
+
*
|
|
6830
|
+
* This only suppresses the ancestor's OWN reaction to hovering/pressing the excluded element — it
|
|
6831
|
+
* has no effect on custom-property inheritance into descendants past the excluded element. If
|
|
6832
|
+
* what you actually need is "stop my own cosmetic styling from reacting to a parent's unrelated
|
|
6833
|
+
* interaction," this is the wrong tool; that's the class of bug `ColorInteractiveHasFocusDirective`
|
|
6834
|
+
* used to have (see its own comment).
|
|
6835
|
+
*/
|
|
6836
|
+
class ColorInteractiveExcludeDirective {
|
|
6837
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ColorInteractiveExcludeDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
6838
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.5", type: ColorInteractiveExcludeDirective, isStandalone: true, selector: "[etColorInteractiveExclude]", host: { classAttribute: "et-color-interactive-exclude" }, ngImport: i0 }); }
|
|
6839
|
+
}
|
|
6840
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ColorInteractiveExcludeDirective, decorators: [{
|
|
6841
|
+
type: Directive,
|
|
6842
|
+
args: [{
|
|
6843
|
+
selector: '[etColorInteractiveExclude]',
|
|
6844
|
+
host: {
|
|
6845
|
+
class: 'et-color-interactive-exclude',
|
|
6846
|
+
},
|
|
6847
|
+
}]
|
|
6848
|
+
}] });
|
|
6849
|
+
|
|
6850
|
+
/**
|
|
6851
|
+
* Tints `--et-theme-color-primary-*` etc. only when a descendant genuinely has `:focus-visible`
|
|
6852
|
+
* (`:has(:focus-visible)`) — never on mouse `:hover`/`:active`. Use this for a wrapper (like a
|
|
6853
|
+
* form field's frame) that should show the theme color while its control is focused, but must
|
|
6854
|
+
* NOT react to incidental mouse interaction with unrelated nested widgets (a toolbar button, a
|
|
6855
|
+
* rendered link) that happen to live inside the same wrapper.
|
|
6856
|
+
*
|
|
6857
|
+
* Deliberately does NOT also carry `ColorInteractiveDirective`'s `et-color-interactive` class:
|
|
6858
|
+
* that class's plain `:hover`/`:active` rules locally override the same (inheriting)
|
|
6859
|
+
* `--et-theme-color-primary-rgb`, so anything bubbling up from ANYWHERE in the subtree would
|
|
6860
|
+
* leak the transient hover/press color into every descendant reading it for unrelated cosmetics —
|
|
6861
|
+
* exactly the bug this directive's only consumer (form-field) shipped once, before the two
|
|
6862
|
+
* behaviors were split apart. If you need the plain hover/active reaction too, add
|
|
6863
|
+
* `ColorInteractiveDirective` explicitly and make sure you actually want both.
|
|
6864
|
+
*/
|
|
6865
|
+
class ColorInteractiveHasFocusDirective {
|
|
6866
|
+
constructor() {
|
|
6867
|
+
this.styleManager = injectStyleManager();
|
|
6868
|
+
this.styleManager.mount(ColorInteractiveStylesComponent);
|
|
6869
|
+
}
|
|
6870
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ColorInteractiveHasFocusDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
6871
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.5", type: ColorInteractiveHasFocusDirective, isStandalone: true, selector: "[etColorInteractiveHasFocus]", host: { classAttribute: "et-color-interactive--has-focus" }, ngImport: i0 }); }
|
|
6872
|
+
}
|
|
6873
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ColorInteractiveHasFocusDirective, decorators: [{
|
|
6874
|
+
type: Directive,
|
|
6875
|
+
args: [{
|
|
6876
|
+
selector: '[etColorInteractiveHasFocus]',
|
|
6877
|
+
host: {
|
|
6878
|
+
class: 'et-color-interactive--has-focus',
|
|
6879
|
+
},
|
|
6880
|
+
}]
|
|
6881
|
+
}], ctorParameters: () => [] });
|
|
6882
|
+
|
|
6883
|
+
/**
|
|
6884
|
+
* Makes an element react to ITS OWN `:hover`/`:active`/`:focus-visible`/`[disabled]` by tinting
|
|
6885
|
+
* `--et-theme-color-primary-*`/`-on-primary-*`/`-ink-*` with the current color theme. Use this on
|
|
6886
|
+
* a single, self-contained interactive element — a button, a checkbox, a segmented button.
|
|
6887
|
+
*
|
|
6888
|
+
* Do NOT apply this to a wrapper that also contains OTHER, independently-interactive elements
|
|
6889
|
+
* (e.g. a toolbar with its own buttons, or a form-field's control slot). These are ordinary
|
|
6890
|
+
* inheriting CSS custom properties, so a descendant reading them for its own cosmetics (a caret
|
|
6891
|
+
* color, a link color) gets swept along whenever ANYTHING inside the wrapper is hovered or
|
|
6892
|
+
* clicked — not just when the wrapper itself is the thing being interacted with. That exact bug
|
|
6893
|
+
* shipped once already; see ColorInteractiveContainerDirective/ColorInteractiveHasFocusDirective
|
|
6894
|
+
* for the shapes that avoid it.
|
|
6895
|
+
*/
|
|
6896
|
+
class ColorInteractiveDirective {
|
|
6897
|
+
constructor() {
|
|
6898
|
+
this.styleManager = injectStyleManager();
|
|
6899
|
+
this.styleManager.mount(ColorInteractiveStylesComponent);
|
|
6900
|
+
}
|
|
6901
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ColorInteractiveDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
6902
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.5", type: ColorInteractiveDirective, isStandalone: true, selector: "[etColorInteractive]", host: { classAttribute: "et-color-interactive" }, ngImport: i0 }); }
|
|
6903
|
+
}
|
|
6904
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ColorInteractiveDirective, decorators: [{
|
|
6905
|
+
type: Directive,
|
|
6906
|
+
args: [{
|
|
6907
|
+
selector: '[etColorInteractive]',
|
|
6908
|
+
host: {
|
|
6909
|
+
class: 'et-color-interactive',
|
|
6910
|
+
},
|
|
6911
|
+
}]
|
|
6912
|
+
}], ctorParameters: () => [] });
|
|
6913
|
+
|
|
6914
|
+
const createCssColorThemeName = (name) => name.replace(/([A-Z])/g, (g) => `-${g[0].toLowerCase()}`);
|
|
5115
6915
|
const [ɵProvideColorThemes, injectColorThemes] = createStaticProvider(undefined, {
|
|
5116
6916
|
name: 'Color Themes',
|
|
5117
6917
|
});
|
|
5118
|
-
const [
|
|
6918
|
+
const [ɵProvideColorThemesPrefix, injectColorThemesPrefix] = createStaticProvider('et', {
|
|
6919
|
+
name: 'Themes Prefix',
|
|
6920
|
+
});
|
|
5119
6921
|
const provideColorThemesWithTailwind4 = (themes, prefix = 'et') => [
|
|
5120
|
-
ɵProvideColorThemes(themes
|
|
5121
|
-
|
|
6922
|
+
ɵProvideColorThemes(themes),
|
|
6923
|
+
ɵProvideColorThemesPrefix(prefix),
|
|
5122
6924
|
];
|
|
6925
|
+
const injectColorThemeByType = (type) => {
|
|
6926
|
+
const themes = injectColorThemes();
|
|
6927
|
+
if (!themes) {
|
|
6928
|
+
throw new Error(`[injectColorThemeByType] No color themes provided. Call provideColorThemesWithTailwind4() in your app config.`);
|
|
6929
|
+
}
|
|
6930
|
+
const theme = themes.find((t) => t.type === type);
|
|
6931
|
+
if (!theme) {
|
|
6932
|
+
throw new Error(`[injectColorThemeByType] No color theme with type "${type}" found. Add a theme with type: "${type}" to provideColorThemesWithTailwind4().`);
|
|
6933
|
+
}
|
|
6934
|
+
if (isDevMode()) {
|
|
6935
|
+
const duplicates = themes.filter((t) => t.type === type);
|
|
6936
|
+
if (duplicates.length > 1) {
|
|
6937
|
+
console.error(`[injectColorThemeByType] Multiple themes with type "${type}" found: ${duplicates.map((t) => t.name).join(', ')}. Only the first one will be used.`);
|
|
6938
|
+
}
|
|
6939
|
+
}
|
|
6940
|
+
return theme;
|
|
6941
|
+
};
|
|
6942
|
+
const injectErrorTheme = () => injectColorThemeByType('error');
|
|
6943
|
+
const injectWarningTheme = () => injectColorThemeByType('warning');
|
|
6944
|
+
const injectSuccessTheme = () => injectColorThemeByType('success');
|
|
5123
6945
|
|
|
5124
6946
|
/**
|
|
5125
6947
|
* @deprecated Migrate to Tailwind v4. Intent to remove in v6.
|
|
@@ -5127,6 +6949,11 @@ const provideColorThemesWithTailwind4 = (themes, prefix = 'et') => [
|
|
|
5127
6949
|
const createSwatchCss = (swatch, isAlt, data) => {
|
|
5128
6950
|
const varSuffix = isAlt ? 'alt-' + swatch : swatch;
|
|
5129
6951
|
const varOnSuffix = isAlt ? 'alt-' : '';
|
|
6952
|
+
const inkDefault = data.inkColor?.default || data.color.default;
|
|
6953
|
+
const inkHover = data.inkColor?.hover || inkDefault;
|
|
6954
|
+
const inkFocus = data.inkColor?.focus || data.inkColor?.hover || inkDefault;
|
|
6955
|
+
const inkActive = data.inkColor?.active || inkDefault;
|
|
6956
|
+
const inkDisabled = data.inkColor?.disabled || inkDefault;
|
|
5130
6957
|
return `
|
|
5131
6958
|
--et-color-${varSuffix}: ${data.color.default};
|
|
5132
6959
|
--et-color-${varSuffix}-hover: ${data.color.hover};
|
|
@@ -5139,6 +6966,12 @@ const createSwatchCss = (swatch, isAlt, data) => {
|
|
|
5139
6966
|
--et-color-${varOnSuffix}on-${swatch}-focus: ${data.onColor.focus || data.onColor.hover || data.onColor.default};
|
|
5140
6967
|
--et-color-${varOnSuffix}on-${swatch}-active: ${data.onColor.active || data.onColor.default};
|
|
5141
6968
|
--et-color-${varOnSuffix}on-${swatch}-disabled: ${data.onColor.disabled || data.onColor.default};
|
|
6969
|
+
|
|
6970
|
+
--et-color-${varSuffix}-ink: ${inkDefault};
|
|
6971
|
+
--et-color-${varSuffix}-ink-hover: ${inkHover};
|
|
6972
|
+
--et-color-${varSuffix}-ink-focus: ${inkFocus};
|
|
6973
|
+
--et-color-${varSuffix}-ink-active: ${inkActive};
|
|
6974
|
+
--et-color-${varSuffix}-ink-disabled: ${inkDisabled};
|
|
5142
6975
|
`;
|
|
5143
6976
|
};
|
|
5144
6977
|
/**
|
|
@@ -5146,6 +6979,11 @@ const createSwatchCss = (swatch, isAlt, data) => {
|
|
|
5146
6979
|
*/
|
|
5147
6980
|
const createRootThemeCss = (themes) => {
|
|
5148
6981
|
const createVars = (name, swatch) => {
|
|
6982
|
+
const inkDefault = swatch.inkColor?.default || swatch.color.default;
|
|
6983
|
+
const inkHover = swatch.inkColor?.hover || inkDefault;
|
|
6984
|
+
const inkFocus = swatch.inkColor?.focus || swatch.inkColor?.hover || inkDefault;
|
|
6985
|
+
const inkActive = swatch.inkColor?.active || inkDefault;
|
|
6986
|
+
const inkDisabled = swatch.inkColor?.disabled || inkDefault;
|
|
5149
6987
|
return `
|
|
5150
6988
|
--et-color-${name}: ${swatch.color.default};
|
|
5151
6989
|
--et-color-${name}-hover: ${swatch.color.hover};
|
|
@@ -5158,11 +6996,17 @@ const createRootThemeCss = (themes) => {
|
|
|
5158
6996
|
--et-color-on-${name}-focus: ${swatch.onColor.focus || swatch.onColor.hover || swatch.onColor.default};
|
|
5159
6997
|
--et-color-on-${name}-active: ${swatch.onColor.active || swatch.onColor.default};
|
|
5160
6998
|
--et-color-on-${name}-disabled: ${swatch.onColor.disabled || swatch.onColor.default};
|
|
6999
|
+
|
|
7000
|
+
--et-color-${name}-ink: ${inkDefault};
|
|
7001
|
+
--et-color-${name}-ink-hover: ${inkHover};
|
|
7002
|
+
--et-color-${name}-ink-focus: ${inkFocus};
|
|
7003
|
+
--et-color-${name}-ink-active: ${inkActive};
|
|
7004
|
+
--et-color-${name}-ink-disabled: ${inkDisabled};
|
|
5161
7005
|
`;
|
|
5162
7006
|
};
|
|
5163
7007
|
const vars = [];
|
|
5164
7008
|
for (const theme of themes) {
|
|
5165
|
-
const name =
|
|
7009
|
+
const name = createCssColorThemeName(theme.name);
|
|
5166
7010
|
if (theme.secondary || theme.tertiary) {
|
|
5167
7011
|
vars.push(createVars(`${name}-primary`, theme.primary));
|
|
5168
7012
|
if (theme.secondary) {
|
|
@@ -5190,13 +7034,13 @@ const createRootThemeCss = (themes) => {
|
|
|
5190
7034
|
* @deprecated Migrate to Tailwind v4. Intent to remove in v6.
|
|
5191
7035
|
*/
|
|
5192
7036
|
const createThemeStyle = (theme, isAlt) => {
|
|
5193
|
-
const cssThemeName =
|
|
5194
|
-
const
|
|
7037
|
+
const cssThemeName = createCssColorThemeName(theme.name);
|
|
7038
|
+
const classPrefix = isAlt ? 'et-color-alt' : 'et-color';
|
|
5195
7039
|
const selectors = [
|
|
5196
7040
|
...((theme.isDefault && !isAlt) || (theme.isDefaultAlt && isAlt)
|
|
5197
|
-
? [':root',
|
|
7041
|
+
? [':root', `.${classPrefix}--default`]
|
|
5198
7042
|
: []),
|
|
5199
|
-
|
|
7043
|
+
`.${classPrefix}--${cssThemeName}`,
|
|
5200
7044
|
];
|
|
5201
7045
|
const css = `
|
|
5202
7046
|
${selectors.join(', ')} {
|
|
@@ -5206,7 +7050,7 @@ const createThemeStyle = (theme, isAlt) => {
|
|
|
5206
7050
|
}
|
|
5207
7051
|
`;
|
|
5208
7052
|
const style = document.createElement('style');
|
|
5209
|
-
style.id =
|
|
7053
|
+
style.id = `${classPrefix}--${cssThemeName}`;
|
|
5210
7054
|
style.appendChild(document.createTextNode(css));
|
|
5211
7055
|
document.head.appendChild(style);
|
|
5212
7056
|
};
|
|
@@ -5242,6 +7086,23 @@ const createTailwindColorThemes = (themes, prefix = 'et') => {
|
|
|
5242
7086
|
active: createTailwindRgbVar(theme.primary.onColor.active) || createTailwindRgbVar(theme.primary.onColor.default),
|
|
5243
7087
|
disabled: createTailwindRgbVar(theme.primary.onColor.disabled) || createTailwindRgbVar(theme.primary.onColor.default),
|
|
5244
7088
|
};
|
|
7089
|
+
const keyInk = `${prefix}-${theme.name}-ink`;
|
|
7090
|
+
twThemes[keyInk] = {
|
|
7091
|
+
DEFAULT: createTailwindRgbVar(theme.primary.inkColor?.default) || createTailwindRgbVar(theme.primary.color.default),
|
|
7092
|
+
hover: createTailwindRgbVar(theme.primary.inkColor?.hover) ||
|
|
7093
|
+
createTailwindRgbVar(theme.primary.inkColor?.default) ||
|
|
7094
|
+
createTailwindRgbVar(theme.primary.color.default),
|
|
7095
|
+
focus: createTailwindRgbVar(theme.primary.inkColor?.focus) ||
|
|
7096
|
+
createTailwindRgbVar(theme.primary.inkColor?.hover) ||
|
|
7097
|
+
createTailwindRgbVar(theme.primary.inkColor?.default) ||
|
|
7098
|
+
createTailwindRgbVar(theme.primary.color.default),
|
|
7099
|
+
active: createTailwindRgbVar(theme.primary.inkColor?.active) ||
|
|
7100
|
+
createTailwindRgbVar(theme.primary.inkColor?.default) ||
|
|
7101
|
+
createTailwindRgbVar(theme.primary.color.default),
|
|
7102
|
+
disabled: createTailwindRgbVar(theme.primary.inkColor?.disabled) ||
|
|
7103
|
+
createTailwindRgbVar(theme.primary.inkColor?.default) ||
|
|
7104
|
+
createTailwindRgbVar(theme.primary.color.default),
|
|
7105
|
+
};
|
|
5245
7106
|
}
|
|
5246
7107
|
return twThemes;
|
|
5247
7108
|
};
|
|
@@ -5267,82 +7128,278 @@ const provideColorThemes = (themes) => {
|
|
|
5267
7128
|
createThemeStyle(theme, true);
|
|
5268
7129
|
}
|
|
5269
7130
|
createRootThemeCss(themes);
|
|
5270
|
-
return [ɵProvideColorThemes(themes
|
|
7131
|
+
return [ɵProvideColorThemes(themes), ɵProvideColorThemesPrefix('et')];
|
|
5271
7132
|
};
|
|
5272
7133
|
|
|
5273
|
-
const
|
|
5274
|
-
|
|
7134
|
+
const COLOR_PROVIDER = new InjectionToken('ColorProvider');
|
|
7135
|
+
const FORCED_COLOR_UNSET = Symbol('FORCED_COLOR_UNSET');
|
|
7136
|
+
class ProvideColorDirective {
|
|
5275
7137
|
constructor() {
|
|
5276
7138
|
this.themes = injectColorThemes({ optional: true });
|
|
5277
|
-
this.prefix =
|
|
7139
|
+
this.prefix = injectColorThemesPrefix({ optional: true });
|
|
5278
7140
|
this.injector = inject(Injector);
|
|
5279
7141
|
this.currentProviderSync = null;
|
|
5280
|
-
this.
|
|
5281
|
-
|
|
5282
|
-
this.
|
|
5283
|
-
|
|
5284
|
-
|
|
5285
|
-
|
|
5286
|
-
|
|
5287
|
-
console.error(`Theme ${value} does not exist. Please make sure to add it to provideColorThemes()`);
|
|
7142
|
+
this.forcedColor = signal(FORCED_COLOR_UNSET, /* @ts-ignore */
|
|
7143
|
+
...(ngDevMode ? [{ debugName: "forcedColor" }] : /* istanbul ignore next */ []));
|
|
7144
|
+
this.color = input(undefined, { ...(ngDevMode ? { debugName: "color" } : /* istanbul ignore next */ {}), alias: 'etProvideColor' });
|
|
7145
|
+
this.effectiveColor = computed(() => {
|
|
7146
|
+
const forcedColor = this.forcedColor();
|
|
7147
|
+
if (forcedColor !== FORCED_COLOR_UNSET) {
|
|
7148
|
+
return forcedColor;
|
|
5288
7149
|
}
|
|
5289
|
-
return
|
|
5290
|
-
},
|
|
5291
|
-
|
|
5292
|
-
|
|
7150
|
+
return this.color();
|
|
7151
|
+
}, /* @ts-ignore */
|
|
7152
|
+
...(ngDevMode ? [{ debugName: "effectiveColor" }] : /* istanbul ignore next */ []));
|
|
7153
|
+
this.colorName = computed(() => {
|
|
7154
|
+
const raw = this.effectiveColor();
|
|
7155
|
+
const value = typeof raw === 'object' && raw !== null ? raw.name : raw;
|
|
5293
7156
|
if (!this.themes || !value)
|
|
5294
7157
|
return;
|
|
5295
|
-
if (isDevMode() && !this.themes
|
|
5296
|
-
console.
|
|
7158
|
+
if (isDevMode() && !this.themes.some((theme) => theme.name === value) && value !== null) {
|
|
7159
|
+
console.error(`Theme ${value} does not exist. Please make sure to add it to provideColorThemesWithTailwind4()`);
|
|
5297
7160
|
}
|
|
5298
|
-
return
|
|
5299
|
-
},
|
|
7161
|
+
return createCssColorThemeName(value);
|
|
7162
|
+
}, /* @ts-ignore */
|
|
7163
|
+
...(ngDevMode ? [{ debugName: "colorName" }] : /* istanbul ignore next */ []));
|
|
5300
7164
|
this.themeClass = computed(() => {
|
|
5301
|
-
const themes = [];
|
|
5302
7165
|
const prefix = this.prefix || 'et';
|
|
5303
|
-
if (this.
|
|
5304
|
-
|
|
7166
|
+
if (this.colorName()) {
|
|
7167
|
+
return `${prefix}-color--${this.colorName()}`;
|
|
5305
7168
|
}
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
|
|
5309
|
-
return themes.join(' ');
|
|
5310
|
-
}, ...(ngDevMode ? [{ debugName: "themeClass" }] : []));
|
|
7169
|
+
return `${prefix}-color--inherited`;
|
|
7170
|
+
}, /* @ts-ignore */
|
|
7171
|
+
...(ngDevMode ? [{ debugName: "themeClass" }] : /* istanbul ignore next */ []));
|
|
5311
7172
|
}
|
|
5312
7173
|
syncWithProvider(provider) {
|
|
5313
7174
|
this.currentProviderSync?.destroy();
|
|
5314
7175
|
runInInjectionContext(this.injector, () => {
|
|
5315
7176
|
this.currentProviderSync = effect(() => {
|
|
5316
|
-
const
|
|
5317
|
-
const provideAltTheme = provider.altTheme();
|
|
7177
|
+
const provideColor = provider.effectiveColor();
|
|
5318
7178
|
untracked(() => {
|
|
5319
|
-
|
|
5320
|
-
|
|
7179
|
+
if (provideColor === undefined) {
|
|
7180
|
+
this.clearForcedColor();
|
|
7181
|
+
return;
|
|
7182
|
+
}
|
|
7183
|
+
this.forceColor(provideColor);
|
|
5321
7184
|
});
|
|
5322
|
-
},
|
|
7185
|
+
}, /* @ts-ignore */
|
|
7186
|
+
...(ngDevMode ? [{ debugName: "currentProviderSync" }] : /* istanbul ignore next */ []));
|
|
5323
7187
|
});
|
|
5324
7188
|
}
|
|
5325
7189
|
stopSyncWithProvider() {
|
|
7190
|
+
const hadProviderSync = !!this.currentProviderSync;
|
|
5326
7191
|
this.currentProviderSync?.destroy();
|
|
5327
7192
|
this.currentProviderSync = null;
|
|
7193
|
+
if (hadProviderSync) {
|
|
7194
|
+
this.clearForcedColor();
|
|
7195
|
+
}
|
|
7196
|
+
}
|
|
7197
|
+
/** @internal */
|
|
7198
|
+
forceColor(color) {
|
|
7199
|
+
this.forcedColor.set(color);
|
|
7200
|
+
}
|
|
7201
|
+
/** @internal */
|
|
7202
|
+
clearForcedColor() {
|
|
7203
|
+
if (this.forcedColor() === FORCED_COLOR_UNSET) {
|
|
7204
|
+
return;
|
|
7205
|
+
}
|
|
7206
|
+
this.forcedColor.set(FORCED_COLOR_UNSET);
|
|
5328
7207
|
}
|
|
5329
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
5330
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "
|
|
7208
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ProvideColorDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
7209
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.5", 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 }); }
|
|
5331
7210
|
}
|
|
5332
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
7211
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ProvideColorDirective, decorators: [{
|
|
5333
7212
|
type: Directive,
|
|
5334
7213
|
args: [{
|
|
5335
|
-
selector: '[
|
|
5336
|
-
providers: [{ provide:
|
|
7214
|
+
selector: '[etProvideColor]',
|
|
7215
|
+
providers: [{ provide: COLOR_PROVIDER, useExisting: ProvideColorDirective }],
|
|
5337
7216
|
host: {
|
|
5338
7217
|
'[class]': 'themeClass()',
|
|
5339
7218
|
},
|
|
5340
7219
|
}]
|
|
5341
|
-
}], propDecorators: {
|
|
7220
|
+
}], propDecorators: { color: [{ type: i0.Input, args: [{ isSignal: true, alias: "etProvideColor", required: false }] }] } });
|
|
7221
|
+
|
|
7222
|
+
const SURFACE_TYPE = {
|
|
7223
|
+
LIGHT: 'light',
|
|
7224
|
+
DARK: 'dark',
|
|
7225
|
+
};
|
|
7226
|
+
const createCssSurfaceName = (name) => name.replace(/([A-Z])/g, (g) => `-${g[0].toLowerCase()}`);
|
|
7227
|
+
const resolveSurfaceByElevation = (themes, type, elevation) => themes.find((t) => t.type === type && t.elevation === elevation) ?? null;
|
|
7228
|
+
const [ɵProvideSurfaceThemes, injectSurfaceThemes] = createStaticProvider(undefined, {
|
|
7229
|
+
name: 'Surface Themes',
|
|
7230
|
+
});
|
|
7231
|
+
const [ɵProvideSurfaceThemesPrefix, injectSurfaceThemesPrefix] = createStaticProvider('et', {
|
|
7232
|
+
name: 'Surface Themes Prefix',
|
|
7233
|
+
});
|
|
7234
|
+
const provideSurfaceThemesWithTailwind4 = (themes, prefix = 'et') => [
|
|
7235
|
+
ɵProvideSurfaceThemes(themes),
|
|
7236
|
+
ɵProvideSurfaceThemesPrefix(prefix),
|
|
7237
|
+
];
|
|
7238
|
+
|
|
7239
|
+
const SURFACE_PROVIDER = new InjectionToken('SurfaceProvider');
|
|
7240
|
+
const FORCED_SURFACE_UNSET = Symbol('FORCED_SURFACE_UNSET');
|
|
7241
|
+
class ProvideSurfaceDirective {
|
|
7242
|
+
constructor() {
|
|
7243
|
+
this.themes = injectSurfaceThemes({ optional: true });
|
|
7244
|
+
this.prefix = injectSurfaceThemesPrefix({ optional: true });
|
|
7245
|
+
this.injector = inject(Injector);
|
|
7246
|
+
this.currentProviderSync = null;
|
|
7247
|
+
this.forcedSurface = signal(FORCED_SURFACE_UNSET, /* @ts-ignore */
|
|
7248
|
+
...(ngDevMode ? [{ debugName: "forcedSurface" }] : /* istanbul ignore next */ []));
|
|
7249
|
+
this.surface = input(undefined, { ...(ngDevMode ? { debugName: "surface" } : /* istanbul ignore next */ {}), alias: 'etProvideSurface' });
|
|
7250
|
+
this.effectiveSurface = computed(() => {
|
|
7251
|
+
const forcedSurface = this.forcedSurface();
|
|
7252
|
+
if (forcedSurface !== FORCED_SURFACE_UNSET) {
|
|
7253
|
+
return forcedSurface;
|
|
7254
|
+
}
|
|
7255
|
+
return this.surface();
|
|
7256
|
+
}, /* @ts-ignore */
|
|
7257
|
+
...(ngDevMode ? [{ debugName: "effectiveSurface" }] : /* istanbul ignore next */ []));
|
|
7258
|
+
this.resolvedTheme = computed(() => {
|
|
7259
|
+
const value = this.effectiveSurface();
|
|
7260
|
+
if (!this.themes || !value)
|
|
7261
|
+
return null;
|
|
7262
|
+
const theme = this.themes.find((t) => t.name === value) ?? null;
|
|
7263
|
+
if (isDevMode() && !theme && value !== null) {
|
|
7264
|
+
console.error(`Surface theme ${value} does not exist. Please make sure to add it to provideSurfaceThemesWithTailwind4()`);
|
|
7265
|
+
}
|
|
7266
|
+
return theme;
|
|
7267
|
+
}, /* @ts-ignore */
|
|
7268
|
+
...(ngDevMode ? [{ debugName: "resolvedTheme" }] : /* istanbul ignore next */ []));
|
|
7269
|
+
this.elevation = computed(() => this.resolvedTheme()?.elevation ?? 0, /* @ts-ignore */
|
|
7270
|
+
...(ngDevMode ? [{ debugName: "elevation" }] : /* istanbul ignore next */ []));
|
|
7271
|
+
this.surfaceType = computed(() => this.resolvedTheme()?.type ?? null, /* @ts-ignore */
|
|
7272
|
+
...(ngDevMode ? [{ debugName: "surfaceType" }] : /* istanbul ignore next */ []));
|
|
7273
|
+
this.surfaceName = computed(() => {
|
|
7274
|
+
const value = this.effectiveSurface();
|
|
7275
|
+
if (!this.themes || !value)
|
|
7276
|
+
return;
|
|
7277
|
+
return createCssSurfaceName(value);
|
|
7278
|
+
}, /* @ts-ignore */
|
|
7279
|
+
...(ngDevMode ? [{ debugName: "surfaceName" }] : /* istanbul ignore next */ []));
|
|
7280
|
+
this.surfaceClass = computed(() => {
|
|
7281
|
+
const prefix = this.prefix || 'et';
|
|
7282
|
+
if (this.surfaceName()) {
|
|
7283
|
+
return `${prefix}-surface--${this.surfaceName()}`;
|
|
7284
|
+
}
|
|
7285
|
+
return `${prefix}-surface--inherited`;
|
|
7286
|
+
}, /* @ts-ignore */
|
|
7287
|
+
...(ngDevMode ? [{ debugName: "surfaceClass" }] : /* istanbul ignore next */ []));
|
|
7288
|
+
}
|
|
7289
|
+
syncWithProvider(provider) {
|
|
7290
|
+
this.currentProviderSync?.destroy();
|
|
7291
|
+
runInInjectionContext(this.injector, () => {
|
|
7292
|
+
this.currentProviderSync = effect(() => {
|
|
7293
|
+
const provideSurface = provider.effectiveSurface();
|
|
7294
|
+
untracked(() => {
|
|
7295
|
+
if (provideSurface === undefined) {
|
|
7296
|
+
this.clearForcedSurface();
|
|
7297
|
+
return;
|
|
7298
|
+
}
|
|
7299
|
+
this.forceSurface(provideSurface);
|
|
7300
|
+
});
|
|
7301
|
+
}, /* @ts-ignore */
|
|
7302
|
+
...(ngDevMode ? [{ debugName: "currentProviderSync" }] : /* istanbul ignore next */ []));
|
|
7303
|
+
});
|
|
7304
|
+
}
|
|
7305
|
+
stopSyncWithProvider() {
|
|
7306
|
+
const hadProviderSync = !!this.currentProviderSync;
|
|
7307
|
+
this.currentProviderSync?.destroy();
|
|
7308
|
+
this.currentProviderSync = null;
|
|
7309
|
+
if (hadProviderSync) {
|
|
7310
|
+
this.clearForcedSurface();
|
|
7311
|
+
}
|
|
7312
|
+
}
|
|
7313
|
+
/** @internal */
|
|
7314
|
+
forceSurface(surface) {
|
|
7315
|
+
this.forcedSurface.set(surface);
|
|
7316
|
+
}
|
|
7317
|
+
/** @internal */
|
|
7318
|
+
clearForcedSurface() {
|
|
7319
|
+
if (this.forcedSurface() === FORCED_SURFACE_UNSET) {
|
|
7320
|
+
return;
|
|
7321
|
+
}
|
|
7322
|
+
this.forcedSurface.set(FORCED_SURFACE_UNSET);
|
|
7323
|
+
}
|
|
7324
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ProvideSurfaceDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
7325
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.5", type: ProvideSurfaceDirective, isStandalone: true, selector: "[etProvideSurface]", inputs: { surface: { classPropertyName: "surface", publicName: "etProvideSurface", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "surfaceClass()" } }, providers: [{ provide: SURFACE_PROVIDER, useExisting: ProvideSurfaceDirective }], ngImport: i0 }); }
|
|
7326
|
+
}
|
|
7327
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ProvideSurfaceDirective, decorators: [{
|
|
7328
|
+
type: Directive,
|
|
7329
|
+
args: [{
|
|
7330
|
+
selector: '[etProvideSurface]',
|
|
7331
|
+
providers: [{ provide: SURFACE_PROVIDER, useExisting: ProvideSurfaceDirective }],
|
|
7332
|
+
host: {
|
|
7333
|
+
'[class]': 'surfaceClass()',
|
|
7334
|
+
},
|
|
7335
|
+
}]
|
|
7336
|
+
}], propDecorators: { surface: [{ type: i0.Input, args: [{ isSignal: true, alias: "etProvideSurface", required: false }] }] } });
|
|
7337
|
+
|
|
7338
|
+
let uniqueId = 0;
|
|
7339
|
+
const [provideSurfaceContextTracker, injectSurfaceContextTracker] = createRootProvider(() => {
|
|
7340
|
+
const entries = signal([], /* @ts-ignore */
|
|
7341
|
+
...(ngDevMode ? [{ debugName: "entries" }] : /* istanbul ignore next */ []));
|
|
7342
|
+
const topEntry = computed(() => {
|
|
7343
|
+
const stack = entries();
|
|
7344
|
+
return stack.length > 0 ? (stack[stack.length - 1] ?? null) : null;
|
|
7345
|
+
}, /* @ts-ignore */
|
|
7346
|
+
...(ngDevMode ? [{ debugName: "topEntry" }] : /* istanbul ignore next */ []));
|
|
7347
|
+
const topType = computed(() => topEntry()?.type ?? null, /* @ts-ignore */
|
|
7348
|
+
...(ngDevMode ? [{ debugName: "topType" }] : /* istanbul ignore next */ []));
|
|
7349
|
+
const topElevation = computed(() => topEntry()?.elevation ?? 0, /* @ts-ignore */
|
|
7350
|
+
...(ngDevMode ? [{ debugName: "topElevation" }] : /* istanbul ignore next */ []));
|
|
7351
|
+
const register = (type, elevation) => {
|
|
7352
|
+
const id = `surface-ctx-${uniqueId++}`;
|
|
7353
|
+
const entry = { id, type, elevation };
|
|
7354
|
+
entries.update((e) => [...e, entry]);
|
|
7355
|
+
return () => {
|
|
7356
|
+
entries.update((e) => e.filter((item) => item.id !== id));
|
|
7357
|
+
};
|
|
7358
|
+
};
|
|
7359
|
+
return { topType, topElevation, register };
|
|
7360
|
+
}, { name: 'SurfaceContextTracker' });
|
|
7361
|
+
|
|
7362
|
+
class SurfaceInteractiveStylesComponent {
|
|
7363
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: SurfaceInteractiveStylesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
7364
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.5", type: SurfaceInteractiveStylesComponent, isStandalone: true, selector: "et-surface-interactive-styles", ngImport: i0, template: '', isInline: true, styles: [":where(.et-surface-interactive){--et-surface-interaction-rgb: var(--et-surface-interaction);--et-surface-interaction-solid: rgb(var(--et-surface-interaction-rgb))}: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"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
7365
|
+
}
|
|
7366
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: SurfaceInteractiveStylesComponent, decorators: [{
|
|
7367
|
+
type: Component,
|
|
7368
|
+
args: [{ selector: 'et-surface-interactive-styles', template: '', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":where(.et-surface-interactive){--et-surface-interaction-rgb: var(--et-surface-interaction);--et-surface-interaction-solid: rgb(var(--et-surface-interaction-rgb))}: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"] }]
|
|
7369
|
+
}] });
|
|
7370
|
+
|
|
7371
|
+
/**
|
|
7372
|
+
* Same shape as `ColorInteractiveDirective` — reacts to its own `:hover`/`:focus-visible`/
|
|
7373
|
+
* `:active`/`[disabled]` — but drives `--et-surface-interaction-*`, a neutral/muted tint, instead
|
|
7374
|
+
* of the ambient color theme. Use it for chrome-level interaction feedback that shouldn't borrow
|
|
7375
|
+
* the page's brand color (a tab trigger's hover state, a toggle button that should look neutral
|
|
7376
|
+
* until it's actually active — see `ButtonDirective`'s `mutedUntilPressed`).
|
|
7377
|
+
*
|
|
7378
|
+
* Has no container/exclude/has-focus variants: it has no descendant-cascading CSS at all, so
|
|
7379
|
+
* applying it to a wrapper with independently-interactive children is safe by construction —
|
|
7380
|
+
* unlike `ColorInteractiveDirective`, there's no bubbling-leak failure mode to worry about here.
|
|
7381
|
+
*/
|
|
7382
|
+
class SurfaceInteractiveDirective {
|
|
7383
|
+
constructor() {
|
|
7384
|
+
this.styleManager = injectStyleManager();
|
|
7385
|
+
this.styleManager.mount(SurfaceInteractiveStylesComponent);
|
|
7386
|
+
}
|
|
7387
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: SurfaceInteractiveDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
7388
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.5", type: SurfaceInteractiveDirective, isStandalone: true, selector: "[etSurfaceInteractive]", host: { classAttribute: "et-surface-interactive" }, ngImport: i0 }); }
|
|
7389
|
+
}
|
|
7390
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: SurfaceInteractiveDirective, decorators: [{
|
|
7391
|
+
type: Directive,
|
|
7392
|
+
args: [{
|
|
7393
|
+
selector: '[etSurfaceInteractive]',
|
|
7394
|
+
host: {
|
|
7395
|
+
class: 'et-surface-interactive',
|
|
7396
|
+
},
|
|
7397
|
+
}]
|
|
7398
|
+
}], ctorParameters: () => [] });
|
|
5342
7399
|
|
|
5343
7400
|
/**
|
|
5344
7401
|
* Generated bundle index. Do not edit.
|
|
5345
7402
|
*/
|
|
5346
7403
|
|
|
5347
|
-
export { ANIMATABLE_TOKEN, ANIMATED_IF_TOKEN, ANIMATED_LIFECYCLE_TOKEN, AT_LEAST_ONE_REQUIRED, AnimatableDirective, AnimatedIfDirective, AnimatedLifecycleDirective, AnimatedOverlayDirective, BOUNDARY_ELEMENT_TOKEN, ClickOutsideDirective, DEFAULT_MULTI_INSTANCE_RELS, DEFAULT_MULTI_INSTANCE_TAGS, DEFAULT_VIEWPORT_CONFIG, DISABLE_LOGGER_PARAM, ET_DISABLE_SCROLL_TOP, ET_DISABLE_SCROLL_TOP_AS_RETURN_ROUTE, ET_DISABLE_SCROLL_TOP_ON_PATH_PARAM_CHANGE, ET_PROPERTY_REMOVED, FOCUS_VISIBLE_TRACKER_TOKEN, IS_ARRAY_NOT_EMPTY, IS_EMAIL, InferMimeTypePipe, IsArrayNotEmpty, IsEmail, jsonLd as JsonLD, KeyPressManager, MUST_MATCH, MustMatch, NormalizeGameResultTypePipe, NormalizeMatchParticipantsPipe, NormalizeMatchScorePipe, NormalizeMatchStatePipe, NormalizeMatchTypePipe, PropsDirective,
|
|
7404
|
+
export { ANIMATABLE_TOKEN, ANIMATED_IF_TOKEN, ANIMATED_LIFECYCLE_TOKEN, ANIMATION_DEBUG_STORAGE_KEY, AT_LEAST_ONE_REQUIRED, AnimatableDirective, AnimatedIfDirective, AnimatedLifecycleDirective, AnimatedOverlayDirective, BOUNDARY_ELEMENT_TOKEN, BREAKPOINT_INSTANCE_TOKEN, BREAKPOINT_ORDER, COLOR_PROVIDER, ClickOutsideDirective, ColorInteractiveContainerDirective, ColorInteractiveDirective, ColorInteractiveExcludeDirective, ColorInteractiveHasFocusDirective, DEFAULT_MULTI_INSTANCE_RELS, DEFAULT_MULTI_INSTANCE_TAGS, DEFAULT_VIEWPORT_CONFIG, DISABLE_LOGGER_PARAM, DragHandleDirective, ET_DISABLE_SCROLL_TOP, ET_DISABLE_SCROLL_TOP_AS_RETURN_ROUTE, ET_DISABLE_SCROLL_TOP_ON_PATH_PARAM_CHANGE, ET_PROPERTY_REMOVED, FOCUSABLE_SELECTOR, FOCUS_VISIBLE_TRACKER_TOKEN, HtmlToMarkdownPipe, IS_ARRAY_NOT_EMPTY, IS_EMAIL, InferMimeTypePipe, IsArrayNotEmpty, IsEmail, jsonLd as JsonLD, KeyPressManager, MUST_MATCH, MarkdownToHtmlPipe, MustMatch, NormalizeGameResultTypePipe, NormalizeMatchParticipantsPipe, NormalizeMatchScorePipe, NormalizeMatchStatePipe, NormalizeMatchTypePipe, PropsDirective, ProvideColorDirective, ProvideSurfaceDirective, RUNTIME_ERROR_NO_DATA, RepeatDirective, ResizeHandlesComponent, RuntimeError, SEO_DIRECTIVE_TOKEN, SURFACE_PROVIDER, SURFACE_TYPE, ScrollObserverDirective, ScrollObserverEndDirective, ScrollObserverStartDirective, SeoDirective, StructuredDataComponent, SurfaceInteractiveDirective, ToArrayPipe, TypedQueryList, ValidateAtLeastOneRequired, Validators, animationDebugLog, applyAlternateBinding, applyAlternateLanguagesBindings, applyArticleBindings, applyAuthorBinding, applyCanonicalBinding, applyCenteredPosition, applyDescriptionBinding, applyGlobalPosition, applyHeadBinding, applyHeadTitleBinding, applyHostListener, applyHostListeners, applyInitialFocus, applyKeywordsBinding, applyLinkBinding, applyMetaBinding, applyNextBinding, applyOgBinding, applyOpenGraphBindings, applyPrevBinding, applyResourceHintsBindings, applyRobotsBinding, applySocialMediaBindings, applyStructuredDataBinding, applyTwitterCardBindings, areScrollStatesEqual, bindProps, boolBreakpointTransform, booleanBreakpointAttribute, boundingClientRectToElementRect, breakpointTransformBase, buildElementSignal, buildSignalEffects, canUseSessionMemory, clamp, clone, cloneFormGroup, computedTillFalsy, computedTillTruthy, controlValueSignal, controlValueSignalWithPrevious, createAnchoredPositionCleanup, createArrayPropertyBinding, createAutoSessionMemoryKey, createBulkPropertyBinding, createCanAnimateSignal, createComponentId, createCssColorThemeName, createCssSurfaceName, createDependencyStash, createDestroy, createDocumentElementSignal, createElementDictionary, createElementDimensions, createEmptyElementSignal, createFlipAnimation, createFlipAnimationGroup, createHostProps, createIsRenderedSignal, createLogger, createOverlayRuntimeRef, createPropHandlers, createPropertyBinding, createProps, createProvider, createRootProvider, createRootThemeCss, createRoute, createRouterState, createRxHostListener, createSessionMemory, createSetup, createStaticProvider, createStaticRootProvider, createSwatchCss, createSwipeTracker, createTailwindColorThemes, createTailwindCssVar, createTailwindRgbVar, createThemeStyle, createUserConsentProvider, deferredSignal, deleteCookie, easeElastic, easeIn, easeInOut, easeLinear, easeOut, easeOutBack, easeOutBackStrong, elementCanScroll, equal, firstElementSignal, focusElement, forceReflow, formatRuntimeError, fromNextFrame, getCookie, getDomain, getElementScrollCoordinates, getFocusableElements, getFormGroupValue, getGroupMatchPoints, getGroupMatchScore, getHeadingElement, getKnockoutMatchScore, getMatchScoreSubLine, getObjectProperty, getScrollContainerTarget, getScrollItemTarget, getScrollSnapTarget, hasCookie, htmlToMarkdown, inferMimeType, injectAngularRootElement, injectBoundaryElement, injectBreakpointInput, injectBreakpointIsMatched, injectBreakpointObserver, injectCanHover, injectColorThemes, injectColorThemesPrefix, injectCurrentBreakpoint, injectDeviceInputType, injectDisplayOrientation, injectErrorTheme, injectFocusVisibleTracker, injectFragment, injectHasPrecisionInput, injectHasTouchInput, injectHostElement, injectIs2Xl, injectIsLandscape, injectIsLg, injectIsMd, injectIsPortrait, injectIsRouterInitialized, injectIsSm, injectIsXl, injectIsXs, injectLinkStore, injectLinkStoreConfig, injectLocale, injectMediaQueryIsMatched, injectMetaConfig, injectMetaStore, injectObserveBreakpoint, injectObserveMediaQuery, injectOverlayRuntime, injectPathParam, injectPathParamChanges, injectPathParams, injectQueryParam, injectQueryParamChanges, injectQueryParams, injectRenderer, injectRoute, injectRouteData, injectRouteDataItem, injectRouteTitle, injectRouterEvent, injectRouterState, injectScrollbarDimensions, injectStructuredDataConfig, injectStructuredDataStore, injectStyleManager, injectSuccessTheme, injectSurfaceContextTracker, injectSurfaceThemes, injectSurfaceThemesPrefix, injectTemplateRef, injectTitleConfig, injectTitleStore, injectUrl, injectViewportConfig, injectViewportDimensions, injectViewportSize, injectWarningTheme, isAnimationDebugEnabled, isArray, isElementSignal, isElementVisible, isFocusable, isGroupMatch, isHTMLElement, isKnockoutMatch, isObject, markdownToHtml, maybeSignalValue, memoizeSignal, nextFrame, normalizeGameResultType, normalizeMatchParticipant, normalizeMatchParticipants, normalizeMatchScore, normalizeMatchState, normalizeMatchType, numberBreakpointAttribute, numberBreakpointTransform, previousSignalValue, provideBoundaryElement, provideBreakpointInstance, provideBreakpointObserver, provideColorThemes, provideColorThemesWithTailwind4, provideFocusVisibleTracker, provideLinkStore, provideLinkStoreConfig, provideLocale, provideMetaConfig, provideMetaStore, provideOverlayRuntime, provideRenderer, provideStructuredDataConfig, provideStructuredDataStore, provideStyleManager, provideSurfaceContextTracker, provideSurfaceThemesWithTailwind4, provideTitleConfig, provideTitleStore, provideViewportConfig, resetPositioningStyles, resolveSurfaceByElevation, round, routerDisableScrollTop, scrollToElement, setBackdropStyles, setBaseElementStyles, setCookie, setInputSignal, setupFocusTrap, setupPositioning, setupScrollRestoration, signalAnimatedNumber, signalAttributes, signalClasses, signalElementChildren, signalElementDimensions, signalElementIntersection, signalElementLastScrollDirection, signalElementMutations, signalElementScrollState, signalHostAttributes, signalHostClasses, signalHostElementDimensions, signalHostElementIntersection, signalHostElementLastScrollDirection, signalHostElementMutations, signalHostElementScrollState, signalHostStyles, signalIsRendered, signalStyles, switchQueryListChanges, syncSignal, templateComputed, toArray, toArrayTrackByFn, toStringBinding, transformOrReturn, typedBreakpointTransform, unbindProps, useCursorDragScroll, writeScrollbarSizeToCssVariables, writeViewportSizeToCssVariables, ɵProvideColorThemes, ɵProvideColorThemesPrefix, ɵProvideSurfaceThemes, ɵProvideSurfaceThemesPrefix };
|
|
5348
7405
|
//# sourceMappingURL=ethlete-core.mjs.map
|