This commit is contained in:
seb
2026-10-11 13:44:39 +02:00
parent 8325402bc6
commit c34f86f762

View File

@@ -15,6 +15,9 @@ import { alpha } from '@mui/material/styles';
* @prop {Array} items - Wheel flips pages. * @prop {Array} items - Wheel flips pages.
* @prop {React.ComponentType|Function} renderItem - Row renderer (component or callback). * @prop {React.ComponentType|Function} renderItem - Row renderer (component or callback).
* @prop {number} [minPageSize=10] - Rows per page. * @prop {number} [minPageSize=10] - Rows per page.
* @prop {number} [maxPageSize] - Maximum rows per page.
* @prop {number} [totalCount] - Total items in unfiltered dataset. When unfiltered count <= pageSize, pagination header is removed entirely. When filtering, the header height is preserved to prevent layout shift.
* @prop {number} [unfilteredCount] - Alias for totalCount.
* @prop {(page: number) => void} [onPageChange] - Called on page change. * @prop {(page: number) => void} [onPageChange] - Called on page change.
* @prop {boolean} [debug=false] - Dashed outline for layout debugging. * @prop {boolean} [debug=false] - Dashed outline for layout debugging.
* @prop {object} [sx] - Extra styles. * @prop {object} [sx] - Extra styles.
@@ -68,6 +71,13 @@ class FillSpace extends Component {
this.wheelAcc = 0; this.wheelAcc = 0;
this.observer = null; this.observer = null;
this.raf = null; this.raf = null;
const explicitCount = props.unfilteredCount ?? props.totalCount;
this.maxSeenCount =
explicitCount != null
? Number(explicitCount)
: Array.isArray(props.items)
? props.items.length
: 0;
} }
componentDidMount() { componentDidMount() {
@@ -99,6 +109,12 @@ class FillSpace extends Component {
this._observe(); this._observe();
this._viewportMeasure(); this._viewportMeasure();
} }
const explicitCount = this.props.unfilteredCount ?? this.props.totalCount;
if (explicitCount != null) {
this.maxSeenCount = Number(explicitCount);
} else if (Array.isArray(this.props.items)) {
this.maxSeenCount = Math.max(this.maxSeenCount || 0, this.props.items.length);
}
// Clamp current page when the item list shrinks (e.g. brand deleted). // Clamp current page when the item list shrinks (e.g. brand deleted).
if ( if (
Array.isArray(this.props.items) && Array.isArray(this.props.items) &&
@@ -265,6 +281,8 @@ class FillSpace extends Component {
maxHeight, maxHeight,
minPageSize, minPageSize,
maxPageSize, maxPageSize,
totalCount,
unfilteredCount,
listRef, listRef,
onPageChange, onPageChange,
onWheel, onWheel,
@@ -281,21 +299,26 @@ class FillSpace extends Component {
const { pageSize, currentPage, viewportHeight } = this.state; const { pageSize, currentPage, viewportHeight } = this.state;
const list = Array.isArray(items) ? items : []; const list = Array.isArray(items) ? items : [];
const total = list.length; const total = list.length;
const fullTotal = unfilteredCount ?? totalCount ?? Math.max(this.maxSeenCount || 0, total);
const needsPaginationContainer = fullTotal > pageSize;
const showPaginationControls = total > pageSize;
const pageCount = Math.max(1, Math.ceil(total / Math.max(1, pageSize))); const pageCount = Math.max(1, Math.ceil(total / Math.max(1, pageSize)));
const safePage = Math.min(Math.max(1, currentPage), pageCount); const safePage = Math.min(Math.max(1, currentPage), pageCount);
const offset = (safePage - 1) * pageSize; const offset = (safePage - 1) * pageSize;
const pageItems = list.slice(offset, offset + pageSize); const pageItems = list.slice(offset, offset + pageSize);
const showPagination = total > pageSize;
// Hidden data-free probe: measures `renderItem` itself (no data). // Hidden data-free probe: measures `renderItem` itself (no data).
const probe = renderProbeElement(renderItem); const probe = renderProbeElement(renderItem);
return ( return (
<> <>
{showPagination ? ( {needsPaginationContainer ? (
<Box <Box
// Fixed single-line bar: the header height must not depend on the
// filtered count so the content never shifts when filtering.
sx={{ mb: 1, height: 44, overflow: 'hidden' }} sx={{ mb: 1, height: 44, overflow: 'hidden' }}
> >
<Box <Box
aria-hidden={!showPaginationControls || undefined}
sx={{ sx={{
display: 'flex', display: 'flex',
justifyContent: 'space-between', justifyContent: 'space-between',
@@ -304,6 +327,8 @@ class FillSpace extends Component {
gap: 1, gap: 1,
width: '100%', width: '100%',
height: 44, height: 44,
visibility: showPaginationControls ? 'visible' : 'hidden',
pointerEvents: showPaginationControls ? 'auto' : 'none',
}} }}
> >
<Typography <Typography