@ethlete/core 5.0.0-next.30 → 5.0.0-next.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # @ethlete/core
2
2
 
3
+ ## 5.0.0-next.32
4
+
5
+ ### Patch Changes
6
+
7
+ - [`ed58b19`](https://github.com/ethlete-io/ethdk/commit/ed58b19b1957f2051e0f1ef68c3814747af9ccd0) Thanks [@TomTomB](https://github.com/TomTomB)! - `etAutoSurface`: opening an overlay (date-picker, select, menu, …) no longer elevates unrelated surfaces on the base page. The overlay surface-context tracker is now matched by DOM containment, so an `etAutoSurface` only adopts an overlay's elevation when it actually renders inside that overlay's pane.
8
+
9
+ ## 5.0.0-next.31
10
+
11
+ ### Minor Changes
12
+
13
+ - [#3030](https://github.com/ethlete-io/ethdk/pull/3030) [`1a6849f`](https://github.com/ethlete-io/ethdk/commit/1a6849fa37e8f6907d08766846a50d3d9de8211b) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add the `unsavedChanges` family for guarding forms against accidental discard, and a close-veto seam in the overlay runtime that powers it.
14
+ - `createUnsavedChangesTracker` — snapshots a default value, tracks whether the watched form/value differs from it (deep-equal snapshot semantics, not signal-forms `dirty()`), and normalizes an async `confirm` (value / Promise / Observable) to a `Promise<boolean>`. Signal-forms `FieldTree` is the first-class source; `Signal<FieldTree | null>` (late/async forms), `AbstractControl` (migration), and `WritableSignal` (escape hatch) are also supported. Includes `refreshDefaultValue` (re-baseline after a save-and-keep-open) and `restoreDefaultValue`.
15
+ - `createUnsavedChangesGuard` — the router/manual flavor, adding a `canDeactivate` bridge for Angular route guards.
16
+ - Overlay runtime: `overlayRef.registerCloseGuard(guard)` (synchronous veto for pending closes, returns an unregister fn) and `overlayRef.forceClose(result?, source?)` (commit a close bypassing guards). `reference-detached` closes always bypass guards. This is the seam `createOverlayUnsavedChangesGuard` in `@ethlete/components` builds on.
17
+
18
+ ### Patch Changes
19
+
20
+ - [#3030](https://github.com/ethlete-io/ethdk/pull/3030) [`4d70fb1`](https://github.com/ethlete-io/ethdk/commit/4d70fb1fd173e7e9d25031551f752196abb6f94e) Thanks [@github-actions](https://github.com/apps/github-actions)! - `etAutoSurface` now elevates correctly for content rendered inside an overlay. Projected/portaled content keeps the injector of where it was _declared_ (the trigger location), not the pane it renders into, so an `etAutoSurface` inside a select body, menu, date-picker, etc. resolved its parent surface from the outer trigger context and came out one elevation too low — the same level as the overlay's own panel instead of one above it.
21
+
22
+ `AutoSurfaceDirective` now also consults the root surface-context tracker (which records the innermost open overlay's surface across the portal boundary) and takes whichever parent surface sits higher. Overlay panels that are themselves the overlay's surface (menu, select/date/cascader panels, tooltip, toggletip) opt out via the new `AutoSurfaceDirective.ignoreOverlaySurfaceContext()` so they keep adopting their overlay's elevation rather than stacking above it — their rendered surface is unchanged.
23
+
24
+ - [`eee0451`](https://github.com/ethlete-io/ethdk/commit/eee0451642bfbce97991e539b938fc7c4c84e846) Thanks [@TomTomB](https://github.com/TomTomB)! - `ColorInteractiveDirective`: a readonly control (`aria-readonly="true"`) now keeps its resting accent — hover/active/focus no longer retint it, matching the view-only intent (previously a readonly switch still showed a press color shift).
25
+
26
+ - [#3030](https://github.com/ethlete-io/ethdk/pull/3030) [`008fca5`](https://github.com/ethlete-io/ethdk/commit/008fca57ad434e6d996b1af21f95c55902f74dcd) Thanks [@github-actions](https://github.com/apps/github-actions)! - `ColorInteractiveHasFocusDirective` (`[etColorInteractiveHasFocus]`) now resolves the theme's **base** accent while a descendant is `:focus-visible`, instead of the `-focus` variant. A container merely mirroring a child's focus (e.g. a form field's frame) should read as the plain accent color; the `-focus` variant remains reserved for an element that is itself focused (`[etColorInteractive]:focus-visible`). Effect: focused form fields now paint their focus border/label in the base accent rather than the focus-adjusted shade.
27
+
3
28
  ## 5.0.0-next.30
4
29
 
5
30
  ### Patch Changes
@@ -1,7 +1,7 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { InjectionToken, inject, ElementRef, Directive, assertInInjectionContext, DestroyRef, TemplateRef, QueryList, RendererFactory2, RendererStyleFlags2, isSignal, DOCUMENT, signal, linkedSignal, isDevMode, computed, afterNextRender, effect, NgZone, untracked, EnvironmentInjector, runInInjectionContext, Injector, booleanAttribute, numberAttribute, PLATFORM_ID, ApplicationRef, createComponent, model, ViewContainerRef, input, output, Pipe, ViewEncapsulation, Component } from '@angular/core';
3
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, defer, from, catchError, timer, takeUntil, pairwise, distinctUntilChanged, take, Observable, concatMap, EMPTY, concat, exhaustMap, share } from 'rxjs';
4
+ import { Subject, BehaviorSubject, debounceTime, combineLatest, map, merge, fromEvent, filter, tap, switchMap, startWith, of, defer, from, catchError, timer, takeUntil, pairwise, distinctUntilChanged, take, Observable, concatMap, EMPTY, concat, exhaustMap, share, isObservable, firstValueFrom, defaultIfEmpty } from 'rxjs';
5
5
  import { FormGroup, FormArray, FormControl } from '@angular/forms';
6
6
  import { SIGNAL, signalSetFn } from '@angular/core/primitives/signals';
7
7
  import { coerceElement } from '@angular/cdk/coercion';
@@ -5081,6 +5081,7 @@ const createOverlayRuntimeRef = (id, config, elements, requestClose) => {
5081
5081
  const afterOpenedSubject = new Subject();
5082
5082
  const beforeClosedSubject = new Subject();
5083
5083
  const afterClosedSubject = new Subject();
5084
+ const closeGuards = new Set();
5084
5085
  return {
5085
5086
  id,
5086
5087
  config,
@@ -5093,8 +5094,29 @@ const createOverlayRuntimeRef = (id, config, elements, requestClose) => {
5093
5094
  if (_state() === 'closing' || _state() === 'closed') {
5094
5095
  return;
5095
5096
  }
5097
+ // `reference-detached` is a forced teardown (the anchor is gone) — never vetoable.
5098
+ if (source !== 'reference-detached') {
5099
+ for (const guard of closeGuards) {
5100
+ if (!guard({ result, source })) {
5101
+ return;
5102
+ }
5103
+ }
5104
+ }
5096
5105
  requestClose(result, source);
5097
5106
  },
5107
+ /** Close bypassing every registered close guard — used by a guard's owner to commit a
5108
+ * close it previously vetoed (e.g. after an async confirm resolved). */
5109
+ forceClose(result, source = 'api') {
5110
+ if (_state() === 'closing' || _state() === 'closed') {
5111
+ return;
5112
+ }
5113
+ requestClose(result, source);
5114
+ },
5115
+ /** Register a synchronous veto for pending closes. Returns an unregister function. */
5116
+ registerCloseGuard(guard) {
5117
+ closeGuards.add(guard);
5118
+ return () => closeGuards.delete(guard);
5119
+ },
5098
5120
  beforeOpened() {
5099
5121
  return beforeOpenedSubject.asObservable();
5100
5122
  },
@@ -7296,11 +7318,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
7296
7318
 
7297
7319
  class ColorInteractiveStylesComponent {
7298
7320
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ColorInteractiveStylesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7299
- 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))}@media(hover:hover){: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"], encapsulation: i0.ViewEncapsulation.None }); }
7321
+ 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))}@media(hover:hover){: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);--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[aria-readonly=true]){--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[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"], encapsulation: i0.ViewEncapsulation.None }); }
7300
7322
  }
7301
7323
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: ColorInteractiveStylesComponent, decorators: [{
7302
7324
  type: Component,
7303
- args: [{ selector: 'et-color-interactive-styles', template: '', encapsulation: ViewEncapsulation.None, 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))}@media(hover:hover){: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"] }]
7325
+ args: [{ selector: 'et-color-interactive-styles', template: '', encapsulation: ViewEncapsulation.None, 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))}@media(hover:hover){: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);--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[aria-readonly=true]){--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[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"] }]
7304
7326
  }] });
7305
7327
 
7306
7328
  /**
@@ -7365,6 +7387,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
7365
7387
  * NOT react to incidental mouse interaction with unrelated nested widgets (a toolbar button, a
7366
7388
  * rendered link) that happen to live inside the same wrapper.
7367
7389
  *
7390
+ * The color it resolves to is the theme's BASE accent, not the `-focus` variant: the `-focus`
7391
+ * shade is the treatment for an element that is itself focused, whereas a container only mirroring
7392
+ * a child's focus should read as the plain accent color.
7393
+ *
7368
7394
  * Deliberately does NOT also carry `ColorInteractiveDirective`'s `et-color-interactive` class:
7369
7395
  * that class's plain `:hover`/`:active` rules locally override the same (inheriting)
7370
7396
  * `--et-theme-color-primary-rgb`, so anything bubbling up from ANYWHERE in the subtree would
@@ -7538,24 +7564,105 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
7538
7564
  }]
7539
7565
  }], propDecorators: { surface: [{ type: i0.Input, args: [{ isSignal: true, alias: "etProvideSurface", required: false }] }] } });
7540
7566
 
7567
+ let uniqueId = 0;
7568
+ const [provideSurfaceContextTracker, injectSurfaceContextTracker] = createRootProvider(() => {
7569
+ const entries = signal([], /* @ts-ignore */
7570
+ ...(ngDevMode ? [{ debugName: "entries" }] : /* istanbul ignore next */ []));
7571
+ const topEntry = computed(() => {
7572
+ const stack = entries();
7573
+ return stack.length > 0 ? (stack[stack.length - 1] ?? null) : null;
7574
+ }, /* @ts-ignore */
7575
+ ...(ngDevMode ? [{ debugName: "topEntry" }] : /* istanbul ignore next */ []));
7576
+ const topType = computed(() => topEntry()?.type ?? null, /* @ts-ignore */
7577
+ ...(ngDevMode ? [{ debugName: "topType" }] : /* istanbul ignore next */ []));
7578
+ const topElevation = computed(() => topEntry()?.elevation ?? 0, /* @ts-ignore */
7579
+ ...(ngDevMode ? [{ debugName: "topElevation" }] : /* istanbul ignore next */ []));
7580
+ const register = (type, elevation, element) => {
7581
+ const id = `surface-ctx-${uniqueId++}`;
7582
+ const entry = { id, type, elevation, element };
7583
+ entries.update((e) => [...e, entry]);
7584
+ return () => {
7585
+ entries.update((e) => e.filter((item) => item.id !== id));
7586
+ };
7587
+ };
7588
+ const surfaceForElement = (host) => {
7589
+ const stack = entries();
7590
+ // Walk newest-first so the innermost overlay containing `host` wins.
7591
+ for (let i = stack.length - 1; i >= 0; i--) {
7592
+ const entry = stack[i];
7593
+ if (entry && entry.element.contains(host)) {
7594
+ return { type: entry.type, elevation: entry.elevation };
7595
+ }
7596
+ }
7597
+ return null;
7598
+ };
7599
+ return { topType, topElevation, register, surfaceForElement };
7600
+ }, { name: 'SurfaceContextTracker' });
7601
+
7541
7602
  class AutoSurfaceDirective {
7603
+ /**
7604
+ * Opt this auto-surface out of the overlay surface-context tracker. An overlay
7605
+ * *panel* (menu, select/date/cascader panel, tooltip, toggletip) is its overlay's
7606
+ * own painted surface, so it must adopt the overlay elevation from its injector or
7607
+ * explicit `surfaceProvider` — not stack a level above it. The tracker exists for
7608
+ * content rendered *inside* such a panel, whose injector points back at the trigger
7609
+ * location and therefore cannot see the overlay it visually lives in.
7610
+ */
7611
+ ignoreOverlaySurfaceContext() {
7612
+ this.consultsOverlayContext.set(false);
7613
+ }
7542
7614
  constructor() {
7543
7615
  this.ownSurfaceProvider = inject(ProvideSurfaceDirective);
7544
7616
  this.contextSurfaceProvider = inject(SURFACE_PROVIDER, { optional: true, skipSelf: true });
7545
7617
  this.surfaceThemes = injectSurfaceThemes({ optional: true });
7618
+ this.surfaceContextTracker = injectSurfaceContextTracker();
7619
+ this.elementRef = inject(ElementRef);
7546
7620
  /**
7547
7621
  * Explicit surface provider to resolve the surface relative to. Falls back to the
7548
7622
  * surface provider from the surrounding (trigger) context when not set.
7549
7623
  */
7550
7624
  this.surfaceProvider = input(null, /* @ts-ignore */
7551
7625
  ...(ngDevMode ? [{ debugName: "surfaceProvider" }] : /* istanbul ignore next */ []));
7626
+ // Overlay panels that ARE their overlay's own surface opt out (see
7627
+ // ignoreOverlaySurfaceContext) so they adopt the overlay elevation from their
7628
+ // injector/explicit context instead of stacking one level above it.
7629
+ this.consultsOverlayContext = signal(true, /* @ts-ignore */
7630
+ ...(ngDevMode ? [{ debugName: "consultsOverlayContext" }] : /* istanbul ignore next */ []));
7552
7631
  this.resolvedSurface = computed(() => {
7553
7632
  const themes = this.surfaceThemes;
7554
- const parentSurfaceProvider = this.surfaceProvider() ?? this.contextSurfaceProvider ?? null;
7555
- if (!themes || !parentSurfaceProvider) {
7633
+ if (!themes) {
7556
7634
  return null;
7557
7635
  }
7558
- return (resolveSurfaceByElevation(themes, parentSurfaceProvider.surfaceType() ?? 'dark', parentSurfaceProvider.elevation() + 1)?.name ?? null);
7636
+ const contextProvider = this.surfaceProvider() ?? this.contextSurfaceProvider ?? null;
7637
+ const contextElevation = contextProvider?.elevation() ?? null;
7638
+ const contextType = contextProvider?.surfaceType() ?? null;
7639
+ // An overlay's projected/portaled content keeps the injector of where it was
7640
+ // *declared* (the trigger location), not the pane it renders into — so the
7641
+ // injector-derived parent surface is one elevation too low. The surface-context
7642
+ // tracker records each open overlay's surface *and* its pane element, so we consult
7643
+ // only the overlay whose pane actually contains this element in the DOM (portaling
7644
+ // moves the DOM into the pane even though the injector stays at the trigger). An
7645
+ // auto-surface on the base page therefore stays put when an overlay opens elsewhere.
7646
+ // Panels that are themselves the overlay's surface opt out via ignoreOverlaySurfaceContext().
7647
+ const overlaySurface = this.consultsOverlayContext()
7648
+ ? this.surfaceContextTracker.surfaceForElement(this.elementRef.nativeElement)
7649
+ : null;
7650
+ const overlayElevation = overlaySurface?.elevation ?? null;
7651
+ const overlayType = overlaySurface?.type ?? null;
7652
+ let parentElevation;
7653
+ let parentType;
7654
+ if (overlayElevation !== null && (contextElevation === null || overlayElevation > contextElevation)) {
7655
+ parentElevation = overlayElevation;
7656
+ parentType = overlayType ?? contextType ?? 'dark';
7657
+ }
7658
+ else if (contextElevation !== null) {
7659
+ parentElevation = contextElevation;
7660
+ parentType = contextType ?? overlayType ?? 'dark';
7661
+ }
7662
+ else {
7663
+ return null;
7664
+ }
7665
+ return resolveSurfaceByElevation(themes, parentType, parentElevation + 1)?.name ?? null;
7559
7666
  }, /* @ts-ignore */
7560
7667
  ...(ngDevMode ? [{ debugName: "resolvedSurface" }] : /* istanbul ignore next */ []));
7561
7668
  effect(() => {
@@ -7920,30 +8027,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
7920
8027
  }]
7921
8028
  }], propDecorators: { color: [{ type: i0.Input, args: [{ isSignal: true, alias: "etProvideColor", required: false }] }] } });
7922
8029
 
7923
- let uniqueId = 0;
7924
- const [provideSurfaceContextTracker, injectSurfaceContextTracker] = createRootProvider(() => {
7925
- const entries = signal([], /* @ts-ignore */
7926
- ...(ngDevMode ? [{ debugName: "entries" }] : /* istanbul ignore next */ []));
7927
- const topEntry = computed(() => {
7928
- const stack = entries();
7929
- return stack.length > 0 ? (stack[stack.length - 1] ?? null) : null;
7930
- }, /* @ts-ignore */
7931
- ...(ngDevMode ? [{ debugName: "topEntry" }] : /* istanbul ignore next */ []));
7932
- const topType = computed(() => topEntry()?.type ?? null, /* @ts-ignore */
7933
- ...(ngDevMode ? [{ debugName: "topType" }] : /* istanbul ignore next */ []));
7934
- const topElevation = computed(() => topEntry()?.elevation ?? 0, /* @ts-ignore */
7935
- ...(ngDevMode ? [{ debugName: "topElevation" }] : /* istanbul ignore next */ []));
7936
- const register = (type, elevation) => {
7937
- const id = `surface-ctx-${uniqueId++}`;
7938
- const entry = { id, type, elevation };
7939
- entries.update((e) => [...e, entry]);
7940
- return () => {
7941
- entries.update((e) => e.filter((item) => item.id !== id));
7942
- };
7943
- };
7944
- return { topType, topElevation, register };
7945
- }, { name: 'SurfaceContextTracker' });
7946
-
7947
8030
  class SurfaceInteractiveStylesComponent {
7948
8031
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: SurfaceInteractiveStylesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7949
8032
  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))}@media(hover:hover){:where(.et-surface-interactive:hover){--et-surface-interaction-rgb: var(--et-surface-interaction-hover, var(--et-surface-interaction));--et-surface-interaction-solid: rgb(var(--et-surface-interaction-rgb))}}:where(.et-surface-interactive:focus-visible){--et-surface-interaction-rgb: var( --et-surface-interaction-focus, var(--et-surface-interaction-hover, var(--et-surface-interaction)) );--et-surface-interaction-solid: rgb(var(--et-surface-interaction-rgb))}:where(.et-surface-interactive:active){--et-surface-interaction-rgb: var( --et-surface-interaction-active, var(--et-surface-interaction-focus, var(--et-surface-interaction-hover, var(--et-surface-interaction))) );--et-surface-interaction-solid: rgb(var(--et-surface-interaction-rgb))}:where(.et-surface-interactive[disabled]),:where(.et-surface-interactive[aria-disabled=true]){--et-surface-interaction-rgb: var( --et-surface-interaction-disabled, var( --et-surface-interaction-active, var(--et-surface-interaction-focus, var(--et-surface-interaction-hover, var(--et-surface-interaction))) ) );--et-surface-interaction-solid: rgb(var(--et-surface-interaction-rgb))}\n"], encapsulation: i0.ViewEncapsulation.None }); }
@@ -7982,9 +8065,142 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
7982
8065
  }]
7983
8066
  }], ctorParameters: () => [] });
7984
8067
 
8068
+ const isAbstractControl = (value) => !!value &&
8069
+ typeof value === 'object' &&
8070
+ typeof value.getRawValue === 'function' &&
8071
+ typeof value.setValue === 'function';
8072
+ // A signal-forms field node is a callable that is NOT an Angular signal (signals are callable too).
8073
+ const isFieldTree = (value) => typeof value === 'function' && !isSignal(value);
8074
+ /** Reduces any {@link UnsavedChangesSource} to a uniform read-signal + writer pair. */
8075
+ const normalizeUnsavedChangesSource = (source) => {
8076
+ if (isAbstractControl(source)) {
8077
+ const value = controlValueSignal(source);
8078
+ return { value, setValue: (next) => source.setValue(next) };
8079
+ }
8080
+ if (isFieldTree(source)) {
8081
+ return {
8082
+ value: computed(() => source().value()),
8083
+ // FieldTree's value type is a generic conditional that TS can't narrow here — cast the writer.
8084
+ setValue: (next) => source().value.set(next),
8085
+ };
8086
+ }
8087
+ if (isSignal(source)) {
8088
+ const peek = untracked(source);
8089
+ // A signal that currently holds a FieldTree — or nothing yet (the late/async form case).
8090
+ if (peek === null || peek === undefined || isFieldTree(peek)) {
8091
+ const fieldSignal = source;
8092
+ return {
8093
+ value: computed(() => {
8094
+ const field = fieldSignal();
8095
+ return isFieldTree(field) ? field().value() : null;
8096
+ }),
8097
+ setValue: (next) => {
8098
+ const field = untracked(fieldSignal);
8099
+ if (isFieldTree(field)) {
8100
+ field().value.set(next);
8101
+ }
8102
+ },
8103
+ };
8104
+ }
8105
+ // A plain writable value signal (escape hatch). Initialize it with a non-null value so it isn't
8106
+ // mistaken for a late FieldTree source above.
8107
+ const writable = source;
8108
+ return { value: writable, setValue: (next) => writable.set(next) };
8109
+ }
8110
+ throw new Error('[unsaved-changes] Unsupported source. Pass a signal-forms FieldTree, a Signal<FieldTree | null>, ' +
8111
+ 'an AbstractControl, or a WritableSignal.');
8112
+ };
8113
+
8114
+ const toBooleanPromise = (result) => {
8115
+ if (result instanceof Promise) {
8116
+ return result.then(Boolean);
8117
+ }
8118
+ if (isObservable(result)) {
8119
+ return firstValueFrom(result.pipe(take(1), map(Boolean), defaultIfEmpty(false), catchError(() => of(false))));
8120
+ }
8121
+ return Promise.resolve(Boolean(result));
8122
+ };
8123
+ /**
8124
+ * The framework-agnostic core of the unsaved-changes family: snapshots a default value, tracks
8125
+ * whether the watched form/value differs from it, and runs an async confirm before a discard.
8126
+ * Call from an injection context (a field initializer or constructor).
8127
+ *
8128
+ * Overlay and router flavors (`createOverlayUnsavedChangesGuard`, `createUnsavedChangesGuard`) build
8129
+ * on this — use them when you want the guard wired to a close/navigation event automatically.
8130
+ */
8131
+ const createUnsavedChangesTracker = (config) => {
8132
+ assertInInjectionContext(createUnsavedChangesTracker);
8133
+ const { compareFn, confirm } = config;
8134
+ const normalized = normalizeUnsavedChangesSource(config.source);
8135
+ const hasExplicitDefault = config.defaultValue !== undefined;
8136
+ const initialDefault = hasExplicitDefault
8137
+ ? typeof config.defaultValue === 'function'
8138
+ ? config.defaultValue()
8139
+ : config.defaultValue
8140
+ : untracked(normalized.value);
8141
+ const _defaultValue = signal(initialDefault, /* @ts-ignore */
8142
+ ...(ngDevMode ? [{ debugName: "_defaultValue" }] : /* istanbul ignore next */ []));
8143
+ // No explicit default → capture the first non-null value the source produces as the baseline.
8144
+ // This makes async-filled forms "just work" while keeping snapshot (not dirty()) semantics.
8145
+ if (!hasExplicitDefault) {
8146
+ let captured = initialDefault !== null && initialDefault !== undefined;
8147
+ effect(() => {
8148
+ const current = normalized.value();
8149
+ if (!captured && current !== null && current !== undefined) {
8150
+ captured = true;
8151
+ untracked(() => _defaultValue.set(current));
8152
+ }
8153
+ });
8154
+ }
8155
+ const hasChanges = computed(() => {
8156
+ const current = normalized.value();
8157
+ if (current === null || current === undefined) {
8158
+ return false;
8159
+ }
8160
+ const defaultValue = _defaultValue();
8161
+ return !(compareFn ? compareFn(current, defaultValue) : equal(current, defaultValue));
8162
+ }, /* @ts-ignore */
8163
+ ...(ngDevMode ? [{ debugName: "hasChanges" }] : /* istanbul ignore next */ []));
8164
+ const runCheck = () => {
8165
+ if (!untracked(hasChanges)) {
8166
+ return Promise.resolve(true);
8167
+ }
8168
+ return toBooleanPromise(confirm(untracked(normalized.value)));
8169
+ };
8170
+ const refreshDefaultValue = () => _defaultValue.set(untracked(normalized.value));
8171
+ const restoreDefaultValue = () => {
8172
+ const defaultValue = untracked(_defaultValue);
8173
+ if (defaultValue !== null && defaultValue !== undefined) {
8174
+ normalized.setValue(defaultValue);
8175
+ }
8176
+ };
8177
+ return {
8178
+ hasChanges,
8179
+ defaultValue: _defaultValue.asReadonly(),
8180
+ runCheck,
8181
+ refreshDefaultValue,
8182
+ restoreDefaultValue,
8183
+ };
8184
+ };
8185
+
8186
+ /**
8187
+ * The router / manual flavor of the unsaved-changes family: a {@link createUnsavedChangesTracker}
8188
+ * plus a `canDeactivate` bridge for Angular route guards. It touches no overlay APIs, so it also
8189
+ * serves as a standalone "does this form have unsaved changes, and may I discard them?" helper.
8190
+ * Call from an injection context.
8191
+ */
8192
+ const createUnsavedChangesGuard = (config) => {
8193
+ assertInInjectionContext(createUnsavedChangesGuard);
8194
+ const tracker = createUnsavedChangesTracker(config);
8195
+ return {
8196
+ ...tracker,
8197
+ canDeactivate: () => tracker.runCheck(),
8198
+ };
8199
+ };
8200
+
7985
8201
  /**
7986
8202
  * Generated bundle index. Do not edit.
7987
8203
  */
7988
8204
 
7989
- export { ANIMATABLE_TOKEN, ANIMATED_IF_TOKEN, ANIMATED_LIFECYCLE_TOKEN, ANIMATION_DEBUG_STORAGE_KEY, AT_LEAST_ONE_REQUIRED, AnimatableDirective, AnimatedIfDirective, AnimatedLifecycleDirective, AnimatedOverlayDirective, AutoSurfaceDirective, BOUNDARY_ELEMENT_TOKEN, BREAKPOINT_INSTANCE_TOKEN, BREAKPOINT_ORDER, COLOR_PROVIDER, ClickOutsideDirective, ColorInteractiveContainerDirective, ColorInteractiveDirective, ColorInteractiveExcludeDirective, ColorInteractiveHasFocusDirective, DEFAULT_MULTI_INSTANCE_RELS, DEFAULT_MULTI_INSTANCE_TAGS, DEFAULT_VIEWPORT_CONFIG, DISABLE_LOGGER_PARAM, DragHandleDirective, ET_DISABLE_SCROLL_TOP, ET_DISABLE_SCROLL_TOP_AS_RETURN_ROUTE, ET_DISABLE_SCROLL_TOP_ON_PATH_PARAM_CHANGE, ET_PROPERTY_REMOVED, FOCUSABLE_SELECTOR, FOCUS_VISIBLE_TRACKER_TOKEN, HtmlToMarkdownPipe, IS_ARRAY_NOT_EMPTY, IS_EMAIL, InferMimeTypePipe, InitialsPipe, IsArrayNotEmpty, IsEmail, jsonLd as JsonLD, KeyPressManager, MUST_MATCH, MarkdownToHtmlPipe, MustMatch, 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, SlugifyPipe, 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, copyToClipboard, 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, initials, injectAngularRootElement, injectAnimatedBlockSize, 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, injectPrefersReducedMotion, 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, randomId, readFromClipboard, resetPositioningStyles, resolveAppRootColorProvider, resolveSurfaceByElevation, round, routerDisableScrollTop, scrollToElement, setBackdropStyles, setBaseElementStyles, setCookie, setInputSignal, setupFocusTrap, setupPositioning, setupScrollRestoration, signalAnimatedNumber, signalAttributes, signalClasses, signalElementChildren, signalElementDimensions, signalElementIntersection, signalElementLastScrollDirection, signalElementMutations, signalElementScrollState, signalHostAttributes, signalHostClasses, signalHostElementDimensions, signalHostElementIntersection, signalHostElementLastScrollDirection, signalHostElementMutations, signalHostElementScrollState, signalHostStyles, signalIsRendered, signalStyles, slugify, switchQueryListChanges, syncSignal, templateComputed, toArray, toArrayTrackByFn, toStringBinding, transformOrReturn, typedBreakpointTransform, unbindProps, useCursorDragScroll, writeScrollbarSizeToCssVariables, writeViewportSizeToCssVariables, ɵProvideColorThemes, ɵProvideColorThemesPrefix, ɵProvideSurfaceThemes, ɵProvideSurfaceThemesPrefix };
8205
+ export { ANIMATABLE_TOKEN, ANIMATED_IF_TOKEN, ANIMATED_LIFECYCLE_TOKEN, ANIMATION_DEBUG_STORAGE_KEY, AT_LEAST_ONE_REQUIRED, AnimatableDirective, AnimatedIfDirective, AnimatedLifecycleDirective, AnimatedOverlayDirective, AutoSurfaceDirective, BOUNDARY_ELEMENT_TOKEN, BREAKPOINT_INSTANCE_TOKEN, BREAKPOINT_ORDER, COLOR_PROVIDER, ClickOutsideDirective, ColorInteractiveContainerDirective, ColorInteractiveDirective, ColorInteractiveExcludeDirective, ColorInteractiveHasFocusDirective, DEFAULT_MULTI_INSTANCE_RELS, DEFAULT_MULTI_INSTANCE_TAGS, DEFAULT_VIEWPORT_CONFIG, DISABLE_LOGGER_PARAM, DragHandleDirective, ET_DISABLE_SCROLL_TOP, ET_DISABLE_SCROLL_TOP_AS_RETURN_ROUTE, ET_DISABLE_SCROLL_TOP_ON_PATH_PARAM_CHANGE, ET_PROPERTY_REMOVED, FOCUSABLE_SELECTOR, FOCUS_VISIBLE_TRACKER_TOKEN, HtmlToMarkdownPipe, IS_ARRAY_NOT_EMPTY, IS_EMAIL, InferMimeTypePipe, InitialsPipe, IsArrayNotEmpty, IsEmail, jsonLd as JsonLD, KeyPressManager, MUST_MATCH, MarkdownToHtmlPipe, MustMatch, 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, SlugifyPipe, 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, copyToClipboard, 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, createUnsavedChangesGuard, createUnsavedChangesTracker, 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, initials, injectAngularRootElement, injectAnimatedBlockSize, 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, injectPrefersReducedMotion, 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, normalizeUnsavedChangesSource, numberBreakpointAttribute, numberBreakpointTransform, previousSignalValue, provideBoundaryElement, provideBreakpointInstance, provideBreakpointObserver, provideColorThemes, provideColorThemesWithTailwind4, provideFocusVisibleTracker, provideLinkStore, provideLinkStoreConfig, provideLocale, provideMetaConfig, provideMetaStore, provideOverlayRuntime, provideRenderer, provideStructuredDataConfig, provideStructuredDataStore, provideStyleManager, provideSurfaceContextTracker, provideSurfaceThemesWithTailwind4, provideTitleConfig, provideTitleStore, provideViewportConfig, randomId, readFromClipboard, resetPositioningStyles, resolveAppRootColorProvider, resolveSurfaceByElevation, round, routerDisableScrollTop, scrollToElement, setBackdropStyles, setBaseElementStyles, setCookie, setInputSignal, setupFocusTrap, setupPositioning, setupScrollRestoration, signalAnimatedNumber, signalAttributes, signalClasses, signalElementChildren, signalElementDimensions, signalElementIntersection, signalElementLastScrollDirection, signalElementMutations, signalElementScrollState, signalHostAttributes, signalHostClasses, signalHostElementDimensions, signalHostElementIntersection, signalHostElementLastScrollDirection, signalHostElementMutations, signalHostElementScrollState, signalHostStyles, signalIsRendered, signalStyles, slugify, switchQueryListChanges, syncSignal, templateComputed, toArray, toArrayTrackByFn, toStringBinding, transformOrReturn, typedBreakpointTransform, unbindProps, useCursorDragScroll, writeScrollbarSizeToCssVariables, writeViewportSizeToCssVariables, ɵProvideColorThemes, ɵProvideColorThemesPrefix, ɵProvideSurfaceThemes, ɵProvideSurfaceThemesPrefix };
7990
8206
  //# sourceMappingURL=ethlete-core.mjs.map