This commit is contained in:
seb
2026-10-11 12:49:16 +02:00
parent 266f5212aa
commit 8325402bc6

View File

@@ -55,10 +55,12 @@ function renderProbeElement(renderItem) {
class FillSpace extends Component { class FillSpace extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
const minSize = Math.max(1, Number(props.minPageSize) || 10);
const maxSize = Number(props.maxPageSize) > 0 ? Number(props.maxPageSize) : Infinity;
this.state = { this.state = {
unitHeight: 0, unitHeight: 0,
viewportHeight: null, viewportHeight: null,
pageSize: Number(props.minPageSize) || 10, pageSize: Math.min(maxSize, minSize),
currentPage: 1, currentPage: 1,
}; };
this.ref = null; this.ref = null;
@@ -79,8 +81,13 @@ class FillSpace extends Component {
if (prevProps.renderItem !== this.props.renderItem) { if (prevProps.renderItem !== this.props.renderItem) {
this._probeMeasure(); this._probeMeasure();
} }
if (prevProps.minPageSize !== this.props.minPageSize) { if (
this.setState({ pageSize: Number(this.props.minPageSize) || 10 }); prevProps.minPageSize !== this.props.minPageSize ||
prevProps.maxPageSize !== this.props.maxPageSize
) {
const minSize = Math.max(1, Number(this.props.minPageSize) || 10);
const maxSize = Number(this.props.maxPageSize) > 0 ? Number(this.props.maxPageSize) : Infinity;
this.setState({ pageSize: Math.min(maxSize, minSize) });
} }
if ( if (
prevProps.aboveRef !== this.props.aboveRef || prevProps.aboveRef !== this.props.aboveRef ||
@@ -165,7 +172,8 @@ class FillSpace extends Component {
/** Only measures the height of the `renderItem` probe. Nothing else. */ /** Only measures the height of the `renderItem` probe. Nothing else. */
_probeMeasure() { _probeMeasure() {
const h = this.probeRef?.offsetHeight; const firstRow = this.ref?.querySelector('[data-fill-row]');
const h = this.probeRef?.offsetHeight || firstRow?.offsetHeight;
if (h > 0 && h !== this.state.unitHeight) { if (h > 0 && h !== this.state.unitHeight) {
this.setState({ unitHeight: h }, () => this._viewportMeasure()); this.setState({ unitHeight: h }, () => this._viewportMeasure());
} }
@@ -197,14 +205,20 @@ class FillSpace extends Component {
available = Math.max(0, window.innerHeight - rect.top - belowPx); available = Math.max(0, window.innerHeight - rect.top - belowPx);
} }
const minSize = Math.max(1, Number(minPageSize) || 10); const minSize = Math.max(1, Number(minPageSize) || 10);
const maxSize = Number(this.props.maxPageSize) > 0 ? Number(this.props.maxPageSize) : Infinity;
const { unitHeight } = this.state; const { unitHeight } = this.state;
const nextPageSize = const calculated =
unitHeight > 0 ? Math.max(minSize, Math.floor(available / unitHeight)) : minSize; unitHeight > 0 ? Math.max(minSize, Math.floor(available / unitHeight)) : minSize;
const nextPageSize = Math.min(maxSize, calculated);
const nextViewportHeight =
Number.isFinite(maxSize) && unitHeight > 0
? Math.min(available, nextPageSize * unitHeight)
: available;
if ( if (
available !== this.state.viewportHeight || nextViewportHeight !== this.state.viewportHeight ||
nextPageSize !== this.state.pageSize nextPageSize !== this.state.pageSize
) { ) {
this.setState({ viewportHeight: available, pageSize: nextPageSize }); this.setState({ viewportHeight: nextViewportHeight, pageSize: nextPageSize });
} }
} }
@@ -250,6 +264,8 @@ class FillSpace extends Component {
minHeight, minHeight,
maxHeight, maxHeight,
minPageSize, minPageSize,
maxPageSize,
listRef,
onPageChange, onPageChange,
onWheel, onWheel,
debug = false, debug = false,
@@ -275,16 +291,11 @@ class FillSpace extends Component {
return ( return (
<> <>
{showPagination ? (
<Box <Box
// Fixed single-line bar: the header height must not depend on the
// page count. Otherwise the first fit (e.g. "1-17") pushes the
// spacer down, the available height shrinks, and a second pass
// flips to "1-15". One pass: constant 44px, real values always
// rendered (only visibility is gated), no placeholder numbers.
sx={{ mb: 1, height: 44, overflow: 'hidden' }} sx={{ mb: 1, height: 44, overflow: 'hidden' }}
> >
<Box <Box
aria-hidden={!showPagination || undefined}
sx={{ sx={{
display: 'flex', display: 'flex',
justifyContent: 'space-between', justifyContent: 'space-between',
@@ -293,8 +304,6 @@ class FillSpace extends Component {
gap: 1, gap: 1,
width: '100%', width: '100%',
height: 44, height: 44,
visibility: showPagination ? 'visible' : 'hidden',
pointerEvents: showPagination ? 'auto' : 'none',
}} }}
> >
<Typography <Typography
@@ -329,6 +338,7 @@ class FillSpace extends Component {
/> />
</Box> </Box>
</Box> </Box>
) : null}
<Box <Box
ref={(el) => { ref={(el) => {
this.ref = el; this.ref = el;
@@ -357,7 +367,7 @@ class FillSpace extends Component {
]} ]}
> >
<Box sx={{ width: '100%' }}> <Box sx={{ width: '100%' }}>
<List dense disablePadding sx={{ width: '100%' }}> <List ref={listRef} dense disablePadding sx={{ width: '100%' }}>
{pageItems.map((item, i) => ( {pageItems.map((item, i) => (
<Box key={item?.id ?? offset + i} data-fill-row sx={{ width: '100%' }}> <Box key={item?.id ?? offset + i} data-fill-row sx={{ width: '100%' }}>
{renderRowElement(renderItem, item, offset + i)} {renderRowElement(renderItem, item, offset + i)}