From bc49139b1e05782ea0113f6c4ccaa34a974d7598 Mon Sep 17 00:00:00 2001 From: seb Date: Sat, 10 Oct 2026 02:37:41 +0200 Subject: [PATCH] u --- README.md | 2 +- src/FillSpace.jsx | 7 +- src/dev/mock-pages/FillSpaceMockPage.jsx | 142 +++++++--------------- src/dev/screenshots/ScreenshotHarness.jsx | 93 +++++++------- 4 files changed, 96 insertions(+), 148 deletions(-) diff --git a/README.md b/README.md index c71f728..0c4d31a 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ This package is source-only: consumers import directly from `src/` via the | `dashgui/tiles` | `src/tiles/` | `Tile`, `TILE_SIZE`, `tileBaseSx` | | `dashgui/ElevatedPill` | `src/ElevatedPill.jsx` | `ElevatedPill`, `ToggleElevatedPill`, `ActionElevatedPill` | | `dashgui/SingleLineTextEdit` | `src/SingleLineTextEdit.jsx` | Centralized single-line text field | -| `dashgui/FillSpace` | `src/FillSpace.jsx` | `FillSpace` — viewport-height spacer between header/footer refs; optional repeating `measureElement` | +| `dashgui/FillSpace` | `src/FillSpace.jsx` | `FillSpace` — paginates `items` via `renderItem`, filling the viewport space between `aboveRef`/`belowRef`; wheel flips pages | ## Design rules diff --git a/src/FillSpace.jsx b/src/FillSpace.jsx index 5891f6f..498e423 100644 --- a/src/FillSpace.jsx +++ b/src/FillSpace.jsx @@ -260,13 +260,14 @@ class FillSpace extends Component { // FillSpace owns current page, wheel-pagination and the pagination header. // Caller feeds `items` plus one row element via `renderItem` (component - // type or callback). + // type or callback). `items` may be undefined while data is loading. const { pageSize, currentPage, viewportHeight } = this.state; - const total = items.length; + const list = Array.isArray(items) ? items : []; + const total = list.length; const pageCount = Math.max(1, Math.ceil(total / Math.max(1, pageSize))); const safePage = Math.min(Math.max(1, currentPage), pageCount); const offset = (safePage - 1) * pageSize; - const pageItems = items.slice(offset, offset + pageSize); + const pageItems = list.slice(offset, offset + pageSize); const showPagination = total > pageSize; // Hidden data-free probe: measures `renderItem` itself (no data). const probe = renderProbeElement(renderItem); diff --git a/src/dev/mock-pages/FillSpaceMockPage.jsx b/src/dev/mock-pages/FillSpaceMockPage.jsx index caf8d16..4984765 100644 --- a/src/dev/mock-pages/FillSpaceMockPage.jsx +++ b/src/dev/mock-pages/FillSpaceMockPage.jsx @@ -1,14 +1,32 @@ import { Component, createRef } from 'react'; import Box from '@mui/material/Box'; +import ListItemButton from '@mui/material/ListItemButton'; +import ListItemText from '@mui/material/ListItemText'; import Paper from '@mui/material/Paper'; import Typography from '@mui/material/Typography'; import FillSpace from '../../FillSpace'; import { ComponentDocs } from '../ComponentDocs'; +/** Row renderer: component types are rendered as elements by FillSpace. */ +class Row extends Component { + render() { + const { item } = this.props; + return ( + + + + ); + } +} + +const SAMPLE_ITEMS = Array.from({ length: 40 }, (_, i) => ({ + id: i + 1, + name: `Eintrag ${i + 1}`, +})); + /** - * Mock page exercising FillSpace: real content on top, and a repeating - * `measureElement` filling only the leftover space down to the end of the - * viewport. + * Mock page exercising FillSpace: header/footer refs, `items` + `renderItem`, + * wheel pagination and the built-in pagination header. */ class FillSpaceMockPage extends Component { constructor(props) { @@ -16,27 +34,26 @@ class FillSpaceMockPage extends Component { this.ex1 = { header: createRef(), footer: createRef() }; this.ex2 = { header: createRef(), footer: createRef() }; this.ex3 = { header: createRef(), footer: createRef() }; - this.state = { fitCount: null }; } render() { - const { fitCount } = this.state; return ( - FillSpace renders real content on top and repeats the measurement - element until the end of the page. + FillSpace paginates items via a renderItem{' '} + row, measures the row height, fills the leftover viewport space and + flips pages on wheel scroll. - {/* Main example: content + repeating fill to end of page */} + {/* Main example: items + renderItem to end of page */} - Content + repeating element to end of page + Items + renderItem, filled to end of page Header (measured) @@ -44,65 +61,17 @@ class FillSpaceMockPage extends Component { - Einheit - - } - onMeasurement={(count) => this.setState({ fitCount: count })} - > - - - Echte Inhalte (children) - - - Diese Zeilen stehen oben, darunter wiederholt sich die - Einheit bis zum Seitenende. - - - - 📏 onMeasurement (würden ohne Inhalt passen):  - - - {fitCount != null ? `${fitCount} Einheiten` : '…'} - - - - + items={SAMPLE_ITEMS} + renderItem={Row} + reserveBottom={32} + minPageSize={5} + /> - Footer (measured) + Footer (reserved) @@ -115,7 +84,7 @@ class FillSpaceMockPage extends Component { Header @@ -123,24 +92,15 @@ class FillSpaceMockPage extends Component { - - - Minimum height of 200px enforced. - - - + /> Footer @@ -155,7 +115,7 @@ class FillSpaceMockPage extends Component { Header @@ -163,25 +123,15 @@ class FillSpaceMockPage extends Component { - - - Green background shows actual spacer bounds; purple overlay - shows full viewport coverage. - - - + /> Footer diff --git a/src/dev/screenshots/ScreenshotHarness.jsx b/src/dev/screenshots/ScreenshotHarness.jsx index 4636e0a..4fc7ed5 100644 --- a/src/dev/screenshots/ScreenshotHarness.jsx +++ b/src/dev/screenshots/ScreenshotHarness.jsx @@ -2,6 +2,8 @@ import { Component, createRef } from 'react'; import Alert from '@mui/material/Alert'; import Box from '@mui/material/Box'; import Chip from '@mui/material/Chip'; +import ListItemButton from '@mui/material/ListItemButton'; +import ListItemText from '@mui/material/ListItemText'; import Typography from '@mui/material/Typography'; import AddIcon from '@mui/icons-material/Add'; import FolderIcon from '@mui/icons-material/FolderOutlined'; @@ -307,8 +309,8 @@ class ScreenshotHarness extends Component { } /** - * Deterministic FillSpace example for the screenshot harness. Bound with a - * `maxHeight` so the reference is stable regardless of the viewport height. + * Deterministic FillSpace example for the screenshot harness: + * `items` + a component `renderItem`, bounded by above/below refs. */ class FillSpaceExample extends Component { constructor(props) { @@ -322,7 +324,7 @@ class FillSpaceExample extends Component { Header (gemessen) @@ -330,26 +332,15 @@ class FillSpaceExample extends Component { - - - FillSpace füllt den Platz zwischen Header und Footer. - - - + /> Footer (gemessen) @@ -358,9 +349,36 @@ class FillSpaceExample extends Component { } } +/** Row renderer used by the FillSpace harness examples. */ +class FillRow extends Component { + render() { + const { item } = this.props; + return ( + + + Platzhalter + + ) + } + /> + + ); + } +} + +const FILL_SAMPLE_ITEMS = Array.from({ length: 24 }, (_, i) => ({ + id: i + 1, + name: `Eintrag ${i + 1}`, +})); + /** - * FillSpace with a repeating measurement element plus real children on top, - * for the screenshot harness. Bound with maxHeight so the reference is stable. + * FillSpace with `items` + a component `renderItem`, for the screenshot + * harness. Bounded by above/below refs so the reference is stable. */ class FillSpaceMeasureExample extends Component { constructor(props) { @@ -374,7 +392,7 @@ class FillSpaceMeasureExample extends Component { Header @@ -382,36 +400,15 @@ class FillSpaceMeasureExample extends Component { - Einheit - - } - measureGap={8} + items={FILL_SAMPLE_ITEMS} + renderItem={FillRow} + minPageSize={4} minHeight={60} - maxHeight={260} - > - - Echte Inhalte - - + /> Footer