@crowdfarming/oliva-ds 1.84.0-rc.1 → 1.85.0-rc.1
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/fesm2022/crowdfarming-oliva-ds.mjs +67 -3
- package/fesm2022/crowdfarming-oliva-ds.mjs.map +1 -1
- package/lib/modal/src/lib/modal/modal.component.d.ts +4 -0
- package/lib/modal/src/lib/modal/modal.interfaces.d.ts +3 -0
- package/lib/modal/src/lib/modal/modal.service.d.ts +1 -0
- package/package.json +1 -1
|
@@ -5644,6 +5644,7 @@ class ModalComponent {
|
|
|
5644
5644
|
_isContentScrollableSignal = signal(false);
|
|
5645
5645
|
_safeAreaInsetBottomSignal = signal(true);
|
|
5646
5646
|
_autoFocusSignal = signal(true);
|
|
5647
|
+
_hasHeaderSlotSignal = signal(false);
|
|
5647
5648
|
modalContentRef = viewChild('modalContent');
|
|
5648
5649
|
bodyContentRef = viewChild('bodyContent');
|
|
5649
5650
|
constructor() {
|
|
@@ -5696,6 +5697,12 @@ class ModalComponent {
|
|
|
5696
5697
|
getAutoFocus() {
|
|
5697
5698
|
return this._autoFocusSignal();
|
|
5698
5699
|
}
|
|
5700
|
+
hasHeaderSlot() {
|
|
5701
|
+
return this._hasHeaderSlotSignal();
|
|
5702
|
+
}
|
|
5703
|
+
setHasHeaderSlot(hasHeaderSlot) {
|
|
5704
|
+
this._hasHeaderSlotSignal.set(hasHeaderSlot);
|
|
5705
|
+
}
|
|
5699
5706
|
setOpen(open) {
|
|
5700
5707
|
this._isOpenSignal.set(open);
|
|
5701
5708
|
}
|
|
@@ -5837,6 +5844,9 @@ class ModalComponent {
|
|
|
5837
5844
|
];
|
|
5838
5845
|
return c.filter(Boolean).join(' ');
|
|
5839
5846
|
}
|
|
5847
|
+
shouldRenderHeader() {
|
|
5848
|
+
return (this.hasHeaderSlot() || !!this.getTitle() || this.getShowCloseButton());
|
|
5849
|
+
}
|
|
5840
5850
|
getContentBodyContentClasses() {
|
|
5841
5851
|
const c = [
|
|
5842
5852
|
'c-modal__content__body__content',
|
|
@@ -5847,11 +5857,11 @@ class ModalComponent {
|
|
|
5847
5857
|
return c.filter(Boolean).join(' ');
|
|
5848
5858
|
}
|
|
5849
5859
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: ModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5850
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.7", type: ModalComponent, isStandalone: true, selector: "lib-modal", viewQueries: [{ propertyName: "modalContentRef", first: true, predicate: ["modalContent"], descendants: true, isSignal: true }, { propertyName: "bodyContentRef", first: true, predicate: ["bodyContent"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (isModalOpen()) {\n<div class=\"c-modal\" [ngClass]=\"getClasses()\">\n <!-- Backdrop -->\n <div\n class=\"c-modal__backdrop\"\n [ngClass]=\"getBackdropClasses()\"\n (click)=\"onBackdropClick()\"\n (keydown.escape)=\"onEscapeKey()\"\n tabindex=\"0\"\n role=\"button\"\n aria-label=\"Close modal\"\n ></div>\n\n <!-- Modal Content -->\n <div\n #modalContent\n class=\"c-modal__content\"\n [ngClass]=\"getContentClasses()\"\n (keydown.escape)=\"onEscapeKey()\"\n role=\"dialog\"\n tabindex=\"-1\"\n [attr.aria-labelledby]=\"getTitle() ? 'modal-title' : null\"\n [attr.aria-describedby]=\"getDescription() ? 'modal-description' : null\"\n >\n <!-- Header -->\n @if (
|
|
5860
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.7", type: ModalComponent, isStandalone: true, selector: "lib-modal", viewQueries: [{ propertyName: "modalContentRef", first: true, predicate: ["modalContent"], descendants: true, isSignal: true }, { propertyName: "bodyContentRef", first: true, predicate: ["bodyContent"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (isModalOpen()) {\n<div class=\"c-modal\" [ngClass]=\"getClasses()\">\n <!-- Backdrop -->\n <div\n class=\"c-modal__backdrop\"\n [ngClass]=\"getBackdropClasses()\"\n (click)=\"onBackdropClick()\"\n (keydown.escape)=\"onEscapeKey()\"\n tabindex=\"0\"\n role=\"button\"\n aria-label=\"Close modal\"\n ></div>\n\n <!-- Modal Content -->\n <div\n #modalContent\n class=\"c-modal__content\"\n [ngClass]=\"getContentClasses()\"\n (keydown.escape)=\"onEscapeKey()\"\n role=\"dialog\"\n tabindex=\"-1\"\n [attr.aria-labelledby]=\"getTitle() && !hasHeaderSlot() ? 'modal-title' : null\"\n [attr.aria-describedby]=\"getDescription() ? 'modal-description' : null\"\n >\n <!-- Header -->\n @if (shouldRenderHeader()) {\n <div [ngClass]=\"getHeaderClasses()\">\n <div class=\"c-modal__content__header__left\">\n @if (hasHeaderSlot()) {\n <div class=\"c-modal__content__header__slot\"></div>\n } @else if (getTitle()) {\n <p id=\"modal-title\" class=\"c-modal__content__header__title\">\n {{ getTitle() }}\n </p>\n }\n </div>\n @if (getShowCloseButton()) {\n <div class=\"c-modal__content__header__right\">\n <lib-button-icon\n iconName=\"x-regular\"\n size=\"sm\"\n variant=\"neutral\"\n (click)=\"onCloseButtonClick()\"\n aria-label=\"Close modal\"\n ></lib-button-icon>\n </div>\n }\n </div>\n }\n\n <!-- Description -->\n <div class=\"c-modal__content__body\">\n <!-- Body Content (scrollable area) -->\n <div #bodyContent [ngClass]=\"getContentBodyContentClasses()\">\n @if (getDescription()) {\n <div id=\"modal-description\" class=\"c-modal__content__body__description\">\n <p>{{ getDescription() }}</p>\n </div>\n }\n <ng-content></ng-content>\n </div>\n </div>\n\n <!-- Footer with Buttons -->\n @if (getPrimaryButton() || getSecondaryButton()) {\n <div [ngClass]=\"getFooterClasses()\">\n @if (getSecondaryButton()) {\n <lib-button\n class=\"c-modal__content__footer__button secondary\"\n [text]=\"getSecondaryButton()!.text\"\n [variant]=\"getSecondaryButton()!.variant\"\n [disabled]=\"getSecondaryButton()!.disabled ?? false\"\n [loading]=\"getSecondaryButton()!.loading ?? false\"\n [fullWidth]=\"true\"\n (clicked)=\"onSecondaryButtonClick()\"\n ></lib-button>\n } @if (getPrimaryButton()) {\n <lib-button\n class=\"c-modal__content__footer__button primary\"\n [text]=\"getPrimaryButton()!.text\"\n [variant]=\"getPrimaryButton()!.variant\"\n [disabled]=\"getPrimaryButton()!.disabled ?? false\"\n [loading]=\"getPrimaryButton()!.loading ?? false\"\n [fullWidth]=\"true\"\n (clicked)=\"onPrimaryButtonClick()\"\n ></lib-button>\n }\n </div>\n }\n </div>\n</div>\n}\n", styles: [".c-modal{position:fixed;top:0;left:0;width:100%;height:100%;z-index:1000;display:flex;align-items:center;justify-content:center;opacity:0;visibility:hidden;transition:opacity .2s ease-in-out,visibility .2s ease-in-out}.c-modal--open{opacity:1;visibility:visible}.c-modal__content{background-color:var(--color-core-background-surface-floating);padding:var(--space-container-padding-sm) 0;box-shadow:var(--elevation-floating);border-radius:var(--size-border-radius-lg);overflow:hidden;display:flex;flex-direction:column;width:100%;box-sizing:border-box;max-height:min(812px,100vh - 128px)}.c-modal__content--open{transform:scale(1)}.c-modal__content--xs{max-width:360px}.c-modal__content--sm{max-width:416px}.c-modal__content--md{max-width:636px}.c-modal__content--lg{max-width:856px}.c-modal__content--safe-area-inset-bottom{padding-bottom:calc(env(safe-area-inset-bottom,0) + var(--space-container-padding-sm))}.c-modal__content__header{display:flex;align-items:flex-start;background-color:var(--color-core-background-surface-floating);padding:0 var(--space-container-padding-sm) var(--space-container-padding-sm);gap:var(--space-container-gap-sm);border-bottom:var(--size-border-width-sm) solid transparent;transition:border-color .15s ease-in-out}.c-modal__content__header--scrollable{z-index:1;border-bottom-color:var(--color-core-border-soft)}.c-modal__content__header__left{flex:1;min-width:0;display:flex;align-items:center}.c-modal__content__header__right{flex:1;display:flex;justify-content:flex-end}.c-modal__content__header__slot{flex:1;min-width:0;display:flex;align-items:center}.c-modal__content__header__title{margin:0;font-family:var(--typography-label-lg-strong-family),sans-serif;font-weight:var(--typography-label-lg-strong-weight);font-size:var(--typography-label-lg-strong-size);line-height:var(--typography-label-lg-strong-line-height);letter-spacing:var(--typography-label-lg-strong-letter-spacing);color:var(--color-core-content-default)}.c-modal__content__body{display:flex;flex-direction:column;flex:1;gap:var(--space-container-gap-md);overflow:hidden;min-height:0}.c-modal__content__body__description p{margin:0;color:var(--color-core-content-soft);font-family:var(--typography-body-md-family),sans-serif;font-weight:var(--typography-body-md-weight);font-size:var(--typography-body-md-size);line-height:var(--typography-body-md-line-height);letter-spacing:var(--typography-body-md-letter-spacing)}.c-modal__content__body__content{padding:0 var(--space-container-padding-sm);display:flex;flex-direction:column;gap:var(--space-container-gap-md);overflow-y:auto;flex:1;min-height:0}.c-modal__content__body__content--scrollable{padding:var(--space-container-padding-sm)}.c-modal__content__footer{display:flex;justify-content:flex-end;gap:var(--space-component-gap-md);background-color:var(--color-core-background-surface-floating);padding:var(--space-container-padding-sm) var(--space-container-padding-sm) 0;border-top:var(--size-border-width-sm) solid transparent;transition:border-color .15s ease-in-out}.c-modal__content__footer--scrollable{z-index:1;border-top-color:var(--color-core-border-soft)}@media (max-width: 767px){.c-modal__content__footer{flex-direction:column;gap:var(--space-component-gap-md)}}@media (max-width: 767px){.c-modal__content__footer__button{width:100%}.c-modal__content__footer__button.primary{order:1}.c-modal__content__footer__button.secondary{order:2}}.c-modal__backdrop{position:absolute;top:0;left:0;width:100%;height:100%;background-color:var(--color-effect-overlay);opacity:0;transition:opacity .2s ease-in-out}.c-modal__backdrop--open{opacity:1}@media (max-width: 767px){.c-modal{align-items:flex-end}.c-modal--xs .c-modal__content,.c-modal--sm .c-modal__content,.c-modal--md .c-modal__content{position:fixed;bottom:0;left:0;right:0;width:100%;max-width:none;max-height:100vh;transform:translateY(100%);transition:transform .3s ease-in-out;border-bottom-left-radius:0;border-bottom-right-radius:0}.c-modal--xs.c-modal--open .c-modal__content,.c-modal--sm.c-modal--open .c-modal__content,.c-modal--md.c-modal--open .c-modal__content{transform:translateY(0);perspective:none;contain:none}.c-modal--lg{align-items:stretch}.c-modal--lg .c-modal__content{position:fixed;inset:0;width:100%;height:100%;max-height:100vh;max-width:none;border-radius:0;transform:scale(.95);transition:transform .3s ease-in-out}.c-modal--lg.c-modal--open .c-modal__content{transform:scale(1)}}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ButtonComponent, selector: "lib-button", inputs: ["text", "ariaLabel", "disabled", "loading", "skeletonActive", "variant", "size", "loadingText", "fullWidth", "iconBefore", "iconAfter", "type"], outputs: ["clicked"] }, { kind: "component", type: ButtonIconComponent, selector: "lib-button-icon", inputs: ["ariaLabel", "variant", "size", "iconName", "disabled", "loading", "skeletonActive"], outputs: ["clicked"] }] });
|
|
5851
5861
|
}
|
|
5852
5862
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: ModalComponent, decorators: [{
|
|
5853
5863
|
type: Component,
|
|
5854
|
-
args: [{ selector: 'lib-modal', imports: [NgClass, ButtonComponent, ButtonIconComponent], template: "@if (isModalOpen()) {\n<div class=\"c-modal\" [ngClass]=\"getClasses()\">\n <!-- Backdrop -->\n <div\n class=\"c-modal__backdrop\"\n [ngClass]=\"getBackdropClasses()\"\n (click)=\"onBackdropClick()\"\n (keydown.escape)=\"onEscapeKey()\"\n tabindex=\"0\"\n role=\"button\"\n aria-label=\"Close modal\"\n ></div>\n\n <!-- Modal Content -->\n <div\n #modalContent\n class=\"c-modal__content\"\n [ngClass]=\"getContentClasses()\"\n (keydown.escape)=\"onEscapeKey()\"\n role=\"dialog\"\n tabindex=\"-1\"\n [attr.aria-labelledby]=\"getTitle() ? 'modal-title' : null\"\n [attr.aria-describedby]=\"getDescription() ? 'modal-description' : null\"\n >\n <!-- Header -->\n @if (
|
|
5864
|
+
args: [{ selector: 'lib-modal', imports: [NgClass, ButtonComponent, ButtonIconComponent], template: "@if (isModalOpen()) {\n<div class=\"c-modal\" [ngClass]=\"getClasses()\">\n <!-- Backdrop -->\n <div\n class=\"c-modal__backdrop\"\n [ngClass]=\"getBackdropClasses()\"\n (click)=\"onBackdropClick()\"\n (keydown.escape)=\"onEscapeKey()\"\n tabindex=\"0\"\n role=\"button\"\n aria-label=\"Close modal\"\n ></div>\n\n <!-- Modal Content -->\n <div\n #modalContent\n class=\"c-modal__content\"\n [ngClass]=\"getContentClasses()\"\n (keydown.escape)=\"onEscapeKey()\"\n role=\"dialog\"\n tabindex=\"-1\"\n [attr.aria-labelledby]=\"getTitle() && !hasHeaderSlot() ? 'modal-title' : null\"\n [attr.aria-describedby]=\"getDescription() ? 'modal-description' : null\"\n >\n <!-- Header -->\n @if (shouldRenderHeader()) {\n <div [ngClass]=\"getHeaderClasses()\">\n <div class=\"c-modal__content__header__left\">\n @if (hasHeaderSlot()) {\n <div class=\"c-modal__content__header__slot\"></div>\n } @else if (getTitle()) {\n <p id=\"modal-title\" class=\"c-modal__content__header__title\">\n {{ getTitle() }}\n </p>\n }\n </div>\n @if (getShowCloseButton()) {\n <div class=\"c-modal__content__header__right\">\n <lib-button-icon\n iconName=\"x-regular\"\n size=\"sm\"\n variant=\"neutral\"\n (click)=\"onCloseButtonClick()\"\n aria-label=\"Close modal\"\n ></lib-button-icon>\n </div>\n }\n </div>\n }\n\n <!-- Description -->\n <div class=\"c-modal__content__body\">\n <!-- Body Content (scrollable area) -->\n <div #bodyContent [ngClass]=\"getContentBodyContentClasses()\">\n @if (getDescription()) {\n <div id=\"modal-description\" class=\"c-modal__content__body__description\">\n <p>{{ getDescription() }}</p>\n </div>\n }\n <ng-content></ng-content>\n </div>\n </div>\n\n <!-- Footer with Buttons -->\n @if (getPrimaryButton() || getSecondaryButton()) {\n <div [ngClass]=\"getFooterClasses()\">\n @if (getSecondaryButton()) {\n <lib-button\n class=\"c-modal__content__footer__button secondary\"\n [text]=\"getSecondaryButton()!.text\"\n [variant]=\"getSecondaryButton()!.variant\"\n [disabled]=\"getSecondaryButton()!.disabled ?? false\"\n [loading]=\"getSecondaryButton()!.loading ?? false\"\n [fullWidth]=\"true\"\n (clicked)=\"onSecondaryButtonClick()\"\n ></lib-button>\n } @if (getPrimaryButton()) {\n <lib-button\n class=\"c-modal__content__footer__button primary\"\n [text]=\"getPrimaryButton()!.text\"\n [variant]=\"getPrimaryButton()!.variant\"\n [disabled]=\"getPrimaryButton()!.disabled ?? false\"\n [loading]=\"getPrimaryButton()!.loading ?? false\"\n [fullWidth]=\"true\"\n (clicked)=\"onPrimaryButtonClick()\"\n ></lib-button>\n }\n </div>\n }\n </div>\n</div>\n}\n", styles: [".c-modal{position:fixed;top:0;left:0;width:100%;height:100%;z-index:1000;display:flex;align-items:center;justify-content:center;opacity:0;visibility:hidden;transition:opacity .2s ease-in-out,visibility .2s ease-in-out}.c-modal--open{opacity:1;visibility:visible}.c-modal__content{background-color:var(--color-core-background-surface-floating);padding:var(--space-container-padding-sm) 0;box-shadow:var(--elevation-floating);border-radius:var(--size-border-radius-lg);overflow:hidden;display:flex;flex-direction:column;width:100%;box-sizing:border-box;max-height:min(812px,100vh - 128px)}.c-modal__content--open{transform:scale(1)}.c-modal__content--xs{max-width:360px}.c-modal__content--sm{max-width:416px}.c-modal__content--md{max-width:636px}.c-modal__content--lg{max-width:856px}.c-modal__content--safe-area-inset-bottom{padding-bottom:calc(env(safe-area-inset-bottom,0) + var(--space-container-padding-sm))}.c-modal__content__header{display:flex;align-items:flex-start;background-color:var(--color-core-background-surface-floating);padding:0 var(--space-container-padding-sm) var(--space-container-padding-sm);gap:var(--space-container-gap-sm);border-bottom:var(--size-border-width-sm) solid transparent;transition:border-color .15s ease-in-out}.c-modal__content__header--scrollable{z-index:1;border-bottom-color:var(--color-core-border-soft)}.c-modal__content__header__left{flex:1;min-width:0;display:flex;align-items:center}.c-modal__content__header__right{flex:1;display:flex;justify-content:flex-end}.c-modal__content__header__slot{flex:1;min-width:0;display:flex;align-items:center}.c-modal__content__header__title{margin:0;font-family:var(--typography-label-lg-strong-family),sans-serif;font-weight:var(--typography-label-lg-strong-weight);font-size:var(--typography-label-lg-strong-size);line-height:var(--typography-label-lg-strong-line-height);letter-spacing:var(--typography-label-lg-strong-letter-spacing);color:var(--color-core-content-default)}.c-modal__content__body{display:flex;flex-direction:column;flex:1;gap:var(--space-container-gap-md);overflow:hidden;min-height:0}.c-modal__content__body__description p{margin:0;color:var(--color-core-content-soft);font-family:var(--typography-body-md-family),sans-serif;font-weight:var(--typography-body-md-weight);font-size:var(--typography-body-md-size);line-height:var(--typography-body-md-line-height);letter-spacing:var(--typography-body-md-letter-spacing)}.c-modal__content__body__content{padding:0 var(--space-container-padding-sm);display:flex;flex-direction:column;gap:var(--space-container-gap-md);overflow-y:auto;flex:1;min-height:0}.c-modal__content__body__content--scrollable{padding:var(--space-container-padding-sm)}.c-modal__content__footer{display:flex;justify-content:flex-end;gap:var(--space-component-gap-md);background-color:var(--color-core-background-surface-floating);padding:var(--space-container-padding-sm) var(--space-container-padding-sm) 0;border-top:var(--size-border-width-sm) solid transparent;transition:border-color .15s ease-in-out}.c-modal__content__footer--scrollable{z-index:1;border-top-color:var(--color-core-border-soft)}@media (max-width: 767px){.c-modal__content__footer{flex-direction:column;gap:var(--space-component-gap-md)}}@media (max-width: 767px){.c-modal__content__footer__button{width:100%}.c-modal__content__footer__button.primary{order:1}.c-modal__content__footer__button.secondary{order:2}}.c-modal__backdrop{position:absolute;top:0;left:0;width:100%;height:100%;background-color:var(--color-effect-overlay);opacity:0;transition:opacity .2s ease-in-out}.c-modal__backdrop--open{opacity:1}@media (max-width: 767px){.c-modal{align-items:flex-end}.c-modal--xs .c-modal__content,.c-modal--sm .c-modal__content,.c-modal--md .c-modal__content{position:fixed;bottom:0;left:0;right:0;width:100%;max-width:none;max-height:100vh;transform:translateY(100%);transition:transform .3s ease-in-out;border-bottom-left-radius:0;border-bottom-right-radius:0}.c-modal--xs.c-modal--open .c-modal__content,.c-modal--sm.c-modal--open .c-modal__content,.c-modal--md.c-modal--open .c-modal__content{transform:translateY(0);perspective:none;contain:none}.c-modal--lg{align-items:stretch}.c-modal--lg .c-modal__content{position:fixed;inset:0;width:100%;height:100%;max-height:100vh;max-width:none;border-radius:0;transform:scale(.95);transition:transform .3s ease-in-out}.c-modal--lg.c-modal--open .c-modal__content{transform:scale(1)}}\n"] }]
|
|
5855
5865
|
}], ctorParameters: () => [] });
|
|
5856
5866
|
|
|
5857
5867
|
class ModalService {
|
|
@@ -5863,6 +5873,7 @@ class ModalService {
|
|
|
5863
5873
|
openModals = new Map();
|
|
5864
5874
|
constructor() {
|
|
5865
5875
|
this.subscribeToNavigationEvents();
|
|
5876
|
+
this.ensureCdkOverlayStacksAboveModal();
|
|
5866
5877
|
}
|
|
5867
5878
|
subscribeToNavigationEvents() {
|
|
5868
5879
|
if (!isPlatformBrowser(this.platformId)) {
|
|
@@ -5874,6 +5885,24 @@ class ModalService {
|
|
|
5874
5885
|
this.closeAll();
|
|
5875
5886
|
});
|
|
5876
5887
|
}
|
|
5888
|
+
// The modal element is appended to <body> with z-index: 1000. Angular CDK's
|
|
5889
|
+
// overlay container is also a sibling of <body> with z-index: 1000, so when
|
|
5890
|
+
// a tooltip/select/etc. is opened inside a modal the modal ends up on top
|
|
5891
|
+
// because it sits later in document order. We raise the CDK container above
|
|
5892
|
+
// the modal so any CDK overlay (tooltip, popover, dropdown...) shows over it.
|
|
5893
|
+
ensureCdkOverlayStacksAboveModal() {
|
|
5894
|
+
if (!isPlatformBrowser(this.platformId)) {
|
|
5895
|
+
return;
|
|
5896
|
+
}
|
|
5897
|
+
const styleId = 'oliva-ds-modal-overlay-stacking';
|
|
5898
|
+
if (document.getElementById(styleId)) {
|
|
5899
|
+
return;
|
|
5900
|
+
}
|
|
5901
|
+
const style = document.createElement('style');
|
|
5902
|
+
style.id = styleId;
|
|
5903
|
+
style.textContent = '.cdk-overlay-container { z-index: 1100; }';
|
|
5904
|
+
document.head.appendChild(style);
|
|
5905
|
+
}
|
|
5877
5906
|
closeAll({ force = false } = {}) {
|
|
5878
5907
|
const modalsToClose = Array.from(this.openModals.values()).filter((entry) => force || !entry.persist);
|
|
5879
5908
|
modalsToClose.forEach((entry) => {
|
|
@@ -5895,10 +5924,28 @@ class ModalService {
|
|
|
5895
5924
|
if (config.data) {
|
|
5896
5925
|
Object.assign(contentRef.instance, config.data);
|
|
5897
5926
|
}
|
|
5927
|
+
// Create header component if provided
|
|
5928
|
+
const headerRef = config.headerComponent
|
|
5929
|
+
? createComponent(config.headerComponent, {
|
|
5930
|
+
environmentInjector: this.appRef.injector,
|
|
5931
|
+
elementInjector: this.injector,
|
|
5932
|
+
})
|
|
5933
|
+
: undefined;
|
|
5934
|
+
if (headerRef && config.headerData) {
|
|
5935
|
+
// Use setInput so it works for both decorator-based inputs and the new
|
|
5936
|
+
// signal `input()` API (assigning directly would clobber InputSignals).
|
|
5937
|
+
for (const [key, value] of Object.entries(config.headerData)) {
|
|
5938
|
+
headerRef.setInput(key, value);
|
|
5939
|
+
}
|
|
5940
|
+
}
|
|
5898
5941
|
this.appRef.attachView(modalRef.hostView);
|
|
5899
5942
|
this.appRef.attachView(contentRef.hostView);
|
|
5943
|
+
if (headerRef) {
|
|
5944
|
+
this.appRef.attachView(headerRef.hostView);
|
|
5945
|
+
}
|
|
5900
5946
|
document.body.appendChild(modalRef.location.nativeElement);
|
|
5901
5947
|
modalRef.instance.setConfig(config);
|
|
5948
|
+
modalRef.instance.setHasHeaderSlot(!!headerRef);
|
|
5902
5949
|
let result;
|
|
5903
5950
|
let resolvePromise;
|
|
5904
5951
|
const afterClosedPromise = new Promise((resolve) => {
|
|
@@ -5932,6 +5979,7 @@ class ModalService {
|
|
|
5932
5979
|
const entry = {
|
|
5933
5980
|
modalRef,
|
|
5934
5981
|
contentRef,
|
|
5982
|
+
headerRef,
|
|
5935
5983
|
resolvePromise: resolvePromise,
|
|
5936
5984
|
result,
|
|
5937
5985
|
modalRefResult,
|
|
@@ -6048,6 +6096,16 @@ class ModalService {
|
|
|
6048
6096
|
console.error('No suitable content container found');
|
|
6049
6097
|
}
|
|
6050
6098
|
}
|
|
6099
|
+
if (headerRef) {
|
|
6100
|
+
const headerElement = headerRef.location.nativeElement;
|
|
6101
|
+
const headerSlotContainer = modalRef.location.nativeElement.querySelector('.c-modal__content__header__slot');
|
|
6102
|
+
if (headerSlotContainer) {
|
|
6103
|
+
headerSlotContainer.appendChild(headerElement);
|
|
6104
|
+
}
|
|
6105
|
+
else {
|
|
6106
|
+
console.error('Header slot container not found in modal');
|
|
6107
|
+
}
|
|
6108
|
+
}
|
|
6051
6109
|
}, 10);
|
|
6052
6110
|
return modalRefResult;
|
|
6053
6111
|
}
|
|
@@ -6056,15 +6114,21 @@ class ModalService {
|
|
|
6056
6114
|
if (!entry) {
|
|
6057
6115
|
return;
|
|
6058
6116
|
}
|
|
6059
|
-
const { modalRef, contentRef, resolvePromise, result } = entry;
|
|
6117
|
+
const { modalRef, contentRef, headerRef, resolvePromise, result } = entry;
|
|
6060
6118
|
modalRef.instance.setOpen(false);
|
|
6061
6119
|
this.openModals.delete(modalRefResult);
|
|
6062
6120
|
// Wait for animation to complete before destroying
|
|
6063
6121
|
setTimeout(() => {
|
|
6064
6122
|
this.appRef.detachView(modalRef.hostView);
|
|
6065
6123
|
this.appRef.detachView(contentRef.hostView);
|
|
6124
|
+
if (headerRef) {
|
|
6125
|
+
this.appRef.detachView(headerRef.hostView);
|
|
6126
|
+
}
|
|
6066
6127
|
modalRef.destroy();
|
|
6067
6128
|
contentRef.destroy();
|
|
6129
|
+
if (headerRef) {
|
|
6130
|
+
headerRef.destroy();
|
|
6131
|
+
}
|
|
6068
6132
|
resolvePromise(result);
|
|
6069
6133
|
}, 200);
|
|
6070
6134
|
}
|