@ceed/ads 1.29.0 → 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.
Files changed (64) hide show
  1. package/dist/components/CurrencyInput/CurrencyInput.d.ts +1 -1
  2. package/dist/components/CurrencyInput/hooks/use-currency-setting.d.ts +2 -2
  3. package/dist/components/DataTable/hooks.d.ts +2 -1
  4. package/dist/components/DataTable/utils.d.ts +1 -0
  5. package/dist/components/ProfileMenu/ProfileMenu.d.ts +1 -1
  6. package/dist/components/SearchBar/SearchBar.d.ts +21 -0
  7. package/dist/components/SearchBar/index.d.ts +3 -0
  8. package/dist/components/data-display/Badge.md +39 -71
  9. package/dist/components/data-display/DataTable.md +1 -1
  10. package/dist/components/data-display/InfoSign.md +98 -74
  11. package/dist/components/data-display/Typography.md +97 -363
  12. package/dist/components/feedback/Dialog.md +62 -76
  13. package/dist/components/feedback/Modal.md +44 -259
  14. package/dist/components/feedback/llms.txt +0 -2
  15. package/dist/components/index.d.ts +2 -0
  16. package/dist/components/inputs/Autocomplete.md +107 -356
  17. package/dist/components/inputs/ButtonGroup.md +106 -115
  18. package/dist/components/inputs/Calendar.md +459 -98
  19. package/dist/components/inputs/CurrencyInput.md +5 -183
  20. package/dist/components/inputs/DatePicker.md +431 -108
  21. package/dist/components/inputs/DateRangePicker.md +492 -131
  22. package/dist/components/inputs/FilterMenu.md +19 -169
  23. package/dist/components/inputs/FilterableCheckboxGroup.md +23 -123
  24. package/dist/components/inputs/IconButton.md +88 -137
  25. package/dist/components/inputs/Input.md +0 -5
  26. package/dist/components/inputs/MonthPicker.md +422 -95
  27. package/dist/components/inputs/MonthRangePicker.md +466 -89
  28. package/dist/components/inputs/PercentageInput.md +16 -185
  29. package/dist/components/inputs/RadioButton.md +35 -163
  30. package/dist/components/inputs/RadioTileGroup.md +61 -150
  31. package/dist/components/inputs/SearchBar.md +44 -0
  32. package/dist/components/inputs/Select.md +326 -222
  33. package/dist/components/inputs/Switch.md +376 -136
  34. package/dist/components/inputs/Textarea.md +10 -213
  35. package/dist/components/inputs/Uploader/Uploader.md +66 -145
  36. package/dist/components/inputs/llms.txt +1 -3
  37. package/dist/components/navigation/Breadcrumbs.md +322 -80
  38. package/dist/components/navigation/Dropdown.md +221 -92
  39. package/dist/components/navigation/IconMenuButton.md +502 -40
  40. package/dist/components/navigation/InsetDrawer.md +738 -68
  41. package/dist/components/navigation/Link.md +298 -39
  42. package/dist/components/navigation/Menu.md +285 -92
  43. package/dist/components/navigation/MenuButton.md +448 -55
  44. package/dist/components/navigation/Pagination.md +338 -47
  45. package/dist/components/navigation/ProfileMenu.md +268 -45
  46. package/dist/components/navigation/Stepper.md +28 -160
  47. package/dist/components/navigation/Tabs.md +316 -57
  48. package/dist/components/surfaces/Sheet.md +334 -151
  49. package/dist/index.browser.js +15 -13
  50. package/dist/index.browser.js.map +4 -4
  51. package/dist/index.cjs +313 -291
  52. package/dist/index.d.ts +1 -1
  53. package/dist/index.js +450 -372
  54. package/dist/llms.txt +1 -8
  55. package/framer/index.js +1 -1
  56. package/package.json +16 -15
  57. package/dist/chunks/rehype-accent-FZRUD7VI.js +0 -39
  58. package/dist/components/feedback/CircularProgress.md +0 -257
  59. package/dist/components/feedback/Skeleton.md +0 -280
  60. package/dist/components/inputs/FormControl.md +0 -361
  61. package/dist/components/inputs/RadioList.md +0 -241
  62. package/dist/components/inputs/Slider.md +0 -334
  63. package/dist/guides/ThemeProvider.md +0 -116
  64. package/dist/guides/llms.txt +0 -9
@@ -2,9 +2,7 @@
2
2
 
3
3
  ## Introduction
4
4
 
5
- The Pagination component enables users to navigate through large datasets or content collections that are divided into discrete pages. It provides controls for moving forward and backward, jumping to specific pages, and understanding the current position within the total set.
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
- ## Features
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 is available in three sizes -- `sm`, `md`, and `lg` -- for both the standard and compact variants.
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
- ### Page Positions
87
+ ### Pages
73
88
 
74
- The component correctly handles the visual presentation when the user is at the beginning, middle, or end of the page range, adjusting ellipsis buttons and disabled states accordingly.
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 Mode
126
+ ### Uncontrolled
112
127
 
113
- In uncontrolled mode the component manages its own page state internally. Pass `defaultPaginationModel` to set the initial state and use `onPageChange` to react to changes.
128
+ Component manages its own page state.
114
129
 
115
130
  ```tsx
116
131
  <Pagination {...args} />
117
132
  ```
118
133
 
119
- ### Controlled Mode
134
+ ### Controlled
120
135
 
121
- In controlled mode the parent component owns the page state via `paginationModel` and updates it through `onPageChange`. This gives full control over navigation behavior.
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
- ### Dynamic Row Count
142
+ ### Change Row Count
128
143
 
129
- Pagination automatically adjusts when the total number of items changes. If the current page exceeds the new page count, the component clamps to the last available page.
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" alignItems="center" mt={2}>
187
+ <Stack direction="row" justifyContent="space-between" mt={2}>
155
188
  <Typography level="body-sm">
156
- Showing {(page - 1) * pageSize + 1}--{Math.min(page * pageSize, totalCount)} of{' '}
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 with Compact Variant
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
- paginationModel={{ page, pageSize: 10 }}
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
- ### URL-Synchronized Pagination
229
+ ### Gallery with Pagination
197
230
 
198
231
  ```tsx
199
- function URLPaginatedList() {
200
- const [searchParams, setSearchParams] = useSearchParams();
201
- const page = parseInt(searchParams.get('page') || '1', 10);
232
+ function Gallery({ images }) {
233
+ const pageSize = 12;
234
+ const [currentPage, setCurrentPage] = useState(1);
202
235
 
203
- const handlePageChange = (newPage: number) => {
204
- setSearchParams({ page: String(newPage) });
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={totalCount}
210
- paginationModel={{ page, pageSize: 25 }}
211
- onPageChange={handlePageChange}
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
- - **Always show context.** Display the total item count and current range (for example "Showing 1--25 of 250") alongside the pagination controls so users understand the scope of the data.
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--25 of 250 items</Typography>
225
- <Pagination rowCount={250} paginationModel={{ page: 1, pageSize: 25 }} onPageChange={setPage} />
422
+ <Typography>Showing 1-25 of 250 items</Typography>
423
+ <Pagination rowCount={250} />
226
424
  </Stack>
227
425
  ```
228
426
 
229
- - **Reset to page 1 when filters change.** When the user applies a new filter or search query, always reset the page to 1 to avoid showing an empty or out-of-range page.
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, searchQuery]);
449
+ }, [filters]);
235
450
  ```
236
451
 
237
- - **Do not paginate very small datasets.** If the total number of items fits comfortably on a single screen, display all items directly instead of adding pagination overhead.
452
+ ### Don't
453
+
454
+ 1. **Don't use for very small datasets**: Pagination adds complexity
238
455
 
239
456
  ```tsx
240
- // Bad -- pagination for 5 items
241
- <Pagination rowCount={5} paginationModel={{ page: 1, pageSize: 10 }} onPageChange={setPage} />
457
+ // Bad: Pagination for 5 items
458
+ <Pagination rowCount={5} />
242
459
 
243
- // Good -- just render the list
460
+ // Good: Just show all items
244
461
  <ItemList items={items} />
245
462
  ```
246
463
 
247
- - **Handle loading states.** Disable pagination controls while data is being fetched to prevent race conditions from rapid page switches.
464
+ 2. **Don't hide the page count**: Users need to know how many pages exist
248
465
 
249
- - **Use the compact variant on small screens.** The standard variant with page numbers can overflow on narrow viewports. Switch to `variant="compact"` or reduce the `size` prop for responsive layouts.
466
+ 3. **Don't use inconsistent page sizes**: Keep pageSize consistent in session
250
467
 
251
- ## Accessibility
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
- - **ARIA attributes**: The current page button is marked with `aria-current="page"`. Previous and next buttons carry descriptive `aria-label` values such as "Previous page" and "Next page".
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.