@almoamendev/ngx-md3 0.0.16 → 0.2.0
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.
|
@@ -10,6 +10,8 @@ import { ComponentPortal, CdkPortalOutlet } from '@angular/cdk/portal';
|
|
|
10
10
|
import * as i2 from '@angular/cdk/scrolling';
|
|
11
11
|
import { CdkScrollable } from '@angular/cdk/scrolling';
|
|
12
12
|
import { FormControlName } from '@angular/forms';
|
|
13
|
+
import { CdkDialogContainer, Dialog as Dialog$1 } from '@angular/cdk/dialog';
|
|
14
|
+
import { hasModifierKey } from '@angular/cdk/keycodes';
|
|
13
15
|
import { Overlay, OverlayConfig } from '@angular/cdk/overlay';
|
|
14
16
|
|
|
15
17
|
class TypeDisplay {
|
|
@@ -557,7 +559,7 @@ class SideSheet {
|
|
|
557
559
|
return this.portalOutlet.attachComponentPortal(portal);
|
|
558
560
|
}
|
|
559
561
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: SideSheet, deps: [{ token: LayoutService }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
560
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.0", type: SideSheet, isStandalone: true, selector: "md3-side-sheet", host: { properties: { "class.md3-active": "isActive()", "class.md3-hidden": "isHidden()", "class.md3-start": "side() === \"start\"", "class.md3-end": "side() === \"end\"", "class.md3-inset": "isInset()", "class.md3-show-divider": "showDivider()" } }, viewQueries: [{ propertyName: "portalOutlet", first: true, predicate: CdkPortalOutlet, descendants: true, static: true }], ngImport: i0, template: "<div class=\"md3-side-sheet-scrim\" (click)=\"close()\"></div>\n<div class=\"md3-side-sheet-container\">\n <ng-template cdkPortalOutlet></ng-template>\n</div>\n", styles: [":host{--background-color: rgb(var(--md-scheme-surface-container-low));--foreground-color: rgb(var(--md-scheme-on-surface));--border-radius: var(--md-border-radius-large);--elevation: var(--md-shadow-0dp);--hidden-offset: 80%;position:relative;height:100%;width:100%;min-height:0;pointer-events:none;z-index:1}:host .md3-side-sheet-scrim{position:fixed;inset:0;width:100vw;height:100vh;z-index:-1;pointer-events:none;display:none;background-color:rgb(var(--md-scheme-scrim));opacity:0;transition:all var(--md-motion-standard-default-spatial-duration) var(--md-motion-standard-default-spatial-easing)}:host .md3-side-sheet-container{flex:1 1 auto;position:relative;max-width:
|
|
562
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.0", type: SideSheet, isStandalone: true, selector: "md3-side-sheet", host: { properties: { "class.md3-active": "isActive()", "class.md3-hidden": "isHidden()", "class.md3-start": "side() === \"start\"", "class.md3-end": "side() === \"end\"", "class.md3-inset": "isInset()", "class.md3-show-divider": "showDivider()" } }, viewQueries: [{ propertyName: "portalOutlet", first: true, predicate: CdkPortalOutlet, descendants: true, static: true }], ngImport: i0, template: "<div class=\"md3-side-sheet-scrim\" (click)=\"close()\"></div>\n<div class=\"md3-side-sheet-container\">\n <ng-template cdkPortalOutlet></ng-template>\n</div>\n", styles: [":host{--background-color: rgb(var(--md-scheme-surface-container-low));--foreground-color: rgb(var(--md-scheme-on-surface));--border-radius: var(--md-border-radius-large);--elevation: var(--md-shadow-0dp);--hidden-offset: 80%;position:relative;height:100%;width:100%;min-height:0;pointer-events:none;z-index:1}:host .md3-side-sheet-scrim{position:fixed;inset:0;width:100vw;height:100vh;z-index:-1;pointer-events:none;display:none;background-color:rgb(var(--md-scheme-scrim));opacity:0;transition:all var(--md-motion-standard-default-spatial-duration) var(--md-motion-standard-default-spatial-easing)}:host .md3-side-sheet-container{flex:1 1 auto;position:relative;max-width:16em;min-width:16em;height:100%;overflow:hidden;pointer-events:all;background-color:var(--background-color);color:var(--foreground-color);box-shadow:var(--elevation);opacity:0;transform:translate(var(--hidden-offset));transition:all var(--md-motion-standard-default-spatial-duration) var(--md-motion-standard-default-spatial-easing)}:host .md3-side-sheet-container>::ng-deep *{display:grid;grid-template-areas:\"header\" \"body\" \"actions\";grid-template-rows:auto minmax(0,1fr) auto;height:100%;overflow:hidden}:host.md3-hidden .md3-side-sheet-container{pointer-events:none;opacity:0;transform:translate(var(--hidden-offset))}:host.md3-active .md3-side-sheet-container{pointer-events:all;opacity:1;transform:translate(0)}:host.md3-show-divider .md3-side-sheet-container:before{content:\"\";position:absolute;height:100%;width:.0625em;top:0;bottom:0;opacity:0;background-color:rgb(var(--md-scheme-outline));pointer-events:none}:host.md3-start{--hidden-offset: -80%}:host.md3-start.md3-style-modal{inset-inline-start:0}:host.md3-start .md3-side-sheet-container{border-start-end-radius:var(--border-radius);border-end-end-radius:var(--border-radius)}:host.md3-start.md3-show-divider .md3-side-sheet-container:before{inset-inline-end:0}:host.md3-end{--hidden-offset: 80%}:host.md3-end.md3-style-modal{inset-inline-end:0}:host.md3-end .md3-side-sheet-container{border-start-start-radius:var(--border-radius);border-end-start-radius:var(--border-radius)}:host.md3-end.md3-show-divider .md3-side-sheet-container:before{inset-inline-start:0}:host.md3-style-standard .md3-side-sheet-container{--background-color: rgb(var(--md-scheme-surface));--border-radius: var(--md-border-radius-none)}:host.md3-style-standard.md3-show-divider .md3-side-sheet-container:before{opacity:1}:host.md3-style-default.md3-inset{padding:1em}:host.md3-style-default.md3-inset .md3-side-sheet-container{border-radius:var(--border-radius)}:host.md3-style-modal{--elevation: var(--md-shadow-1dp);position:fixed;top:0;bottom:0;z-index:500}:host.md3-style-modal .md3-side-sheet-container{max-width:25em}:host.md3-style-modal .md3-side-sheet-scrim{display:block}:host.md3-style-modal.md3-active .md3-side-sheet-scrim{pointer-events:all;opacity:.32}:host.md3-style-modal.md3-inset{padding:1em}:host.md3-style-modal.md3-inset .md3-side-sheet-container{border-radius:var(--border-radius)}:host.md3-style-modal.md3-end .md3-side-sheet-container{margin-inline-start:auto}:host ::ng-deep md3-nav-group [md3-nav-item]{padding-inline:1.25em;margin-bottom:.5em}:host ::ng-deep md3-nav-group [md3-nav-item] .md3-item-container{padding:0 1em;flex-direction:row;align-items:center;justify-content:start;width:fit-content;height:3.5em}:host ::ng-deep md3-nav-group [md3-nav-item] .md3-item-container:before,:host ::ng-deep md3-nav-group [md3-nav-item] .md3-item-container:after{inset:0;height:auto;width:auto;border-radius:var(--md-border-radius-xlarge)}:host ::ng-deep md3-nav-group [md3-nav-item] .md3-item-container .md3-icon-container{padding:0}:host ::ng-deep md3-nav-group [md3-nav-item] .md3-item-container .md3-label{font-size:.875em;line-height:1.428571em;letter-spacing:.007143em;max-height:2.857143em;padding-inline:0}:host ::ng-deep md3-nav-group [md3-nav-item] .md3-item-container .md3-badge-container{position:relative;inset:auto}:host ::ng-deep md3-nav-group [md3-nav-item] .md3-item-container .md3-badge-container.md3-small{position:absolute;height:1.875em;width:1.625em}\n"], dependencies: [{ kind: "directive", type: CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }] });
|
|
561
563
|
}
|
|
562
564
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: SideSheet, decorators: [{
|
|
563
565
|
type: Component,
|
|
@@ -570,7 +572,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
570
572
|
'[class.md3-end]': 'side() === "end"',
|
|
571
573
|
'[class.md3-inset]': 'isInset()',
|
|
572
574
|
'[class.md3-show-divider]': 'showDivider()',
|
|
573
|
-
}, template: "<div class=\"md3-side-sheet-scrim\" (click)=\"close()\"></div>\n<div class=\"md3-side-sheet-container\">\n <ng-template cdkPortalOutlet></ng-template>\n</div>\n", styles: [":host{--background-color: rgb(var(--md-scheme-surface-container-low));--foreground-color: rgb(var(--md-scheme-on-surface));--border-radius: var(--md-border-radius-large);--elevation: var(--md-shadow-0dp);--hidden-offset: 80%;position:relative;height:100%;width:100%;min-height:0;pointer-events:none;z-index:1}:host .md3-side-sheet-scrim{position:fixed;inset:0;width:100vw;height:100vh;z-index:-1;pointer-events:none;display:none;background-color:rgb(var(--md-scheme-scrim));opacity:0;transition:all var(--md-motion-standard-default-spatial-duration) var(--md-motion-standard-default-spatial-easing)}:host .md3-side-sheet-container{flex:1 1 auto;position:relative;max-width:
|
|
575
|
+
}, template: "<div class=\"md3-side-sheet-scrim\" (click)=\"close()\"></div>\n<div class=\"md3-side-sheet-container\">\n <ng-template cdkPortalOutlet></ng-template>\n</div>\n", styles: [":host{--background-color: rgb(var(--md-scheme-surface-container-low));--foreground-color: rgb(var(--md-scheme-on-surface));--border-radius: var(--md-border-radius-large);--elevation: var(--md-shadow-0dp);--hidden-offset: 80%;position:relative;height:100%;width:100%;min-height:0;pointer-events:none;z-index:1}:host .md3-side-sheet-scrim{position:fixed;inset:0;width:100vw;height:100vh;z-index:-1;pointer-events:none;display:none;background-color:rgb(var(--md-scheme-scrim));opacity:0;transition:all var(--md-motion-standard-default-spatial-duration) var(--md-motion-standard-default-spatial-easing)}:host .md3-side-sheet-container{flex:1 1 auto;position:relative;max-width:16em;min-width:16em;height:100%;overflow:hidden;pointer-events:all;background-color:var(--background-color);color:var(--foreground-color);box-shadow:var(--elevation);opacity:0;transform:translate(var(--hidden-offset));transition:all var(--md-motion-standard-default-spatial-duration) var(--md-motion-standard-default-spatial-easing)}:host .md3-side-sheet-container>::ng-deep *{display:grid;grid-template-areas:\"header\" \"body\" \"actions\";grid-template-rows:auto minmax(0,1fr) auto;height:100%;overflow:hidden}:host.md3-hidden .md3-side-sheet-container{pointer-events:none;opacity:0;transform:translate(var(--hidden-offset))}:host.md3-active .md3-side-sheet-container{pointer-events:all;opacity:1;transform:translate(0)}:host.md3-show-divider .md3-side-sheet-container:before{content:\"\";position:absolute;height:100%;width:.0625em;top:0;bottom:0;opacity:0;background-color:rgb(var(--md-scheme-outline));pointer-events:none}:host.md3-start{--hidden-offset: -80%}:host.md3-start.md3-style-modal{inset-inline-start:0}:host.md3-start .md3-side-sheet-container{border-start-end-radius:var(--border-radius);border-end-end-radius:var(--border-radius)}:host.md3-start.md3-show-divider .md3-side-sheet-container:before{inset-inline-end:0}:host.md3-end{--hidden-offset: 80%}:host.md3-end.md3-style-modal{inset-inline-end:0}:host.md3-end .md3-side-sheet-container{border-start-start-radius:var(--border-radius);border-end-start-radius:var(--border-radius)}:host.md3-end.md3-show-divider .md3-side-sheet-container:before{inset-inline-start:0}:host.md3-style-standard .md3-side-sheet-container{--background-color: rgb(var(--md-scheme-surface));--border-radius: var(--md-border-radius-none)}:host.md3-style-standard.md3-show-divider .md3-side-sheet-container:before{opacity:1}:host.md3-style-default.md3-inset{padding:1em}:host.md3-style-default.md3-inset .md3-side-sheet-container{border-radius:var(--border-radius)}:host.md3-style-modal{--elevation: var(--md-shadow-1dp);position:fixed;top:0;bottom:0;z-index:500}:host.md3-style-modal .md3-side-sheet-container{max-width:25em}:host.md3-style-modal .md3-side-sheet-scrim{display:block}:host.md3-style-modal.md3-active .md3-side-sheet-scrim{pointer-events:all;opacity:.32}:host.md3-style-modal.md3-inset{padding:1em}:host.md3-style-modal.md3-inset .md3-side-sheet-container{border-radius:var(--border-radius)}:host.md3-style-modal.md3-end .md3-side-sheet-container{margin-inline-start:auto}:host ::ng-deep md3-nav-group [md3-nav-item]{padding-inline:1.25em;margin-bottom:.5em}:host ::ng-deep md3-nav-group [md3-nav-item] .md3-item-container{padding:0 1em;flex-direction:row;align-items:center;justify-content:start;width:fit-content;height:3.5em}:host ::ng-deep md3-nav-group [md3-nav-item] .md3-item-container:before,:host ::ng-deep md3-nav-group [md3-nav-item] .md3-item-container:after{inset:0;height:auto;width:auto;border-radius:var(--md-border-radius-xlarge)}:host ::ng-deep md3-nav-group [md3-nav-item] .md3-item-container .md3-icon-container{padding:0}:host ::ng-deep md3-nav-group [md3-nav-item] .md3-item-container .md3-label{font-size:.875em;line-height:1.428571em;letter-spacing:.007143em;max-height:2.857143em;padding-inline:0}:host ::ng-deep md3-nav-group [md3-nav-item] .md3-item-container .md3-badge-container{position:relative;inset:auto}:host ::ng-deep md3-nav-group [md3-nav-item] .md3-item-container .md3-badge-container.md3-small{position:absolute;height:1.875em;width:1.625em}\n"] }]
|
|
574
576
|
}], ctorParameters: () => [{ type: LayoutService }, { type: i0.ElementRef }], propDecorators: { portalOutlet: [{
|
|
575
577
|
type: ViewChild,
|
|
576
578
|
args: [CdkPortalOutlet, { static: true }]
|
|
@@ -603,37 +605,45 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
603
605
|
|
|
604
606
|
class SheetsService {
|
|
605
607
|
injector = inject(Injector);
|
|
608
|
+
/**
|
|
609
|
+
* Outlets registered per side, from the page scaffold up to whatever took
|
|
610
|
+
* them over last. Sheets always open in the outlet on top, so a full screen
|
|
611
|
+
* dialog can host them while it is up and hand them back when it closes.
|
|
612
|
+
*/
|
|
606
613
|
states = new Map();
|
|
607
614
|
registerSideSheetOutlet(side, outlet) {
|
|
608
|
-
const
|
|
609
|
-
if (
|
|
615
|
+
const stack = this.getOutletStack(side);
|
|
616
|
+
if (stack.some((state) => state.outlet === outlet)) {
|
|
610
617
|
return;
|
|
611
618
|
}
|
|
612
|
-
if (currentState) {
|
|
613
|
-
this.disposeOutletState(currentState);
|
|
614
|
-
}
|
|
615
619
|
if (outlet.hasAttached()) {
|
|
616
620
|
outlet.detach();
|
|
617
621
|
}
|
|
618
622
|
const stackPortal = new ComponentPortal(SideSheetStack, null, this.injector);
|
|
619
623
|
const stackComponentRef = outlet.attachComponentPortal(stackPortal);
|
|
620
|
-
|
|
624
|
+
stack.push({
|
|
621
625
|
outlet,
|
|
622
626
|
stackComponentRef,
|
|
623
627
|
refs: [],
|
|
624
628
|
});
|
|
625
629
|
}
|
|
626
630
|
unregisterSideSheetOutlet(side, outlet) {
|
|
627
|
-
const
|
|
628
|
-
|
|
631
|
+
const stack = this.states.get(side);
|
|
632
|
+
const index = stack?.findIndex((state) => state.outlet === outlet) ?? -1;
|
|
633
|
+
if (!stack || index === -1) {
|
|
629
634
|
return;
|
|
630
635
|
}
|
|
631
|
-
this
|
|
632
|
-
|
|
636
|
+
// Sheets opened in this outlet go with it, and the outlet underneath
|
|
637
|
+
// becomes the one new sheets open in.
|
|
638
|
+
this.disposeOutletState(stack[index]);
|
|
639
|
+
stack.splice(index, 1);
|
|
640
|
+
if (stack.length === 0) {
|
|
641
|
+
this.states.delete(side);
|
|
642
|
+
}
|
|
633
643
|
}
|
|
634
644
|
openSideSheet(component, config = {}) {
|
|
635
645
|
const sheetConfig = this.mergeConfig(config);
|
|
636
|
-
const state = this.
|
|
646
|
+
const state = this.activeState(sheetConfig.side);
|
|
637
647
|
if (!state) {
|
|
638
648
|
throw new Error(`No ${sheetConfig.side} side sheet outlet is registered.`);
|
|
639
649
|
}
|
|
@@ -653,7 +663,19 @@ class SheetsService {
|
|
|
653
663
|
return sheetRef;
|
|
654
664
|
}
|
|
655
665
|
closeSideSheet(side = 'end', result) {
|
|
656
|
-
this.getVisibleRef(this.
|
|
666
|
+
this.getVisibleRef(this.activeState(side))?.close(result);
|
|
667
|
+
}
|
|
668
|
+
/** Outlet that sheets currently open in: the last one that registered. */
|
|
669
|
+
activeState(side) {
|
|
670
|
+
const stack = this.states.get(side);
|
|
671
|
+
return stack?.[stack.length - 1];
|
|
672
|
+
}
|
|
673
|
+
getOutletStack(side) {
|
|
674
|
+
const stack = this.states.get(side) ?? [];
|
|
675
|
+
if (!this.states.has(side)) {
|
|
676
|
+
this.states.set(side, stack);
|
|
677
|
+
}
|
|
678
|
+
return stack;
|
|
657
679
|
}
|
|
658
680
|
mergeConfig(config) {
|
|
659
681
|
return {
|
|
@@ -3087,42 +3109,144 @@ const DIALOG_DATA = new InjectionToken('MD3_DIALOG_DATA');
|
|
|
3087
3109
|
const DIALOG_CONFIG = new InjectionToken('MD3_DIALOG_CONFIG');
|
|
3088
3110
|
const DIALOG_COMPONENT = new InjectionToken('MD3_DIALOG_COMPONENT');
|
|
3089
3111
|
const DIALOG_EXIT_ANIMATION_FALLBACK_MS = 300;
|
|
3112
|
+
const HIDDEN_CLASS = 'md3-dialog-hidden';
|
|
3090
3113
|
class DialogRef {
|
|
3091
|
-
|
|
3092
|
-
|
|
3114
|
+
cdkRef;
|
|
3115
|
+
isFullScreen;
|
|
3093
3116
|
closed = new Subject();
|
|
3094
|
-
|
|
3117
|
+
closing = new Subject();
|
|
3118
|
+
closePromise = null;
|
|
3119
|
+
closeStarted = false;
|
|
3120
|
+
closeSettled = false;
|
|
3121
|
+
hidden = false;
|
|
3122
|
+
/** Shell hosting the dialog: the regular dialog or the full screen one. */
|
|
3095
3123
|
dialogInstance;
|
|
3096
3124
|
/**
|
|
3097
3125
|
* Filled by DialogService after the user component is attached. Keeping the
|
|
3098
3126
|
* instance here lets callers imperatively update inputs when that is useful.
|
|
3099
3127
|
*/
|
|
3100
3128
|
componentInstance;
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
this.
|
|
3104
|
-
}
|
|
3129
|
+
/** Overlay hosting the dialog, useful to reach the panel and the scrim. */
|
|
3130
|
+
get overlayRef() {
|
|
3131
|
+
return this.cdkRef.overlayRef;
|
|
3132
|
+
}
|
|
3133
|
+
/** Whether the dialog started closing. Such a dialog cannot be hidden or shown anymore. */
|
|
3134
|
+
get isClosing() {
|
|
3135
|
+
return this.closeStarted;
|
|
3136
|
+
}
|
|
3137
|
+
/** Whether the dialog is currently hidden behind another dialog. */
|
|
3138
|
+
get isHidden() {
|
|
3139
|
+
return this.hidden;
|
|
3140
|
+
}
|
|
3141
|
+
constructor(cdkRef, disableCloseEvents,
|
|
3142
|
+
/** Whether this reference belongs to a full screen dialog. */
|
|
3143
|
+
isFullScreen = false) {
|
|
3144
|
+
this.cdkRef = cdkRef;
|
|
3145
|
+
this.isFullScreen = isFullScreen;
|
|
3146
|
+
// Closing always goes through this reference so the exit animation can
|
|
3147
|
+
// run before the CDK disposes the overlay. Detachments triggered from
|
|
3148
|
+
// the outside (navigation, scroll strategy) still settle this ref.
|
|
3149
|
+
this.cdkRef.closed.pipe(take(1)).subscribe((result) => this.settle(result));
|
|
3150
|
+
if (!disableCloseEvents) {
|
|
3151
|
+
this.connectCloseEvents();
|
|
3152
|
+
}
|
|
3153
|
+
}
|
|
3154
|
+
/** Closes the dialog. The promise resolves once the exit animation is done. */
|
|
3105
3155
|
close(result) {
|
|
3106
|
-
if (this.
|
|
3156
|
+
if (this.closePromise) {
|
|
3157
|
+
return this.closePromise;
|
|
3158
|
+
}
|
|
3159
|
+
this.startClosing();
|
|
3160
|
+
this.closePromise = this.startCloseAnimation().then(() => this.cdkRef.close(result));
|
|
3161
|
+
return this.closePromise;
|
|
3162
|
+
}
|
|
3163
|
+
/**
|
|
3164
|
+
* Hides the dialog with the closing animation while keeping it alive, so
|
|
3165
|
+
* its content, form state and subscriptions survive until show() is called.
|
|
3166
|
+
* The promise resolves once the dialog is out of sight.
|
|
3167
|
+
*/
|
|
3168
|
+
hide() {
|
|
3169
|
+
if (this.hidden || this.closeStarted) {
|
|
3170
|
+
return Promise.resolve();
|
|
3171
|
+
}
|
|
3172
|
+
this.hidden = true;
|
|
3173
|
+
this.toggleHiddenState(true);
|
|
3174
|
+
this.dialogInstance?.setActive(false);
|
|
3175
|
+
return this.waitForSurfaceAnimation();
|
|
3176
|
+
}
|
|
3177
|
+
/**
|
|
3178
|
+
* Brings a hidden dialog back with the opening animation. Focus moves back
|
|
3179
|
+
* into the dialog even when it was never hidden, which is what makes it
|
|
3180
|
+
* usable again once the dialog above it closes.
|
|
3181
|
+
*/
|
|
3182
|
+
show() {
|
|
3183
|
+
if (this.closeStarted) {
|
|
3107
3184
|
return;
|
|
3108
3185
|
}
|
|
3109
|
-
this.
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3186
|
+
if (this.hidden) {
|
|
3187
|
+
this.hidden = false;
|
|
3188
|
+
this.toggleHiddenState(false);
|
|
3189
|
+
this.dialogInstance?.setActive(true);
|
|
3190
|
+
}
|
|
3191
|
+
this.dialogInstance?.recaptureFocus();
|
|
3192
|
+
}
|
|
3193
|
+
/** Emits when the dialog starts closing, before the exit animation runs. */
|
|
3194
|
+
beforeClosed() {
|
|
3195
|
+
return this.closing.asObservable();
|
|
3196
|
+
}
|
|
3197
|
+
afterClosed() {
|
|
3198
|
+
return this.closed.asObservable();
|
|
3199
|
+
}
|
|
3200
|
+
connectCloseEvents() {
|
|
3201
|
+
// The CDK config keeps `disableClose` on, so the scrim and Escape key
|
|
3202
|
+
// are handled here instead and the dialog can animate out.
|
|
3203
|
+
this.cdkRef.backdropClick.pipe(take(1)).subscribe(() => {
|
|
3204
|
+
this.cdkRef.containerInstance._closeInteractionType = 'mouse';
|
|
3205
|
+
this.close();
|
|
3206
|
+
});
|
|
3207
|
+
this.cdkRef.keydownEvents.pipe(filter((event) => event.key === 'Escape' && !hasModifierKey(event)), take(1)).subscribe((event) => {
|
|
3208
|
+
event.preventDefault();
|
|
3209
|
+
this.cdkRef.containerInstance._closeInteractionType = 'keyboard';
|
|
3210
|
+
this.close();
|
|
3117
3211
|
});
|
|
3118
3212
|
}
|
|
3213
|
+
toggleHiddenState(isHidden) {
|
|
3214
|
+
const overlayRef = this.cdkRef.overlayRef;
|
|
3215
|
+
const panel = overlayRef.overlayElement;
|
|
3216
|
+
const backdrop = overlayRef.backdropElement;
|
|
3217
|
+
panel.classList.toggle(HIDDEN_CLASS, isHidden);
|
|
3218
|
+
backdrop?.classList.toggle(HIDDEN_CLASS, isHidden);
|
|
3219
|
+
// `inert` keeps a hidden dialog out of the tab order and away from
|
|
3220
|
+
// assistive technology without removing it from the DOM.
|
|
3221
|
+
if (isHidden) {
|
|
3222
|
+
panel.setAttribute('inert', '');
|
|
3223
|
+
}
|
|
3224
|
+
else {
|
|
3225
|
+
panel.removeAttribute('inert');
|
|
3226
|
+
}
|
|
3227
|
+
}
|
|
3228
|
+
startClosing() {
|
|
3229
|
+
if (this.closeStarted) {
|
|
3230
|
+
return;
|
|
3231
|
+
}
|
|
3232
|
+
this.closeStarted = true;
|
|
3233
|
+
this.closing.next();
|
|
3234
|
+
this.closing.complete();
|
|
3235
|
+
}
|
|
3119
3236
|
startCloseAnimation() {
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3237
|
+
const overlayRef = this.cdkRef.overlayRef;
|
|
3238
|
+
const wasVisible = !this.hidden;
|
|
3239
|
+
overlayRef.overlayElement.classList.add('md3-dialog-closing');
|
|
3240
|
+
overlayRef.backdropElement?.classList.add('md3-dialog-closing');
|
|
3241
|
+
this.dialogInstance?.setActive(false);
|
|
3242
|
+
// A hidden dialog already played the exit animation, so there is
|
|
3243
|
+
// nothing left to transition and it can be disposed right away.
|
|
3244
|
+
return wasVisible ? this.waitForSurfaceAnimation() : Promise.resolve();
|
|
3245
|
+
}
|
|
3246
|
+
/** Resolves when the surface finished animating, with a timeout as a safety net. */
|
|
3247
|
+
waitForSurfaceAnimation() {
|
|
3248
|
+
const panel = this.cdkRef.overlayRef.overlayElement;
|
|
3249
|
+
const surface = this.dialogInstance?.surfaceElement ?? panel;
|
|
3126
3250
|
return new Promise((resolve) => {
|
|
3127
3251
|
let isResolved = false;
|
|
3128
3252
|
let timeoutId = setTimeout(done, DIALOG_EXIT_ANIMATION_FALLBACK_MS);
|
|
@@ -3132,82 +3256,327 @@ class DialogRef {
|
|
|
3132
3256
|
}
|
|
3133
3257
|
isResolved = true;
|
|
3134
3258
|
clearTimeout(timeoutId);
|
|
3135
|
-
|
|
3259
|
+
surface.removeEventListener('transitionend', onTransitionEnd);
|
|
3136
3260
|
resolve();
|
|
3137
3261
|
}
|
|
3138
3262
|
function onTransitionEnd(event) {
|
|
3139
|
-
if (event.target ===
|
|
3263
|
+
if (event.target === surface) {
|
|
3140
3264
|
done();
|
|
3141
3265
|
}
|
|
3142
3266
|
}
|
|
3143
|
-
|
|
3267
|
+
surface.addEventListener('transitionend', onTransitionEnd);
|
|
3144
3268
|
});
|
|
3145
3269
|
}
|
|
3146
|
-
|
|
3147
|
-
|
|
3270
|
+
/** Emits the result once the CDK reference is closed. Focus is restored by the container. */
|
|
3271
|
+
settle(result) {
|
|
3272
|
+
if (this.closeSettled) {
|
|
3273
|
+
return;
|
|
3274
|
+
}
|
|
3275
|
+
// Covers detachments that did not go through close(), so anything
|
|
3276
|
+
// waiting on beforeClosed() is still notified.
|
|
3277
|
+
this.startClosing();
|
|
3278
|
+
this.closeSettled = true;
|
|
3279
|
+
this.closed.next(result);
|
|
3280
|
+
this.closed.complete();
|
|
3148
3281
|
}
|
|
3149
3282
|
}
|
|
3150
3283
|
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3284
|
+
/**
|
|
3285
|
+
* Material 3 dialog shell. It extends the CDK dialog container, so focus
|
|
3286
|
+
* trapping, focus restoration and the ARIA attributes are handled by the CDK
|
|
3287
|
+
* while this component only owns the MD3 surface and its animation.
|
|
3288
|
+
*/
|
|
3289
|
+
class Dialog extends CdkDialogContainer {
|
|
3290
|
+
surface = viewChild('surface', /* @ts-ignore */
|
|
3291
|
+
...(ngDevMode ? [{ debugName: "surface" }] : /* istanbul ignore next */ []));
|
|
3154
3292
|
isActive = signal(false, /* @ts-ignore */
|
|
3155
3293
|
...(ngDevMode ? [{ debugName: "isActive" }] : /* istanbul ignore next */ []));
|
|
3156
3294
|
config = inject(DIALOG_CONFIG, { optional: true }) ?? {};
|
|
3157
|
-
get
|
|
3158
|
-
return this.
|
|
3295
|
+
get surfaceElement() {
|
|
3296
|
+
return this.surface()?.nativeElement ?? null;
|
|
3159
3297
|
}
|
|
3160
|
-
|
|
3298
|
+
/**
|
|
3299
|
+
* Started by DialogService, either right after the dialog is created or
|
|
3300
|
+
* once the dialog it replaces has had its head start. The animation runs on
|
|
3301
|
+
* the next frame so the surface has a real from/to state.
|
|
3302
|
+
*/
|
|
3303
|
+
startEnterAnimation() {
|
|
3161
3304
|
requestAnimationFrame(() => {
|
|
3162
3305
|
this.isActive.set(true);
|
|
3163
3306
|
});
|
|
3164
3307
|
}
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
const portal = new ComponentPortal(component, null, injector);
|
|
3171
|
-
return this.portalOutlet().attachComponentPortal(portal);
|
|
3308
|
+
setActive(value) {
|
|
3309
|
+
this.isActive.set(value);
|
|
3310
|
+
}
|
|
3311
|
+
recaptureFocus() {
|
|
3312
|
+
this._recaptureFocus();
|
|
3172
3313
|
}
|
|
3173
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: Dialog, deps:
|
|
3174
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.0", type: Dialog, isStandalone: true, selector: "md3-dialog", viewQueries: [{ propertyName: "
|
|
3314
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: Dialog, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
3315
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.0", type: Dialog, isStandalone: true, selector: "md3-dialog", viewQueries: [{ propertyName: "surface", first: true, predicate: ["surface"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<!-- The role and aria attributes live on the host element, applied by the CDK dialog container. -->\n<section\n #surface\n class=\"md3-dialog-container\"\n [class.md3-active]=\"isActive()\"\n [class.md-scheme-dark]=\"config.scheme == 'dark'\"\n [class.md-scheme-light]=\"config.scheme == 'light'\"\n [attr.dir]=\"config.direction ?? null\">\n <ng-template cdkPortalOutlet></ng-template>\n</section>\n", styles: ["::ng-deep .cdk-overlay-container{position:fixed;z-index:1000;inset:0;pointer-events:none;font-size:1rem}::ng-deep .cdk-overlay-container .md3-dialog-scrim{position:absolute;inset:0;pointer-events:auto;background-color:rgb(var(--md-scheme-scrim));transition:all var(--md-motion-expressive-slow-spatial-duration) var(--md-motion-expressive-slow-spatial-easing);opacity:.32}::ng-deep .cdk-overlay-container .md3-dialog-scrim.md3-dialog-opening{opacity:0}::ng-deep .cdk-overlay-container .md3-dialog-scrim.md3-dialog-closing{opacity:0}::ng-deep .cdk-overlay-container .md3-dialog-scrim.md3-dialog-hidden{opacity:0}::ng-deep .cdk-overlay-container .md3-dialog-scrim.md3-dialog-scrim-kept{opacity:.32;transition:none}::ng-deep .cdk-overlay-container .md3-dialog-scrim.md3-dialog-scrim-instant{transition:none}::ng-deep .cdk-overlay-container .cdk-global-overlay-wrapper{position:absolute;display:flex;inset:0;pointer-events:none;padding:3.5rem 1.5rem;overflow:hidden}::ng-deep .cdk-overlay-container .cdk-global-overlay-wrapper .md3-dialog-panel{position:absolute;pointer-events:auto;max-width:35em}::ng-deep .cdk-overlay-container .cdk-global-overlay-wrapper .md3-dialog-panel.md3-dialog-closing,::ng-deep .cdk-overlay-container .cdk-global-overlay-wrapper .md3-dialog-panel.md3-dialog-hidden{pointer-events:none}:host{display:block;max-width:100%;min-width:17.5em;outline:0}:host .md3-dialog-container{display:block;width:100%;max-height:inherit;overflow:auto;color:rgb(var(--md-scheme-on-surface));background-color:rgb(var(--md-scheme-surface-container-high));border-radius:var(--md-border-radius-xlarge);box-shadow:var(--md-shadow-6dp);transform-origin:center;transition:all var(--md-motion-expressive-default-spatial-duration) var(--md-motion-expressive-default-spatial-easing);opacity:0;transform:scaleY(.8);margin-top:-8rem}:host .md3-dialog-container.md3-active{opacity:1;transform:scaleY(1);margin-top:0}\n"], dependencies: [{ kind: "directive", type: CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }] });
|
|
3175
3316
|
}
|
|
3176
3317
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: Dialog, decorators: [{
|
|
3177
3318
|
type: Component,
|
|
3178
3319
|
args: [{ selector: 'md3-dialog', imports: [
|
|
3179
3320
|
CdkPortalOutlet,
|
|
3180
|
-
], template: "<section\n class=\"md3-dialog-container\"\n [class.md3-active]=\"isActive()\"\n [class.md-scheme-dark]=\"config.scheme == 'dark'\"\n [class.md-scheme-light]=\"config.scheme == 'light'\"\n [attr.dir]=\"config.direction ?? null\"
|
|
3181
|
-
}], propDecorators: {
|
|
3321
|
+
], template: "<!-- The role and aria attributes live on the host element, applied by the CDK dialog container. -->\n<section\n #surface\n class=\"md3-dialog-container\"\n [class.md3-active]=\"isActive()\"\n [class.md-scheme-dark]=\"config.scheme == 'dark'\"\n [class.md-scheme-light]=\"config.scheme == 'light'\"\n [attr.dir]=\"config.direction ?? null\">\n <ng-template cdkPortalOutlet></ng-template>\n</section>\n", styles: ["::ng-deep .cdk-overlay-container{position:fixed;z-index:1000;inset:0;pointer-events:none;font-size:1rem}::ng-deep .cdk-overlay-container .md3-dialog-scrim{position:absolute;inset:0;pointer-events:auto;background-color:rgb(var(--md-scheme-scrim));transition:all var(--md-motion-expressive-slow-spatial-duration) var(--md-motion-expressive-slow-spatial-easing);opacity:.32}::ng-deep .cdk-overlay-container .md3-dialog-scrim.md3-dialog-opening{opacity:0}::ng-deep .cdk-overlay-container .md3-dialog-scrim.md3-dialog-closing{opacity:0}::ng-deep .cdk-overlay-container .md3-dialog-scrim.md3-dialog-hidden{opacity:0}::ng-deep .cdk-overlay-container .md3-dialog-scrim.md3-dialog-scrim-kept{opacity:.32;transition:none}::ng-deep .cdk-overlay-container .md3-dialog-scrim.md3-dialog-scrim-instant{transition:none}::ng-deep .cdk-overlay-container .cdk-global-overlay-wrapper{position:absolute;display:flex;inset:0;pointer-events:none;padding:3.5rem 1.5rem;overflow:hidden}::ng-deep .cdk-overlay-container .cdk-global-overlay-wrapper .md3-dialog-panel{position:absolute;pointer-events:auto;max-width:35em}::ng-deep .cdk-overlay-container .cdk-global-overlay-wrapper .md3-dialog-panel.md3-dialog-closing,::ng-deep .cdk-overlay-container .cdk-global-overlay-wrapper .md3-dialog-panel.md3-dialog-hidden{pointer-events:none}:host{display:block;max-width:100%;min-width:17.5em;outline:0}:host .md3-dialog-container{display:block;width:100%;max-height:inherit;overflow:auto;color:rgb(var(--md-scheme-on-surface));background-color:rgb(var(--md-scheme-surface-container-high));border-radius:var(--md-border-radius-xlarge);box-shadow:var(--md-shadow-6dp);transform-origin:center;transition:all var(--md-motion-expressive-default-spatial-duration) var(--md-motion-expressive-default-spatial-easing);opacity:0;transform:scaleY(.8);margin-top:-8rem}:host .md3-dialog-container.md3-active{opacity:1;transform:scaleY(1);margin-top:0}\n"] }]
|
|
3322
|
+
}], propDecorators: { surface: [{ type: i0.ViewChild, args: ['surface', { isSignal: true }] }] } });
|
|
3323
|
+
|
|
3324
|
+
/**
|
|
3325
|
+
* Material 3 full screen dialog shell. It covers the viewport and lays its
|
|
3326
|
+
* content out like the scaffold does, with a main pane and a side sheet outlet
|
|
3327
|
+
* on each side, so side sheets opened while it is up land inside the dialog
|
|
3328
|
+
* instead of behind it.
|
|
3329
|
+
*/
|
|
3330
|
+
class FullScreenDialog extends CdkDialogContainer {
|
|
3331
|
+
surface = viewChild('surface', /* @ts-ignore */
|
|
3332
|
+
...(ngDevMode ? [{ debugName: "surface" }] : /* istanbul ignore next */ []));
|
|
3333
|
+
startOutlet = viewChild('startOutlet', { ...(ngDevMode ? { debugName: "startOutlet" } : /* istanbul ignore next */ {}), read: CdkPortalOutlet });
|
|
3334
|
+
endOutlet = viewChild('endOutlet', { ...(ngDevMode ? { debugName: "endOutlet" } : /* istanbul ignore next */ {}), read: CdkPortalOutlet });
|
|
3335
|
+
sheets = inject(SheetsService);
|
|
3336
|
+
isActive = signal(false, /* @ts-ignore */
|
|
3337
|
+
...(ngDevMode ? [{ debugName: "isActive" }] : /* istanbul ignore next */ []));
|
|
3338
|
+
config = inject(DIALOG_CONFIG, { optional: true }) ?? {};
|
|
3339
|
+
get surfaceElement() {
|
|
3340
|
+
return this.surface()?.nativeElement ?? null;
|
|
3341
|
+
}
|
|
3342
|
+
ngAfterViewInit() {
|
|
3343
|
+
const startOutlet = this.startOutlet();
|
|
3344
|
+
const endOutlet = this.endOutlet();
|
|
3345
|
+
// Taking the outlets over is what sends the next side sheet inside the
|
|
3346
|
+
// dialog. The scaffold gets them back when this dialog is destroyed.
|
|
3347
|
+
if (startOutlet) {
|
|
3348
|
+
this.sheets.registerSideSheetOutlet('start', startOutlet);
|
|
3349
|
+
}
|
|
3350
|
+
if (endOutlet) {
|
|
3351
|
+
this.sheets.registerSideSheetOutlet('end', endOutlet);
|
|
3352
|
+
}
|
|
3353
|
+
}
|
|
3354
|
+
ngOnDestroy() {
|
|
3355
|
+
const startOutlet = this.startOutlet();
|
|
3356
|
+
const endOutlet = this.endOutlet();
|
|
3357
|
+
if (startOutlet) {
|
|
3358
|
+
this.sheets.unregisterSideSheetOutlet('start', startOutlet);
|
|
3359
|
+
}
|
|
3360
|
+
if (endOutlet) {
|
|
3361
|
+
this.sheets.unregisterSideSheetOutlet('end', endOutlet);
|
|
3362
|
+
}
|
|
3363
|
+
super.ngOnDestroy();
|
|
3364
|
+
}
|
|
3365
|
+
startEnterAnimation() {
|
|
3366
|
+
requestAnimationFrame(() => {
|
|
3367
|
+
this.isActive.set(true);
|
|
3368
|
+
});
|
|
3369
|
+
}
|
|
3370
|
+
setActive(value) {
|
|
3371
|
+
this.isActive.set(value);
|
|
3372
|
+
}
|
|
3373
|
+
recaptureFocus() {
|
|
3374
|
+
this._recaptureFocus();
|
|
3375
|
+
}
|
|
3376
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: FullScreenDialog, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
3377
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.0", type: FullScreenDialog, isStandalone: true, selector: "md3-fullscreen-dialog", viewQueries: [{ propertyName: "surface", first: true, predicate: ["surface"], descendants: true, isSignal: true }, { propertyName: "startOutlet", first: true, predicate: ["startOutlet"], descendants: true, read: CdkPortalOutlet, isSignal: true }, { propertyName: "endOutlet", first: true, predicate: ["endOutlet"], descendants: true, read: CdkPortalOutlet, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<!-- The role and aria attributes live on the host element, applied by the CDK dialog container. -->\n<section\n #surface\n class=\"md3-fullscreen-dialog-container\"\n [class.md3-active]=\"isActive()\"\n [class.md-scheme-dark]=\"config.scheme == 'dark'\"\n [class.md-scheme-light]=\"config.scheme == 'light'\"\n [attr.dir]=\"config.direction ?? null\">\n <div class=\"md3-panes-container md3-scrollable\">\n <!--\n The CDK attaches the dialog content to the first portal outlet of\n this template, so the main pane has to come first. The panes are\n placed by grid area, which makes the DOM order irrelevant visually.\n -->\n <div class=\"md3-pane md3-pane-main\">\n <ng-template cdkPortalOutlet></ng-template>\n </div>\n <div class=\"md3-pane md3-pane-start\">\n <ng-template #startOutlet cdkPortalOutlet></ng-template>\n </div>\n <div class=\"md3-pane md3-pane-end\">\n <ng-template #endOutlet cdkPortalOutlet></ng-template>\n </div>\n </div>\n</section>\n", styles: ["::ng-deep .cdk-overlay-container{position:fixed;z-index:1000;inset:0;pointer-events:none;font-size:1rem}::ng-deep .cdk-overlay-container .cdk-global-overlay-wrapper{position:absolute;display:flex;inset:0;pointer-events:none;overflow:hidden}::ng-deep .cdk-overlay-container .cdk-global-overlay-wrapper:has(>.md3-fullscreen-dialog-panel){padding:0}::ng-deep .cdk-overlay-container .cdk-global-overlay-wrapper .md3-fullscreen-dialog-panel{width:100%;height:100%;max-width:none;pointer-events:auto}::ng-deep .cdk-overlay-container .cdk-global-overlay-wrapper .md3-fullscreen-dialog-panel.md3-dialog-closing,::ng-deep .cdk-overlay-container .cdk-global-overlay-wrapper .md3-fullscreen-dialog-panel.md3-dialog-hidden{pointer-events:none}:host{display:block;height:100%;width:100%;outline:0}:host .md3-fullscreen-dialog-container{display:grid;grid-template-rows:minmax(0,1fr);height:100%;min-height:0;overflow:hidden;color:rgb(var(--md-scheme-on-surface));background-color:rgb(var(--md-scheme-surface));transition:all var(--md-motion-expressive-default-spatial-duration) var(--md-motion-expressive-default-spatial-easing);opacity:0;transform:translateY(1.5em)}:host .md3-fullscreen-dialog-container.md3-active{opacity:1;transform:none}:host .md3-panes-container{display:grid;grid-template-areas:\"start main end\";grid-template-columns:auto minmax(0,1fr) auto;grid-template-rows:minmax(0,1fr);min-width:0;min-height:0;overflow:hidden}:host .md3-panes-container .md3-pane{justify-self:stretch;align-self:stretch;min-width:0;min-height:0;height:100%;overflow:hidden}:host .md3-panes-container .md3-pane.md3-pane-start{grid-area:start}:host .md3-panes-container .md3-pane.md3-pane-main{position:relative;grid-area:main;z-index:1;display:grid;grid-template-rows:minmax(0,1fr)}:host .md3-panes-container .md3-pane.md3-pane-main>::ng-deep *{display:grid;grid-template-areas:\"header\" \"body\";grid-template-rows:auto minmax(0,1fr) auto;min-height:0;height:100%;overflow-x:hidden;overflow-y:auto;scrollbar-width:thin;scrollbar-color:rgb(var(--md-scheme-outline-variant)) transparent}:host .md3-panes-container .md3-pane.md3-pane-main>::ng-deep *::-webkit-scrollbar{width:.5rem;height:.5rem}:host .md3-panes-container .md3-pane.md3-pane-main>::ng-deep *::-webkit-scrollbar-track{background:transparent}:host .md3-panes-container .md3-pane.md3-pane-main>::ng-deep *>md3-dialog-body{grid-area:body;margin:0;padding:1em 1.5em;overflow-y:visible;height:auto}:host .md3-panes-container .md3-pane.md3-pane-end{grid-area:end}\n"], dependencies: [{ kind: "directive", type: CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }] });
|
|
3378
|
+
}
|
|
3379
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: FullScreenDialog, decorators: [{
|
|
3380
|
+
type: Component,
|
|
3381
|
+
args: [{ selector: 'md3-fullscreen-dialog', imports: [
|
|
3382
|
+
CdkPortalOutlet,
|
|
3383
|
+
], template: "<!-- The role and aria attributes live on the host element, applied by the CDK dialog container. -->\n<section\n #surface\n class=\"md3-fullscreen-dialog-container\"\n [class.md3-active]=\"isActive()\"\n [class.md-scheme-dark]=\"config.scheme == 'dark'\"\n [class.md-scheme-light]=\"config.scheme == 'light'\"\n [attr.dir]=\"config.direction ?? null\">\n <div class=\"md3-panes-container md3-scrollable\">\n <!--\n The CDK attaches the dialog content to the first portal outlet of\n this template, so the main pane has to come first. The panes are\n placed by grid area, which makes the DOM order irrelevant visually.\n -->\n <div class=\"md3-pane md3-pane-main\">\n <ng-template cdkPortalOutlet></ng-template>\n </div>\n <div class=\"md3-pane md3-pane-start\">\n <ng-template #startOutlet cdkPortalOutlet></ng-template>\n </div>\n <div class=\"md3-pane md3-pane-end\">\n <ng-template #endOutlet cdkPortalOutlet></ng-template>\n </div>\n </div>\n</section>\n", styles: ["::ng-deep .cdk-overlay-container{position:fixed;z-index:1000;inset:0;pointer-events:none;font-size:1rem}::ng-deep .cdk-overlay-container .cdk-global-overlay-wrapper{position:absolute;display:flex;inset:0;pointer-events:none;overflow:hidden}::ng-deep .cdk-overlay-container .cdk-global-overlay-wrapper:has(>.md3-fullscreen-dialog-panel){padding:0}::ng-deep .cdk-overlay-container .cdk-global-overlay-wrapper .md3-fullscreen-dialog-panel{width:100%;height:100%;max-width:none;pointer-events:auto}::ng-deep .cdk-overlay-container .cdk-global-overlay-wrapper .md3-fullscreen-dialog-panel.md3-dialog-closing,::ng-deep .cdk-overlay-container .cdk-global-overlay-wrapper .md3-fullscreen-dialog-panel.md3-dialog-hidden{pointer-events:none}:host{display:block;height:100%;width:100%;outline:0}:host .md3-fullscreen-dialog-container{display:grid;grid-template-rows:minmax(0,1fr);height:100%;min-height:0;overflow:hidden;color:rgb(var(--md-scheme-on-surface));background-color:rgb(var(--md-scheme-surface));transition:all var(--md-motion-expressive-default-spatial-duration) var(--md-motion-expressive-default-spatial-easing);opacity:0;transform:translateY(1.5em)}:host .md3-fullscreen-dialog-container.md3-active{opacity:1;transform:none}:host .md3-panes-container{display:grid;grid-template-areas:\"start main end\";grid-template-columns:auto minmax(0,1fr) auto;grid-template-rows:minmax(0,1fr);min-width:0;min-height:0;overflow:hidden}:host .md3-panes-container .md3-pane{justify-self:stretch;align-self:stretch;min-width:0;min-height:0;height:100%;overflow:hidden}:host .md3-panes-container .md3-pane.md3-pane-start{grid-area:start}:host .md3-panes-container .md3-pane.md3-pane-main{position:relative;grid-area:main;z-index:1;display:grid;grid-template-rows:minmax(0,1fr)}:host .md3-panes-container .md3-pane.md3-pane-main>::ng-deep *{display:grid;grid-template-areas:\"header\" \"body\";grid-template-rows:auto minmax(0,1fr) auto;min-height:0;height:100%;overflow-x:hidden;overflow-y:auto;scrollbar-width:thin;scrollbar-color:rgb(var(--md-scheme-outline-variant)) transparent}:host .md3-panes-container .md3-pane.md3-pane-main>::ng-deep *::-webkit-scrollbar{width:.5rem;height:.5rem}:host .md3-panes-container .md3-pane.md3-pane-main>::ng-deep *::-webkit-scrollbar-track{background:transparent}:host .md3-panes-container .md3-pane.md3-pane-main>::ng-deep *>md3-dialog-body{grid-area:body;margin:0;padding:1em 1.5em;overflow-y:visible;height:auto}:host .md3-panes-container .md3-pane.md3-pane-end{grid-area:end}\n"] }]
|
|
3384
|
+
}], propDecorators: { surface: [{ type: i0.ViewChild, args: ['surface', { isSignal: true }] }], startOutlet: [{ type: i0.ViewChild, args: ['startOutlet', { ...{ read: CdkPortalOutlet }, isSignal: true }] }], endOutlet: [{ type: i0.ViewChild, args: ['endOutlet', { ...{ read: CdkPortalOutlet }, isSignal: true }] }] } });
|
|
3182
3385
|
|
|
3386
|
+
const PANEL_CLASS = 'md3-dialog-panel';
|
|
3387
|
+
const FULL_SCREEN_PANEL_CLASS = 'md3-fullscreen-dialog-panel';
|
|
3388
|
+
const OPENING_CLASS = 'md3-dialog-opening';
|
|
3389
|
+
const SCRIM_KEPT_CLASS = 'md3-dialog-scrim-kept';
|
|
3390
|
+
const SCRIM_INSTANT_CLASS = 'md3-dialog-scrim-instant';
|
|
3391
|
+
/**
|
|
3392
|
+
* Head start given to a dialog that leaves the screen before the dialog taking
|
|
3393
|
+
* its place animates in. Long enough to read as one dialog replacing another,
|
|
3394
|
+
* short enough to still feel like a single gesture.
|
|
3395
|
+
*/
|
|
3396
|
+
const DIALOG_HANDOVER_DELAY_MS = 160;
|
|
3183
3397
|
class DialogService {
|
|
3398
|
+
cdkDialog = inject(Dialog$1);
|
|
3184
3399
|
overlay = inject(Overlay);
|
|
3185
3400
|
injector = inject(Injector);
|
|
3186
3401
|
document = inject(DOCUMENT);
|
|
3402
|
+
/** Open dialogs, from the first one opened to the one currently on top. */
|
|
3403
|
+
refs = [];
|
|
3404
|
+
/**
|
|
3405
|
+
* Page scrolling is blocked here instead of per overlay, so stacked dialogs
|
|
3406
|
+
* cannot unblock the page while another dialog is still open.
|
|
3407
|
+
*/
|
|
3408
|
+
scrollBlock = this.overlay.scrollStrategies.block();
|
|
3409
|
+
/** Element that was focused before the first dialog of the stack opened. */
|
|
3410
|
+
rootTrigger = null;
|
|
3411
|
+
get openDialogs() {
|
|
3412
|
+
return this.refs;
|
|
3413
|
+
}
|
|
3414
|
+
/** The full screen dialog that is open, if there is one. */
|
|
3415
|
+
get fullScreenDialog() {
|
|
3416
|
+
return this.refs.find((ref) => ref.isFullScreen && !ref.isClosing);
|
|
3417
|
+
}
|
|
3187
3418
|
open(component, config = {}) {
|
|
3188
3419
|
const dialogConfig = this.mergeConfig(config);
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
//
|
|
3194
|
-
//
|
|
3195
|
-
const
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
dialogRef
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3420
|
+
if (this.refs.length === 0) {
|
|
3421
|
+
this.rootTrigger = this.getFocusedElement();
|
|
3422
|
+
}
|
|
3423
|
+
// The dialog that is on screen starts leaving first, so the two dialogs
|
|
3424
|
+
// never animate on top of each other. A full screen dialog is not part
|
|
3425
|
+
// of this: regular dialogs open on top of it and leave it alone.
|
|
3426
|
+
const previousRef = this.topRegularRef();
|
|
3427
|
+
if (previousRef) {
|
|
3428
|
+
this.dismissPrevious(previousRef, dialogConfig.previousDialog);
|
|
3429
|
+
}
|
|
3430
|
+
let dialogRef;
|
|
3431
|
+
const cdkRef = this.cdkDialog.open(component, {
|
|
3432
|
+
// The MD3 shell replaces the default CDK container, so the overlay,
|
|
3433
|
+
// focus trap and focus restoration come from the CDK while the shell
|
|
3434
|
+
// only renders the surface.
|
|
3435
|
+
container: {
|
|
3436
|
+
type: Dialog,
|
|
3437
|
+
providers: () => [
|
|
3438
|
+
{ provide: DIALOG_CONFIG, useValue: dialogConfig },
|
|
3439
|
+
],
|
|
3440
|
+
},
|
|
3441
|
+
// These tokens make the dialog controllable from the dynamic
|
|
3442
|
+
// component without coupling that component to the service.
|
|
3443
|
+
providers: (cdkDialogRef) => {
|
|
3444
|
+
dialogRef = new DialogRef(cdkDialogRef, dialogConfig.disableCloseEvents);
|
|
3445
|
+
return [
|
|
3446
|
+
{ provide: DialogRef, useValue: dialogRef },
|
|
3447
|
+
{ provide: DIALOG_DATA, useValue: dialogConfig.data },
|
|
3448
|
+
{ provide: DIALOG_CONFIG, useValue: dialogConfig },
|
|
3449
|
+
{ provide: DIALOG_COMPONENT, useValue: component },
|
|
3450
|
+
];
|
|
3451
|
+
},
|
|
3452
|
+
data: dialogConfig.data,
|
|
3453
|
+
role: dialogConfig.role,
|
|
3454
|
+
ariaModal: true,
|
|
3455
|
+
ariaLabel: dialogConfig.ariaLabel || null,
|
|
3456
|
+
ariaLabelledBy: dialogConfig.ariaLabelledBy || null,
|
|
3457
|
+
ariaDescribedBy: dialogConfig.ariaDescribedBy || null,
|
|
3458
|
+
direction: dialogConfig.direction ?? undefined,
|
|
3459
|
+
viewContainerRef: dialogConfig.viewContainerRef,
|
|
3460
|
+
injector: dialogConfig.injector,
|
|
3461
|
+
hasBackdrop: true,
|
|
3462
|
+
backdropClass: ['md3-dialog-scrim', OPENING_CLASS],
|
|
3463
|
+
panelClass: [PANEL_CLASS, OPENING_CLASS],
|
|
3464
|
+
positionStrategy: this.overlay.position()
|
|
3465
|
+
.global()
|
|
3466
|
+
.centerHorizontally()
|
|
3467
|
+
.centerVertically(),
|
|
3468
|
+
// Scrolling is blocked by the service for the whole stack.
|
|
3469
|
+
scrollStrategy: this.overlay.scrollStrategies.noop(),
|
|
3470
|
+
// Focus goes back to whatever opened the stack, even when the dialog
|
|
3471
|
+
// that was open underneath has been closed in the meantime.
|
|
3472
|
+
restoreFocus: this.rootTrigger ?? true,
|
|
3473
|
+
// Scrim and Escape handling lives in DialogRef so the dialog can
|
|
3474
|
+
// play its exit animation before the overlay is disposed.
|
|
3475
|
+
disableClose: true,
|
|
3476
|
+
});
|
|
3477
|
+
this.registerDialog(dialogRef, cdkRef, dialogConfig, previousRef);
|
|
3478
|
+
return dialogRef;
|
|
3479
|
+
}
|
|
3480
|
+
/**
|
|
3481
|
+
* Opens a dialog that covers the whole screen. Only one can be open at a
|
|
3482
|
+
* time, so it replaces whatever is open, and while it is up the side sheet
|
|
3483
|
+
* outlets belong to it: side sheets open inside the dialog, not behind it.
|
|
3484
|
+
*/
|
|
3485
|
+
openFullScreen(component, config = {}) {
|
|
3486
|
+
const dialogConfig = this.mergeConfig(config);
|
|
3487
|
+
if (this.refs.length === 0) {
|
|
3488
|
+
this.rootTrigger = this.getFocusedElement();
|
|
3489
|
+
}
|
|
3490
|
+
// A full screen dialog is a context of its own: the dialog it replaces
|
|
3491
|
+
// and anything stacked on that dialog goes with it.
|
|
3492
|
+
const previousRef = this.topRef();
|
|
3493
|
+
if (previousRef) {
|
|
3494
|
+
// Everything open belongs to the context being replaced, including
|
|
3495
|
+
// a full screen dialog that is already up.
|
|
3496
|
+
this.closeAll();
|
|
3497
|
+
}
|
|
3498
|
+
let dialogRef;
|
|
3499
|
+
const cdkRef = this.cdkDialog.open(component, {
|
|
3500
|
+
container: {
|
|
3501
|
+
type: FullScreenDialog,
|
|
3502
|
+
providers: () => [
|
|
3503
|
+
{ provide: DIALOG_CONFIG, useValue: dialogConfig },
|
|
3504
|
+
],
|
|
3505
|
+
},
|
|
3506
|
+
providers: (cdkDialogRef) => {
|
|
3507
|
+
dialogRef = new DialogRef(cdkDialogRef, dialogConfig.disableCloseEvents, true);
|
|
3508
|
+
return [
|
|
3509
|
+
{ provide: DialogRef, useValue: dialogRef },
|
|
3510
|
+
{ provide: DIALOG_DATA, useValue: dialogConfig.data },
|
|
3511
|
+
{ provide: DIALOG_CONFIG, useValue: dialogConfig },
|
|
3512
|
+
{ provide: DIALOG_COMPONENT, useValue: component },
|
|
3513
|
+
];
|
|
3514
|
+
},
|
|
3515
|
+
data: dialogConfig.data,
|
|
3516
|
+
role: dialogConfig.role,
|
|
3517
|
+
ariaModal: true,
|
|
3518
|
+
ariaLabel: dialogConfig.ariaLabel || null,
|
|
3519
|
+
ariaLabelledBy: dialogConfig.ariaLabelledBy || null,
|
|
3520
|
+
ariaDescribedBy: dialogConfig.ariaDescribedBy || null,
|
|
3521
|
+
direction: dialogConfig.direction ?? undefined,
|
|
3522
|
+
viewContainerRef: dialogConfig.viewContainerRef,
|
|
3523
|
+
injector: dialogConfig.injector,
|
|
3524
|
+
// The dialog covers the page on its own, so there is nothing left
|
|
3525
|
+
// for a scrim to dim.
|
|
3526
|
+
hasBackdrop: false,
|
|
3527
|
+
panelClass: [FULL_SCREEN_PANEL_CLASS, OPENING_CLASS],
|
|
3528
|
+
// The CDK writes the size on the panel and the global strategy then
|
|
3529
|
+
// drops its centering margins, which is how the panel ends up
|
|
3530
|
+
// covering the whole wrapper.
|
|
3531
|
+
width: '100%',
|
|
3532
|
+
height: '100%',
|
|
3533
|
+
positionStrategy: this.overlay.position().global(),
|
|
3534
|
+
scrollStrategy: this.overlay.scrollStrategies.noop(),
|
|
3535
|
+
restoreFocus: this.rootTrigger ?? true,
|
|
3536
|
+
disableClose: true,
|
|
3537
|
+
});
|
|
3538
|
+
this.registerDialog(dialogRef, cdkRef, dialogConfig, previousRef);
|
|
3204
3539
|
return dialogRef;
|
|
3205
3540
|
}
|
|
3541
|
+
/** Wires a freshly created dialog into the stack and starts its animation. */
|
|
3542
|
+
registerDialog(dialogRef, cdkRef, dialogConfig, previousRef) {
|
|
3543
|
+
dialogRef.dialogInstance = cdkRef.containerInstance;
|
|
3544
|
+
dialogRef.componentInstance = cdkRef.componentInstance ?? undefined;
|
|
3545
|
+
if (cdkRef.componentRef) {
|
|
3546
|
+
this.bindDataToInputs(cdkRef.componentRef, dialogConfig);
|
|
3547
|
+
}
|
|
3548
|
+
this.refs.push(dialogRef);
|
|
3549
|
+
this.updateScrollBlock();
|
|
3550
|
+
if (previousRef) {
|
|
3551
|
+
setTimeout(() => this.startReplacingAnimation(dialogRef, previousRef), DIALOG_HANDOVER_DELAY_MS);
|
|
3552
|
+
}
|
|
3553
|
+
else {
|
|
3554
|
+
this.startOpenAnimation(dialogRef);
|
|
3555
|
+
}
|
|
3556
|
+
// Restoring starts with the exit animation, so the dialog underneath is
|
|
3557
|
+
// already coming back while this one is fading out.
|
|
3558
|
+
dialogRef.beforeClosed().subscribe(() => this.restorePreviousDialog(dialogRef));
|
|
3559
|
+
dialogRef.afterClosed().subscribe(() => this.removeRef(dialogRef));
|
|
3560
|
+
}
|
|
3561
|
+
/** Closes every open dialog, including the hidden and the full screen ones. */
|
|
3562
|
+
closeAll() {
|
|
3563
|
+
// Closed from the bottom up so a closing dialog never brings back a
|
|
3564
|
+
// hidden dialog that is about to close as well.
|
|
3565
|
+
return Promise.all([...this.refs].map((ref) => ref.close())).then(() => undefined);
|
|
3566
|
+
}
|
|
3567
|
+
/** Closes the regular dialogs and leaves a full screen dialog alone. */
|
|
3568
|
+
closeRegularDialogs() {
|
|
3569
|
+
const closing = this.refs
|
|
3570
|
+
.filter((ref) => !ref.isFullScreen)
|
|
3571
|
+
.map((ref) => ref.close());
|
|
3572
|
+
return Promise.all(closing).then(() => undefined);
|
|
3573
|
+
}
|
|
3206
3574
|
mergeConfig(config) {
|
|
3207
3575
|
return {
|
|
3208
3576
|
data: config.data,
|
|
3209
3577
|
bindDataToInputs: config.bindDataToInputs ?? false,
|
|
3210
3578
|
disableCloseEvents: config.disableCloseEvents ?? false,
|
|
3579
|
+
previousDialog: config.previousDialog ?? 'close',
|
|
3211
3580
|
role: config.role ?? 'dialog',
|
|
3212
3581
|
ariaLabel: config.ariaLabel ?? '',
|
|
3213
3582
|
ariaLabelledBy: config.ariaLabelledBy ?? '',
|
|
@@ -3218,20 +3587,17 @@ class DialogService {
|
|
|
3218
3587
|
injector: config.injector ?? this.injector,
|
|
3219
3588
|
};
|
|
3220
3589
|
}
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
.centerVertically(),
|
|
3230
|
-
scrollStrategy: this.overlay.scrollStrategies.block(),
|
|
3231
|
-
});
|
|
3232
|
-
return this.overlay.create(overlayConfig);
|
|
3590
|
+
/**
|
|
3591
|
+
* Hides or closes the dialog that is on screen. Its scrim stays up until
|
|
3592
|
+
* the dialog taking over is ready for it, so the page behind never
|
|
3593
|
+
* brightens between the two dialogs.
|
|
3594
|
+
*/
|
|
3595
|
+
dismissPrevious(previousRef, behavior) {
|
|
3596
|
+
previousRef.overlayRef.backdropElement?.classList.add(SCRIM_KEPT_CLASS);
|
|
3597
|
+
return behavior === 'hide' ? previousRef.hide() : this.closeRegularDialogs();
|
|
3233
3598
|
}
|
|
3234
|
-
startOpenAnimation(
|
|
3599
|
+
startOpenAnimation(dialogRef) {
|
|
3600
|
+
const overlayRef = dialogRef.overlayRef;
|
|
3235
3601
|
const panel = overlayRef.overlayElement;
|
|
3236
3602
|
const backdrop = overlayRef.backdropElement;
|
|
3237
3603
|
// The overlay is inserted already rendered. Keep an initial class for
|
|
@@ -3240,22 +3606,58 @@ class DialogService {
|
|
|
3240
3606
|
requestAnimationFrame(() => {
|
|
3241
3607
|
setTimeout(() => {
|
|
3242
3608
|
panel.getBoundingClientRect();
|
|
3243
|
-
panel.classList.remove(
|
|
3244
|
-
backdrop?.classList.remove(
|
|
3609
|
+
panel.classList.remove(OPENING_CLASS);
|
|
3610
|
+
backdrop?.classList.remove(OPENING_CLASS);
|
|
3245
3611
|
}, 100);
|
|
3246
3612
|
});
|
|
3613
|
+
dialogRef.dialogInstance?.startEnterAnimation();
|
|
3247
3614
|
}
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3615
|
+
/** Opening animation for a dialog that took the place of another one. */
|
|
3616
|
+
startReplacingAnimation(dialogRef, previousRef) {
|
|
3617
|
+
if (dialogRef.isClosing) {
|
|
3618
|
+
return;
|
|
3619
|
+
}
|
|
3620
|
+
const panel = dialogRef.overlayRef.overlayElement;
|
|
3621
|
+
const backdrop = dialogRef.overlayRef.backdropElement;
|
|
3622
|
+
this.beginScrimHandover(previousRef, dialogRef);
|
|
3623
|
+
panel.getBoundingClientRect();
|
|
3624
|
+
panel.classList.remove(OPENING_CLASS);
|
|
3625
|
+
backdrop?.classList.remove(OPENING_CLASS);
|
|
3626
|
+
this.endScrimHandover(previousRef, dialogRef);
|
|
3627
|
+
dialogRef.dialogInstance?.startEnterAnimation();
|
|
3628
|
+
}
|
|
3629
|
+
/** Opening animation for a dialog coming back from behind a closing one. */
|
|
3630
|
+
startRestoringAnimation(closingRef, previousRef) {
|
|
3631
|
+
if (previousRef.isClosing) {
|
|
3632
|
+
return;
|
|
3633
|
+
}
|
|
3634
|
+
this.beginScrimHandover(closingRef, previousRef);
|
|
3635
|
+
previousRef.show();
|
|
3636
|
+
this.endScrimHandover(closingRef, previousRef);
|
|
3637
|
+
}
|
|
3638
|
+
/**
|
|
3639
|
+
* Moves both scrims to their new value in a single frame, without a
|
|
3640
|
+
* transition on either side, so the dim behind the dialogs never changes.
|
|
3641
|
+
*/
|
|
3642
|
+
beginScrimHandover(fromRef, toRef) {
|
|
3643
|
+
const from = fromRef.overlayRef.backdropElement;
|
|
3644
|
+
const to = toRef.overlayRef.backdropElement;
|
|
3645
|
+
// Nothing to hand the scrim over to, e.g. a full screen dialog: the
|
|
3646
|
+
// outgoing scrim fades out on its own instead.
|
|
3647
|
+
if (!to) {
|
|
3648
|
+
return;
|
|
3649
|
+
}
|
|
3650
|
+
from?.classList.add(SCRIM_INSTANT_CLASS);
|
|
3651
|
+
from?.classList.remove(SCRIM_KEPT_CLASS);
|
|
3652
|
+
to?.classList.add(SCRIM_INSTANT_CLASS);
|
|
3653
|
+
}
|
|
3654
|
+
/** Gives the scrims their transitions back once the handover is painted. */
|
|
3655
|
+
endScrimHandover(fromRef, toRef) {
|
|
3656
|
+
const from = fromRef.overlayRef.backdropElement;
|
|
3657
|
+
const to = toRef.overlayRef.backdropElement;
|
|
3658
|
+
requestAnimationFrame(() => {
|
|
3659
|
+
from?.classList.remove(SCRIM_INSTANT_CLASS);
|
|
3660
|
+
to?.classList.remove(SCRIM_INSTANT_CLASS);
|
|
3259
3661
|
});
|
|
3260
3662
|
}
|
|
3261
3663
|
bindDataToInputs(componentRef, config) {
|
|
@@ -3268,34 +3670,69 @@ class DialogService {
|
|
|
3268
3670
|
componentRef.setInput(inputName, inputValue);
|
|
3269
3671
|
});
|
|
3270
3672
|
}
|
|
3271
|
-
|
|
3272
|
-
|
|
3673
|
+
canBindDataToInputs(data) {
|
|
3674
|
+
return typeof data === 'object' && data !== null && !Array.isArray(data);
|
|
3675
|
+
}
|
|
3676
|
+
/** Last dialog of the stack that is not closing yet. */
|
|
3677
|
+
topRef() {
|
|
3678
|
+
for (let index = this.refs.length - 1; index >= 0; index--) {
|
|
3679
|
+
if (!this.refs[index].isClosing) {
|
|
3680
|
+
return this.refs[index];
|
|
3681
|
+
}
|
|
3682
|
+
}
|
|
3683
|
+
return undefined;
|
|
3684
|
+
}
|
|
3685
|
+
/**
|
|
3686
|
+
* Same, without the full screen dialog: it hosts the dialogs opened on top
|
|
3687
|
+
* of it, so it is never the one that gets hidden or closed to make room.
|
|
3688
|
+
*/
|
|
3689
|
+
topRegularRef() {
|
|
3690
|
+
const ref = this.topRef();
|
|
3691
|
+
return ref?.isFullScreen ? undefined : ref;
|
|
3692
|
+
}
|
|
3693
|
+
restorePreviousDialog(ref) {
|
|
3694
|
+
const index = this.refs.indexOf(ref);
|
|
3695
|
+
if (index < 1) {
|
|
3273
3696
|
return;
|
|
3274
3697
|
}
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3698
|
+
for (let previousIndex = index - 1; previousIndex >= 0; previousIndex--) {
|
|
3699
|
+
const previousRef = this.refs[previousIndex];
|
|
3700
|
+
if (previousRef.isClosing) {
|
|
3701
|
+
continue;
|
|
3702
|
+
}
|
|
3703
|
+
// The closing dialog gets the same head start it was given when it
|
|
3704
|
+
// took the screen, and keeps the scrim until then. Nothing to keep
|
|
3705
|
+
// when the dialog underneath has no scrim of its own.
|
|
3706
|
+
if (previousRef.overlayRef.backdropElement) {
|
|
3707
|
+
ref.overlayRef.backdropElement?.classList.add(SCRIM_KEPT_CLASS);
|
|
3708
|
+
}
|
|
3709
|
+
setTimeout(() => this.startRestoringAnimation(ref, previousRef), DIALOG_HANDOVER_DELAY_MS);
|
|
3710
|
+
return;
|
|
3711
|
+
}
|
|
3712
|
+
}
|
|
3713
|
+
removeRef(ref) {
|
|
3714
|
+
const index = this.refs.indexOf(ref);
|
|
3715
|
+
if (index === -1) {
|
|
3716
|
+
return;
|
|
3717
|
+
}
|
|
3718
|
+
this.refs.splice(index, 1);
|
|
3719
|
+
if (this.refs.length === 0) {
|
|
3720
|
+
this.rootTrigger = null;
|
|
3721
|
+
}
|
|
3722
|
+
this.updateScrollBlock();
|
|
3723
|
+
}
|
|
3724
|
+
updateScrollBlock() {
|
|
3725
|
+
if (this.refs.length > 0) {
|
|
3726
|
+
this.scrollBlock.enable();
|
|
3727
|
+
}
|
|
3728
|
+
else {
|
|
3729
|
+
this.scrollBlock.disable();
|
|
3730
|
+
}
|
|
3291
3731
|
}
|
|
3292
3732
|
getFocusedElement() {
|
|
3293
3733
|
const activeElement = this.document.activeElement;
|
|
3294
3734
|
return activeElement instanceof HTMLElement ? activeElement : null;
|
|
3295
3735
|
}
|
|
3296
|
-
canBindDataToInputs(data) {
|
|
3297
|
-
return typeof data === 'object' && data !== null && !Array.isArray(data);
|
|
3298
|
-
}
|
|
3299
3736
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: DialogService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
3300
3737
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: DialogService, providedIn: 'root' });
|
|
3301
3738
|
}
|
|
@@ -3319,13 +3756,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
3319
3756
|
|
|
3320
3757
|
class DialogBody {
|
|
3321
3758
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: DialogBody, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3322
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.0", type: DialogBody, isStandalone: true, selector: "md3-dialog-body", ngImport: i0, template: "<md3-type-body size=\"medium\">\n <ng-content></ng-content>\n</md3-type-body>", styles: [":host{display:block;margin:1em 1.5em 1.5em;color:rgb(var(--md-scheme-on-surface-variant))}:host .md3-text-body.md3-text-medium{letter-spacing:.017857em}\n"], dependencies: [{ kind: "directive", type: TypeBody, selector: "md3-type-body, [md3-type-body]", inputs: ["size", "color", "emphasized"] }] });
|
|
3759
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.0", type: DialogBody, isStandalone: true, selector: "md3-dialog-body", host: { classAttribute: "md3-scrollable" }, ngImport: i0, template: "<md3-type-body size=\"medium\">\n <ng-content></ng-content>\n</md3-type-body>", styles: [":host{display:block;margin:1em 1.5em 1.5em;color:rgb(var(--md-scheme-on-surface-variant))}:host .md3-text-body.md3-text-medium{letter-spacing:.017857em}\n"], dependencies: [{ kind: "directive", type: TypeBody, selector: "md3-type-body, [md3-type-body]", inputs: ["size", "color", "emphasized"] }] });
|
|
3323
3760
|
}
|
|
3324
3761
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: DialogBody, decorators: [{
|
|
3325
3762
|
type: Component,
|
|
3326
3763
|
args: [{ selector: 'md3-dialog-body', imports: [
|
|
3327
3764
|
TypeBody
|
|
3328
|
-
],
|
|
3765
|
+
], host: {
|
|
3766
|
+
'class': 'md3-scrollable',
|
|
3767
|
+
}, template: "<md3-type-body size=\"medium\">\n <ng-content></ng-content>\n</md3-type-body>", styles: [":host{display:block;margin:1em 1.5em 1.5em;color:rgb(var(--md-scheme-on-surface-variant))}:host .md3-text-body.md3-text-medium{letter-spacing:.017857em}\n"] }]
|
|
3329
3768
|
}] });
|
|
3330
3769
|
|
|
3331
3770
|
class DialogActions {
|
|
@@ -3337,6 +3776,38 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
3337
3776
|
args: [{ selector: 'md3-dialog-actions', imports: [], template: "<div class=\"md3-actions\">\n <ng-content></ng-content>\n</div>", styles: [":host{display:block;margin:1.5em}:host .md3-actions{display:flex;gap:1em;flex-direction:row-reverse}\n"] }]
|
|
3338
3777
|
}] });
|
|
3339
3778
|
|
|
3779
|
+
/**
|
|
3780
|
+
* Header of a full screen dialog: a leading icon button to leave the dialog,
|
|
3781
|
+
* the headline, and a trailing action. It sticks to the top of the dialog while
|
|
3782
|
+
* the content scrolls underneath.
|
|
3783
|
+
*/
|
|
3784
|
+
class FullScreenDialogHeader {
|
|
3785
|
+
title = input('', { ...(ngDevMode ? { debugName: "title" } : /* istanbul ignore next */ {}), alias: 'title' });
|
|
3786
|
+
// context values
|
|
3787
|
+
buttonContextSize = signal('small', /* @ts-ignore */
|
|
3788
|
+
...(ngDevMode ? [{ debugName: "buttonContextSize" }] : /* istanbul ignore next */ []));
|
|
3789
|
+
buttonContextWidth = signal('default', /* @ts-ignore */
|
|
3790
|
+
...(ngDevMode ? [{ debugName: "buttonContextWidth" }] : /* istanbul ignore next */ []));
|
|
3791
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: FullScreenDialogHeader, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3792
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.0", type: FullScreenDialogHeader, isStandalone: true, selector: "md3-fullscreen-dialog-header", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
|
|
3793
|
+
{
|
|
3794
|
+
provide: MD3_BUTTON_CONTEXT,
|
|
3795
|
+
useExisting: FullScreenDialogHeader,
|
|
3796
|
+
},
|
|
3797
|
+
], ngImport: i0, template: "<ng-content select=\"[md3-icon-button][md3-header-leading]\"></ng-content>\n<div class=\"md3-title-container\">\n <md3-type-title size=\"large\">{{ title() }}</md3-type-title>\n</div>\n<div class=\"md3-actions-container\">\n <ng-content select=\"[md3-header-trailing]\"></ng-content>\n</div>\n", styles: [":host{--foreground-color: rgb(var(--md-scheme-on-surface));position:sticky;top:0;z-index:3;grid-area:header;display:flex;align-items:center;gap:.5em;height:4em;padding:0 1em;color:var(--foreground-color);background-color:rgb(var(--md-scheme-surface))}:host ::ng-deep [md3-header-leading]:first-child{margin-inline-start:-.5em}:host .md3-title-container{flex:1 1 auto;min-width:0;color:inherit}:host .md3-title-container:first-child{padding-inline-start:.5em}:host .md3-actions-container{display:flex;flex:0 0 auto;align-items:center;gap:.5em}\n"], dependencies: [{ kind: "directive", type: TypeTitle, selector: "md3-type-title, [md3-type-title]", inputs: ["size", "color", "emphasized"] }] });
|
|
3798
|
+
}
|
|
3799
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: FullScreenDialogHeader, decorators: [{
|
|
3800
|
+
type: Component,
|
|
3801
|
+
args: [{ selector: 'md3-fullscreen-dialog-header', imports: [
|
|
3802
|
+
TypeTitle,
|
|
3803
|
+
], providers: [
|
|
3804
|
+
{
|
|
3805
|
+
provide: MD3_BUTTON_CONTEXT,
|
|
3806
|
+
useExisting: FullScreenDialogHeader,
|
|
3807
|
+
},
|
|
3808
|
+
], template: "<ng-content select=\"[md3-icon-button][md3-header-leading]\"></ng-content>\n<div class=\"md3-title-container\">\n <md3-type-title size=\"large\">{{ title() }}</md3-type-title>\n</div>\n<div class=\"md3-actions-container\">\n <ng-content select=\"[md3-header-trailing]\"></ng-content>\n</div>\n", styles: [":host{--foreground-color: rgb(var(--md-scheme-on-surface));position:sticky;top:0;z-index:3;grid-area:header;display:flex;align-items:center;gap:.5em;height:4em;padding:0 1em;color:var(--foreground-color);background-color:rgb(var(--md-scheme-surface))}:host ::ng-deep [md3-header-leading]:first-child{margin-inline-start:-.5em}:host .md3-title-container{flex:1 1 auto;min-width:0;color:inherit}:host .md3-title-container:first-child{padding-inline-start:.5em}:host .md3-actions-container{display:flex;flex:0 0 auto;align-items:center;gap:.5em}\n"] }]
|
|
3809
|
+
}], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }] } });
|
|
3810
|
+
|
|
3340
3811
|
const MENU_DATA = new InjectionToken('MD3_MENU_DATA');
|
|
3341
3812
|
const MENU_CONFIG = new InjectionToken('MD3_MENU_CONFIG');
|
|
3342
3813
|
const MENU_COMPONENT = new InjectionToken('MD3_MENU_COMPONENT');
|
|
@@ -4367,5 +4838,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
4367
4838
|
* Generated bundle index. Do not edit.
|
|
4368
4839
|
*/
|
|
4369
4840
|
|
|
4370
|
-
export { AppBar, AppBarLogo, Avatar, Badge, Button, ButtonGroup, Card, Checkbox, ChipAvatar, Chips, CircularProgressIndicator, DIALOG_COMPONENT, DIALOG_CONFIG, DIALOG_DATA, Dialog, DialogActions, DialogBody, DialogHeader, DialogRef, DialogService, Divider, FloatingActionButton, Grid, GridItem, IconButton, IconElement, InputElement, LayoutService, LinearProgressIndicator, List, ListItem, ListItemPrimaryAction, ListLeading, ListSlot, LoadingIndicator, MENU_COMPONENT, MENU_CONFIG, MENU_DATA, MaterialIcon, Menu, MenuGroup, MenuItem, MenuRef, MenuService, NavigationBar, NavigationGroup, NavigationItem, NavigationRail, RadioButton, SIDE_SHEET_COMPONENT, SIDE_SHEET_CONFIG, SIDE_SHEET_DATA, SNACKBAR_ACTION_LABEL, SNACKBAR_CONFIG, SNACKBAR_MESSAGE, Scaffold, ScaffoldBar, ScaffoldPane, ScaffoldRail, SheetsService, SideSheetActions, SideSheetBody, SideSheetHeader, SideSheetRef, Slider, Snackbar, SnackbarRef, SnackbarService, SplitButton, StateComponent, SupportingText, Switch, TextField, TypeBody, TypeDisplay, TypeHeadline, TypeLabel, TypeTitle };
|
|
4841
|
+
export { AppBar, AppBarLogo, Avatar, Badge, Button, ButtonGroup, Card, Checkbox, ChipAvatar, Chips, CircularProgressIndicator, DIALOG_COMPONENT, DIALOG_CONFIG, DIALOG_DATA, Dialog, DialogActions, DialogBody, DialogHeader, DialogRef, DialogService, Divider, FloatingActionButton, FullScreenDialog, FullScreenDialogHeader, Grid, GridItem, IconButton, IconElement, InputElement, LayoutService, LinearProgressIndicator, List, ListItem, ListItemPrimaryAction, ListLeading, ListSlot, LoadingIndicator, MENU_COMPONENT, MENU_CONFIG, MENU_DATA, MaterialIcon, Menu, MenuGroup, MenuItem, MenuRef, MenuService, NavigationBar, NavigationGroup, NavigationItem, NavigationRail, RadioButton, SIDE_SHEET_COMPONENT, SIDE_SHEET_CONFIG, SIDE_SHEET_DATA, SNACKBAR_ACTION_LABEL, SNACKBAR_CONFIG, SNACKBAR_MESSAGE, Scaffold, ScaffoldBar, ScaffoldPane, ScaffoldRail, SheetsService, SideSheetActions, SideSheetBody, SideSheetHeader, SideSheetRef, Slider, Snackbar, SnackbarRef, SnackbarService, SplitButton, StateComponent, SupportingText, Switch, TextField, TypeBody, TypeDisplay, TypeHeadline, TypeLabel, TypeTitle };
|
|
4371
4842
|
//# sourceMappingURL=almoamendev-ngx-md3.mjs.map
|