@zohodesk/hooks
Version:
Unified Component Library - Hooks
118 lines (113 loc) • 3.81 kB
JavaScript
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
};
}