feat: Удаление устаревших файлов документации и оптимизация структуры проекта. Упрощение кода и улучшение читаемости за счет удаления ненужных компонентов и отчетов, что способствует более эффективному управлению проектом.
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m34s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m34s
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
import { useState, useCallback, useEffect } from 'react';
|
||||
|
||||
/**
|
||||
* Хук для управления состоянием модального окна
|
||||
* Упрощает работу с открытием/закрытием модалок
|
||||
*/
|
||||
export function useModal(initialState = false) {
|
||||
const [isOpen, setIsOpen] = useState(initialState);
|
||||
|
||||
const open = useCallback(() => {
|
||||
setIsOpen(true);
|
||||
}, []);
|
||||
|
||||
const close = useCallback(() => {
|
||||
setIsOpen(false);
|
||||
}, []);
|
||||
|
||||
const toggle = useCallback(() => {
|
||||
setIsOpen(prev => !prev);
|
||||
}, []);
|
||||
|
||||
return {
|
||||
isOpen,
|
||||
open,
|
||||
close,
|
||||
toggle,
|
||||
setIsOpen
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Хук для управления ESC и клавиатурной навигацией в модалках
|
||||
*/
|
||||
export function useModalKeyboard(isOpen, onClose) {
|
||||
useEffect(() => {
|
||||
if (!isOpen) return;
|
||||
|
||||
const handleEscape = (e) => {
|
||||
if (e.key === 'Escape') {
|
||||
onClose?.();
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('keydown', handleEscape);
|
||||
return () => document.removeEventListener('keydown', handleEscape);
|
||||
}, [isOpen, onClose]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Хук для управления классом modal-open на body
|
||||
*/
|
||||
export function useModalBodyClass(isOpen) {
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
document.body.classList.add('modal-open');
|
||||
} else {
|
||||
document.body.classList.remove('modal-open');
|
||||
}
|
||||
|
||||
return () => {
|
||||
document.body.classList.remove('modal-open');
|
||||
};
|
||||
}, [isOpen]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Хук для управления focus trap внутри модалки
|
||||
*/
|
||||
export function useFocusTrap(isOpen, containerRef) {
|
||||
useEffect(() => {
|
||||
if (!isOpen || !containerRef.current) return;
|
||||
|
||||
const container = containerRef.current;
|
||||
const focusableElements = container.querySelectorAll(
|
||||
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
|
||||
);
|
||||
|
||||
if (focusableElements.length === 0) return;
|
||||
|
||||
const firstElement = focusableElements[0];
|
||||
const lastElement = focusableElements[focusableElements.length - 1];
|
||||
|
||||
// Фокус на первый элемент при открытии
|
||||
firstElement?.focus();
|
||||
|
||||
const handleTabKey = (e) => {
|
||||
if (e.key !== 'Tab') return;
|
||||
|
||||
if (e.shiftKey) {
|
||||
// Shift + Tab
|
||||
if (document.activeElement === firstElement) {
|
||||
e.preventDefault();
|
||||
lastElement?.focus();
|
||||
}
|
||||
} else {
|
||||
// Tab
|
||||
if (document.activeElement === lastElement) {
|
||||
e.preventDefault();
|
||||
firstElement?.focus();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
container.addEventListener('keydown', handleTabKey);
|
||||
return () => container.removeEventListener('keydown', handleTabKey);
|
||||
}, [isOpen, containerRef]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Комплексный хук, объединяющий все хуки для модалок
|
||||
*/
|
||||
export function useModalManager(initialState = false) {
|
||||
const modal = useModal(initialState);
|
||||
|
||||
return {
|
||||
...modal,
|
||||
// Дополнительные утилиты
|
||||
openWithData: (data) => {
|
||||
modal.setData?.(data);
|
||||
modal.open();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default useModal;
|
||||
|
||||
Reference in New Issue
Block a user