@praxisui/dialog 8.0.0-beta.11 → 8.0.0-beta.12
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 +419 -4
- package/index.d.ts +9 -2
- package/package.json +2 -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;
|
|
@@ -736,7 +744,11 @@ class PraxisDialog {
|
|
|
736
744
|
}
|
|
737
745
|
});
|
|
738
746
|
// Attach portal content now that the outlet exists
|
|
747
|
+
let contentAttached = false;
|
|
739
748
|
const doAttach = () => {
|
|
749
|
+
if (contentAttached || !container.contentHost)
|
|
750
|
+
return;
|
|
751
|
+
contentAttached = true;
|
|
740
752
|
if (content instanceof TemplateRef) {
|
|
741
753
|
const origin = config?.viewContainerRef ?? null;
|
|
742
754
|
const portal = new TemplatePortal(content, origin, { $implicit: config?.data });
|
|
@@ -758,7 +770,7 @@ class PraxisDialog {
|
|
|
758
770
|
}
|
|
759
771
|
catch { }
|
|
760
772
|
queueMicrotask(() => {
|
|
761
|
-
if (
|
|
773
|
+
if (overlayRef.hasAttached())
|
|
762
774
|
doAttach();
|
|
763
775
|
});
|
|
764
776
|
}
|
|
@@ -1210,8 +1222,411 @@ function providePraxisDialogExamples() {
|
|
|
1210
1222
|
};
|
|
1211
1223
|
}
|
|
1212
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
|
+
|
|
1213
1628
|
/**
|
|
1214
1629
|
* Generated bundle index. Do not edit.
|
|
1215
1630
|
*/
|
|
1216
1631
|
|
|
1217
|
-
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,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@praxisui/dialog",
|
|
3
|
-
"version": "8.0.0-beta.
|
|
3
|
+
"version": "8.0.0-beta.12",
|
|
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.12"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"tslib": "^2.3.0"
|