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 };