@frame-kit/ui-ng 0.0.2 → 0.0.4

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,8 +1,7 @@
1
1
  import { BreakpointObserver } from '@angular/cdk/layout';
2
2
  import * as i0 from '@angular/core';
3
- import { input, inject, signal, computed, DestroyRef, afterNextRender, HostBinding, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { input, signal, computed, inject, DestroyRef, afterNextRender, HostBinding, ChangeDetectionStrategy, Component } from '@angular/core';
4
4
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
5
- import { OverlayOrchestrator, OVERLAY_PRIORITY } from '@frame-kit/ui-ng/services/overlay-orchestrator';
6
5
 
7
6
  class AppShellComponent {
8
7
  // ===== INPUTS =====
@@ -24,9 +23,6 @@ class AppShellComponent {
24
23
  endWidth = input('320px', ...(ngDevMode ? [{ debugName: "endWidth" }] : /* istanbul ignore next */ []));
25
24
  /** Width of the end panel when collapsed to icon-rail mode. */
26
25
  endCollapsedWidth = input('64px', ...(ngDevMode ? [{ debugName: "endCollapsedWidth" }] : /* istanbul ignore next */ []));
27
- orchestrator = inject(OverlayOrchestrator);
28
- navOverlayId = null;
29
- endOverlayId = null;
30
26
  // ===== INTERNAL STATE =====
31
27
  stickyPreference = signal(null, ...(ngDevMode ? [{ debugName: "stickyPreference" }] : /* istanbul ignore next */ []));
32
28
  tempOpen = signal(false, ...(ngDevMode ? [{ debugName: "tempOpen" }] : /* istanbul ignore next */ []));
@@ -141,28 +137,19 @@ class AppShellComponent {
141
137
  });
142
138
  }
143
139
  // ===== METHODS =====
144
- /** Open the primary sidenav, registering it with the overlay orchestrator on mobile. */
140
+ /** Open the primary sidenav (temporary overlay on mobile). */
145
141
  openSidenav() {
146
142
  this.animate.set(true);
147
143
  this.stickyPreference.set(null);
148
144
  if (this.isMobile()) {
149
145
  this.tempOpen.set(true);
150
- this.navOverlayId = this.orchestrator.register({
151
- priority: OVERLAY_PRIORITY.NAVIGATION,
152
- type: 'navigation',
153
- close: () => this.closeSidenav(),
154
- });
155
146
  }
156
147
  }
157
- /** Close the primary sidenav and unregister it from the overlay orchestrator. */
148
+ /** Close the primary sidenav. */
158
149
  closeSidenav() {
159
150
  this.animate.set(true);
160
151
  this.stickyPreference.set('closed');
161
152
  this.tempOpen.set(false);
162
- if (this.navOverlayId) {
163
- this.orchestrator.unregister(this.navOverlayId);
164
- this.navOverlayId = null;
165
- }
166
153
  }
167
154
  /** Toggle the primary sidenav between open and closed. */
168
155
  toggleSidenav() {
@@ -178,28 +165,19 @@ class AppShellComponent {
178
165
  this.animate.set(true);
179
166
  this.tempOpen.set(false);
180
167
  }
181
- /** Open the end panel, registering it with the overlay orchestrator on mobile. */
168
+ /** Open the end panel (temporary overlay on mobile). */
182
169
  openEnd() {
183
170
  this.animate.set(true);
184
171
  this.endStickyPreference.set(null);
185
172
  if (this.isMobile()) {
186
173
  this.endTempOpen.set(true);
187
- this.endOverlayId = this.orchestrator.register({
188
- priority: OVERLAY_PRIORITY.NAVIGATION,
189
- type: 'navigation',
190
- close: () => this.closeEnd(),
191
- });
192
174
  }
193
175
  }
194
- /** Close the end panel and unregister it from the overlay orchestrator. */
176
+ /** Close the end panel. */
195
177
  closeEnd() {
196
178
  this.animate.set(true);
197
179
  this.endStickyPreference.set('closed');
198
180
  this.endTempOpen.set(false);
199
- if (this.endOverlayId) {
200
- this.orchestrator.unregister(this.endOverlayId);
201
- this.endOverlayId = null;
202
- }
203
181
  }
204
182
  /** Toggle the end panel between open and closed. */
205
183
  toggleEnd() {
@@ -210,15 +188,11 @@ class AppShellComponent {
210
188
  this.openEnd();
211
189
  }
212
190
  }
213
- /** Dismiss the end panel overlay and unregister it from the overlay orchestrator. */
191
+ /** Dismiss the end panel overlay. */
214
192
  dismissEnd() {
215
193
  this.animate.set(true);
216
194
  this.endStickyPreference.set('closed');
217
195
  this.endTempOpen.set(false);
218
- if (this.endOverlayId) {
219
- this.orchestrator.unregister(this.endOverlayId);
220
- this.endOverlayId = null;
221
- }
222
196
  }
223
197
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AppShellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
224
198
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AppShellComponent, isStandalone: true, selector: "fk-app-shell", inputs: { mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, sidenavWidth: { classPropertyName: "sidenavWidth", publicName: "sidenavWidth", isSignal: true, isRequired: false, transformFunction: null }, collapsedWidth: { classPropertyName: "collapsedWidth", publicName: "collapsedWidth", isSignal: true, isRequired: false, transformFunction: null }, breakpoint: { classPropertyName: "breakpoint", publicName: "breakpoint", isSignal: true, isRequired: false, transformFunction: null }, sticky: { classPropertyName: "sticky", publicName: "sticky", isSignal: true, isRequired: false, transformFunction: null }, collapseOnMobile: { classPropertyName: "collapseOnMobile", publicName: "collapseOnMobile", isSignal: true, isRequired: false, transformFunction: null }, endMode: { classPropertyName: "endMode", publicName: "endMode", isSignal: true, isRequired: false, transformFunction: null }, endWidth: { classPropertyName: "endWidth", publicName: "endWidth", isSignal: true, isRequired: false, transformFunction: null }, endCollapsedWidth: { classPropertyName: "endCollapsedWidth", publicName: "endCollapsedWidth", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style": "this.hostStyle" } }, ngImport: i0, template: "<div [class]=\"classes()\">\n <header class=\"fk-app-shell__header\">\n <ng-content select=\"[appShellHeader]\" />\n </header>\n\n <div class=\"fk-app-shell__body\">\n @if (showOverlay()) {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <div class=\"fk-app-shell__overlay\" (click)=\"dismissSidenav()\"></div>\n }\n\n <aside\n class=\"fk-app-shell__aside\"\n [class.fk-app-shell__aside--open]=\"sidenavOpen()\"\n [class.fk-app-shell__aside--collapsed]=\"isCollapsed()\"\n >\n <ng-content select=\"[appShellSidenav]\" />\n </aside>\n\n <main class=\"fk-app-shell__content\">\n <ng-content select=\"[appShellContent]\" />\n </main>\n\n @if (showEndOverlay()) {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <div class=\"fk-app-shell__end-overlay\" (click)=\"dismissEnd()\"></div>\n }\n\n <aside\n class=\"fk-app-shell__end\"\n [class.fk-app-shell__end--open]=\"endOpen()\"\n [class.fk-app-shell__end--collapsed]=\"isEndCollapsed()\"\n >\n <ng-content select=\"[appShellEnd]\" />\n </aside>\n </div>\n\n <footer class=\"fk-app-shell__footer\">\n <ng-content select=\"[appShellFooter]\" />\n </footer>\n</div>\n", styles: [":host{display:block;height:100%;flex:1;min-height:0}.fk-app-shell{display:flex;flex-direction:column;height:100%;overflow:hidden}.fk-app-shell--animate .fk-app-shell__aside,.fk-app-shell--animate .fk-app-shell__end{transition:width .25s cubic-bezier(.4,0,.2,1),transform .25s cubic-bezier(.4,0,.2,1)}.fk-app-shell__header{position:relative;z-index:var(--fk-app-shell-header-z-index, 100);flex-shrink:0}.fk-app-shell__body{display:flex;flex:1;position:relative;min-height:0}.fk-app-shell__overlay{position:fixed;inset:0;z-index:var(--fk-app-shell-overlay-z-index, 200);background:var(--fk-app-shell-overlay-bg, var(--fk-black-50, rgba(0, 0, 0, .5)))}.fk-app-shell__aside{display:flex;flex-direction:column;width:var(--fk-app-shell-sidenav-width);flex-shrink:0;overflow:hidden}.fk-app-shell__content{flex:1;min-width:0;overflow-y:auto;overscroll-behavior:contain}.fk-app-shell__footer{flex-shrink:0}.fk-app-shell--side .fk-app-shell__aside{position:relative}.fk-app-shell--side:not(.fk-app-shell--mobile):not(.fk-app-shell--open) .fk-app-shell__aside{width:0;overflow:hidden}.fk-app-shell--mobile .fk-app-shell__aside,.fk-app-shell--over .fk-app-shell__aside{position:fixed;top:0;left:0;bottom:0;z-index:var(--fk-app-shell-aside-z-index, 201);width:var(--fk-app-shell-sidenav-width);transform:translate(-100%);background:var(--fk-app-shell-aside-bg, var(--fk-color-surface, #ffffff))}.fk-app-shell--mobile .fk-app-shell__aside{width:var(--fk-app-shell-mobile-sidenav-width, 100%)}.fk-app-shell--mobile .fk-app-shell__aside--open,.fk-app-shell--over .fk-app-shell__aside--open{transform:translate(0)}.fk-app-shell--icon:not(.fk-app-shell--mobile) .fk-app-shell__aside{position:relative}.fk-app-shell--icon:not(.fk-app-shell--mobile) .fk-app-shell__aside--collapsed{width:var(--fk-app-shell-collapsed-width)}.fk-app-shell--mobile .fk-app-shell__aside--collapsed{position:relative;top:auto;left:auto;bottom:auto;width:var(--fk-app-shell-collapsed-width);transform:none;z-index:auto}.fk-app-shell__end-overlay{position:fixed;inset:0;z-index:var(--fk-app-shell-overlay-z-index, 200);background:var(--fk-app-shell-overlay-bg, var(--fk-black-50, rgba(0, 0, 0, .5)))}.fk-app-shell__end{display:flex;flex-direction:column;width:var(--fk-app-shell-end-width);flex-shrink:0;overflow:hidden;background:var(--fk-app-shell-end-bg, var(--fk-color-surface, #ffffff));border-radius:var(--fk-app-shell-end-radius, 0)}.fk-app-shell--end-side .fk-app-shell__end{position:relative}.fk-app-shell--end-side:not(.fk-app-shell--mobile):not(.fk-app-shell--end-open) .fk-app-shell__end{width:0;overflow:hidden}.fk-app-shell--mobile .fk-app-shell__end,.fk-app-shell--end-over .fk-app-shell__end{position:fixed;top:0;right:0;bottom:0;z-index:var(--fk-app-shell-end-z-index, 201);width:var(--fk-app-shell-end-width);transform:translate(100%);background:var(--fk-app-shell-end-bg, var(--fk-color-surface, #ffffff))}.fk-app-shell--mobile .fk-app-shell__end--open,.fk-app-shell--end-over .fk-app-shell__end--open{box-shadow:var(--fk-app-shell-end-shadow, -4px 0 16px rgba(0, 0, 0, .08))}.fk-app-shell--mobile .fk-app-shell__end--open,.fk-app-shell--end-over .fk-app-shell__end--open{transform:translate(0)}.fk-app-shell--end-icon:not(.fk-app-shell--mobile) .fk-app-shell__end{position:relative}.fk-app-shell--end-icon:not(.fk-app-shell--mobile) .fk-app-shell__end--collapsed{width:var(--fk-app-shell-end-collapsed-width)}@media(prefers-reduced-motion:reduce){.fk-app-shell--animate .fk-app-shell__aside,.fk-app-shell--animate .fk-app-shell__end{transition:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
@@ -1 +1 @@
1
- {"version":3,"file":"frame-kit-ui-ng-layouts-app-shell.mjs","sources":["../../../../packages/ui-ng/layouts/app-shell/app-shell.component.ts","../../../../packages/ui-ng/layouts/app-shell/app-shell.component.html","../../../../packages/ui-ng/layouts/app-shell/frame-kit-ui-ng-layouts-app-shell.ts"],"sourcesContent":["import { BreakpointObserver } from '@angular/cdk/layout';\nimport {\n afterNextRender,\n ChangeDetectionStrategy,\n Component,\n computed,\n DestroyRef,\n HostBinding,\n inject,\n input,\n signal,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { OverlayOrchestrator } from '@frame-kit/ui-ng/services/overlay-orchestrator';\nimport { OVERLAY_PRIORITY } from '@frame-kit/ui-ng/services/overlay-orchestrator';\nimport type { AppShellMode } from './app-shell.types';\n\n@Component({\n selector: 'fk-app-shell',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './app-shell.component.html',\n styleUrl: './app-shell.component.scss',\n})\nexport class AppShellComponent {\n // ===== INPUTS =====\n /** Layout mode for the primary sidenav — `\"side\"` pushes content, `\"over\"` floats above it, `\"icon\"` collapses to an icon rail. */\n readonly mode = input<AppShellMode>('side');\n /** Width of the primary sidenav when fully open. */\n readonly sidenavWidth = input<string>('260px');\n /** Width of the primary sidenav when collapsed to icon-rail mode. */\n readonly collapsedWidth = input<string>('64px');\n /** CSS media query used to determine mobile breakpoint for the primary sidenav. */\n readonly breakpoint = input<string>('(min-width: 48em)');\n /** When true, the main header sticks to the top of the viewport during scroll. */\n readonly sticky = input<boolean>(true);\n /** When true and on mobile, the sidenav collapses to the icon rail instead of hiding entirely. */\n readonly collapseOnMobile = input<boolean>(false);\n\n /** Layout mode for the end (trailing) panel. */\n readonly endMode = input<AppShellMode>('over');\n /** Width of the end panel when fully open. */\n readonly endWidth = input<string>('320px');\n /** Width of the end panel when collapsed to icon-rail mode. */\n readonly endCollapsedWidth = input<string>('64px');\n\n private readonly orchestrator = inject(OverlayOrchestrator);\n private navOverlayId: string | null = null;\n private endOverlayId: string | null = null;\n\n // ===== INTERNAL STATE =====\n readonly stickyPreference = signal<'closed' | null>(null);\n readonly tempOpen = signal<boolean>(false);\n readonly isMobile = signal<boolean>(false);\n\n readonly endStickyPreference = signal<'closed' | null>('closed');\n readonly endTempOpen = signal<boolean>(false);\n\n /**\n * Transitions are opt-in: only enabled after a user action (toggle, open,\n * close, dismiss). Viewport changes clear this flag so layout shifts are\n * always instant — no flash of the aside sliding in/out on resize.\n */\n readonly animate = signal<boolean>(false);\n\n // ===== COMPUTED =====\n readonly sidenavOpen = computed(() => {\n if (this.stickyPreference() === 'closed') {\n return false;\n }\n\n if (this.tempOpen()) {\n return true;\n }\n\n return !this.isMobile();\n });\n\n readonly showOverlay = computed(() => {\n if (!this.sidenavOpen()) {\n return false;\n }\n\n if (this.mode() === 'over') {\n return true;\n }\n\n return this.isMobile();\n });\n\n readonly isCollapsed = computed(() => {\n if (this.mode() !== 'icon') {\n return false;\n }\n\n if (this.sidenavOpen()) {\n return false;\n }\n\n if (this.isMobile()) {\n return this.collapseOnMobile();\n }\n\n return true;\n });\n\n readonly endOpen = computed(() => {\n if (this.endStickyPreference() === 'closed') {\n return false;\n }\n\n if (this.endTempOpen()) {\n return true;\n }\n\n return !this.isMobile();\n });\n\n readonly showEndOverlay = computed(() => {\n if (!this.endOpen()) {\n return false;\n }\n\n if (this.endMode() === 'over') {\n return true;\n }\n\n return this.isMobile();\n });\n\n readonly isEndCollapsed = computed(() => {\n return this.endMode() === 'icon' && !this.endOpen() && !this.isMobile();\n });\n\n readonly classes = computed(() => {\n const mode = this.mode();\n\n const endMode = this.endMode();\n\n return [\n 'fk-app-shell',\n `fk-app-shell--${mode}`,\n this.sticky() ? 'fk-app-shell--sticky' : '',\n this.sidenavOpen() ? 'fk-app-shell--open' : '',\n this.isCollapsed() ? 'fk-app-shell--collapsed' : '',\n this.isMobile() ? 'fk-app-shell--mobile' : '',\n this.animate() ? 'fk-app-shell--animate' : '',\n `fk-app-shell--end-${endMode}`,\n this.endOpen() ? 'fk-app-shell--end-open' : '',\n this.isEndCollapsed() ? 'fk-app-shell--end-collapsed' : '',\n ]\n .filter(Boolean)\n .join(' ');\n });\n\n @HostBinding('style')\n get hostStyle() {\n return {\n '--fk-app-shell-sidenav-width': this.sidenavWidth(),\n '--fk-app-shell-collapsed-width': this.collapsedWidth(),\n '--fk-app-shell-end-width': this.endWidth(),\n '--fk-app-shell-end-collapsed-width': this.endCollapsedWidth(),\n };\n }\n\n // ===== BREAKPOINT =====\n private readonly breakpointObserver = inject(BreakpointObserver);\n private readonly destroyRef = inject(DestroyRef);\n\n constructor() {\n // Defer the breakpoint subscription until the first client-side render.\n // During SSR, CDK's MediaMatcher returns `{ matches: false }` for every\n // query, which would flip `isMobile` to true and produce a mobile-layout\n // HTML in the server output, causing a visible flash of the overlay\n // sidebar before the client corrects it on hydration. `afterNextRender`\n // only runs in the browser, so `isMobile` stays at its `false` default\n // through SSR and the real viewport check happens post-hydration.\n afterNextRender(() => {\n this.breakpointObserver\n .observe(this.breakpoint())\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe((result) => {\n this.animate.set(false);\n this.isMobile.set(!result.matches);\n this.tempOpen.set(false);\n this.endTempOpen.set(false);\n });\n });\n }\n\n // ===== METHODS =====\n /** Open the primary sidenav, registering it with the overlay orchestrator on mobile. */\n openSidenav(): void {\n this.animate.set(true);\n this.stickyPreference.set(null);\n\n if (this.isMobile()) {\n this.tempOpen.set(true);\n\n this.navOverlayId = this.orchestrator.register({\n priority: OVERLAY_PRIORITY.NAVIGATION,\n type: 'navigation',\n close: () => this.closeSidenav(),\n });\n }\n }\n\n /** Close the primary sidenav and unregister it from the overlay orchestrator. */\n closeSidenav(): void {\n this.animate.set(true);\n this.stickyPreference.set('closed');\n this.tempOpen.set(false);\n\n if (this.navOverlayId) {\n this.orchestrator.unregister(this.navOverlayId);\n this.navOverlayId = null;\n }\n }\n\n /** Toggle the primary sidenav between open and closed. */\n toggleSidenav(): void {\n if (this.sidenavOpen()) {\n this.closeSidenav();\n } else {\n this.openSidenav();\n }\n }\n\n /** Dismiss the sidenav overlay on mobile without marking it as permanently closed. */\n dismissSidenav(): void {\n this.animate.set(true);\n this.tempOpen.set(false);\n }\n\n /** Open the end panel, registering it with the overlay orchestrator on mobile. */\n openEnd(): void {\n this.animate.set(true);\n this.endStickyPreference.set(null);\n\n if (this.isMobile()) {\n this.endTempOpen.set(true);\n\n this.endOverlayId = this.orchestrator.register({\n priority: OVERLAY_PRIORITY.NAVIGATION,\n type: 'navigation',\n close: () => this.closeEnd(),\n });\n }\n }\n\n /** Close the end panel and unregister it from the overlay orchestrator. */\n closeEnd(): void {\n this.animate.set(true);\n this.endStickyPreference.set('closed');\n this.endTempOpen.set(false);\n\n if (this.endOverlayId) {\n this.orchestrator.unregister(this.endOverlayId);\n this.endOverlayId = null;\n }\n }\n\n /** Toggle the end panel between open and closed. */\n toggleEnd(): void {\n if (this.endOpen()) {\n this.closeEnd();\n } else {\n this.openEnd();\n }\n }\n\n /** Dismiss the end panel overlay and unregister it from the overlay orchestrator. */\n dismissEnd(): void {\n this.animate.set(true);\n this.endStickyPreference.set('closed');\n this.endTempOpen.set(false);\n\n if (this.endOverlayId) {\n this.orchestrator.unregister(this.endOverlayId);\n this.endOverlayId = null;\n }\n }\n}\n","<div [class]=\"classes()\">\n <header class=\"fk-app-shell__header\">\n <ng-content select=\"[appShellHeader]\" />\n </header>\n\n <div class=\"fk-app-shell__body\">\n @if (showOverlay()) {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <div class=\"fk-app-shell__overlay\" (click)=\"dismissSidenav()\"></div>\n }\n\n <aside\n class=\"fk-app-shell__aside\"\n [class.fk-app-shell__aside--open]=\"sidenavOpen()\"\n [class.fk-app-shell__aside--collapsed]=\"isCollapsed()\"\n >\n <ng-content select=\"[appShellSidenav]\" />\n </aside>\n\n <main class=\"fk-app-shell__content\">\n <ng-content select=\"[appShellContent]\" />\n </main>\n\n @if (showEndOverlay()) {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <div class=\"fk-app-shell__end-overlay\" (click)=\"dismissEnd()\"></div>\n }\n\n <aside\n class=\"fk-app-shell__end\"\n [class.fk-app-shell__end--open]=\"endOpen()\"\n [class.fk-app-shell__end--collapsed]=\"isEndCollapsed()\"\n >\n <ng-content select=\"[appShellEnd]\" />\n </aside>\n </div>\n\n <footer class=\"fk-app-shell__footer\">\n <ng-content select=\"[appShellFooter]\" />\n </footer>\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"frame-kit-ui-ng-layouts-app-shell.mjs","sources":["../../../../packages/ui-ng/layouts/app-shell/app-shell.component.ts","../../../../packages/ui-ng/layouts/app-shell/app-shell.component.html","../../../../packages/ui-ng/layouts/app-shell/frame-kit-ui-ng-layouts-app-shell.ts"],"sourcesContent":["import { BreakpointObserver } from '@angular/cdk/layout';\nimport {\n afterNextRender,\n ChangeDetectionStrategy,\n Component,\n computed,\n DestroyRef,\n HostBinding,\n inject,\n input,\n signal,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport type { AppShellMode } from './app-shell.types';\n\n@Component({\n selector: 'fk-app-shell',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './app-shell.component.html',\n styleUrl: './app-shell.component.scss',\n})\nexport class AppShellComponent {\n // ===== INPUTS =====\n /** Layout mode for the primary sidenav — `\"side\"` pushes content, `\"over\"` floats above it, `\"icon\"` collapses to an icon rail. */\n readonly mode = input<AppShellMode>('side');\n /** Width of the primary sidenav when fully open. */\n readonly sidenavWidth = input<string>('260px');\n /** Width of the primary sidenav when collapsed to icon-rail mode. */\n readonly collapsedWidth = input<string>('64px');\n /** CSS media query used to determine mobile breakpoint for the primary sidenav. */\n readonly breakpoint = input<string>('(min-width: 48em)');\n /** When true, the main header sticks to the top of the viewport during scroll. */\n readonly sticky = input<boolean>(true);\n /** When true and on mobile, the sidenav collapses to the icon rail instead of hiding entirely. */\n readonly collapseOnMobile = input<boolean>(false);\n\n /** Layout mode for the end (trailing) panel. */\n readonly endMode = input<AppShellMode>('over');\n /** Width of the end panel when fully open. */\n readonly endWidth = input<string>('320px');\n /** Width of the end panel when collapsed to icon-rail mode. */\n readonly endCollapsedWidth = input<string>('64px');\n\n // ===== INTERNAL STATE =====\n readonly stickyPreference = signal<'closed' | null>(null);\n readonly tempOpen = signal<boolean>(false);\n readonly isMobile = signal<boolean>(false);\n\n readonly endStickyPreference = signal<'closed' | null>('closed');\n readonly endTempOpen = signal<boolean>(false);\n\n /**\n * Transitions are opt-in: only enabled after a user action (toggle, open,\n * close, dismiss). Viewport changes clear this flag so layout shifts are\n * always instant — no flash of the aside sliding in/out on resize.\n */\n readonly animate = signal<boolean>(false);\n\n // ===== COMPUTED =====\n readonly sidenavOpen = computed(() => {\n if (this.stickyPreference() === 'closed') {\n return false;\n }\n\n if (this.tempOpen()) {\n return true;\n }\n\n return !this.isMobile();\n });\n\n readonly showOverlay = computed(() => {\n if (!this.sidenavOpen()) {\n return false;\n }\n\n if (this.mode() === 'over') {\n return true;\n }\n\n return this.isMobile();\n });\n\n readonly isCollapsed = computed(() => {\n if (this.mode() !== 'icon') {\n return false;\n }\n\n if (this.sidenavOpen()) {\n return false;\n }\n\n if (this.isMobile()) {\n return this.collapseOnMobile();\n }\n\n return true;\n });\n\n readonly endOpen = computed(() => {\n if (this.endStickyPreference() === 'closed') {\n return false;\n }\n\n if (this.endTempOpen()) {\n return true;\n }\n\n return !this.isMobile();\n });\n\n readonly showEndOverlay = computed(() => {\n if (!this.endOpen()) {\n return false;\n }\n\n if (this.endMode() === 'over') {\n return true;\n }\n\n return this.isMobile();\n });\n\n readonly isEndCollapsed = computed(() => {\n return this.endMode() === 'icon' && !this.endOpen() && !this.isMobile();\n });\n\n readonly classes = computed(() => {\n const mode = this.mode();\n\n const endMode = this.endMode();\n\n return [\n 'fk-app-shell',\n `fk-app-shell--${mode}`,\n this.sticky() ? 'fk-app-shell--sticky' : '',\n this.sidenavOpen() ? 'fk-app-shell--open' : '',\n this.isCollapsed() ? 'fk-app-shell--collapsed' : '',\n this.isMobile() ? 'fk-app-shell--mobile' : '',\n this.animate() ? 'fk-app-shell--animate' : '',\n `fk-app-shell--end-${endMode}`,\n this.endOpen() ? 'fk-app-shell--end-open' : '',\n this.isEndCollapsed() ? 'fk-app-shell--end-collapsed' : '',\n ]\n .filter(Boolean)\n .join(' ');\n });\n\n @HostBinding('style')\n get hostStyle() {\n return {\n '--fk-app-shell-sidenav-width': this.sidenavWidth(),\n '--fk-app-shell-collapsed-width': this.collapsedWidth(),\n '--fk-app-shell-end-width': this.endWidth(),\n '--fk-app-shell-end-collapsed-width': this.endCollapsedWidth(),\n };\n }\n\n // ===== BREAKPOINT =====\n private readonly breakpointObserver = inject(BreakpointObserver);\n private readonly destroyRef = inject(DestroyRef);\n\n constructor() {\n // Defer the breakpoint subscription until the first client-side render.\n // During SSR, CDK's MediaMatcher returns `{ matches: false }` for every\n // query, which would flip `isMobile` to true and produce a mobile-layout\n // HTML in the server output, causing a visible flash of the overlay\n // sidebar before the client corrects it on hydration. `afterNextRender`\n // only runs in the browser, so `isMobile` stays at its `false` default\n // through SSR and the real viewport check happens post-hydration.\n afterNextRender(() => {\n this.breakpointObserver\n .observe(this.breakpoint())\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe((result) => {\n this.animate.set(false);\n this.isMobile.set(!result.matches);\n this.tempOpen.set(false);\n this.endTempOpen.set(false);\n });\n });\n }\n\n // ===== METHODS =====\n /** Open the primary sidenav (temporary overlay on mobile). */\n openSidenav(): void {\n this.animate.set(true);\n this.stickyPreference.set(null);\n\n if (this.isMobile()) {\n this.tempOpen.set(true);\n }\n }\n\n /** Close the primary sidenav. */\n closeSidenav(): void {\n this.animate.set(true);\n this.stickyPreference.set('closed');\n this.tempOpen.set(false);\n }\n\n /** Toggle the primary sidenav between open and closed. */\n toggleSidenav(): void {\n if (this.sidenavOpen()) {\n this.closeSidenav();\n } else {\n this.openSidenav();\n }\n }\n\n /** Dismiss the sidenav overlay on mobile without marking it as permanently closed. */\n dismissSidenav(): void {\n this.animate.set(true);\n this.tempOpen.set(false);\n }\n\n /** Open the end panel (temporary overlay on mobile). */\n openEnd(): void {\n this.animate.set(true);\n this.endStickyPreference.set(null);\n\n if (this.isMobile()) {\n this.endTempOpen.set(true);\n }\n }\n\n /** Close the end panel. */\n closeEnd(): void {\n this.animate.set(true);\n this.endStickyPreference.set('closed');\n this.endTempOpen.set(false);\n }\n\n /** Toggle the end panel between open and closed. */\n toggleEnd(): void {\n if (this.endOpen()) {\n this.closeEnd();\n } else {\n this.openEnd();\n }\n }\n\n /** Dismiss the end panel overlay. */\n dismissEnd(): void {\n this.animate.set(true);\n this.endStickyPreference.set('closed');\n this.endTempOpen.set(false);\n }\n}\n","<div [class]=\"classes()\">\n <header class=\"fk-app-shell__header\">\n <ng-content select=\"[appShellHeader]\" />\n </header>\n\n <div class=\"fk-app-shell__body\">\n @if (showOverlay()) {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <div class=\"fk-app-shell__overlay\" (click)=\"dismissSidenav()\"></div>\n }\n\n <aside\n class=\"fk-app-shell__aside\"\n [class.fk-app-shell__aside--open]=\"sidenavOpen()\"\n [class.fk-app-shell__aside--collapsed]=\"isCollapsed()\"\n >\n <ng-content select=\"[appShellSidenav]\" />\n </aside>\n\n <main class=\"fk-app-shell__content\">\n <ng-content select=\"[appShellContent]\" />\n </main>\n\n @if (showEndOverlay()) {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <div class=\"fk-app-shell__end-overlay\" (click)=\"dismissEnd()\"></div>\n }\n\n <aside\n class=\"fk-app-shell__end\"\n [class.fk-app-shell__end--open]=\"endOpen()\"\n [class.fk-app-shell__end--collapsed]=\"isEndCollapsed()\"\n >\n <ng-content select=\"[appShellEnd]\" />\n </aside>\n </div>\n\n <footer class=\"fk-app-shell__footer\">\n <ng-content select=\"[appShellFooter]\" />\n </footer>\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -2,8 +2,10 @@ import * as i1 from '@angular/cdk/a11y';
2
2
  import { A11yModule } from '@angular/cdk/a11y';
3
3
  import { DOCUMENT } from '@angular/common';
4
4
  import * as i0 from '@angular/core';
5
- import { Directive, input, contentChild, output, inject, DestroyRef, signal, computed, effect, HostListener, HostBinding, ChangeDetectionStrategy, Component, ApplicationRef, EnvironmentInjector, Injector, createComponent, Injectable } from '@angular/core';
6
- import { OverlayOrchestrator, OVERLAY_PRIORITY } from '@frame-kit/ui-ng/services/overlay-orchestrator';
5
+ import { Directive, input, contentChild, output, inject, signal, computed, effect, HostBinding, ChangeDetectionStrategy, Component, ApplicationRef, EnvironmentInjector, Injector, createComponent, Injectable } from '@angular/core';
6
+ import { ESCAPE } from '@angular/cdk/keycodes';
7
+ import { Overlay } from '@angular/cdk/overlay';
8
+ import { ComponentPortal } from '@angular/cdk/portal';
7
9
  import { Subject } from 'rxjs';
8
10
  import { take } from 'rxjs/operators';
9
11
 
@@ -20,18 +22,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
20
22
  }] });
21
23
 
22
24
  let nextDialogId = 0;
25
+ /**
26
+ * Dialog panel chrome.
27
+ *
28
+ * Hosted inside a CDK overlay by `DialogService`, so the overlay layer owns
29
+ * the backdrop, scroll blocking, positioning, stacking, and Escape / outside
30
+ * dispatch. This component renders the panel itself: header / body / footer
31
+ * projection, sizing, the enter animation, focus trapping, and the close
32
+ * guard.
33
+ */
23
34
  class DialogComponent {
24
35
  // ===== INPUTS =====
25
36
  /** Controls whether the dialog is open. */
26
37
  open = input(false, ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
27
- /** When true, renders a backdrop overlay behind the dialog. */
38
+ /** When true, marks the panel `aria-modal` and traps focus. */
28
39
  modal = input(true, ...(ngDevMode ? [{ debugName: "modal" }] : /* istanbul ignore next */ []));
29
40
  /** When true, shows the close button in the dialog header. */
30
41
  closable = input(true, ...(ngDevMode ? [{ debugName: "closable" }] : /* istanbul ignore next */ []));
31
- /** When true, pressing Escape closes the dialog. */
32
- closeOnEscape = input(true, ...(ngDevMode ? [{ debugName: "closeOnEscape" }] : /* istanbul ignore next */ []));
33
- /** When true, clicking the backdrop overlay closes the dialog. */
34
- closeOnBackdrop = input(false, ...(ngDevMode ? [{ debugName: "closeOnBackdrop" }] : /* istanbul ignore next */ []));
35
42
  /** Size variant that controls the dialog's max-width. */
36
43
  size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
37
44
  /** Where the dialog is anchored on screen. */
@@ -72,10 +79,8 @@ class DialogComponent {
72
79
  closed = output();
73
80
  // ===== INTERNAL STATE =====
74
81
  doc = inject(DOCUMENT);
75
- destroyRef = inject(DestroyRef);
76
82
  titleId = `fk-dialog-title-${nextDialogId++}`;
77
83
  previouslyFocusedElement = null;
78
- bodyScrollLocked = false;
79
84
  closeGuardRunning = false;
80
85
  /** Whether the dialog DOM is rendered (stays true during exit animation). */
81
86
  visible = signal(false, ...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
@@ -101,9 +106,6 @@ class DialogComponent {
101
106
  this.onDialogClose();
102
107
  }
103
108
  });
104
- this.destroyRef.onDestroy(() => {
105
- this.unlockBodyScroll();
106
- });
107
109
  }
108
110
  get hostClass() {
109
111
  return this.classes();
@@ -111,12 +113,6 @@ class DialogComponent {
111
113
  get hostId() {
112
114
  return this.id();
113
115
  }
114
- // ===== KEYBOARD =====
115
- onEscapeKey() {
116
- if (this.open() && this.closeOnEscape()) {
117
- this.close();
118
- }
119
- }
120
116
  // ===== ACTIONS =====
121
117
  /** Closes the dialog, running any `canClose` guard first; no-ops when `preventClose` is true. */
122
118
  async close() {
@@ -143,12 +139,7 @@ class DialogComponent {
143
139
  this.openChange.emit(false);
144
140
  this.closed.emit();
145
141
  }
146
- onOverlayClick() {
147
- if (this.closeOnBackdrop()) {
148
- this.close();
149
- }
150
- }
151
- /** Called when the overlay exit animation finishes. */
142
+ /** Called when the panel exit animation finishes. */
152
143
  onExitAnimationDone() {
153
144
  if (this.animatingOut()) {
154
145
  this.animatingOut.set(false);
@@ -162,13 +153,9 @@ class DialogComponent {
162
153
  this.beforeOpen.emit();
163
154
  this.animatingOut.set(false);
164
155
  this.visible.set(true);
165
- if (this.modal()) {
166
- this.lockBodyScroll();
167
- }
168
156
  this.opened.emit();
169
157
  }
170
158
  onDialogClose() {
171
- this.unlockBodyScroll();
172
159
  if (this.visible()) {
173
160
  if (this.animation() !== 'none') {
174
161
  this.animatingOut.set(true);
@@ -182,34 +169,18 @@ class DialogComponent {
182
169
  this.previouslyFocusedElement = null;
183
170
  }
184
171
  }
185
- // ===== SCROLL LOCK =====
186
- lockBodyScroll() {
187
- if (!this.bodyScrollLocked) {
188
- this.doc.body.style.overflow = 'hidden';
189
- this.bodyScrollLocked = true;
190
- }
191
- }
192
- unlockBodyScroll() {
193
- if (this.bodyScrollLocked) {
194
- this.doc.body.style.overflow = '';
195
- this.bodyScrollLocked = false;
196
- }
197
- }
198
172
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
199
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: DialogComponent, isStandalone: true, selector: "fk-dialog", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, modal: { classPropertyName: "modal", publicName: "modal", isSignal: true, isRequired: false, transformFunction: null }, closable: { classPropertyName: "closable", publicName: "closable", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null }, closeOnBackdrop: { classPropertyName: "closeOnBackdrop", publicName: "closeOnBackdrop", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, header: { classPropertyName: "header", publicName: "header", isSignal: true, isRequired: false, transformFunction: null }, restoreFocus: { classPropertyName: "restoreFocus", publicName: "restoreFocus", isSignal: true, isRequired: false, transformFunction: null }, autoFocus: { classPropertyName: "autoFocus", publicName: "autoFocus", isSignal: true, isRequired: false, transformFunction: null }, animation: { classPropertyName: "animation", publicName: "animation", isSignal: true, isRequired: false, transformFunction: null }, preventClose: { classPropertyName: "preventClose", publicName: "preventClose", isSignal: true, isRequired: false, transformFunction: null }, canClose: { classPropertyName: "canClose", publicName: "canClose", isSignal: true, isRequired: false, transformFunction: null }, fullscreenMobile: { classPropertyName: "fullscreenMobile", publicName: "fullscreenMobile", isSignal: true, isRequired: false, transformFunction: null }, flexBody: { classPropertyName: "flexBody", publicName: "flexBody", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "ariaDescribedBy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { openChange: "openChange", beforeOpen: "beforeOpen", opened: "opened", beforeClose: "beforeClose", closed: "closed" }, host: { listeners: { "document:keydown.escape": "onEscapeKey()" }, properties: { "class": "this.hostClass", "attr.id": "this.hostId" } }, queries: [{ propertyName: "customHeader", first: true, predicate: FkDialogHeaderDirective, descendants: true, isSignal: true }], ngImport: i0, template: "@if (visible()) {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <div\n class=\"fk-dialog__overlay\"\n [class.fk-dialog__overlay--modal]=\"modal()\"\n [class.fk-dialog__animate-overlay--in]=\"!animatingOut()\"\n [class.fk-dialog__animate-overlay--out]=\"animatingOut()\"\n [class.fk-dialog__animate-overlay--none]=\"animation() === 'none'\"\n (click)=\"onOverlayClick()\"\n (animationend)=\"onExitAnimationDone()\"\n >\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -->\n <div\n class=\"fk-dialog__panel\"\n [class.fk-dialog__animate-panel--scale-fade]=\"\n animation() === 'scale-fade' && !animatingOut()\n \"\n [class.fk-dialog__animate-panel--fade]=\"\n animation() === 'fade' && !animatingOut()\n \"\n [class.fk-dialog__animate-panel--slide-up]=\"\n animation() === 'slide-up' && !animatingOut()\n \"\n [class.fk-dialog__animate-panel--slide-down]=\"\n animation() === 'slide-down' && !animatingOut()\n \"\n [class.fk-dialog__animate-panel-out--scale-fade]=\"\n animation() === 'scale-fade' && animatingOut()\n \"\n [class.fk-dialog__animate-panel-out--fade]=\"\n animation() === 'fade' && animatingOut()\n \"\n [class.fk-dialog__animate-panel-out--slide-up]=\"\n animation() === 'slide-up' && animatingOut()\n \"\n [class.fk-dialog__animate-panel-out--slide-down]=\"\n animation() === 'slide-down' && animatingOut()\n \"\n [class.fk-dialog__panel--sm]=\"size() === 'sm'\"\n [class.fk-dialog__panel--md]=\"size() === 'md'\"\n [class.fk-dialog__panel--lg]=\"size() === 'lg'\"\n [class.fk-dialog__panel--xl]=\"size() === 'xl'\"\n [class.fk-dialog__panel--fullscreen]=\"size() === 'fullscreen'\"\n [class.fk-dialog__panel--fullscreen-auto]=\"fullscreenMobile()\"\n [class.fk-dialog__panel--top]=\"position() === 'top'\"\n role=\"dialog\"\n [attr.aria-modal]=\"modal() ? 'true' : null\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledBy()\"\n [attr.aria-describedby]=\"ariaDescribedBy()\"\n [cdkTrapFocus]=\"modal()\"\n [cdkTrapFocusAutoCapture]=\"autoFocus()\"\n (click)=\"$event.stopPropagation()\"\n >\n @if (customHeader() || header() || closable()) {\n <div class=\"fk-dialog__header\">\n <ng-content select=\"[fkDialogHeader]\" />\n\n @if (!customHeader() && header()) {\n <span class=\"fk-dialog__title\" [id]=\"titleId\">{{ header() }}</span>\n }\n\n @if (closable()) {\n <button\n class=\"fk-dialog__close\"\n type=\"button\"\n aria-label=\"Close dialog\"\n (click)=\"close()\"\n >\n &times;\n </button>\n }\n </div>\n }\n\n <div class=\"fk-dialog__body\" [class.fk-dialog__body--flex]=\"flexBody()\">\n <ng-content />\n </div>\n\n <ng-content select=\"[libDialogFooter]\" />\n </div>\n </div>\n}\n", styles: [":host{display:contents}.fk-dialog__overlay{position:fixed;inset:0;z-index:var(--fk-dialog-overlay-z-index, 1000);display:flex;align-items:center;justify-content:center;padding:var(--fk-dialog-panel-margin, var(--fk-rhythm-4, 1rem))}.fk-dialog__overlay--modal{background:var(--fk-dialog-overlay-bg, rgba(0, 0, 0, .5))}.fk-dialog__overlay.fk-dialog__animate-overlay--in{animation:fk-dialog-overlay-fade-in .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__overlay.fk-dialog__animate-overlay--out{animation:fk-dialog-overlay-fade-out .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__overlay.fk-dialog__animate-overlay--none{animation:none}.fk-dialog__panel{display:flex;flex-direction:column;background:var(--fk-dialog-panel-bg, var(--fk-color-surface, #ffffff));border:var(--fk-dialog-panel-border, none);border-radius:var(--fk-dialog-panel-border-radius, var(--fk-radius-lg, .75rem));box-shadow:var(--fk-dialog-panel-shadow, 0 8px 32px rgba(0, 0, 0, .12));max-height:var(--fk-dialog-panel-max-height, 85vh);width:100%;overflow:clip}.fk-dialog__panel--sm{max-width:var(--fk-dialog-width-sm, 24rem)}.fk-dialog__panel--md{max-width:var(--fk-dialog-width-md, 32rem)}.fk-dialog__panel--lg{max-width:var(--fk-dialog-width-lg, 40rem)}.fk-dialog__panel--xl{max-width:var(--fk-dialog-width-xl, 52rem)}.fk-dialog__panel--fullscreen{max-width:none;max-height:none;width:100%;height:100%;border-radius:0}@media(max-width:47.999em){.fk-dialog__panel--fullscreen-auto{max-width:none;max-height:none;width:100%;height:100%;border-radius:0}}.fk-dialog__panel--top{align-self:flex-start}.fk-dialog__panel.fk-dialog__animate-panel--scale-fade{animation:fk-dialog-scale-fade-in .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__panel.fk-dialog__animate-panel-out--scale-fade{animation:fk-dialog-scale-fade-out .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__panel.fk-dialog__animate-panel--fade{animation:fk-dialog-fade-in .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__panel.fk-dialog__animate-panel-out--fade{animation:fk-dialog-fade-out .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__panel.fk-dialog__animate-panel--slide-up{animation:fk-dialog-slide-up-in .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__panel.fk-dialog__animate-panel-out--slide-up{animation:fk-dialog-slide-up-out .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__panel.fk-dialog__animate-panel--slide-down{animation:fk-dialog-slide-down-in .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__panel.fk-dialog__animate-panel-out--slide-down{animation:fk-dialog-slide-down-out .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__header{display:flex;align-items:center;justify-content:center;position:relative;padding:var(--fk-dialog-header-padding, var(--fk-rhythm-4, 1rem) var(--fk-dialog-header-padding-inline, var(--fk-rhythm-6, 1.5rem)));flex-shrink:0}.fk-dialog__title{font-family:var(--fk-font-family-base, \"Inter\", ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, \"Apple Color Emoji\", \"Segoe UI Emoji\");font-size:var(--fk-typography-h4-font-size, 1.125rem);font-weight:var(--fk-font-weight-semibold, 600);color:var(--fk-color-text, #1f2d3d);line-height:var(--fk-typography-h4-line-height, 1.25);padding-inline-end:var(--fk-rhythm-7, 2rem)}.fk-dialog__close{position:absolute;right:var(--fk-dialog-header-padding-inline, var(--fk-rhythm-6, 1.5rem));display:flex;align-items:center;justify-content:center;width:var(--fk-dialog-close-size, 2rem);height:var(--fk-dialog-close-size, 2rem);padding:0;border:none;border-radius:var(--fk-radius-sm, .25rem);background:transparent;color:var(--fk-dialog-close-color, var(--fk-color-muted, #8a98a8));font-size:var(--fk-font-size-xl, 1.25rem);line-height:1;cursor:pointer;transition:color .15s ease,background-color .15s ease}.fk-dialog__close:hover{color:var(--fk-dialog-close-color-hover, var(--fk-color-text, #1f2d3d));background-color:var(--fk-color-surface-muted, #f7f9fb)}.fk-dialog__close:focus-visible{outline:none;box-shadow:var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18))}.fk-dialog__body{flex:1;padding:var(--fk-dialog-body-padding, var(--fk-rhythm-6, 1.5rem));overflow-y:auto;overscroll-behavior:contain;container-type:inline-size}.fk-dialog__body--flex{display:flex;flex-direction:column;overflow:hidden}::ng-deep [libDialogFooter]{display:flex;align-items:center;justify-content:center;gap:var(--fk-dialog-footer-gap, .75rem);padding:var(--fk-dialog-footer-padding, var(--fk-rhythm-4, 1rem) var(--fk-rhythm-6, 1.5rem));border-top:var(--fk-dialog-footer-border, 1px solid var(--fk-color-border, #d9e2ee));flex-shrink:0}::ng-deep [libDialogFooter]>*{flex:1 1 0;min-width:0}::ng-deep [fkDialogActions]{display:flex;gap:var(--fk-dialog-actions-gap, var(--fk-rhythm-3, .75rem));margin-top:var(--fk-dialog-actions-margin-top, var(--fk-rhythm-5, 1.25rem))}::ng-deep [fkDialogActions]>*{flex:1 1 0;min-width:0}@container (max-width: 24rem){::ng-deep [fkDialogActions]{flex-direction:column-reverse}::ng-deep [fkDialogActions]>*{flex:none;width:100%}}@keyframes fk-dialog-overlay-fade-in{0%{opacity:0}to{opacity:1}}@keyframes fk-dialog-overlay-fade-out{0%{opacity:1}to{opacity:0}}@keyframes fk-dialog-scale-fade-in{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}@keyframes fk-dialog-scale-fade-out{0%{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(.95)}}@keyframes fk-dialog-fade-in{0%{opacity:0}to{opacity:1}}@keyframes fk-dialog-fade-out{0%{opacity:1}to{opacity:0}}@keyframes fk-dialog-slide-up-in{0%{opacity:0;transform:translateY(1rem)}to{opacity:1;transform:translateY(0)}}@keyframes fk-dialog-slide-up-out{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(1rem)}}@keyframes fk-dialog-slide-down-in{0%{opacity:0;transform:translateY(-1rem)}to{opacity:1;transform:translateY(0)}}@keyframes fk-dialog-slide-down-out{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(-1rem)}}@media(prefers-reduced-motion:reduce){.fk-dialog__animate-overlay--in,.fk-dialog__animate-overlay--out,.fk-dialog__animate-panel--scale-fade,.fk-dialog__animate-panel--fade,.fk-dialog__animate-panel--slide-up,.fk-dialog__animate-panel--slide-down,.fk-dialog__animate-panel-out--scale-fade,.fk-dialog__animate-panel-out--fade,.fk-dialog__animate-panel-out--slide-up,.fk-dialog__animate-panel-out--slide-down{animation:none}}\n"], dependencies: [{ kind: "ngmodule", type: A11yModule }, { kind: "directive", type: i1.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
173
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: DialogComponent, isStandalone: true, selector: "fk-dialog", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, modal: { classPropertyName: "modal", publicName: "modal", isSignal: true, isRequired: false, transformFunction: null }, closable: { classPropertyName: "closable", publicName: "closable", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, header: { classPropertyName: "header", publicName: "header", isSignal: true, isRequired: false, transformFunction: null }, restoreFocus: { classPropertyName: "restoreFocus", publicName: "restoreFocus", isSignal: true, isRequired: false, transformFunction: null }, autoFocus: { classPropertyName: "autoFocus", publicName: "autoFocus", isSignal: true, isRequired: false, transformFunction: null }, animation: { classPropertyName: "animation", publicName: "animation", isSignal: true, isRequired: false, transformFunction: null }, preventClose: { classPropertyName: "preventClose", publicName: "preventClose", isSignal: true, isRequired: false, transformFunction: null }, canClose: { classPropertyName: "canClose", publicName: "canClose", isSignal: true, isRequired: false, transformFunction: null }, fullscreenMobile: { classPropertyName: "fullscreenMobile", publicName: "fullscreenMobile", isSignal: true, isRequired: false, transformFunction: null }, flexBody: { classPropertyName: "flexBody", publicName: "flexBody", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "ariaDescribedBy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { openChange: "openChange", beforeOpen: "beforeOpen", opened: "opened", beforeClose: "beforeClose", closed: "closed" }, host: { properties: { "class": "this.hostClass", "attr.id": "this.hostId" } }, queries: [{ propertyName: "customHeader", first: true, predicate: FkDialogHeaderDirective, descendants: true, isSignal: true }], ngImport: i0, template: "@if (visible()) {\n <div\n class=\"fk-dialog__panel\"\n [class.fk-dialog__animate-panel--scale-fade]=\"\n animation() === 'scale-fade' && !animatingOut()\n \"\n [class.fk-dialog__animate-panel--fade]=\"\n animation() === 'fade' && !animatingOut()\n \"\n [class.fk-dialog__animate-panel--slide-up]=\"\n animation() === 'slide-up' && !animatingOut()\n \"\n [class.fk-dialog__animate-panel--slide-down]=\"\n animation() === 'slide-down' && !animatingOut()\n \"\n [class.fk-dialog__animate-panel-out--scale-fade]=\"\n animation() === 'scale-fade' && animatingOut()\n \"\n [class.fk-dialog__animate-panel-out--fade]=\"\n animation() === 'fade' && animatingOut()\n \"\n [class.fk-dialog__animate-panel-out--slide-up]=\"\n animation() === 'slide-up' && animatingOut()\n \"\n [class.fk-dialog__animate-panel-out--slide-down]=\"\n animation() === 'slide-down' && animatingOut()\n \"\n [class.fk-dialog__panel--sm]=\"size() === 'sm'\"\n [class.fk-dialog__panel--md]=\"size() === 'md'\"\n [class.fk-dialog__panel--lg]=\"size() === 'lg'\"\n [class.fk-dialog__panel--xl]=\"size() === 'xl'\"\n [class.fk-dialog__panel--fullscreen]=\"size() === 'fullscreen'\"\n [class.fk-dialog__panel--fullscreen-auto]=\"fullscreenMobile()\"\n [class.fk-dialog__panel--top]=\"position() === 'top'\"\n role=\"dialog\"\n [attr.aria-modal]=\"modal() ? 'true' : null\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledBy()\"\n [attr.aria-describedby]=\"ariaDescribedBy()\"\n [cdkTrapFocus]=\"modal()\"\n [cdkTrapFocusAutoCapture]=\"autoFocus()\"\n (animationend)=\"onExitAnimationDone()\"\n >\n @if (customHeader() || header() || closable()) {\n <div class=\"fk-dialog__header\">\n <ng-content select=\"[fkDialogHeader]\" />\n\n @if (!customHeader() && header()) {\n <span class=\"fk-dialog__title\" [id]=\"titleId\">{{ header() }}</span>\n }\n\n @if (closable()) {\n <button\n class=\"fk-dialog__close\"\n type=\"button\"\n aria-label=\"Close dialog\"\n (click)=\"close()\"\n >\n &times;\n </button>\n }\n </div>\n }\n\n <div class=\"fk-dialog__body\" [class.fk-dialog__body--flex]=\"flexBody()\">\n <ng-content />\n </div>\n\n <ng-content select=\"[libDialogFooter]\" />\n </div>\n}\n", styles: [":host{display:contents}.fk-dialog__panel{display:flex;flex-direction:column;background:var(--fk-dialog-panel-bg, var(--fk-color-surface, #ffffff));border:var(--fk-dialog-panel-border, none);border-radius:var(--fk-dialog-panel-border-radius, var(--fk-radius-lg, .75rem));box-shadow:var(--fk-dialog-panel-shadow, 0 8px 32px rgba(0, 0, 0, .12));max-height:var(--fk-dialog-panel-max-height, 85vh);width:calc(100vw - 2 * var(--fk-dialog-panel-margin, var(--fk-rhythm-4, 1rem)));overflow:clip}.fk-dialog__panel--sm{max-width:var(--fk-dialog-width-sm, 24rem)}.fk-dialog__panel--md{max-width:var(--fk-dialog-width-md, 32rem)}.fk-dialog__panel--lg{max-width:var(--fk-dialog-width-lg, 40rem)}.fk-dialog__panel--xl{max-width:var(--fk-dialog-width-xl, 52rem)}.fk-dialog__panel--fullscreen{max-width:none;max-height:none;width:100%;height:100%;border-radius:0}@media(max-width:47.999em){.fk-dialog__panel--fullscreen-auto{max-width:none;max-height:none;width:100%;height:100%;border-radius:0}}.fk-dialog__panel--top{align-self:flex-start}.fk-dialog__panel.fk-dialog__animate-panel--scale-fade{animation:fk-dialog-scale-fade-in .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__panel.fk-dialog__animate-panel-out--scale-fade{animation:fk-dialog-scale-fade-out .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__panel.fk-dialog__animate-panel--fade{animation:fk-dialog-fade-in .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__panel.fk-dialog__animate-panel-out--fade{animation:fk-dialog-fade-out .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__panel.fk-dialog__animate-panel--slide-up{animation:fk-dialog-slide-up-in .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__panel.fk-dialog__animate-panel-out--slide-up{animation:fk-dialog-slide-up-out .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__panel.fk-dialog__animate-panel--slide-down{animation:fk-dialog-slide-down-in .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__panel.fk-dialog__animate-panel-out--slide-down{animation:fk-dialog-slide-down-out .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__header{display:flex;align-items:center;justify-content:center;position:relative;padding:var(--fk-dialog-header-padding, var(--fk-rhythm-4, 1rem) var(--fk-dialog-header-padding-inline, var(--fk-rhythm-6, 1.5rem)));flex-shrink:0}.fk-dialog__title{font-family:var(--fk-font-family-base, \"Inter\", ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, \"Apple Color Emoji\", \"Segoe UI Emoji\");font-size:var(--fk-typography-h4-font-size, 1.125rem);font-weight:var(--fk-font-weight-semibold, 600);color:var(--fk-color-text, #1f2d3d);line-height:var(--fk-typography-h4-line-height, 1.25);padding-inline-end:var(--fk-rhythm-7, 2rem)}.fk-dialog__close{position:absolute;right:var(--fk-dialog-header-padding-inline, var(--fk-rhythm-6, 1.5rem));display:flex;align-items:center;justify-content:center;width:var(--fk-dialog-close-size, 2rem);height:var(--fk-dialog-close-size, 2rem);padding:0;border:none;border-radius:var(--fk-radius-sm, .25rem);background:transparent;color:var(--fk-dialog-close-color, var(--fk-color-muted, #8a98a8));font-size:var(--fk-font-size-xl, 1.25rem);line-height:1;cursor:pointer;transition:color .15s ease,background-color .15s ease}.fk-dialog__close:hover{color:var(--fk-dialog-close-color-hover, var(--fk-color-text, #1f2d3d));background-color:var(--fk-color-surface-muted, #f7f9fb)}.fk-dialog__close:focus-visible{outline:none;box-shadow:var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18))}.fk-dialog__body{flex:1;padding:var(--fk-dialog-body-padding, var(--fk-rhythm-6, 1.5rem));overflow-y:auto;overscroll-behavior:contain;container-type:inline-size}.fk-dialog__body--flex{display:flex;flex-direction:column;overflow:hidden}::ng-deep [libDialogFooter]{display:flex;align-items:center;justify-content:center;gap:var(--fk-dialog-footer-gap, .75rem);padding:var(--fk-dialog-footer-padding, var(--fk-rhythm-4, 1rem) var(--fk-rhythm-6, 1.5rem));border-top:var(--fk-dialog-footer-border, 1px solid var(--fk-color-border, #d9e2ee));flex-shrink:0}::ng-deep [libDialogFooter]>*{flex:1 1 0;min-width:0}::ng-deep [fkDialogActions]{display:flex;gap:var(--fk-dialog-actions-gap, var(--fk-rhythm-3, .75rem));margin-top:var(--fk-dialog-actions-margin-top, var(--fk-rhythm-5, 1.25rem))}::ng-deep [fkDialogActions]>*{flex:1 1 0;min-width:0}@container (max-width: 24rem){::ng-deep [fkDialogActions]{flex-direction:column-reverse}::ng-deep [fkDialogActions]>*{flex:none;width:100%}}@keyframes fk-dialog-scale-fade-in{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}@keyframes fk-dialog-scale-fade-out{0%{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(.95)}}@keyframes fk-dialog-fade-in{0%{opacity:0}to{opacity:1}}@keyframes fk-dialog-fade-out{0%{opacity:1}to{opacity:0}}@keyframes fk-dialog-slide-up-in{0%{opacity:0;transform:translateY(1rem)}to{opacity:1;transform:translateY(0)}}@keyframes fk-dialog-slide-up-out{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(1rem)}}@keyframes fk-dialog-slide-down-in{0%{opacity:0;transform:translateY(-1rem)}to{opacity:1;transform:translateY(0)}}@keyframes fk-dialog-slide-down-out{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(-1rem)}}@media(prefers-reduced-motion:reduce){.fk-dialog__animate-panel--scale-fade,.fk-dialog__animate-panel--fade,.fk-dialog__animate-panel--slide-up,.fk-dialog__animate-panel--slide-down,.fk-dialog__animate-panel-out--scale-fade,.fk-dialog__animate-panel-out--fade,.fk-dialog__animate-panel-out--slide-up,.fk-dialog__animate-panel-out--slide-down{animation:none}}\n"], dependencies: [{ kind: "ngmodule", type: A11yModule }, { kind: "directive", type: i1.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
200
174
  }
201
175
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DialogComponent, decorators: [{
202
176
  type: Component,
203
- args: [{ selector: 'fk-dialog', standalone: true, imports: [A11yModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (visible()) {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <div\n class=\"fk-dialog__overlay\"\n [class.fk-dialog__overlay--modal]=\"modal()\"\n [class.fk-dialog__animate-overlay--in]=\"!animatingOut()\"\n [class.fk-dialog__animate-overlay--out]=\"animatingOut()\"\n [class.fk-dialog__animate-overlay--none]=\"animation() === 'none'\"\n (click)=\"onOverlayClick()\"\n (animationend)=\"onExitAnimationDone()\"\n >\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -->\n <div\n class=\"fk-dialog__panel\"\n [class.fk-dialog__animate-panel--scale-fade]=\"\n animation() === 'scale-fade' && !animatingOut()\n \"\n [class.fk-dialog__animate-panel--fade]=\"\n animation() === 'fade' && !animatingOut()\n \"\n [class.fk-dialog__animate-panel--slide-up]=\"\n animation() === 'slide-up' && !animatingOut()\n \"\n [class.fk-dialog__animate-panel--slide-down]=\"\n animation() === 'slide-down' && !animatingOut()\n \"\n [class.fk-dialog__animate-panel-out--scale-fade]=\"\n animation() === 'scale-fade' && animatingOut()\n \"\n [class.fk-dialog__animate-panel-out--fade]=\"\n animation() === 'fade' && animatingOut()\n \"\n [class.fk-dialog__animate-panel-out--slide-up]=\"\n animation() === 'slide-up' && animatingOut()\n \"\n [class.fk-dialog__animate-panel-out--slide-down]=\"\n animation() === 'slide-down' && animatingOut()\n \"\n [class.fk-dialog__panel--sm]=\"size() === 'sm'\"\n [class.fk-dialog__panel--md]=\"size() === 'md'\"\n [class.fk-dialog__panel--lg]=\"size() === 'lg'\"\n [class.fk-dialog__panel--xl]=\"size() === 'xl'\"\n [class.fk-dialog__panel--fullscreen]=\"size() === 'fullscreen'\"\n [class.fk-dialog__panel--fullscreen-auto]=\"fullscreenMobile()\"\n [class.fk-dialog__panel--top]=\"position() === 'top'\"\n role=\"dialog\"\n [attr.aria-modal]=\"modal() ? 'true' : null\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledBy()\"\n [attr.aria-describedby]=\"ariaDescribedBy()\"\n [cdkTrapFocus]=\"modal()\"\n [cdkTrapFocusAutoCapture]=\"autoFocus()\"\n (click)=\"$event.stopPropagation()\"\n >\n @if (customHeader() || header() || closable()) {\n <div class=\"fk-dialog__header\">\n <ng-content select=\"[fkDialogHeader]\" />\n\n @if (!customHeader() && header()) {\n <span class=\"fk-dialog__title\" [id]=\"titleId\">{{ header() }}</span>\n }\n\n @if (closable()) {\n <button\n class=\"fk-dialog__close\"\n type=\"button\"\n aria-label=\"Close dialog\"\n (click)=\"close()\"\n >\n &times;\n </button>\n }\n </div>\n }\n\n <div class=\"fk-dialog__body\" [class.fk-dialog__body--flex]=\"flexBody()\">\n <ng-content />\n </div>\n\n <ng-content select=\"[libDialogFooter]\" />\n </div>\n </div>\n}\n", styles: [":host{display:contents}.fk-dialog__overlay{position:fixed;inset:0;z-index:var(--fk-dialog-overlay-z-index, 1000);display:flex;align-items:center;justify-content:center;padding:var(--fk-dialog-panel-margin, var(--fk-rhythm-4, 1rem))}.fk-dialog__overlay--modal{background:var(--fk-dialog-overlay-bg, rgba(0, 0, 0, .5))}.fk-dialog__overlay.fk-dialog__animate-overlay--in{animation:fk-dialog-overlay-fade-in .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__overlay.fk-dialog__animate-overlay--out{animation:fk-dialog-overlay-fade-out .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__overlay.fk-dialog__animate-overlay--none{animation:none}.fk-dialog__panel{display:flex;flex-direction:column;background:var(--fk-dialog-panel-bg, var(--fk-color-surface, #ffffff));border:var(--fk-dialog-panel-border, none);border-radius:var(--fk-dialog-panel-border-radius, var(--fk-radius-lg, .75rem));box-shadow:var(--fk-dialog-panel-shadow, 0 8px 32px rgba(0, 0, 0, .12));max-height:var(--fk-dialog-panel-max-height, 85vh);width:100%;overflow:clip}.fk-dialog__panel--sm{max-width:var(--fk-dialog-width-sm, 24rem)}.fk-dialog__panel--md{max-width:var(--fk-dialog-width-md, 32rem)}.fk-dialog__panel--lg{max-width:var(--fk-dialog-width-lg, 40rem)}.fk-dialog__panel--xl{max-width:var(--fk-dialog-width-xl, 52rem)}.fk-dialog__panel--fullscreen{max-width:none;max-height:none;width:100%;height:100%;border-radius:0}@media(max-width:47.999em){.fk-dialog__panel--fullscreen-auto{max-width:none;max-height:none;width:100%;height:100%;border-radius:0}}.fk-dialog__panel--top{align-self:flex-start}.fk-dialog__panel.fk-dialog__animate-panel--scale-fade{animation:fk-dialog-scale-fade-in .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__panel.fk-dialog__animate-panel-out--scale-fade{animation:fk-dialog-scale-fade-out .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__panel.fk-dialog__animate-panel--fade{animation:fk-dialog-fade-in .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__panel.fk-dialog__animate-panel-out--fade{animation:fk-dialog-fade-out .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__panel.fk-dialog__animate-panel--slide-up{animation:fk-dialog-slide-up-in .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__panel.fk-dialog__animate-panel-out--slide-up{animation:fk-dialog-slide-up-out .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__panel.fk-dialog__animate-panel--slide-down{animation:fk-dialog-slide-down-in .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__panel.fk-dialog__animate-panel-out--slide-down{animation:fk-dialog-slide-down-out .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__header{display:flex;align-items:center;justify-content:center;position:relative;padding:var(--fk-dialog-header-padding, var(--fk-rhythm-4, 1rem) var(--fk-dialog-header-padding-inline, var(--fk-rhythm-6, 1.5rem)));flex-shrink:0}.fk-dialog__title{font-family:var(--fk-font-family-base, \"Inter\", ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, \"Apple Color Emoji\", \"Segoe UI Emoji\");font-size:var(--fk-typography-h4-font-size, 1.125rem);font-weight:var(--fk-font-weight-semibold, 600);color:var(--fk-color-text, #1f2d3d);line-height:var(--fk-typography-h4-line-height, 1.25);padding-inline-end:var(--fk-rhythm-7, 2rem)}.fk-dialog__close{position:absolute;right:var(--fk-dialog-header-padding-inline, var(--fk-rhythm-6, 1.5rem));display:flex;align-items:center;justify-content:center;width:var(--fk-dialog-close-size, 2rem);height:var(--fk-dialog-close-size, 2rem);padding:0;border:none;border-radius:var(--fk-radius-sm, .25rem);background:transparent;color:var(--fk-dialog-close-color, var(--fk-color-muted, #8a98a8));font-size:var(--fk-font-size-xl, 1.25rem);line-height:1;cursor:pointer;transition:color .15s ease,background-color .15s ease}.fk-dialog__close:hover{color:var(--fk-dialog-close-color-hover, var(--fk-color-text, #1f2d3d));background-color:var(--fk-color-surface-muted, #f7f9fb)}.fk-dialog__close:focus-visible{outline:none;box-shadow:var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18))}.fk-dialog__body{flex:1;padding:var(--fk-dialog-body-padding, var(--fk-rhythm-6, 1.5rem));overflow-y:auto;overscroll-behavior:contain;container-type:inline-size}.fk-dialog__body--flex{display:flex;flex-direction:column;overflow:hidden}::ng-deep [libDialogFooter]{display:flex;align-items:center;justify-content:center;gap:var(--fk-dialog-footer-gap, .75rem);padding:var(--fk-dialog-footer-padding, var(--fk-rhythm-4, 1rem) var(--fk-rhythm-6, 1.5rem));border-top:var(--fk-dialog-footer-border, 1px solid var(--fk-color-border, #d9e2ee));flex-shrink:0}::ng-deep [libDialogFooter]>*{flex:1 1 0;min-width:0}::ng-deep [fkDialogActions]{display:flex;gap:var(--fk-dialog-actions-gap, var(--fk-rhythm-3, .75rem));margin-top:var(--fk-dialog-actions-margin-top, var(--fk-rhythm-5, 1.25rem))}::ng-deep [fkDialogActions]>*{flex:1 1 0;min-width:0}@container (max-width: 24rem){::ng-deep [fkDialogActions]{flex-direction:column-reverse}::ng-deep [fkDialogActions]>*{flex:none;width:100%}}@keyframes fk-dialog-overlay-fade-in{0%{opacity:0}to{opacity:1}}@keyframes fk-dialog-overlay-fade-out{0%{opacity:1}to{opacity:0}}@keyframes fk-dialog-scale-fade-in{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}@keyframes fk-dialog-scale-fade-out{0%{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(.95)}}@keyframes fk-dialog-fade-in{0%{opacity:0}to{opacity:1}}@keyframes fk-dialog-fade-out{0%{opacity:1}to{opacity:0}}@keyframes fk-dialog-slide-up-in{0%{opacity:0;transform:translateY(1rem)}to{opacity:1;transform:translateY(0)}}@keyframes fk-dialog-slide-up-out{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(1rem)}}@keyframes fk-dialog-slide-down-in{0%{opacity:0;transform:translateY(-1rem)}to{opacity:1;transform:translateY(0)}}@keyframes fk-dialog-slide-down-out{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(-1rem)}}@media(prefers-reduced-motion:reduce){.fk-dialog__animate-overlay--in,.fk-dialog__animate-overlay--out,.fk-dialog__animate-panel--scale-fade,.fk-dialog__animate-panel--fade,.fk-dialog__animate-panel--slide-up,.fk-dialog__animate-panel--slide-down,.fk-dialog__animate-panel-out--scale-fade,.fk-dialog__animate-panel-out--fade,.fk-dialog__animate-panel-out--slide-up,.fk-dialog__animate-panel-out--slide-down{animation:none}}\n"] }]
204
- }], ctorParameters: () => [], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }], modal: [{ type: i0.Input, args: [{ isSignal: true, alias: "modal", required: false }] }], closable: [{ type: i0.Input, args: [{ isSignal: true, alias: "closable", required: false }] }], closeOnEscape: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnEscape", required: false }] }], closeOnBackdrop: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnBackdrop", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], header: [{ type: i0.Input, args: [{ isSignal: true, alias: "header", required: false }] }], restoreFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "restoreFocus", required: false }] }], autoFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoFocus", required: false }] }], animation: [{ type: i0.Input, args: [{ isSignal: true, alias: "animation", required: false }] }], preventClose: [{ type: i0.Input, args: [{ isSignal: true, alias: "preventClose", required: false }] }], canClose: [{ type: i0.Input, args: [{ isSignal: true, alias: "canClose", required: false }] }], fullscreenMobile: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullscreenMobile", required: false }] }], flexBody: [{ type: i0.Input, args: [{ isSignal: true, alias: "flexBody", required: false }] }], customHeader: [{ type: i0.ContentChild, args: [i0.forwardRef(() => FkDialogHeaderDirective), { isSignal: true }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], ariaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaDescribedBy", required: false }] }], openChange: [{ type: i0.Output, args: ["openChange"] }], beforeOpen: [{ type: i0.Output, args: ["beforeOpen"] }], opened: [{ type: i0.Output, args: ["opened"] }], beforeClose: [{ type: i0.Output, args: ["beforeClose"] }], closed: [{ type: i0.Output, args: ["closed"] }], hostClass: [{
177
+ args: [{ selector: 'fk-dialog', standalone: true, imports: [A11yModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (visible()) {\n <div\n class=\"fk-dialog__panel\"\n [class.fk-dialog__animate-panel--scale-fade]=\"\n animation() === 'scale-fade' && !animatingOut()\n \"\n [class.fk-dialog__animate-panel--fade]=\"\n animation() === 'fade' && !animatingOut()\n \"\n [class.fk-dialog__animate-panel--slide-up]=\"\n animation() === 'slide-up' && !animatingOut()\n \"\n [class.fk-dialog__animate-panel--slide-down]=\"\n animation() === 'slide-down' && !animatingOut()\n \"\n [class.fk-dialog__animate-panel-out--scale-fade]=\"\n animation() === 'scale-fade' && animatingOut()\n \"\n [class.fk-dialog__animate-panel-out--fade]=\"\n animation() === 'fade' && animatingOut()\n \"\n [class.fk-dialog__animate-panel-out--slide-up]=\"\n animation() === 'slide-up' && animatingOut()\n \"\n [class.fk-dialog__animate-panel-out--slide-down]=\"\n animation() === 'slide-down' && animatingOut()\n \"\n [class.fk-dialog__panel--sm]=\"size() === 'sm'\"\n [class.fk-dialog__panel--md]=\"size() === 'md'\"\n [class.fk-dialog__panel--lg]=\"size() === 'lg'\"\n [class.fk-dialog__panel--xl]=\"size() === 'xl'\"\n [class.fk-dialog__panel--fullscreen]=\"size() === 'fullscreen'\"\n [class.fk-dialog__panel--fullscreen-auto]=\"fullscreenMobile()\"\n [class.fk-dialog__panel--top]=\"position() === 'top'\"\n role=\"dialog\"\n [attr.aria-modal]=\"modal() ? 'true' : null\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledBy()\"\n [attr.aria-describedby]=\"ariaDescribedBy()\"\n [cdkTrapFocus]=\"modal()\"\n [cdkTrapFocusAutoCapture]=\"autoFocus()\"\n (animationend)=\"onExitAnimationDone()\"\n >\n @if (customHeader() || header() || closable()) {\n <div class=\"fk-dialog__header\">\n <ng-content select=\"[fkDialogHeader]\" />\n\n @if (!customHeader() && header()) {\n <span class=\"fk-dialog__title\" [id]=\"titleId\">{{ header() }}</span>\n }\n\n @if (closable()) {\n <button\n class=\"fk-dialog__close\"\n type=\"button\"\n aria-label=\"Close dialog\"\n (click)=\"close()\"\n >\n &times;\n </button>\n }\n </div>\n }\n\n <div class=\"fk-dialog__body\" [class.fk-dialog__body--flex]=\"flexBody()\">\n <ng-content />\n </div>\n\n <ng-content select=\"[libDialogFooter]\" />\n </div>\n}\n", styles: [":host{display:contents}.fk-dialog__panel{display:flex;flex-direction:column;background:var(--fk-dialog-panel-bg, var(--fk-color-surface, #ffffff));border:var(--fk-dialog-panel-border, none);border-radius:var(--fk-dialog-panel-border-radius, var(--fk-radius-lg, .75rem));box-shadow:var(--fk-dialog-panel-shadow, 0 8px 32px rgba(0, 0, 0, .12));max-height:var(--fk-dialog-panel-max-height, 85vh);width:calc(100vw - 2 * var(--fk-dialog-panel-margin, var(--fk-rhythm-4, 1rem)));overflow:clip}.fk-dialog__panel--sm{max-width:var(--fk-dialog-width-sm, 24rem)}.fk-dialog__panel--md{max-width:var(--fk-dialog-width-md, 32rem)}.fk-dialog__panel--lg{max-width:var(--fk-dialog-width-lg, 40rem)}.fk-dialog__panel--xl{max-width:var(--fk-dialog-width-xl, 52rem)}.fk-dialog__panel--fullscreen{max-width:none;max-height:none;width:100%;height:100%;border-radius:0}@media(max-width:47.999em){.fk-dialog__panel--fullscreen-auto{max-width:none;max-height:none;width:100%;height:100%;border-radius:0}}.fk-dialog__panel--top{align-self:flex-start}.fk-dialog__panel.fk-dialog__animate-panel--scale-fade{animation:fk-dialog-scale-fade-in .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__panel.fk-dialog__animate-panel-out--scale-fade{animation:fk-dialog-scale-fade-out .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__panel.fk-dialog__animate-panel--fade{animation:fk-dialog-fade-in .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__panel.fk-dialog__animate-panel-out--fade{animation:fk-dialog-fade-out .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__panel.fk-dialog__animate-panel--slide-up{animation:fk-dialog-slide-up-in .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__panel.fk-dialog__animate-panel-out--slide-up{animation:fk-dialog-slide-up-out .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__panel.fk-dialog__animate-panel--slide-down{animation:fk-dialog-slide-down-in .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__panel.fk-dialog__animate-panel-out--slide-down{animation:fk-dialog-slide-down-out .2s cubic-bezier(.4,0,.2,1) both}.fk-dialog__header{display:flex;align-items:center;justify-content:center;position:relative;padding:var(--fk-dialog-header-padding, var(--fk-rhythm-4, 1rem) var(--fk-dialog-header-padding-inline, var(--fk-rhythm-6, 1.5rem)));flex-shrink:0}.fk-dialog__title{font-family:var(--fk-font-family-base, \"Inter\", ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, \"Apple Color Emoji\", \"Segoe UI Emoji\");font-size:var(--fk-typography-h4-font-size, 1.125rem);font-weight:var(--fk-font-weight-semibold, 600);color:var(--fk-color-text, #1f2d3d);line-height:var(--fk-typography-h4-line-height, 1.25);padding-inline-end:var(--fk-rhythm-7, 2rem)}.fk-dialog__close{position:absolute;right:var(--fk-dialog-header-padding-inline, var(--fk-rhythm-6, 1.5rem));display:flex;align-items:center;justify-content:center;width:var(--fk-dialog-close-size, 2rem);height:var(--fk-dialog-close-size, 2rem);padding:0;border:none;border-radius:var(--fk-radius-sm, .25rem);background:transparent;color:var(--fk-dialog-close-color, var(--fk-color-muted, #8a98a8));font-size:var(--fk-font-size-xl, 1.25rem);line-height:1;cursor:pointer;transition:color .15s ease,background-color .15s ease}.fk-dialog__close:hover{color:var(--fk-dialog-close-color-hover, var(--fk-color-text, #1f2d3d));background-color:var(--fk-color-surface-muted, #f7f9fb)}.fk-dialog__close:focus-visible{outline:none;box-shadow:var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18))}.fk-dialog__body{flex:1;padding:var(--fk-dialog-body-padding, var(--fk-rhythm-6, 1.5rem));overflow-y:auto;overscroll-behavior:contain;container-type:inline-size}.fk-dialog__body--flex{display:flex;flex-direction:column;overflow:hidden}::ng-deep [libDialogFooter]{display:flex;align-items:center;justify-content:center;gap:var(--fk-dialog-footer-gap, .75rem);padding:var(--fk-dialog-footer-padding, var(--fk-rhythm-4, 1rem) var(--fk-rhythm-6, 1.5rem));border-top:var(--fk-dialog-footer-border, 1px solid var(--fk-color-border, #d9e2ee));flex-shrink:0}::ng-deep [libDialogFooter]>*{flex:1 1 0;min-width:0}::ng-deep [fkDialogActions]{display:flex;gap:var(--fk-dialog-actions-gap, var(--fk-rhythm-3, .75rem));margin-top:var(--fk-dialog-actions-margin-top, var(--fk-rhythm-5, 1.25rem))}::ng-deep [fkDialogActions]>*{flex:1 1 0;min-width:0}@container (max-width: 24rem){::ng-deep [fkDialogActions]{flex-direction:column-reverse}::ng-deep [fkDialogActions]>*{flex:none;width:100%}}@keyframes fk-dialog-scale-fade-in{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}@keyframes fk-dialog-scale-fade-out{0%{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(.95)}}@keyframes fk-dialog-fade-in{0%{opacity:0}to{opacity:1}}@keyframes fk-dialog-fade-out{0%{opacity:1}to{opacity:0}}@keyframes fk-dialog-slide-up-in{0%{opacity:0;transform:translateY(1rem)}to{opacity:1;transform:translateY(0)}}@keyframes fk-dialog-slide-up-out{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(1rem)}}@keyframes fk-dialog-slide-down-in{0%{opacity:0;transform:translateY(-1rem)}to{opacity:1;transform:translateY(0)}}@keyframes fk-dialog-slide-down-out{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(-1rem)}}@media(prefers-reduced-motion:reduce){.fk-dialog__animate-panel--scale-fade,.fk-dialog__animate-panel--fade,.fk-dialog__animate-panel--slide-up,.fk-dialog__animate-panel--slide-down,.fk-dialog__animate-panel-out--scale-fade,.fk-dialog__animate-panel-out--fade,.fk-dialog__animate-panel-out--slide-up,.fk-dialog__animate-panel-out--slide-down{animation:none}}\n"] }]
178
+ }], ctorParameters: () => [], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }], modal: [{ type: i0.Input, args: [{ isSignal: true, alias: "modal", required: false }] }], closable: [{ type: i0.Input, args: [{ isSignal: true, alias: "closable", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], header: [{ type: i0.Input, args: [{ isSignal: true, alias: "header", required: false }] }], restoreFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "restoreFocus", required: false }] }], autoFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoFocus", required: false }] }], animation: [{ type: i0.Input, args: [{ isSignal: true, alias: "animation", required: false }] }], preventClose: [{ type: i0.Input, args: [{ isSignal: true, alias: "preventClose", required: false }] }], canClose: [{ type: i0.Input, args: [{ isSignal: true, alias: "canClose", required: false }] }], fullscreenMobile: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullscreenMobile", required: false }] }], flexBody: [{ type: i0.Input, args: [{ isSignal: true, alias: "flexBody", required: false }] }], customHeader: [{ type: i0.ContentChild, args: [i0.forwardRef(() => FkDialogHeaderDirective), { isSignal: true }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], ariaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaDescribedBy", required: false }] }], openChange: [{ type: i0.Output, args: ["openChange"] }], beforeOpen: [{ type: i0.Output, args: ["beforeOpen"] }], opened: [{ type: i0.Output, args: ["opened"] }], beforeClose: [{ type: i0.Output, args: ["beforeClose"] }], closed: [{ type: i0.Output, args: ["closed"] }], hostClass: [{
205
179
  type: HostBinding,
206
180
  args: ['class']
207
181
  }], hostId: [{
208
182
  type: HostBinding,
209
183
  args: ['attr.id']
210
- }], onEscapeKey: [{
211
- type: HostListener,
212
- args: ['document:keydown.escape']
213
184
  }] } });
214
185
 
215
186
  const DEFAULT_DIALOG_CONFIG = {
@@ -296,15 +267,23 @@ class DialogRef {
296
267
 
297
268
  const DIALOG_DATA = Symbol('DIALOG_DATA');
298
269
  const DIALOG_REF = Symbol('DIALOG_REF');
299
- const BASE_Z_INDEX = 1000;
300
- const Z_INDEX_STEP = 10;
270
+ /**
271
+ * Opens dialogs as CDK overlays.
272
+ *
273
+ * CDK owns the cross-cutting overlay concerns — backdrop, scroll blocking,
274
+ * centered positioning, z-index stacking (overlays layer by open order), and
275
+ * top-of-stack dispatch of Escape / outside clicks. The `DialogComponent` it
276
+ * hosts is just the panel chrome (header / body / footer, sizing, enter
277
+ * animation, focus trap). There is no global "opening X closes lower overlays"
278
+ * rule: a dialog opened over a drawer stacks on top of it, and Escape / an
279
+ * outside press dismisses whichever overlay is on top.
280
+ */
301
281
  class DialogService {
282
+ overlay = inject(Overlay);
302
283
  appRef = inject(ApplicationRef);
303
284
  injector = inject(EnvironmentInjector);
304
285
  doc = inject(DOCUMENT);
305
- orchestrator = inject(OverlayOrchestrator);
306
286
  activeDialogs = [];
307
- overlayIds = new Map();
308
287
  get openCount() {
309
288
  return this.activeDialogs.length;
310
289
  }
@@ -314,6 +293,24 @@ class DialogService {
314
293
  ...config,
315
294
  };
316
295
  const dialogRef = new DialogRef(mergedConfig);
296
+ const positionStrategy = this.overlay
297
+ .position()
298
+ .global()
299
+ .centerHorizontally();
300
+ if (mergedConfig.position === 'top') {
301
+ positionStrategy.top('10vh');
302
+ }
303
+ else {
304
+ positionStrategy.centerVertically();
305
+ }
306
+ const overlayRef = this.overlay.create({
307
+ hasBackdrop: mergedConfig.modal ?? true,
308
+ backdropClass: 'fk-dialog__backdrop',
309
+ panelClass: 'fk-dialog__pane',
310
+ scrollStrategy: this.overlay.scrollStrategies.block(),
311
+ positionStrategy,
312
+ disposeOnNavigation: true,
313
+ });
317
314
  const childInjector = Injector.create({
318
315
  parent: this.injector,
319
316
  providers: [
@@ -321,32 +318,34 @@ class DialogService {
321
318
  { provide: DIALOG_REF, useValue: dialogRef },
322
319
  ],
323
320
  });
324
- const hostRef = createComponent(DialogComponent, {
325
- environmentInjector: this.injector,
326
- elementInjector: childInjector,
327
- });
321
+ const hostRef = overlayRef.attach(new ComponentPortal(DialogComponent, null, childInjector));
328
322
  const contentRef = createComponent(content, {
329
323
  environmentInjector: this.injector,
330
324
  elementInjector: childInjector,
331
325
  hostElement: this.doc.createElement('div'),
332
326
  });
333
- this.applyConfig(hostRef, mergedConfig);
334
- this.appRef.attachView(hostRef.hostView);
335
327
  this.appRef.attachView(contentRef.hostView);
336
- this.doc.body.appendChild(hostRef.location.nativeElement);
337
328
  const entry = {
338
329
  ref: dialogRef,
330
+ overlayRef,
339
331
  hostRef,
340
332
  contentRef,
341
333
  };
342
334
  this.activeDialogs.push(entry);
343
- // Register with orchestrator — closes lower-priority overlays
344
- const overlayId = this.orchestrator.register({
345
- priority: OVERLAY_PRIORITY.DIALOG,
346
- type: 'dialog',
347
- close: () => dialogRef.close(),
335
+ this.applyConfig(hostRef, mergedConfig);
336
+ // CDK dispatches these to the top overlay only, so Escape / an outside
337
+ // press dismisses the topmost dialog. `dialogRef.close()` runs the
338
+ // preventClose + canClose guards.
339
+ overlayRef.keydownEvents().subscribe((event) => {
340
+ if (event.keyCode === ESCAPE && mergedConfig.closeOnEscape) {
341
+ dialogRef.close();
342
+ }
343
+ });
344
+ overlayRef.backdropClick().subscribe(() => {
345
+ if (mergedConfig.closeOnBackdrop) {
346
+ dialogRef.close();
347
+ }
348
348
  });
349
- this.overlayIds.set(entry, overlayId);
350
349
  hostRef.instance.beforeOpen.subscribe(() => {
351
350
  dialogRef.markBeforeOpen();
352
351
  });
@@ -361,42 +360,26 @@ class DialogService {
361
360
  });
362
361
  hostRef.setInput('open', true);
363
362
  hostRef.changeDetectorRef.detectChanges();
364
- const panelBody = hostRef.location.nativeElement.querySelector('.fk-dialog__body');
363
+ const panelBody = overlayRef.overlayElement.querySelector('.fk-dialog__body');
365
364
  if (panelBody) {
366
365
  panelBody.appendChild(contentRef.location.nativeElement);
367
366
  contentRef.changeDetectorRef.detectChanges();
368
- // Move [libDialogFooter] elements out of body to the panel root
369
- // so they render in the pinned footer area (after fk-dialog__body)
370
- const panel = panelBody.parentElement;
367
+ // Move [libDialogFooter] elements out of the body to the panel root so
368
+ // they render in the pinned footer area (after fk-dialog__body).
369
+ const panel = panelBody.closest('.fk-dialog__panel');
371
370
  const footerEls = panelBody.querySelectorAll('[libDialogFooter]');
372
371
  footerEls.forEach((el) => {
373
372
  panel?.appendChild(el);
374
373
  });
375
374
  }
376
- this.applyZIndex(entry);
377
375
  return dialogRef;
378
376
  }
379
377
  closeAll() {
380
378
  [...this.activeDialogs].forEach((entry) => entry.ref.close());
381
379
  }
382
- /** Returns true if the given entry is the topmost (last) active dialog. */
383
- isTopmost(entry) {
384
- return (this.activeDialogs.length > 0 &&
385
- this.activeDialogs[this.activeDialogs.length - 1] === entry);
386
- }
387
- applyZIndex(entry) {
388
- const index = this.activeDialogs.indexOf(entry);
389
- const zIndex = BASE_Z_INDEX + index * Z_INDEX_STEP;
390
- const overlay = entry.hostRef.location.nativeElement.querySelector('.fk-dialog__overlay');
391
- if (overlay) {
392
- overlay.style.zIndex = String(zIndex);
393
- }
394
- }
395
380
  applyConfig(hostRef, config) {
396
381
  hostRef.setInput('modal', config.modal ?? true);
397
382
  hostRef.setInput('closable', config.closable ?? true);
398
- hostRef.setInput('closeOnEscape', config.closeOnEscape ?? true);
399
- hostRef.setInput('closeOnBackdrop', config.closeOnBackdrop ?? false);
400
383
  hostRef.setInput('size', config.size ?? 'md');
401
384
  hostRef.setInput('position', config.position ?? 'center');
402
385
  hostRef.setInput('animation', config.animation ?? 'scale-fade');
@@ -412,21 +395,19 @@ class DialogService {
412
395
  hostRef.setInput('ariaDescribedBy', config.ariaDescribedBy ?? null);
413
396
  }
414
397
  destroyDialog(entry) {
415
- const overlayId = this.overlayIds.get(entry);
416
- if (overlayId) {
417
- this.orchestrator.unregister(overlayId);
418
- this.overlayIds.delete(entry);
419
- }
420
398
  const idx = this.activeDialogs.indexOf(entry);
421
399
  if (idx > -1) {
422
400
  this.activeDialogs.splice(idx, 1);
423
401
  }
402
+ // Let the component restore focus before the overlay (and its hosted
403
+ // component) are torn down.
424
404
  entry.hostRef.setInput('open', false);
425
405
  entry.hostRef.changeDetectorRef.detectChanges();
426
406
  this.appRef.detachView(entry.contentRef.hostView);
427
- this.appRef.detachView(entry.hostRef.hostView);
428
407
  entry.contentRef.destroy();
429
- entry.hostRef.destroy();
408
+ // Disposing the overlay detaches + destroys the hosted DialogComponent,
409
+ // removes the backdrop, and releases the scroll-block strategy.
410
+ entry.overlayRef.dispose();
430
411
  }
431
412
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DialogService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
432
413
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DialogService, providedIn: 'root' });