72 lines
3.2 KiB
TypeScript
72 lines
3.2 KiB
TypeScript
|
|
import { ChevronDown, ChevronLeft, ChevronRight, ChevronUp } from "lucide-react"
|
||
|
|
import { DayPicker, type DayPickerProps } from "react-day-picker"
|
||
|
|
import { zhCN } from "react-day-picker/locale"
|
||
|
|
|
||
|
|
import { cn } from "@/shared/ui/utils"
|
||
|
|
|
||
|
|
function Calendar({
|
||
|
|
className,
|
||
|
|
classNames,
|
||
|
|
showOutsideDays = true,
|
||
|
|
...props
|
||
|
|
}: DayPickerProps) {
|
||
|
|
return (
|
||
|
|
<DayPicker
|
||
|
|
className={cn("p-3", className)}
|
||
|
|
classNames={{
|
||
|
|
months: "flex flex-col gap-4 sm:flex-row",
|
||
|
|
month: "flex w-full flex-col gap-4",
|
||
|
|
month_caption: "flex items-center justify-center pt-1",
|
||
|
|
caption_label: "text-sm font-medium",
|
||
|
|
nav: "flex items-center gap-1",
|
||
|
|
button_previous:
|
||
|
|
"absolute left-1 inline-flex size-7 items-center justify-center rounded-md text-muted-foreground outline-none hover:bg-muted hover:text-foreground focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50",
|
||
|
|
button_next:
|
||
|
|
"absolute right-1 inline-flex size-7 items-center justify-center rounded-md text-muted-foreground outline-none hover:bg-muted hover:text-foreground focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50",
|
||
|
|
month_grid: "w-full border-collapse",
|
||
|
|
weekdays: "flex",
|
||
|
|
weekday:
|
||
|
|
"w-9 rounded-md text-[0.8rem] font-normal text-muted-foreground",
|
||
|
|
week: "mt-2 flex w-full",
|
||
|
|
day: "relative size-9 p-0 text-center text-sm [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-muted/50 [&:has([aria-selected])]:bg-muted first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20",
|
||
|
|
day_button:
|
||
|
|
"inline-flex size-9 items-center justify-center rounded-md p-0 font-normal outline-none hover:bg-muted hover:text-foreground focus-visible:ring-3 focus-visible:ring-ring/50 aria-selected:bg-primary aria-selected:text-primary-foreground",
|
||
|
|
range_start: "day-range-start rounded-l-md bg-muted",
|
||
|
|
range_middle: "rounded-none bg-muted",
|
||
|
|
range_end: "day-range-end rounded-r-md bg-muted",
|
||
|
|
selected: "rounded-md bg-primary text-primary-foreground",
|
||
|
|
today: "bg-muted text-foreground",
|
||
|
|
outside:
|
||
|
|
"day-outside text-muted-foreground opacity-50 aria-selected:bg-muted/50 aria-selected:text-muted-foreground aria-selected:opacity-30",
|
||
|
|
disabled: "text-muted-foreground opacity-50",
|
||
|
|
hidden: "invisible",
|
||
|
|
...classNames,
|
||
|
|
}}
|
||
|
|
components={{
|
||
|
|
Chevron: ({ className: chevronClassName, orientation, style }) => {
|
||
|
|
const Icon =
|
||
|
|
orientation === "left"
|
||
|
|
? ChevronLeft
|
||
|
|
: orientation === "right"
|
||
|
|
? ChevronRight
|
||
|
|
: orientation === "up"
|
||
|
|
? ChevronUp
|
||
|
|
: ChevronDown
|
||
|
|
return (
|
||
|
|
<Icon
|
||
|
|
aria-hidden="true"
|
||
|
|
className={cn("size-4", chevronClassName)}
|
||
|
|
style={style}
|
||
|
|
/>
|
||
|
|
)
|
||
|
|
},
|
||
|
|
}}
|
||
|
|
locale={zhCN}
|
||
|
|
showOutsideDays={showOutsideDays}
|
||
|
|
{...props}
|
||
|
|
/>
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
export { Calendar }
|