| 1 | import * as React from "react"; |
| 2 | import { ChevronLeft, ChevronRight, MoreHorizontal } from "lucide-react"; |
| 3 | |
| 4 | import { cn } from "@/lib/utils"; |
| 5 | import { ButtonProps, buttonVariants } from "@/components/ui/button"; |
| 6 | |
| 7 | const Pagination = ({ className, ...props }: React.ComponentProps<"nav">) => ( |
| 8 | <nav |
| 9 | role="navigation" |
| 10 | aria-label="pagination" |
| 11 | className={cn("mx-auto flex w-full justify-center", className)} |
| 12 | {...props} |
| 13 | /> |
| 14 | ); |
| 15 | Pagination.displayName = "Pagination"; |
| 16 | |
| 17 | const PaginationContent = React.forwardRef<HTMLUListElement, React.ComponentProps<"ul">>( |
| 18 | ({ className, ...props }, ref) => ( |
| 19 | <ul ref={ref} className={cn("flex flex-row items-center gap-1", className)} {...props} /> |
| 20 | ), |
| 21 | ); |
| 22 | PaginationContent.displayName = "PaginationContent"; |
| 23 | |
| 24 | const PaginationItem = React.forwardRef<HTMLLIElement, React.ComponentProps<"li">>(({ className, ...props }, ref) => ( |
| 25 | <li ref={ref} className={cn("", className)} {...props} /> |
| 26 | )); |
| 27 | PaginationItem.displayName = "PaginationItem"; |
| 28 | |
| 29 | type PaginationLinkProps = { |
| 30 | isActive?: boolean; |
| 31 | } & Pick<ButtonProps, "size"> & |
| 32 | React.ComponentProps<"a">; |
| 33 | |
| 34 | const PaginationLink = ({ className, isActive, size = "icon", ...props }: PaginationLinkProps) => ( |
| 35 | <a |
| 36 | aria-current={isActive ? "page" : undefined} |
| 37 | className={cn( |
| 38 | buttonVariants({ |
| 39 | variant: isActive ? "outline" : "ghost", |
| 40 | size, |
| 41 | }), |
| 42 | className, |
| 43 | )} |
| 44 | {...props} |
| 45 | /> |
| 46 | ); |
| 47 | PaginationLink.displayName = "PaginationLink"; |
| 48 | |
| 49 | const PaginationPrevious = ({ className, ...props }: React.ComponentProps<typeof PaginationLink>) => ( |
| 50 | <PaginationLink aria-label="Go to previous page" size="default" className={cn("gap-1 pl-2.5", className)} {...props}> |
| 51 | <ChevronLeft className="h-4 w-4" /> |
| 52 | <span>Previous</span> |
| 53 | </PaginationLink> |
| 54 | ); |
| 55 | PaginationPrevious.displayName = "PaginationPrevious"; |
| 56 | |
| 57 | const PaginationNext = ({ className, ...props }: React.ComponentProps<typeof PaginationLink>) => ( |
| 58 | <PaginationLink aria-label="Go to next page" size="default" className={cn("gap-1 pr-2.5", className)} {...props}> |
| 59 | <span>Next</span> |
| 60 | <ChevronRight className="h-4 w-4" /> |
| 61 | </PaginationLink> |
| 62 | ); |
| 63 | PaginationNext.displayName = "PaginationNext"; |
| 64 | |
| 65 | const PaginationEllipsis = ({ className, ...props }: React.ComponentProps<"span">) => ( |
| 66 | <span aria-hidden className={cn("flex h-9 w-9 items-center justify-center", className)} {...props}> |
| 67 | <MoreHorizontal className="h-4 w-4" /> |
| 68 | <span className="sr-only">More pages</span> |
| 69 | </span> |
| 70 | ); |
| 71 | PaginationEllipsis.displayName = "PaginationEllipsis"; |
| 72 | |
| 73 | export { |
| 74 | Pagination, |
| 75 | PaginationContent, |
| 76 | PaginationEllipsis, |
| 77 | PaginationItem, |
| 78 | PaginationLink, |
| 79 | PaginationNext, |
| 80 | PaginationPrevious, |
| 81 | }; |