@sproutsocial/seeds-react-pagination 0.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/.turbo/turbo-build.log +21 -0
- package/dist/esm/index.js +223 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/index.d.mts +91 -0
- package/dist/index.d.ts +91 -0
- package/dist/index.js +261 -0
- package/dist/index.js.map +1 -0
- package/jest.config.js +11 -0
- package/package.json +52 -0
- package/src/Pagination.tsx +210 -0
- package/src/PaginationTypes.ts +84 -0
- package/src/index.ts +2 -0
- package/src/styles.ts +75 -0
- package/tsconfig.json +8 -0
- package/tsup.config.ts +12 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
yarn run v1.22.22
|
|
2
|
+
$ tsup --dts
|
|
3
|
+
[34mCLI[39m Building entry: src/index.ts
|
|
4
|
+
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
5
|
+
[34mCLI[39m tsup v8.5.0
|
|
6
|
+
[34mCLI[39m Using tsup config: /home/runner/work/seeds/seeds/seeds-react/seeds-react-pagination/tsup.config.ts
|
|
7
|
+
[34mCLI[39m Target: es2022
|
|
8
|
+
[34mCLI[39m Cleaning output folder
|
|
9
|
+
[34mCJS[39m Build start
|
|
10
|
+
[34mESM[39m Build start
|
|
11
|
+
[32mCJS[39m [1mdist/index.js [22m[32m9.42 KB[39m
|
|
12
|
+
[32mCJS[39m [1mdist/index.js.map [22m[32m15.70 KB[39m
|
|
13
|
+
[32mCJS[39m ⚡️ Build success in 160ms
|
|
14
|
+
[32mESM[39m [1mdist/esm/index.js [22m[32m7.07 KB[39m
|
|
15
|
+
[32mESM[39m [1mdist/esm/index.js.map [22m[32m15.50 KB[39m
|
|
16
|
+
[32mESM[39m ⚡️ Build success in 155ms
|
|
17
|
+
[34mDTS[39m Build start
|
|
18
|
+
[32mDTS[39m ⚡️ Build success in 25208ms
|
|
19
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m3.08 KB[39m
|
|
20
|
+
[32mDTS[39m [1mdist/index.d.mts [22m[32m3.08 KB[39m
|
|
21
|
+
Done in 33.52s.
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
// src/Pagination.tsx
|
|
2
|
+
import "react";
|
|
3
|
+
import { Select } from "@sproutsocial/seeds-react-select";
|
|
4
|
+
import { Icon } from "@sproutsocial/seeds-react-icon";
|
|
5
|
+
|
|
6
|
+
// src/styles.ts
|
|
7
|
+
import styled from "styled-components";
|
|
8
|
+
import { Text } from "@sproutsocial/seeds-react-text";
|
|
9
|
+
var StyledPaginationContainer = styled.div`
|
|
10
|
+
${(props) => props.theme.typography[200]}
|
|
11
|
+
display: flex;
|
|
12
|
+
align-items: center;
|
|
13
|
+
gap: ${(props) => props.theme.space[300]};
|
|
14
|
+
margin-top: ${(props) => props.theme.space[400]};
|
|
15
|
+
flex-wrap: wrap;
|
|
16
|
+
`;
|
|
17
|
+
var StyledPaginationControls = styled.div`
|
|
18
|
+
display: flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
margin-left: auto;
|
|
21
|
+
`;
|
|
22
|
+
var StyledPaginationInfo = styled(Text)`
|
|
23
|
+
white-space: nowrap;
|
|
24
|
+
`;
|
|
25
|
+
var StyledPageSizeSelector = styled.div`
|
|
26
|
+
display: flex;
|
|
27
|
+
align-items: center;
|
|
28
|
+
gap: ${(props) => props.theme.space[300]};
|
|
29
|
+
`;
|
|
30
|
+
var StyledPageButtons = styled.div`
|
|
31
|
+
display: inline-flex;
|
|
32
|
+
flex-flow: row wrap;
|
|
33
|
+
background-clip: padding-box;
|
|
34
|
+
border: 1px solid
|
|
35
|
+
${(props) => props.theme.colors.button.secondary.border.base};
|
|
36
|
+
border-radius: ${(props) => props.theme.radii.outer};
|
|
37
|
+
padding: ${(props) => props.theme.space[100]};
|
|
38
|
+
background: transparent;
|
|
39
|
+
`;
|
|
40
|
+
var StyledPaginationButton = styled.button`
|
|
41
|
+
min-width: calc(${(props) => props.theme.space[500]} + 4px);
|
|
42
|
+
min-height: calc(${(props) => props.theme.space[500]} + 2px);
|
|
43
|
+
padding: calc(${(props) => props.theme.space[350]} - 6px);
|
|
44
|
+
line-height: ${(props) => props.theme.space[400]};
|
|
45
|
+
font-weight: ${(props) => props.theme.fontWeights.semibold};
|
|
46
|
+
background-color: ${(props) => props.isSelected ? props.theme.colors.button.secondary.background.active : "transparent"};
|
|
47
|
+
color: ${(props) => props.isSelected ? props.theme.colors.text.inverse : props.theme.colors.text.body};
|
|
48
|
+
border: none;
|
|
49
|
+
border-radius: ${(props) => props.theme.radii.inner};
|
|
50
|
+
cursor: pointer;
|
|
51
|
+
display: inline-flex;
|
|
52
|
+
align-items: center;
|
|
53
|
+
justify-content: center;
|
|
54
|
+
|
|
55
|
+
&:hover:not(:disabled) {
|
|
56
|
+
color: ${(props) => props.isSelected ? props.theme.colors.text.inverse : void 0};
|
|
57
|
+
background-color: ${(props) => props.isSelected ? props.theme.colors.button.secondary.background.active : props.theme.colors.listItem.background.hover};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
&:disabled {
|
|
61
|
+
cursor: default;
|
|
62
|
+
opacity: ${(props) => props.isSelected ? 1 : 0.5};
|
|
63
|
+
}
|
|
64
|
+
`;
|
|
65
|
+
|
|
66
|
+
// src/Pagination.tsx
|
|
67
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
68
|
+
var Pagination = ({
|
|
69
|
+
paginationConfig,
|
|
70
|
+
currentPageIndex,
|
|
71
|
+
pageSize,
|
|
72
|
+
totalRows,
|
|
73
|
+
onPageChange,
|
|
74
|
+
onPageSizeChange
|
|
75
|
+
}) => {
|
|
76
|
+
const { displayType, pageSizeOptions, tableCountFunction } = paginationConfig;
|
|
77
|
+
const totalPages = Math.ceil(totalRows / pageSize);
|
|
78
|
+
const currentPage = currentPageIndex + 1;
|
|
79
|
+
const startRow = totalRows === 0 ? 0 : currentPageIndex * pageSize + 1;
|
|
80
|
+
const endRow = Math.min((currentPageIndex + 1) * pageSize, totalRows);
|
|
81
|
+
const canGoPrevious = currentPageIndex > 0;
|
|
82
|
+
const canGoNext = currentPageIndex < totalPages - 1;
|
|
83
|
+
const handlePrevious = () => {
|
|
84
|
+
if (canGoPrevious) {
|
|
85
|
+
onPageChange(currentPageIndex - 1);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
const handleNext = () => {
|
|
89
|
+
if (canGoNext) {
|
|
90
|
+
onPageChange(currentPageIndex + 1);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
const handlePageSizeChange = (e) => {
|
|
94
|
+
const newPageSize = Number(e.currentTarget.value);
|
|
95
|
+
onPageSizeChange(newPageSize);
|
|
96
|
+
onPageChange(0);
|
|
97
|
+
};
|
|
98
|
+
const getPageNumbers = () => {
|
|
99
|
+
const pages = [];
|
|
100
|
+
const size = paginationConfig.size || "default";
|
|
101
|
+
const NUM_PAGE_LOWER = size === "mini" ? 0 : 1;
|
|
102
|
+
const NUM_PAGE_UPPER = size === "mini" ? 0 : 2;
|
|
103
|
+
if (totalPages <= 5 + NUM_PAGE_LOWER + NUM_PAGE_UPPER) {
|
|
104
|
+
for (let i = 1; i <= totalPages; i++) {
|
|
105
|
+
pages.push(i);
|
|
106
|
+
}
|
|
107
|
+
} else {
|
|
108
|
+
pages.push(1);
|
|
109
|
+
if (currentPage > 3 + NUM_PAGE_LOWER) {
|
|
110
|
+
pages.push("...");
|
|
111
|
+
}
|
|
112
|
+
let start;
|
|
113
|
+
let end;
|
|
114
|
+
if (currentPage <= 3 + NUM_PAGE_LOWER) {
|
|
115
|
+
start = 2;
|
|
116
|
+
end = 3 + NUM_PAGE_LOWER + NUM_PAGE_UPPER;
|
|
117
|
+
} else if (currentPage > totalPages - (3 + NUM_PAGE_UPPER)) {
|
|
118
|
+
start = totalPages - (2 + NUM_PAGE_LOWER + NUM_PAGE_UPPER);
|
|
119
|
+
end = totalPages - 1;
|
|
120
|
+
} else {
|
|
121
|
+
start = currentPage - NUM_PAGE_LOWER;
|
|
122
|
+
end = currentPage + NUM_PAGE_UPPER;
|
|
123
|
+
}
|
|
124
|
+
for (let i = start; i <= end; i++) {
|
|
125
|
+
pages.push(i);
|
|
126
|
+
}
|
|
127
|
+
if (currentPage < totalPages - (2 + NUM_PAGE_UPPER)) {
|
|
128
|
+
pages.push("...");
|
|
129
|
+
}
|
|
130
|
+
pages.push(totalPages);
|
|
131
|
+
}
|
|
132
|
+
return pages;
|
|
133
|
+
};
|
|
134
|
+
const pageNumbers = getPageNumbers();
|
|
135
|
+
if (totalPages <= 1 && !pageSizeOptions) {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
return /* @__PURE__ */ jsxs(StyledPaginationContainer, { children: [
|
|
139
|
+
/* @__PURE__ */ jsx(StyledPaginationInfo, { children: tableCountFunction({
|
|
140
|
+
startNum: startRow,
|
|
141
|
+
endNum: endRow,
|
|
142
|
+
totalRowCount: totalRows
|
|
143
|
+
}) }),
|
|
144
|
+
pageSizeOptions && displayType === "dropdown" && /* @__PURE__ */ jsx(StyledPageSizeSelector, { children: /* @__PURE__ */ jsx(
|
|
145
|
+
Select,
|
|
146
|
+
{
|
|
147
|
+
id: "page-size-select",
|
|
148
|
+
name: "page-size",
|
|
149
|
+
value: String(pageSize),
|
|
150
|
+
onChange: handlePageSizeChange,
|
|
151
|
+
ariaLabel: "Rows per page",
|
|
152
|
+
size: "small",
|
|
153
|
+
children: pageSizeOptions.map((size) => /* @__PURE__ */ jsxs("option", { value: size, children: [
|
|
154
|
+
size,
|
|
155
|
+
" per page"
|
|
156
|
+
] }, size))
|
|
157
|
+
}
|
|
158
|
+
) }),
|
|
159
|
+
totalPages > 1 && /* @__PURE__ */ jsx(StyledPaginationControls, { children: /* @__PURE__ */ jsxs(StyledPageButtons, { children: [
|
|
160
|
+
/* @__PURE__ */ jsx(
|
|
161
|
+
StyledPaginationButton,
|
|
162
|
+
{
|
|
163
|
+
onClick: handlePrevious,
|
|
164
|
+
disabled: !canGoPrevious,
|
|
165
|
+
"aria-label": "Previous page",
|
|
166
|
+
children: /* @__PURE__ */ jsx(Icon, { name: "chevron-left-outline" })
|
|
167
|
+
}
|
|
168
|
+
),
|
|
169
|
+
pageNumbers.map((pageNum, index) => {
|
|
170
|
+
if (pageNum === "...") {
|
|
171
|
+
return /* @__PURE__ */ jsx(
|
|
172
|
+
StyledPaginationButton,
|
|
173
|
+
{
|
|
174
|
+
disabled: true,
|
|
175
|
+
"aria-label": "More pages",
|
|
176
|
+
children: /* @__PURE__ */ jsx(Icon, { name: "ellipsis-horizontal-outline" })
|
|
177
|
+
},
|
|
178
|
+
`ellipsis-${index}`
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
const page = pageNum;
|
|
182
|
+
const isCurrentPage = page === currentPage;
|
|
183
|
+
return /* @__PURE__ */ jsx(
|
|
184
|
+
StyledPaginationButton,
|
|
185
|
+
{
|
|
186
|
+
onClick: () => onPageChange(page - 1),
|
|
187
|
+
disabled: isCurrentPage,
|
|
188
|
+
"aria-label": `Page ${page}`,
|
|
189
|
+
"aria-current": isCurrentPage ? "page" : void 0,
|
|
190
|
+
isSelected: isCurrentPage,
|
|
191
|
+
children: page
|
|
192
|
+
},
|
|
193
|
+
page
|
|
194
|
+
);
|
|
195
|
+
}),
|
|
196
|
+
/* @__PURE__ */ jsx(
|
|
197
|
+
StyledPaginationButton,
|
|
198
|
+
{
|
|
199
|
+
onClick: handleNext,
|
|
200
|
+
disabled: !canGoNext,
|
|
201
|
+
"aria-label": "Next page",
|
|
202
|
+
children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right-outline" })
|
|
203
|
+
}
|
|
204
|
+
)
|
|
205
|
+
] }) })
|
|
206
|
+
] });
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
// src/PaginationTypes.ts
|
|
210
|
+
import "react";
|
|
211
|
+
var PAGE_SIZE_OPTIONS_STANDARD = [10, 25, 50, 100];
|
|
212
|
+
var PAGE_SIZE_OPTIONS_COMPACT = [5, 10, 20];
|
|
213
|
+
var PAGE_SIZE_OPTIONS_LARGE = [50, 100, 200, 500];
|
|
214
|
+
var PAGE_SIZE_OPTIONS = {
|
|
215
|
+
STANDARD: PAGE_SIZE_OPTIONS_STANDARD,
|
|
216
|
+
COMPACT: PAGE_SIZE_OPTIONS_COMPACT,
|
|
217
|
+
LARGE: PAGE_SIZE_OPTIONS_LARGE
|
|
218
|
+
};
|
|
219
|
+
export {
|
|
220
|
+
PAGE_SIZE_OPTIONS,
|
|
221
|
+
Pagination
|
|
222
|
+
};
|
|
223
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/Pagination.tsx","../../src/styles.ts","../../src/PaginationTypes.ts"],"sourcesContent":["import * as React from \"react\";\nimport { Select } from \"@sproutsocial/seeds-react-select\";\nimport { Icon } from \"@sproutsocial/seeds-react-icon\";\nimport type { TypePaginationConfig } from \"./PaginationTypes\";\nimport {\n StyledPaginationContainer,\n StyledPaginationControls,\n StyledPaginationInfo,\n StyledPageSizeSelector,\n StyledPageButtons,\n StyledPaginationButton,\n} from \"./styles\";\n\ninterface PaginationProps {\n paginationConfig: TypePaginationConfig;\n currentPageIndex: number;\n pageSize: number;\n totalRows: number;\n onPageChange: (pageIndex: number) => void;\n onPageSizeChange: (pageSize: number) => void;\n}\n\nexport const Pagination = ({\n paginationConfig,\n currentPageIndex,\n pageSize,\n totalRows,\n onPageChange,\n onPageSizeChange,\n}: PaginationProps) => {\n const { displayType, pageSizeOptions, tableCountFunction } = paginationConfig;\n\n // Calculate pagination values\n const totalPages = Math.ceil(totalRows / pageSize);\n const currentPage = currentPageIndex + 1; // Convert 0-based to 1-based for display\n const startRow = totalRows === 0 ? 0 : currentPageIndex * pageSize + 1;\n const endRow = Math.min((currentPageIndex + 1) * pageSize, totalRows);\n\n const canGoPrevious = currentPageIndex > 0;\n const canGoNext = currentPageIndex < totalPages - 1;\n\n const handlePrevious = () => {\n if (canGoPrevious) {\n onPageChange(currentPageIndex - 1);\n }\n };\n\n const handleNext = () => {\n if (canGoNext) {\n onPageChange(currentPageIndex + 1);\n }\n };\n\n const handlePageSizeChange = (e: React.SyntheticEvent<HTMLSelectElement>) => {\n const newPageSize = Number(e.currentTarget.value);\n onPageSizeChange(newPageSize);\n // Reset to first page when page size changes\n onPageChange(0);\n };\n\n // Generate page number buttons using web-app-core's algorithm\n const getPageNumbers = () => {\n const pages: (number | string)[] = [];\n const size = paginationConfig.size || \"default\";\n\n // Configuration for how many pages to show around current page\n const NUM_PAGE_LOWER = size === \"mini\" ? 0 : 1;\n const NUM_PAGE_UPPER = size === \"mini\" ? 0 : 2;\n\n // If number of pages is small enough, show all the page tokens without ellipsis\n if (totalPages <= 5 + NUM_PAGE_LOWER + NUM_PAGE_UPPER) {\n for (let i = 1; i <= totalPages; i++) {\n pages.push(i);\n }\n } else {\n // Add first page\n pages.push(1);\n\n // Add ellipsis at the beginning if needed\n if (currentPage > 3 + NUM_PAGE_LOWER) {\n pages.push(\"...\");\n }\n\n // Add pages in the middle\n let start: number;\n let end: number; // inclusive index\n\n // If near beginning - Show number of pages before ending ellipsis\n if (currentPage <= 3 + NUM_PAGE_LOWER) {\n start = 2;\n end = 3 + NUM_PAGE_LOWER + NUM_PAGE_UPPER;\n } else if (currentPage > totalPages - (3 + NUM_PAGE_UPPER)) {\n // If near end - Show number of pages after starting ellipsis\n start = totalPages - (2 + NUM_PAGE_LOWER + NUM_PAGE_UPPER);\n end = totalPages - 1;\n } else {\n // If in the middle - Show number of pages between two ellipses\n start = currentPage - NUM_PAGE_LOWER;\n end = currentPage + NUM_PAGE_UPPER;\n }\n\n for (let i = start; i <= end; i++) {\n pages.push(i);\n }\n\n // Add a final ellipsis if necessary\n if (currentPage < totalPages - (2 + NUM_PAGE_UPPER)) {\n pages.push(\"...\");\n }\n\n // Add the last page number\n pages.push(totalPages);\n }\n\n return pages;\n };\n\n const pageNumbers = getPageNumbers();\n\n if (totalPages <= 1 && !pageSizeOptions) {\n // No pagination needed if only one page and no page size options\n return null;\n }\n\n return (\n <StyledPaginationContainer>\n <StyledPaginationInfo>\n {tableCountFunction({\n startNum: startRow,\n endNum: endRow,\n totalRowCount: totalRows,\n })}\n </StyledPaginationInfo>\n {/* Page size selector */}\n {pageSizeOptions && displayType === \"dropdown\" && (\n <StyledPageSizeSelector>\n <Select\n id=\"page-size-select\"\n name=\"page-size\"\n value={String(pageSize)}\n onChange={handlePageSizeChange}\n ariaLabel=\"Rows per page\"\n size=\"small\"\n >\n {pageSizeOptions.map((size) => (\n <option key={size} value={size}>\n {size} per page\n </option>\n ))}\n </Select>\n </StyledPageSizeSelector>\n )}\n\n {/* TODO: Add inline page size selector for displayType === 'inline' */}\n\n {/* Page navigation controls */}\n {totalPages > 1 && (\n <StyledPaginationControls>\n <StyledPageButtons>\n <StyledPaginationButton\n onClick={handlePrevious}\n disabled={!canGoPrevious}\n aria-label=\"Previous page\"\n >\n <Icon name=\"chevron-left-outline\" />\n </StyledPaginationButton>\n\n {pageNumbers.map((pageNum, index) => {\n if (pageNum === \"...\") {\n return (\n <StyledPaginationButton\n key={`ellipsis-${index}`}\n disabled\n aria-label=\"More pages\"\n >\n <Icon name=\"ellipsis-horizontal-outline\" />\n </StyledPaginationButton>\n );\n }\n\n const page = pageNum as number;\n const isCurrentPage = page === currentPage;\n\n return (\n <StyledPaginationButton\n key={page}\n onClick={() => onPageChange(page - 1)}\n disabled={isCurrentPage}\n aria-label={`Page ${page}`}\n aria-current={isCurrentPage ? \"page\" : undefined}\n isSelected={isCurrentPage}\n >\n {page}\n </StyledPaginationButton>\n );\n })}\n\n <StyledPaginationButton\n onClick={handleNext}\n disabled={!canGoNext}\n aria-label=\"Next page\"\n >\n <Icon name=\"chevron-right-outline\" />\n </StyledPaginationButton>\n </StyledPageButtons>\n </StyledPaginationControls>\n )}\n </StyledPaginationContainer>\n );\n};\n","import styled from \"styled-components\";\nimport { Text } from \"@sproutsocial/seeds-react-text\";\n\n// Pagination Styles\nexport const StyledPaginationContainer = styled.div`\n ${(props) => props.theme.typography[200]}\n display: flex;\n align-items: center;\n gap: ${(props) => props.theme.space[300]};\n margin-top: ${(props) => props.theme.space[400]};\n flex-wrap: wrap;\n`;\n\nexport const StyledPaginationControls = styled.div`\n display: flex;\n align-items: center;\n margin-left: auto;\n`;\n\nexport const StyledPaginationInfo = styled(Text)`\n white-space: nowrap;\n`;\n\nexport const StyledPageSizeSelector = styled.div`\n display: flex;\n align-items: center;\n gap: ${(props) => props.theme.space[300]};\n`;\n\nexport const StyledPageButtons = styled.div`\n display: inline-flex;\n flex-flow: row wrap;\n background-clip: padding-box;\n border: 1px solid\n ${(props) => props.theme.colors.button.secondary.border.base};\n border-radius: ${(props) => props.theme.radii.outer};\n padding: ${(props) => props.theme.space[100]};\n background: transparent;\n`;\n\nexport const StyledPaginationButton = styled.button<{ isSelected?: boolean }>`\n min-width: calc(${(props) => props.theme.space[500]} + 4px);\n min-height: calc(${(props) => props.theme.space[500]} + 2px);\n padding: calc(${(props) => props.theme.space[350]} - 6px);\n line-height: ${(props) => props.theme.space[400]};\n font-weight: ${(props) => props.theme.fontWeights.semibold};\n background-color: ${(props) =>\n props.isSelected\n ? props.theme.colors.button.secondary.background.active\n : \"transparent\"};\n color: ${(props) =>\n props.isSelected\n ? props.theme.colors.text.inverse\n : props.theme.colors.text.body};\n border: none;\n border-radius: ${(props) => props.theme.radii.inner};\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n\n &:hover:not(:disabled) {\n color: ${(props) =>\n props.isSelected ? props.theme.colors.text.inverse : undefined};\n background-color: ${(props) =>\n props.isSelected\n ? props.theme.colors.button.secondary.background.active\n : props.theme.colors.listItem.background.hover};\n }\n\n &:disabled {\n cursor: default;\n opacity: ${(props) => (props.isSelected ? 1 : 0.5)};\n }\n`;\n","import * as React from \"react\";\n\n/**\n * Standard page size option sets for pagination.\n * Export these constants to maintain consistency across tables.\n */\nconst PAGE_SIZE_OPTIONS_STANDARD = [10, 25, 50, 100] as const;\nconst PAGE_SIZE_OPTIONS_COMPACT = [5, 10, 20] as const;\nconst PAGE_SIZE_OPTIONS_LARGE = [50, 100, 200, 500] as const;\n\nexport const PAGE_SIZE_OPTIONS = {\n STANDARD: PAGE_SIZE_OPTIONS_STANDARD,\n COMPACT: PAGE_SIZE_OPTIONS_COMPACT,\n LARGE: PAGE_SIZE_OPTIONS_LARGE,\n};\n\n/**\n * Allowed page size option sets.\n * Use one of the predefined PAGE_SIZE_OPTIONS for consistency.\n */\nexport type TypeAllowedPageSizeOptions =\n | typeof PAGE_SIZE_OPTIONS_STANDARD\n | typeof PAGE_SIZE_OPTIONS_COMPACT\n | typeof PAGE_SIZE_OPTIONS_LARGE;\n\n/**\n * Configuration for pagination controls with page navigation and size selection.\n *\n * @example\n * ```tsx\n * <Pagination\n * paginationConfig={{\n * initialPageSize: 25,\n * displayType: 'dropdown',\n * pageSizeOptions: PAGE_SIZE_OPTIONS.STANDARD,\n * tableCountFunction: ({ startNum, endNum, totalRowCount }) =>\n * `${startNum}-${endNum} of ${totalRowCount}`\n * }}\n * currentPageIndex={0}\n * pageSize={25}\n * totalRows={100}\n * onPageChange={(index) => console.log('Page:', index)}\n * onPageSizeChange={(size) => console.log('Page size:', size)}\n * />\n * ```\n */\nexport interface TypePaginationConfig {\n /**\n * Initial number of rows per page.\n * @default 10\n */\n initialPageSize: number;\n /**\n * Function that returns the intl for displaying the table counts underneath a DataTable\n */\n tableCountFunction: (args: {\n startNum: number;\n endNum: number;\n totalRowCount: number;\n }) => React.ReactNode;\n /**\n * Display mode for page size selector.\n * - 'dropdown': Shows page size selector as a dropdown\n * Only used when pageSizeOptions is provided.\n * @default 'dropdown'\n */\n displayType?: \"dropdown\";\n /**\n * Optional array of page size options for the selector.\n * If not provided, page size selection will not be available.\n * Use PAGE_SIZE_OPTIONS constants for consistency.\n *\n * @example\n * pageSizeOptions: PAGE_SIZE_OPTIONS.STANDARD // [10, 25, 50, 100]\n */\n pageSizeOptions?: TypeAllowedPageSizeOptions;\n /**\n * Size variant for page number display.\n * - 'default': Shows current page ±1-2 pages (more visible pages)\n * - 'mini': Shows only current page (fewer visible pages)\n * @default 'default'\n */\n size?: \"default\" | \"mini\";\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Standard page size option sets for pagination.
|
|
6
|
+
* Export these constants to maintain consistency across tables.
|
|
7
|
+
*/
|
|
8
|
+
declare const PAGE_SIZE_OPTIONS_STANDARD: readonly [10, 25, 50, 100];
|
|
9
|
+
declare const PAGE_SIZE_OPTIONS_COMPACT: readonly [5, 10, 20];
|
|
10
|
+
declare const PAGE_SIZE_OPTIONS_LARGE: readonly [50, 100, 200, 500];
|
|
11
|
+
declare const PAGE_SIZE_OPTIONS: {
|
|
12
|
+
STANDARD: readonly [10, 25, 50, 100];
|
|
13
|
+
COMPACT: readonly [5, 10, 20];
|
|
14
|
+
LARGE: readonly [50, 100, 200, 500];
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Allowed page size option sets.
|
|
18
|
+
* Use one of the predefined PAGE_SIZE_OPTIONS for consistency.
|
|
19
|
+
*/
|
|
20
|
+
type TypeAllowedPageSizeOptions = typeof PAGE_SIZE_OPTIONS_STANDARD | typeof PAGE_SIZE_OPTIONS_COMPACT | typeof PAGE_SIZE_OPTIONS_LARGE;
|
|
21
|
+
/**
|
|
22
|
+
* Configuration for pagination controls with page navigation and size selection.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* <Pagination
|
|
27
|
+
* paginationConfig={{
|
|
28
|
+
* initialPageSize: 25,
|
|
29
|
+
* displayType: 'dropdown',
|
|
30
|
+
* pageSizeOptions: PAGE_SIZE_OPTIONS.STANDARD,
|
|
31
|
+
* tableCountFunction: ({ startNum, endNum, totalRowCount }) =>
|
|
32
|
+
* `${startNum}-${endNum} of ${totalRowCount}`
|
|
33
|
+
* }}
|
|
34
|
+
* currentPageIndex={0}
|
|
35
|
+
* pageSize={25}
|
|
36
|
+
* totalRows={100}
|
|
37
|
+
* onPageChange={(index) => console.log('Page:', index)}
|
|
38
|
+
* onPageSizeChange={(size) => console.log('Page size:', size)}
|
|
39
|
+
* />
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
interface TypePaginationConfig {
|
|
43
|
+
/**
|
|
44
|
+
* Initial number of rows per page.
|
|
45
|
+
* @default 10
|
|
46
|
+
*/
|
|
47
|
+
initialPageSize: number;
|
|
48
|
+
/**
|
|
49
|
+
* Function that returns the intl for displaying the table counts underneath a DataTable
|
|
50
|
+
*/
|
|
51
|
+
tableCountFunction: (args: {
|
|
52
|
+
startNum: number;
|
|
53
|
+
endNum: number;
|
|
54
|
+
totalRowCount: number;
|
|
55
|
+
}) => React.ReactNode;
|
|
56
|
+
/**
|
|
57
|
+
* Display mode for page size selector.
|
|
58
|
+
* - 'dropdown': Shows page size selector as a dropdown
|
|
59
|
+
* Only used when pageSizeOptions is provided.
|
|
60
|
+
* @default 'dropdown'
|
|
61
|
+
*/
|
|
62
|
+
displayType?: "dropdown";
|
|
63
|
+
/**
|
|
64
|
+
* Optional array of page size options for the selector.
|
|
65
|
+
* If not provided, page size selection will not be available.
|
|
66
|
+
* Use PAGE_SIZE_OPTIONS constants for consistency.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* pageSizeOptions: PAGE_SIZE_OPTIONS.STANDARD // [10, 25, 50, 100]
|
|
70
|
+
*/
|
|
71
|
+
pageSizeOptions?: TypeAllowedPageSizeOptions;
|
|
72
|
+
/**
|
|
73
|
+
* Size variant for page number display.
|
|
74
|
+
* - 'default': Shows current page ±1-2 pages (more visible pages)
|
|
75
|
+
* - 'mini': Shows only current page (fewer visible pages)
|
|
76
|
+
* @default 'default'
|
|
77
|
+
*/
|
|
78
|
+
size?: "default" | "mini";
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
interface PaginationProps {
|
|
82
|
+
paginationConfig: TypePaginationConfig;
|
|
83
|
+
currentPageIndex: number;
|
|
84
|
+
pageSize: number;
|
|
85
|
+
totalRows: number;
|
|
86
|
+
onPageChange: (pageIndex: number) => void;
|
|
87
|
+
onPageSizeChange: (pageSize: number) => void;
|
|
88
|
+
}
|
|
89
|
+
declare const Pagination: ({ paginationConfig, currentPageIndex, pageSize, totalRows, onPageChange, onPageSizeChange, }: PaginationProps) => react_jsx_runtime.JSX.Element | null;
|
|
90
|
+
|
|
91
|
+
export { PAGE_SIZE_OPTIONS, Pagination, type TypeAllowedPageSizeOptions, type TypePaginationConfig };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Standard page size option sets for pagination.
|
|
6
|
+
* Export these constants to maintain consistency across tables.
|
|
7
|
+
*/
|
|
8
|
+
declare const PAGE_SIZE_OPTIONS_STANDARD: readonly [10, 25, 50, 100];
|
|
9
|
+
declare const PAGE_SIZE_OPTIONS_COMPACT: readonly [5, 10, 20];
|
|
10
|
+
declare const PAGE_SIZE_OPTIONS_LARGE: readonly [50, 100, 200, 500];
|
|
11
|
+
declare const PAGE_SIZE_OPTIONS: {
|
|
12
|
+
STANDARD: readonly [10, 25, 50, 100];
|
|
13
|
+
COMPACT: readonly [5, 10, 20];
|
|
14
|
+
LARGE: readonly [50, 100, 200, 500];
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Allowed page size option sets.
|
|
18
|
+
* Use one of the predefined PAGE_SIZE_OPTIONS for consistency.
|
|
19
|
+
*/
|
|
20
|
+
type TypeAllowedPageSizeOptions = typeof PAGE_SIZE_OPTIONS_STANDARD | typeof PAGE_SIZE_OPTIONS_COMPACT | typeof PAGE_SIZE_OPTIONS_LARGE;
|
|
21
|
+
/**
|
|
22
|
+
* Configuration for pagination controls with page navigation and size selection.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* <Pagination
|
|
27
|
+
* paginationConfig={{
|
|
28
|
+
* initialPageSize: 25,
|
|
29
|
+
* displayType: 'dropdown',
|
|
30
|
+
* pageSizeOptions: PAGE_SIZE_OPTIONS.STANDARD,
|
|
31
|
+
* tableCountFunction: ({ startNum, endNum, totalRowCount }) =>
|
|
32
|
+
* `${startNum}-${endNum} of ${totalRowCount}`
|
|
33
|
+
* }}
|
|
34
|
+
* currentPageIndex={0}
|
|
35
|
+
* pageSize={25}
|
|
36
|
+
* totalRows={100}
|
|
37
|
+
* onPageChange={(index) => console.log('Page:', index)}
|
|
38
|
+
* onPageSizeChange={(size) => console.log('Page size:', size)}
|
|
39
|
+
* />
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
interface TypePaginationConfig {
|
|
43
|
+
/**
|
|
44
|
+
* Initial number of rows per page.
|
|
45
|
+
* @default 10
|
|
46
|
+
*/
|
|
47
|
+
initialPageSize: number;
|
|
48
|
+
/**
|
|
49
|
+
* Function that returns the intl for displaying the table counts underneath a DataTable
|
|
50
|
+
*/
|
|
51
|
+
tableCountFunction: (args: {
|
|
52
|
+
startNum: number;
|
|
53
|
+
endNum: number;
|
|
54
|
+
totalRowCount: number;
|
|
55
|
+
}) => React.ReactNode;
|
|
56
|
+
/**
|
|
57
|
+
* Display mode for page size selector.
|
|
58
|
+
* - 'dropdown': Shows page size selector as a dropdown
|
|
59
|
+
* Only used when pageSizeOptions is provided.
|
|
60
|
+
* @default 'dropdown'
|
|
61
|
+
*/
|
|
62
|
+
displayType?: "dropdown";
|
|
63
|
+
/**
|
|
64
|
+
* Optional array of page size options for the selector.
|
|
65
|
+
* If not provided, page size selection will not be available.
|
|
66
|
+
* Use PAGE_SIZE_OPTIONS constants for consistency.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* pageSizeOptions: PAGE_SIZE_OPTIONS.STANDARD // [10, 25, 50, 100]
|
|
70
|
+
*/
|
|
71
|
+
pageSizeOptions?: TypeAllowedPageSizeOptions;
|
|
72
|
+
/**
|
|
73
|
+
* Size variant for page number display.
|
|
74
|
+
* - 'default': Shows current page ±1-2 pages (more visible pages)
|
|
75
|
+
* - 'mini': Shows only current page (fewer visible pages)
|
|
76
|
+
* @default 'default'
|
|
77
|
+
*/
|
|
78
|
+
size?: "default" | "mini";
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
interface PaginationProps {
|
|
82
|
+
paginationConfig: TypePaginationConfig;
|
|
83
|
+
currentPageIndex: number;
|
|
84
|
+
pageSize: number;
|
|
85
|
+
totalRows: number;
|
|
86
|
+
onPageChange: (pageIndex: number) => void;
|
|
87
|
+
onPageSizeChange: (pageSize: number) => void;
|
|
88
|
+
}
|
|
89
|
+
declare const Pagination: ({ paginationConfig, currentPageIndex, pageSize, totalRows, onPageChange, onPageSizeChange, }: PaginationProps) => react_jsx_runtime.JSX.Element | null;
|
|
90
|
+
|
|
91
|
+
export { PAGE_SIZE_OPTIONS, Pagination, type TypeAllowedPageSizeOptions, type TypePaginationConfig };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
PAGE_SIZE_OPTIONS: () => PAGE_SIZE_OPTIONS,
|
|
34
|
+
Pagination: () => Pagination
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(index_exports);
|
|
37
|
+
|
|
38
|
+
// src/Pagination.tsx
|
|
39
|
+
var React = require("react");
|
|
40
|
+
var import_seeds_react_select = require("@sproutsocial/seeds-react-select");
|
|
41
|
+
var import_seeds_react_icon = require("@sproutsocial/seeds-react-icon");
|
|
42
|
+
|
|
43
|
+
// src/styles.ts
|
|
44
|
+
var import_styled_components = __toESM(require("styled-components"));
|
|
45
|
+
var import_seeds_react_text = require("@sproutsocial/seeds-react-text");
|
|
46
|
+
var StyledPaginationContainer = import_styled_components.default.div`
|
|
47
|
+
${(props) => props.theme.typography[200]}
|
|
48
|
+
display: flex;
|
|
49
|
+
align-items: center;
|
|
50
|
+
gap: ${(props) => props.theme.space[300]};
|
|
51
|
+
margin-top: ${(props) => props.theme.space[400]};
|
|
52
|
+
flex-wrap: wrap;
|
|
53
|
+
`;
|
|
54
|
+
var StyledPaginationControls = import_styled_components.default.div`
|
|
55
|
+
display: flex;
|
|
56
|
+
align-items: center;
|
|
57
|
+
margin-left: auto;
|
|
58
|
+
`;
|
|
59
|
+
var StyledPaginationInfo = (0, import_styled_components.default)(import_seeds_react_text.Text)`
|
|
60
|
+
white-space: nowrap;
|
|
61
|
+
`;
|
|
62
|
+
var StyledPageSizeSelector = import_styled_components.default.div`
|
|
63
|
+
display: flex;
|
|
64
|
+
align-items: center;
|
|
65
|
+
gap: ${(props) => props.theme.space[300]};
|
|
66
|
+
`;
|
|
67
|
+
var StyledPageButtons = import_styled_components.default.div`
|
|
68
|
+
display: inline-flex;
|
|
69
|
+
flex-flow: row wrap;
|
|
70
|
+
background-clip: padding-box;
|
|
71
|
+
border: 1px solid
|
|
72
|
+
${(props) => props.theme.colors.button.secondary.border.base};
|
|
73
|
+
border-radius: ${(props) => props.theme.radii.outer};
|
|
74
|
+
padding: ${(props) => props.theme.space[100]};
|
|
75
|
+
background: transparent;
|
|
76
|
+
`;
|
|
77
|
+
var StyledPaginationButton = import_styled_components.default.button`
|
|
78
|
+
min-width: calc(${(props) => props.theme.space[500]} + 4px);
|
|
79
|
+
min-height: calc(${(props) => props.theme.space[500]} + 2px);
|
|
80
|
+
padding: calc(${(props) => props.theme.space[350]} - 6px);
|
|
81
|
+
line-height: ${(props) => props.theme.space[400]};
|
|
82
|
+
font-weight: ${(props) => props.theme.fontWeights.semibold};
|
|
83
|
+
background-color: ${(props) => props.isSelected ? props.theme.colors.button.secondary.background.active : "transparent"};
|
|
84
|
+
color: ${(props) => props.isSelected ? props.theme.colors.text.inverse : props.theme.colors.text.body};
|
|
85
|
+
border: none;
|
|
86
|
+
border-radius: ${(props) => props.theme.radii.inner};
|
|
87
|
+
cursor: pointer;
|
|
88
|
+
display: inline-flex;
|
|
89
|
+
align-items: center;
|
|
90
|
+
justify-content: center;
|
|
91
|
+
|
|
92
|
+
&:hover:not(:disabled) {
|
|
93
|
+
color: ${(props) => props.isSelected ? props.theme.colors.text.inverse : void 0};
|
|
94
|
+
background-color: ${(props) => props.isSelected ? props.theme.colors.button.secondary.background.active : props.theme.colors.listItem.background.hover};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
&:disabled {
|
|
98
|
+
cursor: default;
|
|
99
|
+
opacity: ${(props) => props.isSelected ? 1 : 0.5};
|
|
100
|
+
}
|
|
101
|
+
`;
|
|
102
|
+
|
|
103
|
+
// src/Pagination.tsx
|
|
104
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
105
|
+
var Pagination = ({
|
|
106
|
+
paginationConfig,
|
|
107
|
+
currentPageIndex,
|
|
108
|
+
pageSize,
|
|
109
|
+
totalRows,
|
|
110
|
+
onPageChange,
|
|
111
|
+
onPageSizeChange
|
|
112
|
+
}) => {
|
|
113
|
+
const { displayType, pageSizeOptions, tableCountFunction } = paginationConfig;
|
|
114
|
+
const totalPages = Math.ceil(totalRows / pageSize);
|
|
115
|
+
const currentPage = currentPageIndex + 1;
|
|
116
|
+
const startRow = totalRows === 0 ? 0 : currentPageIndex * pageSize + 1;
|
|
117
|
+
const endRow = Math.min((currentPageIndex + 1) * pageSize, totalRows);
|
|
118
|
+
const canGoPrevious = currentPageIndex > 0;
|
|
119
|
+
const canGoNext = currentPageIndex < totalPages - 1;
|
|
120
|
+
const handlePrevious = () => {
|
|
121
|
+
if (canGoPrevious) {
|
|
122
|
+
onPageChange(currentPageIndex - 1);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
const handleNext = () => {
|
|
126
|
+
if (canGoNext) {
|
|
127
|
+
onPageChange(currentPageIndex + 1);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
const handlePageSizeChange = (e) => {
|
|
131
|
+
const newPageSize = Number(e.currentTarget.value);
|
|
132
|
+
onPageSizeChange(newPageSize);
|
|
133
|
+
onPageChange(0);
|
|
134
|
+
};
|
|
135
|
+
const getPageNumbers = () => {
|
|
136
|
+
const pages = [];
|
|
137
|
+
const size = paginationConfig.size || "default";
|
|
138
|
+
const NUM_PAGE_LOWER = size === "mini" ? 0 : 1;
|
|
139
|
+
const NUM_PAGE_UPPER = size === "mini" ? 0 : 2;
|
|
140
|
+
if (totalPages <= 5 + NUM_PAGE_LOWER + NUM_PAGE_UPPER) {
|
|
141
|
+
for (let i = 1; i <= totalPages; i++) {
|
|
142
|
+
pages.push(i);
|
|
143
|
+
}
|
|
144
|
+
} else {
|
|
145
|
+
pages.push(1);
|
|
146
|
+
if (currentPage > 3 + NUM_PAGE_LOWER) {
|
|
147
|
+
pages.push("...");
|
|
148
|
+
}
|
|
149
|
+
let start;
|
|
150
|
+
let end;
|
|
151
|
+
if (currentPage <= 3 + NUM_PAGE_LOWER) {
|
|
152
|
+
start = 2;
|
|
153
|
+
end = 3 + NUM_PAGE_LOWER + NUM_PAGE_UPPER;
|
|
154
|
+
} else if (currentPage > totalPages - (3 + NUM_PAGE_UPPER)) {
|
|
155
|
+
start = totalPages - (2 + NUM_PAGE_LOWER + NUM_PAGE_UPPER);
|
|
156
|
+
end = totalPages - 1;
|
|
157
|
+
} else {
|
|
158
|
+
start = currentPage - NUM_PAGE_LOWER;
|
|
159
|
+
end = currentPage + NUM_PAGE_UPPER;
|
|
160
|
+
}
|
|
161
|
+
for (let i = start; i <= end; i++) {
|
|
162
|
+
pages.push(i);
|
|
163
|
+
}
|
|
164
|
+
if (currentPage < totalPages - (2 + NUM_PAGE_UPPER)) {
|
|
165
|
+
pages.push("...");
|
|
166
|
+
}
|
|
167
|
+
pages.push(totalPages);
|
|
168
|
+
}
|
|
169
|
+
return pages;
|
|
170
|
+
};
|
|
171
|
+
const pageNumbers = getPageNumbers();
|
|
172
|
+
if (totalPages <= 1 && !pageSizeOptions) {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(StyledPaginationContainer, { children: [
|
|
176
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(StyledPaginationInfo, { children: tableCountFunction({
|
|
177
|
+
startNum: startRow,
|
|
178
|
+
endNum: endRow,
|
|
179
|
+
totalRowCount: totalRows
|
|
180
|
+
}) }),
|
|
181
|
+
pageSizeOptions && displayType === "dropdown" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StyledPageSizeSelector, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
182
|
+
import_seeds_react_select.Select,
|
|
183
|
+
{
|
|
184
|
+
id: "page-size-select",
|
|
185
|
+
name: "page-size",
|
|
186
|
+
value: String(pageSize),
|
|
187
|
+
onChange: handlePageSizeChange,
|
|
188
|
+
ariaLabel: "Rows per page",
|
|
189
|
+
size: "small",
|
|
190
|
+
children: pageSizeOptions.map((size) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("option", { value: size, children: [
|
|
191
|
+
size,
|
|
192
|
+
" per page"
|
|
193
|
+
] }, size))
|
|
194
|
+
}
|
|
195
|
+
) }),
|
|
196
|
+
totalPages > 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StyledPaginationControls, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(StyledPageButtons, { children: [
|
|
197
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
198
|
+
StyledPaginationButton,
|
|
199
|
+
{
|
|
200
|
+
onClick: handlePrevious,
|
|
201
|
+
disabled: !canGoPrevious,
|
|
202
|
+
"aria-label": "Previous page",
|
|
203
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_seeds_react_icon.Icon, { name: "chevron-left-outline" })
|
|
204
|
+
}
|
|
205
|
+
),
|
|
206
|
+
pageNumbers.map((pageNum, index) => {
|
|
207
|
+
if (pageNum === "...") {
|
|
208
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
209
|
+
StyledPaginationButton,
|
|
210
|
+
{
|
|
211
|
+
disabled: true,
|
|
212
|
+
"aria-label": "More pages",
|
|
213
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_seeds_react_icon.Icon, { name: "ellipsis-horizontal-outline" })
|
|
214
|
+
},
|
|
215
|
+
`ellipsis-${index}`
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
const page = pageNum;
|
|
219
|
+
const isCurrentPage = page === currentPage;
|
|
220
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
221
|
+
StyledPaginationButton,
|
|
222
|
+
{
|
|
223
|
+
onClick: () => onPageChange(page - 1),
|
|
224
|
+
disabled: isCurrentPage,
|
|
225
|
+
"aria-label": `Page ${page}`,
|
|
226
|
+
"aria-current": isCurrentPage ? "page" : void 0,
|
|
227
|
+
isSelected: isCurrentPage,
|
|
228
|
+
children: page
|
|
229
|
+
},
|
|
230
|
+
page
|
|
231
|
+
);
|
|
232
|
+
}),
|
|
233
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
234
|
+
StyledPaginationButton,
|
|
235
|
+
{
|
|
236
|
+
onClick: handleNext,
|
|
237
|
+
disabled: !canGoNext,
|
|
238
|
+
"aria-label": "Next page",
|
|
239
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_seeds_react_icon.Icon, { name: "chevron-right-outline" })
|
|
240
|
+
}
|
|
241
|
+
)
|
|
242
|
+
] }) })
|
|
243
|
+
] });
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
// src/PaginationTypes.ts
|
|
247
|
+
var React2 = require("react");
|
|
248
|
+
var PAGE_SIZE_OPTIONS_STANDARD = [10, 25, 50, 100];
|
|
249
|
+
var PAGE_SIZE_OPTIONS_COMPACT = [5, 10, 20];
|
|
250
|
+
var PAGE_SIZE_OPTIONS_LARGE = [50, 100, 200, 500];
|
|
251
|
+
var PAGE_SIZE_OPTIONS = {
|
|
252
|
+
STANDARD: PAGE_SIZE_OPTIONS_STANDARD,
|
|
253
|
+
COMPACT: PAGE_SIZE_OPTIONS_COMPACT,
|
|
254
|
+
LARGE: PAGE_SIZE_OPTIONS_LARGE
|
|
255
|
+
};
|
|
256
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
257
|
+
0 && (module.exports = {
|
|
258
|
+
PAGE_SIZE_OPTIONS,
|
|
259
|
+
Pagination
|
|
260
|
+
});
|
|
261
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/Pagination.tsx","../src/styles.ts","../src/PaginationTypes.ts"],"sourcesContent":["export { Pagination } from \"./Pagination\";\nexport * from \"./PaginationTypes\";\n","import * as React from \"react\";\nimport { Select } from \"@sproutsocial/seeds-react-select\";\nimport { Icon } from \"@sproutsocial/seeds-react-icon\";\nimport type { TypePaginationConfig } from \"./PaginationTypes\";\nimport {\n StyledPaginationContainer,\n StyledPaginationControls,\n StyledPaginationInfo,\n StyledPageSizeSelector,\n StyledPageButtons,\n StyledPaginationButton,\n} from \"./styles\";\n\ninterface PaginationProps {\n paginationConfig: TypePaginationConfig;\n currentPageIndex: number;\n pageSize: number;\n totalRows: number;\n onPageChange: (pageIndex: number) => void;\n onPageSizeChange: (pageSize: number) => void;\n}\n\nexport const Pagination = ({\n paginationConfig,\n currentPageIndex,\n pageSize,\n totalRows,\n onPageChange,\n onPageSizeChange,\n}: PaginationProps) => {\n const { displayType, pageSizeOptions, tableCountFunction } = paginationConfig;\n\n // Calculate pagination values\n const totalPages = Math.ceil(totalRows / pageSize);\n const currentPage = currentPageIndex + 1; // Convert 0-based to 1-based for display\n const startRow = totalRows === 0 ? 0 : currentPageIndex * pageSize + 1;\n const endRow = Math.min((currentPageIndex + 1) * pageSize, totalRows);\n\n const canGoPrevious = currentPageIndex > 0;\n const canGoNext = currentPageIndex < totalPages - 1;\n\n const handlePrevious = () => {\n if (canGoPrevious) {\n onPageChange(currentPageIndex - 1);\n }\n };\n\n const handleNext = () => {\n if (canGoNext) {\n onPageChange(currentPageIndex + 1);\n }\n };\n\n const handlePageSizeChange = (e: React.SyntheticEvent<HTMLSelectElement>) => {\n const newPageSize = Number(e.currentTarget.value);\n onPageSizeChange(newPageSize);\n // Reset to first page when page size changes\n onPageChange(0);\n };\n\n // Generate page number buttons using web-app-core's algorithm\n const getPageNumbers = () => {\n const pages: (number | string)[] = [];\n const size = paginationConfig.size || \"default\";\n\n // Configuration for how many pages to show around current page\n const NUM_PAGE_LOWER = size === \"mini\" ? 0 : 1;\n const NUM_PAGE_UPPER = size === \"mini\" ? 0 : 2;\n\n // If number of pages is small enough, show all the page tokens without ellipsis\n if (totalPages <= 5 + NUM_PAGE_LOWER + NUM_PAGE_UPPER) {\n for (let i = 1; i <= totalPages; i++) {\n pages.push(i);\n }\n } else {\n // Add first page\n pages.push(1);\n\n // Add ellipsis at the beginning if needed\n if (currentPage > 3 + NUM_PAGE_LOWER) {\n pages.push(\"...\");\n }\n\n // Add pages in the middle\n let start: number;\n let end: number; // inclusive index\n\n // If near beginning - Show number of pages before ending ellipsis\n if (currentPage <= 3 + NUM_PAGE_LOWER) {\n start = 2;\n end = 3 + NUM_PAGE_LOWER + NUM_PAGE_UPPER;\n } else if (currentPage > totalPages - (3 + NUM_PAGE_UPPER)) {\n // If near end - Show number of pages after starting ellipsis\n start = totalPages - (2 + NUM_PAGE_LOWER + NUM_PAGE_UPPER);\n end = totalPages - 1;\n } else {\n // If in the middle - Show number of pages between two ellipses\n start = currentPage - NUM_PAGE_LOWER;\n end = currentPage + NUM_PAGE_UPPER;\n }\n\n for (let i = start; i <= end; i++) {\n pages.push(i);\n }\n\n // Add a final ellipsis if necessary\n if (currentPage < totalPages - (2 + NUM_PAGE_UPPER)) {\n pages.push(\"...\");\n }\n\n // Add the last page number\n pages.push(totalPages);\n }\n\n return pages;\n };\n\n const pageNumbers = getPageNumbers();\n\n if (totalPages <= 1 && !pageSizeOptions) {\n // No pagination needed if only one page and no page size options\n return null;\n }\n\n return (\n <StyledPaginationContainer>\n <StyledPaginationInfo>\n {tableCountFunction({\n startNum: startRow,\n endNum: endRow,\n totalRowCount: totalRows,\n })}\n </StyledPaginationInfo>\n {/* Page size selector */}\n {pageSizeOptions && displayType === \"dropdown\" && (\n <StyledPageSizeSelector>\n <Select\n id=\"page-size-select\"\n name=\"page-size\"\n value={String(pageSize)}\n onChange={handlePageSizeChange}\n ariaLabel=\"Rows per page\"\n size=\"small\"\n >\n {pageSizeOptions.map((size) => (\n <option key={size} value={size}>\n {size} per page\n </option>\n ))}\n </Select>\n </StyledPageSizeSelector>\n )}\n\n {/* TODO: Add inline page size selector for displayType === 'inline' */}\n\n {/* Page navigation controls */}\n {totalPages > 1 && (\n <StyledPaginationControls>\n <StyledPageButtons>\n <StyledPaginationButton\n onClick={handlePrevious}\n disabled={!canGoPrevious}\n aria-label=\"Previous page\"\n >\n <Icon name=\"chevron-left-outline\" />\n </StyledPaginationButton>\n\n {pageNumbers.map((pageNum, index) => {\n if (pageNum === \"...\") {\n return (\n <StyledPaginationButton\n key={`ellipsis-${index}`}\n disabled\n aria-label=\"More pages\"\n >\n <Icon name=\"ellipsis-horizontal-outline\" />\n </StyledPaginationButton>\n );\n }\n\n const page = pageNum as number;\n const isCurrentPage = page === currentPage;\n\n return (\n <StyledPaginationButton\n key={page}\n onClick={() => onPageChange(page - 1)}\n disabled={isCurrentPage}\n aria-label={`Page ${page}`}\n aria-current={isCurrentPage ? \"page\" : undefined}\n isSelected={isCurrentPage}\n >\n {page}\n </StyledPaginationButton>\n );\n })}\n\n <StyledPaginationButton\n onClick={handleNext}\n disabled={!canGoNext}\n aria-label=\"Next page\"\n >\n <Icon name=\"chevron-right-outline\" />\n </StyledPaginationButton>\n </StyledPageButtons>\n </StyledPaginationControls>\n )}\n </StyledPaginationContainer>\n );\n};\n","import styled from \"styled-components\";\nimport { Text } from \"@sproutsocial/seeds-react-text\";\n\n// Pagination Styles\nexport const StyledPaginationContainer = styled.div`\n ${(props) => props.theme.typography[200]}\n display: flex;\n align-items: center;\n gap: ${(props) => props.theme.space[300]};\n margin-top: ${(props) => props.theme.space[400]};\n flex-wrap: wrap;\n`;\n\nexport const StyledPaginationControls = styled.div`\n display: flex;\n align-items: center;\n margin-left: auto;\n`;\n\nexport const StyledPaginationInfo = styled(Text)`\n white-space: nowrap;\n`;\n\nexport const StyledPageSizeSelector = styled.div`\n display: flex;\n align-items: center;\n gap: ${(props) => props.theme.space[300]};\n`;\n\nexport const StyledPageButtons = styled.div`\n display: inline-flex;\n flex-flow: row wrap;\n background-clip: padding-box;\n border: 1px solid\n ${(props) => props.theme.colors.button.secondary.border.base};\n border-radius: ${(props) => props.theme.radii.outer};\n padding: ${(props) => props.theme.space[100]};\n background: transparent;\n`;\n\nexport const StyledPaginationButton = styled.button<{ isSelected?: boolean }>`\n min-width: calc(${(props) => props.theme.space[500]} + 4px);\n min-height: calc(${(props) => props.theme.space[500]} + 2px);\n padding: calc(${(props) => props.theme.space[350]} - 6px);\n line-height: ${(props) => props.theme.space[400]};\n font-weight: ${(props) => props.theme.fontWeights.semibold};\n background-color: ${(props) =>\n props.isSelected\n ? props.theme.colors.button.secondary.background.active\n : \"transparent\"};\n color: ${(props) =>\n props.isSelected\n ? props.theme.colors.text.inverse\n : props.theme.colors.text.body};\n border: none;\n border-radius: ${(props) => props.theme.radii.inner};\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n\n &:hover:not(:disabled) {\n color: ${(props) =>\n props.isSelected ? props.theme.colors.text.inverse : undefined};\n background-color: ${(props) =>\n props.isSelected\n ? props.theme.colors.button.secondary.background.active\n : props.theme.colors.listItem.background.hover};\n }\n\n &:disabled {\n cursor: default;\n opacity: ${(props) => (props.isSelected ? 1 : 0.5)};\n }\n`;\n","import * as React from \"react\";\n\n/**\n * Standard page size option sets for pagination.\n * Export these constants to maintain consistency across tables.\n */\nconst PAGE_SIZE_OPTIONS_STANDARD = [10, 25, 50, 100] as const;\nconst PAGE_SIZE_OPTIONS_COMPACT = [5, 10, 20] as const;\nconst PAGE_SIZE_OPTIONS_LARGE = [50, 100, 200, 500] as const;\n\nexport const PAGE_SIZE_OPTIONS = {\n STANDARD: PAGE_SIZE_OPTIONS_STANDARD,\n COMPACT: PAGE_SIZE_OPTIONS_COMPACT,\n LARGE: PAGE_SIZE_OPTIONS_LARGE,\n};\n\n/**\n * Allowed page size option sets.\n * Use one of the predefined PAGE_SIZE_OPTIONS for consistency.\n */\nexport type TypeAllowedPageSizeOptions =\n | typeof PAGE_SIZE_OPTIONS_STANDARD\n | typeof PAGE_SIZE_OPTIONS_COMPACT\n | typeof PAGE_SIZE_OPTIONS_LARGE;\n\n/**\n * Configuration for pagination controls with page navigation and size selection.\n *\n * @example\n * ```tsx\n * <Pagination\n * paginationConfig={{\n * initialPageSize: 25,\n * displayType: 'dropdown',\n * pageSizeOptions: PAGE_SIZE_OPTIONS.STANDARD,\n * tableCountFunction: ({ startNum, endNum, totalRowCount }) =>\n * `${startNum}-${endNum} of ${totalRowCount}`\n * }}\n * currentPageIndex={0}\n * pageSize={25}\n * totalRows={100}\n * onPageChange={(index) => console.log('Page:', index)}\n * onPageSizeChange={(size) => console.log('Page size:', size)}\n * />\n * ```\n */\nexport interface TypePaginationConfig {\n /**\n * Initial number of rows per page.\n * @default 10\n */\n initialPageSize: number;\n /**\n * Function that returns the intl for displaying the table counts underneath a DataTable\n */\n tableCountFunction: (args: {\n startNum: number;\n endNum: number;\n totalRowCount: number;\n }) => React.ReactNode;\n /**\n * Display mode for page size selector.\n * - 'dropdown': Shows page size selector as a dropdown\n * Only used when pageSizeOptions is provided.\n * @default 'dropdown'\n */\n displayType?: \"dropdown\";\n /**\n * Optional array of page size options for the selector.\n * If not provided, page size selection will not be available.\n * Use PAGE_SIZE_OPTIONS constants for consistency.\n *\n * @example\n * pageSizeOptions: PAGE_SIZE_OPTIONS.STANDARD // [10, 25, 50, 100]\n */\n pageSizeOptions?: TypeAllowedPageSizeOptions;\n /**\n * Size variant for page number display.\n * - 'default': Shows current page ±1-2 pages (more visible pages)\n * - 'mini': Shows only current page (fewer visible pages)\n * @default 'default'\n */\n size?: \"default\" | \"mini\";\n}\n"],"mappings":"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","names":["styled","React"]}
|
package/jest.config.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sproutsocial/seeds-react-pagination",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Seeds React Pagination",
|
|
5
|
+
"author": "Sprout Social, Inc.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"module": "dist/esm/index.js",
|
|
9
|
+
"types": "dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/esm/index.js",
|
|
14
|
+
"require": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsup --dts",
|
|
19
|
+
"build:debug": "tsup --dts --metafile",
|
|
20
|
+
"dev": "tsup --watch --dts",
|
|
21
|
+
"clean": "rm -rf .turbo dist",
|
|
22
|
+
"clean:modules": "rm -rf node_modules",
|
|
23
|
+
"typecheck": "tsc --noEmit",
|
|
24
|
+
"test": "jest",
|
|
25
|
+
"test:watch": "jest --watch --coverage=false"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@sproutsocial/seeds-react-theme": "^3.5.1",
|
|
29
|
+
"@sproutsocial/seeds-react-system-props": "^3.0.2",
|
|
30
|
+
"@sproutsocial/seeds-react-icon": "^2.2.4",
|
|
31
|
+
"@sproutsocial/seeds-react-select": "^1.1.21",
|
|
32
|
+
"@sproutsocial/seeds-react-text": "^1.4.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/react": "^18.0.0",
|
|
36
|
+
"@types/styled-components": "^5.1.26",
|
|
37
|
+
"@sproutsocial/eslint-config-seeds": "*",
|
|
38
|
+
"react": "^18.0.0",
|
|
39
|
+
"styled-components": "^5.2.3",
|
|
40
|
+
"tsup": "^8.3.4",
|
|
41
|
+
"typescript": "^5.6.2",
|
|
42
|
+
"@sproutsocial/seeds-tsconfig": "*",
|
|
43
|
+
"@sproutsocial/seeds-testing": "*",
|
|
44
|
+
"@sproutsocial/seeds-react-testing-library": "*"
|
|
45
|
+
},
|
|
46
|
+
"peerDependencies": {
|
|
47
|
+
"styled-components": "^5.2.3"
|
|
48
|
+
},
|
|
49
|
+
"engines": {
|
|
50
|
+
"node": ">=18"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Select } from "@sproutsocial/seeds-react-select";
|
|
3
|
+
import { Icon } from "@sproutsocial/seeds-react-icon";
|
|
4
|
+
import type { TypePaginationConfig } from "./PaginationTypes";
|
|
5
|
+
import {
|
|
6
|
+
StyledPaginationContainer,
|
|
7
|
+
StyledPaginationControls,
|
|
8
|
+
StyledPaginationInfo,
|
|
9
|
+
StyledPageSizeSelector,
|
|
10
|
+
StyledPageButtons,
|
|
11
|
+
StyledPaginationButton,
|
|
12
|
+
} from "./styles";
|
|
13
|
+
|
|
14
|
+
interface PaginationProps {
|
|
15
|
+
paginationConfig: TypePaginationConfig;
|
|
16
|
+
currentPageIndex: number;
|
|
17
|
+
pageSize: number;
|
|
18
|
+
totalRows: number;
|
|
19
|
+
onPageChange: (pageIndex: number) => void;
|
|
20
|
+
onPageSizeChange: (pageSize: number) => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const Pagination = ({
|
|
24
|
+
paginationConfig,
|
|
25
|
+
currentPageIndex,
|
|
26
|
+
pageSize,
|
|
27
|
+
totalRows,
|
|
28
|
+
onPageChange,
|
|
29
|
+
onPageSizeChange,
|
|
30
|
+
}: PaginationProps) => {
|
|
31
|
+
const { displayType, pageSizeOptions, tableCountFunction } = paginationConfig;
|
|
32
|
+
|
|
33
|
+
// Calculate pagination values
|
|
34
|
+
const totalPages = Math.ceil(totalRows / pageSize);
|
|
35
|
+
const currentPage = currentPageIndex + 1; // Convert 0-based to 1-based for display
|
|
36
|
+
const startRow = totalRows === 0 ? 0 : currentPageIndex * pageSize + 1;
|
|
37
|
+
const endRow = Math.min((currentPageIndex + 1) * pageSize, totalRows);
|
|
38
|
+
|
|
39
|
+
const canGoPrevious = currentPageIndex > 0;
|
|
40
|
+
const canGoNext = currentPageIndex < totalPages - 1;
|
|
41
|
+
|
|
42
|
+
const handlePrevious = () => {
|
|
43
|
+
if (canGoPrevious) {
|
|
44
|
+
onPageChange(currentPageIndex - 1);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const handleNext = () => {
|
|
49
|
+
if (canGoNext) {
|
|
50
|
+
onPageChange(currentPageIndex + 1);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const handlePageSizeChange = (e: React.SyntheticEvent<HTMLSelectElement>) => {
|
|
55
|
+
const newPageSize = Number(e.currentTarget.value);
|
|
56
|
+
onPageSizeChange(newPageSize);
|
|
57
|
+
// Reset to first page when page size changes
|
|
58
|
+
onPageChange(0);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// Generate page number buttons using web-app-core's algorithm
|
|
62
|
+
const getPageNumbers = () => {
|
|
63
|
+
const pages: (number | string)[] = [];
|
|
64
|
+
const size = paginationConfig.size || "default";
|
|
65
|
+
|
|
66
|
+
// Configuration for how many pages to show around current page
|
|
67
|
+
const NUM_PAGE_LOWER = size === "mini" ? 0 : 1;
|
|
68
|
+
const NUM_PAGE_UPPER = size === "mini" ? 0 : 2;
|
|
69
|
+
|
|
70
|
+
// If number of pages is small enough, show all the page tokens without ellipsis
|
|
71
|
+
if (totalPages <= 5 + NUM_PAGE_LOWER + NUM_PAGE_UPPER) {
|
|
72
|
+
for (let i = 1; i <= totalPages; i++) {
|
|
73
|
+
pages.push(i);
|
|
74
|
+
}
|
|
75
|
+
} else {
|
|
76
|
+
// Add first page
|
|
77
|
+
pages.push(1);
|
|
78
|
+
|
|
79
|
+
// Add ellipsis at the beginning if needed
|
|
80
|
+
if (currentPage > 3 + NUM_PAGE_LOWER) {
|
|
81
|
+
pages.push("...");
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Add pages in the middle
|
|
85
|
+
let start: number;
|
|
86
|
+
let end: number; // inclusive index
|
|
87
|
+
|
|
88
|
+
// If near beginning - Show number of pages before ending ellipsis
|
|
89
|
+
if (currentPage <= 3 + NUM_PAGE_LOWER) {
|
|
90
|
+
start = 2;
|
|
91
|
+
end = 3 + NUM_PAGE_LOWER + NUM_PAGE_UPPER;
|
|
92
|
+
} else if (currentPage > totalPages - (3 + NUM_PAGE_UPPER)) {
|
|
93
|
+
// If near end - Show number of pages after starting ellipsis
|
|
94
|
+
start = totalPages - (2 + NUM_PAGE_LOWER + NUM_PAGE_UPPER);
|
|
95
|
+
end = totalPages - 1;
|
|
96
|
+
} else {
|
|
97
|
+
// If in the middle - Show number of pages between two ellipses
|
|
98
|
+
start = currentPage - NUM_PAGE_LOWER;
|
|
99
|
+
end = currentPage + NUM_PAGE_UPPER;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
for (let i = start; i <= end; i++) {
|
|
103
|
+
pages.push(i);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Add a final ellipsis if necessary
|
|
107
|
+
if (currentPage < totalPages - (2 + NUM_PAGE_UPPER)) {
|
|
108
|
+
pages.push("...");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Add the last page number
|
|
112
|
+
pages.push(totalPages);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return pages;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const pageNumbers = getPageNumbers();
|
|
119
|
+
|
|
120
|
+
if (totalPages <= 1 && !pageSizeOptions) {
|
|
121
|
+
// No pagination needed if only one page and no page size options
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return (
|
|
126
|
+
<StyledPaginationContainer>
|
|
127
|
+
<StyledPaginationInfo>
|
|
128
|
+
{tableCountFunction({
|
|
129
|
+
startNum: startRow,
|
|
130
|
+
endNum: endRow,
|
|
131
|
+
totalRowCount: totalRows,
|
|
132
|
+
})}
|
|
133
|
+
</StyledPaginationInfo>
|
|
134
|
+
{/* Page size selector */}
|
|
135
|
+
{pageSizeOptions && displayType === "dropdown" && (
|
|
136
|
+
<StyledPageSizeSelector>
|
|
137
|
+
<Select
|
|
138
|
+
id="page-size-select"
|
|
139
|
+
name="page-size"
|
|
140
|
+
value={String(pageSize)}
|
|
141
|
+
onChange={handlePageSizeChange}
|
|
142
|
+
ariaLabel="Rows per page"
|
|
143
|
+
size="small"
|
|
144
|
+
>
|
|
145
|
+
{pageSizeOptions.map((size) => (
|
|
146
|
+
<option key={size} value={size}>
|
|
147
|
+
{size} per page
|
|
148
|
+
</option>
|
|
149
|
+
))}
|
|
150
|
+
</Select>
|
|
151
|
+
</StyledPageSizeSelector>
|
|
152
|
+
)}
|
|
153
|
+
|
|
154
|
+
{/* TODO: Add inline page size selector for displayType === 'inline' */}
|
|
155
|
+
|
|
156
|
+
{/* Page navigation controls */}
|
|
157
|
+
{totalPages > 1 && (
|
|
158
|
+
<StyledPaginationControls>
|
|
159
|
+
<StyledPageButtons>
|
|
160
|
+
<StyledPaginationButton
|
|
161
|
+
onClick={handlePrevious}
|
|
162
|
+
disabled={!canGoPrevious}
|
|
163
|
+
aria-label="Previous page"
|
|
164
|
+
>
|
|
165
|
+
<Icon name="chevron-left-outline" />
|
|
166
|
+
</StyledPaginationButton>
|
|
167
|
+
|
|
168
|
+
{pageNumbers.map((pageNum, index) => {
|
|
169
|
+
if (pageNum === "...") {
|
|
170
|
+
return (
|
|
171
|
+
<StyledPaginationButton
|
|
172
|
+
key={`ellipsis-${index}`}
|
|
173
|
+
disabled
|
|
174
|
+
aria-label="More pages"
|
|
175
|
+
>
|
|
176
|
+
<Icon name="ellipsis-horizontal-outline" />
|
|
177
|
+
</StyledPaginationButton>
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const page = pageNum as number;
|
|
182
|
+
const isCurrentPage = page === currentPage;
|
|
183
|
+
|
|
184
|
+
return (
|
|
185
|
+
<StyledPaginationButton
|
|
186
|
+
key={page}
|
|
187
|
+
onClick={() => onPageChange(page - 1)}
|
|
188
|
+
disabled={isCurrentPage}
|
|
189
|
+
aria-label={`Page ${page}`}
|
|
190
|
+
aria-current={isCurrentPage ? "page" : undefined}
|
|
191
|
+
isSelected={isCurrentPage}
|
|
192
|
+
>
|
|
193
|
+
{page}
|
|
194
|
+
</StyledPaginationButton>
|
|
195
|
+
);
|
|
196
|
+
})}
|
|
197
|
+
|
|
198
|
+
<StyledPaginationButton
|
|
199
|
+
onClick={handleNext}
|
|
200
|
+
disabled={!canGoNext}
|
|
201
|
+
aria-label="Next page"
|
|
202
|
+
>
|
|
203
|
+
<Icon name="chevron-right-outline" />
|
|
204
|
+
</StyledPaginationButton>
|
|
205
|
+
</StyledPageButtons>
|
|
206
|
+
</StyledPaginationControls>
|
|
207
|
+
)}
|
|
208
|
+
</StyledPaginationContainer>
|
|
209
|
+
);
|
|
210
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Standard page size option sets for pagination.
|
|
5
|
+
* Export these constants to maintain consistency across tables.
|
|
6
|
+
*/
|
|
7
|
+
const PAGE_SIZE_OPTIONS_STANDARD = [10, 25, 50, 100] as const;
|
|
8
|
+
const PAGE_SIZE_OPTIONS_COMPACT = [5, 10, 20] as const;
|
|
9
|
+
const PAGE_SIZE_OPTIONS_LARGE = [50, 100, 200, 500] as const;
|
|
10
|
+
|
|
11
|
+
export const PAGE_SIZE_OPTIONS = {
|
|
12
|
+
STANDARD: PAGE_SIZE_OPTIONS_STANDARD,
|
|
13
|
+
COMPACT: PAGE_SIZE_OPTIONS_COMPACT,
|
|
14
|
+
LARGE: PAGE_SIZE_OPTIONS_LARGE,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Allowed page size option sets.
|
|
19
|
+
* Use one of the predefined PAGE_SIZE_OPTIONS for consistency.
|
|
20
|
+
*/
|
|
21
|
+
export type TypeAllowedPageSizeOptions =
|
|
22
|
+
| typeof PAGE_SIZE_OPTIONS_STANDARD
|
|
23
|
+
| typeof PAGE_SIZE_OPTIONS_COMPACT
|
|
24
|
+
| typeof PAGE_SIZE_OPTIONS_LARGE;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Configuration for pagination controls with page navigation and size selection.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```tsx
|
|
31
|
+
* <Pagination
|
|
32
|
+
* paginationConfig={{
|
|
33
|
+
* initialPageSize: 25,
|
|
34
|
+
* displayType: 'dropdown',
|
|
35
|
+
* pageSizeOptions: PAGE_SIZE_OPTIONS.STANDARD,
|
|
36
|
+
* tableCountFunction: ({ startNum, endNum, totalRowCount }) =>
|
|
37
|
+
* `${startNum}-${endNum} of ${totalRowCount}`
|
|
38
|
+
* }}
|
|
39
|
+
* currentPageIndex={0}
|
|
40
|
+
* pageSize={25}
|
|
41
|
+
* totalRows={100}
|
|
42
|
+
* onPageChange={(index) => console.log('Page:', index)}
|
|
43
|
+
* onPageSizeChange={(size) => console.log('Page size:', size)}
|
|
44
|
+
* />
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export interface TypePaginationConfig {
|
|
48
|
+
/**
|
|
49
|
+
* Initial number of rows per page.
|
|
50
|
+
* @default 10
|
|
51
|
+
*/
|
|
52
|
+
initialPageSize: number;
|
|
53
|
+
/**
|
|
54
|
+
* Function that returns the intl for displaying the table counts underneath a DataTable
|
|
55
|
+
*/
|
|
56
|
+
tableCountFunction: (args: {
|
|
57
|
+
startNum: number;
|
|
58
|
+
endNum: number;
|
|
59
|
+
totalRowCount: number;
|
|
60
|
+
}) => React.ReactNode;
|
|
61
|
+
/**
|
|
62
|
+
* Display mode for page size selector.
|
|
63
|
+
* - 'dropdown': Shows page size selector as a dropdown
|
|
64
|
+
* Only used when pageSizeOptions is provided.
|
|
65
|
+
* @default 'dropdown'
|
|
66
|
+
*/
|
|
67
|
+
displayType?: "dropdown";
|
|
68
|
+
/**
|
|
69
|
+
* Optional array of page size options for the selector.
|
|
70
|
+
* If not provided, page size selection will not be available.
|
|
71
|
+
* Use PAGE_SIZE_OPTIONS constants for consistency.
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* pageSizeOptions: PAGE_SIZE_OPTIONS.STANDARD // [10, 25, 50, 100]
|
|
75
|
+
*/
|
|
76
|
+
pageSizeOptions?: TypeAllowedPageSizeOptions;
|
|
77
|
+
/**
|
|
78
|
+
* Size variant for page number display.
|
|
79
|
+
* - 'default': Shows current page ±1-2 pages (more visible pages)
|
|
80
|
+
* - 'mini': Shows only current page (fewer visible pages)
|
|
81
|
+
* @default 'default'
|
|
82
|
+
*/
|
|
83
|
+
size?: "default" | "mini";
|
|
84
|
+
}
|
package/src/index.ts
ADDED
package/src/styles.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import styled from "styled-components";
|
|
2
|
+
import { Text } from "@sproutsocial/seeds-react-text";
|
|
3
|
+
|
|
4
|
+
// Pagination Styles
|
|
5
|
+
export const StyledPaginationContainer = styled.div`
|
|
6
|
+
${(props) => props.theme.typography[200]}
|
|
7
|
+
display: flex;
|
|
8
|
+
align-items: center;
|
|
9
|
+
gap: ${(props) => props.theme.space[300]};
|
|
10
|
+
margin-top: ${(props) => props.theme.space[400]};
|
|
11
|
+
flex-wrap: wrap;
|
|
12
|
+
`;
|
|
13
|
+
|
|
14
|
+
export const StyledPaginationControls = styled.div`
|
|
15
|
+
display: flex;
|
|
16
|
+
align-items: center;
|
|
17
|
+
margin-left: auto;
|
|
18
|
+
`;
|
|
19
|
+
|
|
20
|
+
export const StyledPaginationInfo = styled(Text)`
|
|
21
|
+
white-space: nowrap;
|
|
22
|
+
`;
|
|
23
|
+
|
|
24
|
+
export const StyledPageSizeSelector = styled.div`
|
|
25
|
+
display: flex;
|
|
26
|
+
align-items: center;
|
|
27
|
+
gap: ${(props) => props.theme.space[300]};
|
|
28
|
+
`;
|
|
29
|
+
|
|
30
|
+
export const StyledPageButtons = styled.div`
|
|
31
|
+
display: inline-flex;
|
|
32
|
+
flex-flow: row wrap;
|
|
33
|
+
background-clip: padding-box;
|
|
34
|
+
border: 1px solid
|
|
35
|
+
${(props) => props.theme.colors.button.secondary.border.base};
|
|
36
|
+
border-radius: ${(props) => props.theme.radii.outer};
|
|
37
|
+
padding: ${(props) => props.theme.space[100]};
|
|
38
|
+
background: transparent;
|
|
39
|
+
`;
|
|
40
|
+
|
|
41
|
+
export const StyledPaginationButton = styled.button<{ isSelected?: boolean }>`
|
|
42
|
+
min-width: calc(${(props) => props.theme.space[500]} + 4px);
|
|
43
|
+
min-height: calc(${(props) => props.theme.space[500]} + 2px);
|
|
44
|
+
padding: calc(${(props) => props.theme.space[350]} - 6px);
|
|
45
|
+
line-height: ${(props) => props.theme.space[400]};
|
|
46
|
+
font-weight: ${(props) => props.theme.fontWeights.semibold};
|
|
47
|
+
background-color: ${(props) =>
|
|
48
|
+
props.isSelected
|
|
49
|
+
? props.theme.colors.button.secondary.background.active
|
|
50
|
+
: "transparent"};
|
|
51
|
+
color: ${(props) =>
|
|
52
|
+
props.isSelected
|
|
53
|
+
? props.theme.colors.text.inverse
|
|
54
|
+
: props.theme.colors.text.body};
|
|
55
|
+
border: none;
|
|
56
|
+
border-radius: ${(props) => props.theme.radii.inner};
|
|
57
|
+
cursor: pointer;
|
|
58
|
+
display: inline-flex;
|
|
59
|
+
align-items: center;
|
|
60
|
+
justify-content: center;
|
|
61
|
+
|
|
62
|
+
&:hover:not(:disabled) {
|
|
63
|
+
color: ${(props) =>
|
|
64
|
+
props.isSelected ? props.theme.colors.text.inverse : undefined};
|
|
65
|
+
background-color: ${(props) =>
|
|
66
|
+
props.isSelected
|
|
67
|
+
? props.theme.colors.button.secondary.background.active
|
|
68
|
+
: props.theme.colors.listItem.background.hover};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
&:disabled {
|
|
72
|
+
cursor: default;
|
|
73
|
+
opacity: ${(props) => (props.isSelected ? 1 : 0.5)};
|
|
74
|
+
}
|
|
75
|
+
`;
|
package/tsconfig.json
ADDED
package/tsup.config.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { defineConfig } from "tsup";
|
|
2
|
+
|
|
3
|
+
export default defineConfig((options) => ({
|
|
4
|
+
entry: ["src/index.ts"],
|
|
5
|
+
format: ["cjs", "esm"],
|
|
6
|
+
clean: true,
|
|
7
|
+
legacyOutput: true,
|
|
8
|
+
dts: options.dts,
|
|
9
|
+
external: ["react"],
|
|
10
|
+
sourcemap: true,
|
|
11
|
+
metafile: options.metafile,
|
|
12
|
+
}));
|