/ src / components / ui / calendar.tsx
calendar.tsx
 1  import { ChevronLeftIcon, ChevronRightIcon } from "@radix-ui/react-icons";
 2  import * as React from "react";
 3  import { DayPicker } from "react-day-picker";
 4  
 5  import { buttonVariants } from "./button";
 6  import { cn } from "../../lib/utils";
 7  
 8  export type CalendarProps = React.ComponentProps<typeof DayPicker> & {
 9    color?:
10      | "primary"
11      | "secondary"
12      | "error"
13      | "success"
14      | "warning"
15      | "info"
16      | "muted";
17  };
18  
19  function Calendar({
20    className,
21    classNames,
22    showOutsideDays = true,
23    ...props
24  }: CalendarProps) {
25    return (
26      <DayPicker
27        showOutsideDays={showOutsideDays}
28        className={cn("p-3", className)}
29        classNames={{
30          months: "flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0",
31          month: "space-y-4",
32          caption: "flex justify-center pt-1 relative items-center",
33          caption_label: "text-sm font-medium",
34          nav: "space-x-1 flex items-center",
35          nav_button: cn(
36            buttonVariants({ variant: "outline" }),
37            "h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100",
38          ),
39          nav_button_previous: "absolute left-1",
40          nav_button_next: "absolute right-1",
41          table: "w-full border-collapse space-y-1",
42          head_row: "flex",
43          head_cell:
44            "text-slate-500 rounded-md w-8 font-normal text-[0.8rem] dark:text-slate-400",
45          row: "flex w-full mt-2",
46          cell: cn(
47            "relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([aria-selected])]:bg-slate-100 [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-slate-100/50 dark:[&:has([aria-selected])]:bg-slate-800 dark:[&:has([aria-selected].day-outside)]:bg-slate-800/50",
48            props.mode === "range"
49              ? "[&: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"
50              : "[&:has([aria-selected])]:rounded-md",
51          ),
52          day: cn(
53            buttonVariants({ variant: "ghost", color: "muted" }),
54            "h-8 w-8 p-0 font-normal aria-selected:opacity-100",
55          ),
56          day_range_start: "day-range-start",
57          day_range_end: "day-range-end",
58          day_selected:
59            "shadow-none bg-slate-900 text-slate-50 hover:bg-slate-900 hover:text-slate-50 focus:bg-slate-900 focus:text-slate-50 dark:bg-slate-50 dark:text-slate-900 dark:hover:bg-slate-50 dark:hover:text-slate-900 dark:focus:bg-slate-50 dark:focus:text-slate-900",
60          day_today:
61            "bg-slate-100 text-slate-900 dark:bg-slate-800 dark:text-slate-50",
62          day_outside:
63            "day-outside text-slate-500 opacity-50  aria-selected:bg-slate-100/50 aria-selected:text-slate-500 aria-selected:opacity-30 dark:text-slate-400 dark:aria-selected:bg-slate-800/50 dark:aria-selected:text-slate-400",
64          day_disabled: "text-slate-500 opacity-50 dark:text-slate-400",
65          day_range_middle:
66            "aria-selected:bg-slate-100 aria-selected:text-slate-900 dark:aria-selected:bg-slate-800 dark:aria-selected:text-slate-50",
67          day_hidden: "invisible",
68          ...classNames,
69        }}
70        components={{
71          IconLeft: ({ ...props }) => <ChevronLeftIcon className="h-4 w-4" />,
72          IconRight: ({ ...props }) => <ChevronRightIcon className="h-4 w-4" />,
73        }}
74        {...props}
75      />
76    );
77  }
78  Calendar.displayName = "Calendar";
79  
80  export { Calendar };