Files
vidconf/frontend/src/hooks/useModalDismiss.ts
Max Ronzhin 07e5aba9c9 refactor(calendar): форма создания/редактирования конференции — в модальное окно
Раньше ConferenceFormCard всегда висела в сайдбаре двухколоночной сетки
.layout-grid; теперь открывается в модалке (по образцу
ConferenceOccurrenceDialog: modal-overlay/modal-panel, закрытие по клику на
оверлей, Escape и возврат фокуса — новый общий хук useModalDismiss).
.layout-grid стала одноколоночной — календарь занимает всю ширину.
2026-07-26 23:33:52 +03:00

33 lines
1.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useEffect, useRef } from 'react'
/**
* Общее поведение модалок оболочки (`.modal-overlay`/`.modal-panel`):
* закрытие по Escape и возврат фокуса на элемент, который был активен до
* открытия модалки (обычно кнопка, её вызвавшая) — доступность по клавиатуре.
*/
export function useModalDismiss(onClose: () => void) {
const previouslyFocused = useRef<Element | null>(null)
// Всегда актуальный колбэк без пересоздания подписки на keydown при каждом
// рендере (onClose у вызывающих обычно инлайновая функция). Синхронизация —
// отдельным эффектом (не прямым присваиванием в теле рендера, см.
// react-hooks/refs — рефы нельзя трогать во время рендера).
const onCloseRef = useRef(onClose)
useEffect(() => {
onCloseRef.current = onClose
})
useEffect(() => {
previouslyFocused.current = document.activeElement
function handleKeyDown(e: KeyboardEvent) {
if (e.key === 'Escape') onCloseRef.current()
}
document.addEventListener('keydown', handleKeyDown)
return () => {
document.removeEventListener('keydown', handleKeyDown)
if (previouslyFocused.current instanceof HTMLElement) previouslyFocused.current.focus()
}
}, [])
}