diff --git a/components/ui/8bit/calendar.tsx b/components/ui/8bit/calendar.tsx
index d37fa695..191d8c3a 100644
--- a/components/ui/8bit/calendar.tsx
+++ b/components/ui/8bit/calendar.tsx
@@ -51,83 +51,88 @@ function Calendar({ className, classNames, font, ...props }: CalendarProps) {
...classNames,
}}
components={{
- IconLeft: ({ className, ...props }) => (
-
- ),
- IconRight: ({ className, ...props }) => (
-
- ),
+ Chevron: ({ className, ...props }) => {
+ if (props.orientation === "left") {
+ return (
+
+ );
+ }
+
+ return (
+
+ );
+ },
}}
{...props}
/>
diff --git a/components/ui/calendar.tsx b/components/ui/calendar.tsx
index d21bcfe1..37ec3edd 100644
--- a/components/ui/calendar.tsx
+++ b/components/ui/calendar.tsx
@@ -2,71 +2,211 @@
import * as React from "react";
-import { ChevronLeft, ChevronRight } from "lucide-react";
-import { DayPicker } from "react-day-picker";
+import {
+ ChevronDownIcon,
+ ChevronLeftIcon,
+ ChevronRightIcon,
+} from "lucide-react";
+import { DayButton, DayPicker, getDefaultClassNames } from "react-day-picker";
import { cn } from "@/lib/utils";
-import { buttonVariants } from "@/components/ui/button";
-
-export type CalendarProps = React.ComponentProps;
+import { Button, buttonVariants } from "@/components/ui/button";
function Calendar({
className,
classNames,
showOutsideDays = true,
+ captionLayout = "label",
+ buttonVariant = "ghost",
+ formatters,
+ components,
...props
-}: CalendarProps) {
+}: React.ComponentProps & {
+ buttonVariant?: React.ComponentProps["variant"];
+}) {
+ const defaultClassNames = getDefaultClassNames();
+
return (
svg]:rotate-180`,
+ String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
+ className
+ )}
+ captionLayout={captionLayout}
+ formatters={{
+ formatMonthDropdown: (date) =>
+ date.toLocaleString("default", { month: "short" }),
+ ...formatters,
+ }}
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" }),
- "size-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-9 font-normal text-[0.8rem]",
- row: "flex w-full mt-2",
- cell: "size-9 text-center text-sm p-0 relative [&:has([aria-selected].day-range-end)]:rounded-r-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20",
+ root: cn("w-fit", defaultClassNames.root),
+ months: cn(
+ "flex gap-4 flex-col md:flex-row relative",
+ defaultClassNames.months
+ ),
+ month: cn("flex flex-col w-full gap-4", defaultClassNames.month),
+ nav: cn(
+ "flex items-center gap-1 w-full absolute top-0 inset-x-0 justify-between",
+ defaultClassNames.nav
+ ),
+ button_previous: cn(
+ buttonVariants({ variant: buttonVariant }),
+ "size-(--cell-size) aria-disabled:opacity-50 p-0 select-none",
+ defaultClassNames.button_previous
+ ),
+ button_next: cn(
+ buttonVariants({ variant: buttonVariant }),
+ "size-(--cell-size) aria-disabled:opacity-50 p-0 select-none",
+ defaultClassNames.button_next
+ ),
+ month_caption: cn(
+ "flex items-center justify-center h-(--cell-size) w-full px-(--cell-size)",
+ defaultClassNames.month_caption
+ ),
+ dropdowns: cn(
+ "w-full flex items-center text-sm font-medium justify-center h-(--cell-size) gap-1.5",
+ defaultClassNames.dropdowns
+ ),
+ dropdown_root: cn(
+ "relative has-focus:border-ring border border-input shadow-xs has-focus:ring-ring/50 has-focus:ring-[3px] rounded-md",
+ defaultClassNames.dropdown_root
+ ),
+ dropdown: cn("absolute inset-0 opacity-0", defaultClassNames.dropdown),
+ caption_label: cn(
+ "select-none font-medium",
+ captionLayout === "label"
+ ? "text-sm"
+ : "rounded-md pl-2 pr-1 flex items-center gap-1 text-sm h-8 [&>svg]:text-muted-foreground [&>svg]:size-3.5",
+ defaultClassNames.caption_label
+ ),
+ table: "w-full border-collapse",
+ weekdays: cn("flex", defaultClassNames.weekdays),
+ weekday: cn(
+ "text-muted-foreground rounded-md flex-1 font-normal text-[0.8rem] select-none",
+ defaultClassNames.weekday
+ ),
+ week: cn("flex w-full mt-2", defaultClassNames.week),
+ week_number_header: cn(
+ "select-none w-(--cell-size)",
+ defaultClassNames.week_number_header
+ ),
+ week_number: cn(
+ "text-[0.8rem] select-none text-muted-foreground",
+ defaultClassNames.week_number
+ ),
day: cn(
- buttonVariants({ variant: "ghost" }),
- "size-9 p-0 font-normal aria-selected:opacity-100"
- ),
- 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",
+ "relative w-full h-full p-0 text-center [&:first-child[data-selected=true]_button]:rounded-l-md [&:last-child[data-selected=true]_button]:rounded-r-md group/day aspect-square select-none",
+ defaultClassNames.day
+ ),
+ range_start: cn(
+ "rounded-l-md bg-accent",
+ defaultClassNames.range_start
+ ),
+ range_middle: cn("rounded-none", defaultClassNames.range_middle),
+ range_end: cn("rounded-r-md bg-accent", defaultClassNames.range_end),
+ today: cn(
+ "bg-accent text-accent-foreground rounded-md data-[selected=true]:rounded-none",
+ defaultClassNames.today
+ ),
+ outside: cn(
+ "text-muted-foreground aria-selected:text-muted-foreground",
+ defaultClassNames.outside
+ ),
+ disabled: cn(
+ "text-muted-foreground opacity-50",
+ defaultClassNames.disabled
+ ),
+ hidden: cn("invisible", defaultClassNames.hidden),
...classNames,
}}
components={{
- IconLeft: ({ className, ...props }) => (
-
- ),
- IconRight: ({ className, ...props }) => (
-
- ),
+ Root: ({ className, rootRef, ...props }) => {
+ return (
+
+ );
+ },
+ Chevron: ({ className, orientation, ...props }) => {
+ if (orientation === "left") {
+ return (
+
+ );
+ }
+
+ if (orientation === "right") {
+ return (
+
+ );
+ }
+
+ return (
+
+ );
+ },
+ DayButton: CalendarDayButton,
+ WeekNumber: ({ children, ...props }) => {
+ return (
+ |
+
+ {children}
+
+ |
+ );
+ },
+ ...components,
}}
{...props}
/>
);
}
-Calendar.displayName = "Calendar";
-export { Calendar };
+function CalendarDayButton({
+ className,
+ day,
+ modifiers,
+ ...props
+}: React.ComponentProps) {
+ const defaultClassNames = getDefaultClassNames();
+
+ const ref = React.useRef(null);
+ React.useEffect(() => {
+ if (modifiers.focused) ref.current?.focus();
+ }, [modifiers.focused]);
+
+ return (
+