diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/backoffice-modal-container/backoffice-modal-container.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/backoffice-modal-container/backoffice-modal-container.element.ts index 71c9b4c005..6a3195706e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/components/backoffice-modal-container/backoffice-modal-container.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/components/backoffice-modal-container/backoffice-modal-container.element.ts @@ -1,13 +1,8 @@ import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; -import type { CSSResultGroup} from '@umbraco-cms/backoffice/external/lit'; -import { css, html, repeat, customElement, state } from '@umbraco-cms/backoffice/external/lit'; -import type { - UmbModalManagerContext, - UmbModalContext} from '@umbraco-cms/backoffice/modal'; -import { - UMB_MODAL_MANAGER_CONTEXT, - UmbModalElement -} from '@umbraco-cms/backoffice/modal'; +import type { CSSResultGroup } from '@umbraco-cms/backoffice/external/lit'; +import { css, html, repeat, customElement, state, nothing } from '@umbraco-cms/backoffice/external/lit'; +import type { UmbModalManagerContext, UmbModalContext } from '@umbraco-cms/backoffice/modal'; +import { UMB_MODAL_MANAGER_CONTEXT, UmbModalElement } from '@umbraco-cms/backoffice/modal'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; @customElement('umb-backoffice-modal-container') @@ -24,6 +19,7 @@ export class UmbBackofficeModalContainerElement extends UmbLitElement { super(); this.consumeContext(UMB_MODAL_MANAGER_CONTEXT, (instance) => { + //TODO: This is being called way to many times if first page load includes an open modal. this._modalManager = instance; this._observeModals(); }); @@ -31,14 +27,24 @@ export class UmbBackofficeModalContainerElement extends UmbLitElement { private _observeModals() { if (!this._modalManager) return; - this.observe(this._modalManager.modals, (modals) => this.#createModalElements(modals)); + this.observe(this._modalManager.modals, (modals) => { + this.#createModalElements(modals); + }); } /** We cannot render the umb-modal element directly in the uui-modal-container because it wont get recognized by UUI. * We therefore have a helper class which creates the uui-modal element and returns it. */ #createModalElements(modals: Array) { + const oldValue = this._modals; this._modals = modals; + const oldModals = oldValue.filter((oldModal) => !modals.some((modal) => modal.key === oldModal.key)); + + oldModals.forEach((modal) => { + this._modalElementMap.get(modal.key)?.removeEventListener('close-end', this.#onCloseEnd.bind(this, modal.key)); + this._modalElementMap.delete(modal.key); + }); + if (this._modals.length === 0) { this._modalElementMap.clear(); return; @@ -50,15 +56,21 @@ export class UmbBackofficeModalContainerElement extends UmbLitElement { const modalElement = new UmbModalElement(); modalElement.modalContext = modal; - modalElement.element?.addEventListener('close-end', () => this._modalManager?.remove(modal.key)); + modalElement.element?.addEventListener('close-end', this.#onCloseEnd.bind(this, modal.key)); this._modalElementMap.set(modal.key, modalElement); + this.requestUpdate(); }); } + #onCloseEnd(key: string) { + this._modalManager?.remove(key); + } + #renderModal(key: string) { const modalElement = this._modalElementMap.get(key); - if (!modalElement) return; + if (!modalElement) return nothing; + return modalElement.render(); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/modal.element.ts index 6d490d3c69..8f7affa2e2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/modal.element.ts @@ -1,22 +1,23 @@ import type { UmbModalContext } from './modal.context.js'; import { UMB_MODAL_CONTEXT } from './modal.context.js'; -import type { ManifestModal} from '@umbraco-cms/backoffice/extension-registry'; +import type { ManifestModal } from '@umbraco-cms/backoffice/extension-registry'; import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; -import type { CSSResultGroup} from '@umbraco-cms/backoffice/external/lit'; +import type { CSSResultGroup } from '@umbraco-cms/backoffice/external/lit'; import { html, customElement } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; import { BehaviorSubject } from '@umbraco-cms/backoffice/external/rxjs'; import type { UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; -import type { UUIDialogElement, UUIModalDialogElement, UUIModalSidebarElement } from '@umbraco-cms/backoffice/external/uui'; +import { + UUIModalCloseEvent, + type UUIDialogElement, + type UUIModalDialogElement, + type UUIModalSidebarElement, +} from '@umbraco-cms/backoffice/external/uui'; import type { UmbRouterSlotElement } from '@umbraco-cms/backoffice/router'; import { createExtensionElement } from '@umbraco-cms/backoffice/extension-api'; -import type { - UmbContextRequestEvent} from '@umbraco-cms/backoffice/context-api'; -import { - UMB_CONTENT_REQUEST_EVENT_TYPE, - UmbContextProvider -} from '@umbraco-cms/backoffice/context-api'; +import type { UmbContextRequestEvent } from '@umbraco-cms/backoffice/context-api'; +import { UMB_CONTENT_REQUEST_EVENT_TYPE, UmbContextProvider } from '@umbraco-cms/backoffice/context-api'; @customElement('umb-modal') export class UmbModalElement extends UmbLitElement { @@ -42,10 +43,19 @@ export class UmbModalElement extends UmbLitElement { #modalExtensionObserver?: UmbObserverController; #modalRouterElement: UmbRouterSlotElement = document.createElement('umb-router-slot'); + #onClose = () => { + this.element?.removeEventListener(UUIModalCloseEvent, this.#onClose); + this.#modalContext?.reject({ type: 'close' }); + }; + #createModalElement() { if (!this.#modalContext) return; this.element = this.#createContainerElement(); + + // Makes sure that the modal triggers the reject of the context promise when it is closed by pressing escape. + this.element.addEventListener(UUIModalCloseEvent, this.#onClose); + if (this.#modalContext.originTarget) { // The following code is the context api proxy. // It re-dispatches the context api request event to the origin target of this modal, in other words the element that initiated the modal.