From 7f2f4442c7a05e61b34c9c66048a5e243aa6f670 Mon Sep 17 00:00:00 2001 From: wanxiankai Date: Tue, 14 Jul 2026 09:28:37 +0800 Subject: [PATCH] Fix keyboard event detection to use logical keys --- specs/Modal.events.spec.js | 29 +++++++++++++++++++++++------ specs/helper.js | 17 ++++++++++------- src/components/ModalPortal.js | 6 +++--- 3 files changed, 36 insertions(+), 16 deletions(-) diff --git a/specs/Modal.events.spec.js b/specs/Modal.events.spec.js index 8c9d5f2b..3382f180 100644 --- a/specs/Modal.events.spec.js +++ b/specs/Modal.events.spec.js @@ -11,9 +11,10 @@ import { mouseDownAt, mouseUpAt, escKeyDown, - escKeyDownWithCode, + escKeyDownWithKey, + nonEscKeyDownWithEscCode, tabKeyDown, - tabKeyDownWithCode, + tabKeyDownWithKey, withModal, withElementCollector, createHTMLElement @@ -111,7 +112,7 @@ export default () => { }); }); - it("traps tab in the modal on shift + tab with KeyboardEvent.code", () => { + it("traps tab in the modal on shift + tab with KeyboardEvent.key", () => { const topButton = ; const bottomButton = ; const modalContent = ( @@ -123,7 +124,7 @@ export default () => { const props = { isOpen: true }; withModal(props, modalContent, modal => { const content = mcontent(modal); - tabKeyDownWithCode(content, { shiftKey: true }); + tabKeyDownWithKey(content, { shiftKey: true }); document.activeElement.textContent.should.be.eql("bottom"); }); }); @@ -149,7 +150,7 @@ export default () => { ); }); - it("should close on Esc key event with KeyboardEvent.code", () => { + it("should close on Esc key event with KeyboardEvent.key", () => { const requestCloseCallback = sinon.spy(); withModal( { @@ -159,7 +160,7 @@ export default () => { }, null, modal => { - escKeyDownWithCode(mcontent(modal)); + escKeyDownWithKey(mcontent(modal)); requestCloseCallback.called.should.be.ok(); // Check if event is passed to onRequestClose callback. const event = requestCloseCallback.getCall(0).args[0]; @@ -167,6 +168,22 @@ export default () => { } ); }); + + it("should not close when Escape code represents another logical key", () => { + const requestCloseCallback = sinon.spy(); + withModal( + { + isOpen: true, + shouldCloseOnEsc: true, + onRequestClose: requestCloseCallback + }, + null, + modal => { + nonEscKeyDownWithEscCode(mcontent(modal)); + requestCloseCallback.called.should.be.false(); + } + ); + }); }); context("when false", () => { diff --git a/specs/helper.js b/specs/helper.js index 825b5510..204a5a14 100644 --- a/specs/helper.js +++ b/specs/helper.js @@ -192,7 +192,7 @@ const dispatchMockEvent = eventCtor => (key, code) => (element, opts) => const dispatchMockKeyDownEvent = dispatchMockEvent(Simulate.keyDown); /** - * @deprecated will be replaced by `escKeyDownWithCode` when `react-modal` + * @deprecated will be replaced by `escKeyDownWithKey` when `react-modal` * drops support for React <18. * * Dispatch an 'esc' key down event using the legacy KeyboardEvent.keyCode. @@ -201,11 +201,16 @@ export const escKeyDown = dispatchMockKeyDownEvent("ESC", { keyCode: 27 }); /** * Dispatch an 'esc' key down event. */ -export const escKeyDownWithCode = dispatchMockKeyDownEvent("ESC", { - code: "Escape" +export const escKeyDownWithKey = dispatchMockKeyDownEvent("Escape", {}); +/** + * Dispatch a non-escape logical key from the physical Escape key location. + */ +export const nonEscKeyDownWithEscCode = dispatchMockKeyDownEvent("Process", { + code: "Escape", + keyCode: 229 }); /** - * @deprecated will be replaced by `escKeyDownWithCode` when `react-modal` + * @deprecated will be replaced by `tabKeyDownWithKey` when `react-modal` * drops support for React <18. * * Dispatch a 'tab' key down event using the legacy KeyboardEvent.keyCode. @@ -214,9 +219,7 @@ export const tabKeyDown = dispatchMockKeyDownEvent("TAB", { keyCode: 9 }); /** * Dispatch a 'tab' key down event. */ -export const tabKeyDownWithCode = dispatchMockKeyDownEvent("TAB", { - code: "Tab" -}); +export const tabKeyDownWithKey = dispatchMockKeyDownEvent("Tab", {}); /** * Dispatch a 'click' event at a node. */ diff --git a/src/components/ModalPortal.js b/src/components/ModalPortal.js index 7f20df67..f909d5a8 100644 --- a/src/components/ModalPortal.js +++ b/src/components/ModalPortal.js @@ -19,11 +19,11 @@ const CLASS_NAMES = { /** * We need to support the deprecated `KeyboardEvent.keyCode` in addition to - * `KeyboardEvent.code` for apps that still support IE11. Can be removed when + * `KeyboardEvent.key` for apps that still support IE11. Can be removed when * `react-modal` only supports React >18 (which dropped IE support). */ -const isTabKey = event => event.code === "Tab" || event.keyCode === 9; -const isEscKey = event => event.code === "Escape" || event.keyCode === 27; +const isTabKey = event => event.key === "Tab" || event.keyCode === 9; +const isEscKey = event => event.key === "Escape" || event.keyCode === 27; let ariaHiddenInstances = 0;