#55: Add SuccessToast after new resource is created. ResourceModal gains an optional onSuccess(displayName) prop; ResourcesClient wires it to a toast that auto-dismisses after 2.5 s. #56: Fix useFocusTrap stale-closure bug. Focusable elements are now queried dynamically inside handleKeyDown (not captured once at mount), so Tab navigation stays correct as the form re-renders. Initial focus is deferred via requestAnimationFrame so the browser layout is stable before focus() fires. Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
@@ -8,16 +8,22 @@ export function useFocusTrap(ref: React.RefObject<HTMLElement | null>, isOpen: b
|
||||
if (!isOpen || !ref.current) return;
|
||||
const el = ref.current;
|
||||
|
||||
const focusable = Array.from(el.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR));
|
||||
const first = focusable[0];
|
||||
const last = focusable[focusable.length - 1];
|
||||
|
||||
// Focus first element when modal opens
|
||||
first?.focus();
|
||||
// Defer initial focus to the next animation frame so the browser layout is
|
||||
// complete before we attempt to focus — prevents intermittent failures when
|
||||
// the modal DOM has just been mounted.
|
||||
const rafId = requestAnimationFrame(() => {
|
||||
const focusable = Array.from(el.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR));
|
||||
focusable[0]?.focus();
|
||||
});
|
||||
|
||||
function handleKeyDown(e: KeyboardEvent) {
|
||||
if (e.key !== "Tab") return;
|
||||
// Re-query on every keydown so the list is always current — form state can
|
||||
// toggle disabled attributes and add/remove sections during a session.
|
||||
const focusable = Array.from(el.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR));
|
||||
if (focusable.length === 0) { e.preventDefault(); return; }
|
||||
const first = focusable[0];
|
||||
const last = focusable[focusable.length - 1];
|
||||
if (e.shiftKey) {
|
||||
if (document.activeElement === first) { e.preventDefault(); last?.focus(); }
|
||||
} else {
|
||||
@@ -26,6 +32,9 @@ export function useFocusTrap(ref: React.RefObject<HTMLElement | null>, isOpen: b
|
||||
}
|
||||
|
||||
el.addEventListener("keydown", handleKeyDown);
|
||||
return () => el.removeEventListener("keydown", handleKeyDown);
|
||||
return () => {
|
||||
cancelAnimationFrame(rafId);
|
||||
el.removeEventListener("keydown", handleKeyDown);
|
||||
};
|
||||
}, [isOpen, ref]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user