UNPKG

@coreui/react-pro

Version:

UI Components Library for React.js

82 lines (79 loc) 4.22 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(() => { if (virtualScrollRef.current) { void virtualScrollRef.current.scrollTop; // force reflow 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(() => { var _a; setMaxHeight(itemsNumber * itemHeight); void ((_a = virtualScrollRef.current) === null || _a === void 0 ? void 0 : _a.scrollTop); // force reflow }, [itemHeight, itemsNumber]); useEffect(() => { setBuffer(Math.floor(visibleItems / 2)); }, [visibleItems]); const handleScroll = (scrollTop) => { const _currentItemIndex = itemHeight ? Math.max(Math.ceil(scrollTop / itemHeight), 1) : 0; setCurrentItemIndex(_currentItemIndex); onScroll === null || onScroll === void 0 ? void 0 : onScroll(_currentItemIndex); }; return (React.createElement("div", Object.assign({ className: classNames('virtual-scroller', className), onScroll: (event) => handleScroll(event.currentTarget.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) { const childElement = child; return React.cloneElement(childElement, { className: classNames(childElement.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