mirror of
https://github.com/nianzhibai/91.git
synced 2026-06-15 08:45:41 +08:00
Fix admin modal focus reset
This commit is contained in:
+9
-3
@@ -12,8 +12,13 @@ type Props = {
|
||||
|
||||
export function Modal({ open, title, onClose, children, footer, className = "" }: Props) {
|
||||
const dialogRef = useRef<HTMLDivElement>(null);
|
||||
const onCloseRef = useRef(onClose);
|
||||
const titleId = useId();
|
||||
|
||||
useEffect(() => {
|
||||
onCloseRef.current = onClose;
|
||||
}, [onClose]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
const previousFocus =
|
||||
@@ -25,7 +30,7 @@ export function Modal({ open, title, onClose, children, footer, className = "" }
|
||||
|
||||
if (e.key === "Escape") {
|
||||
e.preventDefault();
|
||||
onClose();
|
||||
onCloseRef.current();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -51,7 +56,7 @@ export function Modal({ open, title, onClose, children, footer, className = "" }
|
||||
}
|
||||
}
|
||||
|
||||
window.setTimeout(() => {
|
||||
const focusTimer = window.setTimeout(() => {
|
||||
const dialog = dialogRef.current;
|
||||
if (!dialog || !isTopDialog(dialog)) return;
|
||||
const first = getFocusableElements(dialog)[0];
|
||||
@@ -60,12 +65,13 @@ export function Modal({ open, title, onClose, children, footer, className = "" }
|
||||
|
||||
document.addEventListener("keydown", onKeyDown);
|
||||
return () => {
|
||||
window.clearTimeout(focusTimer);
|
||||
document.removeEventListener("keydown", onKeyDown);
|
||||
if (previousFocus?.isConnected) {
|
||||
previousFocus.focus();
|
||||
}
|
||||
};
|
||||
}, [open, onClose]);
|
||||
}, [open]);
|
||||
|
||||
if (!open) return null;
|
||||
return (
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { readFileSync } from "node:fs";
|
||||
import test from "node:test";
|
||||
|
||||
const modalSource = readFileSync(
|
||||
new URL("../src/admin/Modal.tsx", import.meta.url),
|
||||
"utf8"
|
||||
);
|
||||
|
||||
test("admin modal does not reset focus when close handler identity changes", () => {
|
||||
assert.match(modalSource, /const onCloseRef = useRef\(onClose\);/);
|
||||
assert.match(modalSource, /onCloseRef\.current = onClose;/);
|
||||
assert.match(modalSource, /onCloseRef\.current\(\);/);
|
||||
assert.match(modalSource, /window\.clearTimeout\(focusTimer\);/);
|
||||
assert.match(modalSource, /\}, \[open\]\);/);
|
||||
assert.doesNotMatch(modalSource, /\}, \[open, onClose\]\);/);
|
||||
});
|
||||
Reference in New Issue
Block a user