UNPKG

@ui5/webcomponents-react

Version:

React Wrapper for UI5 Web Components and additional components

114 lines (111 loc) 3.78 kB
import { useIsomorphicLayoutEffect } from '@ui5/webcomponents-react-base'; import { useRef } from 'react'; import { jsx as _jsx } from "react/jsx-runtime"; export function RowSubComponent(props) { const { subComponentsHeight = {}, virtualRow, dispatch, row, rowHeight, children, rows, alwaysShowSubComponent, rowIndex, classNames, renderSubComp } = props; const subComponentRef = useRef(null); useIsomorphicLayoutEffect(() => { const subComponentElement = subComponentRef.current; if (!subComponentElement || !renderSubComp) { return; } const measureAndDispatch = rawHeight => { // ceil: avoid under-estimation (would overlap next row) and absorb sub-px precision diff between getComputedStyle and borderBoxSize const height = Math.ceil(rawHeight); const prev = subComponentsHeight?.[virtualRow.index] ?? {}; if (height === 0 || prev.subComponentHeight === height && prev.rowId === row.id) { return; } // use most common subComponentHeight height of first 10 subcomponents as default height if (alwaysShowSubComponent && Object.keys(subComponentsHeight).length === 10) { // create frequency map -> most common height has the highest number const frequencyMap = {}; Object.values(subComponentsHeight).forEach(({ subComponentHeight }) => { if (subComponentHeight) { frequencyMap[subComponentHeight] = (frequencyMap[subComponentHeight] || 0) + 1; } }); const mostUsedHeight = Number(Object.entries(frequencyMap).sort((a, b) => b[1] - a[1])[0]?.[0] || 0); const estimatedHeight = {}; rows.forEach((row, index) => { estimatedHeight[index] = { subComponentHeight: mostUsedHeight, rowId: row.id }; }); dispatch({ type: 'SUB_COMPONENTS_HEIGHT', payload: { ...estimatedHeight, ...subComponentsHeight } }); } else { dispatch({ type: 'SUB_COMPONENTS_HEIGHT', payload: { ...subComponentsHeight, [virtualRow.index]: { subComponentHeight: height, rowId: row.id } } }); } }; // sync initial read for first-paint correctness; blockSize matches borderBoxSize coords (getBoundingClientRect returns zoom-applied) measureAndDispatch(parseFloat(getComputedStyle(subComponentElement).blockSize)); const observer = new ResizeObserver(([entry]) => { measureAndDispatch(entry.borderBoxSize[0].blockSize); }); observer.observe(subComponentElement); return () => { observer.disconnect(); }; }, [renderSubComp, subComponentsHeight, virtualRow.index, row.id, alwaysShowSubComponent, rows]); // reset subComponentHeight useIsomorphicLayoutEffect(() => { if (!renderSubComp && subComponentsHeight?.[virtualRow.index]?.subComponentHeight) { dispatch({ type: 'SUB_COMPONENTS_HEIGHT', payload: { ...subComponentsHeight, [virtualRow.index]: { subComponentHeight: 0, rowId: row.id } } }); } }, [renderSubComp, subComponentsHeight, virtualRow.index, row.id, dispatch]); if (!renderSubComp) { return null; } return /*#__PURE__*/_jsx("div", { ref: subComponentRef, "data-subcomponent": true, "data-subcomponent-row-index": rowIndex, tabIndex: -1, style: { boxSizing: 'border-box', transform: `translateY(${rowHeight}px)` }, className: classNames.subcomponent, children: children }); } RowSubComponent.displayName = 'RowSubComponent';