@ui5/webcomponents-react
Version:
React Wrapper for UI5 Web Components and additional components
114 lines (111 loc) • 3.78 kB
JavaScript
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';