@coreui/react-pro
Version:
UI Components Library for React.js
79 lines (76 loc) • 4.04 kB
JavaScript
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