shadcn-ui / ui

Beautifully designed components that you can copy and paste into your apps. Accessible. Customizable. Open Source.
https://ui.shadcn.com
MIT License
74.63k stars 4.64k forks source link

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

Open HamidShaikh1499 opened 5 days ago

HamidShaikh1499 commented 5 days ago

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

kamami commented 4 days ago

Same issue

hamidradical commented 4 days ago

@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.

kamami commented 4 days ago

@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...

hamidradical commented 4 days ago

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

huybuidac commented 4 days ago

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

Sparticuz commented 4 days ago

There are already 2 or 3 PR's addressing this

cuonggoaptive commented 2 days ago

Any update please ?

cuonggoaptive commented 2 days ago

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;