@ssa-ui-kit/core 1.0.17 → 1.0.18
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/dist/components/Pagination/Pagination.d.ts +1 -1
- package/dist/components/Pagination/PaginationContext.d.ts +1 -1
- package/dist/components/Pagination/components/RowsPerPageDropdown/RowsPerPageDropdown.d.ts +2 -0
- package/dist/components/Pagination/components/RowsPerPageDropdown/index.d.ts +2 -0
- package/dist/components/Pagination/components/RowsPerPageDropdown/types.d.ts +9 -0
- package/dist/components/Pagination/components/index.d.ts +1 -0
- package/dist/components/Pagination/constants.d.ts +6 -0
- package/dist/components/Pagination/styles.d.ts +7 -0
- package/dist/components/Pagination/types.d.ts +10 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Pagination/Pagination.spec.tsx +2 -1
- package/src/components/Pagination/Pagination.stories.tsx +16 -2
- package/src/components/Pagination/Pagination.tsx +85 -43
- package/src/components/Pagination/PaginationContext.tsx +4 -1
- package/src/components/Pagination/components/RowsPerPageDropdown/RowsPerPageDropdown.tsx +70 -0
- package/src/components/Pagination/components/RowsPerPageDropdown/index.ts +2 -0
- package/src/components/Pagination/components/RowsPerPageDropdown/types.ts +7 -0
- package/src/components/Pagination/components/index.ts +1 -0
- package/src/components/Pagination/constants.ts +18 -0
- package/src/components/Pagination/styles.tsx +25 -0
- package/src/components/Pagination/types.ts +10 -0
- package/tsbuildcache +1 -1
package/package.json
CHANGED
|
@@ -43,6 +43,7 @@ const testCases = {
|
|
|
43
43
|
|
|
44
44
|
const checkPages = (range: number[], selected?: number) => {
|
|
45
45
|
const navigation = screen.getByRole('navigation');
|
|
46
|
+
const buttonsWrapper = navigation.querySelector('div') as HTMLDivElement;
|
|
46
47
|
const withinNavigation = within(navigation);
|
|
47
48
|
|
|
48
49
|
const prevPageBtn = within(
|
|
@@ -54,7 +55,7 @@ const checkPages = (range: number[], selected?: number) => {
|
|
|
54
55
|
);
|
|
55
56
|
nextPageBtn.getByTitle('Carrot right');
|
|
56
57
|
|
|
57
|
-
const buttonsAndBreaks = Array.from(
|
|
58
|
+
const buttonsAndBreaks = Array.from(buttonsWrapper.children).slice(1, -1);
|
|
58
59
|
|
|
59
60
|
for (let i = 0; i < range.length; ++i) {
|
|
60
61
|
const page = range[i];
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Meta } from '@storybook/react';
|
|
2
|
+
import { StoryAnnotations } from '@storybook/types';
|
|
2
3
|
import { Pagination, PaginationContextProvider } from './index';
|
|
3
4
|
|
|
4
5
|
export default {
|
|
@@ -6,9 +7,8 @@ export default {
|
|
|
6
7
|
component: Pagination,
|
|
7
8
|
decorators: [
|
|
8
9
|
(Story, { parameters, args }) => {
|
|
9
|
-
const { selectedPage } = parameters;
|
|
10
10
|
return (
|
|
11
|
-
<PaginationContextProvider
|
|
11
|
+
<PaginationContextProvider {...parameters}>
|
|
12
12
|
{Story(args)}
|
|
13
13
|
</PaginationContextProvider>
|
|
14
14
|
);
|
|
@@ -58,3 +58,17 @@ export const Disabled = {
|
|
|
58
58
|
selectedPage: 5,
|
|
59
59
|
},
|
|
60
60
|
};
|
|
61
|
+
|
|
62
|
+
export const WithManualPageSettingAndPerPage: StoryAnnotations = {
|
|
63
|
+
args: {
|
|
64
|
+
pagesCount: 10,
|
|
65
|
+
isPageSettingVisible: true,
|
|
66
|
+
isRowPerPageVisible: true,
|
|
67
|
+
},
|
|
68
|
+
parameters: {
|
|
69
|
+
selectedPage: 1,
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
WithManualPageSettingAndPerPage.storyName =
|
|
74
|
+
'With records per page and page number setting';
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { KeyboardEvent, useState } from 'react';
|
|
2
2
|
import { usePaginationRange } from '@ssa-ui-kit/hooks';
|
|
3
|
-
|
|
3
|
+
import { InputProps } from '@components/Input/types';
|
|
4
|
+
import Wrapper from '@components/Wrapper';
|
|
4
5
|
import { ArrowButton } from './ArrowButton';
|
|
5
6
|
import { PaginationButtons } from './PaginationButtons';
|
|
6
|
-
|
|
7
7
|
import { PaginationProps } from './types';
|
|
8
8
|
import { usePaginationContext } from './PaginationContext';
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
import { RowsPerPageDropdown } from './components';
|
|
10
|
+
import * as S from './styles';
|
|
11
11
|
|
|
12
12
|
const Pagination = ({
|
|
13
13
|
pagesCount,
|
|
@@ -15,51 +15,93 @@ const Pagination = ({
|
|
|
15
15
|
as,
|
|
16
16
|
ariaLabel,
|
|
17
17
|
isDisabled,
|
|
18
|
+
pageNumberPlaceholder = 'Page №',
|
|
19
|
+
isPageSettingVisible = false,
|
|
20
|
+
isRowPerPageVisible = false,
|
|
21
|
+
rowPerPageProps,
|
|
22
|
+
manualPageNumberProps,
|
|
18
23
|
}: PaginationProps) => {
|
|
19
24
|
const { page, setPage } = usePaginationContext();
|
|
20
25
|
const range = usePaginationRange({ pagesCount, selectedPage: page });
|
|
26
|
+
const [inputStatus, setInputStatus] = useState<InputProps['status']>('basic');
|
|
27
|
+
const handlePageNumberChange = (event: KeyboardEvent<HTMLInputElement>) => {
|
|
28
|
+
if (event.code === 'Enter') {
|
|
29
|
+
const { value: inputValue } = event.currentTarget;
|
|
30
|
+
const newPageNumber = Number(inputValue);
|
|
31
|
+
if (newPageNumber > 0 && newPageNumber <= pagesCount) {
|
|
32
|
+
setInputStatus('basic');
|
|
33
|
+
setPage(Number(inputValue));
|
|
34
|
+
} else {
|
|
35
|
+
setInputStatus('error');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
};
|
|
21
39
|
|
|
22
40
|
return (
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
41
|
+
<S.PaginationNav
|
|
42
|
+
className={className}
|
|
43
|
+
as={as}
|
|
44
|
+
aria-label={ariaLabel || 'Pagination'}>
|
|
45
|
+
{isRowPerPageVisible && <RowsPerPageDropdown {...rowPerPageProps} />}
|
|
46
|
+
{isPageSettingVisible && (
|
|
47
|
+
<Wrapper css={{ width: 'auto', marginRight: 32 }}>
|
|
48
|
+
<S.PageNumberInput
|
|
49
|
+
name="page-number"
|
|
50
|
+
placeholder={pageNumberPlaceholder}
|
|
51
|
+
onKeyUp={handlePageNumberChange}
|
|
52
|
+
status={inputStatus}
|
|
53
|
+
type="number"
|
|
54
|
+
inputProps={{
|
|
55
|
+
autoComplete: 'off',
|
|
56
|
+
}}
|
|
57
|
+
{...manualPageNumberProps}
|
|
58
|
+
/>
|
|
59
|
+
<span css={{ textWrap: 'nowrap', fontSize: 14 }}>
|
|
60
|
+
{page || 0} / {pagesCount}
|
|
61
|
+
</span>
|
|
62
|
+
</Wrapper>
|
|
63
|
+
)}
|
|
64
|
+
<Wrapper>
|
|
65
|
+
<ArrowButton
|
|
66
|
+
direction="left"
|
|
67
|
+
onClick={() => {
|
|
68
|
+
if (page) {
|
|
69
|
+
setPage(page - 1);
|
|
70
|
+
}
|
|
71
|
+
}}
|
|
72
|
+
isDisabled={
|
|
73
|
+
isDisabled ||
|
|
74
|
+
pagesCount == null ||
|
|
75
|
+
pagesCount <= 1 ||
|
|
76
|
+
page == null ||
|
|
77
|
+
page === 1
|
|
29
78
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
79
|
+
css={{ marginRight: '12px' }}
|
|
80
|
+
/>
|
|
81
|
+
<PaginationButtons
|
|
82
|
+
range={range}
|
|
83
|
+
selectedPage={page}
|
|
84
|
+
onClick={setPage}
|
|
85
|
+
isDisabled={isDisabled}
|
|
86
|
+
/>
|
|
87
|
+
<ArrowButton
|
|
88
|
+
direction="right"
|
|
89
|
+
onClick={() => {
|
|
90
|
+
if (page) {
|
|
91
|
+
setPage(page + 1);
|
|
92
|
+
}
|
|
93
|
+
}}
|
|
94
|
+
isDisabled={
|
|
95
|
+
isDisabled ||
|
|
96
|
+
pagesCount == null ||
|
|
97
|
+
pagesCount <= 1 ||
|
|
98
|
+
page == null ||
|
|
99
|
+
page === pagesCount
|
|
51
100
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
pagesCount <= 1 ||
|
|
57
|
-
page == null ||
|
|
58
|
-
page === pagesCount
|
|
59
|
-
}
|
|
60
|
-
css={{ marginLeft: '7px' }}
|
|
61
|
-
/>
|
|
62
|
-
</Nav>
|
|
101
|
+
css={{ marginLeft: '7px' }}
|
|
102
|
+
/>
|
|
103
|
+
</Wrapper>
|
|
104
|
+
</S.PaginationNav>
|
|
63
105
|
);
|
|
64
106
|
};
|
|
65
107
|
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
PaginationContextProps,
|
|
4
4
|
PaginationContextProviderProps,
|
|
5
5
|
} from './types';
|
|
6
|
+
import { DEFAULT_PER_PAGE_VALUE } from './constants';
|
|
6
7
|
|
|
7
8
|
export const PaginationContext = createContext<PaginationContextProps>(
|
|
8
9
|
{} as PaginationContextProps,
|
|
@@ -12,11 +13,13 @@ export const usePaginationContext = () => useContext(PaginationContext);
|
|
|
12
13
|
|
|
13
14
|
export const PaginationContextProvider = ({
|
|
14
15
|
selectedPage,
|
|
16
|
+
defaultPerPage = DEFAULT_PER_PAGE_VALUE,
|
|
15
17
|
children,
|
|
16
18
|
}: PaginationContextProviderProps) => {
|
|
19
|
+
const [perPage, setPerPage] = useState<number>(defaultPerPage);
|
|
17
20
|
const [page, setPage] = useState(selectedPage);
|
|
18
21
|
return (
|
|
19
|
-
<PaginationContext.Provider value={{ page, setPage }}>
|
|
22
|
+
<PaginationContext.Provider value={{ page, perPage, setPage, setPerPage }}>
|
|
20
23
|
{children}
|
|
21
24
|
</PaginationContext.Provider>
|
|
22
25
|
);
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { useTheme } from '@emotion/react';
|
|
2
|
+
import {
|
|
3
|
+
DropdownOption,
|
|
4
|
+
Typography,
|
|
5
|
+
Wrapper,
|
|
6
|
+
Dropdown,
|
|
7
|
+
usePaginationContext,
|
|
8
|
+
} from '@components';
|
|
9
|
+
import { RowsPerPageDropdownProps } from './types';
|
|
10
|
+
import { DEFAULT_PER_PAGE_VALUE, ROWS_PER_PAGE_LIST } from '../../constants';
|
|
11
|
+
|
|
12
|
+
export const RowsPerPageDropdown = ({
|
|
13
|
+
selectedItem = DEFAULT_PER_PAGE_VALUE,
|
|
14
|
+
rowsPerPageList = ROWS_PER_PAGE_LIST,
|
|
15
|
+
rowsPerPageText = 'Rows per page',
|
|
16
|
+
...rest
|
|
17
|
+
}: RowsPerPageDropdownProps) => {
|
|
18
|
+
const theme = useTheme();
|
|
19
|
+
const { setPerPage } = usePaginationContext();
|
|
20
|
+
|
|
21
|
+
const selectedItemForDropdown =
|
|
22
|
+
rowsPerPageList.find(({ value }) => value === selectedItem) ||
|
|
23
|
+
rowsPerPageList[0];
|
|
24
|
+
|
|
25
|
+
const onChange: Parameters<typeof Dropdown>[0]['onChange'] = ({ value }) => {
|
|
26
|
+
setPerPage(value as number);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<Wrapper css={{ width: 'auto', ul: { width: 'auto' } }}>
|
|
31
|
+
<Typography
|
|
32
|
+
variant="subtitle"
|
|
33
|
+
css={{
|
|
34
|
+
fontSize: 14,
|
|
35
|
+
lineHeight: 1,
|
|
36
|
+
textWrap: 'nowrap',
|
|
37
|
+
}}>
|
|
38
|
+
{rowsPerPageText}:
|
|
39
|
+
</Typography>
|
|
40
|
+
<Dropdown
|
|
41
|
+
selectedItem={selectedItemForDropdown}
|
|
42
|
+
onChange={onChange}
|
|
43
|
+
css={{
|
|
44
|
+
marginLeft: 10,
|
|
45
|
+
marginRight: 37,
|
|
46
|
+
background: 'none',
|
|
47
|
+
color: '#070821',
|
|
48
|
+
gap: 5,
|
|
49
|
+
padding: 0,
|
|
50
|
+
'&:focus': {
|
|
51
|
+
color: '#070821',
|
|
52
|
+
background: 'none',
|
|
53
|
+
'&::before': {
|
|
54
|
+
display: 'none',
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
'& svg path': {
|
|
58
|
+
stroke: theme.colors.greyDarker,
|
|
59
|
+
},
|
|
60
|
+
}}
|
|
61
|
+
{...rest}>
|
|
62
|
+
{rowsPerPageList.map((item) => (
|
|
63
|
+
<DropdownOption key={item.id} value={item.value}>
|
|
64
|
+
{item.value}
|
|
65
|
+
</DropdownOption>
|
|
66
|
+
))}
|
|
67
|
+
</Dropdown>
|
|
68
|
+
</Wrapper>
|
|
69
|
+
);
|
|
70
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './RowsPerPageDropdown';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const ROWS_PER_PAGE_LIST = [
|
|
2
|
+
{
|
|
3
|
+
id: 1,
|
|
4
|
+
value: 10,
|
|
5
|
+
},
|
|
6
|
+
{
|
|
7
|
+
id: 2,
|
|
8
|
+
value: 25,
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
id: 3,
|
|
12
|
+
value: 50,
|
|
13
|
+
},
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
export const DEFAULT_SELECTED_INDEX = 1;
|
|
17
|
+
export const DEFAULT_PER_PAGE_VALUE =
|
|
18
|
+
ROWS_PER_PAGE_LIST[DEFAULT_SELECTED_INDEX].value;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import Input from '@components/Input';
|
|
1
2
|
import { css, Theme } from '@emotion/react';
|
|
3
|
+
import styled from '@emotion/styled';
|
|
2
4
|
|
|
3
5
|
const baseBtnStyles = (theme: Theme) => css`
|
|
4
6
|
height: 30px;
|
|
@@ -96,3 +98,26 @@ export const arrowBtnStyles = (theme: Theme) => css`
|
|
|
96
98
|
cursor: pointer;
|
|
97
99
|
}
|
|
98
100
|
`;
|
|
101
|
+
|
|
102
|
+
export const PaginationNav = styled.nav`
|
|
103
|
+
display: flex;
|
|
104
|
+
`;
|
|
105
|
+
|
|
106
|
+
export const PageNumberInput = styled(Input)`
|
|
107
|
+
width: 80px;
|
|
108
|
+
margin-right: 16px;
|
|
109
|
+
-moz-appearance: textfield;
|
|
110
|
+
appearance: textfield;
|
|
111
|
+
&::-webkit-outer-spin-button,
|
|
112
|
+
&::-webkit-inner-spin-button {
|
|
113
|
+
-webkit-appearance: none;
|
|
114
|
+
margin: 0;
|
|
115
|
+
}
|
|
116
|
+
&:focus,
|
|
117
|
+
&:hover {
|
|
118
|
+
border-width: 1px !important;
|
|
119
|
+
}
|
|
120
|
+
& + div {
|
|
121
|
+
right: 24px;
|
|
122
|
+
}
|
|
123
|
+
`;
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import { CommonProps } from '@global-types/emotion';
|
|
2
|
+
import { InputProps } from '@components/Input/types';
|
|
3
|
+
import { RowsPerPageDropdownProps } from './components/RowsPerPageDropdown/types';
|
|
2
4
|
|
|
3
5
|
export interface PaginationProps extends CommonProps {
|
|
4
6
|
pagesCount: number;
|
|
5
7
|
ariaLabel?: string;
|
|
6
8
|
isDisabled?: boolean;
|
|
9
|
+
pageNumberPlaceholder?: string;
|
|
10
|
+
isPageSettingVisible?: boolean;
|
|
11
|
+
isRowPerPageVisible?: boolean;
|
|
12
|
+
rowPerPageProps?: RowsPerPageDropdownProps;
|
|
13
|
+
manualPageNumberProps?: InputProps;
|
|
7
14
|
}
|
|
8
15
|
|
|
9
16
|
export interface PaginationButtonsProps {
|
|
@@ -29,10 +36,13 @@ export interface PageButtonProps {
|
|
|
29
36
|
|
|
30
37
|
export interface PaginationContextProps {
|
|
31
38
|
page?: number;
|
|
39
|
+
perPage: number;
|
|
32
40
|
setPage: React.Dispatch<React.SetStateAction<number | undefined>>;
|
|
41
|
+
setPerPage: React.Dispatch<React.SetStateAction<number>>;
|
|
33
42
|
}
|
|
34
43
|
|
|
35
44
|
export interface PaginationContextProviderProps {
|
|
36
45
|
selectedPage?: number;
|
|
46
|
+
defaultPerPage?: number;
|
|
37
47
|
children: React.ReactNode;
|
|
38
48
|
}
|