([])
@@ -436,23 +428,11 @@ function PermissionsModal({ isOpen, onClose, user, proxyHosts }: PermissionsModa
}
}, [user])
- // Keyboard navigation - close on Escape
const handleClose = useCallback(() => {
onClose()
}, [onClose])
- useEffect(() => {
- const handleKeyDown = (e: KeyboardEvent) => {
- if (e.key === 'Escape') {
- handleClose()
- }
- }
-
- if (isOpen) {
- document.addEventListener('keydown', handleKeyDown)
- return () => document.removeEventListener('keydown', handleKeyDown)
- }
- }, [isOpen, handleClose])
+ useFocusTrap(dialogRef, isOpen, handleClose)
const updatePermissionsMutation = useMutation({
mutationFn: async () => {
@@ -492,6 +472,7 @@ function PermissionsModal({ isOpen, onClose, user, proxyHosts }: PermissionsModa
{/* Layer 3: Form content (pointer-events-auto) */}
{
- if (!isOpen) return
-
- const handleKeyDown = (e: KeyboardEvent) => {
- if (e.key === 'Escape') {
- onClose()
- return
- }
- // Focus trap
- if (e.key === 'Tab' && dialogRef.current) {
- const focusable = dialogRef.current.querySelectorAll(
- 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
- )
- if (focusable.length === 0) return
- const first = focusable[0]
- const last = focusable[focusable.length - 1]
- if (e.shiftKey && document.activeElement === first) {
- e.preventDefault()
- last.focus()
- } else if (!e.shiftKey && document.activeElement === last) {
- e.preventDefault()
- first.focus()
- }
- }
- }
-
- document.addEventListener('keydown', handleKeyDown)
- // Focus first focusable element on open
- requestAnimationFrame(() => {
- const first = dialogRef.current?.querySelector(
- 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
- )
- first?.focus()
- })
-
- return () => document.removeEventListener('keydown', handleKeyDown)
- }, [isOpen, onClose])
+ useFocusTrap(dialogRef, isOpen, onClose)
const profileMutation = useMutation({
mutationFn: async () => {