Skip to content

Commit dec7d41

Browse files
authored
fix: pagination RTL (#2393)
* fix(components): handle RTL in onNext and onPrevious in use-pagination.ts * fix(components): invert forward icon for RTL * fix(hooks): invert pagination logic for RTL * chore(root): add changeset for pagination RTL change * fix(hooks): add isRTL to hook dependency * fix(components): add isRTL to hook dependency * fix(components): incorrect isDisabled logic * refactor(hooks): remove isRTL dependency from paginationRange * chore(deps): add @react-aria/i18n
1 parent 37bed23 commit dec7d41

File tree

7 files changed

+307
-265
lines changed

7 files changed

+307
-265
lines changed

.changeset/strange-onions-bow.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@nextui-org/pagination": patch
3+
"@nextui-org/use-pagination": patch
4+
---
5+
6+
fixed inversed RTL pagination arrows (#2292)

packages/components/pagination/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
"@react-aria/focus": "^3.14.3",
4949
"@react-aria/interactions": "^3.19.1",
5050
"@react-aria/utils": "^3.21.1",
51+
"@react-aria/i18n": "^3.8.4",
5152
"scroll-into-view-if-needed": "3.0.10"
5253
},
5354
"devDependencies": {

packages/components/pagination/src/pagination.tsx

+20-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {PaginationItemValue} from "@nextui-org/use-pagination";
22
import {useCallback} from "react";
3+
import {useLocale} from "@react-aria/i18n";
34
import {forwardRef} from "@nextui-org/system";
45
import {PaginationItemType} from "@nextui-org/use-pagination";
56
import {ChevronIcon, EllipsisIcon, ForwardIcon} from "@nextui-org/shared-icons";
@@ -35,6 +36,10 @@ const Pagination = forwardRef<"nav", PaginationProps>((props, ref) => {
3536
getCursorProps,
3637
} = usePagination({...props, ref});
3738

39+
const {direction} = useLocale();
40+
41+
const isRTL = direction === "rtl";
42+
3843
const renderItem = useCallback(
3944
(value: PaginationItemValue, index: number) => {
4045
const isBefore = index < range.indexOf(activePage);
@@ -114,7 +119,7 @@ const Pagination = forwardRef<"nav", PaginationProps>((props, ref) => {
114119
})}
115120
data-slot="prev"
116121
getAriaLabel={getItemAriaLabel}
117-
isDisabled={!loop && activePage === 1}
122+
isDisabled={!loop && activePage === (isRTL ? total : 1)}
118123
value={value}
119124
onPress={onPrevious}
120125
>
@@ -131,7 +136,7 @@ const Pagination = forwardRef<"nav", PaginationProps>((props, ref) => {
131136
})}
132137
data-slot="next"
133138
getAriaLabel={getItemAriaLabel}
134-
isDisabled={!loop && activePage === total}
139+
isDisabled={!loop && activePage === (isRTL ? 1 : total)}
135140
value={value}
136141
onPress={onNext}
137142
>
@@ -163,7 +168,7 @@ const Pagination = forwardRef<"nav", PaginationProps>((props, ref) => {
163168
<EllipsisIcon className={slots?.ellipsis({class: classNames?.ellipsis})} />
164169
<ForwardIcon
165170
className={slots?.forwardIcon({class: classNames?.forwardIcon})}
166-
data-before={dataAttr(isBefore)}
171+
data-before={dataAttr(isRTL ? !isBefore : isBefore)}
167172
/>
168173
</PaginationItem>
169174
);
@@ -175,7 +180,18 @@ const Pagination = forwardRef<"nav", PaginationProps>((props, ref) => {
175180
</PaginationItem>
176181
);
177182
},
178-
[activePage, dotsJump, getItemProps, loop, range, renderItemProp, slots, classNames, total],
183+
[
184+
isRTL,
185+
activePage,
186+
dotsJump,
187+
getItemProps,
188+
loop,
189+
range,
190+
renderItemProp,
191+
slots,
192+
classNames,
193+
total,
194+
],
179195
);
180196

181197
return (

packages/components/pagination/src/use-pagination.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type {Timer} from "@nextui-org/shared-utils";
33
import type {Key, ReactNode, Ref} from "react";
44
import type {HTMLNextUIProps, PropGetter} from "@nextui-org/system";
55

6+
import {useLocale} from "@react-aria/i18n";
67
import {
78
UsePaginationProps as UseBasePaginationProps,
89
PaginationItemValue,
@@ -191,6 +192,10 @@ export function usePagination(originalProps: UsePaginationProps) {
191192

192193
const cursorTimer = useRef<Timer>();
193194

195+
const {direction} = useLocale();
196+
197+
const isRTL = direction === "rtl";
198+
194199
function getItemsRefMap() {
195200
if (!itemsRef.current) {
196201
// Initialize the Map on first usage.
@@ -296,15 +301,15 @@ export function usePagination(originalProps: UsePaginationProps) {
296301
const baseStyles = clsx(classNames?.base, className);
297302

298303
const onNext = () => {
299-
if (loop && activePage === total) {
304+
if (loop && activePage === (isRTL ? 1 : total)) {
300305
return first();
301306
}
302307

303308
return next();
304309
};
305310

306311
const onPrevious = () => {
307-
if (loop && activePage === 1) {
312+
if (loop && activePage === (isRTL ? total : 1)) {
308313
return last();
309314
}
310315

packages/hooks/use-pagination/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@
3434
"postpack": "clean-package restore"
3535
},
3636
"dependencies": {
37-
"@nextui-org/shared-utils": "workspace:*"
37+
"@nextui-org/shared-utils": "workspace:*",
38+
"@react-aria/i18n": "^3.8.4"
3839
},
3940
"peerDependencies": {
4041
"react": ">=18"

packages/hooks/use-pagination/src/index.ts

+13-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {useMemo, useCallback, useState, useEffect} from "react";
2+
import {useLocale} from "@react-aria/i18n";
23
import {range} from "@nextui-org/shared-utils";
34

45
export enum PaginationItemType {
@@ -56,6 +57,10 @@ export function usePagination(props: UsePaginationProps) {
5657
} = props;
5758
const [activePage, setActivePage] = useState(page || initialPage);
5859

60+
const {direction} = useLocale();
61+
62+
const isRTL = direction === "rtl";
63+
5964
const onChangeActivePage = (newPage: number) => {
6065
setActivePage(newPage);
6166
onChange && onChange(newPage);
@@ -80,20 +85,22 @@ export function usePagination(props: UsePaginationProps) {
8085
[total, activePage],
8186
);
8287

83-
const next = () => setPage(activePage + 1);
84-
const previous = () => setPage(activePage - 1);
85-
const first = () => setPage(1);
86-
const last = () => setPage(total);
88+
const next = () => (isRTL ? setPage(activePage - 1) : setPage(activePage + 1));
89+
const previous = () => (isRTL ? setPage(activePage + 1) : setPage(activePage - 1));
90+
const first = () => (isRTL ? setPage(total) : setPage(1));
91+
const last = () => (isRTL ? setPage(1) : setPage(total));
8792

8893
const formatRange = useCallback(
8994
(range: PaginationItemValue[]) => {
9095
if (showControls) {
91-
return [PaginationItemType.PREV, ...range, PaginationItemType.NEXT];
96+
return isRTL
97+
? [PaginationItemType.NEXT, ...range, PaginationItemType.PREV]
98+
: [PaginationItemType.PREV, ...range, PaginationItemType.NEXT];
9299
}
93100

94101
return range;
95102
},
96-
[showControls],
103+
[isRTL, showControls],
97104
);
98105

99106
const paginationRange = useMemo((): PaginationItemValue[] => {

0 commit comments

Comments
 (0)