UNPKG

@coreui/react-pro

Version:

UI Components Library for React.js

79 lines (76 loc) 4.04 kB
import { __rest } from '../../node_modules/tslib/tslib.es6.js'; import React, { forwardRef, useRef, useState, useEffect } from 'react'; import PropTypes from 'prop-types'; import classNames from '../../_virtual/index.js'; import '@popperjs/core'; import { useForkedRef } from '../../hooks/useForkedRef.js'; const CVirtualScroller = forwardRef((_a, ref) => { var { children, className, visibleItems, onScroll } = _a, rest = __rest(_a, ["children", "className", "visibleItems", "onScroll"]); const virtualScrollRef = useRef(null); const virtualScrollContentRef = useRef(null); const forkedRef = useForkedRef(ref, virtualScrollRef); const [buffer, setBuffer] = useState(Math.floor(visibleItems / 2)); const [currentItemIndex, setCurrentItemIndex] = useState(1); const [itemHeight, setItemHeight] = useState(0); const [itemsNumber, setItemsNumber] = useState(React.Children.count(children)); const [viewportPadding, setViewportPadding] = useState(0); const [viewportHeight, setViewportHeight] = useState(visibleItems * itemHeight + 2 * viewportPadding); const [maxHeight, setMaxHeight] = useState(itemsNumber * itemHeight + 2 * viewportPadding); useEffect(() => { virtualScrollRef.current && virtualScrollRef.current.scrollTop; virtualScrollRef.current && setViewportPadding(Number.parseFloat(getComputedStyle(virtualScrollRef.current).paddingTop)); }); useEffect(() => { setItemsNumber(React.Children.count(children)); }, [children]); useEffect(() => { setViewportHeight(Math.min(visibleItems, itemsNumber) * itemHeight + 2 * viewportPadding); }, [itemHeight, itemsNumber, viewportPadding, visibleItems]); useEffect(() => { setMaxHeight(itemsNumber * itemHeight); virtualScrollRef.current && virtualScrollRef.current.scrollTop; }, [itemHeight, itemsNumber]); useEffect(() => { setBuffer(Math.floor(visibleItems / 2)); }, [visibleItems]); const handleScroll = (scrollTop) => { const _currentItemIndex = itemHeight && Math.max(Math.ceil(scrollTop / itemHeight), 1); setCurrentItemIndex(_currentItemIndex); onScroll && onScroll(_currentItemIndex); }; return (React.createElement("div", Object.assign({ className: classNames('virtual-scroller', className), onScroll: (event) => handleScroll(event.target.scrollTop), style: { height: viewportHeight, overflowY: 'auto', }, ref: forkedRef }, rest), React.createElement("div", { className: "virtual-scroller-content", style: { height: maxHeight, }, ref: virtualScrollContentRef }, React.Children.map(children, (child, index) => { if (React.isValidElement(child) && index + 1 > Math.max(currentItemIndex - buffer, 0) && index + 1 <= currentItemIndex + visibleItems + buffer) { return React.cloneElement(child, { className: classNames(child.props.className, { 'virtual-scroller-item-preload': index + 1 > currentItemIndex + visibleItems || index + 1 < currentItemIndex, }), key: index, style: Object.assign({}, (currentItemIndex > buffer && { transform: `translateY(${(currentItemIndex - buffer) * itemHeight}px)`, })), ref: (node) => node && node.offsetHeight && setItemHeight(node.offsetHeight + Number.parseFloat(getComputedStyle(node).marginTop) + Number.parseFloat(getComputedStyle(node).marginBottom)), }); } return; })))); }); CVirtualScroller.propTypes = { onScroll: PropTypes.func, visibleItems: PropTypes.number.isRequired, }; CVirtualScroller.displayName = 'CVirtualScroller'; export { CVirtualScroller }; //# sourceMappingURL=CVirtualScroller.js.map