refactor(calendar): форма создания/редактирования конференции — в модальное окно
Раньше ConferenceFormCard всегда висела в сайдбаре двухколоночной сетки .layout-grid; теперь открывается в модалке (по образцу ConferenceOccurrenceDialog: modal-overlay/modal-panel, закрытие по клику на оверлей, Escape и возврат фокуса — новый общий хук useModalDismiss). .layout-grid стала одноколоночной — календарь занимает всю ширину.
This commit is contained in:
32
frontend/src/hooks/useModalDismiss.ts
Normal file
32
frontend/src/hooks/useModalDismiss.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
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()
|
||||
}
|
||||
}, [])
|
||||
}
|
||||
Reference in New Issue
Block a user