UNPKG

@syncfusion/react-navigations

Version:

A package of Pure React navigation components such as Toolbar and Context-menu which is used to navigate from one page to another

127 lines (126 loc) 5.57 kB
import { jsx as _jsx } from "react/jsx-runtime"; import { useRef, useState, memo, useMemo, useCallback, forwardRef, useImperativeHandle, useEffect, Children } from 'react'; import { isVisible, isNullOrUndefined } from '@syncfusion/react-base'; import { Orientation } from './toolbar'; import { HScroll, VScroll } from '../common/index'; const CLS_ITEMS = 'sf-toolbar-items'; const CLS_HSCROLLBAR = 'sf-hscroll-bar'; const CLS_VSCROLLBAR = 'sf-vscroll-bar'; const CLS_HSCROLLCNT = 'sf-hscroll-content'; const CLS_VSCROLLCNT = 'sf-vscroll-content'; /** * ToolbarScrollable component that renders toolbar items with scrolling capability. * * This component manages the display of toolbar items that don't fit in the available space * by providing horizontal or vertical scrolling functionality. It automatically detects * when content overflows and renders appropriate scroll controls based on the toolbar's * orientation. */ const ToolbarScrollable = memo(forwardRef((props, ref) => { const { toolbarRef, orientation, scrollStep, children, className, onOverflowChange } = props; const resizeObserverRef = useRef(null); const previousChildrenCountRef = useRef(null); const resizeTimerRef = useRef(null); const [isOverflow, setIsOverflow] = useState(false); const [activeScrollStep, setActiveScrollStep] = useState(scrollStep); const getScrollCntEle = useCallback((itemsElement) => { return itemsElement.querySelector('.' + (orientation === Orientation.Vertical ? CLS_VSCROLLCNT : CLS_HSCROLLCNT)); }, [orientation]); const checkOverflow = useCallback(() => { let itemsOverflowing = false; if (toolbarRef.current && isVisible(toolbarRef.current)) { let itemsElement = toolbarRef.current.querySelector(`.${CLS_ITEMS}`); itemsElement = isOverflow ? getScrollCntEle(itemsElement) : itemsElement; const isVertical = orientation === Orientation.Vertical; const toolbarWidth = isVertical ? toolbarRef.current.offsetHeight : toolbarRef.current.offsetWidth; const itemsWidth = isVertical ? itemsElement.scrollHeight : itemsElement.scrollWidth; if (itemsWidth > toolbarWidth) { itemsOverflowing = true; } else { itemsOverflowing = false; } } return itemsOverflowing; }, [isOverflow, orientation, getScrollCntEle]); const resize = useCallback((updateScrollStep = true) => { if (toolbarRef.current) { if (resizeTimerRef.current) { clearTimeout(resizeTimerRef.current); } const isOverflowing = checkOverflow(); if (isOverflowing !== isOverflow) { setIsOverflow(isOverflowing); } if (isOverflowing && updateScrollStep) { resizeTimerRef.current = window.setTimeout(() => { if (toolbarRef.current) { const selector = orientation === Orientation.Vertical ? `.${CLS_VSCROLLBAR}` : `.${CLS_HSCROLLBAR}`; const scrollBar = toolbarRef.current.querySelector(selector); if (scrollBar) { setActiveScrollStep(orientation === Orientation.Vertical ? scrollBar.offsetHeight : scrollBar.offsetWidth); } } }, 500); } } }, [checkOverflow, orientation, isOverflow]); const resizeRef = useRef(resize); useEffect(() => { resizeRef.current = resize; }, [resize]); const refreshOverflow = useCallback(() => { resizeRef.current(); }, []); useEffect(() => { if (toolbarRef.current) { let isFirstObservation = true; resizeObserverRef.current = new ResizeObserver(() => { if (isFirstObservation) { isFirstObservation = false; return; } resizeRef.current(); }); resizeObserverRef.current.observe(toolbarRef.current); } return () => { resizeObserverRef.current?.disconnect(); resizeObserverRef.current = null; }; }, []); useEffect(() => { const currentCount = Children.count(children); if (isNullOrUndefined(previousChildrenCountRef.current) || previousChildrenCountRef.current !== currentCount) { previousChildrenCountRef.current = Children.count(children); onOverflowChange(); resizeRef.current(false); } }, [children, onOverflowChange]); useEffect(() => { onOverflowChange(); }, [isOverflow, onOverflowChange]); useImperativeHandle(ref, () => ({ refreshOverflow }), [refreshOverflow]); const classes = useMemo(() => { const classArray = [CLS_ITEMS]; if (className) { classArray.push(className); } return classArray.join(' '); }, [className]); if (isOverflow) { if (orientation === Orientation.Horizontal) { return (_jsx(HScroll, { scrollStep: activeScrollStep, className: classes, children: children })); } else { return (_jsx(VScroll, { scrollStep: activeScrollStep, className: classes, children: children })); } } else { return _jsx("div", { className: classes, children: children }); } })); ToolbarScrollable.displayName = 'ToolbarScrollable'; export { ToolbarScrollable };