ui icon indicating copy to clipboard operation
ui copied to clipboard

[bug]: Calender UI is messed up after updating to react-day-picker

Open HamidShaikh1499 opened this issue 1 year ago • 19 comments

Describe the bug

Calender component has issue i updated react-day-picker then issue appeared. UI of calender is messed up terible UI.

Look on following image:

image

I am using NextJs14 and problem version of react-day-picker is ^9.3.0

Another thing i noticed that the dev of react-day-picker has changed something on it like currently i am getting error on image

Thanks @shadcn

Affected component/components

Calender Component

How to reproduce

Just update react-day-picker to latest version that is 9.3.0

Codesandbox/StackBlitz link

No response

Logs

No response

System Info

Windows 10
NextJs14

Before submitting

  • [X] I've made research efforts and searched the documentation
  • [X] I've searched for existing issues

HamidShaikh1499 avatar Nov 11 '24 16:11 HamidShaikh1499

Same issue

kamami avatar Nov 12 '24 10:11 kamami

@kamami, just downgrade react-day-picker version. Still i am using old version of it. Use version 8.X.X then calender will look good.

hamidradical avatar Nov 12 '24 10:11 hamidradical

@kamami, just downgrade react-day-picker version. Still i am using old version of it. Use version 8.X.X then calender will look good.

I would like to, but I need the new UTC support of react-day-picker v9...

kamami avatar Nov 12 '24 10:11 kamami

Let me try to fix and if i will fix it then generate PR.

hamidradical avatar Nov 12 '24 10:11 hamidradical

It looks like you have date-fns v4 in your package.json, but this code requires v3.

If you'd prefer to use the latest version, you might consider using an alternative component designed for v4 compatibility and UTC support. https://shadcn-datetime-picker-pro.vercel.app/?path=/story/datetimepicker--timezone https://github.com/huybuidac/shadcn-datetime-picker

huybuidac avatar Nov 12 '24 13:11 huybuidac

There are already 2 or 3 PR's addressing this

Sparticuz avatar Nov 12 '24 14:11 Sparticuz

Any update please ?

cuonggoaptive avatar Nov 14 '24 14:11 cuonggoaptive

I have fixed it temporary, here the code:

function Calendar({
  className,
  classNames,
  showOutsideDays = true,
  ...props
}: CalendarProps) {
  return (
    <DayPicker
      showOutsideDays={showOutsideDays}
      className={cn('p-3', className)}
      classNames={{
        months: 'flex flex-col relative',
        month_caption: 'flex justify-center h-7 mx-10 relative items-center',
        weekdays: 'flex flex-row',
        weekday: 'text-muted-foreground w-8 font-normal text-[0.8rem]',
        month: 'gap-y-4 overflow-x-hidden w-full',
        caption: 'flex justify-center pt-1 relative items-center',
        caption_label: 'text-sm font-medium truncate',
        button_next: cn(
          buttonVariants({
            variant: 'outline',
            className:
              'absolute right-0 h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',
          }),
        ),
        button_previous: cn(
          buttonVariants({
            variant: 'outline',
            className:
              'absolute left-0 h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',
          }),
        ),
        nav: 'flex items-start justify-between absolute w-full',
        month_grid: 'mt-4',
        week: 'flex w-full mt-2',
        day: 'p-0 size-8 text-sm flex-1 flex items-center justify-center has-[button]:hover:!bg-accent rounded-md has-[button]:hover:aria-selected:!bg-primary has-[button]:hover:text-accent-foreground has-[button]:hover:aria-selected:text-primary-foreground',
        day_button: cn(
          buttonVariants({ variant: 'ghost' }),
          'size-8 p-0 font-normal transition-none hover:bg-transparent hover:text-inherit aria-selected:opacity-100',
        ),
        range_start: 'day-range-start rounded-s-md',
        range_end: 'day-range-end rounded-e-md',
        selected:
          'bg-primary text-primary-foreground hover:!bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground',
        today: 'bg-accent text-accent-foreground',
        outside:
          'day-outside text-muted-foreground opacity-50 aria-selected:bg-accent/50 aria-selected:text-muted-foreground aria-selected:opacity-30',
        disabled: 'text-muted-foreground opacity-50',
        range_middle:
          'aria-selected:bg-accent hover:aria-selected:!bg-accent rounded-none aria-selected:text-accent-foreground hover:aria-selected:text-accent-foreground',
        hidden: 'invisible',
        ...classNames,
      }}
      components={{
        PreviousMonthButton: ({ ...props }) => (
          <div>
            <ChevronLeft className="h-4 w-4 cursor-pointer" />
          </div>
        ),
        NextMonthButton: ({ ...props }) => (
          <div>
            <ChevronRight className="h-4 w-4 cursor-pointer" />
          </div>
        ),
      }}
      {...props}
    />
  );
}
Calendar.displayName = 'Calendar';

export { Calendar };

And

import React from 'react';

import { format, subMonths, addMonths } from 'date-fns';
import { CalendarIcon, XIcon } from 'lucide-react';

import { cn } from '../../../lib/utils';
import ArrowNarrowLeft from '../Icon/ArrowNarrowLeft';
import ArrowNarrowRight from '../Icon/ArrowNarrowRight';
import { Button } from '../ui/button';
import { Calendar } from '../ui/calendar';
import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover';

export interface DatepickerProps {
  title?: string | React.ReactNode;
  minDate?: string;
  maxDate?: string;
  getSelectedDate?: (date: Date) => void;
}

const Datepicker: React.FC<DatepickerProps> = ({
  title,
  getSelectedDate,
  minDate = new Date('11/11/1991'),
  maxDate = new Date('11/11/3059'),
}) => {
  const [date, setDate] = React.useState<Date | undefined>();
  const [isCalendarOpen, setIsCalendarOpen] = React.useState(false);
  const [month, setMonth] = React.useState(new Date());

  const onSelect = (date: Date | undefined) => {
    if (date) {
      setDate(date);
      getSelectedDate && getSelectedDate(date);
    }
  };

  const onHandleClear = () => {
    setIsCalendarOpen(false);
    setDate(undefined);
  };

  const onHandleOpenChangePopover = (isOpen: boolean) => {
    setIsCalendarOpen(isOpen);
  };

  const onClickCancel = () => {
    setIsCalendarOpen(false);
    setDate(undefined);
  };

  const onHandleApply = () => {
    setIsCalendarOpen(false);
  };

  const onClickCalendarIcon = () => {
    setIsCalendarOpen(true);
  };

  const handlePrevMonthClick = () => {
    setMonth(subMonths(month, 1));
  };

  const handleNextMonthClick = () => {
    setMonth(addMonths(month, 1));
  };

  return (
    <div>
      {title && (
        <div className="text-[14px] leading-[16px] font-normal text-[#4B5563] mb-[4px]">
          {title}
        </div>
      )}
      <div className="flex h-[38px] border border-[#E5E7EB] overflow-hidden rounded-[4px]">
        <Popover open={isCalendarOpen} onOpenChange={onHandleOpenChangePopover}>
          <PopoverTrigger asChild>
            <Button
              variant={'outline'}
              className={cn(
                'w-full h-[38px] justify-between font-normal p-[0px] pl-[12px] overflow-hidden border-none',
                !date && 'text-muted-foreground',
              )}
            >
              {date ? (
                format(date, 'dd-mm-yyyy')
              ) : (
                <span className="text-[#A9A9A9] text-[14px] leading-[16px]">
                  DD-MM-YYYY
                </span>
              )}
            </Button>
          </PopoverTrigger>
          <PopoverContent className="w-auto rounded-none shadow-none p-[0px]">
            <div>
              <div className="border-b pt-[6px] pl-[12px] pr-[12px]">
                <Calendar
                  month={month}
                  mode="single"
                  selected={date}
                  onSelect={onSelect}
                  autoFocus
                  hidden={{
                    before: new Date(minDate),
                    after: new Date(maxDate),
                  }}
                  components={{
                    PreviousMonthButton: ({ ...props }) => (
                      <div onClick={handlePrevMonthClick}>
                        <ArrowNarrowLeft />
                      </div>
                    ),
                    NextMonthButton: ({ ...props }) => (
                      <div onClick={handleNextMonthClick}>
                        <ArrowNarrowRight />
                      </div>
                    ),
                  }}
                />
              </div>
              <div className="flex justify-end items-center pt-[18px] pb-[18px] pr-[24px] pl-[24px]">
                <Button
                  onClick={onClickCancel}
                  variant={'outline'}
                  className="rounded-8px h-[36px] pr-[20px] pl-[20px] pt-[10px] pb-[10px] text-[14px] leading-[16px] text-[#4B5563] border-[#D1D5DB] border"
                >
                  Cancel
                </Button>

                <Button
                  onClick={onHandleApply}
                  className="ml-[16px] h-[36px] rounded-8px bg-[#007AFF] text-[white] pr-[20px] pl-[20px] pt-[10px] pb-[10px] text-[14px] leading-[16px]"
                >
                  Apply
                </Button>
              </div>
            </div>
          </PopoverContent>
        </Popover>
        <div className="w-[80px] h-full bg-[#F9FAFB] flex justify-center items-center border-l pl-[15px] pr-[15px]">
          {date && (
            <XIcon
              onClick={onHandleClear}
              className="h-[20px] mr-[4px] w-[20px] text-[#9CA3AF] cursor-pointer"
            />
          )}
          <CalendarIcon
            onClick={onClickCalendarIcon}
            className="h-[20px] ml-[4px] w-[20px] text-[#9CA3AF] cursor-pointer"
          />
        </div>
      </div>
    </div>
  );
};

export default Datepicker;

cuonggoaptive avatar Nov 14 '24 14:11 cuonggoaptive

Same issue here with version 9.3.2. I had to fix the components property in Shad CN's calendar but then the styling is all off.

everspader avatar Nov 22 '24 09:11 everspader

you guys can use sippet provide by Yoon Han here https://github.com/shadcn-ui/ui/issues/1574 or

"use client";

import {
  ChevronDownIcon,
  ChevronLeftIcon,
  ChevronRightIcon,
  ChevronUpIcon,
} from "lucide-react";
import * as React from "react";
import { DayFlag, DayPicker, SelectionState, UI } from "react-day-picker";

import { cn } from "@/lib/utils";
import { buttonVariants } from "./button";

export type CalendarProps = React.ComponentProps<typeof DayPicker>;

export const Calendar = ({
  className,
  classNames,
  showOutsideDays = true,
  ...props
}: CalendarProps) => {
  return (
    <DayPicker
      showOutsideDays={showOutsideDays}
      className={cn("p-3", className)}
      classNames={{
        [UI.Months]: "relative",
        [UI.Month]: "space-y-4 ml-0",
        [UI.MonthCaption]: "flex justify-center items-center h-7",
        [UI.CaptionLabel]: "text-sm font-medium",
        [UI.PreviousMonthButton]: cn(
          buttonVariants({ variant: "outline" }),
          "absolute left-1 top-0 h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100",
        ),
        [UI.NextMonthButton]: cn(
          buttonVariants({ variant: "outline" }),
          "absolute right-1 top-0 h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100",
        ),
        [UI.MonthGrid]: "w-full border-collapse space-y-1",
        [UI.Weekdays]: "flex",
        [UI.Weekday]:
          "text-muted-foreground rounded-md w-9 font-normal text-[0.8rem]",
        [UI.Week]: "flex w-full mt-2",
        [UI.Day]:
          "h-9 w-9 text-center rounded-md text-sm p-0 relative [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20",
        [UI.DayButton]: cn(
          buttonVariants({ variant: "ghost" }),
          "h-9 w-9 p-0 font-normal aria-selected:opacity-100 hover:bg-primary hover:text-primary-foreground",
        ),
        [SelectionState.range_end]: "day-range-end",
        [SelectionState.selected]:
          "bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground",
        [SelectionState.range_middle]:
          "aria-selected:bg-accent aria-selected:text-accent-foreground",
        [DayFlag.today]: "bg-accent text-accent-foreground",
        [DayFlag.outside]:
          "day-outside text-muted-foreground opacity-50 aria-selected:bg-accent/50 aria-selected:text-muted-foreground aria-selected:opacity-30",
        [DayFlag.disabled]: "text-muted-foreground opacity-50",
        [DayFlag.hidden]: "invisible",
        ...classNames,
      }}
      components={{
        Chevron: ({ ...props }) => <Chevron {...props} />,
      }}
      {...props}
    />
  );
};

const Chevron = ({ orientation = "left" }) => {
  switch (orientation) {
    case "left":
      return <ChevronLeftIcon className="h-4 w-4" />;
    case "right":
      return <ChevronRightIcon className="h-4 w-4" />;
    case "up":
      return <ChevronUpIcon className="h-4 w-4" />;
    case "down":
      return <ChevronDownIcon className="h-4 w-4" />;
    default:
      return null;
  }
};


sibteali786 avatar Dec 03 '24 08:12 sibteali786

@shadcn i think it would be better if docs are updated with this as it took my whole day today figuring this out. Also please refer the repo where the docs can be updated i am up for it. Thanks

sibteali786 avatar Dec 03 '24 08:12 sibteali786

typesafe version:

import { ChevronProps } from "react-day-picker";

import { ChevronDown, ChevronLeft, ChevronRight, ChevronUp } from "lucide-react";

const Chevron = ({ orientation }: ChevronProps) => {
	if (orientation === "up") {
		return <ChevronUp className="h-4 w-4" />;
	}
	if (orientation === "down") {
		return <ChevronDown className="h-4 w-4" />;
	}
	if (orientation === "right") {
		return <ChevronRight className="h-4 w-4" />;
	}
	return <ChevronLeft className="h-4 w-4" />;
};

Goldziher avatar Dec 17 '24 19:12 Goldziher

This is a temporary solution:


import { ChevronLeft, ChevronRight } from 'lucide-react';
import * as React from 'react';
import { DayFlag, DayPicker, SelectionState, UI } from 'react-day-picker';

import { buttonVariants } from '@/shared/ui/presentation/components/button';
import { cn } from '@/shared/ui/services/utils';

export type CalendarProps = React.ComponentProps<typeof DayPicker>;

function Calendar({
  className,
  classNames,
  showOutsideDays = true,
  ...props
}: CalendarProps) {
  return (
    <DayPicker
      showOutsideDays={showOutsideDays}
      className={cn('p-3', className)}
      /*  classNames={{
        
        months:
          'flex flex-col relative sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0',
        month: 'space-y-4 ',
        month_caption: 'flex justify-center items-center',
        caption_label: 'text-sm font-medium',
        nav: 'space-x-1 flex items-center',
        button_previous: cn(
          buttonVariants({ variant: 'outline' }),
          'absolute left-9 top-3 h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',
        ),
        button_next: cn(
          buttonVariants({ variant: 'outline' }),
          'absolute right-9 top-3 h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',
        ),
        month_grid: 'w-full border-collapse space-y-1',
        weekdays: 'flex',
        weekday:
          'text-muted-foreground rounded-md w-9 font-normal text-[0.8rem]',
        week: 'flex w-full mt-2',
        day: 'h-9 w-9 text-center rounded-md text-sm p-0 relative [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20',
        day_button: cn(
          buttonVariants({ variant: 'ghost' }),
          'h-9 w-9 p-0 font-normal aria-selected:opacity-100',
        ),
        range_end: 'day-range-end',
        selected:
          'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground',
        today: 'bg-accent text-accent-foreground',
        outside:
          'day-outside text-muted-foreground opacity-50 aria-selected:bg-accent/50 aria-selected:text-muted-foreground aria-selected:opacity-30',
        disabled: 'text-muted-foreground opacity-50',
        range_middle:
          'aria-selected:bg-accent aria-selected:text-accent-foreground',
        hidden: 'invisible',
        ...classNames,
      }} */
      classNames={{
        [UI.Months]: 'relative',
        [UI.Month]: 'space-y-4 ml-0',
        [UI.MonthCaption]: 'flex justify-center items-center h-7',
        [UI.CaptionLabel]: 'text-sm font-medium',
        [UI.PreviousMonthButton]: cn(
          buttonVariants({ variant: 'outline' }),
          'absolute left-1 top-0 h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',
        ),
        [UI.NextMonthButton]: cn(
          buttonVariants({ variant: 'outline' }),
          'absolute right-1 top-0 h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',
        ),
        [UI.MonthGrid]: 'w-full border-collapse space-y-1',
        [UI.Weekdays]: 'flex',
        [UI.Weekday]:
          'text-muted-foreground rounded-md w-9 font-normal text-[0.8rem]',
        [UI.Week]: 'flex w-full mt-2',
        [UI.Day]:
          'h-9 w-9 text-center rounded-md text-sm p-0 relative [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20',
        [UI.DayButton]: cn(
          buttonVariants({ variant: 'ghost' }),
          'h-9 w-9 p-0 font-normal aria-selected:opacity-100 hover:bg-primary hover:text-primary-foreground',
        ),
        [SelectionState.range_end]: 'day-range-end',
        [SelectionState.selected]:
          'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground',
        [SelectionState.range_middle]:
          'aria-selected:bg-accent aria-selected:text-accent-foreground',
        [DayFlag.today]: 'bg-accent text-accent-foreground',
        [DayFlag.outside]:
          'day-outside text-muted-foreground opacity-50 aria-selected:bg-accent/50 aria-selected:text-muted-foreground aria-selected:opacity-30',
        [DayFlag.disabled]: 'text-muted-foreground opacity-50',
        [DayFlag.hidden]: 'invisible',
        ...classNames,
      }}
      components={{
        // @ts-expect-error https://github.com/shadcn-ui/ui/issues/5799
        IconLeft: ({ className, ...props }) => (
          <ChevronLeft className={cn('h-4 w-4', className)} {...props} />
        ),
        // @ts-expect-error https://github.com/shadcn-ui/ui/issues/5799
        IconRight: ({ className, ...props }) => (
          <ChevronRight className={cn('h-4 w-4', className)} {...props} />
        ),
      }}
      {...props}
    />
  );
}
Calendar.displayName = 'Calendar';

export { Calendar };

Be sure to update the imports.

david-github-repo avatar Jan 01 '25 12:01 david-github-repo

When will be there an official update of the component?

kamami avatar Jan 02 '25 10:01 kamami

I am having the same issue. Any update on when an official update will be available?

joselvelez avatar Jan 17 '25 10:01 joselvelez

Just checking in to see if there has been an update. Please do not close this.

joselvelez avatar Feb 06 '25 20:02 joselvelez

same problem here

johnalxndr avatar Feb 20 '25 12:02 johnalxndr

bump pls fix

rinmeng avatar Mar 10 '25 10:03 rinmeng

Can someone validate that the fix I used:

import * as React from "react"
import { DayPicker } from "react-day-picker"
import { ChevronLeftIcon, ChevronRightIcon } from "@radix-ui/react-icons"

import { cn } from "@/lib/utils"
import { buttonVariants } from "@/components/ui/button"

export type CalendarProps = React.ComponentProps<typeof DayPicker>

function Calendar({
  className,
  classNames,
  showOutsideDays = true,
  ...props
}: CalendarProps) {
  return (
    <DayPicker
      showOutsideDays={showOutsideDays}
      className={cn("p-3", className)}
      classNames={{
        months: "flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0",
        month: "space-y-4",
        caption: "flex justify-center pt-1 relative items-center",
        caption_label: "text-sm font-medium",
        nav: "space-x-1 flex items-center",
        nav_button: cn(
          buttonVariants({ variant: "outline" }),
          "h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100"
        ),
        nav_button_previous: "absolute left-1",
        nav_button_next: "absolute right-1",
        table: "w-full border-collapse space-y-1",
        head_row: "flex",
        head_cell:
          "text-muted-foreground rounded-md w-8 font-normal text-[0.8rem]",
        row: "flex w-full mt-2",
        cell: cn(
          "relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([aria-selected])]:bg-accent [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected].day-range-end)]:rounded-r-md",
          props.mode === "range"
            ? "[&:has(>.day-range-end)]:rounded-r-md [&:has(>.day-range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md"
            : "[&:has([aria-selected])]:rounded-md"
        ),
        day: cn(
          buttonVariants({ variant: "ghost" }),
          "h-8 w-8 p-0 font-normal aria-selected:opacity-100"
        ),
        day_range_start: "day-range-start",
        day_range_end: "day-range-end",
        day_selected:
          "bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground",
        day_today: "bg-accent text-accent-foreground",
        day_outside:
          "day-outside text-muted-foreground aria-selected:bg-accent/50 aria-selected:text-muted-foreground",
        day_disabled: "text-muted-foreground opacity-50",
        day_range_middle:
          "aria-selected:bg-accent aria-selected:text-accent-foreground",
        day_hidden: "invisible",
        ...classNames,
      }}
      components={{
        IconLeft: ({ className }) => (
          <ChevronLeftIcon className={cn("h-4 w-4", className)} />
        ),
        IconRight: ({ className }) => (
          <ChevronRightIcon className={cn("h-4 w-4", className)} />
        ),
      }}
      {...props}
    />
  )
}
Calendar.displayName = "Calendar"

export { Calendar }

This seems to work for me removing the ...props spread but may not be correct

kryptobaseddev avatar Mar 18 '25 01:03 kryptobaseddev

I can confirm that the issue still occurs in the latest versions of shadcn/react-day-picker looking very similar to the images from July 2024.

The solution by sibteali786 copied below fixed it. With this solution I had no styling issues.

Versions used:

  • "react-day-picker": "^9.6.4"
  • "date-fns": "^4.1.0"
  • @latest shadcn button

Before: Image

After: Image

"use client";

import {
  ChevronDownIcon,
  ChevronLeftIcon,
  ChevronRightIcon,
  ChevronUpIcon,
} from "lucide-react";
import * as React from "react";
import { DayFlag, DayPicker, SelectionState, UI } from "react-day-picker";

import { cn } from "@/lib/utils";
import { buttonVariants } from "./button";


export type CalendarProps = React.ComponentProps<typeof DayPicker>;

export const Calendar = ({
  className,
  classNames,
  showOutsideDays = true,
  ...props
}: CalendarProps) => {
  return (
    <DayPicker
      showOutsideDays={showOutsideDays}
      className={cn("p-3", className)}
      classNames={{
        [UI.Months]: "relative",
        [UI.Month]: "space-y-4 ml-0",
        [UI.MonthCaption]: "flex justify-center items-center h-7",
        [UI.CaptionLabel]: "text-sm font-medium",
        [UI.PreviousMonthButton]: cn(
          buttonVariants({ variant: "outline" }),
          "absolute left-1 top-0 h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100",
        ),
        [UI.NextMonthButton]: cn(
          buttonVariants({ variant: "outline" }),
          "absolute right-1 top-0 h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100",
        ),
        [UI.MonthGrid]: "w-full border-collapse space-y-1",
        [UI.Weekdays]: "flex",
        [UI.Weekday]:
          "text-muted-foreground rounded-md w-9 font-normal text-[0.8rem]",
        [UI.Week]: "flex w-full mt-2",
        [UI.Day]:
          "h-9 w-9 text-center rounded-md text-sm p-0 relative [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20",
        [UI.DayButton]: cn(
          buttonVariants({ variant: "ghost" }),
          "h-9 w-9 p-0 font-normal aria-selected:opacity-100 hover:bg-primary hover:text-primary-foreground",
        ),
        [SelectionState.range_end]: "day-range-end",
        [SelectionState.selected]:
          "bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground",
        [SelectionState.range_middle]:
          "aria-selected:bg-accent aria-selected:text-accent-foreground",
        [DayFlag.today]: "bg-accent text-accent-foreground",
        [DayFlag.outside]:
          "day-outside text-muted-foreground opacity-50 aria-selected:bg-accent/50 aria-selected:text-muted-foreground aria-selected:opacity-30",
        [DayFlag.disabled]: "text-muted-foreground opacity-50",
        [DayFlag.hidden]: "invisible",
        ...classNames,
      }}
      components={{
        Chevron: ({ ...props }) => <Chevron {...props} />,
      }}
      {...props}
    />
  );
};

const Chevron = ({ orientation = "left" }) => {
  switch (orientation) {
    case "left":
      return <ChevronLeftIcon className="h-4 w-4" />;
    case "right":
      return <ChevronRightIcon className="h-4 w-4" />;
    case "up":
      return <ChevronUpIcon className="h-4 w-4" />;
    case "down":
      return <ChevronDownIcon className="h-4 w-4" />;
    default:
      return null;
  }
};

liawagner avatar Apr 04 '25 06:04 liawagner

"use client";

import { ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, } from "lucide-react"; import * as React from "react"; import { DayFlag, DayPicker, SelectionState, UI } from "react-day-picker";

import { cn } from "@/lib/utils"; import { buttonVariants } from "./button";

export type CalendarProps = React.ComponentProps<typeof DayPicker>;

export const Calendar = ({ className, classNames, showOutsideDays = true, ...props }: CalendarProps) => { return ( <DayPicker showOutsideDays={showOutsideDays} className={cn("p-3", className)} classNames={{ [UI.Months]: "relative", [UI.Month]: "space-y-4 ml-0", [UI.MonthCaption]: "flex justify-center items-center h-7", [UI.CaptionLabel]: "text-sm font-medium", [UI.PreviousMonthButton]: cn( buttonVariants({ variant: "outline" }), "absolute left-1 top-0 h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100", ), [UI.NextMonthButton]: cn( buttonVariants({ variant: "outline" }), "absolute right-1 top-0 h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100", ), [UI.MonthGrid]: "w-full border-collapse space-y-1", [UI.Weekdays]: "flex", [UI.Weekday]: "text-muted-foreground rounded-md w-9 font-normal text-[0.8rem]", [UI.Week]: "flex w-full mt-2", [UI.Day]: "h-9 w-9 text-center rounded-md text-sm p-0 relative [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20", [UI.DayButton]: cn( buttonVariants({ variant: "ghost" }), "h-9 w-9 p-0 font-normal aria-selected:opacity-100 hover:bg-primary hover:text-primary-foreground", ), [SelectionState.range_end]: "day-range-end", [SelectionState.selected]: "bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground", [SelectionState.range_middle]: "aria-selected:bg-accent aria-selected:text-accent-foreground", [DayFlag.today]: "bg-accent text-accent-foreground", [DayFlag.outside]: "day-outside text-muted-foreground opacity-50 aria-selected:bg-accent/50 aria-selected:text-muted-foreground aria-selected:opacity-30", [DayFlag.disabled]: "text-muted-foreground opacity-50", [DayFlag.hidden]: "invisible", ...classNames, }} components={{ Chevron: ({ ...props }) => <Chevron {...props} />, }} {...props} /> ); };

const Chevron = ({ orientation = "left" }) => { switch (orientation) { case "left": return <ChevronLeftIcon className="h-4 w-4" />; case "right": return <ChevronRightIcon className="h-4 w-4" />; case "up": return <ChevronUpIcon className="h-4 w-4" />; case "down": return <ChevronDownIcon className="h-4 w-4" />; default: return null; } };

Is the code for "after"? How did you manage to get it?

rinmeng avatar Apr 04 '25 06:04 rinmeng

@liawagner Thank you for sharing the patch code. I’m encountering a new issue with the calendar. When I place the calendar control inside a dialog box, clicking on the calendar popover opens the calendar as expected. However, I’m unable to interact with it—any click on the calendar causes it to close immediately, preventing me from selecting a date. Additionally, the next and previous buttons on the calendar are unresponsive.

I found that setting the dialog box's modal property to false resolves the issue, allowing the calendar to function correctly. However, I want the dialog box to remain modal. Has anyone else experienced this problem? If so, what solutions have you found to make the calendar work properly while keeping the dialog box modal?

sanjay-gthb avatar Apr 10 '25 14:04 sanjay-gthb

@liawagner Thank you for sharing the patch code. I’m encountering a new issue with the calendar. When I place the calendar control inside a dialog box, clicking on the calendar popover opens the calendar as expected. However, I’m unable to interact with it—any click on the calendar causes it to close immediately, preventing me from selecting a date. Additionally, the next and previous buttons on the calendar are unresponsive.

I found that setting the dialog box's modal property to false resolves the issue, allowing the calendar to function correctly. However, I want the dialog box to remain modal. Has anyone else experienced this problem? If so, what solutions have you found to make the calendar work properly while keeping the dialog box modal?

Issue resolved by implementing following.

{ // Prevent closing when interacting with the calendar if (!openState) { onOpenChange(openState); } }} > { // Prevent closing when interacting with the calendar popover const target = event.target as HTMLElement; if (target.closest('.ignore-modal-close')) { event.preventDefault(); } }} >

<PopoverContent className="w-auto p-0 ignore-modal-close z-[60] pointer-events-auto" // Add z-index and pointer-events align="start" >


globals.css Higher than the modal's z-index Ensure the calendar captures pointer events

.ignore-modal-close { z-index: 60; pointer-events: auto; }

sanjay-gthb avatar Apr 10 '25 17:04 sanjay-gthb