diff --git a/package.json b/package.json index 902e321..4cdccfa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tp/tp-dialog", - "version": "1.4.0", + "version": "1.5.0", "description": "", "main": "tp-dialog.js", "scripts": { diff --git a/tp-dialog.js b/tp-dialog.js index d70338a..0f8e4f9 100644 --- a/tp-dialog.js +++ b/tp-dialog.js @@ -9,6 +9,21 @@ import { LitElement, html, css, svg } from 'lit'; import { EventHelpers } from '@tp/helpers/event-helpers.js'; import { closest } from '@tp/helpers/closest.js'; +// Global stack to track opened dialogs with closeOnEsc +const dialogStack = []; +let escKeyListener = null; + +// Global escape key handler +function handleGlobalEscKey(event) { + if (event.key === 'Escape' && dialogStack.length > 0) { + // Get the most recently opened dialog + const lastDialog = dialogStack[dialogStack.length - 1]; + if (lastDialog && lastDialog.closeOnEsc) { + lastDialog.close(); + } + } +} + class TpDialog extends EventHelpers(LitElement) { static get styles() { return [ @@ -83,7 +98,6 @@ class TpDialog extends EventHelpers(LitElement) { constructor() { super(); - this._handleEscKey = this._handleEscKey.bind(this); this._currentPromise = null; this._resolvePromise = null; } @@ -103,9 +117,8 @@ class TpDialog extends EventHelpers(LitElement) { this.unlisten(this, 'confirmed', '_handleConfirmed'); this.unlisten(this, 'dismissed', '_handleDismissed'); - if (this.closeOnEsc) { - document.removeEventListener('keydown', this._handleEscKey); - } + // Remove this dialog from the stack + this._removeFromDialogStack(); // Clean up promise if dialog is removed while open if (this._currentPromise && this._resolvePromise) { @@ -119,9 +132,8 @@ class TpDialog extends EventHelpers(LitElement) { this.dialog.show(); this.open = true; - if (this.closeOnEsc) { - document.addEventListener('keydown', this._handleEscKey, { once: true }); - } + // Add to dialog stack if closeOnEsc is enabled + this._addToDialogStack(); // Create and return a new promise this._currentPromise = new Promise((resolve) => { @@ -135,9 +147,8 @@ class TpDialog extends EventHelpers(LitElement) { this.dialog.showModal(); this.open = true; - if (this.closeOnEsc) { - document.addEventListener('keydown', this._handleEscKey, { once: true }); - } + // Add to dialog stack if closeOnEsc is enabled + this._addToDialogStack(); if (this.closeOnOutsideClick) { this.addEventListener('click', this._handleOutsideClick, { once: true }); @@ -161,6 +172,9 @@ class TpDialog extends EventHelpers(LitElement) { this.dispatchEvent(new CustomEvent('closed', { detail: null, bubbles: true, composed: true })); this.open = false; + // Remove from dialog stack + this._removeFromDialogStack(); + // If closed without explicit confirm/dismiss (like ESC key), treat as dismissed if (this._currentPromise && this._resolvePromise) { this._resolvePromise('dismissed'); @@ -185,6 +199,35 @@ class TpDialog extends EventHelpers(LitElement) { } } + _addToDialogStack() { + if (this.closeOnEsc) { + // Remove if already in stack (shouldn't happen, but just in case) + this._removeFromDialogStack(); + + // Add to the end of the stack + dialogStack.push(this); + + // Set up global listener if this is the first dialog + if (dialogStack.length === 1 && !escKeyListener) { + escKeyListener = handleGlobalEscKey; + document.addEventListener('keydown', escKeyListener); + } + } + } + + _removeFromDialogStack() { + const index = dialogStack.indexOf(this); + if (index > -1) { + dialogStack.splice(index, 1); + + // Remove global listener if no more dialogs with closeOnEsc + if (dialogStack.length === 0 && escKeyListener) { + document.removeEventListener('keydown', escKeyListener); + escKeyListener = null; + } + } + } + _onDialogClick(event) { if (this.closeOnOutsideClick) { const path = event.composedPath(); @@ -217,10 +260,10 @@ class TpDialog extends EventHelpers(LitElement) { } } - _handleEscKey(event) { - if (event.key === 'Escape' && this.closeOnEsc) { - this.close(); - } + _handleOutsideClick(event) { + // This method should be implemented if closeOnOutsideClick functionality is needed + // For now, just close the dialog when clicking outside + this.close(); } }