@praxisui/dialog 9.0.5 → 9.0.7

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/README.md CHANGED
@@ -64,13 +64,33 @@ export class UsersComponent {
64
64
  ## Custom Content And Tag Mode
65
65
 
66
66
  ```ts
67
- this.dialog.open(CustomerFormComponent, {
68
- title: "Edit customer",
69
- width: "720px",
70
- data: customer,
71
- });
67
+ import { inject, Injector } from "@angular/core";
68
+ import { PraxisDialog } from "@praxisui/dialog";
69
+
70
+ export class CustomerPage {
71
+ private readonly dialog = inject(PraxisDialog);
72
+ private readonly featureInjector = inject(Injector);
73
+
74
+ openCustomer(customer: Customer): void {
75
+ this.dialog.open(CustomerFormComponent, {
76
+ title: "Edit customer",
77
+ width: "720px",
78
+ data: customer,
79
+ injector: this.featureInjector,
80
+ });
81
+ }
82
+ }
72
83
  ```
73
84
 
85
+ Pass the feature `Injector` when the dynamic content depends on providers owned
86
+ by a lazy route or feature. If omitted, Dialog derives it from
87
+ `viewContainerRef` and then falls back to the injector that created
88
+ `PraxisDialog`. Metadata-driven `surface.open` dialogs forward their provider's
89
+ feature injector automatically.
90
+
91
+ `injector` and `viewContainerRef` are runtime-only integration fields. Do not
92
+ persist them in presets, AI-authored configuration or JSON documents.
93
+
74
94
  Use `openByRegistry(id, config)` or `openTemplateById(id, config)` for governed registries. Use `<praxis-dialog>` when the host template controls the shell instead of the overlay service.
75
95
 
76
96
  ```html
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
- "generatedAt": "2026-08-18T02:12:19.525Z",
3
+ "generatedAt": "2026-08-20T16:41:04.405Z",
4
4
  "packageName": "@praxisui/dialog",
5
- "packageVersion": "9.0.5",
5
+ "packageVersion": "9.0.7",
6
6
  "sourceRegistry": "praxis-component-registry-ingestion",
7
7
  "sourceRegistryVersion": "1.0.0",
8
8
  "componentCount": 1,
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, Directive, EventEmitter, inject, HostBinding, ContentChild, ViewChild, Output, Input, ViewEncapsulation, ChangeDetectionStrategy, Component, Injectable, ApplicationRef, Injector, TemplateRef, ENVIRONMENT_INITIALIZER } from '@angular/core';
2
+ import { InjectionToken, Directive, EventEmitter, inject, HostBinding, ContentChild, ViewChild, Output, Input, ViewEncapsulation, ChangeDetectionStrategy, Component, Injectable, Injector, ApplicationRef, TemplateRef, ENVIRONMENT_INITIALIZER } from '@angular/core';
3
3
  import { Subject, firstValueFrom } from 'rxjs';
4
4
  import * as i1 from '@angular/common';
5
5
  import { CommonModule } from '@angular/common';
@@ -61,6 +61,7 @@ class PraxisDialogRef {
61
61
  this.overlayRef = overlayRef;
62
62
  }
63
63
  beforeCloseHandler;
64
+ closePromise;
64
65
  setBeforeClose(handler) {
65
66
  this.beforeCloseHandler = handler;
66
67
  }
@@ -89,7 +90,13 @@ class PraxisDialogRef {
89
90
  notifyKeydown(ev) {
90
91
  this._keydownEvents.next(ev);
91
92
  }
92
- async close(result) {
93
+ close(result) {
94
+ if (this.closePromise)
95
+ return this.closePromise;
96
+ this.closePromise = this.performClose(result);
97
+ return this.closePromise;
98
+ }
99
+ async performClose(result) {
93
100
  this._beforeClosed.next(result);
94
101
  this._beforeClosed.complete();
95
102
  if (this.beforeCloseHandler) {
@@ -240,7 +247,6 @@ class PraxisDialogComponent {
240
247
  if (!this.overlayMode)
241
248
  this.opened.emit();
242
249
  });
243
- this.scheduleInitialFocus();
244
250
  }
245
251
  if (this.ariaRole === 'alertdialog') {
246
252
  const hasLabel = !!(this.title || this.ariaLabel || this.ariaLabelledBy);
@@ -255,6 +261,10 @@ class PraxisDialogComponent {
255
261
  catch { }
256
262
  }
257
263
  }
264
+ ngAfterViewInit() {
265
+ if (this.open)
266
+ this.scheduleInitialFocus();
267
+ }
258
268
  ngOnChanges(changes) {
259
269
  if (changes['open'] && this.open) {
260
270
  this.isDisplayed = true;
@@ -330,32 +340,44 @@ class PraxisDialogComponent {
330
340
  }
331
341
  catch { }
332
342
  }
343
+ /**
344
+ * Moves focus into the currently materialized panel. Overlay hosts call this
345
+ * after switching to the overlay template branch and attaching its content.
346
+ */
347
+ focusInitialElement() {
348
+ this.captureFocusOrigin();
349
+ this.applyInitialFocus();
350
+ }
333
351
  scheduleInitialFocus() {
334
- const panel = this.panelEl?.nativeElement;
335
- if (!panel)
336
- return;
352
+ this.captureFocusOrigin();
353
+ queueMicrotask(() => this.applyInitialFocus());
354
+ }
355
+ captureFocusOrigin() {
337
356
  const prev = document.activeElement;
338
357
  if (!this._previouslyFocused && this.restoreFocus)
339
358
  this._previouslyFocused = prev;
340
- queueMicrotask(() => {
341
- try {
342
- if (this.autoFocus && this.ariaRole === 'alertdialog') {
343
- // In alertdialog, focus the primary action if present
344
- const focused = this.focusPrimaryAction();
345
- if (focused)
346
- return;
347
- }
348
- if (this.autoFocusedElement) {
349
- const el = panel.querySelector(this.autoFocusedElement);
350
- el?.focus?.();
359
+ }
360
+ applyInitialFocus() {
361
+ const panel = this.panelEl?.nativeElement;
362
+ if (!panel || this.autoFocus === false)
363
+ return;
364
+ try {
365
+ if (this.autoFocus && this.ariaRole === 'alertdialog') {
366
+ // In alertdialog, focus the primary action if present
367
+ const focused = this.focusPrimaryAction();
368
+ if (focused)
351
369
  return;
352
- }
353
- // focus first focusable
354
- const focusable = panel.querySelector('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
355
- (focusable || panel).focus?.();
356
370
  }
357
- catch { }
358
- });
371
+ if (this.autoFocusedElement) {
372
+ const el = panel.querySelector(this.autoFocusedElement);
373
+ el?.focus?.();
374
+ return;
375
+ }
376
+ // focus first focusable
377
+ const focusable = panel.querySelector('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
378
+ (focusable || panel).focus?.();
379
+ }
380
+ catch { }
359
381
  }
360
382
  _previouslyFocused;
361
383
  ngOnDestroy() {
@@ -527,7 +549,7 @@ class PraxisDialogComponent {
527
549
  }
528
550
  }
529
551
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
530
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PraxisDialogComponent, isStandalone: true, selector: "praxis-dialog", inputs: { title: "title", actions: "actions", actionsLayout: "actionsLayout", animation: "animation", open: "open", width: "width", height: "height", minWidth: "minWidth", maxWidth: "maxWidth", minHeight: "minHeight", maxHeight: "maxHeight", themeColor: "themeColor", disableClose: "disableClose", hasBackdrop: "hasBackdrop", closeOnBackdropClick: "closeOnBackdropClick", overlayMode: "overlayMode", zIndex: "zIndex", panelClass: "panelClass", backdropClass: "backdropClass", position: "position", autoFocusedElement: "autoFocusedElement", autoFocus: "autoFocus", restoreFocus: "restoreFocus", id: "id", ariaRole: "ariaRole", ariaLabel: "ariaLabel", ariaLabelledBy: "ariaLabelledBy", ariaDescribedBy: "ariaDescribedBy", styles: "styles", titleIcon: "titleIcon" }, outputs: { action: "action", close: "close", opened: "opened", afterClosed: "afterClosed" }, host: { properties: { "class": "this.hostClass", "attr.tabindex": "this.tabindex" } }, queries: [{ propertyName: "titleTpl", first: true, predicate: PraxisDialogTitleDirective, descendants: true, read: PraxisDialogTitleDirective }, { propertyName: "actionsTpl", first: true, predicate: PraxisDialogActionsDirective, descendants: true, read: PraxisDialogActionsDirective }, { propertyName: "contentTpl", first: true, predicate: PraxisDialogContentDirective, descendants: true, read: PraxisDialogContentDirective }], viewQueries: [{ propertyName: "contentHost", first: true, predicate: CdkPortalOutlet, descendants: true }, { propertyName: "panelEl", first: true, predicate: ["panel"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "@let _titleId = (id ?? \"praxis-dialog\") + \"-title\";\n\n<ng-template #panelHeader>\n @if (titleTpl?.templateRef || title || titleIcon || displaysCloseButton) {\n <div class=\"pdx-dialog__title\">\n <div class=\"pdx-dialog__title-row\">\n @if (titleTpl?.templateRef) {\n <div class=\"pdx-dialog__title-custom\">\n <ng-container\n [ngTemplateOutlet]=\"titleTpl!.templateRef\"\n ></ng-container>\n </div>\n } @else {\n @if (titleIcon) {\n <mat-icon\n class=\"pdx-dialog__title-icon\"\n [praxisIcon]=\"titleIcon\"\n aria-hidden=\"true\"\n ></mat-icon>\n }\n @if (title) {\n <h2 class=\"pdx-dialog__title-text\" [attr.id]=\"_titleId\">\n {{ title }}\n </h2>\n }\n }\n @if (displaysCloseButton) {\n <button\n type=\"button\"\n class=\"pdx-dialog__close-btn\"\n [attr.aria-label]=\"closeButtonLabel\"\n [attr.title]=\"closeButtonLabel\"\n data-testid=\"dialog-close\"\n (click)=\"requestClose()\"\n >\n <mat-icon praxisIcon=\"close\" aria-hidden=\"true\"></mat-icon>\n </button>\n }\n </div>\n </div>\n }\n</ng-template>\n\n<ng-template #panelActions>\n <div\n class=\"pdx-dialog__actions\"\n [class.is-stretched]=\"actionsLayout === 'stretched'\"\n >\n @if (actionsTpl?.templateRef) {\n <ng-container [ngTemplateOutlet]=\"actionsTpl!.templateRef\"></ng-container>\n } @else {\n @for (a of actions; track a?.id ?? a) {\n <button\n type=\"button\"\n class=\"pdx-dialog__action-btn\"\n [attr.data-testid]=\"a.id || null\"\n [attr.data-role]=\"a.role || null\"\n [attr.data-theme]=\"a.themeColor || null\"\n [attr.data-fill]=\"a.fillMode || null\"\n [ngClass]=\"a.cssClass\"\n (click)=\"onActionClick(a)\"\n [attr.cdkFocusInitial]=\"\n a.role === 'primary' && ariaRole === 'alertdialog' ? '' : null\n \"\n >\n @if (a.icon) {\n <mat-icon [praxisIcon]=\"a.icon\"></mat-icon>\n } @else if (a.svgIcon) {\n <mat-icon [svgIcon]=\"a.svgIcon\"></mat-icon>\n }\n {{ a.text }}\n </button>\n }\n }\n </div>\n</ng-template>\n\n@if (overlayMode) {\n <div\n #panel\n class=\"pdx-dialog pdx-dialog--{{ themeColor }} pdx-dialog--layout-{{\n actionsLayout\n }}\"\n [attr.role]=\"ariaRole\"\n [attr.id]=\"id || null\"\n [attr.aria-modal]=\"true\"\n [attr.aria-label]=\"ariaLabel || null\"\n [attr.aria-labelledby]=\"ariaLabelledBy || (title ? _titleId : null)\"\n [attr.aria-describedby]=\"ariaDescribedBy || null\"\n (keydown)=\"onKeydown($event)\"\n cdkTrapFocus\n [ngClass]=\"panelNgClass\"\n [style.width]=\"width\"\n [style.height]=\"height\"\n [style.min-width]=\"minWidth\"\n [style.max-width]=\"maxWidth\"\n [style.min-height]=\"minHeight\"\n [style.max-height]=\"maxHeight\"\n [class.has-actions]=\"(actions.length || 0) > 0 || !!actionsTpl?.templateRef\"\n >\n <ng-container [ngTemplateOutlet]=\"panelHeader\"></ng-container>\n <div class=\"pdx-dialog__content\">\n @if (contentTpl?.templateRef) {\n <ng-container\n [ngTemplateOutlet]=\"contentTpl!.templateRef\"\n ></ng-container>\n } @else {\n <ng-template cdkPortalOutlet></ng-template>\n }\n </div>\n <ng-container [ngTemplateOutlet]=\"panelActions\"></ng-container>\n </div>\n} @else {\n <div\n class=\"pdx-dialog-overlay\"\n [class.has-backdrop]=\"hasBackdrop\"\n [hidden]=\"!isDisplayed\"\n (click)=\"onBackdrop($event)\"\n [ngClass]=\"backdropClass\"\n [style.z-index]=\"zIndex\"\n >\n <div class=\"pdx-dialog-shell\" (click)=\"$event.stopPropagation()\">\n <div\n #panel\n class=\"pdx-dialog pdx-dialog--{{ themeColor }} pdx-dialog--layout-{{\n actionsLayout\n }}\"\n [attr.role]=\"ariaRole\"\n [attr.id]=\"id || null\"\n [attr.aria-modal]=\"true\"\n [attr.aria-label]=\"ariaLabel || null\"\n [attr.aria-labelledby]=\"ariaLabelledBy || (title ? _titleId : null)\"\n [attr.aria-describedby]=\"ariaDescribedBy || null\"\n (keydown)=\"onKeydown($event)\"\n cdkTrapFocus\n [ngClass]=\"panelNgClass\"\n [style.width]=\"width\"\n [style.height]=\"height\"\n [style.min-width]=\"minWidth\"\n [style.max-width]=\"maxWidth\"\n [style.min-height]=\"minHeight\"\n [style.max-height]=\"maxHeight\"\n [style.top]=\"position?.top || null\"\n [style.bottom]=\"position?.bottom || null\"\n [style.left]=\"position?.left || null\"\n [style.right]=\"position?.right || null\"\n [class.pdx-has-position]=\"position\"\n [class.has-actions]=\"\n (actions.length || 0) > 0 || !!actionsTpl?.templateRef\n \"\n >\n <ng-container [ngTemplateOutlet]=\"panelHeader\"></ng-container>\n <div class=\"pdx-dialog__content\">\n @if (contentTpl?.templateRef) {\n <ng-container\n [ngTemplateOutlet]=\"contentTpl!.templateRef\"\n ></ng-container>\n } @else {\n <ng-template cdkPortalOutlet></ng-template>\n }\n </div>\n <ng-container [ngTemplateOutlet]=\"panelActions\"></ng-container>\n </div>\n </div>\n </div>\n}\n", styles: ["@charset \"UTF-8\";.pdx-dialog-host{--pdx-dialog-bg: var(--praxis-theme-surface, var(--md-sys-color-surface));--pdx-dialog-surface: var( --praxis-theme-surface-overlay, var(--md-sys-color-surface-container-high) );--pdx-dialog-border: var( --praxis-theme-outline, var(--md-sys-color-outline-variant) );--pdx-dialog-title-fg: var( --praxis-theme-on-surface, var(--md-sys-color-on-surface) );--pdx-dialog-elevation: var( --praxis-theme-elevation, var(--mat-elevation-level4) )}.pdx-dialog-overlay{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;z-index:var(--praxis-layer-dialog, 1300);background:transparent}.pdx-dialog-overlay.has-backdrop{background:var(--pdx-dialog-backdrop, rgba(0, 0, 0, .6))}.pdx-dialog-shell{display:contents}.pdx-dialog.pdx-has-position{position:absolute}.pdx-dialog{background:var(--pdx-dialog-container-color, var(--pdx-dialog-surface));color:var(--praxis-theme-on-surface, var(--md-sys-color-on-surface, #111));border:1px solid var(--pdx-dialog-border);border-radius:var(--pdx-dialog-shape, 16px);box-shadow:var(--pdx-dialog-elevation-shadow, var(--pdx-dialog-elevation));max-width:var(--pdx-dialog-max-width, 90vw);max-height:var(--pdx-dialog-max-height, 80vh);display:flex;flex-direction:column;min-width:var(--pdx-dialog-min-width, 280px);outline:0}.pdx-dialog__title{padding:var(--pdx-dialog-headline-padding, 12px 24px 10px);border-bottom:1px solid var(--pdx-dialog-border);color:var(--pdx-dialog-subhead-color, var(--pdx-dialog-title-fg));background:var(--pdx-dialog-title-bg, transparent);flex:0 0 auto}.pdx-dialog__title-row{display:flex;align-items:center;gap:10px;min-height:40px}.pdx-dialog__title-custom,.pdx-dialog__title-text{min-width:0;flex:1 1 auto}.pdx-dialog__title-icon{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;flex:0 0 24px;font-size:20px;line-height:1;opacity:.87}.pdx-dialog__title-text{margin:0;font-family:var(--pdx-dialog-subhead-font, inherit);font-size:var(--pdx-dialog-subhead-size, 16px);letter-spacing:var(--pdx-dialog-subhead-tracking, normal);font-weight:var(--pdx-dialog-subhead-weight, 600);line-height:1.2}.pdx-dialog__close-btn{appearance:none;display:inline-flex;align-items:center;justify-content:center;flex:0 0 40px;width:40px;height:40px;margin:-4px -8px -4px 8px;padding:0;border:0;border-radius:999px;color:inherit;background:transparent;cursor:pointer;transition:background-color .16s ease,color .16s ease}.pdx-dialog__close-btn:hover{background:color-mix(in srgb,currentColor 10%,transparent)}.pdx-dialog__close-btn:focus-visible{outline:2px solid var(--praxis-theme-focus-outline, var(--md-sys-color-primary));outline-offset:2px}.pdx-dialog__close-btn .mat-icon{width:22px;height:22px;font-size:22px;line-height:1}.pdx-dialog__content{padding:var(--pdx-dialog-content-padding, 16px);overflow:auto;flex:1 1 auto;min-height:0;color:var(--pdx-dialog-supporting-text-color, inherit);font-family:var(--pdx-dialog-supporting-text-font, inherit);line-height:var(--pdx-dialog-supporting-text-line-height, 1.4);font-size:var(--pdx-dialog-supporting-text-size, 14px);letter-spacing:var(--pdx-dialog-supporting-text-tracking, normal);font-weight:var(--pdx-dialog-supporting-text-weight, 400)}.pdx-dialog.has-actions .pdx-dialog__content{padding-bottom:var(--pdx-dialog-with-actions-content-padding, var(--pdx-dialog-content-padding, 16px))}.pdx-dialog__actions{display:flex;gap:8px;padding:var(--pdx-dialog-actions-padding, 12px 24px 16px);border-top:1px solid var(--pdx-dialog-border);justify-content:flex-end;align-items:center;background:var(--pdx-dialog-actions-bg, transparent);flex:0 0 auto}.pdx-dialog__actions.is-stretched{justify-content:stretch}.pdx-dialog__actions.is-stretched .pdx-dialog__action-btn{flex:1 1 0;justify-content:center}.pdx-dialog__action-btn{appearance:none;border:1px solid var(--pdx-dialog-border);background:var(--praxis-theme-surface, var(--md-sys-color-surface-container-low));color:var(--praxis-theme-on-surface, var(--md-sys-color-on-surface));border-radius:var(--pdx-dialog-action-radius, 8px);padding:var(--pdx-dialog-action-padding, 0 14px);min-height:var(--pdx-dialog-action-min-height, 36px);cursor:pointer;display:inline-flex;align-items:center;gap:8px;line-height:1;transition:background-color .18s ease,border-color .18s ease,color .18s ease}.pdx-dialog__action-btn:hover{background:var(--praxis-theme-surface-raised, var(--md-sys-color-surface-container))}.pdx-dialog__action-btn:focus-visible{outline:2px solid var(--praxis-theme-focus-outline, var(--md-sys-color-primary));outline-offset:2px}.pdx-dialog__action-btn:disabled{opacity:.6;cursor:not-allowed}.pdx-dialog__action-btn[data-role=primary]:not([data-fill]),.pdx-dialog__action-btn[data-fill=solid]{background:var(--md-sys-color-primary);border-color:var(--md-sys-color-primary);color:var(--md-sys-color-on-primary)}.pdx-dialog__action-btn[data-role=primary]:not([data-fill]):hover,.pdx-dialog__action-btn[data-fill=solid]:hover{background:var(--md-sys-color-primary-container);color:var(--md-sys-color-on-primary-container);border-color:var(--md-sys-color-primary-container)}.pdx-dialog__action-btn[data-role=danger]:not([data-fill]),.pdx-dialog__action-btn[data-fill=solid][data-theme=warn],.pdx-dialog__action-btn[data-theme=warn][data-fill=solid]{background:var(--md-sys-color-error);border-color:var(--md-sys-color-error);color:var(--md-sys-color-on-error)}.pdx-dialog__action-btn[data-role=danger]:not([data-fill]):hover,.pdx-dialog__action-btn[data-fill=solid][data-theme=warn]:hover,.pdx-dialog__action-btn[data-theme=warn][data-fill=solid]:hover{background:var(--md-sys-color-error-container);color:var(--md-sys-color-on-error-container);border-color:var(--md-sys-color-error-container)}.pdx-dialog__action-btn[data-fill=solid][data-theme=accent],.pdx-dialog__action-btn[data-theme=accent][data-fill=solid]{background:var(--md-sys-color-secondary);border-color:var(--md-sys-color-secondary);color:var(--md-sys-color-on-secondary)}.pdx-dialog__action-btn[data-fill=solid][data-theme=accent]:hover,.pdx-dialog__action-btn[data-theme=accent][data-fill=solid]:hover{background:var(--md-sys-color-secondary-container);color:var(--md-sys-color-on-secondary-container);border-color:var(--md-sys-color-secondary-container)}.pdx-dialog__action-btn[data-fill=outline]{background:transparent;color:var(--praxis-theme-on-surface, var(--md-sys-color-on-surface))}.pdx-dialog__action-btn[data-fill=outline][data-theme=primary],.pdx-dialog__action-btn[data-fill=flat][data-theme=primary]{color:var(--md-sys-color-primary);border-color:var(--md-sys-color-primary)}.pdx-dialog__action-btn[data-fill=outline][data-theme=accent],.pdx-dialog__action-btn[data-fill=flat][data-theme=accent]{color:var(--md-sys-color-secondary);border-color:var(--md-sys-color-secondary)}.pdx-dialog__action-btn[data-fill=outline][data-theme=warn],.pdx-dialog__action-btn[data-fill=flat][data-theme=warn]{color:var(--md-sys-color-error);border-color:var(--md-sys-color-error)}.pdx-dialog__action-btn[data-fill=flat]{background:transparent;border-color:transparent;color:var(--md-sys-color-primary)}.pdx-dialog__action-btn .mat-icon{font-size:20px;width:20px;height:20px;line-height:1;display:inline-flex;align-items:center;justify-content:center}.pdx-dialog--primary .pdx-dialog__title{background:var(--md-sys-color-primary-container);color:var(--md-sys-color-on-primary-container);border-bottom-color:var(--praxis-theme-outline, var(--md-sys-color-outline-variant))}.pdx-dialog--dark{background:var(--praxis-theme-surface-raised, var(--md-sys-color-surface-container));color:var(--praxis-theme-on-surface, var(--md-sys-color-on-surface))}.pdx-dialog{transform-origin:center;transition-property:transform,opacity;transition-duration:var(--pdx-dialog-anim-duration, .3s);transition-timing-function:var(--pdx-dialog-anim-ease, cubic-bezier(.2, 0, 0, 1))}.pdx-dialog.pdx-anim-fade{opacity:1}.pdx-dialog.pdx-anim-zoom{transform:scale(1)}.pdx-dialog.pdx-anim-translate-up,.pdx-dialog.pdx-anim-translate-down{transform:translateY(0)}.pdx-dialog.pdx-anim-translate-left,.pdx-dialog.pdx-anim-translate-right{transform:translate(0)}.pdx-dialog.pdx-state-opening.pdx-anim-fade{opacity:0}.pdx-dialog.pdx-state-opening.pdx-anim-zoom{transform:scale(.96);opacity:0}.pdx-dialog.pdx-state-opening.pdx-anim-translate-up{transform:translateY(-16px);opacity:0}.pdx-dialog.pdx-state-opening.pdx-anim-translate-down{transform:translateY(16px);opacity:0}.pdx-dialog.pdx-state-opening.pdx-anim-translate-left{transform:translate(-16px);opacity:0}.pdx-dialog.pdx-state-opening.pdx-anim-translate-right{transform:translate(16px);opacity:0}.pdx-dialog.pdx-state-closing.pdx-anim-fade{opacity:0}.pdx-dialog.pdx-state-closing.pdx-anim-zoom{transform:scale(.96);opacity:0}.pdx-dialog.pdx-state-closing.pdx-anim-translate-up{transform:translateY(-16px);opacity:0}.pdx-dialog.pdx-state-closing.pdx-anim-translate-down{transform:translateY(16px);opacity:0}.pdx-dialog.pdx-state-closing.pdx-anim-translate-left{transform:translate(-16px);opacity:0}.pdx-dialog.pdx-state-closing.pdx-anim-translate-right{transform:translate(16px);opacity:0}@media(prefers-reduced-motion:reduce){.pdx-dialog{transition:none!important}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: PortalModule }, { kind: "directive", type: i2.CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }, { kind: "ngmodule", type: A11yModule }, { kind: "directive", type: i3.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
552
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PraxisDialogComponent, isStandalone: true, selector: "praxis-dialog", inputs: { title: "title", actions: "actions", actionsLayout: "actionsLayout", animation: "animation", open: "open", width: "width", height: "height", minWidth: "minWidth", maxWidth: "maxWidth", minHeight: "minHeight", maxHeight: "maxHeight", themeColor: "themeColor", disableClose: "disableClose", hasBackdrop: "hasBackdrop", closeOnBackdropClick: "closeOnBackdropClick", overlayMode: "overlayMode", zIndex: "zIndex", panelClass: "panelClass", backdropClass: "backdropClass", position: "position", autoFocusedElement: "autoFocusedElement", autoFocus: "autoFocus", restoreFocus: "restoreFocus", id: "id", ariaRole: "ariaRole", ariaLabel: "ariaLabel", ariaLabelledBy: "ariaLabelledBy", ariaDescribedBy: "ariaDescribedBy", styles: "styles", titleIcon: "titleIcon" }, outputs: { action: "action", close: "close", opened: "opened", afterClosed: "afterClosed" }, host: { properties: { "class": "this.hostClass", "attr.tabindex": "this.tabindex" } }, queries: [{ propertyName: "titleTpl", first: true, predicate: PraxisDialogTitleDirective, descendants: true, read: PraxisDialogTitleDirective }, { propertyName: "actionsTpl", first: true, predicate: PraxisDialogActionsDirective, descendants: true, read: PraxisDialogActionsDirective }, { propertyName: "contentTpl", first: true, predicate: PraxisDialogContentDirective, descendants: true, read: PraxisDialogContentDirective }], viewQueries: [{ propertyName: "contentHost", first: true, predicate: CdkPortalOutlet, descendants: true }, { propertyName: "panelEl", first: true, predicate: ["panel"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "@let _titleId = (id ?? \"praxis-dialog\") + \"-title\";\n\n<ng-template #panelHeader>\n @if (titleTpl?.templateRef || title || titleIcon || displaysCloseButton) {\n <div class=\"pdx-dialog__title\">\n <div class=\"pdx-dialog__title-row\">\n @if (titleTpl?.templateRef) {\n <div class=\"pdx-dialog__title-custom\">\n <ng-container\n [ngTemplateOutlet]=\"titleTpl!.templateRef\"\n ></ng-container>\n </div>\n } @else {\n @if (titleIcon) {\n <mat-icon\n class=\"pdx-dialog__title-icon\"\n [praxisIcon]=\"titleIcon\"\n aria-hidden=\"true\"\n ></mat-icon>\n }\n @if (title) {\n <h2 class=\"pdx-dialog__title-text\" [attr.id]=\"_titleId\">\n {{ title }}\n </h2>\n }\n }\n @if (displaysCloseButton) {\n <button\n type=\"button\"\n class=\"pdx-dialog__close-btn\"\n [attr.aria-label]=\"closeButtonLabel\"\n [attr.title]=\"closeButtonLabel\"\n data-testid=\"dialog-close\"\n (click)=\"requestClose()\"\n >\n <mat-icon praxisIcon=\"close\" aria-hidden=\"true\"></mat-icon>\n </button>\n }\n </div>\n </div>\n }\n</ng-template>\n\n<ng-template #panelActions>\n <div\n class=\"pdx-dialog__actions\"\n [class.is-stretched]=\"actionsLayout === 'stretched'\"\n >\n @if (actionsTpl?.templateRef) {\n <ng-container [ngTemplateOutlet]=\"actionsTpl!.templateRef\"></ng-container>\n } @else {\n @for (a of actions; track a?.id ?? a) {\n <button\n type=\"button\"\n class=\"pdx-dialog__action-btn\"\n [attr.data-testid]=\"a.id || null\"\n [attr.data-role]=\"a.role || null\"\n [attr.data-theme]=\"a.themeColor || null\"\n [attr.data-fill]=\"a.fillMode || null\"\n [ngClass]=\"a.cssClass\"\n (click)=\"onActionClick(a)\"\n [attr.cdkFocusInitial]=\"\n a.role === 'primary' && ariaRole === 'alertdialog' ? '' : null\n \"\n >\n @if (a.icon) {\n <mat-icon [praxisIcon]=\"a.icon\"></mat-icon>\n } @else if (a.svgIcon) {\n <mat-icon [svgIcon]=\"a.svgIcon\"></mat-icon>\n }\n {{ a.text }}\n </button>\n }\n }\n </div>\n</ng-template>\n\n@if (overlayMode) {\n <div\n #panel\n class=\"pdx-dialog pdx-dialog--{{ themeColor }} pdx-dialog--layout-{{\n actionsLayout\n }}\"\n [attr.role]=\"ariaRole\"\n [attr.id]=\"id || null\"\n [attr.aria-modal]=\"true\"\n [attr.aria-label]=\"ariaLabel || null\"\n [attr.aria-labelledby]=\"ariaLabelledBy || (title ? _titleId : null)\"\n [attr.aria-describedby]=\"ariaDescribedBy || null\"\n (keydown)=\"onKeydown($event)\"\n cdkTrapFocus\n [ngClass]=\"panelNgClass\"\n [style.width]=\"width\"\n [style.height]=\"height\"\n [style.min-width]=\"minWidth\"\n [style.max-width]=\"maxWidth\"\n [style.min-height]=\"minHeight\"\n [style.max-height]=\"maxHeight\"\n [class.has-actions]=\"(actions.length || 0) > 0 || !!actionsTpl?.templateRef\"\n >\n <ng-container [ngTemplateOutlet]=\"panelHeader\"></ng-container>\n <div class=\"pdx-dialog__content\">\n @if (contentTpl?.templateRef) {\n <ng-container\n [ngTemplateOutlet]=\"contentTpl!.templateRef\"\n ></ng-container>\n } @else {\n <ng-template cdkPortalOutlet></ng-template>\n }\n </div>\n <ng-container [ngTemplateOutlet]=\"panelActions\"></ng-container>\n </div>\n} @else {\n <div\n class=\"pdx-dialog-overlay\"\n [class.has-backdrop]=\"hasBackdrop\"\n [hidden]=\"!isDisplayed\"\n (click)=\"onBackdrop($event)\"\n [ngClass]=\"backdropClass\"\n [style.z-index]=\"zIndex\"\n >\n <div class=\"pdx-dialog-shell\" (click)=\"$event.stopPropagation()\">\n <div\n #panel\n class=\"pdx-dialog pdx-dialog--{{ themeColor }} pdx-dialog--layout-{{\n actionsLayout\n }}\"\n [attr.role]=\"ariaRole\"\n [attr.id]=\"id || null\"\n [attr.aria-modal]=\"true\"\n [attr.aria-label]=\"ariaLabel || null\"\n [attr.aria-labelledby]=\"ariaLabelledBy || (title ? _titleId : null)\"\n [attr.aria-describedby]=\"ariaDescribedBy || null\"\n (keydown)=\"onKeydown($event)\"\n cdkTrapFocus\n [ngClass]=\"panelNgClass\"\n [style.width]=\"width\"\n [style.height]=\"height\"\n [style.min-width]=\"minWidth\"\n [style.max-width]=\"maxWidth\"\n [style.min-height]=\"minHeight\"\n [style.max-height]=\"maxHeight\"\n [style.top]=\"position?.top || null\"\n [style.bottom]=\"position?.bottom || null\"\n [style.left]=\"position?.left || null\"\n [style.right]=\"position?.right || null\"\n [class.pdx-has-position]=\"position\"\n [class.has-actions]=\"\n (actions.length || 0) > 0 || !!actionsTpl?.templateRef\n \"\n >\n <ng-container [ngTemplateOutlet]=\"panelHeader\"></ng-container>\n <div class=\"pdx-dialog__content\">\n @if (contentTpl?.templateRef) {\n <ng-container\n [ngTemplateOutlet]=\"contentTpl!.templateRef\"\n ></ng-container>\n } @else {\n <ng-template cdkPortalOutlet></ng-template>\n }\n </div>\n <ng-container [ngTemplateOutlet]=\"panelActions\"></ng-container>\n </div>\n </div>\n </div>\n}\n", styles: ["@charset \"UTF-8\";.pdx-dialog-host{--pdx-dialog-bg: var(--praxis-theme-surface, var(--md-sys-color-surface));--pdx-dialog-surface: var( --praxis-theme-surface-overlay, var(--md-sys-color-surface-container-high) );--pdx-dialog-border: var( --praxis-theme-outline, var(--md-sys-color-outline-variant) );--pdx-dialog-title-fg: var( --praxis-theme-on-surface, var(--md-sys-color-on-surface) );--pdx-dialog-elevation: var( --praxis-theme-elevation, var(--mat-elevation-level4) )}.pdx-dialog-overlay{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;z-index:var(--praxis-layer-dialog, 1300);background:transparent}.pdx-dialog-overlay.has-backdrop{background:var(--pdx-dialog-backdrop, rgba(0, 0, 0, .6))}.pdx-dialog-shell{display:contents}.pdx-dialog.pdx-has-position{position:absolute}.pdx-dialog{background:var(--pdx-dialog-container-color, var(--pdx-dialog-surface));color:var(--praxis-theme-on-surface, var(--md-sys-color-on-surface, #111));border:1px solid var(--pdx-dialog-border);border-radius:var(--pdx-dialog-shape, 16px);box-shadow:var(--pdx-dialog-elevation-shadow, var(--pdx-dialog-elevation));max-width:var(--pdx-dialog-max-width, 90vw);max-height:var(--pdx-dialog-max-height, 80vh);display:flex;flex-direction:column;min-width:var(--pdx-dialog-min-width, 280px);outline:0}.pdx-dialog__title{padding:var(--pdx-dialog-headline-padding, 12px 24px 10px);border-bottom:1px solid var(--pdx-dialog-border);color:var(--pdx-dialog-subhead-color, var(--pdx-dialog-title-fg));background:var(--pdx-dialog-title-bg, transparent);flex:0 0 auto}.pdx-dialog__title-row{display:flex;align-items:center;gap:10px;min-height:40px}.pdx-dialog__title-custom,.pdx-dialog__title-text{min-width:0;flex:1 1 auto}.pdx-dialog__title-icon{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;flex:0 0 24px;font-size:20px;line-height:1;opacity:.87}.pdx-dialog__title-text{margin:0;font-family:var(--pdx-dialog-subhead-font, inherit);font-size:var(--pdx-dialog-subhead-size, 16px);letter-spacing:var(--pdx-dialog-subhead-tracking, normal);font-weight:var(--pdx-dialog-subhead-weight, 600);line-height:1.2}.pdx-dialog__close-btn{appearance:none;display:inline-flex;align-items:center;justify-content:center;flex:0 0 40px;width:40px;height:40px;margin:-4px -8px -4px 8px;padding:0;border:0;border-radius:999px;color:inherit;background:transparent;cursor:pointer;transition:background-color .16s ease,color .16s ease}.pdx-dialog__close-btn:hover{background:color-mix(in srgb,currentColor 10%,transparent)}.pdx-dialog__close-btn:focus-visible{outline:2px solid var(--praxis-theme-focus-outline, var(--md-sys-color-primary));outline-offset:2px}.pdx-dialog__close-btn .mat-icon{width:22px;height:22px;font-size:22px;line-height:1}.pdx-dialog__content{padding:var(--pdx-dialog-content-padding, 16px);overflow:auto;flex:1 1 auto;min-height:0;color:var(--pdx-dialog-supporting-text-color, inherit);font-family:var(--pdx-dialog-supporting-text-font, inherit);line-height:var(--pdx-dialog-supporting-text-line-height, 1.4);font-size:var(--pdx-dialog-supporting-text-size, 14px);letter-spacing:var(--pdx-dialog-supporting-text-tracking, normal);font-weight:var(--pdx-dialog-supporting-text-weight, 400)}.pdx-dialog.has-actions .pdx-dialog__content{padding-bottom:var(--pdx-dialog-with-actions-content-padding, var(--pdx-dialog-content-padding, 16px))}.pdx-dialog__actions{display:flex;gap:8px;padding:var(--pdx-dialog-actions-padding, 12px 24px 16px);border-top:1px solid var(--pdx-dialog-border);justify-content:flex-end;align-items:center;background:var(--pdx-dialog-actions-bg, transparent);flex:0 0 auto}.pdx-dialog__actions.is-stretched{justify-content:stretch}.pdx-dialog__actions.is-stretched .pdx-dialog__action-btn{flex:1 1 0;justify-content:center}.pdx-dialog__action-btn{appearance:none;border:1px solid var(--pdx-dialog-border);background:var(--praxis-theme-surface, var(--md-sys-color-surface-container-low));color:var(--praxis-theme-on-surface, var(--md-sys-color-on-surface));border-radius:var(--pdx-dialog-action-radius, 8px);padding:var(--pdx-dialog-action-padding, 0 14px);min-height:var(--pdx-dialog-action-min-height, 36px);cursor:pointer;display:inline-flex;align-items:center;gap:8px;line-height:1;transition:background-color .18s ease,border-color .18s ease,color .18s ease}.pdx-dialog__action-btn:hover{background:var(--praxis-theme-surface-raised, var(--md-sys-color-surface-container))}.pdx-dialog__action-btn:focus-visible{outline:2px solid var(--praxis-theme-focus-outline, var(--md-sys-color-primary));outline-offset:2px}.pdx-dialog__action-btn:disabled{opacity:.6;cursor:not-allowed}.pdx-dialog__action-btn[data-role=primary]:not([data-fill]),.pdx-dialog__action-btn[data-fill=solid]{background:var(--md-sys-color-primary);border-color:var(--md-sys-color-primary);color:var(--md-sys-color-on-primary)}.pdx-dialog__action-btn[data-role=primary]:not([data-fill]):hover,.pdx-dialog__action-btn[data-fill=solid]:hover{background:var(--md-sys-color-primary-container);color:var(--md-sys-color-on-primary-container);border-color:var(--md-sys-color-primary-container)}.pdx-dialog__action-btn[data-role=danger]:not([data-fill]),.pdx-dialog__action-btn[data-fill=solid][data-theme=warn],.pdx-dialog__action-btn[data-theme=warn][data-fill=solid]{background:var(--md-sys-color-error);border-color:var(--md-sys-color-error);color:var(--md-sys-color-on-error)}.pdx-dialog__action-btn[data-role=danger]:not([data-fill]):hover,.pdx-dialog__action-btn[data-fill=solid][data-theme=warn]:hover,.pdx-dialog__action-btn[data-theme=warn][data-fill=solid]:hover{background:var(--md-sys-color-error-container);color:var(--md-sys-color-on-error-container);border-color:var(--md-sys-color-error-container)}.pdx-dialog__action-btn[data-fill=solid][data-theme=accent],.pdx-dialog__action-btn[data-theme=accent][data-fill=solid]{background:var(--md-sys-color-secondary);border-color:var(--md-sys-color-secondary);color:var(--md-sys-color-on-secondary)}.pdx-dialog__action-btn[data-fill=solid][data-theme=accent]:hover,.pdx-dialog__action-btn[data-theme=accent][data-fill=solid]:hover{background:var(--md-sys-color-secondary-container);color:var(--md-sys-color-on-secondary-container);border-color:var(--md-sys-color-secondary-container)}.pdx-dialog__action-btn[data-fill=outline]{background:transparent;color:var(--praxis-theme-on-surface, var(--md-sys-color-on-surface))}.pdx-dialog__action-btn[data-fill=outline][data-theme=primary],.pdx-dialog__action-btn[data-fill=flat][data-theme=primary]{color:var(--md-sys-color-primary);border-color:var(--md-sys-color-primary)}.pdx-dialog__action-btn[data-fill=outline][data-theme=accent],.pdx-dialog__action-btn[data-fill=flat][data-theme=accent]{color:var(--md-sys-color-secondary);border-color:var(--md-sys-color-secondary)}.pdx-dialog__action-btn[data-fill=outline][data-theme=warn],.pdx-dialog__action-btn[data-fill=flat][data-theme=warn]{color:var(--md-sys-color-error);border-color:var(--md-sys-color-error)}.pdx-dialog__action-btn[data-fill=flat]{background:transparent;border-color:transparent;color:var(--md-sys-color-primary)}.pdx-dialog__action-btn .mat-icon{font-size:20px;width:20px;height:20px;line-height:1;display:inline-flex;align-items:center;justify-content:center}.pdx-dialog--primary .pdx-dialog__title{background:var(--md-sys-color-primary-container);color:var(--md-sys-color-on-primary-container);border-bottom-color:var(--praxis-theme-outline, var(--md-sys-color-outline-variant))}.pdx-dialog--dark{background:var(--praxis-theme-surface-raised, var(--md-sys-color-surface-container));color:var(--praxis-theme-on-surface, var(--md-sys-color-on-surface))}.pdx-dialog{transform-origin:center;transition-property:transform,opacity;transition-duration:var(--pdx-dialog-anim-duration, .3s);transition-timing-function:var(--pdx-dialog-anim-ease, cubic-bezier(.2, 0, 0, 1))}.pdx-dialog.pdx-anim-fade{opacity:1}.pdx-dialog.pdx-anim-zoom{transform:scale(1)}.pdx-dialog.pdx-anim-translate-up,.pdx-dialog.pdx-anim-translate-down{transform:translateY(0)}.pdx-dialog.pdx-anim-translate-left,.pdx-dialog.pdx-anim-translate-right{transform:translate(0)}.pdx-dialog.pdx-state-opening.pdx-anim-fade{opacity:0}.pdx-dialog.pdx-state-opening.pdx-anim-zoom{transform:scale(.96);opacity:0}.pdx-dialog.pdx-state-opening.pdx-anim-translate-up{transform:translateY(-16px);opacity:0}.pdx-dialog.pdx-state-opening.pdx-anim-translate-down{transform:translateY(16px);opacity:0}.pdx-dialog.pdx-state-opening.pdx-anim-translate-left{transform:translate(-16px);opacity:0}.pdx-dialog.pdx-state-opening.pdx-anim-translate-right{transform:translate(16px);opacity:0}.pdx-dialog.pdx-state-closing.pdx-anim-fade{opacity:0}.pdx-dialog.pdx-state-closing.pdx-anim-zoom{transform:scale(.96);opacity:0}.pdx-dialog.pdx-state-closing.pdx-anim-translate-up{transform:translateY(-16px);opacity:0}.pdx-dialog.pdx-state-closing.pdx-anim-translate-down{transform:translateY(16px);opacity:0}.pdx-dialog.pdx-state-closing.pdx-anim-translate-left{transform:translate(-16px);opacity:0}.pdx-dialog.pdx-state-closing.pdx-anim-translate-right{transform:translate(16px);opacity:0}@media(prefers-reduced-motion:reduce){.pdx-dialog{transition:none!important}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: PortalModule }, { kind: "directive", type: i2.CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }, { kind: "ngmodule", type: A11yModule }, { kind: "directive", type: i3.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
531
553
  }
532
554
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisDialogComponent, decorators: [{
533
555
  type: Component,
@@ -611,7 +633,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
611
633
  args: [CdkPortalOutlet, { static: false }]
612
634
  }], panelEl: [{
613
635
  type: ViewChild,
614
- args: ['panel', { static: true }]
636
+ args: ['panel']
615
637
  }], titleTpl: [{
616
638
  type: ContentChild,
617
639
  args: [PraxisDialogTitleDirective, {
@@ -638,13 +660,16 @@ const PraxisDialogDirectives = [];
638
660
 
639
661
  class DialogOverlayService {
640
662
  overlay = inject(Overlay);
641
- createOverlay(cfg, injector) {
663
+ createOverlay(cfg) {
642
664
  const overlayConfig = this.buildOverlayConfig(cfg);
643
665
  return this.overlay.create(overlayConfig);
644
666
  }
645
667
  attachContainer(ref, injector) {
646
668
  const portal = new ComponentPortal(PraxisDialogComponent, null, injector);
647
669
  const compRef = ref.attach(portal);
670
+ // CDK 21 defers the first position calculation to afterNextRender. Apply the
671
+ // configured strategy now so dialogs never paint at the viewport origin.
672
+ ref.updatePosition();
648
673
  return compRef;
649
674
  }
650
675
  buildOverlayConfig(cfg) {
@@ -706,6 +731,7 @@ const DialogOverlayImports = [OverlayModule, PortalModule];
706
731
 
707
732
  class PraxisDialog {
708
733
  overlay = inject(DialogOverlayService);
734
+ injector = inject(Injector);
709
735
  layerScale = inject(PraxisLayerScaleStyleService);
710
736
  appRef = inject(ApplicationRef);
711
737
  registry = inject(PRAXIS_DIALOG_CONTENT_REGISTRY);
@@ -717,14 +743,18 @@ class PraxisDialog {
717
743
  afterAllClosed = new Subject();
718
744
  afterOpened = new Subject();
719
745
  _openDialogs = [];
720
- get openDialogs() { return this._openDialogs.slice(); }
746
+ get openDialogs() {
747
+ return this._openDialogs.slice();
748
+ }
721
749
  _seq = 0;
722
750
  open(content, config) {
723
751
  this.layerScale.ensureInstalled();
752
+ const effectiveInjector = config?.injector ?? config?.viewContainerRef?.injector ?? this.injector;
724
753
  const injector = Injector.create({
725
754
  providers: [{ provide: PRAXIS_DIALOG_DATA, useValue: config?.data }],
755
+ parent: effectiveInjector,
726
756
  });
727
- const overlayRef = this.overlay.createOverlay(config ?? {}, injector);
757
+ const overlayRef = this.overlay.createOverlay(config ?? {});
728
758
  const ref = new PraxisDialogRef(overlayRef);
729
759
  // Auto-id fallback if not provided
730
760
  let assignedId = config?.id ?? `praxis-dialog-${++this._seq}`;
@@ -739,10 +769,14 @@ class PraxisDialog {
739
769
  // Set inputs before detectChanges so the correct branch/materialization occurs
740
770
  container.overlayMode = true;
741
771
  container.title = config?.title;
742
- container.titleIcon = config?.icon ?? config?.titleIcon;
772
+ container.titleIcon =
773
+ config?.icon ?? config?.titleIcon;
743
774
  container.actions = config?.actions ?? [];
744
775
  container.actionsLayout = config?.actionsLayout ?? 'stretched';
745
- container.animation = config?.animation ?? { type: 'translate', duration: 300 };
776
+ container.animation = config?.animation ?? {
777
+ type: 'translate',
778
+ duration: 300,
779
+ };
746
780
  container.width = config?.width;
747
781
  container.height = config?.height;
748
782
  container.minWidth = config?.minWidth;
@@ -758,7 +792,8 @@ class PraxisDialog {
758
792
  container.backdropClass = config?.backdropClass;
759
793
  container.position = config?.position;
760
794
  container.autoFocusedElement = config?.autoFocusedElement;
761
- container.autoFocus = config?.autoFocus ?? container.autoFocus;
795
+ container.autoFocus =
796
+ config?.autoFocus ?? container.autoFocus;
762
797
  container.restoreFocus = config?.restoreFocus ?? true;
763
798
  container.id = assignedId;
764
799
  container.ariaRole = config?.ariaRole ?? 'dialog';
@@ -813,16 +848,20 @@ class PraxisDialog {
813
848
  return;
814
849
  contentAttached = true;
815
850
  if (content instanceof TemplateRef) {
816
- const origin = config?.viewContainerRef ?? null;
817
- const portal = new TemplatePortal(content, origin, { $implicit: config?.data });
851
+ const origin = config?.viewContainerRef ??
852
+ null;
853
+ const portal = new TemplatePortal(content, origin, {
854
+ $implicit: config?.data,
855
+ });
818
856
  container.contentHost.attachTemplatePortal(portal);
819
857
  }
820
858
  else {
821
- const portal = new ComponentPortal(content);
859
+ const portal = new ComponentPortal(content, config?.viewContainerRef ?? null, injector);
822
860
  const innerRef = container.contentHost.attachComponentPortal(portal);
823
861
  ref.componentInstance = innerRef.instance;
824
862
  ref.componentRef = innerRef;
825
863
  }
864
+ container.focusInitialElement();
826
865
  };
827
866
  if (container.contentHost) {
828
867
  doAttach();
@@ -864,8 +903,20 @@ class PraxisDialog {
864
903
  confirm(cfg, variant) {
865
904
  const merged = this.mergePresets('confirm', variant, cfg);
866
905
  const actions = [
867
- { text: merged.cancelLabel ?? this.i18n.cancel, role: 'secondary', close: true, id: 'cancel', payload: false },
868
- { text: merged.confirmLabel ?? this.i18n.ok, role: 'primary', close: true, id: 'confirm', payload: true },
906
+ {
907
+ text: merged.cancelLabel ?? this.i18n.cancel,
908
+ role: 'secondary',
909
+ close: true,
910
+ id: 'cancel',
911
+ payload: false,
912
+ },
913
+ {
914
+ text: merged.confirmLabel ?? this.i18n.ok,
915
+ role: 'primary',
916
+ close: true,
917
+ id: 'confirm',
918
+ payload: true,
919
+ },
869
920
  ];
870
921
  const Comp = SimpleDialogContentComponent;
871
922
  return this.open(Comp, {
@@ -878,21 +929,53 @@ class PraxisDialog {
878
929
  alert(cfg) {
879
930
  const merged = this.mergePresets('alert', undefined, cfg);
880
931
  const actions = [
881
- { text: merged.okLabel ?? this.i18n.ok, role: 'primary', close: true, id: 'ok' },
932
+ {
933
+ text: merged.okLabel ?? this.i18n.ok,
934
+ role: 'primary',
935
+ close: true,
936
+ id: 'ok',
937
+ },
882
938
  ];
883
939
  const Comp = SimpleDialogContentComponent;
884
- return this.open(Comp, { ...merged, actions, data: { message: merged.message, mode: 'alert' }, ariaRole: merged.ariaRole ?? 'alertdialog' });
940
+ return this.open(Comp, {
941
+ ...merged,
942
+ actions,
943
+ data: { message: merged.message, mode: 'alert' },
944
+ ariaRole: merged.ariaRole ?? 'alertdialog',
945
+ });
885
946
  }
886
947
  prompt(cfg) {
887
948
  const merged = this.mergePresets('prompt', undefined, cfg);
888
949
  const actions = [
889
- { text: merged.cancelLabel ?? this.i18n.cancel, role: 'secondary', close: true, id: 'cancel', payload: null },
890
- { text: merged.okLabel ?? this.i18n.ok, role: 'primary', close: false, id: 'ok' },
950
+ {
951
+ text: merged.cancelLabel ?? this.i18n.cancel,
952
+ role: 'secondary',
953
+ close: true,
954
+ id: 'cancel',
955
+ payload: null,
956
+ },
957
+ {
958
+ text: merged.okLabel ?? this.i18n.ok,
959
+ role: 'primary',
960
+ close: false,
961
+ id: 'ok',
962
+ },
891
963
  ];
892
964
  const Comp = SimpleDialogContentComponent;
893
- const ref = this.open(Comp, { ...merged, actions, data: { message: merged.message, mode: 'prompt', placeholder: merged.placeholder, defaultValue: merged.defaultValue }, ariaRole: merged.ariaRole ?? 'dialog' });
965
+ const ref = this.open(Comp, {
966
+ ...merged,
967
+ actions,
968
+ data: {
969
+ message: merged.message,
970
+ mode: 'prompt',
971
+ placeholder: merged.placeholder,
972
+ defaultValue: merged.defaultValue,
973
+ },
974
+ ariaRole: merged.ariaRole ?? 'dialog',
975
+ });
894
976
  ref.afterOpened().subscribe(() => {
895
- const inst = ref.componentInstance;
977
+ const inst = ref
978
+ .componentInstance;
896
979
  inst.submit = () => ref.close(inst.value ?? '');
897
980
  });
898
981
  return ref;
@@ -917,7 +1000,9 @@ class PraxisDialog {
917
1000
  }
918
1001
  mergePresets(type, variant, cfg) {
919
1002
  const base = this.globalPresets?.[type] ?? {};
920
- const variantCfg = variant ? (this.globalPresets?.variants?.[variant] ?? {}) : {};
1003
+ const variantCfg = variant
1004
+ ? (this.globalPresets?.variants?.[variant] ?? {})
1005
+ : {};
921
1006
  return mergeDialogConfig(mergeDialogConfig(base, variantCfg), cfg);
922
1007
  }
923
1008
  closeAll() {
@@ -940,7 +1025,9 @@ class SimpleDialogContentComponent {
940
1025
  placeholder;
941
1026
  value;
942
1027
  submit;
943
- dialogData = inject(PRAXIS_DIALOG_DATA, { optional: true });
1028
+ dialogData = inject(PRAXIS_DIALOG_DATA, {
1029
+ optional: true,
1030
+ });
944
1031
  constructor() {
945
1032
  const data = this.dialogData;
946
1033
  try {
@@ -964,7 +1051,7 @@ class SimpleDialogContentComponent {
964
1051
  </mat-form-field>
965
1052
  }
966
1053
  </div>
967
- `, isInline: true, styles: [".pdx-simple-dialog{display:grid;gap:12px}.pdx-simple-dialog__message{margin:0}.pdx-simple-dialog__field{width:100%}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$1.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }] });
1054
+ `, isInline: true, styles: [".pdx-simple-dialog{display:grid;gap:12px}.pdx-simple-dialog__message{margin:0}.pdx-simple-dialog__field{width:100%}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$1.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }] });
968
1055
  }
969
1056
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: SimpleDialogContentComponent, decorators: [{
970
1057
  type: Component,
@@ -980,7 +1067,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
980
1067
  </mat-form-field>
981
1068
  }
982
1069
  </div>
983
- `, styles: [".pdx-simple-dialog{display:grid;gap:12px}.pdx-simple-dialog__message{margin:0}.pdx-simple-dialog__field{width:100%}\n"] }]
1070
+ `, styles: [".pdx-simple-dialog{display:grid;gap:12px}.pdx-simple-dialog__message{margin:0}.pdx-simple-dialog__field{width:100%}\n"] }]
984
1071
  }], ctorParameters: () => [] });
985
1072
  class SimpleHtmlDialogContentComponent {
986
1073
  safeHtml;
@@ -1156,7 +1243,7 @@ function providePraxisDialogGlobalActions() {
1156
1243
  };
1157
1244
  }
1158
1245
 
1159
- function buildDialogConfig(payload) {
1246
+ function buildDialogConfig(payload, injector) {
1160
1247
  return {
1161
1248
  title: payload.title,
1162
1249
  titleIcon: payload.icon,
@@ -1166,6 +1253,7 @@ function buildDialogConfig(payload) {
1166
1253
  maxWidth: payload.size?.maxWidth,
1167
1254
  minHeight: payload.size?.minHeight,
1168
1255
  maxHeight: payload.size?.maxHeight,
1256
+ injector,
1169
1257
  };
1170
1258
  }
1171
1259
  function buildHostInputs(payload, context, options) {
@@ -1194,7 +1282,9 @@ function buildDialogSurfaceRuntime(ref, resultSubject, complete) {
1194
1282
  result$: resultSubject.asObservable(),
1195
1283
  emitResult: (result) => resultSubject.next(result),
1196
1284
  complete,
1197
- close: (result) => { void ref.close(result); },
1285
+ close: (result) => {
1286
+ void ref.close(result);
1287
+ },
1198
1288
  updateSize: (preset) => {
1199
1289
  const width = resolveDialogWidth(preset);
1200
1290
  if (width) {
@@ -1248,7 +1338,8 @@ function bindSurfaceHostSelectionResults(instance, resultSubject) {
1248
1338
  return () => subscriptions.forEach((unsubscribe) => unsubscribe());
1249
1339
  }
1250
1340
  function subscribeToOutput(output, handler) {
1251
- if (!output || typeof output.subscribe !== 'function') {
1341
+ if (!output ||
1342
+ typeof output.subscribe !== 'function') {
1252
1343
  return null;
1253
1344
  }
1254
1345
  const subscription = output.subscribe(handler);
@@ -1263,9 +1354,9 @@ function toSurfaceSelectionResult(output, payload) {
1263
1354
  };
1264
1355
  }
1265
1356
  function resolveParentSurfaceRuntime(context) {
1266
- const runtime = context?.runtime?.state?.surfaceRuntime
1267
- || context?.payload?.surfaceContext?.surfaceRuntime
1268
- || context?.pageContext?.surfaceRuntime;
1357
+ const runtime = context?.runtime?.state?.surfaceRuntime ||
1358
+ context?.payload?.surfaceContext?.surfaceRuntime ||
1359
+ context?.pageContext?.surfaceRuntime;
1269
1360
  return runtime && typeof runtime === 'object'
1270
1361
  ? runtime
1271
1362
  : null;
@@ -1276,11 +1367,10 @@ function resolveParentSurfaceRuntime(context) {
1276
1367
  * control after the surface terminates.
1277
1368
  */
1278
1369
  function resolveRuntimeFocusOrigin(context) {
1279
- const candidate = context?.runtime
1280
- ?.focusOrigin;
1281
- return candidate
1282
- && typeof candidate.focus === 'function'
1283
- && (candidate.isConnected || !!candidate.getAttribute('data-praxis-focus-key'))
1370
+ const candidate = context?.runtime?.focusOrigin;
1371
+ return candidate &&
1372
+ typeof candidate.focus === 'function' &&
1373
+ (candidate.isConnected || !!candidate.getAttribute('data-praxis-focus-key'))
1284
1374
  ? candidate
1285
1375
  : null;
1286
1376
  }
@@ -1292,9 +1382,7 @@ function resolveReplacementFocusOrigin(focusOrigin) {
1292
1382
  if (!key || typeof document === 'undefined') {
1293
1383
  return null;
1294
1384
  }
1295
- return Array.from(document.querySelectorAll('[data-praxis-focus-key]'))
1296
- .find((candidate) => candidate.getAttribute('data-praxis-focus-key') === key)
1297
- ?? null;
1385
+ return (Array.from(document.querySelectorAll('[data-praxis-focus-key]')).find((candidate) => candidate.getAttribute('data-praxis-focus-key') === key) ?? null);
1298
1386
  }
1299
1387
  function restoreRuntimeFocusOnClose(closed$, focusOrigin) {
1300
1388
  if (!focusOrigin || typeof closed$?.subscribe !== 'function')
@@ -1303,8 +1391,8 @@ function restoreRuntimeFocusOnClose(closed$, focusOrigin) {
1303
1391
  const restore = (remainingAttempts) => {
1304
1392
  const target = resolveReplacementFocusOrigin(focusOrigin);
1305
1393
  const activeElement = typeof document !== 'undefined' ? document.activeElement : null;
1306
- const focusWasLostToDocument = activeElement === document.body
1307
- || activeElement === document.documentElement;
1394
+ const focusWasLostToDocument = activeElement === document.body ||
1395
+ activeElement === document.documentElement;
1308
1396
  const targetAlreadyFocused = activeElement === target;
1309
1397
  if (target && (focusWasLostToDocument || targetAlreadyFocused)) {
1310
1398
  try {
@@ -1317,12 +1405,12 @@ function restoreRuntimeFocusOnClose(closed$, focusOrigin) {
1317
1405
  catch { }
1318
1406
  }
1319
1407
  }
1320
- if (remainingAttempts > 0
1321
- && typeof setTimeout !== 'undefined'
1408
+ if (remainingAttempts > 0 &&
1409
+ typeof setTimeout !== 'undefined' &&
1322
1410
  // A late overlay teardown can return focus to document.body after the
1323
1411
  // first restore. Keep checking only while focus remains unowned (or
1324
1412
  // on the restored target); never steal a user-initiated new focus.
1325
- && (focusWasLostToDocument || targetAlreadyFocused)) {
1413
+ (focusWasLostToDocument || targetAlreadyFocused)) {
1326
1414
  setTimeout(() => restore(remainingAttempts - 1), 50);
1327
1415
  }
1328
1416
  };
@@ -1337,6 +1425,7 @@ function providePraxisSurfaceGlobalActions() {
1337
1425
  provide: GLOBAL_SURFACE_SERVICE,
1338
1426
  useFactory: () => {
1339
1427
  const dialog = inject(PraxisDialog);
1428
+ const injector = inject(Injector);
1340
1429
  const materializer = inject(SurfaceOpenMaterializerService);
1341
1430
  const logger = inject(LoggerService, { optional: true });
1342
1431
  const surfaceDrawer = inject(SURFACE_DRAWER_BRIDGE, {
@@ -1401,7 +1490,7 @@ function providePraxisSurfaceGlobalActions() {
1401
1490
  restoreRuntimeFocusOnClose(ref.closed$, focusOrigin);
1402
1491
  return ref;
1403
1492
  }
1404
- const ref = dialog.open(PraxisSurfaceHostComponent, buildDialogConfig(materializedPayload));
1493
+ const ref = dialog.open(PraxisSurfaceHostComponent, buildDialogConfig(materializedPayload, injector));
1405
1494
  restoreRuntimeFocusOnClose(ref.afterClosed(), focusOrigin);
1406
1495
  const resultSubject = new Subject();
1407
1496
  let terminalOutcomeEmitted = false;
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@praxisui/dialog",
3
- "version": "9.0.5",
3
+ "version": "9.0.7",
4
4
  "description": "Dialog helpers and components for Praxis UI with Angular Material integration.",
5
5
  "peerDependencies": {
6
6
  "@angular/common": "^21.0.0",
7
7
  "@angular/core": "^21.0.0",
8
8
  "@angular/cdk": "^21.0.0",
9
9
  "@angular/forms": "^21.0.0",
10
- "@praxisui/core": "^9.0.5",
10
+ "@praxisui/core": "^9.0.7",
11
11
  "@angular/material": "^21.0.0",
12
12
  "@angular/platform-browser": "^21.0.0",
13
13
  "rxjs": "~7.8.0"
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, TemplateRef, ComponentRef, OnInit, OnChanges, OnDestroy, EventEmitter, ElementRef, SimpleChanges, Type, Provider } from '@angular/core';
2
+ import { Injector, ViewContainerRef, InjectionToken, TemplateRef, ComponentRef, OnInit, AfterViewInit, OnChanges, OnDestroy, EventEmitter, ElementRef, SimpleChanges, Type, Provider } from '@angular/core';
3
3
  import { OverlayRef } from '@angular/cdk/overlay';
4
4
  import { Observable, Subject } from 'rxjs';
5
5
  import { CdkPortalOutlet } from '@angular/cdk/portal';
@@ -64,7 +64,13 @@ interface PraxisDialogConfig<D = any> {
64
64
  ariaLabelledBy?: string;
65
65
  ariaDescribedBy?: string;
66
66
  appendTo?: Element | any;
67
- viewContainerRef?: i0.ViewContainerRef;
67
+ /**
68
+ * Runtime-only injector used to create the dialog container and its dynamic
69
+ * content. It takes precedence over the injector derived from
70
+ * viewContainerRef and must not be persisted or authored as JSON.
71
+ */
72
+ injector?: Injector;
73
+ viewContainerRef?: ViewContainerRef;
68
74
  closeOnNavigation?: boolean;
69
75
  zIndex?: number;
70
76
  styles?: PraxisDialogStyleConfig;
@@ -166,6 +172,7 @@ declare class PraxisDialogRef<T = any, R = any> {
166
172
  componentRef?: ComponentRef<T>;
167
173
  constructor(overlayRef: OverlayRef);
168
174
  private beforeCloseHandler?;
175
+ private closePromise?;
169
176
  setBeforeClose(handler: (result?: R) => Promise<void> | void): void;
170
177
  emitOpened(): void;
171
178
  backdropClick(): Observable<MouseEvent>;
@@ -176,6 +183,7 @@ declare class PraxisDialogRef<T = any, R = any> {
176
183
  notifyBackdropClick(ev: MouseEvent): void;
177
184
  notifyKeydown(ev: KeyboardEvent): void;
178
185
  close(result?: R): Promise<void>;
186
+ private performClose;
179
187
  updateSize(width?: string | number, height?: string | number): this;
180
188
  updatePosition(position?: PraxisDialogPosition): this;
181
189
  }
@@ -201,7 +209,7 @@ declare class PraxisDialogContentDirective {
201
209
  static ɵdir: i0.ɵɵDirectiveDeclaration<PraxisDialogContentDirective, "ng-template[praxisDialogContent]", never, {}, {}, never, never, true, never>;
202
210
  }
203
211
 
204
- declare class PraxisDialogComponent implements OnInit, OnChanges, OnDestroy {
212
+ declare class PraxisDialogComponent implements OnInit, AfterViewInit, OnChanges, OnDestroy {
205
213
  title?: string;
206
214
  actions: DialogAction[];
207
215
  actionsLayout: ActionsLayout;
@@ -256,12 +264,20 @@ declare class PraxisDialogComponent implements OnInit, OnChanges, OnDestroy {
256
264
  requestClose(): void;
257
265
  isDisplayed: boolean;
258
266
  ngOnInit(): void;
267
+ ngAfterViewInit(): void;
259
268
  ngOnChanges(changes: SimpleChanges): void;
260
269
  onKeydown(ev: KeyboardEvent): void;
261
270
  onActionClick(a: DialogAction): void;
262
271
  onBackdrop(ev: MouseEvent): void;
263
272
  focus(): void;
273
+ /**
274
+ * Moves focus into the currently materialized panel. Overlay hosts call this
275
+ * after switching to the overlay template branch and attaching its content.
276
+ */
277
+ focusInitialElement(): void;
264
278
  private scheduleInitialFocus;
279
+ private captureFocusOrigin;
280
+ private applyInitialFocus;
265
281
  private _previouslyFocused?;
266
282
  ngOnDestroy(): void;
267
283
  get animationClasses(): string[];
@@ -278,6 +294,7 @@ declare const PraxisDialogDirectives: readonly [];
278
294
 
279
295
  declare class PraxisDialog {
280
296
  private readonly overlay;
297
+ private readonly injector;
281
298
  private readonly layerScale;
282
299
  private readonly appRef;
283
300
  private readonly registry;