@praxisui/dialog 8.0.0-beta.2 → 8.0.0-beta.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -0
- package/fesm2022/praxisui-dialog.mjs +440 -11
- package/index.d.ts +9 -2
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -212,6 +212,31 @@ this.dialog.openByRegistry(PRAXIS_DIALOG_EXAMPLE_LONG_CONTENT, {
|
|
|
212
212
|
- In `alertdialog`, focuses the primary action when present
|
|
213
213
|
- Restores focus on close (service and tag)
|
|
214
214
|
|
|
215
|
+
## Agentic Authoring Contract
|
|
216
|
+
|
|
217
|
+
`@praxisui/dialog` publishes an executable authoring manifest for the
|
|
218
|
+
`praxis-dialog` shell. The manifest governs overlay configuration such as size,
|
|
219
|
+
position, backdrop, close policy, presets, accessibility fields and the child
|
|
220
|
+
host envelope.
|
|
221
|
+
|
|
222
|
+
Dialog authoring intentionally separates shell semantics from child component
|
|
223
|
+
semantics:
|
|
224
|
+
|
|
225
|
+
- shell operations edit `PraxisDialogConfig`
|
|
226
|
+
- size, position and backdrop operations are visual overlay changes
|
|
227
|
+
- close policy edits are explicit, confirmation-gated shell configuration
|
|
228
|
+
- preset operations preserve the merge order `type -> variant -> local config`
|
|
229
|
+
- child host operations resolve component/template ids through governed
|
|
230
|
+
registries
|
|
231
|
+
- child component config edits must be delegated to the child component
|
|
232
|
+
manifest through `childOperation.delegate`
|
|
233
|
+
|
|
234
|
+
This prevents the dialog manifest from becoming an ad hoc facade over table,
|
|
235
|
+
form, page or custom component configuration.
|
|
236
|
+
Each operation declares its editable target, resolver, ambiguity policy,
|
|
237
|
+
preconditions, validators, effects, affected paths and typed
|
|
238
|
+
`submissionImpact`.
|
|
239
|
+
|
|
215
240
|
## Theming & Styles
|
|
216
241
|
|
|
217
242
|
- `themeColor: 'light' | 'dark' | 'primary'`
|
|
@@ -182,6 +182,7 @@ class PraxisDialogComponent {
|
|
|
182
182
|
themeColor = 'light';
|
|
183
183
|
disableClose = false;
|
|
184
184
|
hasBackdrop = true;
|
|
185
|
+
closeOnBackdropClick = true;
|
|
185
186
|
overlayMode = false; // true when opened via service/CDK overlay
|
|
186
187
|
zIndex;
|
|
187
188
|
panelClass;
|
|
@@ -292,6 +293,8 @@ class PraxisDialogComponent {
|
|
|
292
293
|
return;
|
|
293
294
|
if (this.disableClose)
|
|
294
295
|
return;
|
|
296
|
+
if (!this.closeOnBackdropClick)
|
|
297
|
+
return;
|
|
295
298
|
// Avoid closing when clicking inside the panel area
|
|
296
299
|
this.close.emit();
|
|
297
300
|
}
|
|
@@ -488,11 +491,11 @@ class PraxisDialogComponent {
|
|
|
488
491
|
}
|
|
489
492
|
}
|
|
490
493
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
491
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", 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", 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 <div class=\"pdx-dialog__title\" @if (titleTpl?.templateRef || title || titleIcon)>\n @if (titleTpl?.templateRef) {\n <ng-container [ngTemplateOutlet]=\"titleTpl!.templateRef\"></ng-container>\n } @else {\n <div class=\"pdx-dialog__title-row\">\n <mat-icon *ngIf=\"titleIcon\" class=\"pdx-dialog__title-icon\" [praxisIcon]=\"titleIcon\" aria-hidden=\"true\"></mat-icon>\n <h2 class=\"pdx-dialog__title-text\" [attr.id]=\"_titleId\">{{ title }}</h2>\n </div>\n }\n </div>\n </ng-template>\n\n<ng-template #panelActions>\n <div class=\"pdx-dialog__actions\" [class.is-stretched]=\"actionsLayout==='stretched'\">\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]=\"a.role==='primary' && ariaRole==='alertdialog' ? '' : null\"\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-{{ actionsLayout }}\"\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 [ngTemplateOutlet]=\"contentTpl!.templateRef\"></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 class=\"pdx-dialog-overlay\" [class.has-backdrop]=\"hasBackdrop\" [hidden]=\"!isDisplayed\" (click)=\"onBackdrop($event)\" [ngClass]=\"backdropClass\" [style.z-index]=\"zIndex\">\n <div class=\"pdx-dialog-shell\" (click)=\"$event.stopPropagation()\">\n <div\n #panel\n class=\"pdx-dialog pdx-dialog--{{ themeColor }} pdx-dialog--layout-{{ actionsLayout }}\"\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]=\"(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 [ngTemplateOutlet]=\"contentTpl!.templateRef\"></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(--md-sys-color-surface);--pdx-dialog-surface: var(--md-sys-color-surface-container-high);--pdx-dialog-border: var(--md-sys-color-outline-variant);--pdx-dialog-title-fg: var(--md-sys-color-on-surface);--pdx-dialog-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(--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;gap:10px}.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__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(--md-sys-color-surface-container-low);color: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(--md-sys-color-surface-container)}.pdx-dialog__action-btn:focus-visible{outline:2px solid 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(--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(--md-sys-color-outline-variant)}.pdx-dialog--dark{background:var(--md-sys-color-surface-container);color: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.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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 });
|
|
494
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", 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) {\n <div class=\"pdx-dialog__title\">\n @if (titleTpl?.templateRef) {\n <ng-container [ngTemplateOutlet]=\"titleTpl!.templateRef\"></ng-container>\n } @else {\n <div class=\"pdx-dialog__title-row\">\n <mat-icon *ngIf=\"titleIcon\" class=\"pdx-dialog__title-icon\" [praxisIcon]=\"titleIcon\" aria-hidden=\"true\"></mat-icon>\n <h2 class=\"pdx-dialog__title-text\" [attr.id]=\"_titleId\">{{ title }}</h2>\n </div>\n }\n </div>\n }\n </ng-template>\n\n<ng-template #panelActions>\n <div class=\"pdx-dialog__actions\" [class.is-stretched]=\"actionsLayout==='stretched'\">\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]=\"a.role==='primary' && ariaRole==='alertdialog' ? '' : null\"\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-{{ actionsLayout }}\"\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 [ngTemplateOutlet]=\"contentTpl!.templateRef\"></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 class=\"pdx-dialog-overlay\" [class.has-backdrop]=\"hasBackdrop\" [hidden]=\"!isDisplayed\" (click)=\"onBackdrop($event)\" [ngClass]=\"backdropClass\" [style.z-index]=\"zIndex\">\n <div class=\"pdx-dialog-shell\" (click)=\"$event.stopPropagation()\">\n <div\n #panel\n class=\"pdx-dialog pdx-dialog--{{ themeColor }} pdx-dialog--layout-{{ actionsLayout }}\"\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]=\"(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 [ngTemplateOutlet]=\"contentTpl!.templateRef\"></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(--md-sys-color-surface);--pdx-dialog-surface: var(--md-sys-color-surface-container-high);--pdx-dialog-border: var(--md-sys-color-outline-variant);--pdx-dialog-title-fg: var(--md-sys-color-on-surface);--pdx-dialog-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(--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;gap:10px}.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__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(--md-sys-color-surface-container-low);color: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(--md-sys-color-surface-container)}.pdx-dialog__action-btn:focus-visible{outline:2px solid 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(--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(--md-sys-color-outline-variant)}.pdx-dialog--dark{background:var(--md-sys-color-surface-container);color: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.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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 });
|
|
492
495
|
}
|
|
493
496
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisDialogComponent, decorators: [{
|
|
494
497
|
type: Component,
|
|
495
|
-
args: [{ selector: 'praxis-dialog', standalone: true, imports: [CommonModule, PortalModule, A11yModule, MatIconModule, PraxisIconDirective], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "@let _titleId = (id ?? 'praxis-dialog') + '-title';\n\n<ng-template #panelHeader>\n <div class=\"pdx-dialog__title\" @if (titleTpl?.templateRef || title || titleIcon)>\n @if (titleTpl?.templateRef) {\n <ng-container [ngTemplateOutlet]=\"titleTpl!.templateRef\"></ng-container>\n } @else {\n <div class=\"pdx-dialog__title-row\">\n <mat-icon *ngIf=\"titleIcon\" class=\"pdx-dialog__title-icon\" [praxisIcon]=\"titleIcon\" aria-hidden=\"true\"></mat-icon>\n <h2 class=\"pdx-dialog__title-text\" [attr.id]=\"_titleId\">{{ title }}</h2>\n </div>\n }\n </div>\n </ng-template>\n\n<ng-template #panelActions>\n <div class=\"pdx-dialog__actions\" [class.is-stretched]=\"actionsLayout==='stretched'\">\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]=\"a.role==='primary' && ariaRole==='alertdialog' ? '' : null\"\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-{{ actionsLayout }}\"\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 [ngTemplateOutlet]=\"contentTpl!.templateRef\"></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 class=\"pdx-dialog-overlay\" [class.has-backdrop]=\"hasBackdrop\" [hidden]=\"!isDisplayed\" (click)=\"onBackdrop($event)\" [ngClass]=\"backdropClass\" [style.z-index]=\"zIndex\">\n <div class=\"pdx-dialog-shell\" (click)=\"$event.stopPropagation()\">\n <div\n #panel\n class=\"pdx-dialog pdx-dialog--{{ themeColor }} pdx-dialog--layout-{{ actionsLayout }}\"\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]=\"(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 [ngTemplateOutlet]=\"contentTpl!.templateRef\"></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(--md-sys-color-surface);--pdx-dialog-surface: var(--md-sys-color-surface-container-high);--pdx-dialog-border: var(--md-sys-color-outline-variant);--pdx-dialog-title-fg: var(--md-sys-color-on-surface);--pdx-dialog-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(--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;gap:10px}.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__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(--md-sys-color-surface-container-low);color: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(--md-sys-color-surface-container)}.pdx-dialog__action-btn:focus-visible{outline:2px solid 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(--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(--md-sys-color-outline-variant)}.pdx-dialog--dark{background:var(--md-sys-color-surface-container);color: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"] }]
|
|
498
|
+
args: [{ selector: 'praxis-dialog', standalone: true, imports: [CommonModule, PortalModule, A11yModule, MatIconModule, PraxisIconDirective], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "@let _titleId = (id ?? 'praxis-dialog') + '-title';\n\n<ng-template #panelHeader>\n @if (titleTpl?.templateRef || title || titleIcon) {\n <div class=\"pdx-dialog__title\">\n @if (titleTpl?.templateRef) {\n <ng-container [ngTemplateOutlet]=\"titleTpl!.templateRef\"></ng-container>\n } @else {\n <div class=\"pdx-dialog__title-row\">\n <mat-icon *ngIf=\"titleIcon\" class=\"pdx-dialog__title-icon\" [praxisIcon]=\"titleIcon\" aria-hidden=\"true\"></mat-icon>\n <h2 class=\"pdx-dialog__title-text\" [attr.id]=\"_titleId\">{{ title }}</h2>\n </div>\n }\n </div>\n }\n </ng-template>\n\n<ng-template #panelActions>\n <div class=\"pdx-dialog__actions\" [class.is-stretched]=\"actionsLayout==='stretched'\">\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]=\"a.role==='primary' && ariaRole==='alertdialog' ? '' : null\"\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-{{ actionsLayout }}\"\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 [ngTemplateOutlet]=\"contentTpl!.templateRef\"></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 class=\"pdx-dialog-overlay\" [class.has-backdrop]=\"hasBackdrop\" [hidden]=\"!isDisplayed\" (click)=\"onBackdrop($event)\" [ngClass]=\"backdropClass\" [style.z-index]=\"zIndex\">\n <div class=\"pdx-dialog-shell\" (click)=\"$event.stopPropagation()\">\n <div\n #panel\n class=\"pdx-dialog pdx-dialog--{{ themeColor }} pdx-dialog--layout-{{ actionsLayout }}\"\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]=\"(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 [ngTemplateOutlet]=\"contentTpl!.templateRef\"></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(--md-sys-color-surface);--pdx-dialog-surface: var(--md-sys-color-surface-container-high);--pdx-dialog-border: var(--md-sys-color-outline-variant);--pdx-dialog-title-fg: var(--md-sys-color-on-surface);--pdx-dialog-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(--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;gap:10px}.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__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(--md-sys-color-surface-container-low);color: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(--md-sys-color-surface-container)}.pdx-dialog__action-btn:focus-visible{outline:2px solid 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(--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(--md-sys-color-outline-variant)}.pdx-dialog--dark{background:var(--md-sys-color-surface-container);color: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"] }]
|
|
496
499
|
}], propDecorators: { title: [{
|
|
497
500
|
type: Input
|
|
498
501
|
}], actions: [{
|
|
@@ -521,6 +524,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
521
524
|
type: Input
|
|
522
525
|
}], hasBackdrop: [{
|
|
523
526
|
type: Input
|
|
527
|
+
}], closeOnBackdropClick: [{
|
|
528
|
+
type: Input
|
|
524
529
|
}], overlayMode: [{
|
|
525
530
|
type: Input
|
|
526
531
|
}], zIndex: [{
|
|
@@ -681,6 +686,8 @@ class PraxisDialog {
|
|
|
681
686
|
ref.id = assignedId;
|
|
682
687
|
const compRef = this.overlay.attachContainer(overlayRef, injector);
|
|
683
688
|
const container = compRef.instance;
|
|
689
|
+
ref.containerInstance = container;
|
|
690
|
+
ref.containerRef = compRef;
|
|
684
691
|
// Set inputs before detectChanges so the correct branch/materialization occurs
|
|
685
692
|
container.overlayMode = true;
|
|
686
693
|
container.title = config?.title;
|
|
@@ -698,6 +705,7 @@ class PraxisDialog {
|
|
|
698
705
|
container.styles = config?.styles;
|
|
699
706
|
container.disableClose = !!config?.disableClose;
|
|
700
707
|
container.hasBackdrop = config?.hasBackdrop ?? true;
|
|
708
|
+
container.closeOnBackdropClick = config?.closeOnBackdropClick ?? true;
|
|
701
709
|
container.panelClass = config?.panelClass;
|
|
702
710
|
container.backdropClass = config?.backdropClass;
|
|
703
711
|
container.position = config?.position;
|
|
@@ -731,9 +739,16 @@ class PraxisDialog {
|
|
|
731
739
|
});
|
|
732
740
|
const keydownSub = overlayRef.keydownEvents().subscribe((ev) => {
|
|
733
741
|
ref.notifyKeydown(ev);
|
|
742
|
+
if (ev.key === 'Escape' && !config?.disableClose) {
|
|
743
|
+
ref.close();
|
|
744
|
+
}
|
|
734
745
|
});
|
|
735
746
|
// Attach portal content now that the outlet exists
|
|
747
|
+
let contentAttached = false;
|
|
736
748
|
const doAttach = () => {
|
|
749
|
+
if (contentAttached || !container.contentHost)
|
|
750
|
+
return;
|
|
751
|
+
contentAttached = true;
|
|
737
752
|
if (content instanceof TemplateRef) {
|
|
738
753
|
const origin = config?.viewContainerRef ?? null;
|
|
739
754
|
const portal = new TemplatePortal(content, origin, { $implicit: config?.data });
|
|
@@ -755,7 +770,7 @@ class PraxisDialog {
|
|
|
755
770
|
}
|
|
756
771
|
catch { }
|
|
757
772
|
queueMicrotask(() => {
|
|
758
|
-
if (
|
|
773
|
+
if (overlayRef.hasAttached())
|
|
759
774
|
doAttach();
|
|
760
775
|
});
|
|
761
776
|
}
|
|
@@ -1093,6 +1108,21 @@ function buildHostInputs(payload, context, options) {
|
|
|
1093
1108
|
},
|
|
1094
1109
|
};
|
|
1095
1110
|
}
|
|
1111
|
+
function applySurfaceHostInputs(ref, hostInputs) {
|
|
1112
|
+
const apply = () => {
|
|
1113
|
+
if (!ref.componentInstance)
|
|
1114
|
+
return false;
|
|
1115
|
+
Object.assign(ref.componentInstance, hostInputs);
|
|
1116
|
+
try {
|
|
1117
|
+
ref.componentRef?.changeDetectorRef?.detectChanges();
|
|
1118
|
+
}
|
|
1119
|
+
catch { }
|
|
1120
|
+
return true;
|
|
1121
|
+
};
|
|
1122
|
+
if (apply())
|
|
1123
|
+
return;
|
|
1124
|
+
queueMicrotask(apply);
|
|
1125
|
+
}
|
|
1096
1126
|
function providePraxisSurfaceGlobalActions() {
|
|
1097
1127
|
return {
|
|
1098
1128
|
provide: GLOBAL_SURFACE_SERVICE,
|
|
@@ -1126,15 +1156,11 @@ function providePraxisSurfaceGlobalActions() {
|
|
|
1126
1156
|
}),
|
|
1127
1157
|
},
|
|
1128
1158
|
});
|
|
1129
|
-
return
|
|
1159
|
+
return ref;
|
|
1130
1160
|
}
|
|
1131
1161
|
const ref = dialog.open(PraxisSurfaceHostComponent, buildDialogConfig(payload));
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
ref.componentRef?.changeDetectorRef?.detectChanges();
|
|
1135
|
-
}
|
|
1136
|
-
catch { }
|
|
1137
|
-
return firstValueFrom(ref.afterClosed());
|
|
1162
|
+
applySurfaceHostInputs(ref, hostInputs);
|
|
1163
|
+
return ref;
|
|
1138
1164
|
},
|
|
1139
1165
|
};
|
|
1140
1166
|
},
|
|
@@ -1196,8 +1222,411 @@ function providePraxisDialogExamples() {
|
|
|
1196
1222
|
};
|
|
1197
1223
|
}
|
|
1198
1224
|
|
|
1225
|
+
const PRAXIS_DIALOG_PORTS = [
|
|
1226
|
+
{
|
|
1227
|
+
id: 'config',
|
|
1228
|
+
label: 'Dialog config',
|
|
1229
|
+
direction: 'input',
|
|
1230
|
+
semanticKind: 'config-fragment',
|
|
1231
|
+
schema: {
|
|
1232
|
+
id: 'PraxisDialogConfig',
|
|
1233
|
+
kind: 'ts-type',
|
|
1234
|
+
ref: 'PraxisDialogConfig',
|
|
1235
|
+
},
|
|
1236
|
+
description: 'Dialog shell configuration for title, actions, dimensions, backdrop, close policy and accessibility.',
|
|
1237
|
+
exposure: { public: true, group: 'config' },
|
|
1238
|
+
},
|
|
1239
|
+
{
|
|
1240
|
+
id: 'close',
|
|
1241
|
+
label: 'Close',
|
|
1242
|
+
direction: 'output',
|
|
1243
|
+
semanticKind: 'event',
|
|
1244
|
+
schema: {
|
|
1245
|
+
id: 'unknown',
|
|
1246
|
+
kind: 'ts-type',
|
|
1247
|
+
ref: 'unknown',
|
|
1248
|
+
},
|
|
1249
|
+
cardinality: 'stream',
|
|
1250
|
+
description: 'Emitted when the dialog shell requests close with an optional result payload.',
|
|
1251
|
+
exposure: { public: true, group: 'events' },
|
|
1252
|
+
},
|
|
1253
|
+
{
|
|
1254
|
+
id: 'action',
|
|
1255
|
+
label: 'Action',
|
|
1256
|
+
direction: 'output',
|
|
1257
|
+
semanticKind: 'event',
|
|
1258
|
+
schema: {
|
|
1259
|
+
id: 'DialogAction',
|
|
1260
|
+
kind: 'ts-type',
|
|
1261
|
+
ref: 'DialogAction',
|
|
1262
|
+
},
|
|
1263
|
+
cardinality: 'stream',
|
|
1264
|
+
description: 'Emitted when a configured dialog action is triggered.',
|
|
1265
|
+
exposure: { public: true, group: 'events' },
|
|
1266
|
+
},
|
|
1267
|
+
];
|
|
1268
|
+
const PRAXIS_DIALOG_COMPONENT_METADATA = {
|
|
1269
|
+
id: 'praxis-dialog',
|
|
1270
|
+
selector: 'praxis-dialog',
|
|
1271
|
+
component: PraxisDialogComponent,
|
|
1272
|
+
friendlyName: 'Praxis Dialog',
|
|
1273
|
+
description: 'Dialog shell for overlay and embedded authoring, with governed size, position, backdrop, close policy, presets and child host delegation.',
|
|
1274
|
+
icon: 'dialogs',
|
|
1275
|
+
tags: ['dialog', 'overlay', 'shell', 'authoring'],
|
|
1276
|
+
lib: '@praxisui/dialog',
|
|
1277
|
+
inputs: [
|
|
1278
|
+
{ name: 'title', type: 'string', label: 'Title', description: 'Dialog title text.' },
|
|
1279
|
+
{ name: 'actions', type: 'DialogAction[]', label: 'Actions', description: 'Dialog footer actions and payloads.' },
|
|
1280
|
+
{ name: 'actionsLayout', type: 'ActionsLayout', label: 'Actions layout', description: 'Footer action alignment.' },
|
|
1281
|
+
{ name: 'width', type: 'string | number', label: 'Width', description: 'Dialog width.' },
|
|
1282
|
+
{ name: 'height', type: 'string | number', label: 'Height', description: 'Dialog height.' },
|
|
1283
|
+
{ name: 'minWidth', type: 'string | number', label: 'Minimum width', description: 'Minimum dialog width.' },
|
|
1284
|
+
{ name: 'maxWidth', type: 'string | number', label: 'Maximum width', description: 'Maximum dialog width.' },
|
|
1285
|
+
{ name: 'minHeight', type: 'string | number', label: 'Minimum height', description: 'Minimum dialog height.' },
|
|
1286
|
+
{ name: 'maxHeight', type: 'string | number', label: 'Maximum height', description: 'Maximum dialog height.' },
|
|
1287
|
+
{ name: 'themeColor', type: 'DialogThemeColor', label: 'Theme color', description: 'Dialog visual theme.' },
|
|
1288
|
+
{ name: 'disableClose', type: 'boolean', label: 'Disable close', description: 'Blocks backdrop and Escape close behavior.' },
|
|
1289
|
+
{ name: 'hasBackdrop', type: 'boolean', label: 'Backdrop', description: 'Controls whether the dialog renders a backdrop.' },
|
|
1290
|
+
{ name: 'closeOnBackdropClick', type: 'boolean', label: 'Close on backdrop click', description: 'Controls backdrop click close policy.' },
|
|
1291
|
+
{ name: 'panelClass', type: 'string | string[] | Record<string, boolean>', label: 'Panel class', description: 'Additional CSS class for the dialog panel.' },
|
|
1292
|
+
{ name: 'backdropClass', type: 'string | string[] | Record<string, boolean>', label: 'Backdrop class', description: 'Additional CSS class for the backdrop.' },
|
|
1293
|
+
{ name: 'position', type: 'PraxisDialogPosition', label: 'Position', description: 'Dialog position offsets.' },
|
|
1294
|
+
{ name: 'ariaRole', type: "'dialog' | 'alertdialog'", label: 'ARIA role', description: 'Accessible dialog role.' },
|
|
1295
|
+
{ name: 'ariaLabel', type: 'string', label: 'ARIA label', description: 'Accessible label when no visible title is present.' },
|
|
1296
|
+
{ name: 'ariaLabelledBy', type: 'string', label: 'ARIA labelled by', description: 'External accessible label id.' },
|
|
1297
|
+
{ name: 'ariaDescribedBy', type: 'string', label: 'ARIA described by', description: 'External accessible description id.' },
|
|
1298
|
+
],
|
|
1299
|
+
outputs: [
|
|
1300
|
+
{ name: 'action', type: 'DialogAction', label: 'Action' },
|
|
1301
|
+
{ name: 'close', type: 'unknown', label: 'Close' },
|
|
1302
|
+
{ name: 'opened', type: 'void', label: 'Opened' },
|
|
1303
|
+
{ name: 'afterClosed', type: 'void', label: 'After closed' },
|
|
1304
|
+
],
|
|
1305
|
+
actions: [
|
|
1306
|
+
{
|
|
1307
|
+
id: 'dialog-open',
|
|
1308
|
+
label: 'Open dialog',
|
|
1309
|
+
icon: 'open_in_new',
|
|
1310
|
+
description: 'Opens a dialog shell with governed config.',
|
|
1311
|
+
scope: 'any',
|
|
1312
|
+
},
|
|
1313
|
+
{
|
|
1314
|
+
id: 'dialog-close',
|
|
1315
|
+
label: 'Close dialog',
|
|
1316
|
+
icon: 'close',
|
|
1317
|
+
description: 'Closes the dialog with an optional payload.',
|
|
1318
|
+
emit: 'close',
|
|
1319
|
+
scope: 'any',
|
|
1320
|
+
},
|
|
1321
|
+
],
|
|
1322
|
+
ports: PRAXIS_DIALOG_PORTS,
|
|
1323
|
+
};
|
|
1324
|
+
function providePraxisDialogMetadata() {
|
|
1325
|
+
return {
|
|
1326
|
+
provide: ENVIRONMENT_INITIALIZER,
|
|
1327
|
+
multi: true,
|
|
1328
|
+
useFactory: (registry) => () => {
|
|
1329
|
+
registry.register(PRAXIS_DIALOG_COMPONENT_METADATA);
|
|
1330
|
+
},
|
|
1331
|
+
deps: [ComponentMetadataRegistry],
|
|
1332
|
+
};
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
const sizeFieldSchema = {
|
|
1336
|
+
type: 'object',
|
|
1337
|
+
minProperties: 1,
|
|
1338
|
+
properties: {
|
|
1339
|
+
width: { oneOf: [{ type: 'string' }, { type: 'number' }] },
|
|
1340
|
+
height: { oneOf: [{ type: 'string' }, { type: 'number' }] },
|
|
1341
|
+
minWidth: { oneOf: [{ type: 'string' }, { type: 'number' }] },
|
|
1342
|
+
maxWidth: { oneOf: [{ type: 'string' }, { type: 'number' }] },
|
|
1343
|
+
minHeight: { oneOf: [{ type: 'string' }, { type: 'number' }] },
|
|
1344
|
+
maxHeight: { oneOf: [{ type: 'string' }, { type: 'number' }] },
|
|
1345
|
+
},
|
|
1346
|
+
};
|
|
1347
|
+
const positionSchema = {
|
|
1348
|
+
type: 'object',
|
|
1349
|
+
minProperties: 1,
|
|
1350
|
+
properties: {
|
|
1351
|
+
top: { type: 'string' },
|
|
1352
|
+
bottom: { type: 'string' },
|
|
1353
|
+
left: { type: 'string' },
|
|
1354
|
+
right: { type: 'string' },
|
|
1355
|
+
},
|
|
1356
|
+
};
|
|
1357
|
+
const closePolicySchema = {
|
|
1358
|
+
type: 'object',
|
|
1359
|
+
minProperties: 1,
|
|
1360
|
+
properties: {
|
|
1361
|
+
disableClose: { type: 'boolean' },
|
|
1362
|
+
closeOnBackdropClick: { type: 'boolean' },
|
|
1363
|
+
closeOnNavigation: { type: 'boolean' },
|
|
1364
|
+
restoreFocus: { type: 'boolean' },
|
|
1365
|
+
autoFocus: { type: 'boolean' },
|
|
1366
|
+
autoFocusedElement: { type: 'string' },
|
|
1367
|
+
},
|
|
1368
|
+
};
|
|
1369
|
+
const childHostSchema = {
|
|
1370
|
+
type: 'object',
|
|
1371
|
+
required: ['contentType'],
|
|
1372
|
+
properties: {
|
|
1373
|
+
contentType: { enum: ['component', 'template'] },
|
|
1374
|
+
componentId: { type: 'string' },
|
|
1375
|
+
templateId: { type: 'string' },
|
|
1376
|
+
inputs: { type: 'object' },
|
|
1377
|
+
data: {},
|
|
1378
|
+
childManifestComponentId: { type: 'string' },
|
|
1379
|
+
},
|
|
1380
|
+
};
|
|
1381
|
+
const PRAXIS_DIALOG_AUTHORING_MANIFEST = {
|
|
1382
|
+
schemaVersion: '1.0.0',
|
|
1383
|
+
componentId: 'praxis-dialog',
|
|
1384
|
+
ownerPackage: '@praxisui/dialog',
|
|
1385
|
+
configSchemaId: 'PraxisDialogConfig',
|
|
1386
|
+
manifestVersion: '1.0.0',
|
|
1387
|
+
runtimeInputs: [
|
|
1388
|
+
{ name: 'config', type: 'PraxisDialogConfig', description: 'Canonical shell configuration consumed by PraxisDialog.open and tag mode.' },
|
|
1389
|
+
{ name: 'content', type: 'ComponentType | TemplateRef | DialogContentDescriptor', description: 'Dialog child host content. Child semantics remain owned by the child component manifest.' },
|
|
1390
|
+
{ name: 'variant', type: 'string', description: 'Optional global preset variant merged after dialog type presets and before local config.' },
|
|
1391
|
+
{ name: 'componentId', type: 'string', description: 'Component metadata or dialog registry id used by global dialog open actions.' },
|
|
1392
|
+
{ name: 'inputs', type: 'Record<string, unknown>', description: 'Inputs applied to the child component after opening the dialog.' },
|
|
1393
|
+
],
|
|
1394
|
+
editableTargets: [
|
|
1395
|
+
{ kind: 'dialogShell', resolver: 'praxis-dialog-config-root', description: 'Top-level PraxisDialogConfig shell fields such as title, role, actions and theme.' },
|
|
1396
|
+
{ kind: 'size', resolver: 'praxis-dialog-size-fields', description: 'Width, height, min/max size fields on PraxisDialogConfig.' },
|
|
1397
|
+
{ kind: 'position', resolver: 'praxis-dialog-position-fields', description: 'Overlay position fields top, bottom, left and right.' },
|
|
1398
|
+
{ kind: 'backdrop', resolver: 'praxis-dialog-backdrop-fields', description: 'Backdrop enablement and backdrop class semantics.' },
|
|
1399
|
+
{ kind: 'closePolicy', resolver: 'praxis-dialog-close-policy-fields', description: 'disableClose, closeOnBackdropClick, closeOnNavigation, restoreFocus and autofocus behavior.' },
|
|
1400
|
+
{ kind: 'preset', resolver: 'praxis-dialog-global-preset-by-type-variant', description: 'Type and variant presets merged through PRAXIS_DIALOG_GLOBAL_PRESETS.' },
|
|
1401
|
+
{ kind: 'childHost', resolver: 'praxis-dialog-child-component-or-template-host', description: 'Component/template registry child host and input/data envelope.' },
|
|
1402
|
+
],
|
|
1403
|
+
operations: [
|
|
1404
|
+
{
|
|
1405
|
+
operationId: 'dialog.shell.set',
|
|
1406
|
+
title: 'Set dialog shell fields',
|
|
1407
|
+
scope: 'global',
|
|
1408
|
+
targetKind: 'dialogShell',
|
|
1409
|
+
target: { kind: 'dialogShell', resolver: 'praxis-dialog-config-root', ambiguityPolicy: 'fail', required: false },
|
|
1410
|
+
inputSchema: {
|
|
1411
|
+
type: 'object',
|
|
1412
|
+
minProperties: 1,
|
|
1413
|
+
properties: {
|
|
1414
|
+
title: { type: 'string' },
|
|
1415
|
+
titleIcon: { type: 'string' },
|
|
1416
|
+
ariaRole: { enum: ['dialog', 'alertdialog'] },
|
|
1417
|
+
ariaLabel: { type: 'string' },
|
|
1418
|
+
ariaLabelledBy: { type: 'string' },
|
|
1419
|
+
ariaDescribedBy: { type: 'string' },
|
|
1420
|
+
themeColor: { enum: ['primary', 'light', 'dark'] },
|
|
1421
|
+
actionsLayout: { enum: ['start', 'center', 'end', 'stretched'] },
|
|
1422
|
+
},
|
|
1423
|
+
},
|
|
1424
|
+
effects: [{ kind: 'merge-object', path: 'config' }],
|
|
1425
|
+
destructive: false,
|
|
1426
|
+
requiresConfirmation: false,
|
|
1427
|
+
validators: ['accessibility-label-preserved', 'aria-role-valid', 'shell-fields-supported', 'dialog-round-trip'],
|
|
1428
|
+
affectedPaths: ['config.title', 'config.titleIcon', 'config.ariaRole', 'config.ariaLabel', 'config.ariaLabelledBy', 'config.ariaDescribedBy', 'config.themeColor', 'config.actionsLayout'],
|
|
1429
|
+
submissionImpact: 'config-only',
|
|
1430
|
+
preconditions: ['config-initialized'],
|
|
1431
|
+
},
|
|
1432
|
+
{
|
|
1433
|
+
operationId: 'dialog.size.set',
|
|
1434
|
+
title: 'Set dialog size',
|
|
1435
|
+
scope: 'layout',
|
|
1436
|
+
targetKind: 'size',
|
|
1437
|
+
target: { kind: 'size', resolver: 'praxis-dialog-size-fields', ambiguityPolicy: 'fail', required: false },
|
|
1438
|
+
inputSchema: sizeFieldSchema,
|
|
1439
|
+
effects: [{ kind: 'merge-object', path: 'config' }],
|
|
1440
|
+
destructive: false,
|
|
1441
|
+
requiresConfirmation: false,
|
|
1442
|
+
validators: ['size-values-safe', 'size-min-max-consistent', 'dialog-round-trip'],
|
|
1443
|
+
affectedPaths: ['config.width', 'config.height', 'config.minWidth', 'config.maxWidth', 'config.minHeight', 'config.maxHeight'],
|
|
1444
|
+
submissionImpact: 'visual-only',
|
|
1445
|
+
preconditions: ['config-initialized'],
|
|
1446
|
+
},
|
|
1447
|
+
{
|
|
1448
|
+
operationId: 'dialog.position.set',
|
|
1449
|
+
title: 'Set dialog position',
|
|
1450
|
+
scope: 'layout',
|
|
1451
|
+
targetKind: 'position',
|
|
1452
|
+
target: { kind: 'position', resolver: 'praxis-dialog-position-fields', ambiguityPolicy: 'fail', required: false },
|
|
1453
|
+
inputSchema: positionSchema,
|
|
1454
|
+
effects: [{ kind: 'set-value', path: 'config.position' }],
|
|
1455
|
+
destructive: false,
|
|
1456
|
+
requiresConfirmation: false,
|
|
1457
|
+
validators: ['position-values-safe', 'position-not-conflicting', 'dialog-round-trip'],
|
|
1458
|
+
affectedPaths: ['config.position'],
|
|
1459
|
+
submissionImpact: 'visual-only',
|
|
1460
|
+
preconditions: ['config-initialized'],
|
|
1461
|
+
},
|
|
1462
|
+
{
|
|
1463
|
+
operationId: 'dialog.backdrop.set',
|
|
1464
|
+
title: 'Set dialog backdrop',
|
|
1465
|
+
scope: 'skin',
|
|
1466
|
+
targetKind: 'backdrop',
|
|
1467
|
+
target: { kind: 'backdrop', resolver: 'praxis-dialog-backdrop-fields', ambiguityPolicy: 'fail', required: false },
|
|
1468
|
+
inputSchema: {
|
|
1469
|
+
type: 'object',
|
|
1470
|
+
minProperties: 1,
|
|
1471
|
+
properties: {
|
|
1472
|
+
hasBackdrop: { type: 'boolean' },
|
|
1473
|
+
backdropClass: { oneOf: [{ type: 'string' }, { type: 'array' }, { type: 'object' }] },
|
|
1474
|
+
},
|
|
1475
|
+
},
|
|
1476
|
+
effects: [{ kind: 'merge-object', path: 'config' }],
|
|
1477
|
+
destructive: false,
|
|
1478
|
+
requiresConfirmation: false,
|
|
1479
|
+
validators: ['backdrop-policy-explicit', 'backdrop-class-safe', 'dialog-round-trip'],
|
|
1480
|
+
affectedPaths: ['config.hasBackdrop', 'config.backdropClass'],
|
|
1481
|
+
submissionImpact: 'visual-only',
|
|
1482
|
+
preconditions: ['config-initialized'],
|
|
1483
|
+
},
|
|
1484
|
+
{
|
|
1485
|
+
operationId: 'dialog.closePolicy.set',
|
|
1486
|
+
title: 'Set dialog close policy',
|
|
1487
|
+
scope: 'accessibility',
|
|
1488
|
+
targetKind: 'closePolicy',
|
|
1489
|
+
target: { kind: 'closePolicy', resolver: 'praxis-dialog-close-policy-fields', ambiguityPolicy: 'fail', required: false },
|
|
1490
|
+
inputSchema: closePolicySchema,
|
|
1491
|
+
effects: [{ kind: 'merge-object', path: 'config' }],
|
|
1492
|
+
destructive: true,
|
|
1493
|
+
requiresConfirmation: true,
|
|
1494
|
+
validators: ['close-policy-explicit', 'unsafe-close-confirmed-when-needed', 'restore-focus-preserved', 'alertdialog-focus-preserved', 'dialog-round-trip'],
|
|
1495
|
+
affectedPaths: ['config.disableClose', 'config.closeOnBackdropClick', 'config.closeOnNavigation', 'config.restoreFocus', 'config.autoFocus', 'config.autoFocusedElement'],
|
|
1496
|
+
submissionImpact: 'config-only',
|
|
1497
|
+
preconditions: ['config-initialized', 'confirmation-collected'],
|
|
1498
|
+
},
|
|
1499
|
+
{
|
|
1500
|
+
operationId: 'dialog.preset.apply',
|
|
1501
|
+
title: 'Apply dialog preset',
|
|
1502
|
+
scope: 'global',
|
|
1503
|
+
targetKind: 'preset',
|
|
1504
|
+
target: { kind: 'preset', resolver: 'praxis-dialog-global-preset-by-type-variant', ambiguityPolicy: 'fail', required: false },
|
|
1505
|
+
inputSchema: {
|
|
1506
|
+
type: 'object',
|
|
1507
|
+
required: ['dialogType'],
|
|
1508
|
+
properties: {
|
|
1509
|
+
dialogType: { enum: ['confirm', 'alert', 'prompt', 'custom'] },
|
|
1510
|
+
variant: { type: 'string' },
|
|
1511
|
+
localConfig: { type: 'object' },
|
|
1512
|
+
},
|
|
1513
|
+
},
|
|
1514
|
+
effects: [{ kind: 'compile-domain-patch', handler: 'dialog-preset-apply', handlerContract: {
|
|
1515
|
+
reads: ['PRAXIS_DIALOG_GLOBAL_PRESETS', 'config', 'variant'],
|
|
1516
|
+
writes: ['config', 'variant'],
|
|
1517
|
+
identityKeys: ['dialogType', 'variant'],
|
|
1518
|
+
inputSchema: { type: 'object', required: ['dialogType'], properties: { dialogType: { enum: ['confirm', 'alert', 'prompt', 'custom'] }, variant: { type: 'string' }, localConfig: { type: 'object' } } },
|
|
1519
|
+
failureModes: ['preset-not-found', 'variant-not-found', 'preset-merge-order-invalid', 'accessibility-regression'],
|
|
1520
|
+
description: 'Applies the canonical merge order type preset -> variant -> local config without mutating child component semantics.',
|
|
1521
|
+
} }],
|
|
1522
|
+
destructive: false,
|
|
1523
|
+
requiresConfirmation: false,
|
|
1524
|
+
validators: ['preset-exists', 'preset-merge-order-preserved', 'accessibility-label-preserved', 'dialog-round-trip'],
|
|
1525
|
+
affectedPaths: ['config', 'variant'],
|
|
1526
|
+
submissionImpact: 'config-only',
|
|
1527
|
+
preconditions: ['config-initialized'],
|
|
1528
|
+
},
|
|
1529
|
+
{
|
|
1530
|
+
operationId: 'childHost.configure',
|
|
1531
|
+
title: 'Configure dialog child host',
|
|
1532
|
+
scope: 'templating',
|
|
1533
|
+
targetKind: 'childHost',
|
|
1534
|
+
target: { kind: 'childHost', resolver: 'praxis-dialog-child-component-or-template-host', ambiguityPolicy: 'fail', required: false },
|
|
1535
|
+
inputSchema: childHostSchema,
|
|
1536
|
+
effects: [{ kind: 'compile-domain-patch', handler: 'dialog-child-host-configure', handlerContract: {
|
|
1537
|
+
reads: ['ComponentMetadataRegistry', 'PRAXIS_DIALOG_CONTENT_REGISTRY', 'PRAXIS_DIALOG_TEMPLATE_REGISTRY', 'content', 'componentId', 'inputs', 'data'],
|
|
1538
|
+
writes: ['content', 'componentId', 'inputs', 'data'],
|
|
1539
|
+
identityKeys: ['componentId', 'templateId'],
|
|
1540
|
+
inputSchema: childHostSchema,
|
|
1541
|
+
failureModes: ['component-not-registered', 'template-not-registered', 'child-inputs-not-serializable', 'child-manifest-required'],
|
|
1542
|
+
description: 'Configures which component/template is hosted in the dialog and serializable host inputs; child config fields remain delegated to the child manifest.',
|
|
1543
|
+
} }],
|
|
1544
|
+
destructive: false,
|
|
1545
|
+
requiresConfirmation: false,
|
|
1546
|
+
validators: ['child-host-registered', 'child-config-delegates-to-child-manifest', 'child-inputs-serializable', 'dialog-round-trip'],
|
|
1547
|
+
affectedPaths: ['content', 'componentId', 'inputs', 'data'],
|
|
1548
|
+
submissionImpact: 'config-only',
|
|
1549
|
+
preconditions: ['config-initialized'],
|
|
1550
|
+
},
|
|
1551
|
+
{
|
|
1552
|
+
operationId: 'childOperation.delegate',
|
|
1553
|
+
title: 'Delegate operation to child manifest',
|
|
1554
|
+
scope: 'templating',
|
|
1555
|
+
targetKind: 'childHost',
|
|
1556
|
+
target: { kind: 'childHost', resolver: 'praxis-dialog-child-component-or-template-host', ambiguityPolicy: 'fail', required: true },
|
|
1557
|
+
inputSchema: {
|
|
1558
|
+
type: 'object',
|
|
1559
|
+
required: ['childManifestComponentId', 'operationId', 'params'],
|
|
1560
|
+
properties: {
|
|
1561
|
+
childManifestComponentId: { type: 'string' },
|
|
1562
|
+
operationId: { type: 'string' },
|
|
1563
|
+
target: { type: 'string' },
|
|
1564
|
+
params: { type: 'object' },
|
|
1565
|
+
},
|
|
1566
|
+
},
|
|
1567
|
+
effects: [{ kind: 'compile-domain-patch', handler: 'dialog-child-operation-delegate', handlerContract: {
|
|
1568
|
+
reads: ['childManifestComponentId', 'operationId', 'params', 'componentRegistry.authoringManifest'],
|
|
1569
|
+
writes: ['inputs', 'data'],
|
|
1570
|
+
identityKeys: ['childManifestComponentId', 'operationId'],
|
|
1571
|
+
inputSchema: { type: 'object', required: ['childManifestComponentId', 'operationId', 'params'], properties: { childManifestComponentId: { type: 'string' }, operationId: { type: 'string' }, target: { type: 'string' }, params: { type: 'object' } } },
|
|
1572
|
+
failureModes: ['child-manifest-not-found', 'child-operation-not-authorized', 'child-operation-validation-failed', 'dialog-shell-child-boundary-violation'],
|
|
1573
|
+
description: 'Delegates child component configuration edits to the child authoring manifest before projecting the validated patch into the dialog child host inputs/data envelope.',
|
|
1574
|
+
} }],
|
|
1575
|
+
destructive: false,
|
|
1576
|
+
requiresConfirmation: false,
|
|
1577
|
+
validators: ['child-manifest-resolvable', 'child-operation-authorized', 'child-config-delegates-to-child-manifest', 'dialog-shell-boundary-preserved'],
|
|
1578
|
+
affectedPaths: ['inputs', 'data'],
|
|
1579
|
+
submissionImpact: 'config-only',
|
|
1580
|
+
preconditions: ['child-host-configured', 'child-manifest-resolved'],
|
|
1581
|
+
},
|
|
1582
|
+
],
|
|
1583
|
+
validators: [
|
|
1584
|
+
{ validatorId: 'accessibility-label-preserved', level: 'error', code: 'DIALOG_ACCESSIBILITY_LABEL_PRESERVED', description: 'Dialog or alertdialog must keep an accessible title or aria label.' },
|
|
1585
|
+
{ validatorId: 'aria-role-valid', level: 'error', code: 'DIALOG_ARIA_ROLE_VALID', description: 'ariaRole must be dialog or alertdialog.' },
|
|
1586
|
+
{ validatorId: 'shell-fields-supported', level: 'error', code: 'DIALOG_SHELL_FIELDS_SUPPORTED', description: 'Shell edits must target supported PraxisDialogConfig fields.' },
|
|
1587
|
+
{ validatorId: 'size-values-safe', level: 'error', code: 'DIALOG_SIZE_VALUES_SAFE', description: 'Size values must be finite numbers or safe CSS size strings.' },
|
|
1588
|
+
{ validatorId: 'size-min-max-consistent', level: 'error', code: 'DIALOG_SIZE_MIN_MAX_CONSISTENT', description: 'Minimum sizes must not exceed maximum sizes.' },
|
|
1589
|
+
{ validatorId: 'position-values-safe', level: 'error', code: 'DIALOG_POSITION_VALUES_SAFE', description: 'Position values must be safe CSS size strings.' },
|
|
1590
|
+
{ validatorId: 'position-not-conflicting', level: 'warning', code: 'DIALOG_POSITION_NOT_CONFLICTING', description: 'Conflicting position pairs should be explicit and intentional.' },
|
|
1591
|
+
{ validatorId: 'backdrop-policy-explicit', level: 'error', code: 'DIALOG_BACKDROP_POLICY_EXPLICIT', description: 'Backdrop and backdrop-click behavior must be explicit when edited.' },
|
|
1592
|
+
{ validatorId: 'backdrop-class-safe', level: 'error', code: 'DIALOG_BACKDROP_CLASS_SAFE', description: 'Backdrop classes must be serializable safe class values.' },
|
|
1593
|
+
{ validatorId: 'close-policy-explicit', level: 'error', code: 'DIALOG_CLOSE_POLICY_EXPLICIT', description: 'Close behavior must explicitly describe ESC, backdrop and navigation semantics.' },
|
|
1594
|
+
{ validatorId: 'unsafe-close-confirmed-when-needed', level: 'error', code: 'DIALOG_UNSAFE_CLOSE_CONFIRMED', description: 'Disabling safe close affordances or enabling unsafe dismissal requires confirmation.' },
|
|
1595
|
+
{ validatorId: 'restore-focus-preserved', level: 'error', code: 'DIALOG_RESTORE_FOCUS_PRESERVED', description: 'restoreFocus must stay enabled unless intentionally changed with confirmation.' },
|
|
1596
|
+
{ validatorId: 'alertdialog-focus-preserved', level: 'error', code: 'DIALOG_ALERTDIALOG_FOCUS_PRESERVED', description: 'alertdialog focus behavior must keep primary action or configured focus target reachable.' },
|
|
1597
|
+
{ validatorId: 'preset-exists', level: 'error', code: 'DIALOG_PRESET_EXISTS', description: 'Preset type and variant must exist in PRAXIS_DIALOG_GLOBAL_PRESETS or be host-provided.' },
|
|
1598
|
+
{ validatorId: 'preset-merge-order-preserved', level: 'error', code: 'DIALOG_PRESET_MERGE_ORDER_PRESERVED', description: 'Preset merge order must remain type -> variant -> local config.' },
|
|
1599
|
+
{ validatorId: 'child-host-registered', level: 'error', code: 'DIALOG_CHILD_HOST_REGISTERED', description: 'Child component/template must resolve through ComponentMetadataRegistry or dialog registries.' },
|
|
1600
|
+
{ validatorId: 'child-config-delegates-to-child-manifest', level: 'error', code: 'DIALOG_CHILD_CONFIG_DELEGATES', description: 'Child component config edits must be delegated to the child authoring manifest.' },
|
|
1601
|
+
{ validatorId: 'child-inputs-serializable', level: 'error', code: 'DIALOG_CHILD_INPUTS_SERIALIZABLE', description: 'Child inputs/data persisted by authoring must be serializable safe values.' },
|
|
1602
|
+
{ validatorId: 'child-manifest-resolvable', level: 'error', code: 'DIALOG_CHILD_MANIFEST_RESOLVABLE', description: 'Delegated child operation must resolve a child component authoring manifest.' },
|
|
1603
|
+
{ validatorId: 'child-operation-authorized', level: 'error', code: 'DIALOG_CHILD_OPERATION_AUTHORIZED', description: 'Delegated child operation must be declared by the child manifest.' },
|
|
1604
|
+
{ validatorId: 'dialog-shell-boundary-preserved', level: 'error', code: 'DIALOG_SHELL_BOUNDARY_PRESERVED', description: 'Dialog shell operations must not rewrite child component semantics directly.' },
|
|
1605
|
+
{ validatorId: 'dialog-round-trip', level: 'error', code: 'DIALOG_ROUND_TRIP', description: 'Service/tag mode must preserve shell config through open, close, afterClosed and host persistence.' },
|
|
1606
|
+
],
|
|
1607
|
+
roundTripRequirements: [
|
|
1608
|
+
'PraxisDialogConfig is the canonical shell config; child component config remains owned by the child manifest.',
|
|
1609
|
+
'Preset application must preserve merge order: type preset, then variant, then local config.',
|
|
1610
|
+
'Close policy edits must keep accessibility, focus trap, ESC/backdrop behavior and restoreFocus explicit.',
|
|
1611
|
+
'Dialog host operations must resolve component/template ids through governed registries instead of ad hoc overlays.',
|
|
1612
|
+
],
|
|
1613
|
+
examples: [
|
|
1614
|
+
{ id: 'set-size', request: 'Open this dialog at 860 by 640 pixels.', operationId: 'dialog.size.set', params: { width: '860px', height: '640px' }, isPositive: true },
|
|
1615
|
+
{ id: 'set-position', request: 'Anchor the dialog to the right side.', operationId: 'dialog.position.set', params: { right: '24px', top: '64px' }, isPositive: true },
|
|
1616
|
+
{ id: 'set-backdrop', request: 'Use a backdrop with the default governed backdrop class.', operationId: 'dialog.backdrop.set', params: { hasBackdrop: true, backdropClass: 'pdx-dialog-backdrop' }, isPositive: true },
|
|
1617
|
+
{ id: 'set-close-policy', request: 'Make this destructive confirm require explicit button close.', operationId: 'dialog.closePolicy.set', params: { disableClose: true, closeOnBackdropClick: false, restoreFocus: true }, isPositive: true },
|
|
1618
|
+
{ id: 'apply-danger-preset', request: 'Apply the danger confirm preset.', operationId: 'dialog.preset.apply', params: { dialogType: 'confirm', variant: 'danger' }, isPositive: true },
|
|
1619
|
+
{ id: 'configure-child-host', request: 'Host the dynamic page component with customization enabled.', operationId: 'childHost.configure', params: { contentType: 'component', componentId: 'praxis-dynamic-page', inputs: { enableCustomization: true } }, isPositive: true },
|
|
1620
|
+
{ id: 'delegate-child-config', request: 'Change the table column inside the dialog.', operationId: 'childOperation.delegate', params: { childManifestComponentId: 'praxis-table', operationId: 'column.label.set', params: { field: 'name', label: 'Name' } }, isPositive: true },
|
|
1621
|
+
{ id: 'set-shell-label', request: 'Set the dialog title and alertdialog role.', operationId: 'dialog.shell.set', params: { title: 'Delete record', ariaRole: 'alertdialog' }, isPositive: true },
|
|
1622
|
+
{ id: 'reject-child-shell-mix', request: 'Directly patch the child table config from the dialog shell manifest.', operationId: 'childOperation.delegate', params: { childManifestComponentId: '', operationId: 'patch-raw-child-config', params: {} }, isPositive: false },
|
|
1623
|
+
{ id: 'reject-inaccessible-alert', request: 'Make an alertdialog with no title or aria label.', operationId: 'dialog.shell.set', params: { ariaRole: 'alertdialog', title: '' }, isPositive: false },
|
|
1624
|
+
{ id: 'reject-unsafe-close', request: 'Let a destructive dialog close on accidental backdrop click with no confirmation.', operationId: 'dialog.closePolicy.set', params: { closeOnBackdropClick: true, disableClose: false, restoreFocus: false }, isPositive: false },
|
|
1625
|
+
],
|
|
1626
|
+
};
|
|
1627
|
+
|
|
1199
1628
|
/**
|
|
1200
1629
|
* Generated bundle index. Do not edit.
|
|
1201
1630
|
*/
|
|
1202
1631
|
|
|
1203
|
-
export { LongContentDialogExampleComponent, PRAXIS_DIALOG_CONTENT_REGISTRY, PRAXIS_DIALOG_DATA, PRAXIS_DIALOG_DEFAULTS, PRAXIS_DIALOG_EXAMPLE_LONG_CONTENT, PRAXIS_DIALOG_GLOBAL_PRESETS, PRAXIS_DIALOG_I18N, PRAXIS_DIALOG_TEMPLATE_REGISTRY, PraxisDialog, PraxisDialogActionsDirective, PraxisDialogComponent, PraxisDialogContentDirective, PraxisDialogDirectives, PraxisDialogRef, PraxisDialogTitleDirective, provideDialogGlobalPresetsFromGlobalConfig, providePraxisDialogExamples, providePraxisDialogGlobalActions, providePraxisSurfaceGlobalActions };
|
|
1632
|
+
export { LongContentDialogExampleComponent, PRAXIS_DIALOG_AUTHORING_MANIFEST, PRAXIS_DIALOG_COMPONENT_METADATA, PRAXIS_DIALOG_CONTENT_REGISTRY, PRAXIS_DIALOG_DATA, PRAXIS_DIALOG_DEFAULTS, PRAXIS_DIALOG_EXAMPLE_LONG_CONTENT, PRAXIS_DIALOG_GLOBAL_PRESETS, PRAXIS_DIALOG_I18N, PRAXIS_DIALOG_TEMPLATE_REGISTRY, PraxisDialog, PraxisDialogActionsDirective, PraxisDialogComponent, PraxisDialogContentDirective, PraxisDialogDirectives, PraxisDialogRef, PraxisDialogTitleDirective, provideDialogGlobalPresetsFromGlobalConfig, providePraxisDialogExamples, providePraxisDialogGlobalActions, providePraxisDialogMetadata, providePraxisSurfaceGlobalActions };
|
package/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { InjectionToken, TemplateRef, ComponentRef, OnInit, OnChanges, OnDestroy
|
|
|
3
3
|
import { OverlayRef } from '@angular/cdk/overlay';
|
|
4
4
|
import { Observable, Subject } from 'rxjs';
|
|
5
5
|
import { CdkPortalOutlet } from '@angular/cdk/portal';
|
|
6
|
+
import { ComponentDocMeta, ComponentAuthoringManifest } from '@praxisui/core';
|
|
6
7
|
|
|
7
8
|
type ActionsLayout = 'start' | 'center' | 'end' | 'stretched';
|
|
8
9
|
type DialogThemeColor = 'primary' | 'light' | 'dark';
|
|
@@ -213,6 +214,7 @@ declare class PraxisDialogComponent implements OnInit, OnChanges, OnDestroy {
|
|
|
213
214
|
themeColor: DialogThemeColor;
|
|
214
215
|
disableClose: boolean;
|
|
215
216
|
hasBackdrop: boolean;
|
|
217
|
+
closeOnBackdropClick: boolean;
|
|
216
218
|
overlayMode: boolean;
|
|
217
219
|
zIndex?: number;
|
|
218
220
|
panelClass?: string | string[] | Record<string, boolean>;
|
|
@@ -264,7 +266,7 @@ declare class PraxisDialogComponent implements OnInit, OnChanges, OnDestroy {
|
|
|
264
266
|
beginCloseAnimation(): Promise<void>;
|
|
265
267
|
private focusPrimaryAction;
|
|
266
268
|
static ɵfac: i0.ɵɵFactoryDeclaration<PraxisDialogComponent, never>;
|
|
267
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<PraxisDialogComponent, "praxis-dialog", never, { "title": { "alias": "title"; "required": false; }; "actions": { "alias": "actions"; "required": false; }; "actionsLayout": { "alias": "actionsLayout"; "required": false; }; "animation": { "alias": "animation"; "required": false; }; "open": { "alias": "open"; "required": false; }; "width": { "alias": "width"; "required": false; }; "height": { "alias": "height"; "required": false; }; "minWidth": { "alias": "minWidth"; "required": false; }; "maxWidth": { "alias": "maxWidth"; "required": false; }; "minHeight": { "alias": "minHeight"; "required": false; }; "maxHeight": { "alias": "maxHeight"; "required": false; }; "themeColor": { "alias": "themeColor"; "required": false; }; "disableClose": { "alias": "disableClose"; "required": false; }; "hasBackdrop": { "alias": "hasBackdrop"; "required": false; }; "overlayMode": { "alias": "overlayMode"; "required": false; }; "zIndex": { "alias": "zIndex"; "required": false; }; "panelClass": { "alias": "panelClass"; "required": false; }; "backdropClass": { "alias": "backdropClass"; "required": false; }; "position": { "alias": "position"; "required": false; }; "autoFocusedElement": { "alias": "autoFocusedElement"; "required": false; }; "autoFocus": { "alias": "autoFocus"; "required": false; }; "restoreFocus": { "alias": "restoreFocus"; "required": false; }; "id": { "alias": "id"; "required": false; }; "ariaRole": { "alias": "ariaRole"; "required": false; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; }; "ariaLabelledBy": { "alias": "ariaLabelledBy"; "required": false; }; "ariaDescribedBy": { "alias": "ariaDescribedBy"; "required": false; }; "styles": { "alias": "styles"; "required": false; }; "titleIcon": { "alias": "titleIcon"; "required": false; }; }, { "action": "action"; "close": "close"; "opened": "opened"; "afterClosed": "afterClosed"; }, ["titleTpl", "actionsTpl", "contentTpl"], never, true, never>;
|
|
269
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<PraxisDialogComponent, "praxis-dialog", never, { "title": { "alias": "title"; "required": false; }; "actions": { "alias": "actions"; "required": false; }; "actionsLayout": { "alias": "actionsLayout"; "required": false; }; "animation": { "alias": "animation"; "required": false; }; "open": { "alias": "open"; "required": false; }; "width": { "alias": "width"; "required": false; }; "height": { "alias": "height"; "required": false; }; "minWidth": { "alias": "minWidth"; "required": false; }; "maxWidth": { "alias": "maxWidth"; "required": false; }; "minHeight": { "alias": "minHeight"; "required": false; }; "maxHeight": { "alias": "maxHeight"; "required": false; }; "themeColor": { "alias": "themeColor"; "required": false; }; "disableClose": { "alias": "disableClose"; "required": false; }; "hasBackdrop": { "alias": "hasBackdrop"; "required": false; }; "closeOnBackdropClick": { "alias": "closeOnBackdropClick"; "required": false; }; "overlayMode": { "alias": "overlayMode"; "required": false; }; "zIndex": { "alias": "zIndex"; "required": false; }; "panelClass": { "alias": "panelClass"; "required": false; }; "backdropClass": { "alias": "backdropClass"; "required": false; }; "position": { "alias": "position"; "required": false; }; "autoFocusedElement": { "alias": "autoFocusedElement"; "required": false; }; "autoFocus": { "alias": "autoFocus"; "required": false; }; "restoreFocus": { "alias": "restoreFocus"; "required": false; }; "id": { "alias": "id"; "required": false; }; "ariaRole": { "alias": "ariaRole"; "required": false; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; }; "ariaLabelledBy": { "alias": "ariaLabelledBy"; "required": false; }; "ariaDescribedBy": { "alias": "ariaDescribedBy"; "required": false; }; "styles": { "alias": "styles"; "required": false; }; "titleIcon": { "alias": "titleIcon"; "required": false; }; }, { "action": "action"; "close": "close"; "opened": "opened"; "afterClosed": "afterClosed"; }, ["titleTpl", "actionsTpl", "contentTpl"], never, true, never>;
|
|
268
270
|
}
|
|
269
271
|
declare const PraxisDialogDirectives: readonly [];
|
|
270
272
|
|
|
@@ -332,5 +334,10 @@ declare function providePraxisDialogExamples(): {
|
|
|
332
334
|
deps: i0.InjectionToken<Record<string, ComponentType<any>>>[];
|
|
333
335
|
};
|
|
334
336
|
|
|
335
|
-
|
|
337
|
+
declare const PRAXIS_DIALOG_COMPONENT_METADATA: ComponentDocMeta;
|
|
338
|
+
declare function providePraxisDialogMetadata(): Provider;
|
|
339
|
+
|
|
340
|
+
declare const PRAXIS_DIALOG_AUTHORING_MANIFEST: ComponentAuthoringManifest;
|
|
341
|
+
|
|
342
|
+
export { LongContentDialogExampleComponent, PRAXIS_DIALOG_AUTHORING_MANIFEST, PRAXIS_DIALOG_COMPONENT_METADATA, PRAXIS_DIALOG_CONTENT_REGISTRY, PRAXIS_DIALOG_DATA, PRAXIS_DIALOG_DEFAULTS, PRAXIS_DIALOG_EXAMPLE_LONG_CONTENT, PRAXIS_DIALOG_GLOBAL_PRESETS, PRAXIS_DIALOG_I18N, PRAXIS_DIALOG_TEMPLATE_REGISTRY, PraxisDialog, PraxisDialogActionsDirective, PraxisDialogComponent, PraxisDialogContentDirective, PraxisDialogDirectives, PraxisDialogRef, PraxisDialogTitleDirective, provideDialogGlobalPresetsFromGlobalConfig, providePraxisDialogExamples, providePraxisDialogGlobalActions, providePraxisDialogMetadata, providePraxisSurfaceGlobalActions };
|
|
336
343
|
export type { ActionsLayout, AnimationDirection, ComponentType, DialogAction, DialogAnimation, DialogAnimationType, DialogContentDescriptor, DialogThemeColor, PraxisAlertConfig, PraxisConfirmConfig, PraxisDialogConfig, PraxisDialogGlobalPresets, PraxisDialogPosition, PraxisDialogStyleConfig, PraxisPromptConfig };
|
package/package.json
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@praxisui/dialog",
|
|
3
|
-
"version": "8.0.0-beta.
|
|
3
|
+
"version": "8.0.0-beta.20",
|
|
4
4
|
"description": "Dialog helpers and components for Praxis UI with Angular Material integration.",
|
|
5
5
|
"peerDependencies": {
|
|
6
6
|
"@angular/common": "^20.0.0",
|
|
7
7
|
"@angular/core": "^20.0.0",
|
|
8
8
|
"@angular/cdk": "^20.0.0",
|
|
9
9
|
"@angular/forms": "^20.0.0",
|
|
10
|
-
"@praxisui/core": "^8.0.0-beta.
|
|
10
|
+
"@praxisui/core": "^8.0.0-beta.20",
|
|
11
|
+
"@angular/material": "^20.0.0",
|
|
12
|
+
"@angular/platform-browser": "^20.0.0",
|
|
13
|
+
"rxjs": "~7.8.0"
|
|
11
14
|
},
|
|
12
15
|
"dependencies": {
|
|
13
16
|
"tslib": "^2.3.0"
|