@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.
@@ -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, linkedSignal, DOCUMENT, isDevMode, computed, afterNextRender, effect, Injector, runInInjectionContext, RendererStyleFlags2, PLATFORM_ID, ApplicationRef, RendererFactory2, model, ViewContainerRef, input, booleanAttribute, output, numberAttribute, Pipe, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
3
- import { takeUntilDestroyed, toObservable, toSignal, outputFromObservable } from '@angular/core/rxjs-interop';
4
- import { Subject, BehaviorSubject, debounceTime, combineLatest, map, merge, fromEvent, filter, tap, switchMap, startWith, of, timer, takeUntil, distinctUntilChanged, pairwise, take, Observable } from 'rxjs';
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 { isPlatformBrowser, DOCUMENT as DOCUMENT$1 } from '@angular/common';
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, 'transitionstart')).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')))
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: "21.2.1", ngImport: i0, type: AnimatableDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
81
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.1", type: AnimatableDirective, isStandalone: true, selector: "[etAnimatable]", providers: [
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: "21.2.1", ngImport: i0, type: AnimatableDirective, decorators: [{
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, ...(ngDevMode ? [{ debugName: "animatedValue" }] : []));
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 controlValueSignal = (control, options) => {
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
- * The first item in the pair is the previous value and the second item is the current value.
743
+ * Default viewport config based on Tailwind CSS.
744
+ * @see https://tailwindcss.com/docs/screens
742
745
  */
743
- const controlValueSignalWithPrevious = (control, options) => {
744
- const data = linkedSignal({ ...(ngDevMode ? { debugName: "data" } : {}), source: controlValueSignal(control, options),
745
- computation: (curr, prev) => [prev?.source ?? null, curr] });
746
- return data.asReadonly();
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, ...(ngDevMode ? [{ debugName: "isRendered" }] : []));
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, ...(ngDevMode ? [{ debugName: "value" }] : []));
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, ...(ngDevMode ? [{ debugName: "value" }] : []));
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 signalElementMutations = (el, options) => {
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 elementMutationsSignal = signal(null, ...(ngDevMode ? [{ debugName: "elementMutationsSignal" }] : []));
896
- const observer = new MutationObserver((e) => {
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
- zone.run(() => elementMutationsSignal.set(entry));
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
- elementMutationsSignal.set(null);
907
- if (els.previousElement) {
908
- observer.disconnect();
909
- }
910
- if (els.currentElement) {
911
- observer.observe(els.currentElement, options);
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 elementMutationsSignal.asReadonly();
1026
+ return computed(() => elementDimensionsSignal(), {
1027
+ equal: (a, b) => equal(a, b),
1028
+ });
916
1029
  };
917
- const signalHostElementMutations = (options) => signalElementMutations(inject(ElementRef), options);
918
-
919
- const signalElementChildren = (el) => {
920
- const elements = buildElementSignal(el);
921
- const firstEl = firstElementSignal(elements);
922
- const isRendered = signalIsRendered();
923
- const elementMutations = signalElementMutations(elements, { childList: true, subtree: true, attributes: true });
924
- return computed(() => {
925
- if (!isRendered())
926
- return [];
927
- const els = firstEl();
928
- // We are not interested what the mutation is, just that there is one.
929
- // Changes to the DOM may affect the children of the element.
930
- elementMutations();
931
- if (!els.currentElement)
932
- return [];
933
- const children = [];
934
- for (let index = 0; index < els.currentElement.children.length; index++) {
935
- const element = els.currentElement.children[index];
936
- if (element instanceof HTMLElement) {
937
- children.push(element);
938
- }
939
- }
940
- return children;
941
- }, { equal: (a, b) => a.length === b.length && a.every((v, i) => v === b[i]) });
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 buildSignalEffects = (el, config) => {
945
- const elements = buildElementSignal(el);
946
- const injector = inject(Injector);
947
- effect(() => {
948
- const { currentElements, previousElements } = elements();
949
- for (const previousEl of previousElements) {
950
- if (currentElements.includes(previousEl))
951
- continue;
952
- const tokens = Object.keys(config.tokenMap)
953
- .map((key) => key.split(' '))
954
- .flat();
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
- for (const currentEl of currentElements) {
960
- if (previousElements.includes(currentEl))
961
- continue;
962
- for (const [tokens, condition] of Object.entries(config.tokenMap)) {
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 effects = {};
973
- const has = (tokens) => tokens in effects;
974
- const push = (tokens, signal) => {
975
- if (has(tokens))
976
- return;
977
- runInInjectionContext(injector, () => {
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 boundingClientRectToElementRect = (rect) => ({
1079
- bottom: rect.bottom,
1080
- height: rect.height,
1081
- left: rect.left,
1082
- right: rect.right,
1083
- top: rect.top,
1084
- width: rect.width,
1085
- x: rect.x,
1086
- y: rect.y,
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 createElementDimensions = (el, rect) => {
1089
- if (!el) {
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
- rect: null,
1092
- client: null,
1093
- scroll: null,
1094
- offset: null,
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 cachedNormalizedRect = rect ? boundingClientRectToElementRect(rect) : null;
1098
- const rectFn = () => cachedNormalizedRect ? cachedNormalizedRect : boundingClientRectToElementRect(el.getBoundingClientRect());
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
- rect: rectFn,
1101
- client: { width: el.clientWidth, height: el.clientHeight },
1102
- scroll: { width: el.scrollWidth, height: el.scrollHeight },
1103
- offset: { width: el.offsetWidth, height: el.offsetHeight },
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 signalElementDimensions = (el) => {
1107
- const destroyRef = inject(DestroyRef);
1108
- const elements = buildElementSignal(el);
1109
- const firstEl = firstElementSignal(elements);
1110
- const zone = inject(NgZone);
1111
- const isRendered = signalIsRendered();
1112
- const initialValue = () => createElementDimensions(firstEl().currentElement);
1113
- const elementDimensionsSignal = signal(initialValue(), ...(ngDevMode ? [{ debugName: "elementDimensionsSignal" }] : []));
1114
- const observer = new ResizeObserver((e) => {
1115
- if (!isRendered())
1116
- return;
1117
- const entry = e[0];
1118
- if (entry) {
1119
- const target = entry.target;
1120
- const newDimensions = createElementDimensions(target);
1121
- zone.run(() => elementDimensionsSignal.set(newDimensions));
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
- effect(() => {
1125
- const els = firstEl();
1126
- untracked(() => {
1127
- elementDimensionsSignal.set(initialValue());
1128
- if (els.previousElement) {
1129
- observer.disconnect();
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
- if (els.currentElement) {
1132
- const computedDisplay = getComputedStyle(els.currentElement).display;
1133
- const currentElIsAngularComponent = els.currentElement?.tagName.toLowerCase().includes('-');
1134
- if (computedDisplay === 'inline' && isDevMode() && currentElIsAngularComponent) {
1135
- 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.`);
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
- observer.observe(els.currentElement);
1850
+ return { element: firstVisible.target, index: firstIndex, origin: 'start' };
1138
1851
  }
1139
- });
1140
- });
1141
- destroyRef.onDestroy(() => observer.disconnect());
1142
- return computed(() => elementDimensionsSignal(), {
1143
- equal: (a, b) => equal(a, b),
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([], ...(ngDevMode ? [{ debugName: "elementIntersectionSignal" }] : []));
1179
- const observer = signal(null, ...(ngDevMode ? [{ debugName: "observer" }] : []));
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, ...(ngDevMode ? [{ debugName: "lastScrollDirection" }] : []));
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
- }, ...(ngDevMode ? [{ debugName: "ref" }] : []));
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, ...(ngDevMode ? [{ debugName: "isDragging" }] : []));
1651
- const isInitDragging = signal(false, ...(ngDevMode ? [{ debugName: "isInitDragging" }] : []));
1652
- const initialDragPosition = signal({ x: 0, y: 0 }, ...(ngDevMode ? [{ debugName: "initialDragPosition" }] : []));
1653
- const initialScrollPosition = signal({ x: 0, y: 0 }, ...(ngDevMode ? [{ debugName: "initialScrollPosition" }] : []));
1654
- const dragAmount = signal({ x: 0, y: 0 }, ...(ngDevMode ? [{ debugName: "dragAmount" }] : []));
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
- }, ...(ngDevMode ? [{ debugName: "canScroll" }] : []));
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
- return linkedSignal({
1835
- source: event,
1836
- computation: (curr, prev) => {
1837
- if (curr instanceof NavigationEnd) {
1838
- return curr.urlAfterRedirects;
1839
- }
1840
- else if (curr instanceof NavigationSkipped) {
1841
- return curr.url;
1842
- }
1843
- else if (prev?.value) {
1844
- return prev.value;
1845
- }
1846
- return createInitialRoute();
1847
- },
1848
- }).asReadonly();
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
- const routerState = signal(createRouterState(router), ...(ngDevMode ? [{ debugName: "routerState" }] : []));
1884
- effect(() => {
1885
- const e = event();
1886
- untracked(() => {
1887
- if (e instanceof NavigationEnd && e.id === -1) {
1888
- return;
1889
- }
1890
- else {
1891
- routerState.set(createRouterState(router));
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, ...(ngDevMode ? [{ debugName: "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, ...(ngDevMode ? [{ debugName: "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, ...(ngDevMode ? [{ debugName: "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, ...(ngDevMode ? [{ debugName: "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, ...(ngDevMode ? [{ debugName: "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 state = injectRouterState();
2014
- const route = injectRoute();
2581
+ const router = inject(Router);
2015
2582
  const document = inject(DOCUMENT);
2016
- combineLatest([toObservable(state).pipe(pairwise()), toObservable(route).pipe(pairwise())])
2017
- .pipe(debounceTime(1))
2018
- .subscribe(([[prevState, currState], [prevRoute, currRoute]]) => {
2019
- const sameUrlNavigation = prevRoute === currRoute;
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, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
2644
+ const unescapeHtml = (str) => str
2645
+ .replace(/&amp;/g, '&')
2646
+ .replace(/&lt;/g, '<')
2647
+ .replace(/&gt;/g, '>')
2648
+ .replace(/&quot;/g, '"')
2649
+ .replace(/&#39;/g, "'")
2650
+ .replace(/&nbsp;/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, '![$2]($1)');
2794
+ md = md.replace(/<img[^>]+alt="([^"]*)"[^>]*src="([^"]*)"[^>]*\/?>/gi, '![$1]($2)');
2795
+ md = md.replace(/<img[^>]+src="([^"]*)"[^>]*\/?>/gi, '![]($1)');
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, devOnly = false, data = RUNTIME_ERROR_NO_DATA) {
2112
- super(formatRuntimeError(code, message, devOnly));
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, devOnly) {
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
- const devOnlyText = devOnly ? ' [DEV ONLY] ' : '';
2136
- return `${devOnlyText}${fullCode}${message ? ': ' + message : ''}`;
2906
+ return `${fullCode}${message ? ': ' + message : ''}`;
2137
2907
  }
2138
2908
 
2139
- /**
2140
- * Checks if an element or the viewport can scroll in a given direction.
2141
- * @param element The element to check. If null/undefined, checks if the viewport can scroll.
2142
- * @param direction The direction to check. If not provided, checks both directions.
2143
- * @returns true if the element or viewport can scroll in the given direction.
2144
- */
2145
- const elementCanScroll = (element, direction) => {
2146
- const el = element || document.documentElement;
2147
- const { scrollHeight, clientHeight, scrollWidth, clientWidth } = el;
2148
- if (direction === 'x') {
2149
- return scrollWidth > clientWidth;
2150
- }
2151
- else if (direction === 'y') {
2152
- return scrollHeight > clientHeight;
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
- return scrollHeight > clientHeight || scrollWidth > clientWidth;
2924
+ const locationPath = element.ownerDocument.defaultView?.location.pathname ?? 'root';
2925
+ return `${prefix}:${locationPath}:${pathSegments.join('/')}`;
2155
2926
  };
2156
- const createViewportRect = () => ({
2157
- left: 0,
2158
- top: 0,
2159
- right: window.innerWidth,
2160
- bottom: window.innerHeight,
2161
- width: window.innerWidth,
2162
- height: window.innerHeight,
2163
- x: 0,
2164
- y: 0,
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
- const elementRect = options.elementRect || element.getBoundingClientRect();
2173
- const containerRect = container ? options.containerRect || container.getBoundingClientRect() : createViewportRect();
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 getElementScrollCoordinates = (options) => {
2218
- const { container, element, direction, behavior = 'smooth', origin = 'nearest', scrollBlockMargin = 0, scrollInlineMargin = 0, } = options;
2219
- if (!element || !container || !elementCanScroll(container)) {
2220
- return {
2221
- behavior,
2222
- left: undefined,
2223
- top: undefined,
2224
- };
2941
+ const getSessionStorage = () => {
2942
+ if (!canUseSessionMemory()) {
2943
+ return null;
2225
2944
  }
2226
- const elementRect = element.getBoundingClientRect();
2227
- const containerRect = container.getBoundingClientRect();
2228
- const { scrollLeft, scrollTop } = container;
2229
- const elWidth = elementRect.width;
2230
- const elHeight = elementRect.height;
2231
- const elLeft = elementRect.left;
2232
- const elTop = elementRect.top;
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
- else if (isBelow || isPartialBelow || isRight || isPartialRight) {
2272
- calculateScrollToEnd();
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
- switch (origin) {
2276
- case 'start':
2277
- calculateScrollToStart();
2278
- break;
2279
- case 'end':
2280
- calculateScrollToEnd();
2281
- break;
2282
- case 'center':
2283
- calculateScrollToCenter();
2284
- break;
2285
- case 'nearest':
2286
- calculateScrollToNearest();
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 scrollToElement = (options) => {
2296
- options.container?.scrollTo(getElementScrollCoordinates(options));
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
- else {
2308
- setTimeout(poll, 25);
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
- value,
2322
- override,
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
- const [provideViewportConfig, injectViewportConfig] = createStaticRootProvider(DEFAULT_VIEWPORT_CONFIG, {
2341
- name: 'Viewport Config',
2342
- });
2343
- const [provideBreakpointObserver, injectBreakpointObserver] = createRootProvider(() => {
2344
- const breakpointObserver = inject(BreakpointObserver);
2345
- const viewportConfig = injectViewportConfig();
2346
- const isMediaQueryMatched = (mediaQuery) => breakpointObserver.isMatched(mediaQuery);
2347
- const observeMediaQuery = (mediaQuery) => {
2348
- return toSignal(breakpointObserver.observe(mediaQuery).pipe(map((x) => x.matches), startWith(isMediaQueryMatched(mediaQuery))), { requireSync: true });
2349
- };
2350
- const observeBreakpoint = (options) => observeMediaQuery(buildMediaQueryString(options));
2351
- const isBreakpointMatched = (options) => isMediaQueryMatched(buildMediaQueryString(options));
2352
- const getBreakpointSize = (type, option) => {
2353
- const index = option === 'min' ? 0 : 1;
2354
- const size = viewportConfig.breakpoints[type][index];
2355
- if (size === Infinity || size === 0) {
2356
- return size;
2357
- }
2358
- if (option === 'min') {
2359
- return size;
2360
- }
2361
- // Due to scaling, the actual size of the viewport may be a decimal number.
2362
- // Eg. on Windows 11 with 150% scaling, the viewport size may be 1535.33px
2363
- // and thus not matching any of the default breakpoints.
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
- mediaQueryParts.push(`(min-width: ${getBreakpointSize(options.min, 'min')}px)`);
3022
+ isSwiping = true;
2377
3023
  }
2378
3024
  }
2379
- if (options.min && options.max) {
2380
- mediaQueryParts.push('and');
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
- if (options.max) {
2383
- if (typeof options.max === 'number') {
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
- observeBreakpoint,
2394
- isBreakpointMatched,
2395
- getBreakpointSize,
2396
- buildMediaQueryString,
2397
- observeMediaQuery,
2398
- isMediaQueryMatched,
3088
+ value,
3089
+ override,
2399
3090
  };
2400
- }, { name: 'Breakpoint Observer' });
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, ...(ngDevMode ? [{ debugName: "isFocusVisible" }] : []));
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', ...(ngDevMode ? [{ debugName: "currentLocale" }] : []));
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, ...(ngDevMode ? [{ debugName: "skipNextEnter" }] : []));
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(() => onComplete()), take(1), takeUntil(cancelSignal), takeUntilDestroyed(this.destroyRef))
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
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: AnimatedLifecycleDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
2886
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.1", 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: [
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: "21.2.1", ngImport: i0, type: AnimatedLifecycleDirective, decorators: [{
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: "21.2.1", ngImport: i0, type: AnimatedIfDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
2941
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.1", type: AnimatedIfDirective, isStandalone: true, selector: "[etAnimatedIf]", inputs: { ifValue: { classPropertyName: "ifValue", publicName: "etAnimatedIf", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
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: "21.2.1", ngImport: i0, type: AnimatedIfDirective, decorators: [{
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', ...(ngDevMode ? [{ debugName: "placement" }] : []));
2973
- this.fallbackPlacements = input(...(ngDevMode ? [undefined, { debugName: "fallbackPlacements" }] : []));
2974
- this.offset = input(null, ...(ngDevMode ? [{ debugName: "offset" }] : []));
2975
- this.arrowPadding = input(4, ...(ngDevMode ? [{ debugName: "arrowPadding" }] : []));
2976
- this.viewportPadding = input(8, ...(ngDevMode ? [{ debugName: "viewportPadding" }] : []));
2977
- this.autoResize = input(false, { ...(ngDevMode ? { debugName: "autoResize" } : {}), transform: booleanAttribute });
2978
- this.shift = input(true, { ...(ngDevMode ? { debugName: "shift" } : {}), transform: booleanAttribute });
2979
- this.autoHide = input(false, { ...(ngDevMode ? { debugName: "autoHide" } : {}), transform: booleanAttribute });
2980
- this.autoCloseIfReferenceHidden = input(false, { ...(ngDevMode ? { debugName: "autoCloseIfReferenceHidden" } : {}), transform: booleanAttribute });
2981
- this.referenceElement = input(this.elementRef.nativeElement, ...(ngDevMode ? [{ debugName: "referenceElement" }] : []));
2982
- this.mirrorWidth = input(false, { ...(ngDevMode ? { debugName: "mirrorWidth" } : {}), transform: booleanAttribute });
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', ...(ngDevMode ? [{ debugName: "state" }] : []));
2991
- this.isMounted = computed(() => this.state() === 'mounted', ...(ngDevMode ? [{ debugName: "isMounted" }] : []));
2992
- this.isMounting = computed(() => this.state() === 'mounting', ...(ngDevMode ? [{ debugName: "isMounting" }] : []));
2993
- this.isUnmounted = computed(() => this.state() === 'unmounted', ...(ngDevMode ? [{ debugName: "isUnmounted" }] : []));
2994
- this.isUnmounting = computed(() => this.state() === 'unmounting', ...(ngDevMode ? [{ debugName: "isUnmounting" }] : []));
2995
- this.canMount = computed(() => !this.isMounted() && !this.isMounting(), ...(ngDevMode ? [{ debugName: "canMount" }] : []));
2996
- this.canUnmount = computed(() => (this.isMounted() || this.isMounting()) && !this.isUnmounting(), ...(ngDevMode ? [{ debugName: "canUnmount" }] : []));
2997
- this.isHidden = signal(false, ...(ngDevMode ? [{ debugName: "isHidden" }] : []));
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.applyThemeProvider(config.themeProvider);
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, themeProvider } = config;
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.applyThemeProvider(themeProvider);
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
- applyThemeProvider(themeProvider) {
3108
- if (!this.componentRef || !themeProvider)
3932
+ applyColorProvider(colorProvider) {
3933
+ if (!this.componentRef || !colorProvider)
3109
3934
  return;
3110
- this.componentRef.instance.setThemeFromProvider(themeProvider);
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: "21.2.1", ngImport: i0, type: AnimatedOverlayDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
3249
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.1", 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 }); }
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: "21.2.1", ngImport: i0, type: AnimatedOverlayDirective, decorators: [{
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: "21.2.1", ngImport: i0, type: ClickOutsideDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
3375
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.1", type: ClickOutsideDirective, isStandalone: true, selector: "[etClickOutside]", outputs: { didClickOutside: "etClickOutside" }, ngImport: i0 }); }
3376
- }
3377
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: ClickOutsideDirective, decorators: [{
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
- class RepeatDirective {
3385
- constructor() {
3386
- this.mainTemplateRef = inject(TemplateRef);
3387
- this.viewContainerRef = inject(ViewContainerRef);
3388
- this.repeatCount = input(2, { ...(ngDevMode ? { debugName: "repeatCount" } : {}), alias: 'etRepeat', transform: numberAttribute });
3389
- this.views = linkedSignal({ ...(ngDevMode ? { debugName: "views" } : {}), source: this.repeatCount,
3390
- computation: (count, previous) => {
3391
- const prevCount = previous?.source ?? 0;
3392
- const views = previous?.value ?? [];
3393
- if (count === prevCount && previous?.value) {
3394
- return previous.value;
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
- const viewsToCreate = count - prevCount;
3397
- if (viewsToCreate > 0) {
3398
- for (let i = 0; i < viewsToCreate; i++) {
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
- else if (viewsToCreate < 0) {
3403
- for (let i = 0; i < -viewsToCreate; i++) {
3404
- this.viewContainerRef.remove(this.viewContainerRef.length - 1);
3405
- }
3406
- views.splice(viewsToCreate);
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
- return views;
3409
- } });
3410
- // Ugly but needed to trigger the linked signal.
3411
- // Otherwise it has no consumers and won't run.
3412
- effect(() => this.views());
3413
- }
3414
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: RepeatDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
3415
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.1", type: RepeatDirective, isStandalone: true, selector: "[etRepeat]", inputs: { repeatCount: { classPropertyName: "repeatCount", publicName: "etRepeat", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); }
3416
- }
3417
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: RepeatDirective, decorators: [{
3418
- type: Directive,
3419
- args: [{
3420
- selector: '[etRepeat]',
3421
- }]
3422
- }], ctorParameters: () => [], propDecorators: { repeatCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "etRepeat", required: false }] }] } });
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: "21.2.1", ngImport: i0, type: NormalizeGameResultTypePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
3429
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.1", ngImport: i0, type: NormalizeGameResultTypePipe, isStandalone: true, name: "etNormalizeGameResultType" }); }
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: "21.2.1", ngImport: i0, type: NormalizeGameResultTypePipe, decorators: [{
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: "21.2.1", ngImport: i0, type: NormalizeMatchStatePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
3474
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.1", ngImport: i0, type: NormalizeMatchStatePipe, isStandalone: true, name: "etNormalizeMatchState" }); }
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: "21.2.1", ngImport: i0, type: NormalizeMatchStatePipe, decorators: [{
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: "21.2.1", ngImport: i0, type: NormalizeMatchParticipantsPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
3504
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.1", ngImport: i0, type: NormalizeMatchParticipantsPipe, isStandalone: true, name: "etNormalizeMatchParticipants" }); }
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: "21.2.1", ngImport: i0, type: NormalizeMatchParticipantsPipe, decorators: [{
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: "21.2.1", ngImport: i0, type: NormalizeMatchScorePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
3561
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.1", ngImport: i0, type: NormalizeMatchScorePipe, isStandalone: true, name: "etNormalizeMatchScore" }); }
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: "21.2.1", ngImport: i0, type: NormalizeMatchScorePipe, decorators: [{
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: "21.2.1", ngImport: i0, type: NormalizeMatchTypePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
3697
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.1", ngImport: i0, type: NormalizeMatchTypePipe, isStandalone: true, name: "etNormalizeMatchType" }); }
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: "21.2.1", ngImport: i0, type: NormalizeMatchTypePipe, decorators: [{
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: "21.2.1", ngImport: i0, type: InferMimeTypePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
3746
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.1", ngImport: i0, type: InferMimeTypePipe, isStandalone: true, name: "inferMimeType" }); }
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: "21.2.1", ngImport: i0, type: InferMimeTypePipe, decorators: [{
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: "21.2.1", ngImport: i0, type: ToArrayPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
3955
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.1", ngImport: i0, type: ToArrayPipe, isStandalone: true, name: "toArray" }); }
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: "21.2.1", ngImport: i0, type: ToArrayPipe, decorators: [{
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
- }, ...(ngDevMode ? [{ debugName: "firstElement" }] : []));
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
- }, ...(ngDevMode ? [{ debugName: "firstId" }] : []));
3994
- const ids = computed(() => dictionary.ids(), ...(ngDevMode ? [{ debugName: "ids" }] : []));
3995
- const elements = computed(() => ids().map((id) => dictionary.elements()[id]), ...(ngDevMode ? [{ debugName: "elements" }] : []));
3996
- const isEmpty = computed(() => dictionary.ids().length === 0, ...(ngDevMode ? [{ debugName: "isEmpty" }] : []));
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(), ...(ngDevMode ? [{ debugName: "attached" }] : []));
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: "21.2.1", ngImport: i0, type: PropsDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4184
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.1", type: PropsDirective, isStandalone: true, selector: "[etProps]", inputs: { props: { classPropertyName: "props", publicName: "etProps", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 }); }
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: "21.2.1", ngImport: i0, type: PropsDirective, decorators: [{
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()) ?? [], ...(ngDevMode ? [{ debugName: "valuesList" }] : []));
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(), ...(ngDevMode ? [{ debugName: "linksByKey" }] : []));
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(), ...(ngDevMode ? [{ debugName: "titleParts" }] : []));
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
- }, ...(ngDevMode ? [{ debugName: "title" }] : []));
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(), ...(ngDevMode ? [{ debugName: "metaTagsBySelector" }] : []));
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: "21.2.1", ngImport: i0, type: SeoDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
5029
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.1", type: SeoDirective, isStandalone: true, providers: [{ provide: SEO_DIRECTIVE_TOKEN, useExisting: SeoDirective }], ngImport: i0 }); }
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: "21.2.1", ngImport: i0, type: SeoDirective, decorators: [{
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(), ...(ngDevMode ? [{ debugName: "scripts" }] : []));
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, ...(ngDevMode ? [{ debugName: "data" }] : []));
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
- }, ...(ngDevMode ? [{ debugName: "jsonLD" }] : []));
6766
+ }, /* @ts-ignore */
6767
+ ...(ngDevMode ? [{ debugName: "jsonLD" }] : /* istanbul ignore next */ []));
5096
6768
  }
5097
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: StructuredDataComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
5098
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.1", 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 }); }
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: "21.2.1", ngImport: i0, type: StructuredDataComponent, decorators: [{
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
- const createCssThemeName = (name) => name.replace(/([A-Z])/g, (g) => `-${g[0].toLowerCase()}`);
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 [ɵProvideThemesPrefix, injectThemesPrefix] = createStaticProvider('et', { name: 'Themes Prefix' });
6918
+ const [ɵProvideColorThemesPrefix, injectColorThemesPrefix] = createStaticProvider('et', {
6919
+ name: 'Themes Prefix',
6920
+ });
5119
6921
  const provideColorThemesWithTailwind4 = (themes, prefix = 'et') => [
5120
- ɵProvideColorThemes(themes.map((theme) => theme.name)),
5121
- ɵProvideThemesPrefix(prefix),
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 = createCssThemeName(theme.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 = createCssThemeName(theme.name);
5194
- const stringSuffix = isAlt ? '-alt' : '';
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', `.et-theme${stringSuffix}--default`]
7041
+ ? [':root', `.${classPrefix}--default`]
5198
7042
  : []),
5199
- `.et-theme${stringSuffix}--${cssThemeName}`,
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 = `et-theme${stringSuffix}--${cssThemeName}`;
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.map((theme) => theme.name)), ɵProvideThemesPrefix('et')];
7131
+ return [ɵProvideColorThemes(themes), ɵProvideColorThemesPrefix('et')];
5271
7132
  };
5272
7133
 
5273
- const THEME_PROVIDER = new InjectionToken('ThemeProvider');
5274
- class ProvideThemeDirective {
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 = injectThemesPrefix({ optional: true });
7139
+ this.prefix = injectColorThemesPrefix({ optional: true });
5278
7140
  this.injector = inject(Injector);
5279
7141
  this.currentProviderSync = null;
5280
- this.mainTheme = input(undefined, { ...(ngDevMode ? { debugName: "mainTheme" } : {}), alias: 'etProvideTheme' });
5281
- this.altTheme = input(undefined, { ...(ngDevMode ? { debugName: "altTheme" } : {}), alias: 'etProvideAltTheme' });
5282
- this.mainThemeName = computed(() => {
5283
- const value = this.mainTheme();
5284
- if (!this.themes || !value)
5285
- return;
5286
- if (isDevMode() && !this.themes?.some((theme) => theme === value) && value !== null) {
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 createCssThemeName(value);
5290
- }, ...(ngDevMode ? [{ debugName: "mainThemeName" }] : []));
5291
- this.altThemeName = computed(() => {
5292
- const value = this.altTheme();
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?.some((theme) => theme === value) && value !== null) {
5296
- console.warn(`Theme ${value} does not exist. Please make sure to add it to provideColorThemes()`);
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 createCssThemeName(value);
5299
- }, ...(ngDevMode ? [{ debugName: "altThemeName" }] : []));
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.mainThemeName()) {
5304
- themes.push(`${prefix}-theme--${this.mainThemeName()}`);
7166
+ if (this.colorName()) {
7167
+ return `${prefix}-color--${this.colorName()}`;
5305
7168
  }
5306
- if (this.altThemeName()) {
5307
- themes.push(`${prefix}-theme-alt--${this.altThemeName()}`);
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 provideMainTheme = provider.mainTheme();
5317
- const provideAltTheme = provider.altTheme();
7177
+ const provideColor = provider.effectiveColor();
5318
7178
  untracked(() => {
5319
- setInputSignal(this.mainTheme, provideMainTheme);
5320
- setInputSignal(this.altTheme, provideAltTheme);
7179
+ if (provideColor === undefined) {
7180
+ this.clearForcedColor();
7181
+ return;
7182
+ }
7183
+ this.forceColor(provideColor);
5321
7184
  });
5322
- }, ...(ngDevMode ? [{ debugName: "currentProviderSync" }] : []));
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: "21.2.1", ngImport: i0, type: ProvideThemeDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
5330
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.1", type: ProvideThemeDirective, isStandalone: true, selector: "[etProvideTheme]", inputs: { mainTheme: { classPropertyName: "mainTheme", publicName: "etProvideTheme", isSignal: true, isRequired: false, transformFunction: null }, altTheme: { classPropertyName: "altTheme", publicName: "etProvideAltTheme", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "themeClass()" } }, providers: [{ provide: THEME_PROVIDER, useExisting: ProvideThemeDirective }], ngImport: i0 }); }
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: "21.2.1", ngImport: i0, type: ProvideThemeDirective, decorators: [{
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: '[etProvideTheme]',
5336
- providers: [{ provide: THEME_PROVIDER, useExisting: ProvideThemeDirective }],
7214
+ selector: '[etProvideColor]',
7215
+ providers: [{ provide: COLOR_PROVIDER, useExisting: ProvideColorDirective }],
5337
7216
  host: {
5338
7217
  '[class]': 'themeClass()',
5339
7218
  },
5340
7219
  }]
5341
- }], propDecorators: { mainTheme: [{ type: i0.Input, args: [{ isSignal: true, alias: "etProvideTheme", required: false }] }], altTheme: [{ type: i0.Input, args: [{ isSignal: true, alias: "etProvideAltTheme", required: false }] }] } });
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, ProvideThemeDirective, RUNTIME_ERROR_NO_DATA, RepeatDirective, RuntimeError, SEO_DIRECTIVE_TOKEN, SeoDirective, StructuredDataComponent, THEME_PROVIDER, ToArrayPipe, TypedQueryList, ValidateAtLeastOneRequired, Validators, applyAlternateBinding, applyAlternateLanguagesBindings, applyArticleBindings, applyAuthorBinding, applyCanonicalBinding, applyDescriptionBinding, applyHeadBinding, applyHeadTitleBinding, applyHostListener, applyHostListeners, applyKeywordsBinding, applyLinkBinding, applyMetaBinding, applyNextBinding, applyOgBinding, applyOpenGraphBindings, applyPrevBinding, applyResourceHintsBindings, applyRobotsBinding, applySocialMediaBindings, applyStructuredDataBinding, applyTwitterCardBindings, areScrollStatesEqual, bindProps, boundingClientRectToElementRect, buildElementSignal, buildSignalEffects, clamp, clone, cloneFormGroup, computedTillFalsy, computedTillTruthy, controlValueSignal, controlValueSignalWithPrevious, createArrayPropertyBinding, createBulkPropertyBinding, createCanAnimateSignal, createComponentId, createCssThemeName, createDependencyStash, createDestroy, createDocumentElementSignal, createElementDictionary, createElementDimensions, createEmptyElementSignal, createFlipAnimation, createFlipAnimationGroup, createHostProps, createIsRenderedSignal, createLogger, createPropHandlers, createPropertyBinding, createProps, createProvider, createRootProvider, createRootThemeCss, createRxHostListener, createSetup, createStaticProvider, createStaticRootProvider, createSwatchCss, createTailwindColorThemes, createTailwindCssVar, createTailwindRgbVar, createThemeStyle, deferredSignal, deleteCookie, easeElastic, easeIn, easeInOut, easeLinear, easeOut, easeOutBack, easeOutBackStrong, elementCanScroll, equal, firstElementSignal, forceReflow, formatRuntimeError, fromNextFrame, getCookie, getDomain, getElementScrollCoordinates, getFormGroupValue, getGroupMatchPoints, getGroupMatchScore, getKnockoutMatchScore, getMatchScoreSubLine, getObjectProperty, hasCookie, inferMimeType, injectAngularRootElement, injectBoundaryElement, injectBreakpointIsMatched, injectBreakpointObserver, injectCanHover, injectColorThemes, injectCurrentBreakpoint, injectDeviceInputType, injectDisplayOrientation, injectFocusVisibleTracker, injectFragment, injectHasPrecisionInput, injectHasTouchInput, injectHostElement, injectIs2Xl, injectIsLandscape, injectIsLg, injectIsMd, injectIsPortrait, injectIsRouterInitialized, injectIsSm, injectIsXl, injectIsXs, injectLinkStore, injectLinkStoreConfig, injectLocale, injectMediaQueryIsMatched, injectMetaConfig, injectMetaStore, injectObserveBreakpoint, injectObserveMediaQuery, injectPathParam, injectPathParamChanges, injectPathParams, injectQueryParam, injectQueryParamChanges, injectQueryParams, injectRenderer, injectRoute, injectRouteData, injectRouteDataItem, injectRouteTitle, injectRouterEvent, injectRouterState, injectScrollbarDimensions, injectStructuredDataConfig, injectStructuredDataStore, injectTemplateRef, injectThemesPrefix, injectTitleConfig, injectTitleStore, injectUrl, injectViewportConfig, injectViewportDimensions, isArray, isElementSignal, isElementVisible, isGroupMatch, isKnockoutMatch, isObject, maybeSignalValue, memoizeSignal, nextFrame, normalizeGameResultType, normalizeMatchParticipant, normalizeMatchParticipants, normalizeMatchScore, normalizeMatchState, normalizeMatchType, previousSignalValue, provideBoundaryElement, provideBreakpointObserver, provideColorThemes, provideColorThemesWithTailwind4, provideFocusVisibleTracker, provideLinkStore, provideLinkStoreConfig, provideLocale, provideMetaConfig, provideMetaStore, provideRenderer, provideStructuredDataConfig, provideStructuredDataStore, provideTitleConfig, provideTitleStore, provideViewportConfig, round, routerDisableScrollTop, scrollToElement, setCookie, setInputSignal, 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, unbindProps, useCursorDragScroll, writeScrollbarSizeToCssVariables, writeViewportSizeToCssVariables, ɵProvideColorThemes, ɵProvideThemesPrefix };
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