Skip to content

Commit 1f50a25

Browse files
refactor: Paginator
1 parent 0f00235 commit 1f50a25

12 files changed

Lines changed: 95 additions & 115 deletions

File tree

packages/@primereact/headless/src/paginator/usePaginator.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,28 @@ const range = (start: number, end: number) => {
1010

1111
const ELLIPSIS = { type: 'ellipsis' as const };
1212

13+
const primereact = {
14+
config: {
15+
locale: {
16+
aria: {
17+
pageLabel: 'Page {page}',
18+
firstPageLabel: 'First Page',
19+
lastPageLabel: 'Last Page',
20+
nextPageLabel: 'Next Page',
21+
prevPageLabel: 'Previous Page'
22+
}
23+
}
24+
}
25+
};
26+
1327
export const usePaginator = withHeadless({
1428
name: 'usePaginator',
1529
defaultProps,
1630
setup({ props }) {
31+
const getAriaLabel = (labelType: string) => {
32+
return primereact?.config?.locale?.aria ? (primereact.config.locale.aria as Record<string, string>)[labelType] : undefined;
33+
};
34+
1735
const { edges = 1, siblings = 1, showEllipsis = true } = props;
1836
const [activePage, setActivePage] = React.useState(props.defaultPage ?? props.page ?? 1);
1937

@@ -86,6 +104,7 @@ export const usePaginator = withHeadless({
86104
const firstProps = {
87105
'data-scope': 'paginator',
88106
'data-part': 'first',
107+
'aria-label': getAriaLabel('firstPageLabel'),
89108
onClick: first,
90109
disabled: !canPrev || props.disabled,
91110
...(!canPrev || props.disabled ? { 'data-disabled': '' } : {})
@@ -94,6 +113,7 @@ export const usePaginator = withHeadless({
94113
const prevProps = {
95114
'data-scope': 'paginator',
96115
'data-part': 'prev',
116+
'aria-label': getAriaLabel('prevPageLabel'),
97117
onClick: prev,
98118
disabled: !canPrev || props.disabled,
99119
...(!canPrev || props.disabled ? { 'data-disabled': '' } : {})
@@ -102,6 +122,7 @@ export const usePaginator = withHeadless({
102122
const nextProps = {
103123
'data-scope': 'paginator',
104124
'data-part': 'next',
125+
'aria-label': getAriaLabel('nextPageLabel'),
105126
onClick: next,
106127
disabled: !canNext || props.disabled,
107128
...(!canNext || props.disabled ? { 'data-disabled': '' } : {})
@@ -110,17 +131,27 @@ export const usePaginator = withHeadless({
110131
const lastProps = {
111132
'data-scope': 'paginator',
112133
'data-part': 'last',
134+
'aria-label': getAriaLabel('lastPageLabel'),
113135
onClick: last,
114136
disabled: !canNext || props.disabled,
115137
...(!canNext || props.disabled ? { 'data-disabled': '' } : {})
116138
};
117139

140+
const pagesProps = {
141+
'data-scope': 'paginator' as const,
142+
'data-part': 'pages' as const,
143+
'aria-label': getAriaLabel('pageLabel')
144+
};
145+
118146
const getPageProps = (value: number) => {
119147
const handleClick = () => handlePage(value);
148+
const pageLabel = getAriaLabel('pageLabel');
149+
const ariaLabel = pageLabel ? pageLabel.replace(/{page}/g, String(value)) : undefined;
120150

121151
return {
122152
'data-scope': 'paginator',
123153
'data-part': 'page',
154+
'aria-label': ariaLabel,
124155
onClick: handleClick,
125156
disabled: props.disabled,
126157
'aria-current': (activePage === value ? 'page' : undefined) as 'page' | undefined,
@@ -143,8 +174,10 @@ export const usePaginator = withHeadless({
143174
prevProps,
144175
nextProps,
145176
lastProps,
177+
pagesProps,
146178
getPageProps,
147179
// methods
180+
getAriaLabel,
148181
prev,
149182
next,
150183
first,

packages/@primereact/types/src/headless/paginator/usePaginator.types.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,28 @@ export interface usePaginatorNavProps {
122122
* Whether the button is disabled.
123123
*/
124124
disabled: boolean | undefined;
125+
/**
126+
* Accessible label for the navigation button.
127+
*/
128+
'aria-label'?: string;
125129
/**
126130
* Data attribute for disabled state.
127131
*/
128132
'data-disabled'?: string;
129133
}
130134

135+
/**
136+
* Pre-built props for the pages container element.
137+
*/
138+
export interface usePaginatorPagesProps {
139+
'data-scope': 'paginator';
140+
'data-part': 'pages';
141+
/**
142+
* Accessible label for the pages container.
143+
*/
144+
'aria-label'?: string;
145+
}
146+
131147
/**
132148
* Pre-built props for a paginator page button.
133149
*/
@@ -140,6 +156,10 @@ export interface usePaginatorPageProps {
140156
* Whether the button is disabled.
141157
*/
142158
disabled: boolean | undefined;
159+
/**
160+
* Accessible label for the page button.
161+
*/
162+
'aria-label'?: string;
143163
/**
144164
* ARIA current page indicator.
145165
*/
@@ -158,6 +178,12 @@ export interface usePaginatorPageProps {
158178
* Defines the return type of usePaginator.
159179
*/
160180
export interface usePaginatorExposes {
181+
/**
182+
* Returns the aria label for the given label type from locale config.
183+
* @param {string} labelType - The label type key.
184+
* @returns {string | undefined} The aria label string.
185+
*/
186+
getAriaLabel: (labelType: string) => string | undefined;
161187
/**
162188
* Go to previous page.
163189
*/
@@ -198,6 +224,10 @@ export interface usePaginatorExposes {
198224
* Pre-built props for the last page button.
199225
*/
200226
lastProps: usePaginatorNavProps;
227+
/**
228+
* Pre-built props for the pages container.
229+
*/
230+
pagesProps: usePaginatorPagesProps;
201231
/**
202232
* Returns pre-built props for a specific page button.
203233
*/

packages/@primereact/types/src/primitive/paginator/PaginatorRoot.types.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
*
1010
*/
1111
import type { ComponentInstance } from '@primereact/types/core';
12-
import type { BaseComponentProps, PassThroughType } from '../..';
1312
import type { usePaginatorChangeEvent, usePaginatorExposes, usePaginatorProps, usePaginatorState } from '@primereact/types/headless/paginator';
13+
import type { BaseComponentProps, PassThroughType } from '../..';
1414

1515
/**
1616
* Defines passthrough(pt) options type in Paginator component.
@@ -62,14 +62,7 @@ export interface PaginatorRootState extends usePaginatorState {}
6262
* Defines the methods and properties exposed by Paginator component.
6363
* @extends usePaginatorExposes
6464
*/
65-
export interface PaginatorRootExposes extends usePaginatorExposes {
66-
/**
67-
* Get the aria label for the given label type.
68-
* @param labelType - The type of label to get.
69-
* @returns The aria label for the given label type.
70-
*/
71-
getAriaLabel: (labelType: string) => string;
72-
}
65+
export interface PaginatorRootExposes extends usePaginatorExposes {}
7366

7467
/**
7568
* Event fired when the paginator's page changes.

packages/primereact/src/paginator/content/PaginatorContent.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,10 @@ export const PaginatorContent = withComponent({
1414
return { paginator };
1515
},
1616
render(instance) {
17-
const { id, props, ptmi, paginator } = instance;
17+
const { props, ptmi, paginator } = instance;
1818

1919
const rootProps = mergeProps(
2020
{
21-
id,
2221
className: paginator?.cx('content')
2322
},
2423
paginator?.ptmi('content'),

packages/primereact/src/paginator/ellipsis/PaginatorEllipsis.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,10 @@ export const PaginatorEllipsis = withComponent({
1414
return { paginator };
1515
},
1616
render(instance) {
17-
const { id, props, ptmi, paginator } = instance;
17+
const { props, ptmi, paginator } = instance;
1818

1919
const rootProps = mergeProps(
2020
{
21-
id,
2221
className: paginator?.cx('ellipsis')
2322
},
2423
paginator?.ptmi('ellipsis'),

packages/primereact/src/paginator/first/PaginatorFirst.tsx

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,18 @@ import { defaultFirstProps } from './PaginatorFirst.props';
88
export const PaginatorFirst = withComponent({
99
name: 'Paginator.First',
1010
defaultProps: defaultFirstProps,
11-
setup() {
11+
setup({ props }) {
1212
const paginator = usePaginatorContext();
13+
const disabled = paginator?.firstProps?.disabled || props.disabled;
1314

14-
const disabled = paginator?.firstProps?.disabled;
15-
16-
const firstProps = {
17-
...paginator?.firstProps,
18-
'aria-label': paginator?.getAriaLabel('firstPageLabel'),
19-
disabled
20-
};
21-
22-
const disabledAttrs = disabled ? { 'data-disabled': '' as const } : {};
23-
24-
return { paginator, firstProps, disabledAttrs };
15+
return { paginator, disabled };
2516
},
2617
render(instance) {
27-
const { id, props, ptmi, paginator, firstProps, disabledAttrs } = instance;
18+
const { props, ptmi, paginator, disabled } = instance;
2819

29-
const disabled = firstProps?.disabled || props.disabled;
3020
const rootProps = mergeProps(
31-
firstProps,
32-
disabledAttrs,
21+
paginator?.firstProps,
3322
{
34-
id,
3523
className: paginator?.cx('first', { disabled }),
3624
disabled
3725
},

packages/primereact/src/paginator/last/PaginatorLast.tsx

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,18 @@ import { defaultLastProps } from './PaginatorLast.props';
88
export const PaginatorLast = withComponent({
99
name: 'Paginator.Last',
1010
defaultProps: defaultLastProps,
11-
setup() {
11+
setup({ props }) {
1212
const paginator = usePaginatorContext();
13+
const disabled = paginator?.lastProps?.disabled || props.disabled;
1314

14-
const disabled = paginator?.lastProps?.disabled;
15-
16-
const lastProps = {
17-
...paginator?.lastProps,
18-
'aria-label': paginator?.getAriaLabel('lastPageLabel'),
19-
disabled
20-
};
21-
22-
const disabledAttrs = disabled ? { 'data-disabled': '' as const } : {};
23-
24-
return { paginator, lastProps, disabledAttrs };
15+
return { paginator, disabled };
2516
},
2617
render(instance) {
27-
const { id, props, ptmi, paginator, lastProps, disabledAttrs } = instance;
18+
const { props, ptmi, paginator, disabled } = instance;
2819

29-
const disabled = lastProps?.disabled || props.disabled;
3020
const rootProps = mergeProps(
31-
lastProps,
32-
disabledAttrs,
21+
paginator?.lastProps,
3322
{
34-
id,
3523
className: paginator?.cx('last', { disabled }),
3624
disabled
3725
},

packages/primereact/src/paginator/next/PaginatorNext.tsx

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,17 @@ import { defaultNextProps } from './PaginatorNext.props';
88
export const PaginatorNext = withComponent({
99
name: 'Paginator.Next',
1010
defaultProps: defaultNextProps,
11-
setup() {
11+
setup({ props }) {
1212
const paginator = usePaginatorContext();
13+
const disabled = paginator?.nextProps?.disabled || props.disabled;
1314

14-
const disabled = paginator?.nextProps?.disabled;
15-
16-
const nextProps = {
17-
...paginator?.nextProps,
18-
'aria-label': paginator?.getAriaLabel('nextPageLabel'),
19-
disabled
20-
};
21-
22-
const disabledAttrs = disabled ? { 'data-disabled': '' as const } : {};
23-
24-
return { paginator, nextProps, disabledAttrs };
15+
return { paginator, disabled };
2516
},
2617
render(instance) {
27-
const { id, props, ptmi, paginator, nextProps, disabledAttrs } = instance;
18+
const { id, props, ptmi, paginator, disabled } = instance;
2819

29-
const disabled = nextProps?.disabled || props.disabled;
3020
const rootProps = mergeProps(
31-
nextProps,
32-
disabledAttrs,
21+
paginator?.nextProps,
3322
{
3423
id,
3524
className: paginator?.cx('next', { disabled }),

packages/primereact/src/paginator/page/PaginatorPage.tsx

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,35 +8,19 @@ import { defaultPageProps } from './PaginatorPage.props';
88
export const PaginatorPage = withComponent({
99
name: 'Paginator.Page',
1010
defaultProps: defaultPageProps,
11-
setup(instance) {
12-
const { props, $primereact } = instance;
11+
setup({ props }) {
1312
const paginator = usePaginatorContext();
14-
1513
const pageProps = props.value != null ? paginator?.getPageProps?.(props.value) : undefined;
1614
const disabled = pageProps?.disabled || props.disabled;
1715

18-
// @ts-expect-error - locale is not typed yet
19-
const ariaLabel = $primereact.config?.locale?.aria ? $primereact.config.locale.aria.pageLabel.replace(/{page}/g, props.value) : undefined;
20-
21-
const computedPageProps = {
22-
...pageProps,
23-
'aria-label': ariaLabel,
24-
disabled
25-
};
26-
27-
const disabledAttrs = disabled ? { 'data-disabled': '' as const } : {};
28-
29-
return { paginator, computedPageProps, disabledAttrs };
16+
return { paginator, pageProps, disabled };
3017
},
3118
render(instance) {
32-
const { id, props, ptmi, paginator, computedPageProps, disabledAttrs } = instance;
19+
const { props, ptmi, paginator, pageProps, disabled } = instance;
3320

34-
const disabled = computedPageProps?.disabled || props.disabled;
3521
const rootProps = mergeProps(
36-
computedPageProps,
37-
disabledAttrs,
22+
pageProps,
3823
{
39-
id,
4024
className: paginator?.cx('page', { selected: paginator?.state.activePage === props.value, disabled }),
4125
disabled
4226
},

packages/primereact/src/paginator/pages/PaginatorPages.tsx

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,14 @@ export const PaginatorPages = withComponent({
1111
setup() {
1212
const paginator = usePaginatorContext();
1313

14-
const pagesProps = {
15-
'data-scope': 'paginator' as const,
16-
'data-part': 'pages' as const,
17-
'aria-label': paginator?.getAriaLabel('pageLabel')
18-
};
19-
20-
return { paginator, pagesProps };
14+
return { paginator };
2115
},
2216
render(instance) {
23-
const { id, props, paginator, pagesProps, ptmi } = instance;
17+
const { props, paginator, ptmi } = instance;
2418

2519
const rootProps = mergeProps(
26-
pagesProps,
20+
paginator?.pagesProps,
2721
{
28-
id,
2922
className: paginator?.cx('pages')
3023
},
3124
paginator?.ptmi('pages'),

0 commit comments

Comments
 (0)