UNPKG

@ui5/webcomponents-react

Version:

React Wrapper for UI5 Web Components and additional components

93 lines (92 loc) 3.54 kB
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 }); };