@gridui/pagination 1.0.7 → 1.1.0

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.
package/README.md CHANGED
@@ -5,6 +5,24 @@ Core family. Public API: `Pagination`, `PaginationLabels`, `PaginationProps`.
5
5
  Import components from `@gridui/pagination` and load `@gridui/pagination/styles.css` after Theme.
6
6
  Load styles for any composed dependency used by this family. Applications own routes, labels, state persistence, and branding.
7
7
 
8
+ ## Unknown page count
9
+
10
+ Pass `pageCount={null}` and a boolean `hasNextPage` when the server does not
11
+ provide a total. Pagination shows Previous, the current page, and Next. The host
12
+ supplies either `onPageChange` or `getPageHref`, as with a known count. Previous
13
+ is disabled on page 1; Next is disabled when no next page is available. No last
14
+ page or total is inferred. Pages must remain positive safe integers; `Infinity`
15
+ is rejected, and Next is disabled at `Number.MAX_SAFE_INTEGER`.
16
+
17
+ ```tsx
18
+ <Pagination page={page} pageCount={null} hasNextPage={response.hasNextPage}
19
+ onPageChange={setPage} labels={labels} />
20
+ ```
21
+
22
+ A numeric `pageCount` retains the existing bounded page window and does not take
23
+ `hasNextPage`. Unknown totals still use page numbers; applications own cursor
24
+ mapping, fetching, and history when their backend uses cursor pagination.
25
+
8
26
  See [component ownership](https://github.com/sudo-ui/GridUI-React-Monorepo/blob/main/docs/component-ownership.md) and [release history](https://github.com/sudo-ui/GridUI-React-Monorepo/tree/main/packages-core/pagination/.changeset/history).
9
27
 
10
28
  [Component reference](docs/reference/README.md) contains focused API pages for each public component.
package/dist/index.js CHANGED
@@ -59,10 +59,14 @@ import { ChevronLeft, ChevronRight, Ellipsis } from "lucide-react";
59
59
  import { Fragment } from "react";
60
60
  import { jsx, jsxs } from "react/jsx-runtime";
61
61
  var Pagination = (props) => {
62
- const { page, pageCount, labels, onPageChange, getPageHref, className, ...restProps } = props;
63
- const entries = paginationRange(page, pageCount);
64
- const compactEntries = paginationRange(page, pageCount, true);
65
- const current = Math.max(1, Math.min(page, pageCount));
62
+ const { page, pageCount, hasNextPage, labels, onPageChange, getPageHref, className, ...restProps } = props;
63
+ if (pageCount === null && (!Number.isSafeInteger(page) || page < 1 || typeof hasNextPage !== "boolean")) {
64
+ throw new RangeError("Unknown-count Pagination requires a positive safe integer page and a boolean hasNextPage.");
65
+ }
66
+ const entries = pageCount === null ? [page] : paginationRange(page, pageCount);
67
+ const compactEntries = pageCount === null ? entries : paginationRange(page, pageCount, true);
68
+ const current = pageCount === null ? page : Math.max(1, Math.min(page, pageCount));
69
+ const nextDisabled = pageCount === null ? !hasNextPage || current === Number.MAX_SAFE_INTEGER : pageCount === 0 || current >= pageCount;
66
70
  const control = (target, label, children, disabled, active = false) => {
67
71
  const shared = {
68
72
  "aria-label": label,
@@ -154,7 +158,7 @@ var Pagination = (props) => {
154
158
  className: "gridui-u-pagination--rtl:rotate-180",
155
159
  "aria-hidden": "true"
156
160
  }
157
- ), pageCount === 0 || current >= pageCount) })
161
+ ), nextDisabled) })
158
162
  ]
159
163
  }
160
164
  )
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/pagination/range.ts", "../src/pagination/pagination.tsx"],
4
- "sourcesContent": ["/**\n * @author WMXPY\n * @package Pagination\n * @namespace Pagination\n * @description Range\n */\n\nexport type PaginationEntry = number | \"start-ellipsis\" | \"end-ellipsis\";\n\nexport const paginationRange = (page: number, pageCount: number, compact = false): PaginationEntry[] => {\n if (!Number.isSafeInteger(pageCount) || pageCount < 0 || !Number.isSafeInteger(page) || page < 1) {\n throw new RangeError(\"Pagination requires a positive integer page and a non-negative integer pageCount.\");\n }\n if (pageCount === 0) {\n return [];\n }\n if (pageCount <= (compact ? 5 : 7)) {\n return Array.from({ length: pageCount }, (_, index) => {\n return index + 1;\n });\n }\n const current = Math.min(page, pageCount);\n if (compact) {\n const positions = [\n ...new Set([\n 1,\n current,\n pageCount,\n ]),\n ];\n const entries: PaginationEntry[] = [];\n for (const [\n index,\n position,\n ] of positions.entries()) {\n if (index > 0 && position - positions[index - 1]! > 1) {\n entries.push(position <= current ? \"start-ellipsis\" : \"end-ellipsis\");\n }\n entries.push(position);\n }\n return entries;\n }\n const start = Math.max(2, Math.min(current - 1, pageCount - 4));\n const end = Math.min(pageCount - 1, Math.max(current + 1, 5));\n const entries: PaginationEntry[] = [1];\n if (start === 3) {\n entries.push(2);\n } else if (start > 3) {\n entries.push(\"start-ellipsis\");\n }\n for (let index = start; index <= end; index++) { entries.push(index); }\n if (end === pageCount - 2) {\n entries.push(pageCount - 1);\n } else if (end < pageCount - 2) {\n entries.push(\"end-ellipsis\");\n }\n entries.push(pageCount);\n return entries;\n};\n", "/**\n * @author WMXPY\n * @package Pagination\n * @namespace Pagination\n * @description Pagination\n */\n\nimport { type PaginationEntry, paginationRange } from \"./range\";\nimport { Button, ButtonLink } from \"@gridui/button\";\nimport { cn } from \"@gridui/style-utils\";\nimport { ChevronLeft, ChevronRight, Ellipsis } from \"lucide-react\";\nimport { type ComponentPropsWithRef, type FC, Fragment, type ReactNode } from \"react\";\n\nexport type PaginationLabels = {\n readonly navigation: string;\n readonly previous: string;\n readonly next: string;\n readonly page: (page: number) => string;\n readonly ellipsis: string;\n};\n\nexport type PaginationProps = Omit<ComponentPropsWithRef<\"nav\">, \"children\" | \"aria-label\"> & {\n readonly page: number;\n readonly pageCount: number;\n readonly labels: PaginationLabels;\n} & ({\n readonly onPageChange: (page: number) => void;\n readonly getPageHref?: never;\n} | {\n readonly getPageHref: (page: number) => string;\n readonly onPageChange?: never;\n});\n\nexport const Pagination: FC<PaginationProps> = (props: PaginationProps) => {\n const { page, pageCount, labels, onPageChange, getPageHref, className, ...restProps } = props;\n const entries = paginationRange(page, pageCount);\n const compactEntries = paginationRange(page, pageCount, true);\n const current = Math.max(1, Math.min(page, pageCount));\n const control = (target: number, label: string, children: ReactNode, disabled: boolean, active = false) => {\n const shared = {\n \"aria-label\": label,\n \"aria-current\": active ? \"page\" as const : undefined,\n variant: active ? \"secondary\" as const : \"quiet\" as const,\n layout: \"icon\" as const,\n className: typeof children === \"number\" ? \"gridui-u-pagination--h-auto gridui-u-pagination--min-h-11 gridui-u-pagination--w-auto gridui-u-pagination--min-w-11 gridui-u-pagination--px-gridui-8 gridui-u-pagination--whitespace-nowrap\" : undefined,\n };\n if (getPageHref && !disabled) {\n return (<ButtonLink\n {...shared}\n href={getPageHref(target)}\n >\n {children}\n </ButtonLink>);\n }\n return (<Button\n {...shared}\n disabled={disabled}\n onClick={() => {\n if (target !== current) {\n onPageChange?.(target);\n }\n }}\n >\n {children}\n </Button>);\n };\n const renderEntry = (entry: PaginationEntry, entryClassName?: string) => {\n return (<li\n className={entryClassName}\n >\n {typeof entry === \"number\"\n ? control(entry, labels.page(entry), entry, false, entry === current)\n : (<span\n role=\"img\"\n className=\"gridui-u-pagination--inline-flex gridui-u-pagination--min-h-11 gridui-u-pagination--min-w-11 gridui-u-pagination--items-center gridui-u-pagination--justify-center gridui-u-pagination--text-muted\"\n aria-label={labels.ellipsis}\n >\n <Ellipsis\n aria-hidden=\"true\"\n />\n </span>)}\n </li>);\n };\n return (<nav\n {...restProps}\n aria-label={labels.navigation}\n className={cn(\"gridui-u-pagination--min-w-0\", className)}\n >\n <ul\n className=\"gridui-u-pagination--m-0 gridui-u-pagination--flex gridui-u-pagination--list-none gridui-u-pagination--flex-wrap gridui-u-pagination--items-center gridui-u-pagination--gap-0 gridui-u-pagination--p-0 gridui-u-pagination--md:gap-gridui-4\"\n >\n <li>\n {control(current - 1, labels.previous, (<ChevronLeft\n className=\"gridui-u-pagination--rtl:rotate-180\"\n aria-hidden=\"true\"\n />), pageCount === 0 || current === 1)}\n </li>\n {entries.map(entry => {\n return (<Fragment\n key={entry}\n >\n {entry === pageCount && compactEntries.includes(\"end-ellipsis\") && !entries.includes(\"end-ellipsis\")\n && renderEntry(\"end-ellipsis\", cn(\"gridui-u-pagination--md:hidden\"))}\n {renderEntry(entry, compactEntries.includes(entry) ? undefined : cn(\"gridui-u-pagination--hidden gridui-u-pagination--md:block\"))}\n {entry === 1 && compactEntries.includes(\"start-ellipsis\") && !entries.includes(\"start-ellipsis\")\n && renderEntry(\"start-ellipsis\", cn(\"gridui-u-pagination--md:hidden\"))}\n </Fragment>);\n })}\n <li>\n {control(current + 1, labels.next, (<ChevronRight\n className=\"gridui-u-pagination--rtl:rotate-180\"\n aria-hidden=\"true\"\n />), pageCount === 0 || current >= pageCount)}\n </li>\n </ul>\n </nav>);\n};\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * @author WMXPY\n * @package Pagination\n * @namespace Pagination\n * @description Range\n */\n\nexport type PaginationEntry = number | \"start-ellipsis\" | \"end-ellipsis\";\n\nexport const paginationRange = (page: number, pageCount: number, compact = false): PaginationEntry[] => {\n if (!Number.isSafeInteger(pageCount) || pageCount < 0 || !Number.isSafeInteger(page) || page < 1) {\n throw new RangeError(\"Pagination requires a positive integer page and a non-negative integer pageCount.\");\n }\n if (pageCount === 0) {\n return [];\n }\n if (pageCount <= (compact ? 5 : 7)) {\n return Array.from({ length: pageCount }, (_, index) => {\n return index + 1;\n });\n }\n const current = Math.min(page, pageCount);\n if (compact) {\n const positions = [\n ...new Set([\n 1,\n current,\n pageCount,\n ]),\n ];\n const entries: PaginationEntry[] = [];\n for (const [\n index,\n position,\n ] of positions.entries()) {\n if (index > 0 && position - positions[index - 1]! > 1) {\n entries.push(position <= current ? \"start-ellipsis\" : \"end-ellipsis\");\n }\n entries.push(position);\n }\n return entries;\n }\n const start = Math.max(2, Math.min(current - 1, pageCount - 4));\n const end = Math.min(pageCount - 1, Math.max(current + 1, 5));\n const entries: PaginationEntry[] = [1];\n if (start === 3) {\n entries.push(2);\n } else if (start > 3) {\n entries.push(\"start-ellipsis\");\n }\n for (let index = start; index <= end; index++) { entries.push(index); }\n if (end === pageCount - 2) {\n entries.push(pageCount - 1);\n } else if (end < pageCount - 2) {\n entries.push(\"end-ellipsis\");\n }\n entries.push(pageCount);\n return entries;\n};\n", "/**\n * @author WMXPY\n * @package Pagination\n * @namespace Pagination\n * @description Pagination\n */\n\nimport { type PaginationEntry, paginationRange } from \"./range\";\nimport { Button, ButtonLink } from \"@gridui/button\";\nimport { cn } from \"@gridui/style-utils\";\nimport { ChevronLeft, ChevronRight, Ellipsis } from \"lucide-react\";\nimport { type ComponentPropsWithRef, type FC, Fragment, type ReactNode } from \"react\";\n\nexport type PaginationLabels = {\n readonly navigation: string;\n readonly previous: string;\n readonly next: string;\n readonly page: (page: number) => string;\n readonly ellipsis: string;\n};\n\nexport type PaginationProps = Omit<ComponentPropsWithRef<\"nav\">, \"children\" | \"aria-label\"> & {\n readonly page: number;\n readonly labels: PaginationLabels;\n} & ({\n readonly pageCount: number;\n readonly hasNextPage?: never;\n} | {\n readonly pageCount: null;\n readonly hasNextPage: boolean;\n}) & ({\n readonly onPageChange: (page: number) => void;\n readonly getPageHref?: never;\n} | {\n readonly getPageHref: (page: number) => string;\n readonly onPageChange?: never;\n});\n\nexport const Pagination: FC<PaginationProps> = (props: PaginationProps) => {\n const { page, pageCount, hasNextPage, labels, onPageChange, getPageHref, className, ...restProps } = props;\n if (pageCount === null && (!Number.isSafeInteger(page) || page < 1 || typeof hasNextPage !== \"boolean\")) {\n throw new RangeError(\"Unknown-count Pagination requires a positive safe integer page and a boolean hasNextPage.\");\n }\n const entries = pageCount === null ? [page] : paginationRange(page, pageCount);\n const compactEntries = pageCount === null ? entries : paginationRange(page, pageCount, true);\n const current = pageCount === null ? page : Math.max(1, Math.min(page, pageCount));\n const nextDisabled = pageCount === null\n ? !hasNextPage || current === Number.MAX_SAFE_INTEGER\n : pageCount === 0 || current >= pageCount;\n const control = (target: number, label: string, children: ReactNode, disabled: boolean, active = false) => {\n const shared = {\n \"aria-label\": label,\n \"aria-current\": active ? \"page\" as const : undefined,\n variant: active ? \"secondary\" as const : \"quiet\" as const,\n layout: \"icon\" as const,\n className: typeof children === \"number\" ? \"gridui-u-pagination--h-auto gridui-u-pagination--min-h-11 gridui-u-pagination--w-auto gridui-u-pagination--min-w-11 gridui-u-pagination--px-gridui-8 gridui-u-pagination--whitespace-nowrap\" : undefined,\n };\n if (getPageHref && !disabled) {\n return (<ButtonLink\n {...shared}\n href={getPageHref(target)}\n >\n {children}\n </ButtonLink>);\n }\n return (<Button\n {...shared}\n disabled={disabled}\n onClick={() => {\n if (target !== current) {\n onPageChange?.(target);\n }\n }}\n >\n {children}\n </Button>);\n };\n const renderEntry = (entry: PaginationEntry, entryClassName?: string) => {\n return (<li\n className={entryClassName}\n >\n {typeof entry === \"number\"\n ? control(entry, labels.page(entry), entry, false, entry === current)\n : (<span\n role=\"img\"\n className=\"gridui-u-pagination--inline-flex gridui-u-pagination--min-h-11 gridui-u-pagination--min-w-11 gridui-u-pagination--items-center gridui-u-pagination--justify-center gridui-u-pagination--text-muted\"\n aria-label={labels.ellipsis}\n >\n <Ellipsis\n aria-hidden=\"true\"\n />\n </span>)}\n </li>);\n };\n return (<nav\n {...restProps}\n aria-label={labels.navigation}\n className={cn(\"gridui-u-pagination--min-w-0\", className)}\n >\n <ul\n className=\"gridui-u-pagination--m-0 gridui-u-pagination--flex gridui-u-pagination--list-none gridui-u-pagination--flex-wrap gridui-u-pagination--items-center gridui-u-pagination--gap-0 gridui-u-pagination--p-0 gridui-u-pagination--md:gap-gridui-4\"\n >\n <li>\n {control(current - 1, labels.previous, (<ChevronLeft\n className=\"gridui-u-pagination--rtl:rotate-180\"\n aria-hidden=\"true\"\n />), pageCount === 0 || current === 1)}\n </li>\n {entries.map(entry => {\n return (<Fragment\n key={entry}\n >\n {entry === pageCount && compactEntries.includes(\"end-ellipsis\") && !entries.includes(\"end-ellipsis\")\n && renderEntry(\"end-ellipsis\", cn(\"gridui-u-pagination--md:hidden\"))}\n {renderEntry(entry, compactEntries.includes(entry) ? undefined : cn(\"gridui-u-pagination--hidden gridui-u-pagination--md:block\"))}\n {entry === 1 && compactEntries.includes(\"start-ellipsis\") && !entries.includes(\"start-ellipsis\")\n && renderEntry(\"start-ellipsis\", cn(\"gridui-u-pagination--md:hidden\"))}\n </Fragment>);\n })}\n <li>\n {control(current + 1, labels.next, (<ChevronRight\n className=\"gridui-u-pagination--rtl:rotate-180\"\n aria-hidden=\"true\"\n />), nextDisabled)}\n </li>\n </ul>\n </nav>);\n};\n"],
5
+ "mappings": "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",
6
6
  "names": ["entries"]
7
7
  }
@@ -14,9 +14,14 @@ export type PaginationLabels = {
14
14
  };
15
15
  export type PaginationProps = Omit<ComponentPropsWithRef<"nav">, "children" | "aria-label"> & {
16
16
  readonly page: number;
17
- readonly pageCount: number;
18
17
  readonly labels: PaginationLabels;
19
18
  } & ({
19
+ readonly pageCount: number;
20
+ readonly hasNextPage?: never;
21
+ } | {
22
+ readonly pageCount: null;
23
+ readonly hasNextPage: boolean;
24
+ }) & ({
20
25
  readonly onPageChange: (page: number) => void;
21
26
  readonly getPageHref?: never;
22
27
  } | {
package/docs/catalog.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "name": "@gridui/pagination",
4
- "version": "1.0.7",
4
+ "version": "1.1.0",
5
5
  "category": "core",
6
6
  "description": "GridUI React pagination",
7
- "usage": "Component reference contains focused API pages for each public component.",
7
+ "usage": "Pass `pageCount={null}` and a boolean `hasNextPage` when the server does not provide a total. Pagination shows Previous, the current page, and Next. The host supplies either `onPageChange` or `getPageHref`, as with a known count. Previous is disabled on page 1; Next is disabled when no next page is available. No last page or total is inferred. Pages must remain positive safe integers; `Infinity` is rejected, and Next is disabled at `Number.MAX_SAFE_INTEGER`.",
8
8
  "documentation": [
9
9
  "README.md",
10
10
  "docs/reference/README.md",
@@ -33,6 +33,7 @@
33
33
  "@gridui/pagination/styles.css"
34
34
  ],
35
35
  "examples": [
36
+ "https://github.com/sudo-ui/GridUI-React-Monorepo/blob/main/packages-core/pagination/stories/getting-started.mdx",
36
37
  "https://github.com/sudo-ui/GridUI-React-Monorepo/blob/main/packages-core/pagination/stories/paginated-navigation.mdx",
37
38
  "https://github.com/sudo-ui/GridUI-React-Monorepo/blob/main/packages-core/pagination/stories/pagination.stories.tsx"
38
39
  ]
@@ -53,13 +53,17 @@ Called when the corresponding interaction occurs; inspect the arguments in Actio
53
53
 
54
54
  ``number`` · Required
55
55
 
56
+ ### labels
57
+
58
+ ``PaginationLabels`` · Required
59
+
56
60
  ### pageCount
57
61
 
58
- ``number`` · Required
62
+ ``number | null`` · Required
59
63
 
60
- ### labels
64
+ ### hasNextPage
61
65
 
62
- ``PaginationLabels`` · Required
66
+ ``boolean | undefined`` · Optional
63
67
 
64
68
  ### onPageChange
65
69
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gridui/pagination",
3
- "version": "1.0.7",
3
+ "version": "1.1.0",
4
4
  "description": "GridUI React pagination",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -27,9 +27,9 @@
27
27
  "react-dom": "^19.2.0"
28
28
  },
29
29
  "dependencies": {
30
- "@gridui/button": "^4.1.0",
30
+ "@gridui/button": "^5.0.0",
31
31
  "@gridui/style-utils": "^4.0.0",
32
- "@gridui/theme": "^2.5.3",
32
+ "@gridui/theme": "^2.5.4",
33
33
  "lucide-react": "1.70.0"
34
34
  },
35
35
  "devDependencies": {