New source found from dndbeyond.com
This commit is contained in:
+30
-11
@@ -40,6 +40,12 @@ export const Dialog: React.FC<DialogProps> = ({
|
||||
const handleClickBackdrop = (e?: MouseEvent) => {
|
||||
if (!e) return;
|
||||
|
||||
// Keyboard-triggered clicks (e.g. pressing Enter on a button) report
|
||||
// clientX/clientY as 0, which falls outside the dialog rect and would
|
||||
// incorrectly be treated as a backdrop click.
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail
|
||||
if (e.detail === 0) return;
|
||||
|
||||
const rect = dialogRef.current?.getBoundingClientRect();
|
||||
const isClickInDialog =
|
||||
rect &&
|
||||
@@ -49,17 +55,14 @@ export const Dialog: React.FC<DialogProps> = ({
|
||||
e.clientX <= rect.left + rect.width;
|
||||
|
||||
if (!isClickInDialog) {
|
||||
// Stop the click from bubbling to a parent dialog's backdrop handler,
|
||||
// so only the innermost dialog closes when its backdrop is clicked.
|
||||
e.stopPropagation();
|
||||
onBackdropClick?.();
|
||||
handleClose();
|
||||
}
|
||||
};
|
||||
|
||||
const handleEsc = (e: KeyboardEvent) => {
|
||||
if (e.key === "Escape" && open) {
|
||||
handleClose();
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
// Get the element that was clicked to open the dialog
|
||||
@@ -78,11 +81,27 @@ export const Dialog: React.FC<DialogProps> = ({
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
document.addEventListener("keydown", handleEsc);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("keydown", handleEsc);
|
||||
};
|
||||
if (modal) {
|
||||
// The native cancel event is only fired for modal dialogs opened via
|
||||
// showModal(). The browser adds its own Escape key listener and ensures
|
||||
// the cancel event only fires on the topmost modal, so stacked dialogs
|
||||
// close one at a time.
|
||||
const dialog = dialogRef.current;
|
||||
const handleCancel = (e: Event) => {
|
||||
e.preventDefault();
|
||||
handleClose();
|
||||
};
|
||||
dialog?.addEventListener("cancel", handleCancel);
|
||||
return () => dialog?.removeEventListener("cancel", handleCancel);
|
||||
} else {
|
||||
// Non-modal dialogs don't receive the cancel event, so we fall back to
|
||||
// a document-level keydown listener.
|
||||
const handleEsc = (e: KeyboardEvent) => {
|
||||
if (e.key === "Escape" && open) handleClose();
|
||||
};
|
||||
document.addEventListener("keydown", handleEsc);
|
||||
return () => document.removeEventListener("keydown", handleEsc);
|
||||
}
|
||||
},
|
||||
//eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[modal, open],
|
||||
|
||||
Reference in New Issue
Block a user