UNPKG

@zohodesk/hooks

Version:

Unified Component Library - Hooks

118 lines (113 loc) 3.81 kB
import { useState, useRef, useLayoutEffect, useCallback } from 'react'; import debounce from '@zohodesk/utils/es/debounce'; import useEvent from "../utils/useEvent"; import useEffectCallOnlyAfterState from "../utils/useEffectCallOnlyAfterState"; import useResizeObserver from "../utils/useResizeObserver"; import getParentElementWidth from "./utils/getParentElementWidth"; import getChildElementWidth from "./utils/getChildElementWidth"; import getMinimumVisibleData from "./utils/getMinimumVisibleData"; import getChildNodesOnly from "./utils/getChildNodesOnly"; import getRemainingWidth from "./utils/getRemainingWidth"; import getRenderableElements from "./utils/getRenderableElements"; export default function useAdaptiveRenderer() { let props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; const { dataList = [], startsFrom = 'left', storeChildrenWidth = false, minimumLeftVisible = 0, minimumRightVisible = 0 } = props; const initialzeState = () => { return { leftElements: startsFrom === 'left' ? dataList : [], rightElements: startsFrom === 'right' ? dataList : [], remainingElements: [], isMoreVisible: true }; }; const [elementsData, setElementsData] = useState(initialzeState); const [isRendered, setRendered] = useState(true); const parentRef = useRef(null); const moreElementRef = useRef(null); const childNodesWidth = useRef({}); const calculateRenderableElements = useEvent(() => { let dataLength = dataList.length; let newElementsData = getMinimumVisibleData({ startsFrom, dataList, minimumLeftVisible, minimumRightVisible }); let parentWidth = getParentElementWidth(parentRef.current); let moreElemWidth = getChildElementWidth(moreElementRef.current); const childNodes = getChildNodesOnly(parentRef.current, moreElementRef.current); const getChildWidth = index => { if (storeChildrenWidth) { let storedWidth = childNodesWidth.current[index]; if (!!storedWidth) { return storedWidth; } else { let width = getChildElementWidth(childNodes[index]); childNodesWidth.current[index] = width; return width; } } else { return getChildElementWidth(childNodes[index]); } }; let newRemainingWidth = getRemainingWidth({ totalWidth: parentWidth, getChildWidth, dataLength, minimumLeftVisible, minimumRightVisible }); let newRenderableElements = getRenderableElements({ elementsData: newElementsData, startsFrom, remainingWidth: newRemainingWidth, getChildWidth, moreElemWidth, minimumLeftVisible, minimumRightVisible }); return newRenderableElements; }); const renderElements = useEvent(() => { let newElementsData = calculateRenderableElements(); setElementsData(newElementsData); setRendered(false); }); const reCalculate = useEvent(() => { let newElementsData = initialzeState(); setElementsData(newElementsData); setRendered(true); }); useLayoutEffect(() => { if (isRendered) { renderElements(); } }, [isRendered]); useEffectCallOnlyAfterState(() => { childNodesWidth.current = {}; reCalculate(); }, [dataList]); const getParentElement = useCallback(() => { return parentRef.current; }, []); useResizeObserver({ getElement: getParentElement, callback: debounce(reCalculate, 100), isObserve: true }); return { parentRef, moreElementRef, reCalculate, isMoreVisible: elementsData.isMoreVisible, leftElements: elementsData.leftElements, rightElements: elementsData.rightElements, remainingElements: elementsData.remainingElements }; }