@westpac/ui 0.43.0 → 0.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/component-type.json +1 -1
- package/dist/components/accordion/components/accordion-item/accordion-item.component.js +3 -1
- package/dist/components/accordion/components/accordion-item/accordion-item.styles.d.ts +3 -0
- package/dist/components/accordion/components/accordion-item/accordion-item.styles.js +2 -1
- package/dist/components/pagination/components/pagination-item/pagination-item.component.js +5 -1
- package/dist/components/pagination/components/pagination-item/pagination-item.styles.d.ts +2 -2
- package/dist/components/pagination/components/pagination-item/pagination-item.styles.js +1 -1
- package/dist/components/pagination/components/pagination-pages/pagination-pages.component.d.ts +2 -0
- package/dist/components/pagination/components/pagination-pages/pagination-pages.component.js +185 -0
- package/dist/components/pagination/components/pagination-pages/pagination-pages.types.d.ts +36 -0
- package/dist/components/pagination/components/pagination-pages/pagination-pages.types.js +1 -0
- package/dist/components/pagination/components/pagination-presentational/pagination-presentational.component.d.ts +2 -0
- package/dist/components/pagination/components/pagination-presentational/pagination-presentational.component.js +44 -0
- package/dist/components/pagination/{pagination.styles.d.ts → components/pagination-presentational/pagination-presentational.styles.d.ts} +3 -0
- package/dist/components/pagination/{pagination.styles.js → components/pagination-presentational/pagination-presentational.styles.js} +2 -1
- package/dist/components/pagination/components/pagination-presentational/pagination-presentational.types.d.ts +41 -0
- package/dist/components/pagination/components/pagination-presentational/pagination-presentational.types.js +1 -0
- package/dist/components/pagination/components/pagination-total-pages/pagination-total-pages.component.d.ts +2 -0
- package/dist/components/pagination/components/pagination-total-pages/pagination-total-pages.component.js +188 -0
- package/dist/components/pagination/components/pagination-total-pages/pagination-total-pages.types.d.ts +40 -0
- package/dist/components/pagination/components/pagination-total-pages/pagination-total-pages.types.js +1 -0
- package/dist/components/pagination/pagination.component.d.ts +1 -1
- package/dist/components/pagination/pagination.component.js +26 -121
- package/dist/components/pagination/pagination.types.d.ts +33 -29
- package/dist/components/pagination/pagination.utils.d.ts +2 -0
- package/dist/components/pagination/pagination.utils.js +12 -0
- package/dist/components/progress-indicator/progress-indicator.component.js +1 -1
- package/dist/css/westpac-ui.css +3 -0
- package/dist/css/westpac-ui.min.css +3 -0
- package/dist/hook/breakpoints.hook.d.ts +1 -0
- package/dist/hook/breakpoints.hook.js +21 -0
- package/package.json +3 -3
- package/src/components/accordion/components/accordion-item/accordion-item.component.tsx +1 -1
- package/src/components/accordion/components/accordion-item/accordion-item.styles.ts +2 -1
- package/src/components/pagination/components/pagination-item/pagination-item.component.tsx +2 -0
- package/src/components/pagination/components/pagination-item/pagination-item.styles.ts +1 -1
- package/src/components/pagination/components/pagination-pages/pagination-pages.component.tsx +212 -0
- package/src/components/pagination/components/pagination-pages/pagination-pages.types.ts +47 -0
- package/src/components/pagination/components/pagination-presentational/pagination-presentational.component.tsx +81 -0
- package/src/components/pagination/{pagination.styles.ts → components/pagination-presentational/pagination-presentational.styles.ts} +2 -0
- package/src/components/pagination/components/pagination-presentational/pagination-presentational.types.ts +48 -0
- package/src/components/pagination/components/pagination-total-pages/pagination-total-pages.component.tsx +234 -0
- package/src/components/pagination/components/pagination-total-pages/pagination-total-pages.types.ts +48 -0
- package/src/components/pagination/pagination.component.tsx +34 -142
- package/src/components/pagination/pagination.types.ts +34 -31
- package/src/components/pagination/pagination.utils.ts +11 -0
- package/src/components/progress-indicator/progress-indicator.component.tsx +1 -1
- package/src/hook/breakpoints.hook.ts +29 -0
|
@@ -30,7 +30,9 @@ export function AccordionItem({ className, tag: Tag = 'div', look = 'soft', ...p
|
|
|
30
30
|
...mergeProps(buttonProps, hoverProps, focusProps),
|
|
31
31
|
ref: ref,
|
|
32
32
|
className: styles.itemHeader()
|
|
33
|
-
}, React.createElement("span",
|
|
33
|
+
}, React.createElement("span", {
|
|
34
|
+
className: styles.headerTitleWrapper()
|
|
35
|
+
}, item.props.title), direction === 'ltr' ? React.createElement(ArrowRightIcon, {
|
|
34
36
|
"aria-hidden": "true",
|
|
35
37
|
className: styles.indicator()
|
|
36
38
|
}) : React.createElement(ArrowLeftIcon, {
|
|
@@ -31,6 +31,7 @@ export declare const styles: import("tailwind-variants").TVReturnType<{
|
|
|
31
31
|
}, {
|
|
32
32
|
base: string;
|
|
33
33
|
itemHeader: string;
|
|
34
|
+
headerTitleWrapper: string;
|
|
34
35
|
indicator: string;
|
|
35
36
|
content: string;
|
|
36
37
|
}, undefined, {
|
|
@@ -68,6 +69,7 @@ export declare const styles: import("tailwind-variants").TVReturnType<{
|
|
|
68
69
|
}, {
|
|
69
70
|
base: string;
|
|
70
71
|
itemHeader: string;
|
|
72
|
+
headerTitleWrapper: string;
|
|
71
73
|
indicator: string;
|
|
72
74
|
content: string;
|
|
73
75
|
}, import("tailwind-variants").TVReturnType<{
|
|
@@ -103,6 +105,7 @@ export declare const styles: import("tailwind-variants").TVReturnType<{
|
|
|
103
105
|
}, {
|
|
104
106
|
base: string;
|
|
105
107
|
itemHeader: string;
|
|
108
|
+
headerTitleWrapper: string;
|
|
106
109
|
indicator: string;
|
|
107
110
|
content: string;
|
|
108
111
|
}, undefined, {
|
|
@@ -2,7 +2,8 @@ import { tv } from 'tailwind-variants';
|
|
|
2
2
|
export const styles = tv({
|
|
3
3
|
slots: {
|
|
4
4
|
base: 'relative',
|
|
5
|
-
itemHeader: 'typography-body-9 flex w-full items-center justify-between px-3 py-2',
|
|
5
|
+
itemHeader: 'typography-body-9 flex w-full flex-1 items-center justify-between px-3 py-2',
|
|
6
|
+
headerTitleWrapper: 'flex-1 pr-2 text-left',
|
|
6
7
|
indicator: 'size-3 rotate-90',
|
|
7
8
|
content: 'hidden'
|
|
8
9
|
},
|
|
@@ -11,6 +11,10 @@ export function PaginationItem({ className, firstItem = false, lastItem = false,
|
|
|
11
11
|
}),
|
|
12
12
|
...props,
|
|
13
13
|
disabled: disabled,
|
|
14
|
-
"aria-
|
|
14
|
+
"aria-disabled": disabled ? 'true' : 'false',
|
|
15
|
+
"aria-current": active ? 'page' : undefined,
|
|
16
|
+
...Tag === 'button' && {
|
|
17
|
+
type: 'button'
|
|
18
|
+
}
|
|
15
19
|
}, children);
|
|
16
20
|
}
|
|
@@ -15,7 +15,7 @@ export declare const styles: import("tailwind-variants").TVReturnType<{
|
|
|
15
15
|
true: string;
|
|
16
16
|
false: string;
|
|
17
17
|
};
|
|
18
|
-
}, undefined, "typography-body-10 relative block border border-border px-2 py-1.5 text-center text-text
|
|
18
|
+
}, undefined, "typography-body-10 relative block min-w-7 border border-border px-2 py-1.5 text-center text-text", {
|
|
19
19
|
responsiveVariants: string[];
|
|
20
20
|
}, {
|
|
21
21
|
firstItem: {
|
|
@@ -51,6 +51,6 @@ export declare const styles: import("tailwind-variants").TVReturnType<{
|
|
|
51
51
|
true: string;
|
|
52
52
|
false: string;
|
|
53
53
|
};
|
|
54
|
-
}, undefined, "typography-body-10 relative block border border-border px-2 py-1.5 text-center text-text
|
|
54
|
+
}, undefined, "typography-body-10 relative block min-w-7 border border-border px-2 py-1.5 text-center text-text", {
|
|
55
55
|
responsiveVariants: string[];
|
|
56
56
|
}, unknown, unknown, undefined>>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { tv } from 'tailwind-variants';
|
|
2
2
|
export const styles = tv({
|
|
3
|
-
base: 'typography-body-10 relative block border border-border px-2 py-1.5 text-center text-text
|
|
3
|
+
base: 'typography-body-10 relative block min-w-7 border border-border px-2 py-1.5 text-center text-text',
|
|
4
4
|
variants: {
|
|
5
5
|
firstItem: {
|
|
6
6
|
true: 'rounded-l',
|
package/dist/components/pagination/components/pagination-pages/pagination-pages.component.d.ts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { type PaginationPageProps } from './pagination-pages.types.js';
|
|
2
|
+
export declare function PaginationPage({ className, pages, tag, role, current, linkComponent, infinite, onChange, backLabel, nextLabel, nextAriaLabel, backAriaLabel, siblingCount, boundaryCount, ...props }: PaginationPageProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import React, { useCallback, useMemo } from 'react';
|
|
3
|
+
import { useBreakpoint } from '../../../../hook/breakpoints.hook.js';
|
|
4
|
+
import { getSiblingOrBoundaryCount } from '../../pagination.utils.js';
|
|
5
|
+
import { PaginationPresentational } from '../pagination-presentational/pagination-presentational.component.js';
|
|
6
|
+
export function PaginationPage({ className, pages, tag = 'nav', role = 'navigation', current = 1, linkComponent, infinite = false, onChange, backLabel = 'Back', nextLabel = 'Next', nextAriaLabel = 'Next', backAriaLabel = 'Back', siblingCount = 2, boundaryCount = 1, ...props }) {
|
|
7
|
+
const breakpoint = useBreakpoint();
|
|
8
|
+
const finalSiblingCount = useMemo(()=>{
|
|
9
|
+
if (typeof siblingCount === 'number') {
|
|
10
|
+
return siblingCount;
|
|
11
|
+
}
|
|
12
|
+
return getSiblingOrBoundaryCount(siblingCount, breakpoint);
|
|
13
|
+
}, [
|
|
14
|
+
breakpoint,
|
|
15
|
+
siblingCount
|
|
16
|
+
]);
|
|
17
|
+
const finalBoundaryCount = useMemo(()=>{
|
|
18
|
+
if (typeof boundaryCount === 'number') {
|
|
19
|
+
return boundaryCount;
|
|
20
|
+
}
|
|
21
|
+
return getSiblingOrBoundaryCount(boundaryCount, breakpoint);
|
|
22
|
+
}, [
|
|
23
|
+
boundaryCount,
|
|
24
|
+
breakpoint
|
|
25
|
+
]);
|
|
26
|
+
const generateHandleOnClickBackwards = useCallback((current, infinite, forwardOnly, onChange, pages)=>()=>{
|
|
27
|
+
if (infinite && forwardOnly) {
|
|
28
|
+
return onChange(pages.length);
|
|
29
|
+
}
|
|
30
|
+
if (!forwardOnly) {
|
|
31
|
+
return onChange(current - 1);
|
|
32
|
+
}
|
|
33
|
+
}, []);
|
|
34
|
+
const paginationBackProps = useMemo(()=>{
|
|
35
|
+
var _pages_;
|
|
36
|
+
const fowardOnly = (current || 1) <= 1;
|
|
37
|
+
const defaultBackProps = {
|
|
38
|
+
disabled: !infinite && fowardOnly,
|
|
39
|
+
firstItem: true,
|
|
40
|
+
'aria-label': backAriaLabel
|
|
41
|
+
};
|
|
42
|
+
if (defaultBackProps.disabled) {
|
|
43
|
+
return {
|
|
44
|
+
...defaultBackProps,
|
|
45
|
+
tag: 'button'
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
if (onChange) {
|
|
49
|
+
return {
|
|
50
|
+
...defaultBackProps,
|
|
51
|
+
tag: linkComponent || 'button',
|
|
52
|
+
...current && {
|
|
53
|
+
onClick: generateHandleOnClickBackwards(current, infinite, fowardOnly, onChange, pages)
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
...defaultBackProps,
|
|
59
|
+
tag: linkComponent || 'a',
|
|
60
|
+
href: fowardOnly ? pages[pages.length - 1].href : (_pages_ = pages[(current || 0) - 2]) === null || _pages_ === void 0 ? void 0 : _pages_.href
|
|
61
|
+
};
|
|
62
|
+
}, [
|
|
63
|
+
current,
|
|
64
|
+
infinite,
|
|
65
|
+
backAriaLabel,
|
|
66
|
+
onChange,
|
|
67
|
+
linkComponent,
|
|
68
|
+
pages,
|
|
69
|
+
generateHandleOnClickBackwards
|
|
70
|
+
]);
|
|
71
|
+
const generateHandleOnClickForward = useCallback((current, infinite, backwardsOnly, onChange)=>()=>{
|
|
72
|
+
if (infinite && backwardsOnly) {
|
|
73
|
+
return onChange(1);
|
|
74
|
+
}
|
|
75
|
+
if (backwardsOnly) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
return onChange(current + 1);
|
|
79
|
+
}, []);
|
|
80
|
+
const paginationNextProps = useMemo(()=>{
|
|
81
|
+
var _pages_;
|
|
82
|
+
const backwardsOnly = (current || 1) >= pages.length;
|
|
83
|
+
const defaultNextProps = {
|
|
84
|
+
disabled: !infinite && backwardsOnly,
|
|
85
|
+
tag: linkComponent,
|
|
86
|
+
lastItem: true,
|
|
87
|
+
'aria-label': nextAriaLabel
|
|
88
|
+
};
|
|
89
|
+
if (defaultNextProps.disabled) {
|
|
90
|
+
return {
|
|
91
|
+
...defaultNextProps,
|
|
92
|
+
tag: 'button'
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
if (onChange) {
|
|
96
|
+
return {
|
|
97
|
+
...defaultNextProps,
|
|
98
|
+
tag: linkComponent || 'button',
|
|
99
|
+
...current && {
|
|
100
|
+
onClick: generateHandleOnClickForward(current, infinite, backwardsOnly, onChange)
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
...defaultNextProps,
|
|
106
|
+
tag: linkComponent || 'a',
|
|
107
|
+
href: backwardsOnly ? pages[0].href : (_pages_ = pages[current || 0]) === null || _pages_ === void 0 ? void 0 : _pages_.href
|
|
108
|
+
};
|
|
109
|
+
}, [
|
|
110
|
+
current,
|
|
111
|
+
pages,
|
|
112
|
+
infinite,
|
|
113
|
+
linkComponent,
|
|
114
|
+
nextAriaLabel,
|
|
115
|
+
onChange,
|
|
116
|
+
generateHandleOnClickForward
|
|
117
|
+
]);
|
|
118
|
+
const numberedPages = useMemo(()=>pages.map((page, index)=>({
|
|
119
|
+
...page,
|
|
120
|
+
page: index + 1
|
|
121
|
+
})), [
|
|
122
|
+
pages
|
|
123
|
+
]);
|
|
124
|
+
const pagesToRender = useMemo(()=>{
|
|
125
|
+
const minEdgePagesVisible = Math.min(finalSiblingCount * 2 + finalBoundaryCount + 2, pages.length);
|
|
126
|
+
let leftCorner = numberedPages.slice(0, finalBoundaryCount);
|
|
127
|
+
let rightCorner = finalBoundaryCount > 0 ? numberedPages.slice(-finalBoundaryCount).filter((page)=>!leftCorner.some((leftItem)=>leftItem.page === page.page)) : [];
|
|
128
|
+
let middle = [];
|
|
129
|
+
if (current) {
|
|
130
|
+
var _middle_, _leftCorner_at, _rightCorner_;
|
|
131
|
+
const nearStart = current < minEdgePagesVisible - finalSiblingCount;
|
|
132
|
+
const nearEnd = current > numberedPages.length - minEdgePagesVisible + finalSiblingCount;
|
|
133
|
+
if (nearStart) {
|
|
134
|
+
leftCorner = numberedPages.slice(0, minEdgePagesVisible);
|
|
135
|
+
}
|
|
136
|
+
if (nearEnd) {
|
|
137
|
+
rightCorner = numberedPages.slice(-minEdgePagesVisible);
|
|
138
|
+
}
|
|
139
|
+
rightCorner = rightCorner.filter((page)=>!leftCorner.some((leftItem)=>leftItem.page === page.page));
|
|
140
|
+
const currentIndex = current - 1;
|
|
141
|
+
const leftEdge = currentIndex - finalSiblingCount;
|
|
142
|
+
middle = numberedPages.slice(Math.max(0, leftEdge), leftEdge + (finalSiblingCount * 2 + 1)).filter((middleItem)=>{
|
|
143
|
+
return !(leftCorner.some((left)=>left.page === middleItem.page) || rightCorner.some((right)=>right.page === middleItem.page));
|
|
144
|
+
});
|
|
145
|
+
const lastItemMiddle = middle.at(-1);
|
|
146
|
+
const hasLeftDots = ((_middle_ = middle[0]) === null || _middle_ === void 0 ? void 0 : _middle_.page) && middle[0].page - 1 !== ((_leftCorner_at = leftCorner.at(-1)) === null || _leftCorner_at === void 0 ? void 0 : _leftCorner_at.page);
|
|
147
|
+
const hasRightDots = (lastItemMiddle === null || lastItemMiddle === void 0 ? void 0 : lastItemMiddle.page) && lastItemMiddle.page + 1 !== ((_rightCorner_ = rightCorner[0]) === null || _rightCorner_ === void 0 ? void 0 : _rightCorner_.page);
|
|
148
|
+
if (middle.length === 0 && leftCorner.length + rightCorner.length !== numberedPages.length) {
|
|
149
|
+
middle = [
|
|
150
|
+
null
|
|
151
|
+
];
|
|
152
|
+
} else {
|
|
153
|
+
if (hasLeftDots) middle.unshift(null);
|
|
154
|
+
if (hasRightDots) middle.push(null);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return [
|
|
158
|
+
...leftCorner,
|
|
159
|
+
...middle,
|
|
160
|
+
...rightCorner
|
|
161
|
+
];
|
|
162
|
+
}, [
|
|
163
|
+
finalBoundaryCount,
|
|
164
|
+
current,
|
|
165
|
+
numberedPages,
|
|
166
|
+
finalSiblingCount,
|
|
167
|
+
pages.length
|
|
168
|
+
]);
|
|
169
|
+
if (!pages.length) {
|
|
170
|
+
return React.createElement(React.Fragment, null);
|
|
171
|
+
}
|
|
172
|
+
return React.createElement(PaginationPresentational, {
|
|
173
|
+
className: className,
|
|
174
|
+
current: current,
|
|
175
|
+
paginationBackProps: paginationBackProps,
|
|
176
|
+
paginationNextProps: paginationNextProps,
|
|
177
|
+
pagesToRender: pagesToRender,
|
|
178
|
+
tag: tag,
|
|
179
|
+
role: role,
|
|
180
|
+
backLabel: backLabel,
|
|
181
|
+
nextLabel: nextLabel,
|
|
182
|
+
onChange: onChange,
|
|
183
|
+
...props
|
|
184
|
+
});
|
|
185
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import { PaginationBase } from '../../pagination.types.js';
|
|
3
|
+
export type PageProps = {
|
|
4
|
+
'aria-label'?: string;
|
|
5
|
+
href: string;
|
|
6
|
+
text: ReactNode;
|
|
7
|
+
};
|
|
8
|
+
export type PaginationAsLinkProps = {
|
|
9
|
+
/**
|
|
10
|
+
* on page change
|
|
11
|
+
*/
|
|
12
|
+
onChange?: never;
|
|
13
|
+
/**
|
|
14
|
+
* Pages items
|
|
15
|
+
*/
|
|
16
|
+
pages: PageProps[];
|
|
17
|
+
};
|
|
18
|
+
export type PaginationAsButtonProps = {
|
|
19
|
+
/**
|
|
20
|
+
* on page change
|
|
21
|
+
*/
|
|
22
|
+
onChange: (page: number) => unknown;
|
|
23
|
+
/**
|
|
24
|
+
* Pages items
|
|
25
|
+
*/
|
|
26
|
+
pages: Omit<PageProps, 'href'>[];
|
|
27
|
+
};
|
|
28
|
+
export type PaginationPageProps = PaginationBase & (PaginationAsLinkProps | PaginationAsButtonProps) & Omit<HTMLAttributes<Element>, 'onChange'>;
|
|
29
|
+
export type PageToRender = {
|
|
30
|
+
href: string;
|
|
31
|
+
page: number;
|
|
32
|
+
text: React.ReactNode;
|
|
33
|
+
} | {
|
|
34
|
+
page: number;
|
|
35
|
+
text: React.ReactNode;
|
|
36
|
+
} | null;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { type PaginationPresentationalProps } from './pagination-presentational.types.js';
|
|
2
|
+
export declare function PaginationPresentational({ className, tag: Tag, role, paginationBackProps, backLabel, pagesToRender, current, linkComponent, onChange, paginationNextProps, nextLabel, ...props }: PaginationPresentationalProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { PaginationItem } from '../../components/index.js';
|
|
4
|
+
import { styles as paginationStyles } from './pagination-presentational.styles.js';
|
|
5
|
+
export function PaginationPresentational({ className, tag: Tag = 'nav', role = 'navigation', paginationBackProps, backLabel, pagesToRender, current, linkComponent, onChange, paginationNextProps, nextLabel, ...props }) {
|
|
6
|
+
const styles = paginationStyles({});
|
|
7
|
+
return React.createElement(Tag, {
|
|
8
|
+
className: styles.base({
|
|
9
|
+
className
|
|
10
|
+
}),
|
|
11
|
+
role: role,
|
|
12
|
+
"aria-label": "Page number",
|
|
13
|
+
...props
|
|
14
|
+
}, React.createElement("ul", {
|
|
15
|
+
className: styles.ul({})
|
|
16
|
+
}, React.createElement("li", null, React.createElement(PaginationItem, paginationBackProps, backLabel)), pagesToRender.map((page, index)=>{
|
|
17
|
+
if (page === null) {
|
|
18
|
+
return React.createElement("li", {
|
|
19
|
+
className: styles.emptyItem(),
|
|
20
|
+
key: `index-${index}`
|
|
21
|
+
}, "…");
|
|
22
|
+
}
|
|
23
|
+
const commonProps = {
|
|
24
|
+
active: (current || 0) === page.page,
|
|
25
|
+
'aria-label': page['aria-label'] || `Go to page ${page.page}`
|
|
26
|
+
};
|
|
27
|
+
return React.createElement("li", {
|
|
28
|
+
key: page.page
|
|
29
|
+
}, 'href' in page ? React.createElement(PaginationItem, {
|
|
30
|
+
...commonProps,
|
|
31
|
+
tag: linkComponent || 'a',
|
|
32
|
+
href: page.href
|
|
33
|
+
}, page.text) : React.createElement(PaginationItem, {
|
|
34
|
+
...commonProps,
|
|
35
|
+
tag: linkComponent || 'button',
|
|
36
|
+
onClick: onChange && (()=>{
|
|
37
|
+
onChange(page.page);
|
|
38
|
+
})
|
|
39
|
+
}, page.text));
|
|
40
|
+
}), React.createElement("li", null, React.createElement(PaginationItem, paginationNextProps, nextLabel))), current && React.createElement("span", {
|
|
41
|
+
className: "sr-only",
|
|
42
|
+
role: "status"
|
|
43
|
+
}, "Page ", current));
|
|
44
|
+
}
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
export declare const styles: import("tailwind-variants").TVReturnType<{}, {
|
|
2
2
|
base: string;
|
|
3
3
|
ul: string;
|
|
4
|
+
emptyItem: string;
|
|
4
5
|
}, undefined, {
|
|
5
6
|
responsiveVariants: string[];
|
|
6
7
|
}, {}, {
|
|
7
8
|
base: string;
|
|
8
9
|
ul: string;
|
|
10
|
+
emptyItem: string;
|
|
9
11
|
}, import("tailwind-variants").TVReturnType<{}, {
|
|
10
12
|
base: string;
|
|
11
13
|
ul: string;
|
|
14
|
+
emptyItem: string;
|
|
12
15
|
}, undefined, {
|
|
13
16
|
responsiveVariants: string[];
|
|
14
17
|
}, unknown, unknown, undefined>>;
|
|
@@ -2,7 +2,8 @@ import { tv } from 'tailwind-variants';
|
|
|
2
2
|
export const styles = tv({
|
|
3
3
|
slots: {
|
|
4
4
|
base: 'flex flex-col items-center',
|
|
5
|
-
ul: 'flex overflow-hidden'
|
|
5
|
+
ul: 'flex overflow-hidden',
|
|
6
|
+
emptyItem: 'typography-body-10 relative block min-w-7 cursor-default border-y border-border px-2 py-1.5 text-center text-text'
|
|
6
7
|
},
|
|
7
8
|
variants: {}
|
|
8
9
|
}, {
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { HTMLAttributes } from 'react';
|
|
2
|
+
import { type PaginationItemProps } from '../../components/index.js';
|
|
3
|
+
import { PaginationBase } from '../../pagination.types.js';
|
|
4
|
+
export type PageToRender = {
|
|
5
|
+
'aria-label'?: string;
|
|
6
|
+
href: string;
|
|
7
|
+
page: number;
|
|
8
|
+
text: React.ReactNode;
|
|
9
|
+
} | {
|
|
10
|
+
'aria-label'?: string;
|
|
11
|
+
page: number;
|
|
12
|
+
text: React.ReactNode;
|
|
13
|
+
} | null;
|
|
14
|
+
export type PaginationPresentationalProps = PaginationBase & {
|
|
15
|
+
/**
|
|
16
|
+
* on page change
|
|
17
|
+
*/
|
|
18
|
+
onChange?: (page: number) => unknown;
|
|
19
|
+
/**
|
|
20
|
+
* Pages to render where the null value is rendered as [...]
|
|
21
|
+
*/
|
|
22
|
+
pagesToRender: PageToRender[];
|
|
23
|
+
/**
|
|
24
|
+
* Props to back button
|
|
25
|
+
*/
|
|
26
|
+
paginationBackProps?: PaginationItemProps;
|
|
27
|
+
/**
|
|
28
|
+
* Props to back button
|
|
29
|
+
*/
|
|
30
|
+
paginationNextProps?: PaginationItemProps;
|
|
31
|
+
/**
|
|
32
|
+
* siblingCount
|
|
33
|
+
* @default 1
|
|
34
|
+
*/
|
|
35
|
+
siblingCount?: number;
|
|
36
|
+
/**
|
|
37
|
+
* Tag to render
|
|
38
|
+
* @default nav
|
|
39
|
+
*/
|
|
40
|
+
tag?: keyof JSX.IntrinsicElements;
|
|
41
|
+
} & Omit<HTMLAttributes<Element>, 'onChange'>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { type PaginationTotalPagesProps } from './pagination-total-pages.types.js';
|
|
2
|
+
export declare function PaginationTotalPages({ className, totalPages, tag, role, current, linkComponent, infinite, onChange, backLabel, backAriaLabel, nextLabel, nextAriaLabel, siblingCount, boundaryCount, onPageItemProps, ...props }: PaginationTotalPagesProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import React, { useCallback, useMemo } from 'react';
|
|
3
|
+
import { useBreakpoint } from '../../../../hook/breakpoints.hook.js';
|
|
4
|
+
import { getSiblingOrBoundaryCount } from '../../pagination.utils.js';
|
|
5
|
+
import { PaginationPresentational } from '../pagination-presentational/pagination-presentational.component.js';
|
|
6
|
+
function generateArray(from, to) {
|
|
7
|
+
return Array.from({
|
|
8
|
+
length: to - from + 1
|
|
9
|
+
}, (_, i)=>i + from);
|
|
10
|
+
}
|
|
11
|
+
export function PaginationTotalPages({ className, totalPages, tag = 'nav', role = 'navigation', current = 1, linkComponent, infinite = false, onChange, backLabel = 'Back', backAriaLabel = 'Back', nextLabel = 'Next', nextAriaLabel = 'Next', siblingCount = 2, boundaryCount = 1, onPageItemProps, ...props }) {
|
|
12
|
+
const breakpoint = useBreakpoint();
|
|
13
|
+
const finalSiblingCount = useMemo(()=>{
|
|
14
|
+
if (typeof siblingCount === 'number') {
|
|
15
|
+
return siblingCount;
|
|
16
|
+
}
|
|
17
|
+
return getSiblingOrBoundaryCount(siblingCount, breakpoint);
|
|
18
|
+
}, [
|
|
19
|
+
breakpoint,
|
|
20
|
+
siblingCount
|
|
21
|
+
]);
|
|
22
|
+
const finalBoundaryCount = useMemo(()=>{
|
|
23
|
+
if (typeof boundaryCount === 'number') {
|
|
24
|
+
return boundaryCount;
|
|
25
|
+
}
|
|
26
|
+
return getSiblingOrBoundaryCount(boundaryCount, breakpoint);
|
|
27
|
+
}, [
|
|
28
|
+
boundaryCount,
|
|
29
|
+
breakpoint
|
|
30
|
+
]);
|
|
31
|
+
const generateHandleOnClickBackwards = useCallback((current, infinite, forwardOnly, onChange, totalPages)=>()=>{
|
|
32
|
+
if (infinite && forwardOnly) {
|
|
33
|
+
return onChange(totalPages);
|
|
34
|
+
}
|
|
35
|
+
if (!forwardOnly) {
|
|
36
|
+
return onChange(current - 1);
|
|
37
|
+
}
|
|
38
|
+
}, []);
|
|
39
|
+
const paginationBackProps = useMemo(()=>{
|
|
40
|
+
var _onPageItemProps;
|
|
41
|
+
const fowardOnly = (current || 1) <= 1;
|
|
42
|
+
const defaultBackProps = {
|
|
43
|
+
disabled: !infinite && fowardOnly,
|
|
44
|
+
firstItem: true,
|
|
45
|
+
'aria-label': backAriaLabel
|
|
46
|
+
};
|
|
47
|
+
if (defaultBackProps.disabled) {
|
|
48
|
+
return {
|
|
49
|
+
...defaultBackProps,
|
|
50
|
+
tag: 'button'
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
if (onChange) {
|
|
54
|
+
return {
|
|
55
|
+
...defaultBackProps,
|
|
56
|
+
tag: linkComponent || 'button',
|
|
57
|
+
...current && {
|
|
58
|
+
onClick: generateHandleOnClickBackwards(current, infinite, fowardOnly, onChange, totalPages)
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
...defaultBackProps,
|
|
64
|
+
tag: linkComponent || 'a',
|
|
65
|
+
href: fowardOnly ? onPageItemProps(totalPages).href : (_onPageItemProps = onPageItemProps(current - 1)) === null || _onPageItemProps === void 0 ? void 0 : _onPageItemProps.href
|
|
66
|
+
};
|
|
67
|
+
}, [
|
|
68
|
+
current,
|
|
69
|
+
infinite,
|
|
70
|
+
backAriaLabel,
|
|
71
|
+
onChange,
|
|
72
|
+
linkComponent,
|
|
73
|
+
onPageItemProps,
|
|
74
|
+
totalPages,
|
|
75
|
+
generateHandleOnClickBackwards
|
|
76
|
+
]);
|
|
77
|
+
const generateHandleOnClickForward = useCallback((current, infinite, backwardsOnly, onChange)=>()=>{
|
|
78
|
+
if (infinite && backwardsOnly) {
|
|
79
|
+
return onChange(1);
|
|
80
|
+
}
|
|
81
|
+
if (backwardsOnly) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
return onChange(current + 1);
|
|
85
|
+
}, []);
|
|
86
|
+
const paginationNextProps = useMemo(()=>{
|
|
87
|
+
var _onPageItemProps, _onPageItemProps1;
|
|
88
|
+
const backwardsOnly = (current || 1) >= totalPages;
|
|
89
|
+
const defaultNextProps = {
|
|
90
|
+
disabled: !infinite && backwardsOnly,
|
|
91
|
+
tag: linkComponent,
|
|
92
|
+
lastItem: true,
|
|
93
|
+
'aria-label': nextAriaLabel
|
|
94
|
+
};
|
|
95
|
+
if (defaultNextProps.disabled) {
|
|
96
|
+
return {
|
|
97
|
+
...defaultNextProps,
|
|
98
|
+
tag: 'button'
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
if (onChange) {
|
|
102
|
+
return {
|
|
103
|
+
...defaultNextProps,
|
|
104
|
+
tag: linkComponent || 'button',
|
|
105
|
+
...current && {
|
|
106
|
+
onClick: generateHandleOnClickForward(current, infinite, backwardsOnly, onChange)
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
...defaultNextProps,
|
|
112
|
+
tag: linkComponent || 'a',
|
|
113
|
+
href: backwardsOnly ? (_onPageItemProps = onPageItemProps(1)) === null || _onPageItemProps === void 0 ? void 0 : _onPageItemProps.href : (_onPageItemProps1 = onPageItemProps(current || 0)) === null || _onPageItemProps1 === void 0 ? void 0 : _onPageItemProps1.href
|
|
114
|
+
};
|
|
115
|
+
}, [
|
|
116
|
+
current,
|
|
117
|
+
totalPages,
|
|
118
|
+
infinite,
|
|
119
|
+
linkComponent,
|
|
120
|
+
nextAriaLabel,
|
|
121
|
+
onChange,
|
|
122
|
+
onPageItemProps,
|
|
123
|
+
generateHandleOnClickForward
|
|
124
|
+
]);
|
|
125
|
+
const pagesToRender = useMemo(()=>{
|
|
126
|
+
const minEdgePagesVisible = Math.min(finalSiblingCount * 2 + finalBoundaryCount + 2, totalPages);
|
|
127
|
+
let leftCorner = generateArray(1, Math.min(finalBoundaryCount, totalPages));
|
|
128
|
+
let rightCorner = finalBoundaryCount > 0 ? generateArray(totalPages + 1 - finalBoundaryCount, totalPages).filter((page)=>!leftCorner.some((leftItem)=>leftItem === page)) : [];
|
|
129
|
+
let middle = [];
|
|
130
|
+
if (current) {
|
|
131
|
+
const nearStart = current < minEdgePagesVisible - finalSiblingCount;
|
|
132
|
+
const nearEnd = current > totalPages - minEdgePagesVisible + finalSiblingCount;
|
|
133
|
+
if (nearStart) {
|
|
134
|
+
leftCorner = generateArray(1, minEdgePagesVisible);
|
|
135
|
+
}
|
|
136
|
+
if (nearEnd) {
|
|
137
|
+
rightCorner = generateArray(totalPages - minEdgePagesVisible + 1, totalPages);
|
|
138
|
+
}
|
|
139
|
+
rightCorner = rightCorner.filter((page)=>!leftCorner.some((leftItem)=>leftItem === page));
|
|
140
|
+
const leftEdge = current - finalSiblingCount;
|
|
141
|
+
middle = generateArray(Math.max(1, leftEdge), Math.min(leftEdge + finalSiblingCount * 2, totalPages)).filter((middleItem)=>{
|
|
142
|
+
return !(leftCorner.some((left)=>left === middleItem) || rightCorner.some((right)=>right === middleItem));
|
|
143
|
+
});
|
|
144
|
+
const lastItemMiddle = middle.at(-1);
|
|
145
|
+
const hasLeftDots = middle[0] && middle[0] - 1 !== leftCorner.at(-1);
|
|
146
|
+
const hasRightDots = lastItemMiddle && lastItemMiddle + 1 !== rightCorner[0];
|
|
147
|
+
if (middle.length === 0 && leftCorner.length + rightCorner.length !== totalPages) {
|
|
148
|
+
middle = [
|
|
149
|
+
null
|
|
150
|
+
];
|
|
151
|
+
} else {
|
|
152
|
+
if (hasLeftDots) middle.unshift(null);
|
|
153
|
+
if (hasRightDots) middle.push(null);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return [
|
|
157
|
+
...leftCorner,
|
|
158
|
+
...middle,
|
|
159
|
+
...rightCorner
|
|
160
|
+
].map((page)=>page ? {
|
|
161
|
+
page,
|
|
162
|
+
text: page,
|
|
163
|
+
...onPageItemProps === null || onPageItemProps === void 0 ? void 0 : onPageItemProps(page)
|
|
164
|
+
} : null);
|
|
165
|
+
}, [
|
|
166
|
+
finalBoundaryCount,
|
|
167
|
+
current,
|
|
168
|
+
onPageItemProps,
|
|
169
|
+
finalSiblingCount,
|
|
170
|
+
totalPages
|
|
171
|
+
]);
|
|
172
|
+
if (totalPages <= 0) {
|
|
173
|
+
return React.createElement(React.Fragment, null);
|
|
174
|
+
}
|
|
175
|
+
return React.createElement(PaginationPresentational, {
|
|
176
|
+
className: className,
|
|
177
|
+
current: current,
|
|
178
|
+
paginationBackProps: paginationBackProps,
|
|
179
|
+
paginationNextProps: paginationNextProps,
|
|
180
|
+
pagesToRender: pagesToRender,
|
|
181
|
+
tag: tag,
|
|
182
|
+
role: role,
|
|
183
|
+
backLabel: backLabel,
|
|
184
|
+
nextLabel: nextLabel,
|
|
185
|
+
onChange: onChange,
|
|
186
|
+
...props
|
|
187
|
+
});
|
|
188
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import { PaginationBase } from '../../pagination.types.js';
|
|
3
|
+
export type PageProps = {
|
|
4
|
+
href: string;
|
|
5
|
+
text: ReactNode;
|
|
6
|
+
};
|
|
7
|
+
export type PaginationAsLinkProps = {
|
|
8
|
+
/**
|
|
9
|
+
* on page change
|
|
10
|
+
*/
|
|
11
|
+
onChange?: never;
|
|
12
|
+
/**
|
|
13
|
+
* Pages items
|
|
14
|
+
*/
|
|
15
|
+
onPageItemProps: (page: number) => Omit<PageToRenderHref, 'page'>;
|
|
16
|
+
};
|
|
17
|
+
export type PaginationAsButtonProps = {
|
|
18
|
+
/**
|
|
19
|
+
* on page change
|
|
20
|
+
*/
|
|
21
|
+
onChange: (page: number) => unknown;
|
|
22
|
+
/**
|
|
23
|
+
* Pages items
|
|
24
|
+
*/
|
|
25
|
+
onPageItemProps?: (page: number) => Omit<PageToRenderBase, 'page'>;
|
|
26
|
+
};
|
|
27
|
+
export type PaginationTotalPagesProps = {
|
|
28
|
+
/**
|
|
29
|
+
* total of pages
|
|
30
|
+
*/
|
|
31
|
+
totalPages: number;
|
|
32
|
+
} & PaginationBase & (PaginationAsLinkProps | PaginationAsButtonProps) & Omit<HTMLAttributes<Element>, 'onChange'>;
|
|
33
|
+
export type PageToRenderBase = {
|
|
34
|
+
'aria-label'?: string;
|
|
35
|
+
page: number;
|
|
36
|
+
text: React.ReactNode;
|
|
37
|
+
};
|
|
38
|
+
export type PageToRenderHref = PageToRenderBase & {
|
|
39
|
+
href: string;
|
|
40
|
+
};
|