diff --git a/.changeset/cyan-deers-tap.md b/.changeset/cyan-deers-tap.md new file mode 100644 index 0000000000..df1fe92a72 --- /dev/null +++ b/.changeset/cyan-deers-tap.md @@ -0,0 +1,6 @@ +--- +"@heroui/calendar": patch +"@heroui/theme": patch +--- + +Fixed reversed navigation behavior of nextButton and prevButton in the RTL calendar. The buttons now correctly navigate to the next and previous months, ensuring consistent behavior across all locales and layouts. (#4541) diff --git a/packages/components/calendar/package.json b/packages/components/calendar/package.json index f0dfca3e8f..ace9deb518 100644 --- a/packages/components/calendar/package.json +++ b/packages/components/calendar/package.json @@ -35,7 +35,7 @@ }, "peerDependencies": { "@heroui/system": ">=2.4.0", - "@heroui/theme": ">=2.4.0", + "@heroui/theme": ">=2.4.7", "framer-motion": ">=11.5.6 || >=12.0.0-alpha.1", "react": ">=18 || >=19.0.0-rc.0", "react-dom": ">=18 || >=19.0.0-rc.0" diff --git a/packages/components/calendar/src/calendar-base.tsx b/packages/components/calendar/src/calendar-base.tsx index 439828f717..9fcef4cdd7 100644 --- a/packages/components/calendar/src/calendar-base.tsx +++ b/packages/components/calendar/src/calendar-base.tsx @@ -8,6 +8,7 @@ import {VisuallyHidden} from "@react-aria/visually-hidden"; import {Button} from "@heroui/button"; import {chain, mergeProps} from "@react-aria/utils"; import {AnimatePresence, LazyMotion, MotionConfig} from "framer-motion"; +import {useLocale} from "@react-aria/i18n"; import {ResizablePanel} from "@heroui/framer-utils"; import {ChevronLeftIcon} from "./chevron-left"; @@ -70,11 +71,15 @@ export function CalendarBase(props: CalendarBaseProps) { const [direction, setDirection] = useState(0); + const {direction: localeDirection} = useLocale(); + const currentMonth = state.visibleRange.start; const headers: React.ReactNode[] = []; const calendars: React.ReactNode[] = []; + const isRTL = localeDirection === "rtl"; + for (let i = 0; i < visibleMonths; i++) { let d = currentMonth.add({months: i}); @@ -82,8 +87,10 @@ export function CalendarBase(props: CalendarBaseProps) { {i === 0 && ( @@ -96,8 +103,10 @@ export function CalendarBase(props: CalendarBaseProps) { /> {i === visibleMonths - 1 && ( diff --git a/packages/components/calendar/src/use-calendar-base.ts b/packages/components/calendar/src/use-calendar-base.ts index a34300ad0a..9a669a490b 100644 --- a/packages/components/calendar/src/use-calendar-base.ts +++ b/packages/components/calendar/src/use-calendar-base.ts @@ -188,7 +188,9 @@ export function useCalendarBase(originalProps: UseCalendarBasePropsComplete) { const globalContext = useProviderContext(); - const {locale} = useLocale(); + const {locale, direction} = useLocale(); + + const isRTL = direction === "rtl"; const calendarProp = createCalendar(new DateFormatter(locale).resolvedOptions().calendar); @@ -261,6 +263,7 @@ export function useCalendarBase(originalProps: UseCalendarBasePropsComplete) { isRange: !!originalProps.isRange, isHeaderWrapperExpanded: isHeaderExpanded, className, + isRTL, }), [objectToDeps(variantProps), showMonthAndYearPickers, isHeaderExpanded, className], ); diff --git a/packages/core/theme/src/components/calendar.ts b/packages/core/theme/src/components/calendar.ts index 224002b373..8874a3e76c 100644 --- a/packages/core/theme/src/components/calendar.ts +++ b/packages/core/theme/src/components/calendar.ts @@ -148,12 +148,20 @@ const calendar = tv({ pickerItem: "transition-opacity", }, }, + isRTL: { + true: { + nextButton: "order-1", + prevButton: "order-3", + }, + false: {}, + }, }, defaultVariants: { color: "primary", showShadow: false, hideDisabledDates: false, showMonthAndYearPickers: false, + isRTL: false, }, compoundVariants: [ // !isRange & colors --> Calendar