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
This commit is contained in:
աӄա 2024-02-27 22:29:54 +08:00 committed by GitHub
parent 37bed2368e
commit dec7d411b5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 307 additions and 265 deletions

View File

@ -0,0 +1,6 @@
---
"@nextui-org/pagination": patch
"@nextui-org/use-pagination": patch
---
fixed inversed RTL pagination arrows (#2292)

View File

@ -48,6 +48,7 @@
"@react-aria/focus": "^3.14.3",
"@react-aria/interactions": "^3.19.1",
"@react-aria/utils": "^3.21.1",
"@react-aria/i18n": "^3.8.4",
"scroll-into-view-if-needed": "3.0.10"
},
"devDependencies": {

View File

@ -1,5 +1,6 @@
import {PaginationItemValue} from "@nextui-org/use-pagination";
import {useCallback} from "react";
import {useLocale} from "@react-aria/i18n";
import {forwardRef} from "@nextui-org/system";
import {PaginationItemType} from "@nextui-org/use-pagination";
import {ChevronIcon, EllipsisIcon, ForwardIcon} from "@nextui-org/shared-icons";
@ -35,6 +36,10 @@ const Pagination = forwardRef<"nav", PaginationProps>((props, ref) => {
getCursorProps,
} = usePagination({...props, ref});
const {direction} = useLocale();
const isRTL = direction === "rtl";
const renderItem = useCallback(
(value: PaginationItemValue, index: number) => {
const isBefore = index < range.indexOf(activePage);
@ -114,7 +119,7 @@ const Pagination = forwardRef<"nav", PaginationProps>((props, ref) => {
})}
data-slot="prev"
getAriaLabel={getItemAriaLabel}
isDisabled={!loop && activePage === 1}
isDisabled={!loop && activePage === (isRTL ? total : 1)}
value={value}
onPress={onPrevious}
>
@ -131,7 +136,7 @@ const Pagination = forwardRef<"nav", PaginationProps>((props, ref) => {
})}
data-slot="next"
getAriaLabel={getItemAriaLabel}
isDisabled={!loop && activePage === total}
isDisabled={!loop && activePage === (isRTL ? 1 : total)}
value={value}
onPress={onNext}
>
@ -163,7 +168,7 @@ const Pagination = forwardRef<"nav", PaginationProps>((props, ref) => {
<EllipsisIcon className={slots?.ellipsis({class: classNames?.ellipsis})} />
<ForwardIcon
className={slots?.forwardIcon({class: classNames?.forwardIcon})}
data-before={dataAttr(isBefore)}
data-before={dataAttr(isRTL ? !isBefore : isBefore)}
/>
</PaginationItem>
);
@ -175,7 +180,18 @@ const Pagination = forwardRef<"nav", PaginationProps>((props, ref) => {
</PaginationItem>
);
},
[activePage, dotsJump, getItemProps, loop, range, renderItemProp, slots, classNames, total],
[
isRTL,
activePage,
dotsJump,
getItemProps,
loop,
range,
renderItemProp,
slots,
classNames,
total,
],
);
return (

View File

@ -3,6 +3,7 @@ import type {Timer} from "@nextui-org/shared-utils";
import type {Key, ReactNode, Ref} from "react";
import type {HTMLNextUIProps, PropGetter} from "@nextui-org/system";
import {useLocale} from "@react-aria/i18n";
import {
UsePaginationProps as UseBasePaginationProps,
PaginationItemValue,
@ -191,6 +192,10 @@ export function usePagination(originalProps: UsePaginationProps) {
const cursorTimer = useRef<Timer>();
const {direction} = useLocale();
const isRTL = direction === "rtl";
function getItemsRefMap() {
if (!itemsRef.current) {
// Initialize the Map on first usage.
@ -296,7 +301,7 @@ export function usePagination(originalProps: UsePaginationProps) {
const baseStyles = clsx(classNames?.base, className);
const onNext = () => {
if (loop && activePage === total) {
if (loop && activePage === (isRTL ? 1 : total)) {
return first();
}
@ -304,7 +309,7 @@ export function usePagination(originalProps: UsePaginationProps) {
};
const onPrevious = () => {
if (loop && activePage === 1) {
if (loop && activePage === (isRTL ? total : 1)) {
return last();
}

View File

@ -34,7 +34,8 @@
"postpack": "clean-package restore"
},
"dependencies": {
"@nextui-org/shared-utils": "workspace:*"
"@nextui-org/shared-utils": "workspace:*",
"@react-aria/i18n": "^3.8.4"
},
"peerDependencies": {
"react": ">=18"

View File

@ -1,4 +1,5 @@
import {useMemo, useCallback, useState, useEffect} from "react";
import {useLocale} from "@react-aria/i18n";
import {range} from "@nextui-org/shared-utils";
export enum PaginationItemType {
@ -56,6 +57,10 @@ export function usePagination(props: UsePaginationProps) {
} = props;
const [activePage, setActivePage] = useState(page || initialPage);
const {direction} = useLocale();
const isRTL = direction === "rtl";
const onChangeActivePage = (newPage: number) => {
setActivePage(newPage);
onChange && onChange(newPage);
@ -80,20 +85,22 @@ export function usePagination(props: UsePaginationProps) {
[total, activePage],
);
const next = () => setPage(activePage + 1);
const previous = () => setPage(activePage - 1);
const first = () => setPage(1);
const last = () => setPage(total);
const next = () => (isRTL ? setPage(activePage - 1) : setPage(activePage + 1));
const previous = () => (isRTL ? setPage(activePage + 1) : setPage(activePage - 1));
const first = () => (isRTL ? setPage(total) : setPage(1));
const last = () => (isRTL ? setPage(1) : setPage(total));
const formatRange = useCallback(
(range: PaginationItemValue[]) => {
if (showControls) {
return [PaginationItemType.PREV, ...range, PaginationItemType.NEXT];
return isRTL
? [PaginationItemType.NEXT, ...range, PaginationItemType.PREV]
: [PaginationItemType.PREV, ...range, PaginationItemType.NEXT];
}
return range;
},
[showControls],
[isRTL, showControls],
);
const paginationRange = useMemo((): PaginationItemValue[] => {

510
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff