@dt-dds/react-pagination 1.0.0-beta.40 → 1.0.0-beta.42
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/CHANGELOG.md +28 -0
- package/README.md +31 -63
- package/dist/index.d.mts +27 -25
- package/dist/index.d.ts +27 -25
- package/dist/index.js +338 -124
- package/dist/index.mjs +334 -123
- package/package.json +8 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# @dt-ui/react-pagination
|
|
2
2
|
|
|
3
|
+
## 1.0.0-beta.42
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- feat: change theme icons to sharp
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- fix: checkbox label alignment
|
|
12
|
+
- Updated dependencies
|
|
13
|
+
- Updated dependencies
|
|
14
|
+
- @dt-dds/react-icon@1.0.0-beta.62
|
|
15
|
+
- @dt-dds/react-select@1.0.0-beta.94
|
|
16
|
+
- @dt-dds/themes@1.0.0-beta.14
|
|
17
|
+
- @dt-dds/react-core@1.0.0-beta.59
|
|
18
|
+
- @dt-dds/react-tooltip@1.0.0-beta.69
|
|
19
|
+
- @dt-dds/react-typography@1.0.0-beta.50
|
|
20
|
+
|
|
21
|
+
## 1.0.0-beta.41
|
|
22
|
+
|
|
23
|
+
### Minor Changes
|
|
24
|
+
|
|
25
|
+
- feat: refactor pagination
|
|
26
|
+
|
|
27
|
+
### Patch Changes
|
|
28
|
+
|
|
29
|
+
- fix: pagination dependency
|
|
30
|
+
|
|
3
31
|
## 1.0.0-beta.40
|
|
4
32
|
|
|
5
33
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -1,77 +1,45 @@
|
|
|
1
1
|
# Pagination Package
|
|
2
2
|
|
|
3
|
-
The Pagination component
|
|
3
|
+
The Pagination component provides page navigation with optional items-per-page selection and item count information.
|
|
4
4
|
|
|
5
5
|
## Pagination Usage
|
|
6
6
|
|
|
7
7
|
```jsx
|
|
8
|
-
import { Pagination
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
<Pagination
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
/>
|
|
25
|
-
<Pagination.Content
|
|
26
|
-
totalPages={totalPages}
|
|
27
|
-
onClick={() => handleChange(totalPages)}
|
|
8
|
+
import { Pagination } from '@dt-dds/react';
|
|
9
|
+
|
|
10
|
+
const Example = () => {
|
|
11
|
+
const [currentPage, setCurrentPage] = useState(1);
|
|
12
|
+
const [itemsPerPage, setItemsPerPage] = useState(10);
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<Pagination
|
|
16
|
+
currentPage={currentPage}
|
|
17
|
+
totalPages={20}
|
|
18
|
+
totalItems={200}
|
|
19
|
+
itemsPerPage={itemsPerPage}
|
|
20
|
+
onPageChange={setCurrentPage}
|
|
21
|
+
onItemsPerPageChange={setItemsPerPage}
|
|
22
|
+
showItemsPerPage
|
|
23
|
+
showItemsInfo
|
|
28
24
|
/>
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
onClick={() => handleChange(currentPage + 1)}
|
|
32
|
-
/>
|
|
33
|
-
</Pagination>
|
|
34
|
-
);
|
|
25
|
+
);
|
|
26
|
+
};
|
|
35
27
|
```
|
|
36
28
|
|
|
37
29
|
## Properties
|
|
38
30
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
|
42
|
-
|
|
|
43
|
-
| `
|
|
44
|
-
| `
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
|
49
|
-
|
|
|
50
|
-
| `
|
|
51
|
-
| `disabled` | `boolean` | false | Determines the disabled state of the button |
|
|
52
|
-
|
|
53
|
-
### Pagination.NextItem
|
|
54
|
-
|
|
55
|
-
| Property | Type | Default | Description |
|
|
56
|
-
| ---------- | ---------- | ------- | ------------------------------------------------- |
|
|
57
|
-
| `onClick` | `function` | - | The triggered function when clicked on the button |
|
|
58
|
-
| `disabled` | `boolean` | false | Determines the disabled state of the button |
|
|
59
|
-
|
|
60
|
-
### Pagination.Content
|
|
61
|
-
|
|
62
|
-
| Property | Type | Default | Description |
|
|
63
|
-
| ------------ | ---------- | ------- | ------------------------------------------------- |
|
|
64
|
-
| `onClick` | `function` | - | The triggered function when clicked on the button |
|
|
65
|
-
| `totalPages` | `number` | - | It will be the number displayed on the button |
|
|
66
|
-
|
|
67
|
-
### PaginationInput
|
|
68
|
-
|
|
69
|
-
| Property | Type | Default | Description |
|
|
70
|
-
| ----------------- | ---------- | ------- | ---------------------------------------------------- |
|
|
71
|
-
| `totalPages` | `number` | - | Total number of pages |
|
|
72
|
-
| `onChange` | `function` | - | Function to be executed when debounced value changes |
|
|
73
|
-
| `onHandleKeyDown` | `function` | - | Event fired when a key is pressed |
|
|
74
|
-
| `value` | `number` | - | Value to be displayed on the input |
|
|
31
|
+
| Property | Type | Default | Description |
|
|
32
|
+
| ---------------------- | ------------------------- | ------------------- | ------------------------------------------------------ |
|
|
33
|
+
| `currentPage` | `number` | — | Currently selected page (1-based index) |
|
|
34
|
+
| `totalPages` | `number` | — | Total number of available pages |
|
|
35
|
+
| `totalItems` | `number` | — | Total number of items across all pages |
|
|
36
|
+
| `itemsPerPage` | `number` | `10` | Number of items displayed per page |
|
|
37
|
+
| `onPageChange` | `(page: number) => void` | — | Callback fired when the current page changes |
|
|
38
|
+
| `onItemsPerPageChange` | `(items: number) => void` | — | Callback fired when items-per-page value changes |
|
|
39
|
+
| `showItemsPerPage` | `boolean` | `false` | Controls visibility of the items-per-page selector |
|
|
40
|
+
| `showItemsInfo` | `boolean` | `true` | Controls visibility of the items information text |
|
|
41
|
+
| `itemsPerPageOptions` | `number[]` | `[10, 20, 50, 100]` | Available options for items per page |
|
|
42
|
+
| `dataTestId` | `string` | `pagination` | Custom test identifier for the pagination root element |
|
|
75
43
|
|
|
76
44
|
## Stack
|
|
77
45
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,39 +1,41 @@
|
|
|
1
1
|
import { CustomTheme } from '@dt-dds/themes';
|
|
2
2
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
-
import
|
|
3
|
+
import { Code } from '@dt-dds/icons';
|
|
4
4
|
import { BaseProps } from '@dt-dds/react-core';
|
|
5
5
|
|
|
6
|
-
interface
|
|
6
|
+
interface PaginationProps extends BaseProps {
|
|
7
|
+
currentPage: number;
|
|
7
8
|
totalPages: number;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
totalItems?: number;
|
|
10
|
+
itemsPerPage?: number;
|
|
11
|
+
onPageChange: (page: number) => void;
|
|
12
|
+
onItemsPerPageChange?: (itemsPerPage: number) => void;
|
|
13
|
+
showItemsPerPage?: boolean;
|
|
14
|
+
showItemsInfo?: boolean;
|
|
15
|
+
itemsPerPageOptions?: number[];
|
|
13
16
|
}
|
|
14
|
-
interface
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
interface PaginationNavButtonProps {
|
|
18
|
+
ariaLabel: string;
|
|
19
|
+
tooltipLabel: string;
|
|
20
|
+
icon: Code;
|
|
21
|
+
targetPage: number;
|
|
22
|
+
isDisabled: boolean;
|
|
23
|
+
testId: string;
|
|
24
|
+
onClick: (page: number) => void;
|
|
19
25
|
}
|
|
20
|
-
declare const Pagination: {
|
|
21
|
-
({ children, dataTestId }: BaseProps): react_jsx_runtime.JSX.Element;
|
|
22
|
-
Content({ totalPages, onClick }: ContentProps): react_jsx_runtime.JSX.Element;
|
|
23
|
-
NextItem({ onClick, disabled }: ArrowProps): react_jsx_runtime.JSX.Element;
|
|
24
|
-
PreviousItem({ onClick, disabled }: ArrowProps): react_jsx_runtime.JSX.Element;
|
|
25
|
-
};
|
|
26
|
-
declare const PaginationInput: ({ totalPages, onHandleKeyDown, value, onChange, }: PaginationInputProps) => react_jsx_runtime.JSX.Element;
|
|
27
26
|
|
|
28
|
-
declare const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
declare const Pagination: ({ currentPage, totalPages, totalItems, itemsPerPage, onPageChange, onItemsPerPageChange, showItemsPerPage, showItemsInfo, itemsPerPageOptions, dataTestId, }: PaginationProps) => react_jsx_runtime.JSX.Element;
|
|
28
|
+
|
|
29
|
+
declare const ITEMS_PER_PAGE_OPTIONS: number[];
|
|
30
|
+
declare const FIRST_PAGE = 1;
|
|
31
|
+
declare const PAGINATION_BUTTON_SIZES = 24;
|
|
32
|
+
declare const ITEMS_PER_PAGE_WIDTH = 200;
|
|
33
|
+
|
|
34
|
+
declare const getPageNumbers: (currentPage: number, totalPages: number) => (number | "ellipsis")[];
|
|
33
35
|
|
|
34
36
|
declare module '@emotion/react' {
|
|
35
37
|
interface Theme extends CustomTheme {
|
|
36
38
|
}
|
|
37
39
|
}
|
|
38
40
|
|
|
39
|
-
export {
|
|
41
|
+
export { FIRST_PAGE, ITEMS_PER_PAGE_OPTIONS, ITEMS_PER_PAGE_WIDTH, PAGINATION_BUTTON_SIZES, Pagination, type PaginationNavButtonProps, type PaginationProps, getPageNumbers };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,39 +1,41 @@
|
|
|
1
1
|
import { CustomTheme } from '@dt-dds/themes';
|
|
2
2
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
-
import
|
|
3
|
+
import { Code } from '@dt-dds/icons';
|
|
4
4
|
import { BaseProps } from '@dt-dds/react-core';
|
|
5
5
|
|
|
6
|
-
interface
|
|
6
|
+
interface PaginationProps extends BaseProps {
|
|
7
|
+
currentPage: number;
|
|
7
8
|
totalPages: number;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
totalItems?: number;
|
|
10
|
+
itemsPerPage?: number;
|
|
11
|
+
onPageChange: (page: number) => void;
|
|
12
|
+
onItemsPerPageChange?: (itemsPerPage: number) => void;
|
|
13
|
+
showItemsPerPage?: boolean;
|
|
14
|
+
showItemsInfo?: boolean;
|
|
15
|
+
itemsPerPageOptions?: number[];
|
|
13
16
|
}
|
|
14
|
-
interface
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
interface PaginationNavButtonProps {
|
|
18
|
+
ariaLabel: string;
|
|
19
|
+
tooltipLabel: string;
|
|
20
|
+
icon: Code;
|
|
21
|
+
targetPage: number;
|
|
22
|
+
isDisabled: boolean;
|
|
23
|
+
testId: string;
|
|
24
|
+
onClick: (page: number) => void;
|
|
19
25
|
}
|
|
20
|
-
declare const Pagination: {
|
|
21
|
-
({ children, dataTestId }: BaseProps): react_jsx_runtime.JSX.Element;
|
|
22
|
-
Content({ totalPages, onClick }: ContentProps): react_jsx_runtime.JSX.Element;
|
|
23
|
-
NextItem({ onClick, disabled }: ArrowProps): react_jsx_runtime.JSX.Element;
|
|
24
|
-
PreviousItem({ onClick, disabled }: ArrowProps): react_jsx_runtime.JSX.Element;
|
|
25
|
-
};
|
|
26
|
-
declare const PaginationInput: ({ totalPages, onHandleKeyDown, value, onChange, }: PaginationInputProps) => react_jsx_runtime.JSX.Element;
|
|
27
26
|
|
|
28
|
-
declare const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
declare const Pagination: ({ currentPage, totalPages, totalItems, itemsPerPage, onPageChange, onItemsPerPageChange, showItemsPerPage, showItemsInfo, itemsPerPageOptions, dataTestId, }: PaginationProps) => react_jsx_runtime.JSX.Element;
|
|
28
|
+
|
|
29
|
+
declare const ITEMS_PER_PAGE_OPTIONS: number[];
|
|
30
|
+
declare const FIRST_PAGE = 1;
|
|
31
|
+
declare const PAGINATION_BUTTON_SIZES = 24;
|
|
32
|
+
declare const ITEMS_PER_PAGE_WIDTH = 200;
|
|
33
|
+
|
|
34
|
+
declare const getPageNumbers: (currentPage: number, totalPages: number) => (number | "ellipsis")[];
|
|
33
35
|
|
|
34
36
|
declare module '@emotion/react' {
|
|
35
37
|
interface Theme extends CustomTheme {
|
|
36
38
|
}
|
|
37
39
|
}
|
|
38
40
|
|
|
39
|
-
export {
|
|
41
|
+
export { FIRST_PAGE, ITEMS_PER_PAGE_OPTIONS, ITEMS_PER_PAGE_WIDTH, PAGINATION_BUTTON_SIZES, Pagination, type PaginationNavButtonProps, type PaginationProps, getPageNumbers };
|
package/dist/index.js
CHANGED
|
@@ -30,171 +30,385 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
FIRST_PAGE: () => FIRST_PAGE,
|
|
34
|
+
ITEMS_PER_PAGE_OPTIONS: () => ITEMS_PER_PAGE_OPTIONS,
|
|
35
|
+
ITEMS_PER_PAGE_WIDTH: () => ITEMS_PER_PAGE_WIDTH,
|
|
36
|
+
PAGINATION_BUTTON_SIZES: () => PAGINATION_BUTTON_SIZES,
|
|
33
37
|
Pagination: () => Pagination,
|
|
34
|
-
|
|
35
|
-
usePagination: () => usePagination
|
|
38
|
+
getPageNumbers: () => getPageNumbers
|
|
36
39
|
});
|
|
37
40
|
module.exports = __toCommonJS(index_exports);
|
|
38
41
|
|
|
39
42
|
// src/Pagination.tsx
|
|
40
43
|
var import_react = require("react");
|
|
41
|
-
var
|
|
44
|
+
var import_react_select = require("@dt-dds/react-select");
|
|
45
|
+
|
|
46
|
+
// src/components/PaginationNavButton/PaginationNavButton.tsx
|
|
42
47
|
var import_react_icon = require("@dt-dds/react-icon");
|
|
43
|
-
var
|
|
48
|
+
var import_react_tooltip = require("@dt-dds/react-tooltip");
|
|
44
49
|
|
|
45
50
|
// src/Pagination.styled.ts
|
|
51
|
+
var import_is_prop_valid = __toESM(require("@emotion/is-prop-valid"));
|
|
46
52
|
var import_styled = __toESM(require("@emotion/styled"));
|
|
53
|
+
|
|
54
|
+
// src/constants/index.ts
|
|
55
|
+
var ITEMS_PER_PAGE_OPTIONS = [10, 20, 50, 100];
|
|
56
|
+
var FIRST_PAGE = 1;
|
|
57
|
+
var PAGINATION_BUTTON_SIZES = 24;
|
|
58
|
+
var ITEMS_PER_PAGE_WIDTH = 200;
|
|
59
|
+
|
|
60
|
+
// src/Pagination.styled.ts
|
|
47
61
|
var PaginationStyled = import_styled.default.div`
|
|
48
62
|
display: flex;
|
|
63
|
+
flex-direction: column-reverse;
|
|
49
64
|
align-items: center;
|
|
50
|
-
|
|
51
|
-
|
|
65
|
+
width: 100%;
|
|
66
|
+
gap: 12px;
|
|
67
|
+
|
|
68
|
+
@media screen and (min-width: ${({ theme }) => theme.breakpoints.mq3}px) {
|
|
69
|
+
flex-direction: row;
|
|
70
|
+
justify-content: center;
|
|
71
|
+
|
|
72
|
+
&:has(> *:nth-of-type(2)) {
|
|
73
|
+
justify-content: space-between;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
52
76
|
`;
|
|
53
|
-
var
|
|
77
|
+
var InfoWrapperStyled = import_styled.default.div`
|
|
78
|
+
display: flex;
|
|
79
|
+
align-items: center;
|
|
80
|
+
justify-content: center;
|
|
81
|
+
gap: 12px;
|
|
82
|
+
|
|
83
|
+
@media screen and (min-width: ${({ theme }) => theme.breakpoints.mq3}px) {
|
|
84
|
+
width: auto;
|
|
85
|
+
flex-shrink: 0;
|
|
86
|
+
}
|
|
87
|
+
`;
|
|
88
|
+
var NavigationWrapperStyled = import_styled.default.div`
|
|
89
|
+
display: flex;
|
|
90
|
+
align-items: center;
|
|
91
|
+
gap: 4px;
|
|
92
|
+
padding: 10px 0;
|
|
93
|
+
flex-shrink: 0;
|
|
94
|
+
flex-wrap: nowrap;
|
|
95
|
+
`;
|
|
96
|
+
var PaginationButtonStyled = import_styled.default.button`
|
|
54
97
|
${({ theme }) => `
|
|
55
|
-
|
|
56
|
-
|
|
98
|
+
display: flex;
|
|
99
|
+
align-items: center;
|
|
100
|
+
justify-content: center;
|
|
101
|
+
width: ${PAGINATION_BUTTON_SIZES}px;
|
|
102
|
+
height: ${PAGINATION_BUTTON_SIZES}px;
|
|
103
|
+
padding: 0;
|
|
57
104
|
border: none;
|
|
105
|
+
position: relative;
|
|
106
|
+
background-color: transparent;
|
|
107
|
+
color: ${theme.palette.content.default};
|
|
58
108
|
cursor: pointer;
|
|
109
|
+
|
|
110
|
+
&:disabled {
|
|
111
|
+
i {
|
|
112
|
+
color: ${theme.palette.content.light};
|
|
113
|
+
}
|
|
114
|
+
cursor: not-allowed;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
&:hover:not(:disabled) {
|
|
118
|
+
background-color: ${theme.palette.informative.light};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
&:focus-visible {
|
|
122
|
+
outline: 2px solid ${theme.palette.primary.default};
|
|
123
|
+
outline-offset: 1px;
|
|
124
|
+
}
|
|
59
125
|
`}
|
|
60
126
|
`;
|
|
61
|
-
var
|
|
62
|
-
|
|
127
|
+
var PaginationPageButtonStyled = (0, import_styled.default)("button", {
|
|
128
|
+
shouldForwardProp: (prop) => (0, import_is_prop_valid.default)(prop) && !prop.startsWith("$")
|
|
129
|
+
})`
|
|
130
|
+
${({ theme, $isActive }) => `
|
|
131
|
+
${theme.fontStyles.bodyXsBold};
|
|
63
132
|
display: flex;
|
|
133
|
+
align-items: center;
|
|
64
134
|
justify-content: center;
|
|
65
|
-
|
|
135
|
+
width: ${PAGINATION_BUTTON_SIZES}px;
|
|
136
|
+
height: ${PAGINATION_BUTTON_SIZES}px;
|
|
66
137
|
border: none;
|
|
67
|
-
|
|
68
|
-
|
|
138
|
+
transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out;
|
|
139
|
+
background-color: transparent;
|
|
140
|
+
color: ${theme.palette.content.default};
|
|
141
|
+
cursor: pointer;
|
|
142
|
+
|
|
143
|
+
&:focus-visible {
|
|
144
|
+
outline: 2px solid ${theme.palette.primary.default};
|
|
145
|
+
outline-offset: 1px;
|
|
146
|
+
transition: none;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
&:hover {
|
|
150
|
+
background-color: ${theme.palette.informative.light};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
${$isActive && `
|
|
154
|
+
background-color: ${theme.palette.primary.default};
|
|
155
|
+
color: ${theme.palette.content.contrast};
|
|
156
|
+
cursor: default;
|
|
157
|
+
|
|
158
|
+
&:hover {
|
|
159
|
+
background-color: ${theme.palette.primary.default};
|
|
160
|
+
}
|
|
161
|
+
`}
|
|
69
162
|
`}
|
|
70
163
|
`;
|
|
71
|
-
var
|
|
72
|
-
${({ theme
|
|
73
|
-
${theme.fontStyles.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
width:
|
|
78
|
-
height:
|
|
79
|
-
background-color: ${theme.palette.surface.contrast};
|
|
164
|
+
var TruncationTextStyled = import_styled.default.span`
|
|
165
|
+
${({ theme }) => `
|
|
166
|
+
${theme.fontStyles.bodyMdRegular};
|
|
167
|
+
display: flex;
|
|
168
|
+
align-items: center;
|
|
169
|
+
justify-content: center;
|
|
170
|
+
width: ${PAGINATION_BUTTON_SIZES}px;
|
|
171
|
+
height: ${PAGINATION_BUTTON_SIZES}px;
|
|
80
172
|
color: ${theme.palette.content.default};
|
|
81
|
-
|
|
82
|
-
|
|
173
|
+
user-select: none;
|
|
174
|
+
`}
|
|
175
|
+
`;
|
|
176
|
+
var ItemsPerPageWrapperStyled = import_styled.default.div`
|
|
177
|
+
${({ theme }) => `
|
|
178
|
+
label:empty {
|
|
179
|
+
display: none;
|
|
180
|
+
}
|
|
83
181
|
|
|
84
|
-
|
|
85
|
-
|
|
182
|
+
@media screen and (min-width: ${theme.breakpoints.mq3}px) {
|
|
183
|
+
min-width: ${ITEMS_PER_PAGE_WIDTH}px;
|
|
86
184
|
}
|
|
87
185
|
`}
|
|
88
186
|
`;
|
|
187
|
+
var ItemsInfoTextStyled = import_styled.default.span`
|
|
188
|
+
${({ theme }) => `
|
|
189
|
+
${theme.fontStyles.bodySmRegular};
|
|
190
|
+
white-space: nowrap;
|
|
191
|
+
`}
|
|
192
|
+
`;
|
|
89
193
|
|
|
90
|
-
// src/
|
|
194
|
+
// src/components/PaginationNavButton/PaginationNavButton.tsx
|
|
91
195
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
92
|
-
var
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
onClick,
|
|
104
|
-
title: "Go to last page",
|
|
105
|
-
children: totalPages
|
|
106
|
-
}
|
|
107
|
-
)
|
|
108
|
-
] });
|
|
109
|
-
};
|
|
110
|
-
Pagination.NextItem = ({ onClick, disabled }) => {
|
|
111
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
112
|
-
ArrowStyled,
|
|
196
|
+
var PaginationNavButton = ({
|
|
197
|
+
ariaLabel,
|
|
198
|
+
tooltipLabel,
|
|
199
|
+
icon,
|
|
200
|
+
targetPage,
|
|
201
|
+
isDisabled,
|
|
202
|
+
testId,
|
|
203
|
+
onClick
|
|
204
|
+
}) => {
|
|
205
|
+
const button = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
206
|
+
PaginationButtonStyled,
|
|
113
207
|
{
|
|
114
|
-
"
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_icon.Icon, { code:
|
|
208
|
+
"aria-label": ariaLabel,
|
|
209
|
+
"data-testid": testId,
|
|
210
|
+
disabled: isDisabled,
|
|
211
|
+
onClick: () => onClick(targetPage),
|
|
212
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_icon.Icon, { code: icon, size: "small" })
|
|
119
213
|
}
|
|
120
214
|
);
|
|
215
|
+
if (isDisabled) return button;
|
|
216
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_tooltip.Tooltip, { children: [
|
|
217
|
+
button,
|
|
218
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_tooltip.Tooltip.Content, { background: "full", direction: "top", children: tooltipLabel })
|
|
219
|
+
] });
|
|
121
220
|
};
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
|
|
221
|
+
PaginationNavButton.displayName = "PaginationNavButton";
|
|
222
|
+
|
|
223
|
+
// src/utils/getPageNumbers.ts
|
|
224
|
+
var PAGINATION_THRESHOLD = 5;
|
|
225
|
+
var START_BOUNDARY = 3;
|
|
226
|
+
var END_OFFSET = 2;
|
|
227
|
+
var NEIGHBOR_COUNT = 1;
|
|
228
|
+
var getPageNumbers = (currentPage, totalPages) => {
|
|
229
|
+
if (totalPages <= PAGINATION_THRESHOLD) {
|
|
230
|
+
return Array.from({ length: totalPages }, (_, i) => i + 1);
|
|
231
|
+
}
|
|
232
|
+
const showLeftEllipsis = currentPage > START_BOUNDARY;
|
|
233
|
+
const showRightEllipsis = currentPage < totalPages - END_OFFSET;
|
|
234
|
+
if (!showLeftEllipsis && showRightEllipsis) {
|
|
235
|
+
return [1, 2, 3, "ellipsis", totalPages];
|
|
236
|
+
}
|
|
237
|
+
if (showLeftEllipsis && !showRightEllipsis) {
|
|
238
|
+
return [1, "ellipsis", totalPages - 2, totalPages - 1, totalPages];
|
|
239
|
+
}
|
|
240
|
+
return [
|
|
241
|
+
1,
|
|
242
|
+
"ellipsis",
|
|
243
|
+
currentPage - NEIGHBOR_COUNT,
|
|
244
|
+
currentPage,
|
|
245
|
+
currentPage + NEIGHBOR_COUNT,
|
|
246
|
+
"ellipsis",
|
|
247
|
+
totalPages
|
|
248
|
+
];
|
|
133
249
|
};
|
|
134
|
-
|
|
250
|
+
|
|
251
|
+
// src/Pagination.tsx
|
|
252
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
253
|
+
var Pagination = ({
|
|
254
|
+
currentPage,
|
|
135
255
|
totalPages,
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
256
|
+
totalItems,
|
|
257
|
+
itemsPerPage = 10,
|
|
258
|
+
onPageChange,
|
|
259
|
+
onItemsPerPageChange,
|
|
260
|
+
showItemsPerPage = false,
|
|
261
|
+
showItemsInfo = true,
|
|
262
|
+
itemsPerPageOptions = ITEMS_PER_PAGE_OPTIONS,
|
|
263
|
+
dataTestId
|
|
139
264
|
}) => {
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
(0, import_react.useEffect)(() => {
|
|
144
|
-
if (value !== void 0) {
|
|
145
|
-
setInputValue(value);
|
|
146
|
-
}
|
|
147
|
-
}, [value]);
|
|
148
|
-
(0, import_react.useEffect)(() => {
|
|
149
|
-
if (inputValue && inputValue <= totalPages) {
|
|
150
|
-
debouncedFn(() => {
|
|
151
|
-
onChange(inputValue);
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
}, [debouncedFn, inputValue, onChange, totalPages]);
|
|
155
|
-
const handleChange = (event) => {
|
|
156
|
-
const value2 = Number(event.target.value);
|
|
157
|
-
setInputValue(value2);
|
|
158
|
-
if (value2 > totalPages || value2 === 0) {
|
|
159
|
-
setHasError(true);
|
|
160
|
-
} else {
|
|
161
|
-
setHasError(false);
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
165
|
-
InputStyled,
|
|
166
|
-
{
|
|
167
|
-
"data-testid": "pagination-input",
|
|
168
|
-
hasError,
|
|
169
|
-
onChange: handleChange,
|
|
170
|
-
onKeyDown: onHandleKeyDown,
|
|
171
|
-
value: inputValue
|
|
172
|
-
}
|
|
265
|
+
const pageNumbers = (0, import_react.useMemo)(
|
|
266
|
+
() => getPageNumbers(currentPage, totalPages),
|
|
267
|
+
[currentPage, totalPages]
|
|
173
268
|
);
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
currentPage,
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
269
|
+
const isFirstPage = currentPage === FIRST_PAGE;
|
|
270
|
+
const isLastPage = currentPage === totalPages;
|
|
271
|
+
const itemsBeforeCurrentPage = (currentPage - FIRST_PAGE) * itemsPerPage;
|
|
272
|
+
const remainingItems = Math.max(
|
|
273
|
+
0,
|
|
274
|
+
(totalItems != null ? totalItems : 0) - itemsBeforeCurrentPage
|
|
275
|
+
);
|
|
276
|
+
const shownItems = Math.min(itemsPerPage, remainingItems);
|
|
277
|
+
const hasInfoSection = showItemsPerPage || showItemsInfo && totalItems !== void 0;
|
|
278
|
+
const handlePageChange = (0, import_react.useCallback)(
|
|
279
|
+
(page) => {
|
|
280
|
+
const canNavigateToPage = page !== currentPage && page >= FIRST_PAGE && page <= totalPages;
|
|
281
|
+
if (canNavigateToPage) {
|
|
282
|
+
onPageChange(page);
|
|
283
|
+
}
|
|
284
|
+
},
|
|
285
|
+
[currentPage, totalPages, onPageChange]
|
|
286
|
+
);
|
|
287
|
+
const handleItemsPerPageChange = (0, import_react.useCallback)(
|
|
288
|
+
(value) => {
|
|
289
|
+
onItemsPerPageChange == null ? void 0 : onItemsPerPageChange(Number(value));
|
|
290
|
+
},
|
|
291
|
+
[onItemsPerPageChange]
|
|
292
|
+
);
|
|
293
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(PaginationStyled, { "data-testid": dataTestId != null ? dataTestId : "pagination", children: [
|
|
294
|
+
hasInfoSection ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(InfoWrapperStyled, { children: [
|
|
295
|
+
showItemsPerPage ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ItemsPerPageWrapperStyled, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
296
|
+
import_react_select.Select,
|
|
297
|
+
{
|
|
298
|
+
dataTestId: "pagination-items-per-page",
|
|
299
|
+
fill: "contrast",
|
|
300
|
+
isFloatingLabel: false,
|
|
301
|
+
label: "",
|
|
302
|
+
onChange: handleItemsPerPageChange,
|
|
303
|
+
placeholder: "Items per page",
|
|
304
|
+
scale: "compact",
|
|
305
|
+
value: itemsPerPage.toString(),
|
|
306
|
+
children: itemsPerPageOptions.map((option, index) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
307
|
+
import_react_select.Select.Option,
|
|
308
|
+
{
|
|
309
|
+
index,
|
|
310
|
+
value: option.toString(),
|
|
311
|
+
children: [
|
|
312
|
+
option,
|
|
313
|
+
" per page"
|
|
314
|
+
]
|
|
315
|
+
},
|
|
316
|
+
option
|
|
317
|
+
))
|
|
318
|
+
}
|
|
319
|
+
) }) : null,
|
|
320
|
+
showItemsInfo && totalItems !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(ItemsInfoTextStyled, { "data-testid": "pagination-items-info", children: [
|
|
321
|
+
"Showing ",
|
|
322
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: shownItems }),
|
|
323
|
+
" of",
|
|
324
|
+
" ",
|
|
325
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: totalItems }),
|
|
326
|
+
" entries"
|
|
327
|
+
] }) : null
|
|
328
|
+
] }) : null,
|
|
329
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(NavigationWrapperStyled, { children: [
|
|
330
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
331
|
+
PaginationNavButton,
|
|
332
|
+
{
|
|
333
|
+
ariaLabel: "Go to first page",
|
|
334
|
+
icon: "first_page",
|
|
335
|
+
isDisabled: isFirstPage,
|
|
336
|
+
onClick: handlePageChange,
|
|
337
|
+
targetPage: FIRST_PAGE,
|
|
338
|
+
testId: "pagination-first-page",
|
|
339
|
+
tooltipLabel: "First page"
|
|
340
|
+
}
|
|
341
|
+
),
|
|
342
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
343
|
+
PaginationNavButton,
|
|
344
|
+
{
|
|
345
|
+
ariaLabel: "Go to previous page",
|
|
346
|
+
icon: "chevron_left",
|
|
347
|
+
isDisabled: isFirstPage,
|
|
348
|
+
onClick: handlePageChange,
|
|
349
|
+
targetPage: currentPage - 1,
|
|
350
|
+
testId: "pagination-previous-page",
|
|
351
|
+
tooltipLabel: "Previous page"
|
|
352
|
+
}
|
|
353
|
+
),
|
|
354
|
+
pageNumbers.map((page) => {
|
|
355
|
+
if (page === "ellipsis") {
|
|
356
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
357
|
+
TruncationTextStyled,
|
|
358
|
+
{
|
|
359
|
+
"data-testid": "pagination-ellipsis",
|
|
360
|
+
children: "..."
|
|
361
|
+
},
|
|
362
|
+
`ellipsis-${page}`
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
366
|
+
PaginationPageButtonStyled,
|
|
367
|
+
{
|
|
368
|
+
$isActive: page === currentPage,
|
|
369
|
+
"aria-current": page === currentPage ? "page" : void 0,
|
|
370
|
+
"aria-label": `Go to page ${page}`,
|
|
371
|
+
"data-testid": `pagination-page-${page}`,
|
|
372
|
+
onClick: () => handlePageChange(page),
|
|
373
|
+
title: `Go to page ${page}`,
|
|
374
|
+
children: page
|
|
375
|
+
},
|
|
376
|
+
page
|
|
377
|
+
);
|
|
378
|
+
}),
|
|
379
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
380
|
+
PaginationNavButton,
|
|
381
|
+
{
|
|
382
|
+
ariaLabel: "Go to next page",
|
|
383
|
+
icon: "chevron_right",
|
|
384
|
+
isDisabled: isLastPage,
|
|
385
|
+
onClick: handlePageChange,
|
|
386
|
+
targetPage: currentPage + 1,
|
|
387
|
+
testId: "pagination-next-page",
|
|
388
|
+
tooltipLabel: "Next page"
|
|
389
|
+
}
|
|
390
|
+
),
|
|
391
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
392
|
+
PaginationNavButton,
|
|
393
|
+
{
|
|
394
|
+
ariaLabel: "Go to last page",
|
|
395
|
+
icon: "last_page",
|
|
396
|
+
isDisabled: isLastPage,
|
|
397
|
+
onClick: handlePageChange,
|
|
398
|
+
targetPage: totalPages,
|
|
399
|
+
testId: "pagination-last-page",
|
|
400
|
+
tooltipLabel: "Last page"
|
|
401
|
+
}
|
|
402
|
+
)
|
|
403
|
+
] })
|
|
404
|
+
] });
|
|
194
405
|
};
|
|
195
406
|
// Annotate the CommonJS export names for ESM import in node:
|
|
196
407
|
0 && (module.exports = {
|
|
408
|
+
FIRST_PAGE,
|
|
409
|
+
ITEMS_PER_PAGE_OPTIONS,
|
|
410
|
+
ITEMS_PER_PAGE_WIDTH,
|
|
411
|
+
PAGINATION_BUTTON_SIZES,
|
|
197
412
|
Pagination,
|
|
198
|
-
|
|
199
|
-
usePagination
|
|
413
|
+
getPageNumbers
|
|
200
414
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -1,161 +1,372 @@
|
|
|
1
1
|
// src/Pagination.tsx
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { useMemo, useCallback } from "react";
|
|
3
|
+
import { Select } from "@dt-dds/react-select";
|
|
4
|
+
|
|
5
|
+
// src/components/PaginationNavButton/PaginationNavButton.tsx
|
|
4
6
|
import { Icon } from "@dt-dds/react-icon";
|
|
5
|
-
import {
|
|
7
|
+
import { Tooltip } from "@dt-dds/react-tooltip";
|
|
6
8
|
|
|
7
9
|
// src/Pagination.styled.ts
|
|
10
|
+
import isPropValid from "@emotion/is-prop-valid";
|
|
8
11
|
import styled from "@emotion/styled";
|
|
12
|
+
|
|
13
|
+
// src/constants/index.ts
|
|
14
|
+
var ITEMS_PER_PAGE_OPTIONS = [10, 20, 50, 100];
|
|
15
|
+
var FIRST_PAGE = 1;
|
|
16
|
+
var PAGINATION_BUTTON_SIZES = 24;
|
|
17
|
+
var ITEMS_PER_PAGE_WIDTH = 200;
|
|
18
|
+
|
|
19
|
+
// src/Pagination.styled.ts
|
|
9
20
|
var PaginationStyled = styled.div`
|
|
21
|
+
display: flex;
|
|
22
|
+
flex-direction: column-reverse;
|
|
23
|
+
align-items: center;
|
|
24
|
+
width: 100%;
|
|
25
|
+
gap: 12px;
|
|
26
|
+
|
|
27
|
+
@media screen and (min-width: ${({ theme }) => theme.breakpoints.mq3}px) {
|
|
28
|
+
flex-direction: row;
|
|
29
|
+
justify-content: center;
|
|
30
|
+
|
|
31
|
+
&:has(> *:nth-of-type(2)) {
|
|
32
|
+
justify-content: space-between;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
`;
|
|
36
|
+
var InfoWrapperStyled = styled.div`
|
|
10
37
|
display: flex;
|
|
11
38
|
align-items: center;
|
|
12
|
-
|
|
13
|
-
|
|
39
|
+
justify-content: center;
|
|
40
|
+
gap: 12px;
|
|
41
|
+
|
|
42
|
+
@media screen and (min-width: ${({ theme }) => theme.breakpoints.mq3}px) {
|
|
43
|
+
width: auto;
|
|
44
|
+
flex-shrink: 0;
|
|
45
|
+
}
|
|
14
46
|
`;
|
|
15
|
-
var
|
|
47
|
+
var NavigationWrapperStyled = styled.div`
|
|
48
|
+
display: flex;
|
|
49
|
+
align-items: center;
|
|
50
|
+
gap: 4px;
|
|
51
|
+
padding: 10px 0;
|
|
52
|
+
flex-shrink: 0;
|
|
53
|
+
flex-wrap: nowrap;
|
|
54
|
+
`;
|
|
55
|
+
var PaginationButtonStyled = styled.button`
|
|
16
56
|
${({ theme }) => `
|
|
17
|
-
|
|
18
|
-
|
|
57
|
+
display: flex;
|
|
58
|
+
align-items: center;
|
|
59
|
+
justify-content: center;
|
|
60
|
+
width: ${PAGINATION_BUTTON_SIZES}px;
|
|
61
|
+
height: ${PAGINATION_BUTTON_SIZES}px;
|
|
62
|
+
padding: 0;
|
|
19
63
|
border: none;
|
|
64
|
+
position: relative;
|
|
65
|
+
background-color: transparent;
|
|
66
|
+
color: ${theme.palette.content.default};
|
|
20
67
|
cursor: pointer;
|
|
68
|
+
|
|
69
|
+
&:disabled {
|
|
70
|
+
i {
|
|
71
|
+
color: ${theme.palette.content.light};
|
|
72
|
+
}
|
|
73
|
+
cursor: not-allowed;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
&:hover:not(:disabled) {
|
|
77
|
+
background-color: ${theme.palette.informative.light};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
&:focus-visible {
|
|
81
|
+
outline: 2px solid ${theme.palette.primary.default};
|
|
82
|
+
outline-offset: 1px;
|
|
83
|
+
}
|
|
21
84
|
`}
|
|
22
85
|
`;
|
|
23
|
-
var
|
|
24
|
-
|
|
86
|
+
var PaginationPageButtonStyled = styled("button", {
|
|
87
|
+
shouldForwardProp: (prop) => isPropValid(prop) && !prop.startsWith("$")
|
|
88
|
+
})`
|
|
89
|
+
${({ theme, $isActive }) => `
|
|
90
|
+
${theme.fontStyles.bodyXsBold};
|
|
25
91
|
display: flex;
|
|
92
|
+
align-items: center;
|
|
26
93
|
justify-content: center;
|
|
27
|
-
|
|
94
|
+
width: ${PAGINATION_BUTTON_SIZES}px;
|
|
95
|
+
height: ${PAGINATION_BUTTON_SIZES}px;
|
|
28
96
|
border: none;
|
|
29
|
-
|
|
30
|
-
|
|
97
|
+
transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out;
|
|
98
|
+
background-color: transparent;
|
|
99
|
+
color: ${theme.palette.content.default};
|
|
100
|
+
cursor: pointer;
|
|
101
|
+
|
|
102
|
+
&:focus-visible {
|
|
103
|
+
outline: 2px solid ${theme.palette.primary.default};
|
|
104
|
+
outline-offset: 1px;
|
|
105
|
+
transition: none;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
&:hover {
|
|
109
|
+
background-color: ${theme.palette.informative.light};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
${$isActive && `
|
|
113
|
+
background-color: ${theme.palette.primary.default};
|
|
114
|
+
color: ${theme.palette.content.contrast};
|
|
115
|
+
cursor: default;
|
|
116
|
+
|
|
117
|
+
&:hover {
|
|
118
|
+
background-color: ${theme.palette.primary.default};
|
|
119
|
+
}
|
|
120
|
+
`}
|
|
31
121
|
`}
|
|
32
122
|
`;
|
|
33
|
-
var
|
|
34
|
-
${({ theme
|
|
35
|
-
${theme.fontStyles.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
width:
|
|
40
|
-
height:
|
|
41
|
-
background-color: ${theme.palette.surface.contrast};
|
|
123
|
+
var TruncationTextStyled = styled.span`
|
|
124
|
+
${({ theme }) => `
|
|
125
|
+
${theme.fontStyles.bodyMdRegular};
|
|
126
|
+
display: flex;
|
|
127
|
+
align-items: center;
|
|
128
|
+
justify-content: center;
|
|
129
|
+
width: ${PAGINATION_BUTTON_SIZES}px;
|
|
130
|
+
height: ${PAGINATION_BUTTON_SIZES}px;
|
|
42
131
|
color: ${theme.palette.content.default};
|
|
43
|
-
|
|
44
|
-
|
|
132
|
+
user-select: none;
|
|
133
|
+
`}
|
|
134
|
+
`;
|
|
135
|
+
var ItemsPerPageWrapperStyled = styled.div`
|
|
136
|
+
${({ theme }) => `
|
|
137
|
+
label:empty {
|
|
138
|
+
display: none;
|
|
139
|
+
}
|
|
45
140
|
|
|
46
|
-
|
|
47
|
-
|
|
141
|
+
@media screen and (min-width: ${theme.breakpoints.mq3}px) {
|
|
142
|
+
min-width: ${ITEMS_PER_PAGE_WIDTH}px;
|
|
48
143
|
}
|
|
49
144
|
`}
|
|
50
145
|
`;
|
|
146
|
+
var ItemsInfoTextStyled = styled.span`
|
|
147
|
+
${({ theme }) => `
|
|
148
|
+
${theme.fontStyles.bodySmRegular};
|
|
149
|
+
white-space: nowrap;
|
|
150
|
+
`}
|
|
151
|
+
`;
|
|
51
152
|
|
|
52
|
-
// src/
|
|
153
|
+
// src/components/PaginationNavButton/PaginationNavButton.tsx
|
|
53
154
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
54
|
-
var
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
onClick,
|
|
66
|
-
title: "Go to last page",
|
|
67
|
-
children: totalPages
|
|
68
|
-
}
|
|
69
|
-
)
|
|
70
|
-
] });
|
|
71
|
-
};
|
|
72
|
-
Pagination.NextItem = ({ onClick, disabled }) => {
|
|
73
|
-
return /* @__PURE__ */ jsx(
|
|
74
|
-
ArrowStyled,
|
|
155
|
+
var PaginationNavButton = ({
|
|
156
|
+
ariaLabel,
|
|
157
|
+
tooltipLabel,
|
|
158
|
+
icon,
|
|
159
|
+
targetPage,
|
|
160
|
+
isDisabled,
|
|
161
|
+
testId,
|
|
162
|
+
onClick
|
|
163
|
+
}) => {
|
|
164
|
+
const button = /* @__PURE__ */ jsx(
|
|
165
|
+
PaginationButtonStyled,
|
|
75
166
|
{
|
|
76
|
-
"
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
children: /* @__PURE__ */ jsx(Icon, { code:
|
|
167
|
+
"aria-label": ariaLabel,
|
|
168
|
+
"data-testid": testId,
|
|
169
|
+
disabled: isDisabled,
|
|
170
|
+
onClick: () => onClick(targetPage),
|
|
171
|
+
children: /* @__PURE__ */ jsx(Icon, { code: icon, size: "small" })
|
|
81
172
|
}
|
|
82
173
|
);
|
|
174
|
+
if (isDisabled) return button;
|
|
175
|
+
return /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
176
|
+
button,
|
|
177
|
+
/* @__PURE__ */ jsx(Tooltip.Content, { background: "full", direction: "top", children: tooltipLabel })
|
|
178
|
+
] });
|
|
83
179
|
};
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
|
|
180
|
+
PaginationNavButton.displayName = "PaginationNavButton";
|
|
181
|
+
|
|
182
|
+
// src/utils/getPageNumbers.ts
|
|
183
|
+
var PAGINATION_THRESHOLD = 5;
|
|
184
|
+
var START_BOUNDARY = 3;
|
|
185
|
+
var END_OFFSET = 2;
|
|
186
|
+
var NEIGHBOR_COUNT = 1;
|
|
187
|
+
var getPageNumbers = (currentPage, totalPages) => {
|
|
188
|
+
if (totalPages <= PAGINATION_THRESHOLD) {
|
|
189
|
+
return Array.from({ length: totalPages }, (_, i) => i + 1);
|
|
190
|
+
}
|
|
191
|
+
const showLeftEllipsis = currentPage > START_BOUNDARY;
|
|
192
|
+
const showRightEllipsis = currentPage < totalPages - END_OFFSET;
|
|
193
|
+
if (!showLeftEllipsis && showRightEllipsis) {
|
|
194
|
+
return [1, 2, 3, "ellipsis", totalPages];
|
|
195
|
+
}
|
|
196
|
+
if (showLeftEllipsis && !showRightEllipsis) {
|
|
197
|
+
return [1, "ellipsis", totalPages - 2, totalPages - 1, totalPages];
|
|
198
|
+
}
|
|
199
|
+
return [
|
|
200
|
+
1,
|
|
201
|
+
"ellipsis",
|
|
202
|
+
currentPage - NEIGHBOR_COUNT,
|
|
203
|
+
currentPage,
|
|
204
|
+
currentPage + NEIGHBOR_COUNT,
|
|
205
|
+
"ellipsis",
|
|
206
|
+
totalPages
|
|
207
|
+
];
|
|
95
208
|
};
|
|
96
|
-
|
|
209
|
+
|
|
210
|
+
// src/Pagination.tsx
|
|
211
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
212
|
+
var Pagination = ({
|
|
213
|
+
currentPage,
|
|
97
214
|
totalPages,
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
215
|
+
totalItems,
|
|
216
|
+
itemsPerPage = 10,
|
|
217
|
+
onPageChange,
|
|
218
|
+
onItemsPerPageChange,
|
|
219
|
+
showItemsPerPage = false,
|
|
220
|
+
showItemsInfo = true,
|
|
221
|
+
itemsPerPageOptions = ITEMS_PER_PAGE_OPTIONS,
|
|
222
|
+
dataTestId
|
|
101
223
|
}) => {
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
useEffect(() => {
|
|
106
|
-
if (value !== void 0) {
|
|
107
|
-
setInputValue(value);
|
|
108
|
-
}
|
|
109
|
-
}, [value]);
|
|
110
|
-
useEffect(() => {
|
|
111
|
-
if (inputValue && inputValue <= totalPages) {
|
|
112
|
-
debouncedFn(() => {
|
|
113
|
-
onChange(inputValue);
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
}, [debouncedFn, inputValue, onChange, totalPages]);
|
|
117
|
-
const handleChange = (event) => {
|
|
118
|
-
const value2 = Number(event.target.value);
|
|
119
|
-
setInputValue(value2);
|
|
120
|
-
if (value2 > totalPages || value2 === 0) {
|
|
121
|
-
setHasError(true);
|
|
122
|
-
} else {
|
|
123
|
-
setHasError(false);
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
return /* @__PURE__ */ jsx(
|
|
127
|
-
InputStyled,
|
|
128
|
-
{
|
|
129
|
-
"data-testid": "pagination-input",
|
|
130
|
-
hasError,
|
|
131
|
-
onChange: handleChange,
|
|
132
|
-
onKeyDown: onHandleKeyDown,
|
|
133
|
-
value: inputValue
|
|
134
|
-
}
|
|
224
|
+
const pageNumbers = useMemo(
|
|
225
|
+
() => getPageNumbers(currentPage, totalPages),
|
|
226
|
+
[currentPage, totalPages]
|
|
135
227
|
);
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
currentPage,
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
228
|
+
const isFirstPage = currentPage === FIRST_PAGE;
|
|
229
|
+
const isLastPage = currentPage === totalPages;
|
|
230
|
+
const itemsBeforeCurrentPage = (currentPage - FIRST_PAGE) * itemsPerPage;
|
|
231
|
+
const remainingItems = Math.max(
|
|
232
|
+
0,
|
|
233
|
+
(totalItems != null ? totalItems : 0) - itemsBeforeCurrentPage
|
|
234
|
+
);
|
|
235
|
+
const shownItems = Math.min(itemsPerPage, remainingItems);
|
|
236
|
+
const hasInfoSection = showItemsPerPage || showItemsInfo && totalItems !== void 0;
|
|
237
|
+
const handlePageChange = useCallback(
|
|
238
|
+
(page) => {
|
|
239
|
+
const canNavigateToPage = page !== currentPage && page >= FIRST_PAGE && page <= totalPages;
|
|
240
|
+
if (canNavigateToPage) {
|
|
241
|
+
onPageChange(page);
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
[currentPage, totalPages, onPageChange]
|
|
245
|
+
);
|
|
246
|
+
const handleItemsPerPageChange = useCallback(
|
|
247
|
+
(value) => {
|
|
248
|
+
onItemsPerPageChange == null ? void 0 : onItemsPerPageChange(Number(value));
|
|
249
|
+
},
|
|
250
|
+
[onItemsPerPageChange]
|
|
251
|
+
);
|
|
252
|
+
return /* @__PURE__ */ jsxs2(PaginationStyled, { "data-testid": dataTestId != null ? dataTestId : "pagination", children: [
|
|
253
|
+
hasInfoSection ? /* @__PURE__ */ jsxs2(InfoWrapperStyled, { children: [
|
|
254
|
+
showItemsPerPage ? /* @__PURE__ */ jsx2(ItemsPerPageWrapperStyled, { children: /* @__PURE__ */ jsx2(
|
|
255
|
+
Select,
|
|
256
|
+
{
|
|
257
|
+
dataTestId: "pagination-items-per-page",
|
|
258
|
+
fill: "contrast",
|
|
259
|
+
isFloatingLabel: false,
|
|
260
|
+
label: "",
|
|
261
|
+
onChange: handleItemsPerPageChange,
|
|
262
|
+
placeholder: "Items per page",
|
|
263
|
+
scale: "compact",
|
|
264
|
+
value: itemsPerPage.toString(),
|
|
265
|
+
children: itemsPerPageOptions.map((option, index) => /* @__PURE__ */ jsxs2(
|
|
266
|
+
Select.Option,
|
|
267
|
+
{
|
|
268
|
+
index,
|
|
269
|
+
value: option.toString(),
|
|
270
|
+
children: [
|
|
271
|
+
option,
|
|
272
|
+
" per page"
|
|
273
|
+
]
|
|
274
|
+
},
|
|
275
|
+
option
|
|
276
|
+
))
|
|
277
|
+
}
|
|
278
|
+
) }) : null,
|
|
279
|
+
showItemsInfo && totalItems !== void 0 ? /* @__PURE__ */ jsxs2(ItemsInfoTextStyled, { "data-testid": "pagination-items-info", children: [
|
|
280
|
+
"Showing ",
|
|
281
|
+
/* @__PURE__ */ jsx2("strong", { children: shownItems }),
|
|
282
|
+
" of",
|
|
283
|
+
" ",
|
|
284
|
+
/* @__PURE__ */ jsx2("strong", { children: totalItems }),
|
|
285
|
+
" entries"
|
|
286
|
+
] }) : null
|
|
287
|
+
] }) : null,
|
|
288
|
+
/* @__PURE__ */ jsxs2(NavigationWrapperStyled, { children: [
|
|
289
|
+
/* @__PURE__ */ jsx2(
|
|
290
|
+
PaginationNavButton,
|
|
291
|
+
{
|
|
292
|
+
ariaLabel: "Go to first page",
|
|
293
|
+
icon: "first_page",
|
|
294
|
+
isDisabled: isFirstPage,
|
|
295
|
+
onClick: handlePageChange,
|
|
296
|
+
targetPage: FIRST_PAGE,
|
|
297
|
+
testId: "pagination-first-page",
|
|
298
|
+
tooltipLabel: "First page"
|
|
299
|
+
}
|
|
300
|
+
),
|
|
301
|
+
/* @__PURE__ */ jsx2(
|
|
302
|
+
PaginationNavButton,
|
|
303
|
+
{
|
|
304
|
+
ariaLabel: "Go to previous page",
|
|
305
|
+
icon: "chevron_left",
|
|
306
|
+
isDisabled: isFirstPage,
|
|
307
|
+
onClick: handlePageChange,
|
|
308
|
+
targetPage: currentPage - 1,
|
|
309
|
+
testId: "pagination-previous-page",
|
|
310
|
+
tooltipLabel: "Previous page"
|
|
311
|
+
}
|
|
312
|
+
),
|
|
313
|
+
pageNumbers.map((page) => {
|
|
314
|
+
if (page === "ellipsis") {
|
|
315
|
+
return /* @__PURE__ */ jsx2(
|
|
316
|
+
TruncationTextStyled,
|
|
317
|
+
{
|
|
318
|
+
"data-testid": "pagination-ellipsis",
|
|
319
|
+
children: "..."
|
|
320
|
+
},
|
|
321
|
+
`ellipsis-${page}`
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
return /* @__PURE__ */ jsx2(
|
|
325
|
+
PaginationPageButtonStyled,
|
|
326
|
+
{
|
|
327
|
+
$isActive: page === currentPage,
|
|
328
|
+
"aria-current": page === currentPage ? "page" : void 0,
|
|
329
|
+
"aria-label": `Go to page ${page}`,
|
|
330
|
+
"data-testid": `pagination-page-${page}`,
|
|
331
|
+
onClick: () => handlePageChange(page),
|
|
332
|
+
title: `Go to page ${page}`,
|
|
333
|
+
children: page
|
|
334
|
+
},
|
|
335
|
+
page
|
|
336
|
+
);
|
|
337
|
+
}),
|
|
338
|
+
/* @__PURE__ */ jsx2(
|
|
339
|
+
PaginationNavButton,
|
|
340
|
+
{
|
|
341
|
+
ariaLabel: "Go to next page",
|
|
342
|
+
icon: "chevron_right",
|
|
343
|
+
isDisabled: isLastPage,
|
|
344
|
+
onClick: handlePageChange,
|
|
345
|
+
targetPage: currentPage + 1,
|
|
346
|
+
testId: "pagination-next-page",
|
|
347
|
+
tooltipLabel: "Next page"
|
|
348
|
+
}
|
|
349
|
+
),
|
|
350
|
+
/* @__PURE__ */ jsx2(
|
|
351
|
+
PaginationNavButton,
|
|
352
|
+
{
|
|
353
|
+
ariaLabel: "Go to last page",
|
|
354
|
+
icon: "last_page",
|
|
355
|
+
isDisabled: isLastPage,
|
|
356
|
+
onClick: handlePageChange,
|
|
357
|
+
targetPage: totalPages,
|
|
358
|
+
testId: "pagination-last-page",
|
|
359
|
+
tooltipLabel: "Last page"
|
|
360
|
+
}
|
|
361
|
+
)
|
|
362
|
+
] })
|
|
363
|
+
] });
|
|
156
364
|
};
|
|
157
365
|
export {
|
|
366
|
+
FIRST_PAGE,
|
|
367
|
+
ITEMS_PER_PAGE_OPTIONS,
|
|
368
|
+
ITEMS_PER_PAGE_WIDTH,
|
|
369
|
+
PAGINATION_BUTTON_SIZES,
|
|
158
370
|
Pagination,
|
|
159
|
-
|
|
160
|
-
usePagination
|
|
371
|
+
getPageNumbers
|
|
161
372
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dt-dds/react-pagination",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.42",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dist/index.js"
|
|
@@ -20,10 +20,13 @@
|
|
|
20
20
|
"test:update:snapshot": "jest -u"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@dt-dds/react-core": "1.0.0-beta.
|
|
24
|
-
"@dt-dds/react-typography": "1.0.0-beta.
|
|
25
|
-
"@dt-dds/react-icon": "1.0.0-beta.
|
|
26
|
-
"@dt-dds/
|
|
23
|
+
"@dt-dds/react-core": "1.0.0-beta.59",
|
|
24
|
+
"@dt-dds/react-typography": "1.0.0-beta.50",
|
|
25
|
+
"@dt-dds/react-icon": "1.0.0-beta.62",
|
|
26
|
+
"@dt-dds/icons": "1.0.0-beta.6",
|
|
27
|
+
"@dt-dds/react-select": "1.0.0-beta.94",
|
|
28
|
+
"@dt-dds/react-tooltip": "1.0.0-beta.69",
|
|
29
|
+
"@dt-dds/themes": "1.0.0-beta.14"
|
|
27
30
|
},
|
|
28
31
|
"devDependencies": {
|
|
29
32
|
"@babel/core": "^7.22.9",
|