@ceed/ads 1.20.0 → 1.20.1-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.
Files changed (30) hide show
  1. package/dist/components/ProfileMenu/ProfileMenu.d.ts +1 -1
  2. package/dist/components/data-display/Markdown.md +832 -0
  3. package/dist/components/feedback/Dialog.md +605 -3
  4. package/dist/components/feedback/Modal.md +656 -24
  5. package/dist/components/feedback/llms.txt +1 -1
  6. package/dist/components/inputs/Autocomplete.md +734 -2
  7. package/dist/components/inputs/Calendar.md +655 -1
  8. package/dist/components/inputs/DatePicker.md +699 -3
  9. package/dist/components/inputs/DateRangePicker.md +815 -1
  10. package/dist/components/inputs/MonthPicker.md +626 -4
  11. package/dist/components/inputs/MonthRangePicker.md +682 -4
  12. package/dist/components/inputs/Select.md +600 -0
  13. package/dist/components/layout/Container.md +507 -0
  14. package/dist/components/navigation/Breadcrumbs.md +582 -0
  15. package/dist/components/navigation/IconMenuButton.md +693 -0
  16. package/dist/components/navigation/InsetDrawer.md +1150 -3
  17. package/dist/components/navigation/Link.md +526 -0
  18. package/dist/components/navigation/MenuButton.md +632 -0
  19. package/dist/components/navigation/NavigationGroup.md +401 -1
  20. package/dist/components/navigation/NavigationItem.md +311 -0
  21. package/dist/components/navigation/Navigator.md +373 -0
  22. package/dist/components/navigation/Pagination.md +521 -0
  23. package/dist/components/navigation/ProfileMenu.md +605 -0
  24. package/dist/components/navigation/Tabs.md +609 -7
  25. package/dist/components/surfaces/Accordions.md +947 -3
  26. package/dist/index.cjs +3 -1
  27. package/dist/index.js +3 -1
  28. package/dist/llms.txt +1 -1
  29. package/framer/index.js +1 -1
  30. package/package.json +3 -2
@@ -2,6 +2,8 @@
2
2
 
3
3
  ## Introduction
4
4
 
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.
6
+
5
7
  ```tsx
6
8
  <Stack spacing={4}>
7
9
  <Stack spacing={1}>
@@ -23,4 +25,523 @@
23
25
 
24
26
  ```tsx
25
27
  import { Pagination } from '@ceed/ads';
28
+
29
+ function DataList() {
30
+ const [page, setPage] = useState(1);
31
+ const pageSize = 10;
32
+ const totalItems = 250;
33
+
34
+ return (
35
+ <>
36
+ <ItemList items={items} page={page} pageSize={pageSize} />
37
+ <Pagination
38
+ rowCount={totalItems}
39
+ paginationModel={{ page, pageSize }}
40
+ onPageChange={setPage}
41
+ />
42
+ </>
43
+ );
44
+ }
45
+ ```
46
+
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
+ ```
65
+
66
+ ### Sizes
67
+
68
+ Pagination supports three sizes for different layouts.
69
+
70
+ ```tsx
71
+ <Stack spacing={4}>
72
+ <Stack spacing={2}>
73
+ <div>Standard</div>
74
+ <Pagination {...args} variant="standard" size="sm" />
75
+ <Pagination {...args} variant="standard" size="md" />
76
+ <Pagination {...args} variant="standard" size="lg" />
77
+ </Stack>
78
+ <Stack spacing={2}>
79
+ <div>Compact</div>
80
+ <Pagination {...args} variant="compact" size="sm" />
81
+ <Pagination {...args} variant="compact" size="md" />
82
+ <Pagination {...args} variant="compact" size="lg" />
83
+ </Stack>
84
+ </Stack>
85
+ ```
86
+
87
+ ### Pages
88
+
89
+ Navigation through different page positions.
90
+
91
+ ```tsx
92
+ <Stack spacing={4}>
93
+ <Stack spacing={2}>
94
+ <div>Standard</div>
95
+ <Pagination {...args} variant="standard" defaultPaginationModel={{
96
+ page: 1,
97
+ pageSize: 1
98
+ }} />
99
+ <Pagination {...args} variant="standard" defaultPaginationModel={{
100
+ page: 10,
101
+ pageSize: 1
102
+ }} />
103
+ <Pagination {...args} variant="standard" defaultPaginationModel={{
104
+ page: 20,
105
+ pageSize: 1
106
+ }} />
107
+ </Stack>
108
+ <Stack spacing={2}>
109
+ <div>Compact</div>
110
+ <Pagination {...args} variant="compact" defaultPaginationModel={{
111
+ page: 1,
112
+ pageSize: 1
113
+ }} />
114
+ <Pagination {...args} variant="compact" defaultPaginationModel={{
115
+ page: 10,
116
+ pageSize: 1
117
+ }} />
118
+ <Pagination {...args} variant="compact" defaultPaginationModel={{
119
+ page: 20,
120
+ pageSize: 1
121
+ }} />
122
+ </Stack>
123
+ </Stack>
124
+ ```
125
+
126
+ ### Uncontrolled
127
+
128
+ Component manages its own page state.
129
+
130
+ ```tsx
131
+ <Pagination {...args} />
26
132
  ```
133
+
134
+ ### Controlled
135
+
136
+ Parent component controls the page state.
137
+
138
+ ```tsx
139
+ <Pagination {...args} paginationModel={paginationModel} onPageChange={handlePageChange} />
140
+ ```
141
+
142
+ ### Change Row Count
143
+
144
+ Pagination automatically adjusts when total items change.
145
+
146
+ ```tsx
147
+ <Stack gap={2}>
148
+ <Pagination {...args} rowCount={rowCount} />
149
+ <Stack direction="row" gap={2}>
150
+ <Button onClick={() => setRowCount(rowCount - 1)}>Decrease Row count</Button>
151
+ <Button onClick={() => setRowCount(rowCount + 1)}>Increase Row count</Button>
152
+ </Stack>
153
+ </Stack>
154
+ ```
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
+
174
+ ## Common Use Cases
175
+
176
+ ### Data Table Pagination
177
+
178
+ ```tsx
179
+ function DataTable({ columns, fetchData }) {
180
+ const [page, setPage] = useState(1);
181
+ const [pageSize, setPageSize] = useState(25);
182
+ const { data, totalCount, isLoading } = useFetchData(page, pageSize);
183
+
184
+ return (
185
+ <Box>
186
+ <Table columns={columns} data={data} loading={isLoading} />
187
+ <Stack direction="row" justifyContent="space-between" mt={2}>
188
+ <Typography level="body-sm">
189
+ Showing {(page - 1) * pageSize + 1} - {Math.min(page * pageSize, totalCount)} of {totalCount}
190
+ </Typography>
191
+ <Pagination
192
+ rowCount={totalCount}
193
+ paginationModel={{ page, pageSize }}
194
+ onPageChange={setPage}
195
+ />
196
+ </Stack>
197
+ </Box>
198
+ );
199
+ }
200
+ ```
201
+
202
+ ### Search Results
203
+
204
+ ```tsx
205
+ function SearchResults({ query }) {
206
+ const [page, setPage] = useState(1);
207
+ const { results, totalCount } = useSearch(query, page);
208
+
209
+ // Reset to page 1 when query changes
210
+ useEffect(() => {
211
+ setPage(1);
212
+ }, [query]);
213
+
214
+ return (
215
+ <Stack spacing={2}>
216
+ <Typography level="body-sm">{totalCount} results for "{query}"</Typography>
217
+ <ResultList results={results} />
218
+ <Pagination
219
+ rowCount={totalCount}
220
+ defaultPaginationModel={{ page: 1, pageSize: 10 }}
221
+ onPageChange={setPage}
222
+ variant="compact"
223
+ />
224
+ </Stack>
225
+ );
226
+ }
227
+ ```
228
+
229
+ ### Gallery with Pagination
230
+
231
+ ```tsx
232
+ function Gallery({ images }) {
233
+ const pageSize = 12;
234
+ const [currentPage, setCurrentPage] = useState(1);
235
+
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)');
299
+
300
+ return (
301
+ <Pagination
302
+ rowCount={rowCount}
303
+ paginationModel={{ page, pageSize: 10 }}
304
+ onPageChange={onPageChange}
305
+ variant={isMobile ? 'compact' : 'standard'}
306
+ size={isMobile ? 'sm' : 'md'}
307
+ />
308
+ );
309
+ }
310
+ ```
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
+
413
+ ## Best Practices
414
+
415
+ ### ✅ Do
416
+
417
+ 1. **Show context**: Display total items and current range
418
+
419
+ ```tsx
420
+ // ✅ Good: Show pagination context
421
+ <Stack direction="row" justifyContent="space-between">
422
+ <Typography>Showing 1-25 of 250 items</Typography>
423
+ <Pagination rowCount={250} />
424
+ </Stack>
425
+ ```
426
+
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
445
+
446
+ ```tsx
447
+ useEffect(() => {
448
+ setPage(1);
449
+ }, [filters]);
450
+ ```
451
+
452
+ ### ❌ Don't
453
+
454
+ 1. **Don't use for very small datasets**: Pagination adds complexity
455
+
456
+ ```tsx
457
+ // ❌ Bad: Pagination for 5 items
458
+ <Pagination rowCount={5} />
459
+
460
+ // ✅ Good: Just show all items
461
+ <ItemList items={items} />
462
+ ```
463
+
464
+ 2. **Don't hide the page count**: Users need to know how many pages exist
465
+
466
+ 3. **Don't use inconsistent page sizes**: Keep pageSize consistent in session
467
+
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
+ ```
546
+
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.