From 46e36287b07760daa27f4f84cf8a4a5ce0c3fb94 Mon Sep 17 00:00:00 2001 From: gerjanvangeest Date: Wed, 3 Jul 2024 16:19:00 +0200 Subject: [PATCH] fix(overlays): prevent closing of a modal dialog on pressing Esc and hidesOnEsc is set to false --- .changeset/poor-bears-beam.md | 5 ++++ .../systems/overlays/configuration.md | 28 ++++++++++++++++++- .../overlays/src/OverlayController.js | 16 +++++++++++ .../overlays/test/OverlayController.test.js | 11 ++++++++ 4 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 .changeset/poor-bears-beam.md diff --git a/.changeset/poor-bears-beam.md b/.changeset/poor-bears-beam.md new file mode 100644 index 0000000000..ae2a48815b --- /dev/null +++ b/.changeset/poor-bears-beam.md @@ -0,0 +1,5 @@ +--- +'@lion/ui': patch +--- + +[overlays] prevent closing of a modal dialog on pressing Esc and hidesOnEsc is set to false diff --git a/docs/fundamentals/systems/overlays/configuration.md b/docs/fundamentals/systems/overlays/configuration.md index ce41d40c0c..f34c9b05bd 100644 --- a/docs/fundamentals/systems/overlays/configuration.md +++ b/docs/fundamentals/systems/overlays/configuration.md @@ -4,7 +4,7 @@ import { html } from '@mdjs/mdjs-preview'; import './assets/demo-el-using-overlaymixin.mjs'; import './assets/applyDemoOverlayStyles.mjs'; -import { withDropdownConfig, withTooltipConfig } from '@lion/ui/overlays.js'; +import { withDropdownConfig, withModalDialogConfig, withTooltipConfig } from '@lion/ui/overlays.js'; ``` The `OverlayController` has many configuration options. @@ -145,6 +145,32 @@ export const hidesOnEsc = () => { }; ``` +And how it works if `hidesOnEsc` is disabled. In most cases `hidesOnOutsideEsc` needs also to be set to `false`. + +```js preview-story +export const hidesOnEscFalse = () => { + const hidesOnEscConfig = { + ...withModalDialogConfig(), + hidesOnEsc: false, + hidesOnOutsideEsc: false, + }; + return html` + + +
+ Hello! You can close this notification here: + +
+
+ `; +}; +``` + ## hidesOnOutsideEsc Boolean property. When enabled allows closing the overlay on ESC key, even when contentNode has no focus. diff --git a/packages/ui/components/overlays/src/OverlayController.js b/packages/ui/components/overlays/src/OverlayController.js index c2801589b5..6a6f13d692 100644 --- a/packages/ui/components/overlays/src/OverlayController.js +++ b/packages/ui/components/overlays/src/OverlayController.js @@ -201,6 +201,8 @@ export class OverlayController extends EventTarget { this.__hasActiveBackdrop = true; /** @private */ this.__escKeyHandler = this.__escKeyHandler.bind(this); + /** @private */ + this.__cancelHandler = this.__cancelHandler.bind(this); } /** @@ -510,6 +512,8 @@ export class OverlayController extends EventTarget { this.__contentHasBeenInitialized = true; } + this.__wrappingDialogNode?.addEventListener('cancel', this.__cancelHandler); + // Reset all positioning styles (local, c.q. Popper) and classes (global) this.contentWrapperNode.removeAttribute('style'); this.contentWrapperNode.removeAttribute('class'); @@ -1126,6 +1130,17 @@ export class OverlayController extends EventTarget { } } + /** + * When the overlay is a modal dialog hidesOnEsc works out of the box, so we prevent that. + * + * There is currently a bug in chrome that makes the dialog close when pressing Esc the second time + * @private + */ + // eslint-disable-next-line class-methods-use-this + __cancelHandler(/** @type {Event} */ ev) { + ev.preventDefault(); + } + /** @private */ __escKeyHandler(/** @type {KeyboardEvent} */ ev) { return ev.key === 'Escape' && this.hide(); @@ -1292,6 +1307,7 @@ export class OverlayController extends EventTarget { teardown() { this.__handleOverlayStyles({ phase: 'teardown' }); this._handleFeatures({ phase: 'teardown' }); + this.__wrappingDialogNode?.removeEventListener('cancel', this.__cancelHandler); } /** @private */ diff --git a/packages/ui/components/overlays/test/OverlayController.test.js b/packages/ui/components/overlays/test/OverlayController.test.js index 277efc8d1a..9c5c01cf4a 100644 --- a/packages/ui/components/overlays/test/OverlayController.test.js +++ b/packages/ui/components/overlays/test/OverlayController.test.js @@ -585,6 +585,17 @@ describe('OverlayController', () => { expect(ctrl.isShown).to.be.false; }); + it("doesn't hide when [escape] is pressed and hidesOnEsc is set to false", async () => { + const ctrl = new OverlayController({ + ...withGlobalTestConfig(), + hidesOnEsc: false, + }); + await ctrl.show(); + ctrl.contentNode.dispatchEvent(new KeyboardEvent('keyup', { key: 'Escape' })); + await aTimeout(0); + expect(ctrl.isShown).to.be.true; + }); + it('stays shown when [escape] is pressed on outside element', async () => { const ctrl = new OverlayController({ ...withGlobalTestConfig(),