P8-Panels/app/components/p8p_header/p8p_header_hooks.js

122 lines
5.3 KiB
JavaScript
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.

/*
Парус 8 - Панели мониторинга - Заголовок
Хуки для заголовка
*/
//---------------------
//Подключение библиотек
//---------------------
import { useState, useEffect, useCallback, useRef, useMemo } from "react"; //Классы React
import { P8P_HEADER_MIN_FILTER_WIDTH } from "./p8p_header_constants"; //Константы заголовка
//-----------
//Тело модуля
//-----------
//Кастомный хук для определения информации об отображении
const useP8PHeaderVisibleInfo = (containerRef, maxDisplay, totalFilters) => {
//Отображаемое количество
const [visibleCount, setVisibleCount] = useState(maxDisplay > 0 ? maxDisplay : 0);
//Признак переполненности
const [isOverflowed, setIsOverflowed] = useState(false);
//Признак уменьшения меньше минимального значения
const [isLessMinWidth, setIsLessMinWidth] = useState(false);
//Пересчет количество отображаемых
const recalcVisibleCount = useCallback(container => {
//Определяем дочерние элементы
const items = container.children;
//Определяем параметры контейнера
const containerRect = container.getBoundingClientRect();
//Если блок меньше минимального значения
if (containerRect.width < P8P_HEADER_MIN_FILTER_WIDTH && items.length > 0) {
//Информируем, что невозможно показать
setVisibleCount(0);
setIsOverflowed(true);
setIsLessMinWidth(true);
return;
}
//Обнуляем счетчик видимых
let visible = 0;
//Обходим дочерние элменты
for (let i = 0; i < items.length; i++) {
//Определяем параметры элемента
const itemRect = items[i].getBoundingClientRect();
//Проверяем, полностью ли элемент виден в контейнере
if (itemRect.bottom <= containerRect.bottom) {
visible++;
} else {
//Если один элемент скрыт, то и все последующие скрыты (при row-direction)
break;
}
}
//Устанавливаем отображаемых
setVisibleCount(visible);
setIsOverflowed(visible < items.length);
setIsLessMinWidth(false);
}, []);
//При открытии страницы
useEffect(() => {
//Определяем контейнер
const container = containerRef.current;
//Если контейнер не определен или установлено максимально отображение - не отслеживаем
if (!container || maxDisplay > 0) {
setIsOverflowed(maxDisplay < totalFilters);
return;
}
//Пересчет количество отображаемых
recalcVisibleCount(container);
//Определяем отслеживание
const observer = new ResizeObserver(() => {
//Пересчет количество отображаемых
recalcVisibleCount(container);
});
//Подключаем отслеживание
observer.observe(container);
//При закрытии компонента
return () => observer.disconnect();
}, [containerRef, maxDisplay, recalcVisibleCount, totalFilters]);
//Возвращаем данные
return { visibleCount, isOverflowed, isLessMinWidth };
};
//Хук состояния фильтра
const useP8PHeaderFilter = ({ filters, maxDisplay }) => {
//Собственное состояние - контейнер элементов
const gridRef = useRef(null);
//Собственное состояние - элемент выпадающего списка
const [anchorEl, setAnchorEl] = useState(null);
//Собственное состояние - информация об отображении
const { visibleCount, isOverflowed, isLessMinWidth } = useP8PHeaderVisibleInfo(gridRef, maxDisplay, filters.length);
//Отображаемые фильтры
const allowedFilters = useMemo(() => {
if (Array.isArray(filters) && filters.length > 0) {
return filters.slice(0, maxDisplay || filters.length);
} else {
return [];
}
}, [filters, maxDisplay]);
//По нажатию на меню скрытых элементов
const handleFilterMoreOpen = event => {
setAnchorEl(event.currentTarget);
};
//При закрытии меню скрытых элементов
const handleFilterMoreClose = () => {
setAnchorEl(null);
};
return { gridRef, anchorEl, allowedFilters, visibleCount, isOverflowed, isLessMinWidth, handleFilterMoreOpen, handleFilterMoreClose };
};
//----------------
//Интерфейс модуля
//----------------
export { useP8PHeaderFilter };