@adamosuiteservices/ui 2.11.16 → 2.11.18

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 (66) hide show
  1. package/dist/accordion-rounded.cjs +1 -1
  2. package/dist/accordion-rounded.js +1 -1
  3. package/dist/badge.cjs +3 -3
  4. package/dist/badge.js +2 -2
  5. package/dist/breadcrumb.cjs +5 -5
  6. package/dist/breadcrumb.js +16 -16
  7. package/dist/components/ui/date-picker-selector/date-picker-selector.d.ts +2 -2
  8. package/dist/components/ui/sheet/sheet.d.ts +2 -1
  9. package/dist/date-picker-selector.cjs +1 -1
  10. package/dist/date-picker-selector.js +29 -30
  11. package/dist/dialog.cjs +1 -1
  12. package/dist/dialog.js +1 -1
  13. package/dist/select.cjs +2 -2
  14. package/dist/select.js +2 -2
  15. package/dist/{sheet-DVT_djHX.cjs → sheet-CvcCaGSl.cjs} +11 -11
  16. package/dist/{sheet-CPf9Guon.js → sheet-IRIc3TJ1.js} +33 -19
  17. package/dist/sheet.cjs +1 -1
  18. package/dist/sheet.js +7 -6
  19. package/dist/sidebar.cjs +1 -1
  20. package/dist/sidebar.js +1 -1
  21. package/dist/styles.css +1 -1
  22. package/dist/tabs-underline.cjs +3 -3
  23. package/dist/tabs-underline.js +13 -13
  24. package/dist/tabs.cjs +5 -4
  25. package/dist/tabs.js +3 -2
  26. package/dist/themes.css +1 -1
  27. package/docs/AI-GUIDE.md +321 -321
  28. package/docs/components/layout/sidebar.md +399 -399
  29. package/docs/components/layout/toaster.md +436 -436
  30. package/docs/components/ui/accordion-rounded.md +584 -584
  31. package/docs/components/ui/accordion.md +269 -269
  32. package/docs/components/ui/badge.md +2 -1
  33. package/docs/components/ui/button-group.md +984 -984
  34. package/docs/components/ui/button.md +1137 -1137
  35. package/docs/components/ui/calendar.md +1159 -1159
  36. package/docs/components/ui/card.md +1455 -1455
  37. package/docs/components/ui/checkbox.md +292 -292
  38. package/docs/components/ui/collapsible.md +323 -323
  39. package/docs/components/ui/command.md +454 -454
  40. package/docs/components/ui/context-menu.md +540 -540
  41. package/docs/components/ui/date-picker-selector.md +0 -2
  42. package/docs/components/ui/dialog.md +628 -628
  43. package/docs/components/ui/dropdown-menu.md +709 -709
  44. package/docs/components/ui/field.md +706 -706
  45. package/docs/components/ui/hover-card.md +446 -446
  46. package/docs/components/ui/input.md +362 -362
  47. package/docs/components/ui/kbd.md +434 -434
  48. package/docs/components/ui/label.md +359 -359
  49. package/docs/components/ui/pagination.md +650 -650
  50. package/docs/components/ui/popover.md +536 -536
  51. package/docs/components/ui/progress.md +182 -182
  52. package/docs/components/ui/radio-group.md +311 -311
  53. package/docs/components/ui/select.md +352 -352
  54. package/docs/components/ui/separator.md +214 -214
  55. package/docs/components/ui/sheet.md +174 -142
  56. package/docs/components/ui/skeleton.md +140 -140
  57. package/docs/components/ui/slider.md +341 -341
  58. package/docs/components/ui/spinner.md +170 -170
  59. package/docs/components/ui/switch.md +408 -408
  60. package/docs/components/ui/tabs-underline.md +106 -106
  61. package/docs/components/ui/tabs.md +122 -122
  62. package/docs/components/ui/textarea.md +243 -243
  63. package/docs/components/ui/toggle.md +237 -237
  64. package/docs/components/ui/tooltip.md +317 -317
  65. package/docs/components/ui/typography.md +280 -280
  66. package/package.json +1 -1
@@ -1,650 +1,650 @@
1
- # Pagination
2
-
3
- Controles de navegación para contenido paginado. Incluye Previous/Next, números de página, ellipsis para gaps y estado activo.
4
-
5
- ## Descripción
6
-
7
- El componente `Pagination` proporciona controles de navegación para contenido paginado.
8
-
9
- ## Importación
10
-
11
- ```typescript
12
- import {
13
- Pagination,
14
- PaginationContent,
15
- PaginationEllipsis,
16
- PaginationItem,
17
- PaginationLink,
18
- PaginationNext,
19
- PaginationPrevious,
20
- } from "@adamosuiteservices/ui/pagination";
21
- ```
22
-
23
- ## Anatomía
24
-
25
- ```tsx
26
- <Pagination>
27
- <PaginationContent>
28
- <PaginationItem>
29
- <PaginationPrevious href="#" />
30
- </PaginationItem>
31
- <PaginationItem>
32
- <PaginationLink href="#">1</PaginationLink>
33
- </PaginationItem>
34
- <PaginationItem>
35
- <PaginationLink href="#" isActive>
36
- 2
37
- </PaginationLink>
38
- </PaginationItem>
39
- <PaginationItem>
40
- <PaginationLink href="#">3</PaginationLink>
41
- </PaginationItem>
42
- <PaginationItem>
43
- <PaginationEllipsis />
44
- </PaginationItem>
45
- <PaginationItem>
46
- <PaginationNext href="#" />
47
- </PaginationItem>
48
- </PaginationContent>
49
- </Pagination>
50
- ```
51
-
52
- **Componentes**: 7 (Pagination, PaginationContent, PaginationItem, PaginationLink, PaginationPrevious, PaginationNext, PaginationEllipsis)
53
-
54
- ## Props Principales
55
-
56
- ### Pagination (Root)
57
-
58
- | Prop | Tipo | Descripción |
59
- | ----------- | -------- | ---------------------- |
60
- | `className` | `string` | Clases CSS adicionales |
61
-
62
- **Nota**: `<nav>` con `role="navigation"` y `aria-label="pagination"`
63
-
64
- ### PaginationContent
65
-
66
- | Prop | Tipo | Descripción |
67
- | ----------- | -------- | ---------------------- |
68
- | `className` | `string` | Clases CSS adicionales |
69
-
70
- **Nota**: `<ul>` con flex y gap-1
71
-
72
- ### PaginationItem
73
-
74
- | Prop | Tipo | Descripción |
75
- | ----------- | -------- | ---------------------- |
76
- | `className` | `string` | Clases CSS adicionales |
77
-
78
- **Nota**: `<li>` wrapper simple
79
-
80
- ### PaginationLink
81
-
82
- | Prop | Tipo | Default | Descripción |
83
- | ----------- | ------------- | -------- | ------------------------ |
84
- | `isActive` | `boolean` | `false` | Marca página como activa |
85
- | `size` | Button size | `"icon"` | Tamaño del link |
86
- | `href` | `string` | - | URL destino |
87
- | `onClick` | `(e) => void` | - | Click handler |
88
- | `className` | `string` | - | Clases CSS adicionales |
89
-
90
- **Nota**: `<a>` estilizado como Button
91
-
92
- ### PaginationPrevious
93
-
94
- | Prop | Tipo | Default | Descripción |
95
- | ----------- | ------------- | ------------ | ---------------------- |
96
- | `children` | `ReactNode` | `"Previous"` | Texto del botón |
97
- | `href` | `string` | - | URL destino |
98
- | `onClick` | `(e) => void` | - | Click handler |
99
- | `className` | `string` | - | Clases CSS adicionales |
100
-
101
- **Nota**: PaginationLink con chevron_left icon (Material Symbol), texto "Previous" oculto en mobile
102
-
103
- ### PaginationNext
104
-
105
- | Prop | Tipo | Default | Descripción |
106
- | ----------- | ------------- | -------- | ---------------------- |
107
- | `children` | `ReactNode` | `"Next"` | Texto del botón |
108
- | `href` | `string` | - | URL destino |
109
- | `onClick` | `(e) => void` | - | Click handler |
110
- | `className` | `string` | - | Clases CSS adicionales |
111
-
112
- **Nota**: PaginationLink con chevron_right icon (Material Symbol), texto "Next" oculto en mobile
113
-
114
- ### PaginationEllipsis
115
-
116
- | Prop | Tipo | Descripción |
117
- | ----------- | -------- | ---------------------- |
118
- | `className` | `string` | Clases CSS adicionales |
119
-
120
- **Nota**: `<span>` con more_horiz icon (Material Symbol) y `aria-hidden`
121
-
122
- ## Patrones de Uso
123
-
124
- ### Básico
125
-
126
- ```tsx
127
- <Pagination>
128
- <PaginationContent>
129
- <PaginationItem>
130
- <PaginationPrevious href="#" />
131
- </PaginationItem>
132
- <PaginationItem>
133
- <PaginationLink href="#">1</PaginationLink>
134
- </PaginationItem>
135
- <PaginationItem>
136
- <PaginationLink href="#" isActive>
137
- 2
138
- </PaginationLink>
139
- </PaginationItem>
140
- <PaginationItem>
141
- <PaginationLink href="#">3</PaginationLink>
142
- </PaginationItem>
143
- <PaginationItem>
144
- <PaginationEllipsis />
145
- </PaginationItem>
146
- <PaginationItem>
147
- <PaginationNext href="#" />
148
- </PaginationItem>
149
- </PaginationContent>
150
- </Pagination>
151
- ```
152
-
153
- ### Simple (Sin Ellipsis)
154
-
155
- ```tsx
156
- <Pagination>
157
- <PaginationContent>
158
- <PaginationItem>
159
- <PaginationPrevious href="#" />
160
- </PaginationItem>
161
- <PaginationItem>
162
- <PaginationLink href="#">1</PaginationLink>
163
- </PaginationItem>
164
- <PaginationItem>
165
- <PaginationLink href="#">2</PaginationLink>
166
- </PaginationItem>
167
- <PaginationItem>
168
- <PaginationLink href="#">3</PaginationLink>
169
- </PaginationItem>
170
- <PaginationItem>
171
- <PaginationNext href="#" />
172
- </PaginationItem>
173
- </PaginationContent>
174
- </Pagination>
175
- ```
176
-
177
- ### Con Ellipsis Doble
178
-
179
- ```tsx
180
- <Pagination>
181
- <PaginationContent>
182
- <PaginationItem>
183
- <PaginationPrevious href="#" />
184
- </PaginationItem>
185
- <PaginationItem>
186
- <PaginationLink href="#">1</PaginationLink>
187
- </PaginationItem>
188
- <PaginationItem>
189
- <PaginationEllipsis />
190
- </PaginationItem>
191
- <PaginationItem>
192
- <PaginationLink href="#">10</PaginationLink>
193
- </PaginationItem>
194
- <PaginationItem>
195
- <PaginationLink href="#" isActive>
196
- 11
197
- </PaginationLink>
198
- </PaginationItem>
199
- <PaginationItem>
200
- <PaginationLink href="#">12</PaginationLink>
201
- </PaginationItem>
202
- <PaginationItem>
203
- <PaginationEllipsis />
204
- </PaginationItem>
205
- <PaginationItem>
206
- <PaginationLink href="#">50</PaginationLink>
207
- </PaginationItem>
208
- <PaginationItem>
209
- <PaginationNext href="#" />
210
- </PaginationItem>
211
- </PaginationContent>
212
- </Pagination>
213
- ```
214
-
215
- ### Primera Página (Disabled Previous)
216
-
217
- ```tsx
218
- <Pagination>
219
- <PaginationContent>
220
- <PaginationItem>
221
- <PaginationPrevious href="#" className="pointer-events-none opacity-50" />
222
- </PaginationItem>
223
- <PaginationItem>
224
- <PaginationLink href="#" isActive>
225
- 1
226
- </PaginationLink>
227
- </PaginationItem>
228
- <PaginationItem>
229
- <PaginationLink href="#">2</PaginationLink>
230
- </PaginationItem>
231
- <PaginationItem>
232
- <PaginationLink href="#">3</PaginationLink>
233
- </PaginationItem>
234
- <PaginationItem>
235
- <PaginationEllipsis />
236
- </PaginationItem>
237
- <PaginationItem>
238
- <PaginationLink href="#">25</PaginationLink>
239
- </PaginationItem>
240
- <PaginationItem>
241
- <PaginationNext href="#" />
242
- </PaginationItem>
243
- </PaginationContent>
244
- </Pagination>
245
- ```
246
-
247
- ### Última Página (Disabled Next)
248
-
249
- ```tsx
250
- <Pagination>
251
- <PaginationContent>
252
- <PaginationItem>
253
- <PaginationPrevious href="#" />
254
- </PaginationItem>
255
- <PaginationItem>
256
- <PaginationLink href="#">1</PaginationLink>
257
- </PaginationItem>
258
- <PaginationItem>
259
- <PaginationEllipsis />
260
- </PaginationItem>
261
- <PaginationItem>
262
- <PaginationLink href="#">23</PaginationLink>
263
- </PaginationItem>
264
- <PaginationItem>
265
- <PaginationLink href="#">24</PaginationLink>
266
- </PaginationItem>
267
- <PaginationItem>
268
- <PaginationLink href="#" isActive>
269
- 25
270
- </PaginationLink>
271
- </PaginationItem>
272
- <PaginationItem>
273
- <PaginationNext href="#" className="pointer-events-none opacity-50" />
274
- </PaginationItem>
275
- </PaginationContent>
276
- </Pagination>
277
- ```
278
-
279
- ### Página Única
280
-
281
- ```tsx
282
- <Pagination>
283
- <PaginationContent>
284
- <PaginationItem>
285
- <PaginationPrevious href="#" className="pointer-events-none opacity-50" />
286
- </PaginationItem>
287
- <PaginationItem>
288
- <PaginationLink href="#" isActive>
289
- 1
290
- </PaginationLink>
291
- </PaginationItem>
292
- <PaginationItem>
293
- <PaginationNext href="#" className="pointer-events-none opacity-50" />
294
- </PaginationItem>
295
- </PaginationContent>
296
- </Pagination>
297
- ```
298
-
299
- ### Compacto (Solo Previous/Next)
300
-
301
- ```tsx
302
- <Pagination className="justify-start">
303
- <PaginationContent>
304
- <PaginationItem>
305
- <PaginationPrevious href="#" />
306
- </PaginationItem>
307
- <PaginationItem>
308
- <PaginationNext href="#" />
309
- </PaginationItem>
310
- </PaginationContent>
311
- </Pagination>
312
- ```
313
-
314
- ### Con Información de Página
315
-
316
- ```tsx
317
- <div className="space-y-4">
318
- <div className="flex items-center justify-between text-sm text-muted-foreground">
319
- <span>Showing 1-10 of 250 results</span>
320
- <span>Page 2 of 25</span>
321
- </div>
322
-
323
- <Pagination>
324
- <PaginationContent>
325
- <PaginationItem>
326
- <PaginationPrevious href="#" />
327
- </PaginationItem>
328
- <PaginationItem>
329
- <PaginationLink href="#">1</PaginationLink>
330
- </PaginationItem>
331
- <PaginationItem>
332
- <PaginationLink href="#" isActive>
333
- 2
334
- </PaginationLink>
335
- </PaginationItem>
336
- <PaginationItem>
337
- <PaginationLink href="#">3</PaginationLink>
338
- </PaginationItem>
339
- <PaginationItem>
340
- <PaginationEllipsis />
341
- </PaginationItem>
342
- <PaginationItem>
343
- <PaginationLink href="#">25</PaginationLink>
344
- </PaginationItem>
345
- <PaginationItem>
346
- <PaginationNext href="#" />
347
- </PaginationItem>
348
- </PaginationContent>
349
- </Pagination>
350
- </div>
351
- ```
352
-
353
- ### Interactivo (Con Estado)
354
-
355
- ```tsx
356
- import { useState } from "react";
357
-
358
- function App() {
359
- const [currentPage, setCurrentPage] = useState(5);
360
- const totalPages = 20;
361
-
362
- const generatePageNumbers = () => {
363
- const pages = [];
364
-
365
- // Always show first page
366
- pages.push(1);
367
-
368
- // Add ellipsis if there's a gap
369
- if (currentPage > 4) {
370
- pages.push(-1); // -1 represents ellipsis
371
- }
372
-
373
- // Show pages around current page
374
- const start = Math.max(2, currentPage - 1);
375
- const end = Math.min(totalPages - 1, currentPage + 1);
376
-
377
- for (let i = start; i <= end; i++) {
378
- if (i !== 1 && i !== totalPages) {
379
- pages.push(i);
380
- }
381
- }
382
-
383
- // Add ellipsis if there's a gap
384
- if (currentPage < totalPages - 3) {
385
- pages.push(-2); // -2 represents ellipsis
386
- }
387
-
388
- // Always show last page if more than 1 page
389
- if (totalPages > 1) {
390
- pages.push(totalPages);
391
- }
392
-
393
- return pages;
394
- };
395
-
396
- const pages = generatePageNumbers();
397
-
398
- const handlePageClick = (page: number) => {
399
- setCurrentPage(page);
400
- };
401
-
402
- const handlePrevious = () => {
403
- if (currentPage > 1) {
404
- setCurrentPage(currentPage - 1);
405
- }
406
- };
407
-
408
- const handleNext = () => {
409
- if (currentPage < totalPages) {
410
- setCurrentPage(currentPage + 1);
411
- }
412
- };
413
-
414
- return (
415
- <div className="space-y-4">
416
- <p className="text-center text-sm text-muted-foreground">
417
- Page {currentPage} of {totalPages}
418
- </p>
419
-
420
- <Pagination>
421
- <PaginationContent>
422
- <PaginationItem>
423
- <PaginationPrevious
424
- href="#"
425
- onClick={(e) => {
426
- e.preventDefault();
427
- handlePrevious();
428
- }}
429
- className={
430
- currentPage === 1 ? "pointer-events-none opacity-50" : ""
431
- }
432
- />
433
- </PaginationItem>
434
-
435
- {pages.map((page, index) => (
436
- <PaginationItem key={index}>
437
- {page < 0 ? (
438
- <PaginationEllipsis />
439
- ) : (
440
- <PaginationLink
441
- href="#"
442
- isActive={page === currentPage}
443
- onClick={(e) => {
444
- e.preventDefault();
445
- handlePageClick(page);
446
- }}
447
- >
448
- {page}
449
- </PaginationLink>
450
- )}
451
- </PaginationItem>
452
- ))}
453
-
454
- <PaginationItem>
455
- <PaginationNext
456
- href="#"
457
- onClick={(e) => {
458
- e.preventDefault();
459
- handleNext();
460
- }}
461
- className={
462
- currentPage === totalPages
463
- ? "pointer-events-none opacity-50"
464
- : ""
465
- }
466
- />
467
- </PaginationItem>
468
- </PaginationContent>
469
- </Pagination>
470
- </div>
471
- );
472
- }
473
- ```
474
-
475
- ### Tamaños Personalizados
476
-
477
- ```tsx
478
- {
479
- /* Small */
480
- }
481
- <Pagination>
482
- <PaginationContent className="gap-0.5">
483
- <PaginationItem>
484
- <PaginationPrevious href="#" className="h-8 px-2 text-xs" />
485
- </PaginationItem>
486
- <PaginationItem>
487
- <PaginationLink href="#" className="h-8 w-8 text-xs">
488
- 1
489
- </PaginationLink>
490
- </PaginationItem>
491
- <PaginationItem>
492
- <PaginationLink href="#" isActive className="h-8 w-8 text-xs">
493
- 2
494
- </PaginationLink>
495
- </PaginationItem>
496
- <PaginationItem>
497
- <PaginationNext href="#" className="h-8 px-2 text-xs" />
498
- </PaginationItem>
499
- </PaginationContent>
500
- </Pagination>;
501
-
502
- {
503
- /* Large */
504
- }
505
- <Pagination>
506
- <PaginationContent className="gap-2">
507
- <PaginationItem>
508
- <PaginationPrevious href="#" className="h-12 px-4 text-base" />
509
- </PaginationItem>
510
- <PaginationItem>
511
- <PaginationLink href="#" className="h-12 w-12 text-base">
512
- 1
513
- </PaginationLink>
514
- </PaginationItem>
515
- <PaginationItem>
516
- <PaginationLink href="#" isActive className="h-12 w-12 text-base">
517
- 2
518
- </PaginationLink>
519
- </PaginationItem>
520
- <PaginationItem>
521
- <PaginationNext href="#" className="h-12 px-4 text-base" />
522
- </PaginationItem>
523
- </PaginationContent>
524
- </Pagination>;
525
- ```
526
-
527
- ## Casos de Uso Comunes
528
-
529
- **Tables**: Paginación de tablas con muchas filas
530
- **Lists**: Listas largas de items (productos, usuarios, posts)
531
- **Search results**: Resultados de búsqueda paginados
532
- **Galleries**: Galerías de imágenes o archivos
533
- **Admin panels**: Dashboards con data paginada
534
- **API results**: Navegación de resultados de API con offset/limit
535
-
536
- ## Estados y Data Attributes
537
-
538
- ### PaginationLink
539
-
540
- - **Active**: `isActive` → variant outline, `aria-current="page"`
541
- - **Inactive**: variant ghost
542
-
543
- ### Disabled (Previous/Next)
544
-
545
- No hay prop disabled nativa, se simula con:
546
-
547
- ```tsx
548
- className = "pointer-events-none opacity-50";
549
- ```
550
-
551
- ## Estilos Base
552
-
553
- ### Pagination (Root)
554
-
555
- - **Layout**: `mx-auto flex w-full justify-center`
556
- - **Semantic**: `<nav role="navigation" aria-label="pagination">`
557
-
558
- ### PaginationContent
559
-
560
- - **Layout**: `flex flex-row items-center gap-1`
561
-
562
- ### PaginationLink
563
-
564
- - **Size default**: `size="icon"` (h-9 w-9)
565
- - **Variants**: ghost (inactive), outline (active)
566
-
567
- ### PaginationPrevious/Next
568
-
569
- - **Size**: `size="default"`
570
- - **Padding**: `px-2.5`
571
- - **Responsive**: Texto oculto en mobile (`hidden sm:block`)
572
- - **Gap**: `gap-1` entre icono y texto
573
-
574
- ### PaginationEllipsis
575
-
576
- - **Size**: `size-9`
577
- - **Icon**: more_horiz (Material Symbol) con `text-lg`
578
- - **Layout**: `flex items-center justify-center`
579
- - **ARIA**: `aria-hidden`
580
-
581
- ## Responsive
582
-
583
- - **Mobile**: Previous/Next solo muestran icono
584
- - **Desktop (sm+)**: Previous/Next muestran icono + texto
585
-
586
- ## Accesibilidad
587
-
588
- - ✅ **Semantic**: `<nav role="navigation" aria-label="pagination">`
589
- - ✅ **Current page**: `aria-current="page"` en página activa
590
- - ✅ **Screen readers**: Ellipsis tiene `<span className="sr-only">More pages</span>`
591
- - ✅ **Keyboard**: Navegación con Tab, activación con Enter/Space
592
- - ✅ **Labels**: Previous/Next tienen `aria-label` descriptivo
593
- - ⚠️ **Disabled**: Usa `pointer-events-none opacity-50` + previene click en handler
594
-
595
- ## Notas de Implementación
596
-
597
- - **Links**: PaginationLink es `<a>` no `<button>`, usa Button styles
598
- - **Icons**: chevron_left, chevron_right, more_horiz (Material Symbols)
599
- - **Responsive text**: Previous/Next usan `hidden sm:block` en texto
600
- - **No state**: Componente stateless, maneja estado externamente
601
- - **Ellipsis logic**: Representación negativa (-1, -2) común para identificar ellipsis
602
- - **Disabled**: No hay prop disabled, usa className manual
603
- - **Centering**: Root tiene `mx-auto justify-center`
604
-
605
- ## Algoritmo de Generación de Páginas
606
-
607
- Patrón común para mostrar páginas con ellipsis:
608
-
609
- ```tsx
610
- const generatePageNumbers = (current: number, total: number) => {
611
- const pages = [];
612
-
613
- // Siempre primera página
614
- pages.push(1);
615
-
616
- // Ellipsis izquierda si hay gap
617
- if (current > 4) pages.push(-1);
618
-
619
- // Páginas alrededor de current
620
- const start = Math.max(2, current - 1);
621
- const end = Math.min(total - 1, current + 1);
622
- for (let i = start; i <= end; i++) {
623
- if (i !== 1 && i !== total) pages.push(i);
624
- }
625
-
626
- // Ellipsis derecha si hay gap
627
- if (current < total - 3) pages.push(-2);
628
-
629
- // Siempre última página
630
- if (total > 1) pages.push(total);
631
-
632
- return pages;
633
- };
634
- ```
635
-
636
- ## Troubleshooting
637
-
638
- **Previous/Next no se deshabilitan**: No hay prop disabled, usa `className="pointer-events-none opacity-50"` y previene click en handler
639
- **Active no se ve**: Verifica `isActive` prop y que solo una página lo tenga
640
- **Texto Previous/Next no se ve en mobile**: Comportamiento esperado, usa `hidden sm:block`
641
- **Ellipsis clickeable**: Ellipsis no debe ser clickeable, es `<span>` no link
642
- **Spacing inconsistente**: PaginationContent tiene `gap-1`, ajusta con className
643
- **No centrado**: Root tiene `justify-center`, override con `className="justify-start"` si necesario
644
- **Links no funcionan**: PaginationLink usa `<a>`, asegúrate de pasar `href` o `onClick`
645
- **Too many pages**: Usa ellipsis y lógica de generación de páginas para mostrar subset
646
-
647
- ## Referencias
648
-
649
- - **shadcn/ui Pagination**: <https://ui.shadcn.com/docs/components/pagination>
650
- - **WAI-ARIA Pagination**: <https://www.w3.org/WAI/ARIA/apg/patterns/pagination/>
1
+ # Pagination
2
+
3
+ Controles de navegación para contenido paginado. Incluye Previous/Next, números de página, ellipsis para gaps y estado activo.
4
+
5
+ ## Descripción
6
+
7
+ El componente `Pagination` proporciona controles de navegación para contenido paginado.
8
+
9
+ ## Importación
10
+
11
+ ```typescript
12
+ import {
13
+ Pagination,
14
+ PaginationContent,
15
+ PaginationEllipsis,
16
+ PaginationItem,
17
+ PaginationLink,
18
+ PaginationNext,
19
+ PaginationPrevious,
20
+ } from "@adamosuiteservices/ui/pagination";
21
+ ```
22
+
23
+ ## Anatomía
24
+
25
+ ```tsx
26
+ <Pagination>
27
+ <PaginationContent>
28
+ <PaginationItem>
29
+ <PaginationPrevious href="#" />
30
+ </PaginationItem>
31
+ <PaginationItem>
32
+ <PaginationLink href="#">1</PaginationLink>
33
+ </PaginationItem>
34
+ <PaginationItem>
35
+ <PaginationLink href="#" isActive>
36
+ 2
37
+ </PaginationLink>
38
+ </PaginationItem>
39
+ <PaginationItem>
40
+ <PaginationLink href="#">3</PaginationLink>
41
+ </PaginationItem>
42
+ <PaginationItem>
43
+ <PaginationEllipsis />
44
+ </PaginationItem>
45
+ <PaginationItem>
46
+ <PaginationNext href="#" />
47
+ </PaginationItem>
48
+ </PaginationContent>
49
+ </Pagination>
50
+ ```
51
+
52
+ **Componentes**: 7 (Pagination, PaginationContent, PaginationItem, PaginationLink, PaginationPrevious, PaginationNext, PaginationEllipsis)
53
+
54
+ ## Props Principales
55
+
56
+ ### Pagination (Root)
57
+
58
+ | Prop | Tipo | Descripción |
59
+ | ----------- | -------- | ---------------------- |
60
+ | `className` | `string` | Clases CSS adicionales |
61
+
62
+ **Nota**: `<nav>` con `role="navigation"` y `aria-label="pagination"`
63
+
64
+ ### PaginationContent
65
+
66
+ | Prop | Tipo | Descripción |
67
+ | ----------- | -------- | ---------------------- |
68
+ | `className` | `string` | Clases CSS adicionales |
69
+
70
+ **Nota**: `<ul>` con flex y gap-1
71
+
72
+ ### PaginationItem
73
+
74
+ | Prop | Tipo | Descripción |
75
+ | ----------- | -------- | ---------------------- |
76
+ | `className` | `string` | Clases CSS adicionales |
77
+
78
+ **Nota**: `<li>` wrapper simple
79
+
80
+ ### PaginationLink
81
+
82
+ | Prop | Tipo | Default | Descripción |
83
+ | ----------- | ------------- | -------- | ------------------------ |
84
+ | `isActive` | `boolean` | `false` | Marca página como activa |
85
+ | `size` | Button size | `"icon"` | Tamaño del link |
86
+ | `href` | `string` | - | URL destino |
87
+ | `onClick` | `(e) => void` | - | Click handler |
88
+ | `className` | `string` | - | Clases CSS adicionales |
89
+
90
+ **Nota**: `<a>` estilizado como Button
91
+
92
+ ### PaginationPrevious
93
+
94
+ | Prop | Tipo | Default | Descripción |
95
+ | ----------- | ------------- | ------------ | ---------------------- |
96
+ | `children` | `ReactNode` | `"Previous"` | Texto del botón |
97
+ | `href` | `string` | - | URL destino |
98
+ | `onClick` | `(e) => void` | - | Click handler |
99
+ | `className` | `string` | - | Clases CSS adicionales |
100
+
101
+ **Nota**: PaginationLink con chevron_left icon (Material Symbol), texto "Previous" oculto en mobile
102
+
103
+ ### PaginationNext
104
+
105
+ | Prop | Tipo | Default | Descripción |
106
+ | ----------- | ------------- | -------- | ---------------------- |
107
+ | `children` | `ReactNode` | `"Next"` | Texto del botón |
108
+ | `href` | `string` | - | URL destino |
109
+ | `onClick` | `(e) => void` | - | Click handler |
110
+ | `className` | `string` | - | Clases CSS adicionales |
111
+
112
+ **Nota**: PaginationLink con chevron_right icon (Material Symbol), texto "Next" oculto en mobile
113
+
114
+ ### PaginationEllipsis
115
+
116
+ | Prop | Tipo | Descripción |
117
+ | ----------- | -------- | ---------------------- |
118
+ | `className` | `string` | Clases CSS adicionales |
119
+
120
+ **Nota**: `<span>` con more_horiz icon (Material Symbol) y `aria-hidden`
121
+
122
+ ## Patrones de Uso
123
+
124
+ ### Básico
125
+
126
+ ```tsx
127
+ <Pagination>
128
+ <PaginationContent>
129
+ <PaginationItem>
130
+ <PaginationPrevious href="#" />
131
+ </PaginationItem>
132
+ <PaginationItem>
133
+ <PaginationLink href="#">1</PaginationLink>
134
+ </PaginationItem>
135
+ <PaginationItem>
136
+ <PaginationLink href="#" isActive>
137
+ 2
138
+ </PaginationLink>
139
+ </PaginationItem>
140
+ <PaginationItem>
141
+ <PaginationLink href="#">3</PaginationLink>
142
+ </PaginationItem>
143
+ <PaginationItem>
144
+ <PaginationEllipsis />
145
+ </PaginationItem>
146
+ <PaginationItem>
147
+ <PaginationNext href="#" />
148
+ </PaginationItem>
149
+ </PaginationContent>
150
+ </Pagination>
151
+ ```
152
+
153
+ ### Simple (Sin Ellipsis)
154
+
155
+ ```tsx
156
+ <Pagination>
157
+ <PaginationContent>
158
+ <PaginationItem>
159
+ <PaginationPrevious href="#" />
160
+ </PaginationItem>
161
+ <PaginationItem>
162
+ <PaginationLink href="#">1</PaginationLink>
163
+ </PaginationItem>
164
+ <PaginationItem>
165
+ <PaginationLink href="#">2</PaginationLink>
166
+ </PaginationItem>
167
+ <PaginationItem>
168
+ <PaginationLink href="#">3</PaginationLink>
169
+ </PaginationItem>
170
+ <PaginationItem>
171
+ <PaginationNext href="#" />
172
+ </PaginationItem>
173
+ </PaginationContent>
174
+ </Pagination>
175
+ ```
176
+
177
+ ### Con Ellipsis Doble
178
+
179
+ ```tsx
180
+ <Pagination>
181
+ <PaginationContent>
182
+ <PaginationItem>
183
+ <PaginationPrevious href="#" />
184
+ </PaginationItem>
185
+ <PaginationItem>
186
+ <PaginationLink href="#">1</PaginationLink>
187
+ </PaginationItem>
188
+ <PaginationItem>
189
+ <PaginationEllipsis />
190
+ </PaginationItem>
191
+ <PaginationItem>
192
+ <PaginationLink href="#">10</PaginationLink>
193
+ </PaginationItem>
194
+ <PaginationItem>
195
+ <PaginationLink href="#" isActive>
196
+ 11
197
+ </PaginationLink>
198
+ </PaginationItem>
199
+ <PaginationItem>
200
+ <PaginationLink href="#">12</PaginationLink>
201
+ </PaginationItem>
202
+ <PaginationItem>
203
+ <PaginationEllipsis />
204
+ </PaginationItem>
205
+ <PaginationItem>
206
+ <PaginationLink href="#">50</PaginationLink>
207
+ </PaginationItem>
208
+ <PaginationItem>
209
+ <PaginationNext href="#" />
210
+ </PaginationItem>
211
+ </PaginationContent>
212
+ </Pagination>
213
+ ```
214
+
215
+ ### Primera Página (Disabled Previous)
216
+
217
+ ```tsx
218
+ <Pagination>
219
+ <PaginationContent>
220
+ <PaginationItem>
221
+ <PaginationPrevious href="#" className="pointer-events-none opacity-50" />
222
+ </PaginationItem>
223
+ <PaginationItem>
224
+ <PaginationLink href="#" isActive>
225
+ 1
226
+ </PaginationLink>
227
+ </PaginationItem>
228
+ <PaginationItem>
229
+ <PaginationLink href="#">2</PaginationLink>
230
+ </PaginationItem>
231
+ <PaginationItem>
232
+ <PaginationLink href="#">3</PaginationLink>
233
+ </PaginationItem>
234
+ <PaginationItem>
235
+ <PaginationEllipsis />
236
+ </PaginationItem>
237
+ <PaginationItem>
238
+ <PaginationLink href="#">25</PaginationLink>
239
+ </PaginationItem>
240
+ <PaginationItem>
241
+ <PaginationNext href="#" />
242
+ </PaginationItem>
243
+ </PaginationContent>
244
+ </Pagination>
245
+ ```
246
+
247
+ ### Última Página (Disabled Next)
248
+
249
+ ```tsx
250
+ <Pagination>
251
+ <PaginationContent>
252
+ <PaginationItem>
253
+ <PaginationPrevious href="#" />
254
+ </PaginationItem>
255
+ <PaginationItem>
256
+ <PaginationLink href="#">1</PaginationLink>
257
+ </PaginationItem>
258
+ <PaginationItem>
259
+ <PaginationEllipsis />
260
+ </PaginationItem>
261
+ <PaginationItem>
262
+ <PaginationLink href="#">23</PaginationLink>
263
+ </PaginationItem>
264
+ <PaginationItem>
265
+ <PaginationLink href="#">24</PaginationLink>
266
+ </PaginationItem>
267
+ <PaginationItem>
268
+ <PaginationLink href="#" isActive>
269
+ 25
270
+ </PaginationLink>
271
+ </PaginationItem>
272
+ <PaginationItem>
273
+ <PaginationNext href="#" className="pointer-events-none opacity-50" />
274
+ </PaginationItem>
275
+ </PaginationContent>
276
+ </Pagination>
277
+ ```
278
+
279
+ ### Página Única
280
+
281
+ ```tsx
282
+ <Pagination>
283
+ <PaginationContent>
284
+ <PaginationItem>
285
+ <PaginationPrevious href="#" className="pointer-events-none opacity-50" />
286
+ </PaginationItem>
287
+ <PaginationItem>
288
+ <PaginationLink href="#" isActive>
289
+ 1
290
+ </PaginationLink>
291
+ </PaginationItem>
292
+ <PaginationItem>
293
+ <PaginationNext href="#" className="pointer-events-none opacity-50" />
294
+ </PaginationItem>
295
+ </PaginationContent>
296
+ </Pagination>
297
+ ```
298
+
299
+ ### Compacto (Solo Previous/Next)
300
+
301
+ ```tsx
302
+ <Pagination className="justify-start">
303
+ <PaginationContent>
304
+ <PaginationItem>
305
+ <PaginationPrevious href="#" />
306
+ </PaginationItem>
307
+ <PaginationItem>
308
+ <PaginationNext href="#" />
309
+ </PaginationItem>
310
+ </PaginationContent>
311
+ </Pagination>
312
+ ```
313
+
314
+ ### Con Información de Página
315
+
316
+ ```tsx
317
+ <div className="space-y-4">
318
+ <div className="flex items-center justify-between text-sm text-muted-foreground">
319
+ <span>Showing 1-10 of 250 results</span>
320
+ <span>Page 2 of 25</span>
321
+ </div>
322
+
323
+ <Pagination>
324
+ <PaginationContent>
325
+ <PaginationItem>
326
+ <PaginationPrevious href="#" />
327
+ </PaginationItem>
328
+ <PaginationItem>
329
+ <PaginationLink href="#">1</PaginationLink>
330
+ </PaginationItem>
331
+ <PaginationItem>
332
+ <PaginationLink href="#" isActive>
333
+ 2
334
+ </PaginationLink>
335
+ </PaginationItem>
336
+ <PaginationItem>
337
+ <PaginationLink href="#">3</PaginationLink>
338
+ </PaginationItem>
339
+ <PaginationItem>
340
+ <PaginationEllipsis />
341
+ </PaginationItem>
342
+ <PaginationItem>
343
+ <PaginationLink href="#">25</PaginationLink>
344
+ </PaginationItem>
345
+ <PaginationItem>
346
+ <PaginationNext href="#" />
347
+ </PaginationItem>
348
+ </PaginationContent>
349
+ </Pagination>
350
+ </div>
351
+ ```
352
+
353
+ ### Interactivo (Con Estado)
354
+
355
+ ```tsx
356
+ import { useState } from "react";
357
+
358
+ function App() {
359
+ const [currentPage, setCurrentPage] = useState(5);
360
+ const totalPages = 20;
361
+
362
+ const generatePageNumbers = () => {
363
+ const pages = [];
364
+
365
+ // Always show first page
366
+ pages.push(1);
367
+
368
+ // Add ellipsis if there's a gap
369
+ if (currentPage > 4) {
370
+ pages.push(-1); // -1 represents ellipsis
371
+ }
372
+
373
+ // Show pages around current page
374
+ const start = Math.max(2, currentPage - 1);
375
+ const end = Math.min(totalPages - 1, currentPage + 1);
376
+
377
+ for (let i = start; i <= end; i++) {
378
+ if (i !== 1 && i !== totalPages) {
379
+ pages.push(i);
380
+ }
381
+ }
382
+
383
+ // Add ellipsis if there's a gap
384
+ if (currentPage < totalPages - 3) {
385
+ pages.push(-2); // -2 represents ellipsis
386
+ }
387
+
388
+ // Always show last page if more than 1 page
389
+ if (totalPages > 1) {
390
+ pages.push(totalPages);
391
+ }
392
+
393
+ return pages;
394
+ };
395
+
396
+ const pages = generatePageNumbers();
397
+
398
+ const handlePageClick = (page: number) => {
399
+ setCurrentPage(page);
400
+ };
401
+
402
+ const handlePrevious = () => {
403
+ if (currentPage > 1) {
404
+ setCurrentPage(currentPage - 1);
405
+ }
406
+ };
407
+
408
+ const handleNext = () => {
409
+ if (currentPage < totalPages) {
410
+ setCurrentPage(currentPage + 1);
411
+ }
412
+ };
413
+
414
+ return (
415
+ <div className="space-y-4">
416
+ <p className="text-center text-sm text-muted-foreground">
417
+ Page {currentPage} of {totalPages}
418
+ </p>
419
+
420
+ <Pagination>
421
+ <PaginationContent>
422
+ <PaginationItem>
423
+ <PaginationPrevious
424
+ href="#"
425
+ onClick={(e) => {
426
+ e.preventDefault();
427
+ handlePrevious();
428
+ }}
429
+ className={
430
+ currentPage === 1 ? "pointer-events-none opacity-50" : ""
431
+ }
432
+ />
433
+ </PaginationItem>
434
+
435
+ {pages.map((page, index) => (
436
+ <PaginationItem key={index}>
437
+ {page < 0 ? (
438
+ <PaginationEllipsis />
439
+ ) : (
440
+ <PaginationLink
441
+ href="#"
442
+ isActive={page === currentPage}
443
+ onClick={(e) => {
444
+ e.preventDefault();
445
+ handlePageClick(page);
446
+ }}
447
+ >
448
+ {page}
449
+ </PaginationLink>
450
+ )}
451
+ </PaginationItem>
452
+ ))}
453
+
454
+ <PaginationItem>
455
+ <PaginationNext
456
+ href="#"
457
+ onClick={(e) => {
458
+ e.preventDefault();
459
+ handleNext();
460
+ }}
461
+ className={
462
+ currentPage === totalPages
463
+ ? "pointer-events-none opacity-50"
464
+ : ""
465
+ }
466
+ />
467
+ </PaginationItem>
468
+ </PaginationContent>
469
+ </Pagination>
470
+ </div>
471
+ );
472
+ }
473
+ ```
474
+
475
+ ### Tamaños Personalizados
476
+
477
+ ```tsx
478
+ {
479
+ /* Small */
480
+ }
481
+ <Pagination>
482
+ <PaginationContent className="gap-0.5">
483
+ <PaginationItem>
484
+ <PaginationPrevious href="#" className="h-8 px-2 text-xs" />
485
+ </PaginationItem>
486
+ <PaginationItem>
487
+ <PaginationLink href="#" className="h-8 w-8 text-xs">
488
+ 1
489
+ </PaginationLink>
490
+ </PaginationItem>
491
+ <PaginationItem>
492
+ <PaginationLink href="#" isActive className="h-8 w-8 text-xs">
493
+ 2
494
+ </PaginationLink>
495
+ </PaginationItem>
496
+ <PaginationItem>
497
+ <PaginationNext href="#" className="h-8 px-2 text-xs" />
498
+ </PaginationItem>
499
+ </PaginationContent>
500
+ </Pagination>;
501
+
502
+ {
503
+ /* Large */
504
+ }
505
+ <Pagination>
506
+ <PaginationContent className="gap-2">
507
+ <PaginationItem>
508
+ <PaginationPrevious href="#" className="h-12 px-4 text-base" />
509
+ </PaginationItem>
510
+ <PaginationItem>
511
+ <PaginationLink href="#" className="h-12 w-12 text-base">
512
+ 1
513
+ </PaginationLink>
514
+ </PaginationItem>
515
+ <PaginationItem>
516
+ <PaginationLink href="#" isActive className="h-12 w-12 text-base">
517
+ 2
518
+ </PaginationLink>
519
+ </PaginationItem>
520
+ <PaginationItem>
521
+ <PaginationNext href="#" className="h-12 px-4 text-base" />
522
+ </PaginationItem>
523
+ </PaginationContent>
524
+ </Pagination>;
525
+ ```
526
+
527
+ ## Casos de Uso Comunes
528
+
529
+ **Tables**: Paginación de tablas con muchas filas
530
+ **Lists**: Listas largas de items (productos, usuarios, posts)
531
+ **Search results**: Resultados de búsqueda paginados
532
+ **Galleries**: Galerías de imágenes o archivos
533
+ **Admin panels**: Dashboards con data paginada
534
+ **API results**: Navegación de resultados de API con offset/limit
535
+
536
+ ## Estados y Data Attributes
537
+
538
+ ### PaginationLink
539
+
540
+ - **Active**: `isActive` → variant outline, `aria-current="page"`
541
+ - **Inactive**: variant ghost
542
+
543
+ ### Disabled (Previous/Next)
544
+
545
+ No hay prop disabled nativa, se simula con:
546
+
547
+ ```tsx
548
+ className = "pointer-events-none opacity-50";
549
+ ```
550
+
551
+ ## Estilos Base
552
+
553
+ ### Pagination (Root)
554
+
555
+ - **Layout**: `mx-auto flex w-full justify-center`
556
+ - **Semantic**: `<nav role="navigation" aria-label="pagination">`
557
+
558
+ ### PaginationContent
559
+
560
+ - **Layout**: `flex flex-row items-center gap-1`
561
+
562
+ ### PaginationLink
563
+
564
+ - **Size default**: `size="icon"` (h-9 w-9)
565
+ - **Variants**: ghost (inactive), outline (active)
566
+
567
+ ### PaginationPrevious/Next
568
+
569
+ - **Size**: `size="default"`
570
+ - **Padding**: `px-2.5`
571
+ - **Responsive**: Texto oculto en mobile (`hidden sm:block`)
572
+ - **Gap**: `gap-1` entre icono y texto
573
+
574
+ ### PaginationEllipsis
575
+
576
+ - **Size**: `size-9`
577
+ - **Icon**: more_horiz (Material Symbol) con `text-lg`
578
+ - **Layout**: `flex items-center justify-center`
579
+ - **ARIA**: `aria-hidden`
580
+
581
+ ## Responsive
582
+
583
+ - **Mobile**: Previous/Next solo muestran icono
584
+ - **Desktop (sm+)**: Previous/Next muestran icono + texto
585
+
586
+ ## Accesibilidad
587
+
588
+ - ✅ **Semantic**: `<nav role="navigation" aria-label="pagination">`
589
+ - ✅ **Current page**: `aria-current="page"` en página activa
590
+ - ✅ **Screen readers**: Ellipsis tiene `<span className="sr-only">More pages</span>`
591
+ - ✅ **Keyboard**: Navegación con Tab, activación con Enter/Space
592
+ - ✅ **Labels**: Previous/Next tienen `aria-label` descriptivo
593
+ - ⚠️ **Disabled**: Usa `pointer-events-none opacity-50` + previene click en handler
594
+
595
+ ## Notas de Implementación
596
+
597
+ - **Links**: PaginationLink es `<a>` no `<button>`, usa Button styles
598
+ - **Icons**: chevron_left, chevron_right, more_horiz (Material Symbols)
599
+ - **Responsive text**: Previous/Next usan `hidden sm:block` en texto
600
+ - **No state**: Componente stateless, maneja estado externamente
601
+ - **Ellipsis logic**: Representación negativa (-1, -2) común para identificar ellipsis
602
+ - **Disabled**: No hay prop disabled, usa className manual
603
+ - **Centering**: Root tiene `mx-auto justify-center`
604
+
605
+ ## Algoritmo de Generación de Páginas
606
+
607
+ Patrón común para mostrar páginas con ellipsis:
608
+
609
+ ```tsx
610
+ const generatePageNumbers = (current: number, total: number) => {
611
+ const pages = [];
612
+
613
+ // Siempre primera página
614
+ pages.push(1);
615
+
616
+ // Ellipsis izquierda si hay gap
617
+ if (current > 4) pages.push(-1);
618
+
619
+ // Páginas alrededor de current
620
+ const start = Math.max(2, current - 1);
621
+ const end = Math.min(total - 1, current + 1);
622
+ for (let i = start; i <= end; i++) {
623
+ if (i !== 1 && i !== total) pages.push(i);
624
+ }
625
+
626
+ // Ellipsis derecha si hay gap
627
+ if (current < total - 3) pages.push(-2);
628
+
629
+ // Siempre última página
630
+ if (total > 1) pages.push(total);
631
+
632
+ return pages;
633
+ };
634
+ ```
635
+
636
+ ## Troubleshooting
637
+
638
+ **Previous/Next no se deshabilitan**: No hay prop disabled, usa `className="pointer-events-none opacity-50"` y previene click en handler
639
+ **Active no se ve**: Verifica `isActive` prop y que solo una página lo tenga
640
+ **Texto Previous/Next no se ve en mobile**: Comportamiento esperado, usa `hidden sm:block`
641
+ **Ellipsis clickeable**: Ellipsis no debe ser clickeable, es `<span>` no link
642
+ **Spacing inconsistente**: PaginationContent tiene `gap-1`, ajusta con className
643
+ **No centrado**: Root tiene `justify-center`, override con `className="justify-start"` si necesario
644
+ **Links no funcionan**: PaginationLink usa `<a>`, asegúrate de pasar `href` o `onClick`
645
+ **Too many pages**: Usa ellipsis y lógica de generación de páginas para mostrar subset
646
+
647
+ ## Referencias
648
+
649
+ - **shadcn/ui Pagination**: <https://ui.shadcn.com/docs/components/pagination>
650
+ - **WAI-ARIA Pagination**: <https://www.w3.org/WAI/ARIA/apg/patterns/pagination/>