periplo-ui 4.1.2 → 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.
@@ -21,6 +21,7 @@ type PaginationLinkProps = {
21
21
  anchorComponent?: React.ComponentType<AnchorComponentProps>;
22
22
  previousLabel?: string;
23
23
  nextLabel?: string;
24
+ ariaLabel?: string;
24
25
  } & Pick<ButtonProps, 'size'> & React.ComponentProps<'a'>;
25
26
  /** Base props shared between both link and button modes */
26
27
  type BasePaginationComponentProps = {
@@ -110,4 +111,4 @@ declare const PaginationEllipsis: {
110
111
  * ```
111
112
  */
112
113
  declare const Pagination: React.FC<PaginationProps>;
113
- export { PaginationRoot, PaginationContent, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PaginationEllipsis, Pagination, };
114
+ export { Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PaginationRoot, };
@@ -1,7 +1,6 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from 'react/jsx-runtime';
3
- import { CaretLeft } from '@phosphor-icons/react/dist/ssr/CaretLeft';
4
- import { CaretRight } from '@phosphor-icons/react/dist/ssr/CaretRight';
3
+ import { CaretLeft, CaretRight } from '@phosphor-icons/react/dist/ssr';
5
4
  import * as React from 'react';
6
5
  import { buttonVariants, Button } from '../Button/Button.js';
7
6
  import { cn } from '../../lib/utils.js';
@@ -21,7 +20,7 @@ PaginationContent.displayName = "PaginationContent";
21
20
  const PaginationItem = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("li", { ref, className: cn(baseStyles.item, className), ...props }));
22
21
  PaginationItem.displayName = "PaginationItem";
23
22
  const PaginationLink = React.forwardRef(
24
- ({ className, isActive, size = "sm", disabled = false, href, rel, ...props }, ref) => {
23
+ ({ className, isActive, ariaLabel, size = "sm", disabled = false, href, rel, ...props }, ref) => {
25
24
  const buttonClassName = cn(
26
25
  buttonVariants({
27
26
  variant: isActive ? "primary" : "text",
@@ -32,7 +31,7 @@ const PaginationLink = React.forwardRef(
32
31
  className
33
32
  );
34
33
  if (disabled) {
35
- 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 });
36
35
  }
37
36
  const AnchorComponent = props.anchorComponent ?? "a";
38
37
  return /* @__PURE__ */ jsx(
@@ -42,6 +41,7 @@ const PaginationLink = React.forwardRef(
42
41
  href: href ?? "#",
43
42
  rel,
44
43
  "aria-current": isActive ? "page" : void 0,
44
+ "aria-label": ariaLabel,
45
45
  className: cn(baseStyles.link, buttonClassName),
46
46
  children: props.children
47
47
  }
@@ -50,11 +50,11 @@ const PaginationLink = React.forwardRef(
50
50
  );
51
51
  PaginationLink.displayName = "PaginationLink";
52
52
  const PaginationPrevious = React.forwardRef(
53
- ({ className, disabled, href, previousLabel = "", ...props }, ref) => /* @__PURE__ */ jsxs(
53
+ ({ className, disabled, href, previousLabel, ...props }, ref) => /* @__PURE__ */ jsxs(
54
54
  PaginationLink,
55
55
  {
56
56
  ref,
57
- "aria-label": previousLabel || "Go to previous page",
57
+ ariaLabel: previousLabel ? previousLabel : "Go to previous page",
58
58
  size: "sm",
59
59
  disabled,
60
60
  href,
@@ -70,11 +70,11 @@ const PaginationPrevious = React.forwardRef(
70
70
  );
71
71
  PaginationPrevious.displayName = "PaginationPrevious";
72
72
  const PaginationNext = React.forwardRef(
73
- ({ className, disabled, href, nextLabel = "", ...props }, ref) => /* @__PURE__ */ jsxs(
73
+ ({ className, disabled, href, nextLabel, ...props }, ref) => /* @__PURE__ */ jsxs(
74
74
  PaginationLink,
75
75
  {
76
76
  ref,
77
- "aria-label": nextLabel || "Go to next page",
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
  }) => {
@@ -116,33 +114,26 @@ const Pagination = ({
116
114
  const commonProps = {
117
115
  isActive: currentPage === pageNum,
118
116
  href: mode === "link" ? generateHref(pageNum) : void 0,
119
- anchorComponent,
120
- pageLabel: labels.page
117
+ ariaLabel: labels.page ? labels.page.replace("{number}", pageNum.toString()) : void 0,
118
+ anchorComponent
121
119
  };
122
120
  const encodedPageNum = btoa(`page-${pageNum}`).replaceAll(/[+/=]/g, "");
123
121
  items.push(
124
- /* @__PURE__ */ jsx(
125
- PaginationItem,
122
+ /* @__PURE__ */ jsx(PaginationItem, { children: mode === "button" ? /* @__PURE__ */ jsx(
123
+ Button,
126
124
  {
127
- "aria-label": labels.page ? labels.page.replace("{number}", pageNum.toString()) : void 0,
128
- children: mode === "button" ? /* @__PURE__ */ jsx(
129
- Button,
130
- {
131
- variant: commonProps.isActive ? "primary" : "text",
132
- size: "sm",
133
- className: baseStyles.button,
134
- onClick: (event) => {
135
- event.preventDefault();
136
- handlePageChange(pageNum);
137
- },
138
- "aria-label": labels.page ? labels.page.replace("{number}", pageNum.toString()) : `Go to page ${pageNum.toString()}`,
139
- "aria-current": commonProps.isActive ? "page" : void 0,
140
- children: pageNum
141
- }
142
- ) : /* @__PURE__ */ jsx(PaginationLink, { ...commonProps, children: pageNum })
143
- },
144
- `${encodedPageNum}`
145
- )
125
+ variant: commonProps.isActive ? "primary" : "text",
126
+ size: "sm",
127
+ className: baseStyles.button,
128
+ onClick: (event) => {
129
+ event.preventDefault();
130
+ handlePageChange(pageNum);
131
+ },
132
+ "aria-label": commonProps.ariaLabel,
133
+ "aria-current": commonProps.isActive ? "page" : void 0,
134
+ children: pageNum
135
+ }
136
+ ) : /* @__PURE__ */ jsx(PaginationLink, { ...commonProps, children: pageNum }) }, `${encodedPageNum}`)
146
137
  );
147
138
  };
148
139
  addPageNumber(1);
@@ -177,7 +168,7 @@ const Pagination = ({
177
168
  className: cn("flex items-center gap-2", baseStyles.button, currentPage === 1 && "opacity-50"),
178
169
  onClick: currentPage > 1 ? commonNavProps(currentPage - 1).onClick : void 0,
179
170
  disabled: currentPage === 1,
180
- "aria-label": labels.previous === "" ? "Go to previous page" : labels.previous,
171
+ "aria-label": labels.previous ? labels.previous : "Go to previous page",
181
172
  children: [
182
173
  /* @__PURE__ */ jsx(CaretLeft, { className: "h-4 w-4 shrink-0" }),
183
174
  labels.previous && /* @__PURE__ */ jsx("span", { children: labels.previous })
@@ -200,7 +191,7 @@ const Pagination = ({
200
191
  className: cn("flex items-center gap-2", baseStyles.button, currentPage === totalPages && "opacity-50"),
201
192
  onClick: currentPage < totalPages ? commonNavProps(currentPage + 1).onClick : void 0,
202
193
  disabled: currentPage === totalPages || totalPages === 0,
203
- "aria-label": labels.next === "" ? "Go to next page" : labels.next,
194
+ "aria-label": labels.next ? labels.next : "Go to next page",
204
195
  children: [
205
196
  labels.next && /* @__PURE__ */ jsx("span", { children: labels.next }),
206
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 } from '@phosphor-icons/react/dist/ssr/CaretLeft'\nimport { CaretRight } from '@phosphor-icons/react/dist/ssr/CaretRight'\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} & 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, 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 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 aria-label={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 aria-label={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 <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 anchorComponent,\n pageLabel: labels.page,\n }\n\n const encodedPageNum = btoa(`page-${pageNum}`).replaceAll(/[+/=]/g, '')\n\n items.push(\n <PaginationItem\n key={`${encodedPageNum}`}\n aria-label={labels.page ? labels.page.replace('{number}', pageNum.toString()) : undefined}\n >\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={\n labels.page ? labels.page.replace('{number}', pageNum.toString()) : `Go to page ${pageNum.toString()}`\n }\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 PaginationRoot,\n PaginationContent,\n PaginationItem,\n PaginationLink,\n PaginationNext,\n PaginationPrevious,\n PaginationEllipsis,\n Pagination,\n}\n"],"names":[],"mappings":";;;;;;;;AAUA;AAAmB;AACZ;AACI;AACH;AACA;AACE;AAEV;AAoFA;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;AACY;AAEvC;AAAA;AACT;AAGN;AACA;AAEA;AAAiC;AAE7B;AAAC;AAAA;AACC;AAC6B;AACxB;AACL;AACA;AACI;AACiE;AACjE;AAEJ;AAAwC;AACD;AAAA;AAAA;AAG7C;AACA;AAEA;AAA6B;AAEzB;AAAC;AAAA;AACC;AACyB;AACpB;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;AAChD;AACkB;AAGpB;AAEA;AAAM;AACJ;AAAC;AAAA;AAEiF;AAG9E;AAAC;AAAA;AAC6C;AACvC;AACiB;AAEpB;AACA;AAAwB;AAC1B;AAEsG;AAExD;AAE7C;AAAA;AAGuC;AAAA;AApBtB;AAsBxB;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;;"}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "periplo-ui",
3
3
  "description": "IATI UI library",
4
4
  "private": false,
5
- "version": "4.1.2",
5
+ "version": "4.2.1",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",
8
8
  "types": "dist/index.d.ts",