periplo-ui 4.2.0 → 4.2.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.
|
@@ -31,7 +31,7 @@ const PaginationLink = React.forwardRef(
|
|
|
31
31
|
className
|
|
32
32
|
);
|
|
33
33
|
if (disabled) {
|
|
34
|
-
return /* @__PURE__ */ jsx(Button, { variant: "text", size: "sm", disabled: true, className: buttonClassName, children: props.children });
|
|
34
|
+
return /* @__PURE__ */ jsx(Button, { variant: "text", size: "sm", disabled: true, className: buttonClassName, "aria-label": ariaLabel, children: props.children });
|
|
35
35
|
}
|
|
36
36
|
const AnchorComponent = props.anchorComponent ?? "a";
|
|
37
37
|
return /* @__PURE__ */ jsx(
|
|
@@ -54,7 +54,7 @@ const PaginationPrevious = React.forwardRef(
|
|
|
54
54
|
PaginationLink,
|
|
55
55
|
{
|
|
56
56
|
ref,
|
|
57
|
-
ariaLabel: previousLabel
|
|
57
|
+
ariaLabel: previousLabel ? previousLabel : "Go to previous page",
|
|
58
58
|
size: "sm",
|
|
59
59
|
disabled,
|
|
60
60
|
href,
|
|
@@ -74,7 +74,7 @@ const PaginationNext = React.forwardRef(
|
|
|
74
74
|
PaginationLink,
|
|
75
75
|
{
|
|
76
76
|
ref,
|
|
77
|
-
ariaLabel: nextLabel
|
|
77
|
+
ariaLabel: nextLabel ? nextLabel : "Go to next page",
|
|
78
78
|
size: "sm",
|
|
79
79
|
disabled,
|
|
80
80
|
href,
|
|
@@ -89,7 +89,7 @@ const PaginationNext = React.forwardRef(
|
|
|
89
89
|
)
|
|
90
90
|
);
|
|
91
91
|
PaginationNext.displayName = "PaginationNext";
|
|
92
|
-
const PaginationEllipsis = ({ className }) => /* @__PURE__ */ jsx("span", { className: cn(baseStyles.ellipsis, className), children: "..." });
|
|
92
|
+
const PaginationEllipsis = ({ className }) => /* @__PURE__ */ jsx("li", { className: cn(baseStyles.item), children: /* @__PURE__ */ jsx("span", { className: cn(baseStyles.ellipsis, className), children: "..." }) });
|
|
93
93
|
PaginationEllipsis.displayName = "PaginationEllipsis";
|
|
94
94
|
const Pagination = ({
|
|
95
95
|
currentPage,
|
|
@@ -100,8 +100,6 @@ const Pagination = ({
|
|
|
100
100
|
anchorComponent,
|
|
101
101
|
generateHref = () => "#",
|
|
102
102
|
labels = {
|
|
103
|
-
previous: "",
|
|
104
|
-
next: "",
|
|
105
103
|
page: "Page {number}"
|
|
106
104
|
}
|
|
107
105
|
}) => {
|
|
@@ -170,7 +168,7 @@ const Pagination = ({
|
|
|
170
168
|
className: cn("flex items-center gap-2", baseStyles.button, currentPage === 1 && "opacity-50"),
|
|
171
169
|
onClick: currentPage > 1 ? commonNavProps(currentPage - 1).onClick : void 0,
|
|
172
170
|
disabled: currentPage === 1,
|
|
173
|
-
"aria-label": labels.previous
|
|
171
|
+
"aria-label": labels.previous ? labels.previous : "Go to previous page",
|
|
174
172
|
children: [
|
|
175
173
|
/* @__PURE__ */ jsx(CaretLeft, { className: "h-4 w-4 shrink-0" }),
|
|
176
174
|
labels.previous && /* @__PURE__ */ jsx("span", { children: labels.previous })
|
|
@@ -193,7 +191,7 @@ const Pagination = ({
|
|
|
193
191
|
className: cn("flex items-center gap-2", baseStyles.button, currentPage === totalPages && "opacity-50"),
|
|
194
192
|
onClick: currentPage < totalPages ? commonNavProps(currentPage + 1).onClick : void 0,
|
|
195
193
|
disabled: currentPage === totalPages || totalPages === 0,
|
|
196
|
-
"aria-label": labels.next
|
|
194
|
+
"aria-label": labels.next ? labels.next : "Go to next page",
|
|
197
195
|
children: [
|
|
198
196
|
labels.next && /* @__PURE__ */ jsx("span", { children: labels.next }),
|
|
199
197
|
/* @__PURE__ */ jsx(CaretRight, { className: "h-4 w-4 shrink-0" })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Pagination.js","sources":["../../../src/components/Pagination/Pagination.tsx"],"sourcesContent":["'use client'\n\nimport { CaretLeft, CaretRight } from '@phosphor-icons/react/dist/ssr'\nimport * as React from 'react'\n\nimport { Button, ButtonProps, buttonVariants } from '../Button'\n\nimport { cn } from '@/lib/utils'\n\nconst baseStyles = {\n nav: 'flex justify-center',\n content: 'flex flex-row items-center gap-1',\n item: 'list-none',\n link: 'outline-none',\n button: 'min-w-8 px-2 transition-none',\n ellipsis: 'flex h-8 w-8 items-center justify-center',\n}\n\ntype BasePaginationProps = {\n className?: string\n}\n\ntype PaginationRootProps = BasePaginationProps & React.ComponentProps<'nav'>\ntype PaginationContentProps = BasePaginationProps & React.ComponentProps<'ul'>\ntype PaginationItemProps = BasePaginationProps & React.ComponentProps<'li'>\n\ntype AnchorComponentProps = {\n href: string\n className?: string\n 'aria-current'?: 'page'\n children: React.ReactNode\n onClick?: (e: React.MouseEvent<HTMLAnchorElement>) => void\n rel?: string\n}\n\ntype PaginationLinkProps = {\n isActive?: boolean\n disabled?: boolean\n href?: string\n anchorComponent?: React.ComponentType<AnchorComponentProps>\n previousLabel?: string\n nextLabel?: string\n ariaLabel?: string\n} & Pick<ButtonProps, 'size'> &\n React.ComponentProps<'a'>\n\n/** Base props shared between both link and button modes */\ntype BasePaginationComponentProps = {\n /** The current active page number (1-based indexing) */\n currentPage: number\n /** The total number of available pages */\n totalPages: number\n /** Optional CSS class name for styling the pagination container */\n className?: string\n labels?: {\n /** Text to show in the previous button (default: '') */\n previous?: string\n /** Text to show in the next button (default: '') */\n next?: string\n /** Aria label to show in the page number (default: 'Page {number}') */\n page?: string\n }\n}\n\n/** Props specific to link mode */\ntype LinkModePaginationProps = {\n mode: 'link'\n /**\n * Custom component to use for links (e.g., Next.js Link)\n * Must accept standard anchor props (href, className, etc.)\n */\n anchorComponent: React.ComponentType<AnchorComponentProps>\n /**\n * Function to generate the href for each page link\n */\n generateHref: (page: number) => string\n /** Optional callback when page changes - not required in link mode since links handle navigation */\n onPageChange?: (page: number) => void\n} & BasePaginationComponentProps\n\n/** Props specific to button mode */\ntype ButtonModePaginationProps = {\n mode: 'button'\n /** Callback function called when a page is selected - required in button mode */\n onPageChange: (page: number) => void\n /** These props are not used in button mode */\n anchorComponent?: never\n generateHref?: never\n} & BasePaginationComponentProps\n\n/** Union type for all possible pagination props */\nexport type PaginationProps =\n | LinkModePaginationProps\n | ButtonModePaginationProps\n | (Omit<BasePaginationComponentProps, 'mode'> & {\n mode: undefined\n onPageChange: (page: number) => void\n anchorComponent?: React.ComponentType<AnchorComponentProps>\n generateHref?: (page: number) => string\n })\n\nconst PaginationRoot = React.forwardRef<HTMLElement, PaginationRootProps>(({ className, ...props }, ref) => (\n <nav ref={ref} role=\"navigation\" aria-label=\"pagination\" className={cn(baseStyles.nav, className)} {...props} />\n))\nPaginationRoot.displayName = 'PaginationRoot'\n\nconst PaginationContent = React.forwardRef<HTMLUListElement, PaginationContentProps>(({ className, ...props }, ref) => (\n <ul ref={ref} className={cn(baseStyles.content, className)} {...props} />\n))\nPaginationContent.displayName = 'PaginationContent'\n\nconst PaginationItem = React.forwardRef<HTMLLIElement, PaginationItemProps>(({ className, ...props }, ref) => (\n <li ref={ref} className={cn(baseStyles.item, className)} {...props} />\n))\nPaginationItem.displayName = 'PaginationItem'\n\nconst PaginationLink = React.forwardRef<HTMLAnchorElement, PaginationLinkProps>(\n ({ className, isActive, ariaLabel, size = 'sm', disabled = false, href, rel, ...props }, ref) => {\n const buttonClassName = cn(\n buttonVariants({\n variant: isActive ? 'primary' : 'text',\n size,\n }),\n disabled && 'opacity-50',\n baseStyles.button,\n className,\n )\n\n if (disabled) {\n return (\n <Button variant=\"text\" size=\"sm\" disabled className={buttonClassName}>\n {props.children}\n </Button>\n )\n }\n\n const AnchorComponent = props.anchorComponent ?? 'a'\n\n return (\n <AnchorComponent\n ref={ref}\n href={href ?? '#'}\n rel={rel}\n aria-current={isActive ? 'page' : undefined}\n aria-label={ariaLabel}\n className={cn(baseStyles.link, buttonClassName)}\n >\n {props.children}\n </AnchorComponent>\n )\n },\n)\nPaginationLink.displayName = 'PaginationLink'\n\nconst PaginationPrevious = React.forwardRef<HTMLAnchorElement, PaginationLinkProps>(\n ({ className, disabled, href, previousLabel, ...props }, ref) => (\n <PaginationLink\n ref={ref}\n ariaLabel={previousLabel === '' ? 'Go to previous page' : previousLabel}\n size=\"sm\"\n disabled={disabled}\n href={href}\n rel=\"prev\"\n className={cn('flex items-center gap-2', baseStyles.button, className)}\n {...props}\n >\n <CaretLeft className=\"h-4 w-4 shrink-0\" />\n {previousLabel && <span>{previousLabel}</span>}\n </PaginationLink>\n ),\n)\nPaginationPrevious.displayName = 'PaginationPrevious'\n\nconst PaginationNext = React.forwardRef<HTMLAnchorElement, PaginationLinkProps>(\n ({ className, disabled, href, nextLabel, ...props }, ref) => (\n <PaginationLink\n ref={ref}\n ariaLabel={nextLabel === '' ? 'Go to next page' : nextLabel}\n size=\"sm\"\n disabled={disabled}\n href={href}\n rel=\"next\"\n className={cn('flex items-center gap-2', baseStyles.button, className)}\n {...props}\n >\n {nextLabel && <span>{nextLabel}</span>}\n <CaretRight className=\"h-4 w-4 shrink-0\" />\n </PaginationLink>\n ),\n)\nPaginationNext.displayName = 'PaginationNext'\n\nconst PaginationEllipsis = ({ className }: BasePaginationProps) => (\n <span className={cn(baseStyles.ellipsis, className)}>...</span>\n)\nPaginationEllipsis.displayName = 'PaginationEllipsis'\n\n/**\n * A pagination component that displays page numbers and navigation controls.\n *\n * @example\n * ```tsx\n * // Basic usage with anchor tags\n * <Pagination\n * currentPage={1}\n * totalPages={10}\n * />\n *\n * // With Next.js Link component\n * <Pagination\n * currentPage={1}\n * totalPages={10}\n * onPageChange={setPage}\n * anchorComponent={Link}\n * generateHref={(page) => `/posts?page=${page}`}\n * />\n *\n * // Client-side table navigation\n * <Pagination\n * currentPage={1}\n * totalPages={10}\n * onPageChange={setPage}\n * mode=\"button\"\n * />\n * ```\n */\nconst Pagination: React.FC<PaginationProps> = ({\n currentPage,\n totalPages,\n onPageChange,\n className,\n mode = 'button',\n anchorComponent,\n generateHref = () => '#',\n labels = {\n previous: '',\n next: '',\n page: 'Page {number}',\n },\n}) => {\n const handlePageChange = (pageNum: number) => {\n if (onPageChange) {\n onPageChange(pageNum)\n }\n }\n\n const renderPageNumbers = () => {\n const items: Array<React.ReactNode> = []\n\n const addPageNumber = (pageNum: number) => {\n const commonProps = {\n isActive: currentPage === pageNum,\n href: mode === 'link' ? generateHref(pageNum) : undefined,\n ariaLabel: labels.page ? labels.page.replace('{number}', pageNum.toString()) : undefined,\n anchorComponent,\n }\n\n const encodedPageNum = btoa(`page-${pageNum}`).replaceAll(/[+/=]/g, '')\n\n items.push(\n <PaginationItem key={`${encodedPageNum}`}>\n {mode === 'button' ? (\n <Button\n variant={commonProps.isActive ? 'primary' : 'text'}\n size=\"sm\"\n className={baseStyles.button}\n onClick={(event: React.MouseEvent) => {\n event.preventDefault()\n handlePageChange(pageNum)\n }}\n aria-label={commonProps.ariaLabel}\n aria-current={commonProps.isActive ? 'page' : undefined}\n >\n {pageNum}\n </Button>\n ) : (\n <PaginationLink {...commonProps}>{pageNum}</PaginationLink>\n )}\n </PaginationItem>,\n )\n }\n\n addPageNumber(1)\n\n if (currentPage > 3) {\n items.push(<PaginationEllipsis key=\"ellipsis-1\" />)\n }\n\n for (let index = Math.max(2, currentPage - 1); index <= Math.min(totalPages - 1, currentPage + 1); index++) {\n addPageNumber(index)\n }\n\n if (currentPage < totalPages - 2) {\n items.push(<PaginationEllipsis key=\"ellipsis-2\" />)\n }\n\n if (totalPages > 1) {\n addPageNumber(totalPages)\n }\n\n return items\n }\n\n const commonNavProps = (page: number) => ({\n onClick: (event: React.MouseEvent) => {\n event.preventDefault()\n handlePageChange(page)\n },\n href: generateHref(page),\n anchorComponent,\n })\n\n return (\n <PaginationRoot className={className}>\n <PaginationContent>\n <PaginationItem>\n {mode === 'button' ? (\n <Button\n variant=\"text\"\n size=\"sm\"\n className={cn('flex items-center gap-2', baseStyles.button, currentPage === 1 && 'opacity-50')}\n onClick={currentPage > 1 ? commonNavProps(currentPage - 1).onClick : undefined}\n disabled={currentPage === 1}\n aria-label={labels.previous === '' ? 'Go to previous page' : labels.previous}\n >\n <CaretLeft className=\"h-4 w-4 shrink-0\" />\n {labels.previous && <span>{labels.previous}</span>}\n </Button>\n ) : (\n <PaginationPrevious\n {...commonNavProps(currentPage - 1)}\n disabled={currentPage === 1}\n previousLabel={labels.previous}\n />\n )}\n </PaginationItem>\n {renderPageNumbers()}\n <PaginationItem>\n {mode === 'button' ? (\n <Button\n variant=\"text\"\n size=\"sm\"\n className={cn('flex items-center gap-2', baseStyles.button, currentPage === totalPages && 'opacity-50')}\n onClick={currentPage < totalPages ? commonNavProps(currentPage + 1).onClick : undefined}\n disabled={currentPage === totalPages || totalPages === 0}\n aria-label={labels.next === '' ? 'Go to next page' : labels.next}\n >\n {labels.next && <span>{labels.next}</span>}\n <CaretRight className=\"h-4 w-4 shrink-0\" />\n </Button>\n ) : (\n <PaginationNext\n {...commonNavProps(currentPage + 1)}\n disabled={currentPage === totalPages || totalPages === 0}\n nextLabel={labels.next}\n />\n )}\n </PaginationItem>\n </PaginationContent>\n </PaginationRoot>\n )\n}\n\nexport {\n Pagination,\n PaginationContent,\n PaginationEllipsis,\n PaginationItem,\n PaginationLink,\n PaginationNext,\n PaginationPrevious,\n PaginationRoot,\n}\n"],"names":[],"mappings":";;;;;;;AASA;AAAmB;AACZ;AACI;AACH;AACA;AACE;AAEV;AAqFA;AAGA;AAEA;AAGA;AAEA;AAGA;AAEA;AAA6B;AAEzB;AAAwB;AACP;AACmB;AAChC;AACD;AACW;AACD;AACX;AAGF;AACE;AAGE;AAIJ;AAEA;AACE;AAAC;AAAA;AACC;AACc;AACd;AACkC;AACtB;AACkC;AAEvC;AAAA;AACT;AAGN;AACA;AAEA;AAAiC;AAE7B;AAAC;AAAA;AACC;AAC0D;AACrD;AACL;AACA;AACI;AACiE;AACjE;AAEJ;AAAwC;AACD;AAAA;AAAA;AAG7C;AACA;AAEA;AAA6B;AAEzB;AAAC;AAAA;AACC;AACkD;AAC7C;AACL;AACA;AACI;AACiE;AACjE;AAEH;AAA8B;AACU;AAAA;AAAA;AAG/C;AACA;AAEA;AAGA;AA+BA;AAA+C;AAC7C;AACA;AACA;AACA;AACO;AACP;AACqB;AACZ;AACG;AACJ;AACA;AAEV;AACE;AACE;AACE;AAAoB;AACtB;AAGF;AACE;AAEA;AACE;AAAoB;AACQ;AACsB;AAC+B;AAC/E;AAGF;AAEA;AAAM;AAGA;AAAC;AAAA;AAC6C;AACvC;AACiB;AAEpB;AACA;AAAwB;AAC1B;AACwB;AACsB;AAE7C;AAAA;AAKP;AACF;AAGF;AAEA;AACE;AAAkD;AAGpD;AACE;AAAmB;AAGrB;AACE;AAAkD;AAGpD;AACE;AAAwB;AAG1B;AAAO;AAGT;AAA0C;AAEtC;AACA;AAAqB;AACvB;AACuB;AACvB;AAGF;AAGM;AAEI;AAAC;AAAA;AACS;AACH;AACwF;AACxB;AAC3C;AAC0C;AAEpE;AAAwC;AACG;AAAA;AAAA;AAG7C;AAAC;AAAA;AACmC;AACR;AACJ;AAAA;AAG5B;AACmB;AAGf;AAAC;AAAA;AACS;AACH;AACiG;AACxB;AACvB;AACK;AAE3D;AAAkC;AACM;AAAA;AAAA;AAG3C;AAAC;AAAA;AACmC;AACqB;AACrC;AAAA;AAGxB;AAIR;;"}
|
|
1
|
+
{"version":3,"file":"Pagination.js","sources":["../../../src/components/Pagination/Pagination.tsx"],"sourcesContent":["'use client'\n\nimport { CaretLeft, CaretRight } from '@phosphor-icons/react/dist/ssr'\nimport * as React from 'react'\n\nimport { Button, ButtonProps, buttonVariants } from '../Button'\n\nimport { cn } from '@/lib/utils'\n\nconst baseStyles = {\n nav: 'flex justify-center',\n content: 'flex flex-row items-center gap-1',\n item: 'list-none',\n link: 'outline-none',\n button: 'min-w-8 px-2 transition-none',\n ellipsis: 'flex h-8 w-8 items-center justify-center',\n}\n\ntype BasePaginationProps = {\n className?: string\n}\n\ntype PaginationRootProps = BasePaginationProps & React.ComponentProps<'nav'>\ntype PaginationContentProps = BasePaginationProps & React.ComponentProps<'ul'>\ntype PaginationItemProps = BasePaginationProps & React.ComponentProps<'li'>\n\ntype AnchorComponentProps = {\n href: string\n className?: string\n 'aria-current'?: 'page'\n children: React.ReactNode\n onClick?: (e: React.MouseEvent<HTMLAnchorElement>) => void\n rel?: string\n}\n\ntype PaginationLinkProps = {\n isActive?: boolean\n disabled?: boolean\n href?: string\n anchorComponent?: React.ComponentType<AnchorComponentProps>\n previousLabel?: string\n nextLabel?: string\n ariaLabel?: string\n} & Pick<ButtonProps, 'size'> &\n React.ComponentProps<'a'>\n\n/** Base props shared between both link and button modes */\ntype BasePaginationComponentProps = {\n /** The current active page number (1-based indexing) */\n currentPage: number\n /** The total number of available pages */\n totalPages: number\n /** Optional CSS class name for styling the pagination container */\n className?: string\n labels?: {\n /** Text to show in the previous button (default: '') */\n previous?: string\n /** Text to show in the next button (default: '') */\n next?: string\n /** Aria label to show in the page number (default: 'Page {number}') */\n page?: string\n }\n}\n\n/** Props specific to link mode */\ntype LinkModePaginationProps = {\n mode: 'link'\n /**\n * Custom component to use for links (e.g., Next.js Link)\n * Must accept standard anchor props (href, className, etc.)\n */\n anchorComponent: React.ComponentType<AnchorComponentProps>\n /**\n * Function to generate the href for each page link\n */\n generateHref: (page: number) => string\n /** Optional callback when page changes - not required in link mode since links handle navigation */\n onPageChange?: (page: number) => void\n} & BasePaginationComponentProps\n\n/** Props specific to button mode */\ntype ButtonModePaginationProps = {\n mode: 'button'\n /** Callback function called when a page is selected - required in button mode */\n onPageChange: (page: number) => void\n /** These props are not used in button mode */\n anchorComponent?: never\n generateHref?: never\n} & BasePaginationComponentProps\n\n/** Union type for all possible pagination props */\nexport type PaginationProps =\n | LinkModePaginationProps\n | ButtonModePaginationProps\n | (Omit<BasePaginationComponentProps, 'mode'> & {\n mode: undefined\n onPageChange: (page: number) => void\n anchorComponent?: React.ComponentType<AnchorComponentProps>\n generateHref?: (page: number) => string\n })\n\nconst PaginationRoot = React.forwardRef<HTMLElement, PaginationRootProps>(({ className, ...props }, ref) => (\n <nav ref={ref} role=\"navigation\" aria-label=\"pagination\" className={cn(baseStyles.nav, className)} {...props} />\n))\nPaginationRoot.displayName = 'PaginationRoot'\n\nconst PaginationContent = React.forwardRef<HTMLUListElement, PaginationContentProps>(({ className, ...props }, ref) => (\n <ul ref={ref} className={cn(baseStyles.content, className)} {...props} />\n))\nPaginationContent.displayName = 'PaginationContent'\n\nconst PaginationItem = React.forwardRef<HTMLLIElement, PaginationItemProps>(({ className, ...props }, ref) => (\n <li ref={ref} className={cn(baseStyles.item, className)} {...props} />\n))\nPaginationItem.displayName = 'PaginationItem'\n\nconst PaginationLink = React.forwardRef<HTMLAnchorElement, PaginationLinkProps>(\n ({ className, isActive, ariaLabel, size = 'sm', disabled = false, href, rel, ...props }, ref) => {\n const buttonClassName = cn(\n buttonVariants({\n variant: isActive ? 'primary' : 'text',\n size,\n }),\n disabled && 'opacity-50',\n baseStyles.button,\n className,\n )\n\n if (disabled) {\n return (\n <Button variant=\"text\" size=\"sm\" disabled className={buttonClassName} aria-label={ariaLabel}>\n {props.children}\n </Button>\n )\n }\n\n const AnchorComponent = props.anchorComponent ?? 'a'\n\n return (\n <AnchorComponent\n ref={ref}\n href={href ?? '#'}\n rel={rel}\n aria-current={isActive ? 'page' : undefined}\n aria-label={ariaLabel}\n className={cn(baseStyles.link, buttonClassName)}\n >\n {props.children}\n </AnchorComponent>\n )\n },\n)\nPaginationLink.displayName = 'PaginationLink'\n\nconst PaginationPrevious = React.forwardRef<HTMLAnchorElement, PaginationLinkProps>(\n ({ className, disabled, href, previousLabel, ...props }, ref) => (\n <PaginationLink\n ref={ref}\n ariaLabel={previousLabel ? previousLabel : 'Go to previous page'}\n size=\"sm\"\n disabled={disabled}\n href={href}\n rel=\"prev\"\n className={cn('flex items-center gap-2', baseStyles.button, className)}\n {...props}\n >\n <CaretLeft className=\"h-4 w-4 shrink-0\" />\n {previousLabel && <span>{previousLabel}</span>}\n </PaginationLink>\n ),\n)\nPaginationPrevious.displayName = 'PaginationPrevious'\n\nconst PaginationNext = React.forwardRef<HTMLAnchorElement, PaginationLinkProps>(\n ({ className, disabled, href, nextLabel, ...props }, ref) => (\n <PaginationLink\n ref={ref}\n ariaLabel={nextLabel ? nextLabel : 'Go to next page'}\n size=\"sm\"\n disabled={disabled}\n href={href}\n rel=\"next\"\n className={cn('flex items-center gap-2', baseStyles.button, className)}\n {...props}\n >\n {nextLabel && <span>{nextLabel}</span>}\n <CaretRight className=\"h-4 w-4 shrink-0\" />\n </PaginationLink>\n ),\n)\nPaginationNext.displayName = 'PaginationNext'\n\nconst PaginationEllipsis = ({ className }: BasePaginationProps) => (\n <li className={cn(baseStyles.item)}>\n <span className={cn(baseStyles.ellipsis, className)}>...</span>\n </li>\n)\nPaginationEllipsis.displayName = 'PaginationEllipsis'\n\n/**\n * A pagination component that displays page numbers and navigation controls.\n *\n * @example\n * ```tsx\n * // Basic usage with anchor tags\n * <Pagination\n * currentPage={1}\n * totalPages={10}\n * />\n *\n * // With Next.js Link component\n * <Pagination\n * currentPage={1}\n * totalPages={10}\n * onPageChange={setPage}\n * anchorComponent={Link}\n * generateHref={(page) => `/posts?page=${page}`}\n * />\n *\n * // Client-side table navigation\n * <Pagination\n * currentPage={1}\n * totalPages={10}\n * onPageChange={setPage}\n * mode=\"button\"\n * />\n * ```\n */\nconst Pagination: React.FC<PaginationProps> = ({\n currentPage,\n totalPages,\n onPageChange,\n className,\n mode = 'button',\n anchorComponent,\n generateHref = () => '#',\n labels = {\n page: 'Page {number}',\n },\n}) => {\n const handlePageChange = (pageNum: number) => {\n if (onPageChange) {\n onPageChange(pageNum)\n }\n }\n\n const renderPageNumbers = () => {\n const items: Array<React.ReactNode> = []\n\n const addPageNumber = (pageNum: number) => {\n const commonProps = {\n isActive: currentPage === pageNum,\n href: mode === 'link' ? generateHref(pageNum) : undefined,\n ariaLabel: labels.page ? labels.page.replace('{number}', pageNum.toString()) : undefined,\n anchorComponent,\n }\n\n const encodedPageNum = btoa(`page-${pageNum}`).replaceAll(/[+/=]/g, '')\n\n items.push(\n <PaginationItem key={`${encodedPageNum}`}>\n {mode === 'button' ? (\n <Button\n variant={commonProps.isActive ? 'primary' : 'text'}\n size=\"sm\"\n className={baseStyles.button}\n onClick={(event: React.MouseEvent) => {\n event.preventDefault()\n handlePageChange(pageNum)\n }}\n aria-label={commonProps.ariaLabel}\n aria-current={commonProps.isActive ? 'page' : undefined}\n >\n {pageNum}\n </Button>\n ) : (\n <PaginationLink {...commonProps}>{pageNum}</PaginationLink>\n )}\n </PaginationItem>,\n )\n }\n\n addPageNumber(1)\n\n if (currentPage > 3) {\n items.push(<PaginationEllipsis key=\"ellipsis-1\" />)\n }\n\n for (let index = Math.max(2, currentPage - 1); index <= Math.min(totalPages - 1, currentPage + 1); index++) {\n addPageNumber(index)\n }\n\n if (currentPage < totalPages - 2) {\n items.push(<PaginationEllipsis key=\"ellipsis-2\" />)\n }\n\n if (totalPages > 1) {\n addPageNumber(totalPages)\n }\n\n return items\n }\n\n const commonNavProps = (page: number) => ({\n onClick: (event: React.MouseEvent) => {\n event.preventDefault()\n handlePageChange(page)\n },\n href: generateHref(page),\n anchorComponent,\n })\n\n return (\n <PaginationRoot className={className}>\n <PaginationContent>\n <PaginationItem>\n {mode === 'button' ? (\n <Button\n variant=\"text\"\n size=\"sm\"\n className={cn('flex items-center gap-2', baseStyles.button, currentPage === 1 && 'opacity-50')}\n onClick={currentPage > 1 ? commonNavProps(currentPage - 1).onClick : undefined}\n disabled={currentPage === 1}\n aria-label={labels.previous ? labels.previous : 'Go to previous page'}\n >\n <CaretLeft className=\"h-4 w-4 shrink-0\" />\n {labels.previous && <span>{labels.previous}</span>}\n </Button>\n ) : (\n <PaginationPrevious\n {...commonNavProps(currentPage - 1)}\n disabled={currentPage === 1}\n previousLabel={labels.previous}\n />\n )}\n </PaginationItem>\n {renderPageNumbers()}\n <PaginationItem>\n {mode === 'button' ? (\n <Button\n variant=\"text\"\n size=\"sm\"\n className={cn('flex items-center gap-2', baseStyles.button, currentPage === totalPages && 'opacity-50')}\n onClick={currentPage < totalPages ? commonNavProps(currentPage + 1).onClick : undefined}\n disabled={currentPage === totalPages || totalPages === 0}\n aria-label={labels.next ? labels.next : 'Go to next page'}\n >\n {labels.next && <span>{labels.next}</span>}\n <CaretRight className=\"h-4 w-4 shrink-0\" />\n </Button>\n ) : (\n <PaginationNext\n {...commonNavProps(currentPage + 1)}\n disabled={currentPage === totalPages || totalPages === 0}\n nextLabel={labels.next}\n />\n )}\n </PaginationItem>\n </PaginationContent>\n </PaginationRoot>\n )\n}\n\nexport {\n Pagination,\n PaginationContent,\n PaginationEllipsis,\n PaginationItem,\n PaginationLink,\n PaginationNext,\n PaginationPrevious,\n PaginationRoot,\n}\n"],"names":[],"mappings":";;;;;;;AASA;AAAmB;AACZ;AACI;AACH;AACA;AACE;AAEV;AAqFA;AAGA;AAEA;AAGA;AAEA;AAGA;AAEA;AAA6B;AAEzB;AAAwB;AACP;AACmB;AAChC;AACD;AACW;AACD;AACX;AAGF;AACE;AAGE;AAIJ;AAEA;AACE;AAAC;AAAA;AACC;AACc;AACd;AACkC;AACtB;AACkC;AAEvC;AAAA;AACT;AAGN;AACA;AAEA;AAAiC;AAE7B;AAAC;AAAA;AACC;AAC2C;AACtC;AACL;AACA;AACI;AACiE;AACjE;AAEJ;AAAwC;AACD;AAAA;AAAA;AAG7C;AACA;AAEA;AAA6B;AAEzB;AAAC;AAAA;AACC;AACmC;AAC9B;AACL;AACA;AACI;AACiE;AACjE;AAEH;AAA8B;AACU;AAAA;AAAA;AAG/C;AACA;AAEA;AAKA;AA+BA;AAA+C;AAC7C;AACA;AACA;AACA;AACO;AACP;AACqB;AACZ;AACD;AAEV;AACE;AACE;AACE;AAAoB;AACtB;AAGF;AACE;AAEA;AACE;AAAoB;AACQ;AACsB;AAC+B;AAC/E;AAGF;AAEA;AAAM;AAGA;AAAC;AAAA;AAC6C;AACvC;AACiB;AAEpB;AACA;AAAwB;AAC1B;AACwB;AACsB;AAE7C;AAAA;AAKP;AACF;AAGF;AAEA;AACE;AAAkD;AAGpD;AACE;AAAmB;AAGrB;AACE;AAAkD;AAGpD;AACE;AAAwB;AAG1B;AAAO;AAGT;AAA0C;AAEtC;AACA;AAAqB;AACvB;AACuB;AACvB;AAGF;AAGM;AAEI;AAAC;AAAA;AACS;AACH;AACwF;AACxB;AAC3C;AACsB;AAEhD;AAAwC;AACG;AAAA;AAAA;AAG7C;AAAC;AAAA;AACmC;AACR;AACJ;AAAA;AAG5B;AACmB;AAGf;AAAC;AAAA;AACS;AACH;AACiG;AACxB;AACvB;AACf;AAEvC;AAAkC;AACM;AAAA;AAAA;AAG3C;AAAC;AAAA;AACmC;AACqB;AACrC;AAAA;AAGxB;AAIR;;"}
|