@sproutsocial/seeds-react-pagination 0.1.27 → 0.1.29
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 +11 -11
- package/CHANGELOG.md +24 -0
- package/dist/esm/index.js +239 -66
- package/dist/esm/index.js.map +1 -1
- package/dist/index.d.mts +32 -10
- package/dist/index.d.ts +32 -10
- package/dist/index.js +239 -66
- package/dist/index.js.map +1 -1
- package/dist/pagination.css +99 -0
- package/package.json +9 -8
- package/postcss.config.js +6 -0
- package/src/Pagination.stories.tsx +58 -0
- package/src/Pagination.tsx +17 -210
- package/src/PaginationHybrid.tsx +20 -0
- package/src/PaginationStyled.tsx +128 -0
- package/src/PaginationTailwind.tsx +152 -0
- package/src/PaginationTypes.ts +19 -0
- package/src/__tests__/Pagination.test.tsx +164 -0
- package/src/__tests__/usePaginationModel.test.ts +91 -0
- package/src/css.d.ts +1 -0
- package/src/pagination.css +99 -0
- package/src/usePaginationModel.ts +124 -0
package/dist/index.js
CHANGED
|
@@ -35,74 +35,16 @@ __export(index_exports, {
|
|
|
35
35
|
});
|
|
36
36
|
module.exports = __toCommonJS(index_exports);
|
|
37
37
|
|
|
38
|
-
// src/
|
|
39
|
-
var
|
|
38
|
+
// src/PaginationHybrid.tsx
|
|
39
|
+
var import_seeds_react_system_props = require("@sproutsocial/seeds-react-system-props");
|
|
40
|
+
|
|
41
|
+
// src/PaginationStyled.tsx
|
|
40
42
|
var import_seeds_react_select = require("@sproutsocial/seeds-react-select");
|
|
41
43
|
var import_seeds_react_icon = require("@sproutsocial/seeds-react-icon");
|
|
42
44
|
|
|
43
|
-
// src/
|
|
44
|
-
var
|
|
45
|
-
var
|
|
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 = ({
|
|
45
|
+
// src/usePaginationModel.ts
|
|
46
|
+
var React = require("react");
|
|
47
|
+
var usePaginationModel = ({
|
|
106
48
|
paginationConfig,
|
|
107
49
|
currentPageIndex,
|
|
108
50
|
pageSize,
|
|
@@ -169,10 +111,106 @@ var Pagination = ({
|
|
|
169
111
|
return pages;
|
|
170
112
|
};
|
|
171
113
|
const pageNumbers = getPageNumbers();
|
|
114
|
+
return {
|
|
115
|
+
displayType,
|
|
116
|
+
pageSizeOptions,
|
|
117
|
+
tableCountFunction,
|
|
118
|
+
totalPages,
|
|
119
|
+
currentPage,
|
|
120
|
+
startRow,
|
|
121
|
+
endRow,
|
|
122
|
+
canGoPrevious,
|
|
123
|
+
canGoNext,
|
|
124
|
+
handlePrevious,
|
|
125
|
+
handleNext,
|
|
126
|
+
handlePageSizeChange,
|
|
127
|
+
pageNumbers
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
// src/styles.ts
|
|
132
|
+
var import_styled_components = __toESM(require("styled-components"));
|
|
133
|
+
var import_seeds_react_text = require("@sproutsocial/seeds-react-text");
|
|
134
|
+
var StyledPaginationContainer = import_styled_components.default.div`
|
|
135
|
+
${(props) => props.theme.typography[200]}
|
|
136
|
+
display: flex;
|
|
137
|
+
align-items: center;
|
|
138
|
+
gap: ${(props) => props.theme.space[300]};
|
|
139
|
+
margin-top: ${(props) => props.theme.space[400]};
|
|
140
|
+
flex-wrap: wrap;
|
|
141
|
+
`;
|
|
142
|
+
var StyledPaginationControls = import_styled_components.default.div`
|
|
143
|
+
display: flex;
|
|
144
|
+
align-items: center;
|
|
145
|
+
margin-left: auto;
|
|
146
|
+
`;
|
|
147
|
+
var StyledPaginationInfo = (0, import_styled_components.default)(import_seeds_react_text.Text)`
|
|
148
|
+
white-space: nowrap;
|
|
149
|
+
`;
|
|
150
|
+
var StyledPageSizeSelector = import_styled_components.default.div`
|
|
151
|
+
display: flex;
|
|
152
|
+
align-items: center;
|
|
153
|
+
gap: ${(props) => props.theme.space[300]};
|
|
154
|
+
`;
|
|
155
|
+
var StyledPageButtons = import_styled_components.default.div`
|
|
156
|
+
display: inline-flex;
|
|
157
|
+
flex-flow: row wrap;
|
|
158
|
+
background-clip: padding-box;
|
|
159
|
+
border: 1px solid
|
|
160
|
+
${(props) => props.theme.colors.button.secondary.border.base};
|
|
161
|
+
border-radius: ${(props) => props.theme.radii.outer};
|
|
162
|
+
padding: ${(props) => props.theme.space[100]};
|
|
163
|
+
background: transparent;
|
|
164
|
+
`;
|
|
165
|
+
var StyledPaginationButton = import_styled_components.default.button`
|
|
166
|
+
min-width: calc(${(props) => props.theme.space[500]} + 4px);
|
|
167
|
+
min-height: calc(${(props) => props.theme.space[500]} + 2px);
|
|
168
|
+
padding: calc(${(props) => props.theme.space[350]} - 6px);
|
|
169
|
+
line-height: ${(props) => props.theme.space[400]};
|
|
170
|
+
font-weight: ${(props) => props.theme.fontWeights.semibold};
|
|
171
|
+
background-color: ${(props) => props.isSelected ? props.theme.colors.button.secondary.background.active : "transparent"};
|
|
172
|
+
color: ${(props) => props.isSelected ? props.theme.colors.text.inverse : props.theme.colors.text.body};
|
|
173
|
+
border: none;
|
|
174
|
+
border-radius: ${(props) => props.theme.radii.inner};
|
|
175
|
+
cursor: pointer;
|
|
176
|
+
display: inline-flex;
|
|
177
|
+
align-items: center;
|
|
178
|
+
justify-content: center;
|
|
179
|
+
|
|
180
|
+
&:hover:not(:disabled) {
|
|
181
|
+
color: ${(props) => props.isSelected ? props.theme.colors.text.inverse : void 0};
|
|
182
|
+
background-color: ${(props) => props.isSelected ? props.theme.colors.button.secondary.background.active : props.theme.colors.listItem.background.hover};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
&:disabled {
|
|
186
|
+
cursor: default;
|
|
187
|
+
opacity: ${(props) => props.isSelected ? 1 : 0.5};
|
|
188
|
+
}
|
|
189
|
+
`;
|
|
190
|
+
|
|
191
|
+
// src/PaginationStyled.tsx
|
|
192
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
193
|
+
var PaginationStyled = (props) => {
|
|
194
|
+
const { pageSize, totalRows, onPageChange, className } = props;
|
|
195
|
+
const {
|
|
196
|
+
displayType,
|
|
197
|
+
pageSizeOptions,
|
|
198
|
+
tableCountFunction,
|
|
199
|
+
totalPages,
|
|
200
|
+
currentPage,
|
|
201
|
+
startRow,
|
|
202
|
+
endRow,
|
|
203
|
+
canGoPrevious,
|
|
204
|
+
canGoNext,
|
|
205
|
+
handlePrevious,
|
|
206
|
+
handleNext,
|
|
207
|
+
handlePageSizeChange,
|
|
208
|
+
pageNumbers
|
|
209
|
+
} = usePaginationModel(props);
|
|
172
210
|
if (totalPages <= 1 && !pageSizeOptions) {
|
|
173
211
|
return null;
|
|
174
212
|
}
|
|
175
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(StyledPaginationContainer, { children: [
|
|
213
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(StyledPaginationContainer, { className, children: [
|
|
176
214
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(StyledPaginationInfo, { children: tableCountFunction({
|
|
177
215
|
startNum: startRow,
|
|
178
216
|
endNum: endRow,
|
|
@@ -243,6 +281,141 @@ var Pagination = ({
|
|
|
243
281
|
] });
|
|
244
282
|
};
|
|
245
283
|
|
|
284
|
+
// src/PaginationTailwind.tsx
|
|
285
|
+
var import_seeds_react_select2 = require("@sproutsocial/seeds-react-select");
|
|
286
|
+
var import_seeds_react_icon2 = require("@sproutsocial/seeds-react-icon");
|
|
287
|
+
var import_seeds_react_text2 = require("@sproutsocial/seeds-react-text");
|
|
288
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
289
|
+
function cn(...inputs) {
|
|
290
|
+
const classes = [];
|
|
291
|
+
for (const input of inputs) {
|
|
292
|
+
if (!input) continue;
|
|
293
|
+
if (typeof input === "string") {
|
|
294
|
+
classes.push(input);
|
|
295
|
+
} else if (typeof input === "object") {
|
|
296
|
+
for (const [key, value] of Object.entries(input)) {
|
|
297
|
+
if (value) {
|
|
298
|
+
classes.push(key);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
return classes.join(" ");
|
|
304
|
+
}
|
|
305
|
+
var PaginationTailwind = (props) => {
|
|
306
|
+
const { pageSize, totalRows, onPageChange, className } = props;
|
|
307
|
+
const {
|
|
308
|
+
displayType,
|
|
309
|
+
pageSizeOptions,
|
|
310
|
+
tableCountFunction,
|
|
311
|
+
totalPages,
|
|
312
|
+
currentPage,
|
|
313
|
+
startRow,
|
|
314
|
+
endRow,
|
|
315
|
+
canGoPrevious,
|
|
316
|
+
canGoNext,
|
|
317
|
+
handlePrevious,
|
|
318
|
+
handleNext,
|
|
319
|
+
handlePageSizeChange,
|
|
320
|
+
pageNumbers
|
|
321
|
+
} = usePaginationModel(props);
|
|
322
|
+
if (totalPages <= 1 && !pageSizeOptions) {
|
|
323
|
+
return null;
|
|
324
|
+
}
|
|
325
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: cn("seeds-pagination-container", className), children: [
|
|
326
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_seeds_react_text2.Text, { className: cn("seeds-pagination-info"), children: tableCountFunction({
|
|
327
|
+
startNum: startRow,
|
|
328
|
+
endNum: endRow,
|
|
329
|
+
totalRowCount: totalRows
|
|
330
|
+
}) }),
|
|
331
|
+
pageSizeOptions && displayType === "dropdown" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: cn("seeds-pagination-page-size-selector"), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
332
|
+
import_seeds_react_select2.Select,
|
|
333
|
+
{
|
|
334
|
+
id: "page-size-select",
|
|
335
|
+
name: "page-size",
|
|
336
|
+
value: String(pageSize),
|
|
337
|
+
onChange: handlePageSizeChange,
|
|
338
|
+
ariaLabel: "Rows per page",
|
|
339
|
+
size: "small",
|
|
340
|
+
children: pageSizeOptions.map((size) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("option", { value: size, children: [
|
|
341
|
+
size,
|
|
342
|
+
" per page"
|
|
343
|
+
] }, size))
|
|
344
|
+
}
|
|
345
|
+
) }),
|
|
346
|
+
totalPages > 1 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: cn("seeds-pagination-controls"), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: cn("seeds-pagination-page-buttons"), children: [
|
|
347
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
348
|
+
"button",
|
|
349
|
+
{
|
|
350
|
+
type: "button",
|
|
351
|
+
className: cn("seeds-pagination-button"),
|
|
352
|
+
onClick: handlePrevious,
|
|
353
|
+
disabled: !canGoPrevious,
|
|
354
|
+
"aria-label": "Previous page",
|
|
355
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_seeds_react_icon2.Icon, { name: "chevron-left-outline" })
|
|
356
|
+
}
|
|
357
|
+
),
|
|
358
|
+
pageNumbers.map((pageNum, index) => {
|
|
359
|
+
if (pageNum === "...") {
|
|
360
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
361
|
+
"button",
|
|
362
|
+
{
|
|
363
|
+
type: "button",
|
|
364
|
+
className: cn("seeds-pagination-button"),
|
|
365
|
+
disabled: true,
|
|
366
|
+
"aria-label": "More pages",
|
|
367
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_seeds_react_icon2.Icon, { name: "ellipsis-horizontal-outline" })
|
|
368
|
+
},
|
|
369
|
+
`ellipsis-${index}`
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
const page = pageNum;
|
|
373
|
+
const isCurrentPage = page === currentPage;
|
|
374
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
375
|
+
"button",
|
|
376
|
+
{
|
|
377
|
+
type: "button",
|
|
378
|
+
className: cn("seeds-pagination-button", {
|
|
379
|
+
"seeds-pagination-button-selected": isCurrentPage
|
|
380
|
+
}),
|
|
381
|
+
onClick: () => onPageChange(page - 1),
|
|
382
|
+
disabled: isCurrentPage,
|
|
383
|
+
"aria-label": `Page ${page}`,
|
|
384
|
+
"aria-current": isCurrentPage ? "page" : void 0,
|
|
385
|
+
children: page
|
|
386
|
+
},
|
|
387
|
+
page
|
|
388
|
+
);
|
|
389
|
+
}),
|
|
390
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
391
|
+
"button",
|
|
392
|
+
{
|
|
393
|
+
type: "button",
|
|
394
|
+
className: cn("seeds-pagination-button"),
|
|
395
|
+
onClick: handleNext,
|
|
396
|
+
disabled: !canGoNext,
|
|
397
|
+
"aria-label": "Next page",
|
|
398
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_seeds_react_icon2.Icon, { name: "chevron-right-outline" })
|
|
399
|
+
}
|
|
400
|
+
)
|
|
401
|
+
] }) })
|
|
402
|
+
] });
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
// src/PaginationHybrid.tsx
|
|
406
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
407
|
+
var PaginationHybrid = (props) => {
|
|
408
|
+
if ((0, import_seeds_react_system_props.hasStyledProps)(props)) {
|
|
409
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PaginationStyled, { ...props });
|
|
410
|
+
}
|
|
411
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PaginationTailwind, { ...props });
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
// src/Pagination.tsx
|
|
415
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
416
|
+
var Pagination = (props) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PaginationHybrid, { ...props });
|
|
417
|
+
Pagination.displayName = "Pagination";
|
|
418
|
+
|
|
246
419
|
// src/PaginationTypes.ts
|
|
247
420
|
var React2 = require("react");
|
|
248
421
|
var PAGE_SIZE_OPTIONS_STANDARD = [10, 25, 50, 100];
|
package/dist/index.js.map
CHANGED
|
@@ -1 +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"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/PaginationHybrid.tsx","../src/PaginationStyled.tsx","../src/usePaginationModel.ts","../src/styles.ts","../src/PaginationTailwind.tsx","../src/Pagination.tsx","../src/PaginationTypes.ts"],"sourcesContent":["export { Pagination } from \"./Pagination\";\nexport * from \"./PaginationTypes\";\n","/**\n * Hybrid Pagination component.\n * Routes between the Tailwind implementation (preferred) and the\n * styled-components implementation (for consumers using system props).\n */\n\nimport { hasStyledProps } from \"@sproutsocial/seeds-react-system-props\";\nimport { PaginationStyled } from \"./PaginationStyled\";\nimport { PaginationTailwind } from \"./PaginationTailwind\";\nimport type { PaginationProps } from \"./PaginationTypes\";\n\nexport const PaginationHybrid = (props: PaginationProps) => {\n // Pagination exposes domain props plus an optional className, none of which\n // are styled-system props, so hasStyledProps is effectively always false; the\n // styled-components branch is retained as a pattern-conformance fallback.\n if (hasStyledProps(props)) {\n return <PaginationStyled {...props} />;\n }\n return <PaginationTailwind {...props} />;\n};\n","/**\n * Styled-components implementation of the Pagination component.\n * Composes the styled sub-components from styles.ts. Retained for backward\n * compatibility (system props / styled() extension) via PaginationHybrid.\n */\n\nimport { Select } from \"@sproutsocial/seeds-react-select\";\nimport { Icon } from \"@sproutsocial/seeds-react-icon\";\nimport type { PaginationProps } from \"./PaginationTypes\";\nimport { usePaginationModel } from \"./usePaginationModel\";\nimport {\n StyledPaginationContainer,\n StyledPaginationControls,\n StyledPaginationInfo,\n StyledPageSizeSelector,\n StyledPageButtons,\n StyledPaginationButton,\n} from \"./styles\";\n\nexport const PaginationStyled = (props: PaginationProps) => {\n const { pageSize, totalRows, onPageChange, className } = props;\n const {\n displayType,\n pageSizeOptions,\n tableCountFunction,\n totalPages,\n currentPage,\n startRow,\n endRow,\n canGoPrevious,\n canGoNext,\n handlePrevious,\n handleNext,\n handlePageSizeChange,\n pageNumbers,\n } = usePaginationModel(props);\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 className={className}>\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","/**\n * Presentation-agnostic Pagination model: page math, the page-number token\n * list, and the event handlers consumed identically by PaginationTailwind and\n * PaginationStyled. Contains NO rendering — the JSX and the `return null` guard\n * stay in each component — so the two implementations cannot drift apart. Call\n * it unconditionally at the top of each component, before any early return.\n */\n\nimport * as React from \"react\";\nimport type { PaginationProps } from \"./PaginationTypes\";\n\nexport const usePaginationModel = ({\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 return {\n displayType,\n pageSizeOptions,\n tableCountFunction,\n totalPages,\n currentPage,\n startRow,\n endRow,\n canGoPrevious,\n canGoNext,\n handlePrevious,\n handleNext,\n handlePageSizeChange,\n pageNumbers,\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","/**\n * Tailwind/CSS implementation of the Pagination component.\n * Uses Seeds pagination CSS classes from pagination.css.\n */\n\nimport { Select } from \"@sproutsocial/seeds-react-select\";\nimport { Icon } from \"@sproutsocial/seeds-react-icon\";\nimport { Text } from \"@sproutsocial/seeds-react-text\";\nimport type { PaginationProps } from \"./PaginationTypes\";\nimport { usePaginationModel } from \"./usePaginationModel\";\n\n// Utility for merging class names properly\nfunction cn(\n ...inputs: (string | undefined | null | false | Record<string, boolean>)[]\n): string {\n const classes: string[] = [];\n\n for (const input of inputs) {\n if (!input) continue;\n\n if (typeof input === \"string\") {\n classes.push(input);\n } else if (typeof input === \"object\") {\n for (const [key, value] of Object.entries(input)) {\n if (value) {\n classes.push(key);\n }\n }\n }\n }\n\n return classes.join(\" \");\n}\n\nexport const PaginationTailwind = (props: PaginationProps) => {\n const { pageSize, totalRows, onPageChange, className } = props;\n const {\n displayType,\n pageSizeOptions,\n tableCountFunction,\n totalPages,\n currentPage,\n startRow,\n endRow,\n canGoPrevious,\n canGoNext,\n handlePrevious,\n handleNext,\n handlePageSizeChange,\n pageNumbers,\n } = usePaginationModel(props);\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 <div className={cn(\"seeds-pagination-container\", className)}>\n <Text className={cn(\"seeds-pagination-info\")}>\n {tableCountFunction({\n startNum: startRow,\n endNum: endRow,\n totalRowCount: totalRows,\n })}\n </Text>\n {/* Page size selector */}\n {pageSizeOptions && displayType === \"dropdown\" && (\n <div className={cn(\"seeds-pagination-page-size-selector\")}>\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 </div>\n )}\n\n {/* TODO: Add inline page size selector for displayType === 'inline' */}\n\n {/* Page navigation controls */}\n {totalPages > 1 && (\n <div className={cn(\"seeds-pagination-controls\")}>\n <div className={cn(\"seeds-pagination-page-buttons\")}>\n <button\n type=\"button\"\n className={cn(\"seeds-pagination-button\")}\n onClick={handlePrevious}\n disabled={!canGoPrevious}\n aria-label=\"Previous page\"\n >\n <Icon name=\"chevron-left-outline\" />\n </button>\n\n {pageNumbers.map((pageNum, index) => {\n if (pageNum === \"...\") {\n return (\n <button\n type=\"button\"\n key={`ellipsis-${index}`}\n className={cn(\"seeds-pagination-button\")}\n disabled\n aria-label=\"More pages\"\n >\n <Icon name=\"ellipsis-horizontal-outline\" />\n </button>\n );\n }\n\n const page = pageNum as number;\n const isCurrentPage = page === currentPage;\n\n return (\n <button\n type=\"button\"\n key={page}\n className={cn(\"seeds-pagination-button\", {\n \"seeds-pagination-button-selected\": isCurrentPage,\n })}\n onClick={() => onPageChange(page - 1)}\n disabled={isCurrentPage}\n aria-label={`Page ${page}`}\n aria-current={isCurrentPage ? \"page\" : undefined}\n >\n {page}\n </button>\n );\n })}\n\n <button\n type=\"button\"\n className={cn(\"seeds-pagination-button\")}\n onClick={handleNext}\n disabled={!canGoNext}\n aria-label=\"Next page\"\n >\n <Icon name=\"chevron-right-outline\" />\n </button>\n </div>\n </div>\n )}\n </div>\n );\n};\n","import { PaginationHybrid } from \"./PaginationHybrid\";\nimport type { PaginationProps } from \"./PaginationTypes\";\n\n/**\n * Pagination component. Automatically routes between the Tailwind implementation\n * (preferred) and the styled-components implementation (for consumers using\n * system props or styled() extension).\n *\n * Defined as a self-named component (rather than a bare re-export of\n * PaginationHybrid) so the `react-docgen` props-docs generation in the Publish\n * pipeline has a suitable component definition to analyze.\n */\nexport const Pagination = (props: PaginationProps) => (\n <PaginationHybrid {...props} />\n);\n\nPagination.displayName = \"Pagination\";\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 */\n/**\n * Props for the Pagination component.\n */\nexport interface 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 * Optional class name applied to the root container. Lets consumers layer\n * Tailwind utility overrides (e.g. `mx-200`, `p-300`) on top of the component\n * styles. Because `className` is not a styled-system prop, providing it keeps\n * the component on the Tailwind rendering path.\n */\n className?: string;\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","import_seeds_react_select","import_seeds_react_icon","import_seeds_react_text","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","React"]}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Seeds Pagination component classes
|
|
3
|
+
* Use these instead of writing out individual Tailwind utility classes.
|
|
4
|
+
*
|
|
5
|
+
* Requires @sproutsocial/seeds-react-theme/dist/theme-all.css imported for
|
|
6
|
+
* CSS variable definitions and dark mode support.
|
|
7
|
+
*
|
|
8
|
+
* Rules are wrapped in @layer components so consumer Tailwind utilities (which
|
|
9
|
+
* live in @layer utilities) win the cascade. Without this layer the unlayered
|
|
10
|
+
* component CSS would beat utilities like mx-200 / p-300 / inline-flex and they
|
|
11
|
+
* could not override component styling. Keep every rule inside this single block
|
|
12
|
+
* in source order — the -selected modifier and the :disabled overrides resolve
|
|
13
|
+
* by source order within the same layer.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
@layer components {
|
|
17
|
+
/* StyledPaginationContainer */
|
|
18
|
+
.seeds-pagination-container {
|
|
19
|
+
font-size: var(--font-size-200);
|
|
20
|
+
line-height: var(--line-height-200);
|
|
21
|
+
display: flex;
|
|
22
|
+
align-items: center;
|
|
23
|
+
gap: var(--space-300);
|
|
24
|
+
margin-top: var(--space-400);
|
|
25
|
+
flex-wrap: wrap;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* StyledPaginationInfo (styled(Text)) */
|
|
29
|
+
.seeds-pagination-info {
|
|
30
|
+
white-space: nowrap;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* StyledPageSizeSelector */
|
|
34
|
+
.seeds-pagination-page-size-selector {
|
|
35
|
+
display: flex;
|
|
36
|
+
align-items: center;
|
|
37
|
+
gap: var(--space-300);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/* StyledPaginationControls */
|
|
41
|
+
.seeds-pagination-controls {
|
|
42
|
+
display: flex;
|
|
43
|
+
align-items: center;
|
|
44
|
+
margin-left: auto;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* StyledPageButtons */
|
|
48
|
+
.seeds-pagination-page-buttons {
|
|
49
|
+
display: inline-flex;
|
|
50
|
+
flex-flow: row wrap;
|
|
51
|
+
background-clip: padding-box;
|
|
52
|
+
border: 1px solid var(--color-button-secondary-border-base);
|
|
53
|
+
border-radius: var(--radius-outer);
|
|
54
|
+
padding: var(--space-100);
|
|
55
|
+
background: transparent;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* StyledPaginationButton — base */
|
|
59
|
+
.seeds-pagination-button {
|
|
60
|
+
min-width: calc(var(--space-500) + 4px);
|
|
61
|
+
min-height: calc(var(--space-500) + 2px);
|
|
62
|
+
padding: calc(var(--space-350) - 6px);
|
|
63
|
+
line-height: var(--space-400);
|
|
64
|
+
font-weight: var(--font-weight-semibold);
|
|
65
|
+
background-color: transparent;
|
|
66
|
+
color: var(--color-text-body);
|
|
67
|
+
border: none;
|
|
68
|
+
border-radius: var(--radius-inner);
|
|
69
|
+
cursor: pointer;
|
|
70
|
+
display: inline-flex;
|
|
71
|
+
align-items: center;
|
|
72
|
+
justify-content: center;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* selected modifier MUST follow base (equal specificity — source order wins) */
|
|
76
|
+
.seeds-pagination-button-selected {
|
|
77
|
+
background-color: var(--color-button-secondary-bg-active);
|
|
78
|
+
color: var(--color-text-inverse);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.seeds-pagination-button:hover:not(:disabled) {
|
|
82
|
+
background-color: var(--color-listItem-bg-hover);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.seeds-pagination-button-selected:hover:not(:disabled) {
|
|
86
|
+
background-color: var(--color-button-secondary-bg-active);
|
|
87
|
+
color: var(--color-text-inverse);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.seeds-pagination-button:disabled {
|
|
91
|
+
cursor: default;
|
|
92
|
+
opacity: 0.5;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* current page renders disabled + selected and must stay fully opaque */
|
|
96
|
+
.seeds-pagination-button-selected:disabled {
|
|
97
|
+
opacity: 1;
|
|
98
|
+
}
|
|
99
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sproutsocial/seeds-react-pagination",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.29",
|
|
4
4
|
"description": "Seeds React Pagination",
|
|
5
5
|
"author": "Sprout Social, Inc.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -12,11 +12,12 @@
|
|
|
12
12
|
"types": "./dist/index.d.ts",
|
|
13
13
|
"import": "./dist/esm/index.js",
|
|
14
14
|
"require": "./dist/index.js"
|
|
15
|
-
}
|
|
15
|
+
},
|
|
16
|
+
"./dist/pagination.css": "./dist/pagination.css"
|
|
16
17
|
},
|
|
17
18
|
"scripts": {
|
|
18
|
-
"build": "tsup --dts",
|
|
19
|
-
"build:debug": "tsup --dts --metafile",
|
|
19
|
+
"build": "tsup --dts && cp src/pagination.css dist/pagination.css",
|
|
20
|
+
"build:debug": "tsup --dts --metafile && cp src/pagination.css dist/pagination.css",
|
|
20
21
|
"dev": "tsup --watch --dts",
|
|
21
22
|
"clean": "rm -rf .turbo dist",
|
|
22
23
|
"clean:modules": "rm -rf node_modules",
|
|
@@ -26,10 +27,10 @@
|
|
|
26
27
|
},
|
|
27
28
|
"dependencies": {
|
|
28
29
|
"@sproutsocial/seeds-react-theme": "^4.3.1",
|
|
29
|
-
"@sproutsocial/seeds-react-system-props": "^3.1.
|
|
30
|
-
"@sproutsocial/seeds-react-icon": "^2.4.
|
|
31
|
-
"@sproutsocial/seeds-react-select": "^1.1.
|
|
32
|
-
"@sproutsocial/seeds-react-text": "^1.5.
|
|
30
|
+
"@sproutsocial/seeds-react-system-props": "^3.1.4",
|
|
31
|
+
"@sproutsocial/seeds-react-icon": "^2.4.8",
|
|
32
|
+
"@sproutsocial/seeds-react-select": "^1.1.49",
|
|
33
|
+
"@sproutsocial/seeds-react-text": "^1.5.3"
|
|
33
34
|
},
|
|
34
35
|
"devDependencies": {
|
|
35
36
|
"@types/react": "^18.0.0",
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Empty PostCSS config — prevents tsup from picking up the root postcss.config.js
|
|
2
|
+
// (which runs Tailwind CSS and would fail without a tailwind.config.js in scope).
|
|
3
|
+
// pagination.css uses plain CSS custom properties and needs no PostCSS processing.
|
|
4
|
+
export default {
|
|
5
|
+
plugins: {},
|
|
6
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { Pagination } from "./Pagination";
|
|
3
|
+
import { PAGE_SIZE_OPTIONS } from "./PaginationTypes";
|
|
4
|
+
|
|
5
|
+
const meta = {
|
|
6
|
+
title: "Components/Pagination",
|
|
7
|
+
component: Pagination,
|
|
8
|
+
} satisfies Meta<typeof Pagination>;
|
|
9
|
+
|
|
10
|
+
export default meta;
|
|
11
|
+
type Story = StoryObj<typeof Pagination>;
|
|
12
|
+
|
|
13
|
+
const paginationConfig = {
|
|
14
|
+
initialPageSize: 10,
|
|
15
|
+
tableCountFunction: ({
|
|
16
|
+
startNum,
|
|
17
|
+
endNum,
|
|
18
|
+
totalRowCount,
|
|
19
|
+
}: {
|
|
20
|
+
startNum: number;
|
|
21
|
+
endNum: number;
|
|
22
|
+
totalRowCount: number;
|
|
23
|
+
}) => `${startNum}-${endNum} of ${totalRowCount}`,
|
|
24
|
+
pageSizeOptions: PAGE_SIZE_OPTIONS.STANDARD,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const defaultStory: Story = {
|
|
28
|
+
name: "Default",
|
|
29
|
+
args: {
|
|
30
|
+
paginationConfig,
|
|
31
|
+
currentPageIndex: 0,
|
|
32
|
+
pageSize: 10,
|
|
33
|
+
totalRows: 100,
|
|
34
|
+
onPageChange: () => {},
|
|
35
|
+
onPageSizeChange: () => {},
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Demonstrates that consumer Tailwind utility classes override the component's
|
|
41
|
+
* own styling. `className="mx-200 p-300 inline-flex"` is forwarded to the root
|
|
42
|
+
* container and wins the cascade only because the component CSS is wrapped in
|
|
43
|
+
* `@layer components` (consumer utilities live in `@layer utilities`, which has
|
|
44
|
+
* higher priority). Because `className` is not a styled-system prop, the
|
|
45
|
+
* component stays on the Tailwind rendering path.
|
|
46
|
+
*/
|
|
47
|
+
export const tailwindOverride: Story = {
|
|
48
|
+
name: "🚀 Tailwind class override (NEW!)",
|
|
49
|
+
args: {
|
|
50
|
+
paginationConfig,
|
|
51
|
+
currentPageIndex: 0,
|
|
52
|
+
pageSize: 10,
|
|
53
|
+
totalRows: 100,
|
|
54
|
+
className: "mx-200 p-300 inline-flex",
|
|
55
|
+
onPageChange: () => {},
|
|
56
|
+
onPageSizeChange: () => {},
|
|
57
|
+
},
|
|
58
|
+
};
|