@ceed/ads 1.29.1 → 1.30.0-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/CurrencyInput/CurrencyInput.d.ts +1 -1
- package/dist/components/CurrencyInput/hooks/use-currency-setting.d.ts +2 -2
- package/dist/components/ProfileMenu/ProfileMenu.d.ts +1 -1
- package/dist/components/SearchBar/SearchBar.d.ts +21 -0
- package/dist/components/SearchBar/index.d.ts +3 -0
- package/dist/components/data-display/Badge.md +39 -71
- package/dist/components/data-display/DataTable.md +1 -1
- package/dist/components/data-display/InfoSign.md +98 -74
- package/dist/components/data-display/Typography.md +97 -363
- package/dist/components/feedback/Dialog.md +62 -76
- package/dist/components/feedback/Modal.md +44 -259
- package/dist/components/feedback/llms.txt +0 -2
- package/dist/components/index.d.ts +2 -0
- package/dist/components/inputs/Autocomplete.md +107 -356
- package/dist/components/inputs/ButtonGroup.md +106 -115
- package/dist/components/inputs/Calendar.md +459 -98
- package/dist/components/inputs/CurrencyInput.md +5 -183
- package/dist/components/inputs/DatePicker.md +431 -108
- package/dist/components/inputs/DateRangePicker.md +492 -131
- package/dist/components/inputs/FilterMenu.md +19 -169
- package/dist/components/inputs/FilterableCheckboxGroup.md +23 -123
- package/dist/components/inputs/IconButton.md +88 -137
- package/dist/components/inputs/Input.md +0 -5
- package/dist/components/inputs/MonthPicker.md +422 -95
- package/dist/components/inputs/MonthRangePicker.md +466 -89
- package/dist/components/inputs/PercentageInput.md +16 -185
- package/dist/components/inputs/RadioButton.md +35 -163
- package/dist/components/inputs/RadioTileGroup.md +61 -150
- package/dist/components/inputs/SearchBar.md +44 -0
- package/dist/components/inputs/Select.md +326 -222
- package/dist/components/inputs/Switch.md +376 -136
- package/dist/components/inputs/Textarea.md +10 -213
- package/dist/components/inputs/Uploader/Uploader.md +66 -145
- package/dist/components/inputs/llms.txt +1 -3
- package/dist/components/navigation/Breadcrumbs.md +322 -80
- package/dist/components/navigation/Dropdown.md +221 -92
- package/dist/components/navigation/IconMenuButton.md +502 -40
- package/dist/components/navigation/InsetDrawer.md +738 -68
- package/dist/components/navigation/Link.md +298 -39
- package/dist/components/navigation/Menu.md +285 -92
- package/dist/components/navigation/MenuButton.md +448 -55
- package/dist/components/navigation/Pagination.md +338 -47
- package/dist/components/navigation/ProfileMenu.md +268 -45
- package/dist/components/navigation/Stepper.md +28 -160
- package/dist/components/navigation/Tabs.md +316 -57
- package/dist/components/surfaces/Sheet.md +334 -151
- package/dist/index.browser.js +15 -13
- package/dist/index.browser.js.map +4 -4
- package/dist/index.cjs +289 -288
- package/dist/index.d.ts +1 -1
- package/dist/index.js +426 -369
- package/dist/llms.txt +1 -8
- package/framer/index.js +1 -1
- package/package.json +16 -15
- package/dist/chunks/rehype-accent-FZRUD7VI.js +0 -39
- package/dist/components/feedback/CircularProgress.md +0 -257
- package/dist/components/feedback/Skeleton.md +0 -280
- package/dist/components/inputs/FormControl.md +0 -361
- package/dist/components/inputs/RadioList.md +0 -241
- package/dist/components/inputs/Slider.md +0 -334
- package/dist/guides/ThemeProvider.md +0 -116
- package/dist/guides/llms.txt +0 -9
|
@@ -2,9 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Introduction
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Pagination ships in two variants -- **standard** (clickable page numbers) and **compact** (dropdown selector) -- making it suitable for different screen sizes and layout constraints. It supports both controlled and uncontrolled usage patterns to integrate smoothly with any state management approach.
|
|
5
|
+
Pagination allows users to navigate through large datasets or content collections by dividing them into discrete pages. It provides intuitive controls for moving between pages, jumping to specific pages, and understanding the current position within the total dataset. Pagination comes in two variants: standard (page numbers) and compact (dropdown selector), making it suitable for different space constraints and use cases.
|
|
8
6
|
|
|
9
7
|
```tsx
|
|
10
8
|
<Stack spacing={4}>
|
|
@@ -46,11 +44,28 @@ function DataList() {
|
|
|
46
44
|
}
|
|
47
45
|
```
|
|
48
46
|
|
|
49
|
-
##
|
|
47
|
+
## Examples
|
|
48
|
+
|
|
49
|
+
### Playground
|
|
50
|
+
|
|
51
|
+
Both standard and compact variants displayed together.
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
<Stack spacing={4}>
|
|
55
|
+
<Stack spacing={1}>
|
|
56
|
+
<div>Standard</div>
|
|
57
|
+
<Pagination {...args} variant="standard" />
|
|
58
|
+
</Stack>
|
|
59
|
+
<Stack spacing={1}>
|
|
60
|
+
<div>Compact</div>
|
|
61
|
+
<Pagination {...args} variant="compact" />
|
|
62
|
+
</Stack>
|
|
63
|
+
</Stack>
|
|
64
|
+
```
|
|
50
65
|
|
|
51
66
|
### Sizes
|
|
52
67
|
|
|
53
|
-
Pagination
|
|
68
|
+
Pagination supports three sizes for different layouts.
|
|
54
69
|
|
|
55
70
|
```tsx
|
|
56
71
|
<Stack spacing={4}>
|
|
@@ -69,9 +84,9 @@ Pagination is available in three sizes -- `sm`, `md`, and `lg` -- for both the s
|
|
|
69
84
|
</Stack>
|
|
70
85
|
```
|
|
71
86
|
|
|
72
|
-
###
|
|
87
|
+
### Pages
|
|
73
88
|
|
|
74
|
-
|
|
89
|
+
Navigation through different page positions.
|
|
75
90
|
|
|
76
91
|
```tsx
|
|
77
92
|
<Stack spacing={4}>
|
|
@@ -108,25 +123,25 @@ The component correctly handles the visual presentation when the user is at the
|
|
|
108
123
|
</Stack>
|
|
109
124
|
```
|
|
110
125
|
|
|
111
|
-
### Uncontrolled
|
|
126
|
+
### Uncontrolled
|
|
112
127
|
|
|
113
|
-
|
|
128
|
+
Component manages its own page state.
|
|
114
129
|
|
|
115
130
|
```tsx
|
|
116
131
|
<Pagination {...args} />
|
|
117
132
|
```
|
|
118
133
|
|
|
119
|
-
### Controlled
|
|
134
|
+
### Controlled
|
|
120
135
|
|
|
121
|
-
|
|
136
|
+
Parent component controls the page state.
|
|
122
137
|
|
|
123
138
|
```tsx
|
|
124
139
|
<Pagination {...args} paginationModel={paginationModel} onPageChange={handlePageChange} />
|
|
125
140
|
```
|
|
126
141
|
|
|
127
|
-
###
|
|
142
|
+
### Change Row Count
|
|
128
143
|
|
|
129
|
-
Pagination automatically adjusts when
|
|
144
|
+
Pagination automatically adjusts when total items change.
|
|
130
145
|
|
|
131
146
|
```tsx
|
|
132
147
|
<Stack gap={2}>
|
|
@@ -138,23 +153,40 @@ Pagination automatically adjusts when the total number of items changes. If the
|
|
|
138
153
|
</Stack>
|
|
139
154
|
```
|
|
140
155
|
|
|
156
|
+
## When to Use
|
|
157
|
+
|
|
158
|
+
### ✅ Good Use Cases
|
|
159
|
+
|
|
160
|
+
- **Data tables**: Navigate through paginated table data
|
|
161
|
+
- **Search results**: Browse through multiple pages of results
|
|
162
|
+
- **Content listings**: Articles, products, or any list content
|
|
163
|
+
- **Admin panels**: Managing records across multiple pages
|
|
164
|
+
- **API data**: When server returns paginated responses
|
|
165
|
+
|
|
166
|
+
### ❌ When Not to Use
|
|
167
|
+
|
|
168
|
+
- **Infinite scroll**: When content loads continuously on scroll
|
|
169
|
+
- **Small datasets**: Less than 20 items don't need pagination
|
|
170
|
+
- **Single content**: Individual articles or detail views
|
|
171
|
+
- **Sequential flows**: Use Stepper for multi-step processes
|
|
172
|
+
- **Real-time data**: Frequently updating data may shift pages unpredictably
|
|
173
|
+
|
|
141
174
|
## Common Use Cases
|
|
142
175
|
|
|
143
176
|
### Data Table Pagination
|
|
144
177
|
|
|
145
178
|
```tsx
|
|
146
|
-
function DataTable({ columns }) {
|
|
179
|
+
function DataTable({ columns, fetchData }) {
|
|
147
180
|
const [page, setPage] = useState(1);
|
|
148
|
-
const [pageSize] = useState(25);
|
|
181
|
+
const [pageSize, setPageSize] = useState(25);
|
|
149
182
|
const { data, totalCount, isLoading } = useFetchData(page, pageSize);
|
|
150
183
|
|
|
151
184
|
return (
|
|
152
185
|
<Box>
|
|
153
186
|
<Table columns={columns} data={data} loading={isLoading} />
|
|
154
|
-
<Stack direction="row" justifyContent="space-between"
|
|
187
|
+
<Stack direction="row" justifyContent="space-between" mt={2}>
|
|
155
188
|
<Typography level="body-sm">
|
|
156
|
-
Showing {(page - 1) * pageSize + 1}
|
|
157
|
-
{totalCount}
|
|
189
|
+
Showing {(page - 1) * pageSize + 1} - {Math.min(page * pageSize, totalCount)} of {totalCount}
|
|
158
190
|
</Typography>
|
|
159
191
|
<Pagination
|
|
160
192
|
rowCount={totalCount}
|
|
@@ -167,13 +199,14 @@ function DataTable({ columns }) {
|
|
|
167
199
|
}
|
|
168
200
|
```
|
|
169
201
|
|
|
170
|
-
### Search Results
|
|
202
|
+
### Search Results
|
|
171
203
|
|
|
172
204
|
```tsx
|
|
173
205
|
function SearchResults({ query }) {
|
|
174
206
|
const [page, setPage] = useState(1);
|
|
175
207
|
const { results, totalCount } = useSearch(query, page);
|
|
176
208
|
|
|
209
|
+
// Reset to page 1 when query changes
|
|
177
210
|
useEffect(() => {
|
|
178
211
|
setPage(1);
|
|
179
212
|
}, [query]);
|
|
@@ -184,7 +217,7 @@ function SearchResults({ query }) {
|
|
|
184
217
|
<ResultList results={results} />
|
|
185
218
|
<Pagination
|
|
186
219
|
rowCount={totalCount}
|
|
187
|
-
|
|
220
|
+
defaultPaginationModel={{ page: 1, pageSize: 10 }}
|
|
188
221
|
onPageChange={setPage}
|
|
189
222
|
variant="compact"
|
|
190
223
|
/>
|
|
@@ -193,64 +226,322 @@ function SearchResults({ query }) {
|
|
|
193
226
|
}
|
|
194
227
|
```
|
|
195
228
|
|
|
196
|
-
###
|
|
229
|
+
### Gallery with Pagination
|
|
197
230
|
|
|
198
231
|
```tsx
|
|
199
|
-
function
|
|
200
|
-
const
|
|
201
|
-
const
|
|
232
|
+
function Gallery({ images }) {
|
|
233
|
+
const pageSize = 12;
|
|
234
|
+
const [currentPage, setCurrentPage] = useState(1);
|
|
202
235
|
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
236
|
+
const paginatedImages = useMemo(() => {
|
|
237
|
+
const start = (currentPage - 1) * pageSize;
|
|
238
|
+
return images.slice(start, start + pageSize);
|
|
239
|
+
}, [images, currentPage, pageSize]);
|
|
240
|
+
|
|
241
|
+
return (
|
|
242
|
+
<Box>
|
|
243
|
+
<Grid container spacing={2}>
|
|
244
|
+
{paginatedImages.map((image) => (
|
|
245
|
+
<Grid key={image.id} xs={4}>
|
|
246
|
+
<ImageCard image={image} />
|
|
247
|
+
</Grid>
|
|
248
|
+
))}
|
|
249
|
+
</Grid>
|
|
250
|
+
<Box display="flex" justifyContent="center" mt={3}>
|
|
251
|
+
<Pagination
|
|
252
|
+
rowCount={images.length}
|
|
253
|
+
paginationModel={{ page: currentPage, pageSize }}
|
|
254
|
+
onPageChange={setCurrentPage}
|
|
255
|
+
/>
|
|
256
|
+
</Box>
|
|
257
|
+
</Box>
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### API Pagination
|
|
263
|
+
|
|
264
|
+
```tsx
|
|
265
|
+
function APIList() {
|
|
266
|
+
const [paginationModel, setPaginationModel] = useState({
|
|
267
|
+
page: 1,
|
|
268
|
+
pageSize: 20,
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
const { data } = useQuery({
|
|
272
|
+
queryKey: ['items', paginationModel],
|
|
273
|
+
queryFn: () => fetchItems({
|
|
274
|
+
page: paginationModel.page,
|
|
275
|
+
limit: paginationModel.pageSize,
|
|
276
|
+
}),
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
return (
|
|
280
|
+
<Box>
|
|
281
|
+
<ItemList items={data?.items || []} />
|
|
282
|
+
<Pagination
|
|
283
|
+
rowCount={data?.totalCount || 0}
|
|
284
|
+
paginationModel={paginationModel}
|
|
285
|
+
onPageChange={(newPage) =>
|
|
286
|
+
setPaginationModel((prev) => ({ ...prev, page: newPage }))
|
|
287
|
+
}
|
|
288
|
+
/>
|
|
289
|
+
</Box>
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### Compact Pagination for Mobile
|
|
295
|
+
|
|
296
|
+
```tsx
|
|
297
|
+
function ResponsivePagination({ rowCount, page, onPageChange }) {
|
|
298
|
+
const isMobile = useMediaQuery('(max-width: 600px)');
|
|
206
299
|
|
|
207
300
|
return (
|
|
208
301
|
<Pagination
|
|
209
|
-
rowCount={
|
|
210
|
-
paginationModel={{ page, pageSize:
|
|
211
|
-
onPageChange={
|
|
302
|
+
rowCount={rowCount}
|
|
303
|
+
paginationModel={{ page, pageSize: 10 }}
|
|
304
|
+
onPageChange={onPageChange}
|
|
305
|
+
variant={isMobile ? 'compact' : 'standard'}
|
|
306
|
+
size={isMobile ? 'sm' : 'md'}
|
|
212
307
|
/>
|
|
213
308
|
);
|
|
214
309
|
}
|
|
215
310
|
```
|
|
216
311
|
|
|
312
|
+
## Props and Customization
|
|
313
|
+
|
|
314
|
+
### Key Props
|
|
315
|
+
|
|
316
|
+
| Prop | Type | Default | Description |
|
|
317
|
+
| ------------------------ | ------------------------------------ | --------------------------- | ---------------------------- |
|
|
318
|
+
| `rowCount` | `number` | - | Total number of items |
|
|
319
|
+
| `paginationModel` | `{ page: number; pageSize: number }` | - | Controlled pagination state |
|
|
320
|
+
| `defaultPaginationModel` | `{ page: number; pageSize: number }` | `{ page: 1, pageSize: 25 }` | Default state (uncontrolled) |
|
|
321
|
+
| `onPageChange` | `(newPage: number) => void` | - | Callback when page changes |
|
|
322
|
+
| `variant` | `'standard' \| 'compact'` | `'standard'` | Pagination style |
|
|
323
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Component size |
|
|
324
|
+
|
|
325
|
+
### Variant Comparison
|
|
326
|
+
|
|
327
|
+
| Feature | Standard | Compact |
|
|
328
|
+
| -------------------- | ------------ | ------------------- |
|
|
329
|
+
| Page numbers visible | Yes | No |
|
|
330
|
+
| Quick page jump | Click number | Dropdown select |
|
|
331
|
+
| Space required | More | Less |
|
|
332
|
+
| Best for | Desktop | Mobile/tight spaces |
|
|
333
|
+
|
|
334
|
+
### Controlled vs Uncontrolled
|
|
335
|
+
|
|
336
|
+
```tsx
|
|
337
|
+
// Uncontrolled - component manages state
|
|
338
|
+
<Pagination
|
|
339
|
+
rowCount={100}
|
|
340
|
+
defaultPaginationModel={{ page: 1, pageSize: 10 }}
|
|
341
|
+
onPageChange={(page) => console.log('Page:', page)}
|
|
342
|
+
/>
|
|
343
|
+
|
|
344
|
+
// Controlled - you manage state
|
|
345
|
+
const [page, setPage] = useState(1);
|
|
346
|
+
<Pagination
|
|
347
|
+
rowCount={100}
|
|
348
|
+
paginationModel={{ page, pageSize: 10 }}
|
|
349
|
+
onPageChange={setPage}
|
|
350
|
+
/>
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### Page Calculation
|
|
354
|
+
|
|
355
|
+
The component automatically calculates total pages:
|
|
356
|
+
|
|
357
|
+
```tsx
|
|
358
|
+
// With 95 items and pageSize of 10:
|
|
359
|
+
// totalPages = Math.ceil(95 / 10) = 10 pages
|
|
360
|
+
|
|
361
|
+
<Pagination
|
|
362
|
+
rowCount={95}
|
|
363
|
+
paginationModel={{ page: 1, pageSize: 10 }}
|
|
364
|
+
onPageChange={handleChange}
|
|
365
|
+
/>
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
## Accessibility
|
|
369
|
+
|
|
370
|
+
Pagination includes built-in accessibility features:
|
|
371
|
+
|
|
372
|
+
### ARIA Attributes
|
|
373
|
+
|
|
374
|
+
- Current page marked with `aria-current="page"`
|
|
375
|
+
- Navigation buttons have descriptive `aria-label` attributes
|
|
376
|
+
- Disabled buttons properly marked with `disabled`
|
|
377
|
+
|
|
378
|
+
### Keyboard Navigation
|
|
379
|
+
|
|
380
|
+
- **Tab**: Move through pagination controls
|
|
381
|
+
- **Enter/Space**: Activate focused button
|
|
382
|
+
- **Arrow Keys**: Navigate within the compact dropdown
|
|
383
|
+
|
|
384
|
+
### Screen Reader Support
|
|
385
|
+
|
|
386
|
+
```tsx
|
|
387
|
+
// Buttons announce their purpose
|
|
388
|
+
<button aria-label="Previous page">←</button>
|
|
389
|
+
<button aria-label="Next page">→</button>
|
|
390
|
+
<button aria-label="More previous pages">...</button>
|
|
391
|
+
<button aria-current="page">5</button> // "Page 5, current"
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### Status Announcements
|
|
395
|
+
|
|
396
|
+
Consider adding live region for page changes:
|
|
397
|
+
|
|
398
|
+
```tsx
|
|
399
|
+
function PaginatedList() {
|
|
400
|
+
const [page, setPage] = useState(1);
|
|
401
|
+
|
|
402
|
+
return (
|
|
403
|
+
<>
|
|
404
|
+
<div aria-live="polite" className="sr-only">
|
|
405
|
+
Page {page} of {totalPages}
|
|
406
|
+
</div>
|
|
407
|
+
<Pagination onPageChange={setPage} />
|
|
408
|
+
</>
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
```
|
|
412
|
+
|
|
217
413
|
## Best Practices
|
|
218
414
|
|
|
219
|
-
|
|
415
|
+
### ✅ Do
|
|
416
|
+
|
|
417
|
+
1. **Show context**: Display total items and current range
|
|
220
418
|
|
|
221
419
|
```tsx
|
|
222
|
-
// Good
|
|
420
|
+
// ✅ Good: Show pagination context
|
|
223
421
|
<Stack direction="row" justifyContent="space-between">
|
|
224
|
-
<Typography>Showing 1
|
|
225
|
-
<Pagination rowCount={250}
|
|
422
|
+
<Typography>Showing 1-25 of 250 items</Typography>
|
|
423
|
+
<Pagination rowCount={250} />
|
|
226
424
|
</Stack>
|
|
227
425
|
```
|
|
228
426
|
|
|
229
|
-
|
|
427
|
+
2. **Start from page 1**: Users expect 1-based pagination
|
|
428
|
+
|
|
429
|
+
```tsx
|
|
430
|
+
// ✅ Good: 1-based pagination
|
|
431
|
+
defaultPaginationModel={{ page: 1, pageSize: 25 }}
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
3. **Handle empty states**: Show appropriate UI when there's no data
|
|
435
|
+
|
|
436
|
+
```tsx
|
|
437
|
+
{totalCount > 0 ? (
|
|
438
|
+
<Pagination rowCount={totalCount} />
|
|
439
|
+
) : (
|
|
440
|
+
<Typography>No results found</Typography>
|
|
441
|
+
)}
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
4. **Reset on filter changes**: Return to page 1 when filters change
|
|
230
445
|
|
|
231
446
|
```tsx
|
|
232
447
|
useEffect(() => {
|
|
233
448
|
setPage(1);
|
|
234
|
-
}, [filters
|
|
449
|
+
}, [filters]);
|
|
235
450
|
```
|
|
236
451
|
|
|
237
|
-
|
|
452
|
+
### ❌ Don't
|
|
453
|
+
|
|
454
|
+
1. **Don't use for very small datasets**: Pagination adds complexity
|
|
238
455
|
|
|
239
456
|
```tsx
|
|
240
|
-
// Bad
|
|
241
|
-
<Pagination rowCount={5}
|
|
457
|
+
// ❌ Bad: Pagination for 5 items
|
|
458
|
+
<Pagination rowCount={5} />
|
|
242
459
|
|
|
243
|
-
// Good
|
|
460
|
+
// ✅ Good: Just show all items
|
|
244
461
|
<ItemList items={items} />
|
|
245
462
|
```
|
|
246
463
|
|
|
247
|
-
|
|
464
|
+
2. **Don't hide the page count**: Users need to know how many pages exist
|
|
248
465
|
|
|
249
|
-
|
|
466
|
+
3. **Don't use inconsistent page sizes**: Keep pageSize consistent in session
|
|
250
467
|
|
|
251
|
-
|
|
468
|
+
4. **Don't forget loading states**: Show loading while fetching page data
|
|
469
|
+
|
|
470
|
+
```tsx
|
|
471
|
+
// ✅ Good: Handle loading
|
|
472
|
+
<Pagination disabled={isLoading} />
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
## Performance Considerations
|
|
476
|
+
|
|
477
|
+
### Server-Side Pagination
|
|
478
|
+
|
|
479
|
+
For large datasets, paginate on the server:
|
|
480
|
+
|
|
481
|
+
```tsx
|
|
482
|
+
function ServerPaginatedList() {
|
|
483
|
+
const [page, setPage] = useState(1);
|
|
484
|
+
const pageSize = 25;
|
|
485
|
+
|
|
486
|
+
const { data, isLoading } = useQuery({
|
|
487
|
+
queryKey: ['items', page, pageSize],
|
|
488
|
+
queryFn: () => api.getItems({ page, pageSize }),
|
|
489
|
+
keepPreviousData: true, // Keep old data while loading
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
return (
|
|
493
|
+
<>
|
|
494
|
+
<ItemList items={data?.items} loading={isLoading} />
|
|
495
|
+
<Pagination
|
|
496
|
+
rowCount={data?.totalCount || 0}
|
|
497
|
+
paginationModel={{ page, pageSize }}
|
|
498
|
+
onPageChange={setPage}
|
|
499
|
+
/>
|
|
500
|
+
</>
|
|
501
|
+
);
|
|
502
|
+
}
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### Memoize Handlers
|
|
506
|
+
|
|
507
|
+
When used in complex components, memoize the change handler:
|
|
508
|
+
|
|
509
|
+
```tsx
|
|
510
|
+
const handlePageChange = useCallback((newPage) => {
|
|
511
|
+
setPage(newPage);
|
|
512
|
+
}, []);
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
### Virtualization Alternative
|
|
516
|
+
|
|
517
|
+
For very large datasets, consider virtualization instead of pagination:
|
|
518
|
+
|
|
519
|
+
```tsx
|
|
520
|
+
// Instead of pagination for 10,000+ items:
|
|
521
|
+
<VirtualizedList items={items} itemHeight={50} />
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
### URL Sync
|
|
525
|
+
|
|
526
|
+
For shareable pagination state, sync with URL:
|
|
527
|
+
|
|
528
|
+
```tsx
|
|
529
|
+
function URLPaginatedList() {
|
|
530
|
+
const [searchParams, setSearchParams] = useSearchParams();
|
|
531
|
+
const page = parseInt(searchParams.get('page') || '1', 10);
|
|
532
|
+
|
|
533
|
+
const handlePageChange = (newPage) => {
|
|
534
|
+
setSearchParams({ page: String(newPage) });
|
|
535
|
+
};
|
|
536
|
+
|
|
537
|
+
return (
|
|
538
|
+
<Pagination
|
|
539
|
+
rowCount={totalCount}
|
|
540
|
+
paginationModel={{ page, pageSize: 25 }}
|
|
541
|
+
onPageChange={handlePageChange}
|
|
542
|
+
/>
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
```
|
|
252
546
|
|
|
253
|
-
|
|
254
|
-
- **Keyboard navigation**: All pagination buttons are focusable with `Tab` and activated with `Enter` or `Space`. In the compact variant, arrow keys navigate the dropdown options.
|
|
255
|
-
- **Disabled states**: When the user is on the first or last page, the corresponding navigation button is properly disabled and announced as such to assistive technologies.
|
|
256
|
-
- **Live region consideration**: For dynamic content updates, consider wrapping a status message in an `aria-live="polite"` region to announce the current page to screen reader users.
|
|
547
|
+
Pagination is essential for managing large datasets in admin interfaces. Choose between standard and compact variants based on available space and user needs, ensuring a smooth navigation experience through your data.
|