Skip to content

Commit 1409fdc

Browse files
Merge pull request #308 from softnetics/supakorn/fix/components
fix: improve pagination hierarchy
2 parents 2461a9e + 681b60f commit 1409fdc

4 files changed

Lines changed: 51 additions & 86 deletions

File tree

.changeset/five-teeth-talk.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@example/ui-playground': patch
3+
'@genseki/ui': patch
4+
---
5+
6+
fix: pagination ui hierarchy.

examples/ui-playground/src/app/playground/shadcn/pagination-section.tsx

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,13 @@ function DefaultPagination() {
4141
{[...Array(3).keys()].map((i) => {
4242
const page = i + 1
4343
return (
44-
<PaginationItem key={page}>
44+
<PaginationItem key={page} isActive={currentPage === page}>
4545
<PaginationLink
4646
href="#"
4747
onClick={(e) => {
4848
e.preventDefault()
4949
setCurrentPage(page)
5050
}}
51-
isActive={currentPage === page}
5251
>
5352
{page}
5453
</PaginationLink>
@@ -86,14 +85,13 @@ function CustomizedPagination() {
8685
const page = i + 1
8786
const isActive = currentPage === page
8887
return (
89-
<PaginationItem key={page}>
88+
<PaginationItem key={page} isActive={currentPage === page}>
9089
<PaginationLink
9190
href="#"
9291
onClick={(e) => {
9392
e.preventDefault()
9493
setCurrentPage(page)
9594
}}
96-
isActive={currentPage === page}
9795
className={cn(
9896
'gap-2',
9997
isActive && 'border-none',
@@ -142,14 +140,13 @@ function FirstLastPagination() {
142140
const page = i + 1
143141

144142
return (
145-
<PaginationItem key={page}>
143+
<PaginationItem key={page} isActive={currentPage === page}>
146144
<PaginationLink
147145
href="#"
148146
onClick={(e) => {
149147
e.preventDefault()
150148
setCurrentPage(page)
151149
}}
152-
isActive={currentPage === page}
153150
>
154151
{page}
155152
</PaginationLink>
@@ -197,27 +194,25 @@ function WithEllipsisPagination() {
197194
<div className="space-y-4">
198195
<Pagination>
199196
<PaginationContent>
200-
<PaginationItem>
197+
<PaginationItem disabled={currentPage === 1}>
201198
<PaginationPrevious
202199
href="#"
203200
onClick={(e) => {
204201
e.preventDefault()
205202
setCurrentPage(Math.max(1, currentPage - 1))
206203
}}
207-
className={currentPage === 1 ? 'pointer-events-none opacity-50' : ''}
208204
/>
209205
</PaginationItem>
210206

211207
{showStartEllipsis && (
212208
<>
213-
<PaginationItem>
209+
<PaginationItem isActive={currentPage === 1}>
214210
<PaginationLink
215211
href="#"
216212
onClick={(e) => {
217213
e.preventDefault()
218214
setCurrentPage(1)
219215
}}
220-
isActive={currentPage === 1}
221216
>
222217
1
223218
</PaginationLink>
@@ -231,14 +226,13 @@ function WithEllipsisPagination() {
231226
)}
232227

233228
{visiblePages.map((page) => (
234-
<PaginationItem key={page}>
229+
<PaginationItem key={page} isActive={currentPage === page}>
235230
<PaginationLink
236231
href="#"
237232
onClick={(e) => {
238233
e.preventDefault()
239234
setCurrentPage(page)
240235
}}
241-
isActive={currentPage === page}
242236
>
243237
{page}
244238
</PaginationLink>
@@ -252,29 +246,27 @@ function WithEllipsisPagination() {
252246
<PaginationEllipsis />
253247
</PaginationLink>
254248
</PaginationItem>
255-
<PaginationItem>
249+
<PaginationItem isActive={currentPage === totalPages}>
256250
<PaginationLink
257251
href="#"
258252
onClick={(e) => {
259253
e.preventDefault()
260254
setCurrentPage(totalPages)
261255
}}
262-
isActive={currentPage === totalPages}
263256
>
264257
{totalPages}
265258
</PaginationLink>
266259
</PaginationItem>
267260
</>
268261
)}
269262

270-
<PaginationItem>
263+
<PaginationItem disabled={currentPage === totalPages}>
271264
<PaginationNext
272265
href="#"
273266
onClick={(e) => {
274267
e.preventDefault()
275268
setCurrentPage(Math.min(totalPages, currentPage + 1))
276269
}}
277-
className={currentPage === totalPages ? 'pointer-events-none opacity-50' : ''}
278270
/>
279271
</PaginationItem>
280272
</PaginationContent>

examples/ui-playground/src/app/playground/shadcn/table/page.tsx

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -500,28 +500,18 @@ function BasicStickyColumnTable() {
500500
<PaginationBarContainer>
501501
<Pagination>
502502
<PaginationContent>
503-
<PaginationItem>
504-
<PaginationPrevious
505-
disabled={firstLage}
506-
onClick={(e) => setPageIndex((prev) => prev - 1)}
507-
/>
503+
<PaginationItem disabled={firstLage}>
504+
<PaginationPrevious onClick={(e) => setPageIndex((prev) => prev - 1)} />
508505
</PaginationItem>
509506
{[...Array(Math.ceil(users.length / pageSize)).keys()].map((index) => (
510-
<PaginationItem key={index}>
511-
<PaginationLink
512-
onClick={() => setPageIndex(index)}
513-
isActive={index === pageIndex}
514-
href="#"
515-
>
507+
<PaginationItem key={index} isActive={index === pageIndex}>
508+
<PaginationLink onClick={() => setPageIndex(index)} href="#">
516509
{index + 1}
517510
</PaginationLink>
518511
</PaginationItem>
519512
))}
520-
<PaginationItem>
521-
<PaginationNext
522-
disabled={lastPage}
523-
onClick={(e) => setPageIndex((prev) => prev + 1)}
524-
/>
513+
<PaginationItem disabled={lastPage}>
514+
<PaginationNext onClick={(e) => setPageIndex((prev) => prev + 1)} />
525515
</PaginationItem>
526516
</PaginationContent>
527517
</Pagination>

packages/ui/src/components/primitives/pagination.tsx

Lines changed: 31 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ import * as React from 'react'
44
import { ArrowLeftIcon, ArrowRightIcon, DotsThreeIcon } from '@phosphor-icons/react'
55
import { Slot } from '@radix-ui/react-slot'
66
import { useControllableState } from '@radix-ui/react-use-controllable-state'
7+
import type { VariantProps } from 'class-variance-authority'
78

8-
import { type Button, buttonVariants } from './button'
9+
import { buttonVariants } from './button'
910
import { ButtonGroup, buttonGroupVariants } from './button-group'
1011
import {
1112
Select,
@@ -41,83 +42,59 @@ function PaginationContent({ className, ...props }: React.ComponentProps<typeof
4142
)
4243
}
4344

44-
function PaginationItem({ ...props }: React.ComponentProps<typeof Slot>) {
45-
return <Slot data-slot="pagination-item" {...props} />
46-
}
47-
48-
type PaginationLinkProps = {
45+
interface PaginationItemProps
46+
extends React.ComponentProps<typeof Slot>,
47+
VariantProps<typeof buttonVariants> {
4948
isActive?: boolean
50-
} & Pick<React.ComponentProps<typeof Button>, 'size' | 'disabled'> &
51-
React.ComponentProps<'a'>
49+
disabled?: boolean
50+
}
5251

53-
function PaginationLink({
52+
function PaginationItem({
5453
className,
55-
isActive,
54+
variant = 'outline',
5655
size = 'icon',
57-
asChild,
56+
isActive,
5857
...props
59-
}: { asChild?: boolean } & PaginationLinkProps) {
60-
const Comp = asChild ? Slot : 'a'
61-
58+
}: PaginationItemProps) {
6259
return (
63-
<Comp
64-
aria-current={isActive ? 'page' : undefined}
65-
data-slot="pagination-link"
66-
data-active={isActive}
60+
<Slot
61+
{...props}
6762
className={cn(
6863
buttonVariants({
69-
variant: 'outline',
64+
variant,
7065
size,
7166
}),
7267
isActive && 'bg-surface-button-outline-hover',
7368
className
7469
)}
75-
{...props}
70+
data-slot="pagination-item"
71+
aria-current={isActive ? 'page' : undefined}
72+
data-active={isActive}
7673
/>
7774
)
7875
}
7976

80-
function PaginationPrevious({ className, ...props }: React.ComponentProps<typeof PaginationLink>) {
77+
type PaginationLinkProps = React.ComponentProps<'a'>
78+
79+
function PaginationLink({ asChild, ...props }: { asChild?: boolean } & PaginationLinkProps) {
80+
const Comp = asChild ? Slot : 'a'
81+
82+
return <Comp data-slot="pagination-link" {...props} />
83+
}
84+
85+
function PaginationPrevious(props: React.ComponentProps<typeof PaginationLink>) {
8186
return (
82-
<PaginationLink
83-
asChild
84-
aria-label="Go to previous page"
85-
size="md"
86-
className={cn(
87-
// Strict width since sizing does not enforce the width
88-
'w-18',
89-
{
90-
'w-16': props.size === 'sm',
91-
'w-20': props.size === 'lg',
92-
},
93-
className
94-
)}
95-
{...props}
96-
>
87+
<PaginationLink asChild aria-label="Go to previous page" {...props}>
9788
<button>
9889
<ArrowLeftIcon />
9990
</button>
10091
</PaginationLink>
10192
)
10293
}
10394

104-
function PaginationNext({ className, ...props }: React.ComponentProps<typeof PaginationLink>) {
95+
function PaginationNext(props: React.ComponentProps<typeof PaginationLink>) {
10596
return (
106-
<PaginationLink
107-
asChild
108-
aria-label="Go to next page"
109-
size="md"
110-
className={cn(
111-
// Strict width since sizing does not enforce the width
112-
'w-18',
113-
{
114-
'w-16': props.size === 'sm',
115-
'w-20': props.size === 'lg',
116-
},
117-
className
118-
)}
119-
{...props}
120-
>
97+
<PaginationLink asChild aria-label="Go to next page" {...props}>
12198
<button>
12299
<ArrowRightIcon />
123100
</button>
@@ -128,10 +105,10 @@ function PaginationNext({ className, ...props }: React.ComponentProps<typeof Pag
128105
function PaginationEllipsis({ className, ...props }: React.ComponentProps<'span'>) {
129106
return (
130107
<span
108+
{...props}
109+
className={cn('flex size-18 items-center justify-center', className)}
131110
aria-hidden
132111
data-slot="pagination-ellipsis"
133-
className={cn('flex size-18 items-center justify-center', className)}
134-
{...props}
135112
>
136113
<DotsThreeIcon className="size-8" />
137114
<span className="sr-only">More pages</span>

0 commit comments

Comments
 (0)