@ui5/webcomponents-react
Version:
React Wrapper for UI5 Web Components and additional components
93 lines (92 loc) • 3.54 kB
JavaScript
import { enrichEventWithDetails, useIsomorphicLayoutEffect } from '@ui5/webcomponents-react-base';
import { clsx } from 'clsx';
import { useCallback, useEffect, useRef, useState } from 'react';
import { jsx as _jsx } from "react/jsx-runtime";
export const VirtualTableBodyContainer = props => {
const {
tableBodyHeight,
totalColumnsWidth,
children,
parentRef,
classes,
infiniteScroll,
infiniteScrollThreshold,
onLoadMore,
rows,
internalRowHeight,
handleExternalScroll,
visibleRows,
popInRowHeight,
rowCollapsedFlag,
isGrouped,
isFirefox,
dispatch
} = props;
const [isMounted, setIsMounted] = useState(false);
useIsomorphicLayoutEffect(() => {
if (parentRef.current) {
// Run before paint so rows appear with the body container (avoids empty-body flash).
setIsMounted(true);
}
}, [parentRef]);
const dataLength = rows.length;
const lastScrollTop = useRef(0);
const firedInfiniteLoadEvents = useRef(new Set());
const prevDataLength = useRef(dataLength);
useEffect(() => {
if (prevDataLength.current > dataLength) {
// if prevData is larger because a row was collapsed, no scroll should be executed
if (rowCollapsedFlag) {
dispatch({
type: 'ROW_COLLAPSED_FLAG',
payload: false
});
} else {
firedInfiniteLoadEvents.current.clear();
parentRef.current.scrollTop = 0;
lastScrollTop.current = 0;
}
}
prevDataLength.current = dataLength;
}, [dataLength, rowCollapsedFlag]);
const onScroll = useCallback(event => {
if (typeof handleExternalScroll === 'function') {
handleExternalScroll(enrichEventWithDetails(event, {
rows,
rowElements: event.target.children[0].children
}));
}
const scrollOffset = event.target.scrollTop;
const isScrollingDown = lastScrollTop.current < scrollOffset;
const target = event.target;
const scrolledToBottom = target.scrollHeight - target.scrollTop === target.clientHeight;
// For a grouped table, it is possible that no new groups (rows) are added since new rows are added to existing groups.
// Because of this, the table should trigger the `onLoadMore` event every time a user scrolls to the bottom.
const applyGroupingLogic = scrolledToBottom && isGrouped;
if ((isScrollingDown || applyGroupingLogic) && infiniteScroll) {
lastScrollTop.current = scrollOffset;
const currentLastRow = Math.floor(scrollOffset / popInRowHeight) + (popInRowHeight === internalRowHeight ? visibleRows : Math.floor(tableBodyHeight / popInRowHeight));
if (rows.length - currentLastRow < infiniteScrollThreshold || applyGroupingLogic) {
if (!firedInfiniteLoadEvents.current.has(rows.length) || applyGroupingLogic) {
onLoadMore(event);
}
firedInfiniteLoadEvents.current.add(rows.length);
}
}
}, [handleExternalScroll, infiniteScroll, infiniteScrollThreshold, internalRowHeight, isGrouped, onLoadMore, popInRowHeight, rows, tableBodyHeight, visibleRows]);
return /*#__PURE__*/_jsx("div", {
className: clsx(classes.tbody, isFirefox && classes.firefoxNativeScrollbar),
ref: parentRef,
onScroll: onScroll,
style: {
position: 'relative',
overflowY: 'auto',
height: `${tableBodyHeight}px`,
width: `${totalColumnsWidth}px`
},
"data-component-name": "AnalyticalTableBody",
tabIndex: -1,
role: "rowgroup",
children: isMounted && children
});
};