svg]:rotate-180`,
String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
className
)}
captionLayout={captionLayout}
+ locale={locale}
formatters={{
formatMonthDropdown: (date) =>
- date.toLocaleString("default", { month: "short" }),
+ date.toLocaleString(locale?.code, { month: "short" }),
...formatters,
}}
classNames={{
root: cn("w-fit", defaultClassNames.root),
months: cn(
- "flex gap-4 flex-col md:flex-row relative",
+ "relative flex flex-col gap-4 md:flex-row",
defaultClassNames.months
),
- month: cn("flex flex-col w-full gap-4", defaultClassNames.month),
+ month: cn("flex w-full flex-col gap-4", defaultClassNames.month),
nav: cn(
- "flex items-center gap-1 w-full absolute top-0 inset-x-0 justify-between",
+ "absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1",
defaultClassNames.nav
),
button_previous: cn(
buttonVariants({ variant: buttonVariant }),
- "size-(--cell-size) aria-disabled:opacity-50 p-0 select-none",
+ "size-(--cell-size) p-0 select-none aria-disabled:opacity-50",
defaultClassNames.button_previous
),
button_next: cn(
buttonVariants({ variant: buttonVariant }),
- "size-(--cell-size) aria-disabled:opacity-50 p-0 select-none",
+ "size-(--cell-size) p-0 select-none aria-disabled:opacity-50",
defaultClassNames.button_next
),
month_caption: cn(
- "flex items-center justify-center h-(--cell-size) w-full px-(--cell-size)",
+ "flex h-(--cell-size) w-full items-center justify-center 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",
+ "flex h-(--cell-size) w-full items-center justify-center gap-1.5 text-sm font-medium",
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",
+ "relative rounded-(--cell-radius)",
defaultClassNames.dropdown_root
),
dropdown: cn(
- "absolute bg-popover inset-0 opacity-0",
+ "absolute inset-0 bg-popover opacity-0",
defaultClassNames.dropdown
),
caption_label: cn(
- "select-none font-medium",
+ "font-medium select-none",
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",
+ : "flex items-center gap-1 rounded-(--cell-radius) text-sm [&>svg]:size-3.5 [&>svg]:text-muted-foreground",
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",
+ "flex-1 rounded-(--cell-radius) text-[0.8rem] font-normal text-muted-foreground select-none",
defaultClassNames.weekday
),
- week: cn("flex w-full mt-2", defaultClassNames.week),
+ week: cn("mt-2 flex w-full", defaultClassNames.week),
week_number_header: cn(
- "select-none w-(--cell-size)",
+ "w-(--cell-size) select-none",
defaultClassNames.week_number_header
),
week_number: cn(
- "text-[0.8rem] select-none text-muted-foreground",
+ "text-[0.8rem] text-muted-foreground select-none",
defaultClassNames.week_number
),
day: cn(
- "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",
+ "group/day relative aspect-square h-full w-full rounded-(--cell-radius) p-0 text-center select-none [&:last-child[data-selected=true]_button]:rounded-r-(--cell-radius)",
+ props.showWeekNumber
+ ? "[&:nth-child(2)[data-selected=true]_button]:rounded-l-(--cell-radius)"
+ : "[&:first-child[data-selected=true]_button]:rounded-l-(--cell-radius)",
defaultClassNames.day
),
range_start: cn(
- "rounded-l-md bg-accent",
+ "relative isolate z-0 rounded-l-(--cell-radius) bg-muted after:absolute after:inset-y-0 after:right-0 after:w-4 after:bg-muted",
defaultClassNames.range_start
),
range_middle: cn("rounded-none", defaultClassNames.range_middle),
- range_end: cn("rounded-r-md bg-accent", defaultClassNames.range_end),
+ range_end: cn(
+ "relative isolate z-0 rounded-r-(--cell-radius) bg-muted after:absolute after:inset-y-0 after:left-0 after:w-4 after:bg-muted",
+ defaultClassNames.range_end
+ ),
today: cn(
- "bg-accent text-accent-foreground rounded-md data-[selected=true]:rounded-none",
+ "rounded-(--cell-radius) bg-muted text-foreground data-[selected=true]:rounded-none",
defaultClassNames.today
),
outside: cn(
@@ -144,10 +153,7 @@ function Calendar({
if (orientation === "right") {
return (
-
+
)
}
@@ -155,7 +161,9 @@ function Calendar({
)
},
- DayButton: CalendarDayButton,
+ DayButton: ({ ...props }) => (
+
+ ),
WeekNumber: ({ children, ...props }) => {
return (
@@ -176,8 +184,9 @@ function CalendarDayButton({
className,
day,
modifiers,
+ locale,
...props
-}: React.ComponentProps) {
+}: React.ComponentProps & { locale?: Partial }) {
const defaultClassNames = getDefaultClassNames()
const ref = React.useRef(null)
@@ -190,7 +199,7 @@ function CalendarDayButton({
ref={ref}
variant="ghost"
size="icon"
- data-day={day.date.toLocaleDateString()}
+ data-day={day.date.toLocaleDateString(locale?.code)}
data-selected-single={
modifiers.selected &&
!modifiers.range_start &&
@@ -201,7 +210,7 @@ function CalendarDayButton({
data-range-end={modifiers.range_end}
data-range-middle={modifiers.range_middle}
className={cn(
- "data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-ring/50 dark:hover:text-accent-foreground flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-[3px] data-[range-end=true]:rounded-md data-[range-end=true]:rounded-r-md data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-md data-[range-start=true]:rounded-l-md [&>span]:text-xs [&>span]:opacity-70",
+ "relative isolate z-10 flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 border-0 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-[3px] group-data-[focused=true]/day:ring-ring/50 data-[range-end=true]:rounded-(--cell-radius) data-[range-end=true]:rounded-r-(--cell-radius) data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground data-[range-middle=true]:rounded-none data-[range-middle=true]:bg-muted data-[range-middle=true]:text-foreground data-[range-start=true]:rounded-(--cell-radius) data-[range-start=true]:rounded-l-(--cell-radius) data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground dark:hover:text-foreground [&>span]:text-xs [&>span]:opacity-70",
defaultClassNames.day,
className
)}
diff --git a/src/components/ui/card.tsx b/src/components/ui/card.tsx
index a854f10..614b60f 100644
--- a/src/components/ui/card.tsx
+++ b/src/components/ui/card.tsx
@@ -2,12 +2,17 @@ import * as React from "react"
import { cn } from "~/lib/utils"
-function Card({ className, ...props }: React.ComponentProps<"div">) {
+function Card({
+ className,
+ size = "default",
+ ...props
+}: React.ComponentProps<"div"> & { size?: "default" | "sm" }) {
return (
img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
className
)}
{...props}
@@ -20,7 +25,7 @@ function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
) {
return (
)
@@ -42,7 +50,7 @@ function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
return (
)
@@ -65,7 +73,7 @@ function CardContent({ className, ...props }: React.ComponentProps<"div">) {
return (
)
@@ -75,7 +83,10 @@ function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
return (
)
diff --git a/src/components/ui/carousel.tsx b/src/components/ui/carousel.tsx
index a1d96b0..811de11 100644
--- a/src/components/ui/carousel.tsx
+++ b/src/components/ui/carousel.tsx
@@ -4,10 +4,10 @@ import * as React from "react"
import useEmblaCarousel, {
type UseEmblaCarouselType,
} from "embla-carousel-react"
-import { ArrowLeft, ArrowRight } from "lucide-react"
import { cn } from "~/lib/utils"
import { Button } from "~/components/ui/button"
+import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react"
type CarouselApi = UseEmblaCarouselType[1]
type UseCarouselParameters = Parameters
@@ -174,7 +174,7 @@ function CarouselItem({ className, ...props }: React.ComponentProps<"div">) {
function CarouselPrevious({
className,
variant = "outline",
- size = "icon",
+ size = "icon-sm",
...props
}: React.ComponentProps) {
const { orientation, scrollPrev, canScrollPrev } = useCarousel()
@@ -185,7 +185,7 @@ function CarouselPrevious({
variant={variant}
size={size}
className={cn(
- "absolute size-8 rounded-full",
+ "absolute touch-manipulation rounded-full",
orientation === "horizontal"
? "top-1/2 -left-12 -translate-y-1/2"
: "-top-12 left-1/2 -translate-x-1/2 rotate-90",
@@ -195,7 +195,7 @@ function CarouselPrevious({
onClick={scrollPrev}
{...props}
>
-
+
Previous slide
)
@@ -204,7 +204,7 @@ function CarouselPrevious({
function CarouselNext({
className,
variant = "outline",
- size = "icon",
+ size = "icon-sm",
...props
}: React.ComponentProps) {
const { orientation, scrollNext, canScrollNext } = useCarousel()
@@ -215,7 +215,7 @@ function CarouselNext({
variant={variant}
size={size}
className={cn(
- "absolute size-8 rounded-full",
+ "absolute touch-manipulation rounded-full",
orientation === "horizontal"
? "top-1/2 -right-12 -translate-y-1/2"
: "-bottom-12 left-1/2 -translate-x-1/2 rotate-90",
@@ -225,7 +225,7 @@ function CarouselNext({
onClick={scrollNext}
{...props}
>
-
+
Next slide
)
@@ -238,4 +238,5 @@ export {
CarouselItem,
CarouselPrevious,
CarouselNext,
+ useCarousel,
}
diff --git a/src/components/ui/chart.tsx b/src/components/ui/chart.tsx
index 00e3543..3bb7c39 100644
--- a/src/components/ui/chart.tsx
+++ b/src/components/ui/chart.tsx
@@ -55,7 +55,7 @@ function ChartContainer({
data-slot="chart"
data-chart={chartId}
className={cn(
- "[&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border flex aspect-video justify-center text-xs [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-hidden [&_.recharts-sector]:outline-hidden [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-surface]:outline-hidden",
+ "flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-hidden [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector]:outline-hidden [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-surface]:outline-hidden",
className
)}
{...props}
@@ -173,76 +173,78 @@ function ChartTooltipContent({
return (
{!nestLabel ? tooltipLabel : null}
- {payload.map((item, index) => {
- const key = `${nameKey || item.name || item.dataKey || "value"}`
- const itemConfig = getPayloadConfigFromPayload(config, item, key)
- const indicatorColor = color || item.payload.fill || item.color
+ {payload
+ .filter((item) => item.type !== "none")
+ .map((item, index) => {
+ const key = `${nameKey || item.name || item.dataKey || "value"}`
+ const itemConfig = getPayloadConfigFromPayload(config, item, key)
+ const indicatorColor = color || item.payload.fill || item.color
- return (
- svg]:text-muted-foreground flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5",
- indicator === "dot" && "items-center"
- )}
- >
- {formatter && item?.value !== undefined && item.name ? (
- formatter(item.value, item.name, item, index, item.payload)
- ) : (
- <>
- {itemConfig?.icon ? (
-
- ) : (
- !hideIndicator && (
- svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
+ indicator === "dot" && "items-center"
+ )}
+ >
+ {formatter && item?.value !== undefined && item.name ? (
+ formatter(item.value, item.name, item, index, item.payload)
+ ) : (
+ <>
+ {itemConfig?.icon ? (
+
+ ) : (
+ !hideIndicator && (
+
- )
- )}
-
+ )
)}
- >
-
- {nestLabel ? tooltipLabel : null}
-
- {itemConfig?.label || item.name}
-
+
+
+ {nestLabel ? tooltipLabel : null}
+
+ {itemConfig?.label || item.name}
+
+
+ {item.value && (
+
+ {item.value.toLocaleString()}
+
+ )}
- {item.value && (
-
- {item.value.toLocaleString()}
-
- )}
-
- >
- )}
-
- )
- })}
+ >
+ )}
+
+ )
+ })}
)
@@ -275,36 +277,37 @@ function ChartLegendContent({
className
)}
>
- {payload.map((item) => {
- const key = `${nameKey || item.dataKey || "value"}`
- const itemConfig = getPayloadConfigFromPayload(config, item, key)
+ {payload
+ .filter((item) => item.type !== "none")
+ .map((item) => {
+ const key = `${nameKey || item.dataKey || "value"}`
+ const itemConfig = getPayloadConfigFromPayload(config, item, key)
- return (
- svg]:text-muted-foreground flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3"
- )}
- >
- {itemConfig?.icon && !hideIcon ? (
-
- ) : (
-
- )}
- {itemConfig?.label}
-
- )
- })}
+ return (
+ svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground"
+ )}
+ >
+ {itemConfig?.icon && !hideIcon ? (
+
+ ) : (
+
+ )}
+ {itemConfig?.label}
+
+ )
+ })}
)
}
-// Helper to extract item config from a payload.
function getPayloadConfigFromPayload(
config: ChartConfig,
payload: unknown,
diff --git a/src/components/ui/checkbox.tsx b/src/components/ui/checkbox.tsx
index 31fbcb6..24648c3 100644
--- a/src/components/ui/checkbox.tsx
+++ b/src/components/ui/checkbox.tsx
@@ -1,10 +1,10 @@
"use client"
import * as React from "react"
-import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
-import { CheckIcon } from "lucide-react"
+import { Checkbox as CheckboxPrimitive } from "radix-ui"
import { cn } from "~/lib/utils"
+import { CheckIcon } from "lucide-react"
function Checkbox({
className,
@@ -14,16 +14,17 @@ function Checkbox({
-
+
)
diff --git a/src/components/ui/collapsible.tsx b/src/components/ui/collapsible.tsx
index ae9fad0..2f7a4e7 100644
--- a/src/components/ui/collapsible.tsx
+++ b/src/components/ui/collapsible.tsx
@@ -1,6 +1,6 @@
"use client"
-import * as CollapsiblePrimitive from "@radix-ui/react-collapsible"
+import { Collapsible as CollapsiblePrimitive } from "radix-ui"
function Collapsible({
...props
diff --git a/src/components/ui/command.tsx b/src/components/ui/command.tsx
index 39840d6..b7c1322 100644
--- a/src/components/ui/command.tsx
+++ b/src/components/ui/command.tsx
@@ -2,7 +2,6 @@
import * as React from "react"
import { Command as CommandPrimitive } from "cmdk"
-import { SearchIcon } from "lucide-react"
import { cn } from "~/lib/utils"
import {
@@ -12,6 +11,11 @@ import {
DialogHeader,
DialogTitle,
} from "~/components/ui/dialog"
+import {
+ InputGroup,
+ InputGroupAddon,
+} from "~/components/ui/input-group"
+import { SearchIcon, CheckIcon } from "lucide-react"
function Command({
className,
@@ -21,7 +25,7 @@ function Command({
& {
title?: string
@@ -49,12 +53,13 @@ function CommandDialog({
{description}
-
- {children}
-
+ {children}
)
@@ -65,19 +70,20 @@ function CommandInput({
...props
}: React.ComponentProps) {
return (
-
-
-
+
+
+
+
+
+
+
)
}
@@ -90,7 +96,7 @@ function CommandList({
) {
return (
)
@@ -118,7 +125,7 @@ function CommandGroup({
)
@@ -141,17 +148,21 @@ function CommandSeparator({
function CommandItem({
className,
+ children,
...props
}: React.ComponentProps) {
return (
+ >
+ {children}
+
+
)
}
@@ -163,7 +174,7 @@ function CommandShortcut({
) {
return (
-
+
)
}
@@ -53,58 +58,17 @@ function ContextMenuRadioGroup({
)
}
-function ContextMenuSubTrigger({
- className,
- inset,
- children,
- ...props
-}: React.ComponentProps & {
- inset?: boolean
-}) {
- return (
-
- {children}
-
-
- )
-}
-
-function ContextMenuSubContent({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
function ContextMenuContent({
className,
...props
-}: React.ComponentProps) {
+}: React.ComponentProps & {
+ side?: "top" | "right" | "bottom" | "left"
+}) {
return (
@@ -126,7 +90,7 @@ function ContextMenuItem({
data-inset={inset}
data-variant={variant}
className={cn(
- "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
+ "group/context-menu-item relative flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-inset:pl-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 focus:*:[svg]:text-accent-foreground data-[variant=destructive]:*:[svg]:text-destructive",
className
)}
{...props}
@@ -134,25 +98,67 @@ function ContextMenuItem({
)
}
+function ContextMenuSubTrigger({
+ className,
+ inset,
+ children,
+ ...props
+}: React.ComponentProps & {
+ inset?: boolean
+}) {
+ return (
+
+ {children}
+
+
+ )
+}
+
+function ContextMenuSubContent({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
function ContextMenuCheckboxItem({
className,
children,
checked,
+ inset,
...props
-}: React.ComponentProps) {
+}: React.ComponentProps & {
+ inset?: boolean
+}) {
return (
-
+
-
+
{children}
@@ -163,20 +169,25 @@ function ContextMenuCheckboxItem({
function ContextMenuRadioItem({
className,
children,
+ inset,
...props
-}: React.ComponentProps) {
+}: React.ComponentProps & {
+ inset?: boolean
+}) {
return (
-
+
-
+
{children}
@@ -196,7 +207,7 @@ function ContextMenuLabel({
data-slot="context-menu-label"
data-inset={inset}
className={cn(
- "text-foreground px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
+ "px-1.5 py-1 text-xs font-medium text-muted-foreground data-inset:pl-7",
className
)}
{...props}
@@ -211,7 +222,7 @@ function ContextMenuSeparator({
return (
)
@@ -225,7 +236,7 @@ function ContextMenuShortcut({
+
{children}
{showCloseButton && (
-
-
- Close
+
+
)}
@@ -84,22 +89,36 @@ function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
return (
)
}
-function DialogFooter({ className, ...props }: React.ComponentProps<"div">) {
+function DialogFooter({
+ className,
+ showCloseButton = false,
+ children,
+ ...props
+}: React.ComponentProps<"div"> & {
+ showCloseButton?: boolean
+}) {
return (
+ >
+ {children}
+ {showCloseButton && (
+
+
+
+ )}
+
)
}
@@ -110,7 +129,7 @@ function DialogTitle({
return (
)
@@ -123,7 +142,10 @@ function DialogDescription({
return (
)
diff --git a/src/components/ui/drawer.tsx b/src/components/ui/drawer.tsx
index 8ca265e..d094a07 100644
--- a/src/components/ui/drawer.tsx
+++ b/src/components/ui/drawer.tsx
@@ -37,7 +37,7 @@ function DrawerOverlay({
-
+
{children}
@@ -77,7 +73,7 @@ function DrawerHeader({ className, ...props }: React.ComponentProps<"div">) {
)
@@ -115,7 +111,7 @@ function DrawerDescription({
return (
)
diff --git a/src/components/ui/dropdown-menu.tsx b/src/components/ui/dropdown-menu.tsx
index f8fbffc..323cc8d 100644
--- a/src/components/ui/dropdown-menu.tsx
+++ b/src/components/ui/dropdown-menu.tsx
@@ -1,10 +1,10 @@
"use client"
import * as React from "react"
-import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
-import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
+import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui"
import { cn } from "~/lib/utils"
+import { CheckIcon, ChevronRightIcon } from "lucide-react"
function DropdownMenu({
...props
@@ -33,6 +33,7 @@ function DropdownMenuTrigger({
function DropdownMenuContent({
className,
+ align = "start",
sideOffset = 4,
...props
}: React.ComponentProps) {
@@ -41,10 +42,8 @@ function DropdownMenuContent({
@@ -74,7 +73,7 @@ function DropdownMenuItem({
data-inset={inset}
data-variant={variant}
className={cn(
- "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
+ "group/dropdown-menu-item relative flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive",
className
)}
{...props}
@@ -86,21 +85,29 @@ function DropdownMenuCheckboxItem({
className,
children,
checked,
+ inset,
...props
-}: React.ComponentProps) {
+}: React.ComponentProps & {
+ inset?: boolean
+}) {
return (
-
+
-
+
{children}
@@ -122,20 +129,28 @@ function DropdownMenuRadioGroup({
function DropdownMenuRadioItem({
className,
children,
+ inset,
...props
-}: React.ComponentProps) {
+}: React.ComponentProps & {
+ inset?: boolean
+}) {
return (
-
+
-
+
{children}
@@ -155,7 +170,7 @@ function DropdownMenuLabel({
data-slot="dropdown-menu-label"
data-inset={inset}
className={cn(
- "px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
+ "px-1.5 py-1 text-xs font-medium text-muted-foreground data-inset:pl-7",
className
)}
{...props}
@@ -170,7 +185,7 @@ function DropdownMenuSeparator({
return (
)
@@ -184,7 +199,7 @@ function DropdownMenuShortcut({
{children}
-
+
)
}
@@ -229,10 +244,7 @@ function DropdownMenuSubContent({
return (
)
diff --git a/src/components/ui/hover-card.tsx b/src/components/ui/hover-card.tsx
index 01febed..65e8220 100644
--- a/src/components/ui/hover-card.tsx
+++ b/src/components/ui/hover-card.tsx
@@ -1,7 +1,7 @@
"use client"
import * as React from "react"
-import * as HoverCardPrimitive from "@radix-ui/react-hover-card"
+import { HoverCard as HoverCardPrimitive } from "radix-ui"
import { cn } from "~/lib/utils"
@@ -32,7 +32,7 @@ function HoverCardContent({
align={align}
sideOffset={sideOffset}
className={cn(
- "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-64 origin-(--radix-hover-card-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",
+ "z-50 w-64 origin-(--radix-hover-card-content-transform-origin) rounded-lg bg-popover p-2.5 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
className
)}
{...props}
diff --git a/src/components/ui/input-group.tsx b/src/components/ui/input-group.tsx
new file mode 100644
index 0000000..ec3a2ea
--- /dev/null
+++ b/src/components/ui/input-group.tsx
@@ -0,0 +1,156 @@
+"use client"
+
+import * as React from "react"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "~/lib/utils"
+import { Button } from "~/components/ui/button"
+import { Input } from "~/components/ui/input"
+import { Textarea } from "~/components/ui/textarea"
+
+function InputGroup({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+ [data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>textarea]:h-auto dark:bg-input/30 dark:has-disabled:bg-input/80 dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40 has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3 has-[>[data-align=inline-end]]:[&>input]:pr-1.5 has-[>[data-align=inline-start]]:[&>input]:pl-1.5",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+const inputGroupAddonVariants = cva(
+ "flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium text-muted-foreground select-none group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4",
+ {
+ variants: {
+ align: {
+ "inline-start":
+ "order-first pl-2 has-[>button]:ml-[-0.3rem] has-[>kbd]:ml-[-0.15rem]",
+ "inline-end":
+ "order-last pr-2 has-[>button]:mr-[-0.3rem] has-[>kbd]:mr-[-0.15rem]",
+ "block-start":
+ "order-first w-full justify-start px-2.5 pt-2 group-has-[>input]/input-group:pt-2 [.border-b]:pb-2",
+ "block-end":
+ "order-last w-full justify-start px-2.5 pb-2 group-has-[>input]/input-group:pb-2 [.border-t]:pt-2",
+ },
+ },
+ defaultVariants: {
+ align: "inline-start",
+ },
+ }
+)
+
+function InputGroupAddon({
+ className,
+ align = "inline-start",
+ ...props
+}: React.ComponentProps<"div"> & VariantProps ) {
+ return (
+ {
+ if ((e.target as HTMLElement).closest("button")) {
+ return
+ }
+ e.currentTarget.parentElement?.querySelector("input")?.focus()
+ }}
+ {...props}
+ />
+ )
+}
+
+const inputGroupButtonVariants = cva(
+ "flex items-center gap-2 text-sm shadow-none",
+ {
+ variants: {
+ size: {
+ xs: "h-6 gap-1 rounded-[calc(var(--radius)-3px)] px-1.5 [&>svg:not([class*='size-'])]:size-3.5",
+ sm: "",
+ "icon-xs":
+ "size-6 rounded-[calc(var(--radius)-3px)] p-0 has-[>svg]:p-0",
+ "icon-sm": "size-8 p-0 has-[>svg]:p-0",
+ },
+ },
+ defaultVariants: {
+ size: "xs",
+ },
+ }
+)
+
+function InputGroupButton({
+ className,
+ type = "button",
+ variant = "ghost",
+ size = "xs",
+ ...props
+}: Omit , "size"> &
+ VariantProps) {
+ return (
+
+ )
+}
+
+function InputGroupText({ className, ...props }: React.ComponentProps<"span">) {
+ return (
+
+ )
+}
+
+function InputGroupInput({
+ className,
+ ...props
+}: React.ComponentProps<"input">) {
+ return (
+
+ )
+}
+
+function InputGroupTextarea({
+ className,
+ ...props
+}: React.ComponentProps<"textarea">) {
+ return (
+
+ )
+}
+
+export {
+ InputGroup,
+ InputGroupAddon,
+ InputGroupButton,
+ InputGroupText,
+ InputGroupInput,
+ InputGroupTextarea,
+}
diff --git a/src/components/ui/input-otp.tsx b/src/components/ui/input-otp.tsx
index 620e95b..981b820 100644
--- a/src/components/ui/input-otp.tsx
+++ b/src/components/ui/input-otp.tsx
@@ -2,9 +2,9 @@
import * as React from "react"
import { OTPInput, OTPInputContext } from "input-otp"
-import { MinusIcon } from "lucide-react"
import { cn } from "~/lib/utils"
+import { MinusIcon } from "lucide-react"
function InputOTP({
className,
@@ -17,9 +17,10 @@ function InputOTP({
@@ -30,7 +31,10 @@ function InputOTPGroup({ className, ...props }: React.ComponentProps<"div">) {
return (
)
@@ -51,7 +55,7 @@ function InputOTPSlot({
data-slot="input-otp-slot"
data-active={isActive}
className={cn(
- "data-[active=true]:border-ring data-[active=true]:ring-ring/50 data-[active=true]:aria-invalid:ring-destructive/20 dark:data-[active=true]:aria-invalid:ring-destructive/40 aria-invalid:border-destructive data-[active=true]:aria-invalid:border-destructive dark:bg-input/30 border-input relative flex h-9 w-9 items-center justify-center border-y border-r text-sm shadow-xs transition-all outline-none first:rounded-l-md first:border-l last:rounded-r-md data-[active=true]:z-10 data-[active=true]:ring-[3px]",
+ "relative flex size-8 items-center justify-center border-y border-r border-input text-sm transition-all outline-none first:rounded-l-lg first:border-l last:rounded-r-lg aria-invalid:border-destructive data-[active=true]:z-10 data-[active=true]:border-ring data-[active=true]:ring-3 data-[active=true]:ring-ring/50 data-[active=true]:aria-invalid:border-destructive data-[active=true]:aria-invalid:ring-destructive/20 dark:bg-input/30 dark:data-[active=true]:aria-invalid:ring-destructive/40",
className
)}
{...props}
@@ -59,7 +63,7 @@ function InputOTPSlot({
{char}
{hasFakeCaret && (
)}
@@ -68,8 +72,14 @@ function InputOTPSlot({
function InputOTPSeparator({ ...props }: React.ComponentProps<"div">) {
return (
-
-
+
+
)
}
diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx
index c9add61..b1c9d4f 100644
--- a/src/components/ui/input.tsx
+++ b/src/components/ui/input.tsx
@@ -8,9 +8,7 @@ function Input({ className, type, ...props }: React.ComponentProps<"input">) {
type={type}
data-slot="input"
className={cn(
- "file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
- "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
- "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
+ "h-8 w-full min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
className
)}
{...props}
diff --git a/src/components/ui/label.tsx b/src/components/ui/label.tsx
index e15fb65..c4d03a3 100644
--- a/src/components/ui/label.tsx
+++ b/src/components/ui/label.tsx
@@ -1,7 +1,7 @@
"use client"
import * as React from "react"
-import * as LabelPrimitive from "@radix-ui/react-label"
+import { Label as LabelPrimitive } from "radix-ui"
import { cn } from "~/lib/utils"
diff --git a/src/components/ui/menubar.tsx b/src/components/ui/menubar.tsx
index 8bddfa4..71942d8 100644
--- a/src/components/ui/menubar.tsx
+++ b/src/components/ui/menubar.tsx
@@ -1,10 +1,10 @@
"use client"
import * as React from "react"
-import * as MenubarPrimitive from "@radix-ui/react-menubar"
-import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
+import { Menubar as MenubarPrimitive } from "radix-ui"
import { cn } from "~/lib/utils"
+import { CheckIcon, ChevronRightIcon } from "lucide-react"
function Menubar({
className,
@@ -14,7 +14,7 @@ function Menubar({
@@ -103,7 +100,7 @@ function MenubarItem({
data-inset={inset}
data-variant={variant}
className={cn(
- "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
+ "group/menubar-item relative flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive!",
className
)}
{...props}
@@ -115,21 +112,26 @@ function MenubarCheckboxItem({
className,
children,
checked,
+ inset,
...props
-}: React.ComponentProps ) {
+}: React.ComponentProps & {
+ inset?: boolean
+}) {
return (
-
+
-
+
{children}
@@ -140,20 +142,25 @@ function MenubarCheckboxItem({
function MenubarRadioItem({
className,
children,
+ inset,
...props
-}: React.ComponentProps) {
+}: React.ComponentProps & {
+ inset?: boolean
+}) {
return (
-
+
-
+
{children}
@@ -173,7 +180,7 @@ function MenubarLabel({
data-slot="menubar-label"
data-inset={inset}
className={cn(
- "px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
+ "px-1.5 py-1 text-sm font-medium data-inset:pl-7",
className
)}
{...props}
@@ -188,7 +195,7 @@ function MenubarSeparator({
return (
)
@@ -202,7 +209,7 @@ function MenubarShortcut({
{children}
-
+
)
}
@@ -247,10 +254,7 @@ function MenubarSubContent({
return (
)
diff --git a/src/components/ui/navigation-menu.tsx b/src/components/ui/navigation-menu.tsx
index 606e02d..301f830 100644
--- a/src/components/ui/navigation-menu.tsx
+++ b/src/components/ui/navigation-menu.tsx
@@ -1,9 +1,9 @@
import * as React from "react"
-import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu"
import { cva } from "class-variance-authority"
-import { ChevronDownIcon } from "lucide-react"
+import { NavigationMenu as NavigationMenuPrimitive } from "radix-ui"
import { cn } from "~/lib/utils"
+import { ChevronDownIcon } from "lucide-react"
function NavigationMenu({
className,
@@ -37,7 +37,7 @@ function NavigationMenuList({
{children}{" "}
-
+
)
}
@@ -90,8 +87,7 @@ function NavigationMenuContent({
-
+
)
}
diff --git a/src/components/ui/pagination.tsx b/src/components/ui/pagination.tsx
index 1f89d73..9b30e28 100644
--- a/src/components/ui/pagination.tsx
+++ b/src/components/ui/pagination.tsx
@@ -1,12 +1,8 @@
import * as React from "react"
-import {
- ChevronLeftIcon,
- ChevronRightIcon,
- MoreHorizontalIcon,
-} from "lucide-react"
import { cn } from "~/lib/utils"
-import { Button, buttonVariants } from "~/components/ui/button"
+import { Button } from "~/components/ui/button"
+import { ChevronLeftIcon, ChevronRightIcon, MoreHorizontalIcon } from "lucide-react"
function Pagination({ className, ...props }: React.ComponentProps<"nav">) {
return (
@@ -27,7 +23,7 @@ function PaginationContent({
return (
)
@@ -49,52 +45,54 @@ function PaginationLink({
...props
}: PaginationLinkProps) {
return (
-
+
)
}
function PaginationPrevious({
className,
+ text = "Previous",
...props
-}: React.ComponentProps) {
+}: React.ComponentProps & { text?: string }) {
return (
-
- Previous
+
+ {text}
)
}
function PaginationNext({
className,
+ text = "Next",
...props
-}: React.ComponentProps) {
+}: React.ComponentProps & { text?: string }) {
return (
- Next
-
+ {text}
+
)
}
@@ -107,10 +105,14 @@ function PaginationEllipsis({
-
+
More pages
)
@@ -119,9 +121,9 @@ function PaginationEllipsis({
export {
Pagination,
PaginationContent,
- PaginationLink,
- PaginationItem,
- PaginationPrevious,
- PaginationNext,
PaginationEllipsis,
+ PaginationItem,
+ PaginationLink,
+ PaginationNext,
+ PaginationPrevious,
}
diff --git a/src/components/ui/popover.tsx b/src/components/ui/popover.tsx
index 9be5957..61f017a 100644
--- a/src/components/ui/popover.tsx
+++ b/src/components/ui/popover.tsx
@@ -1,7 +1,7 @@
"use client"
import * as React from "react"
-import * as PopoverPrimitive from "@radix-ui/react-popover"
+import { Popover as PopoverPrimitive } from "radix-ui"
import { cn } from "~/lib/utils"
@@ -30,7 +30,7 @@ function PopoverContent({
align={align}
sideOffset={sideOffset}
className={cn(
- "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",
+ "z-50 flex w-72 origin-(--radix-popover-content-transform-origin) flex-col gap-2.5 rounded-lg bg-popover p-2.5 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
className
)}
{...props}
@@ -45,4 +45,45 @@ function PopoverAnchor({
return
}
-export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }
+function PopoverHeader({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function PopoverTitle({ className, ...props }: React.ComponentProps<"h2">) {
+ return (
+
+ )
+}
+
+function PopoverDescription({
+ className,
+ ...props
+}: React.ComponentProps<"p">) {
+ return (
+
+ )
+}
+
+export {
+ Popover,
+ PopoverAnchor,
+ PopoverContent,
+ PopoverDescription,
+ PopoverHeader,
+ PopoverTitle,
+ PopoverTrigger,
+}
diff --git a/src/components/ui/progress.tsx b/src/components/ui/progress.tsx
index 37f457f..d6e72b4 100644
--- a/src/components/ui/progress.tsx
+++ b/src/components/ui/progress.tsx
@@ -1,7 +1,7 @@
"use client"
import * as React from "react"
-import * as ProgressPrimitive from "@radix-ui/react-progress"
+import { Progress as ProgressPrimitive } from "radix-ui"
import { cn } from "~/lib/utils"
@@ -14,14 +14,14 @@ function Progress({
diff --git a/src/components/ui/radio-group.tsx b/src/components/ui/radio-group.tsx
index b1c5667..21a1349 100644
--- a/src/components/ui/radio-group.tsx
+++ b/src/components/ui/radio-group.tsx
@@ -1,8 +1,7 @@
"use client"
import * as React from "react"
-import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"
-import { CircleIcon } from "lucide-react"
+import { RadioGroup as RadioGroupPrimitive } from "radix-ui"
import { cn } from "~/lib/utils"
@@ -13,7 +12,7 @@ function RadioGroup({
return (
)
@@ -27,16 +26,16 @@ function RadioGroupItem({
-
+
)
diff --git a/src/components/ui/resizable.tsx b/src/components/ui/resizable.tsx
index b36d4b3..e38d949 100644
--- a/src/components/ui/resizable.tsx
+++ b/src/components/ui/resizable.tsx
@@ -1,7 +1,5 @@
"use client"
-import * as React from "react"
-import { GripVerticalIcon } from "lucide-react"
import * as ResizablePrimitive from "react-resizable-panels"
import { cn } from "~/lib/utils"
@@ -9,12 +7,12 @@ import { cn } from "~/lib/utils"
function ResizablePanelGroup({
className,
...props
-}: React.ComponentProps) {
+}: ResizablePrimitive.GroupProps) {
return (
- ) {
+function ResizablePanel({ ...props }: ResizablePrimitive.PanelProps) {
return
}
@@ -32,25 +28,23 @@ function ResizableHandle({
withHandle,
className,
...props
-}: React.ComponentProps & {
+}: ResizablePrimitive.SeparatorProps & {
withHandle?: boolean
}) {
return (
- div]:rotate-90",
+ "relative flex w-px items-center justify-center bg-border ring-offset-background after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-hidden aria-[orientation=horizontal]:h-px aria-[orientation=horizontal]:w-full aria-[orientation=horizontal]:after:left-0 aria-[orientation=horizontal]:after:h-1 aria-[orientation=horizontal]:after:w-full aria-[orientation=horizontal]:after:translate-x-0 aria-[orientation=horizontal]:after:-translate-y-1/2 [&[aria-orientation=horizontal]>div]:rotate-90",
className
)}
{...props}
>
{withHandle && (
-
-
-
+
)}
-
+
)
}
-export { ResizablePanelGroup, ResizablePanel, ResizableHandle }
+export { ResizableHandle, ResizablePanel, ResizablePanelGroup }
diff --git a/src/components/ui/scroll-area.tsx b/src/components/ui/scroll-area.tsx
index 424eb4e..d968587 100644
--- a/src/components/ui/scroll-area.tsx
+++ b/src/components/ui/scroll-area.tsx
@@ -1,7 +1,7 @@
"use client"
import * as React from "react"
-import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
+import { ScrollArea as ScrollAreaPrimitive } from "radix-ui"
import { cn } from "~/lib/utils"
@@ -18,7 +18,7 @@ function ScrollArea({
>
{children}
@@ -36,20 +36,17 @@ function ScrollBar({
return (
)
diff --git a/src/components/ui/select.tsx b/src/components/ui/select.tsx
index 1d0e3ff..c8798d4 100644
--- a/src/components/ui/select.tsx
+++ b/src/components/ui/select.tsx
@@ -1,10 +1,10 @@
"use client"
import * as React from "react"
-import * as SelectPrimitive from "@radix-ui/react-select"
-import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react"
+import { Select as SelectPrimitive } from "radix-ui"
import { cn } from "~/lib/utils"
+import { ChevronDownIcon, CheckIcon, ChevronUpIcon } from "lucide-react"
function Select({
...props
@@ -13,9 +13,16 @@ function Select({
}
function SelectGroup({
+ className,
...props
}: React.ComponentProps) {
- return
+ return (
+
+ )
}
function SelectValue({
@@ -37,14 +44,14 @@ function SelectTrigger({
data-slot="select-trigger"
data-size={size}
className={cn(
- "border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
+ "flex w-fit items-center justify-between gap-1.5 rounded-lg border border-input bg-transparent py-2 pr-2 pl-2.5 text-sm whitespace-nowrap transition-colors outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-placeholder:text-muted-foreground data-[size=default]:h-8 data-[size=sm]:h-7 data-[size=sm]:rounded-[min(var(--radius-md),10px)] *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className
)}
{...props}
>
{children}
-
+
)
@@ -53,28 +60,26 @@ function SelectTrigger({
function SelectContent({
className,
children,
- position = "popper",
+ position = "item-aligned",
+ align = "center",
...props
}: React.ComponentProps) {
return (
{children}
@@ -92,7 +97,7 @@ function SelectLabel({
return (
)
@@ -107,14 +112,14 @@ function SelectItem({
-
+
-
+
{children}
@@ -129,7 +134,7 @@ function SelectSeparator({
return (
)
@@ -143,12 +148,13 @@ function SelectScrollUpButton({
-
+
)
}
@@ -161,12 +167,13 @@ function SelectScrollDownButton({
-
+
)
}
diff --git a/src/components/ui/separator.tsx b/src/components/ui/separator.tsx
index 5d90a5d..9eeeb2d 100644
--- a/src/components/ui/separator.tsx
+++ b/src/components/ui/separator.tsx
@@ -1,7 +1,7 @@
"use client"
import * as React from "react"
-import * as SeparatorPrimitive from "@radix-ui/react-separator"
+import { Separator as SeparatorPrimitive } from "radix-ui"
import { cn } from "~/lib/utils"
@@ -17,7 +17,7 @@ function Separator({
decorative={decorative}
orientation={orientation}
className={cn(
- "bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
+ "shrink-0 bg-border data-horizontal:h-px data-horizontal:w-full data-vertical:w-px data-vertical:self-stretch",
className
)}
{...props}
diff --git a/src/components/ui/sheet.tsx b/src/components/ui/sheet.tsx
index c016b5c..f33115f 100644
--- a/src/components/ui/sheet.tsx
+++ b/src/components/ui/sheet.tsx
@@ -1,10 +1,11 @@
"use client"
import * as React from "react"
-import * as SheetPrimitive from "@radix-ui/react-dialog"
-import { XIcon } from "lucide-react"
+import { Dialog as SheetPrimitive } from "radix-ui"
import { cn } from "~/lib/utils"
+import { Button } from "~/components/ui/button"
+import { XIcon } from "lucide-react"
function Sheet({ ...props }: React.ComponentProps) {
return
@@ -36,7 +37,7 @@ function SheetOverlay({
& {
side?: "top" | "right" | "bottom" | "left"
+ showCloseButton?: boolean
}) {
return (
{children}
-
-
- Close
-
+ {showCloseButton && (
+
+
+
+ )}
)
@@ -85,7 +90,7 @@ function SheetHeader({ className, ...props }: React.ComponentProps<"div">) {
return (
)
@@ -108,7 +113,7 @@ function SheetTitle({
return (
)
@@ -121,7 +126,7 @@ function SheetDescription({
return (
)
diff --git a/src/components/ui/sidebar.tsx b/src/components/ui/sidebar.tsx
index 020e867..239a2a0 100644
--- a/src/components/ui/sidebar.tsx
+++ b/src/components/ui/sidebar.tsx
@@ -1,9 +1,8 @@
"use client"
import * as React from "react"
-import { Slot } from "@radix-ui/react-slot"
-import { cva, VariantProps } from "class-variance-authority"
-import { PanelLeftIcon } from "lucide-react"
+import { cva, type VariantProps } from "class-variance-authority"
+import { Slot } from "radix-ui"
import { useIsMobile } from "~/hooks/use-mobile"
import { cn } from "~/lib/utils"
@@ -21,9 +20,9 @@ import { Skeleton } from "~/components/ui/skeleton"
import {
Tooltip,
TooltipContent,
- TooltipProvider,
TooltipTrigger,
} from "~/components/ui/tooltip"
+import { PanelLeftIcon } from "lucide-react"
const SIDEBAR_COOKIE_NAME = "sidebar_state"
const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7
@@ -128,25 +127,23 @@ function SidebarProvider({
return (
-
-
- {children}
-
-
+
+ {children}
+
)
}
@@ -157,6 +154,7 @@ function Sidebar({
collapsible = "offcanvas",
className,
children,
+ dir,
...props
}: React.ComponentProps<"div"> & {
side?: "left" | "right"
@@ -170,7 +168,7 @@ function Sidebar({
{children}
@@ -265,8 +262,8 @@ function SidebarTrigger({
data-sidebar="trigger"
data-slot="sidebar-trigger"
variant="ghost"
- size="icon"
- className={cn("size-7", className)}
+ size="icon-sm"
+ className={cn(className)}
onClick={(event) => {
onClick?.(event)
toggleSidebar()
@@ -291,10 +288,10 @@ function SidebarRail({ className, ...props }: React.ComponentProps<"button">) {
onClick={toggleSidebar}
title="Toggle Sidebar"
className={cn(
- "hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] sm:flex",
+ "absolute inset-y-0 z-20 hidden w-4 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:start-1/2 after:w-[2px] hover:after:bg-sidebar-border sm:flex ltr:-translate-x-1/2 rtl:-translate-x-1/2",
"in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize",
"[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize",
- "hover:group-data-[collapsible=offcanvas]:bg-sidebar group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full",
+ "group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full hover:group-data-[collapsible=offcanvas]:bg-sidebar",
"[[data-side=left][data-collapsible=offcanvas]_&]:-right-2",
"[[data-side=right][data-collapsible=offcanvas]_&]:-left-2",
className
@@ -309,8 +306,7 @@ function SidebarInset({ className, ...props }: React.ComponentProps<"main">) {
)
@@ -362,7 +358,7 @@ function SidebarSeparator({
)
@@ -374,7 +370,7 @@ function SidebarContent({ className, ...props }: React.ComponentProps<"div">) {
data-slot="sidebar-content"
data-sidebar="content"
className={cn(
- "flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden",
+ "no-scrollbar flex min-h-0 flex-1 flex-col gap-0 overflow-auto group-data-[collapsible=icon]:overflow-hidden",
className
)}
{...props}
@@ -398,15 +394,14 @@ function SidebarGroupLabel({
asChild = false,
...props
}: React.ComponentProps<"div"> & { asChild?: boolean }) {
- const Comp = asChild ? Slot : "div"
+ const Comp = asChild ? Slot.Root : "div"
return (
svg]:size-4 [&>svg]:shrink-0",
- "group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",
+ "flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-sidebar-foreground/70 ring-sidebar-ring outline-hidden transition-[margin,opacity] duration-200 ease-linear group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0 focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
className
)}
{...props}
@@ -419,17 +414,14 @@ function SidebarGroupAction({
asChild = false,
...props
}: React.ComponentProps<"button"> & { asChild?: boolean }) {
- const Comp = asChild ? Slot : "button"
+ const Comp = asChild ? Slot.Root : "button"
return (
svg]:size-4 [&>svg]:shrink-0",
- // Increases the hit area of the button on mobile.
- "after:absolute after:-inset-2 md:after:hidden",
- "group-data-[collapsible=icon]:hidden",
+ "absolute top-3.5 right-3 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground ring-sidebar-ring outline-hidden transition-transform group-data-[collapsible=icon]:hidden after:absolute after:-inset-2 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 md:after:hidden [&>svg]:size-4 [&>svg]:shrink-0",
className
)}
{...props}
@@ -456,7 +448,7 @@ function SidebarMenu({ className, ...props }: React.ComponentProps<"ul">) {
)
@@ -474,7 +466,7 @@ function SidebarMenuItem({ className, ...props }: React.ComponentProps<"li">) {
}
const sidebarMenuButtonVariants = cva(
- "peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-data-[sidebar=menu-action]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
+ "peer/menu-button group/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm ring-sidebar-ring outline-hidden transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-open:hover:bg-sidebar-accent data-open:hover:text-sidebar-accent-foreground data-active:bg-sidebar-accent data-active:font-medium data-active:text-sidebar-accent-foreground [&_svg]:size-4 [&_svg]:shrink-0 [&>span:last-child]:truncate",
{
variants: {
variant: {
@@ -508,7 +500,7 @@ function SidebarMenuButton({
isActive?: boolean
tooltip?: string | React.ComponentProps
} & VariantProps) {
- const Comp = asChild ? Slot : "button"
+ const Comp = asChild ? Slot.Root : "button"
const { isMobile, state } = useSidebar()
const button = (
@@ -554,22 +546,16 @@ function SidebarMenuAction({
asChild?: boolean
showOnHover?: boolean
}) {
- const Comp = asChild ? Slot : "button"
+ const Comp = asChild ? Slot.Root : "button"
return (
svg]:size-4 [&>svg]:shrink-0",
- // Increases the hit area of the button on mobile.
- "after:absolute after:-inset-2 md:after:hidden",
- "peer-data-[size=sm]/menu-button:top-1",
- "peer-data-[size=default]/menu-button:top-1.5",
- "peer-data-[size=lg]/menu-button:top-2.5",
- "group-data-[collapsible=icon]:hidden",
+ "absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground ring-sidebar-ring outline-hidden transition-transform group-data-[collapsible=icon]:hidden peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[size=default]/menu-button:top-1.5 peer-data-[size=lg]/menu-button:top-2.5 peer-data-[size=sm]/menu-button:top-1 after:absolute after:-inset-2 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 md:after:hidden [&>svg]:size-4 [&>svg]:shrink-0",
showOnHover &&
- "peer-data-[active=true]/menu-button:text-sidebar-accent-foreground group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 md:opacity-0",
+ "group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 peer-data-active/menu-button:text-sidebar-accent-foreground aria-expanded:opacity-100 md:opacity-0",
className
)}
{...props}
@@ -586,12 +572,7 @@ function SidebarMenuBadge({
data-slot="sidebar-menu-badge"
data-sidebar="menu-badge"
className={cn(
- "text-sidebar-foreground pointer-events-none absolute right-1 flex h-5 min-w-5 items-center justify-center rounded-md px-1 text-xs font-medium tabular-nums select-none",
- "peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground",
- "peer-data-[size=sm]/menu-button:top-1",
- "peer-data-[size=default]/menu-button:top-1.5",
- "peer-data-[size=lg]/menu-button:top-2.5",
- "group-data-[collapsible=icon]:hidden",
+ "pointer-events-none absolute right-1 flex h-5 min-w-5 items-center justify-center rounded-md px-1 text-xs font-medium text-sidebar-foreground tabular-nums select-none group-data-[collapsible=icon]:hidden peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[size=default]/menu-button:top-1.5 peer-data-[size=lg]/menu-button:top-2.5 peer-data-[size=sm]/menu-button:top-1 peer-data-active/menu-button:text-sidebar-accent-foreground",
className
)}
{...props}
@@ -607,9 +588,9 @@ function SidebarMenuSkeleton({
showIcon?: boolean
}) {
// Random width between 50 to 90%.
- const width = React.useMemo(() => {
+ const [width] = React.useState(() => {
return `${Math.floor(Math.random() * 40) + 50}%`
- }, [])
+ })
return (
) {
data-slot="sidebar-menu-sub"
data-sidebar="menu-sub"
className={cn(
- "border-sidebar-border mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l px-2.5 py-0.5",
- "group-data-[collapsible=icon]:hidden",
+ "mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l border-sidebar-border px-2.5 py-0.5 group-data-[collapsible=icon]:hidden",
className
)}
{...props}
@@ -677,7 +657,7 @@ function SidebarMenuSubButton({
size?: "sm" | "md"
isActive?: boolean
}) {
- const Comp = asChild ? Slot : "a"
+ const Comp = asChild ? Slot.Root : "a"
return (
svg]:text-sidebar-accent-foreground flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 outline-hidden focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
- "data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground",
- size === "sm" && "text-xs",
- size === "md" && "text-sm",
- "group-data-[collapsible=icon]:hidden",
+ "flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 text-sidebar-foreground ring-sidebar-ring outline-hidden group-data-[collapsible=icon]:hidden hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[size=md]:text-sm data-[size=sm]:text-xs data-active:bg-sidebar-accent data-active:text-sidebar-accent-foreground [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-sidebar-accent-foreground",
className
)}
{...props}
diff --git a/src/components/ui/skeleton.tsx b/src/components/ui/skeleton.tsx
index 1e29d7a..91720f2 100644
--- a/src/components/ui/skeleton.tsx
+++ b/src/components/ui/skeleton.tsx
@@ -4,7 +4,7 @@ function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
return (
)
diff --git a/src/components/ui/slider.tsx b/src/components/ui/slider.tsx
index 51178ab..3847523 100644
--- a/src/components/ui/slider.tsx
+++ b/src/components/ui/slider.tsx
@@ -1,7 +1,7 @@
"use client"
import * as React from "react"
-import * as SliderPrimitive from "@radix-ui/react-slider"
+import { Slider as SliderPrimitive } from "radix-ui"
import { cn } from "~/lib/utils"
@@ -31,29 +31,25 @@ function Slider({
min={min}
max={max}
className={cn(
- "relative flex w-full touch-none items-center select-none data-[disabled]:opacity-50 data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col",
+ "relative flex w-full touch-none items-center select-none data-disabled:opacity-50 data-vertical:h-full data-vertical:min-h-40 data-vertical:w-auto data-vertical:flex-col",
className
)}
{...props}
>
{Array.from({ length: _values.length }, (_, index) => (
))}
diff --git a/src/components/ui/sonner.tsx b/src/components/ui/sonner.tsx
index 957524e..9280ee5 100644
--- a/src/components/ui/sonner.tsx
+++ b/src/components/ui/sonner.tsx
@@ -1,7 +1,8 @@
"use client"
import { useTheme } from "next-themes"
-import { Toaster as Sonner, ToasterProps } from "sonner"
+import { Toaster as Sonner, type ToasterProps } from "sonner"
+import { CircleCheckIcon, InfoIcon, TriangleAlertIcon, OctagonXIcon, Loader2Icon } from "lucide-react"
const Toaster = ({ ...props }: ToasterProps) => {
const { theme = "system" } = useTheme()
@@ -10,13 +11,36 @@ const Toaster = ({ ...props }: ToasterProps) => {
+ ),
+ info: (
+
+ ),
+ warning: (
+
+ ),
+ error: (
+
+ ),
+ loading: (
+
+ ),
+ }}
style={
{
"--normal-bg": "var(--popover)",
"--normal-text": "var(--popover-foreground)",
"--normal-border": "var(--border)",
+ "--border-radius": "var(--radius)",
} as React.CSSProperties
}
+ toastOptions={{
+ classNames: {
+ toast: "cn-toast",
+ },
+ }}
{...props}
/>
)
diff --git a/src/components/ui/switch.tsx b/src/components/ui/switch.tsx
index e3ce6ea..e417937 100644
--- a/src/components/ui/switch.tsx
+++ b/src/components/ui/switch.tsx
@@ -1,28 +1,30 @@
"use client"
import * as React from "react"
-import * as SwitchPrimitive from "@radix-ui/react-switch"
+import { Switch as SwitchPrimitive } from "radix-ui"
import { cn } from "~/lib/utils"
function Switch({
className,
+ size = "default",
...props
-}: React.ComponentProps) {
+}: React.ComponentProps & {
+ size?: "sm" | "default"
+}) {
return (
)
diff --git a/src/components/ui/table.tsx b/src/components/ui/table.tsx
index 80e98d4..95f2704 100644
--- a/src/components/ui/table.tsx
+++ b/src/components/ui/table.tsx
@@ -44,7 +44,7 @@ function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
tr]:last:border-b-0",
+ "border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
className
)}
{...props}
@@ -57,7 +57,7 @@ function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
) {
| [role=checkbox]]:translate-y-[2px]",
+ "h-10 px-2 text-left align-middle font-medium whitespace-nowrap text-foreground [&:has([role=checkbox])]:pr-0",
className
)}
{...props}
@@ -83,7 +83,7 @@ function TableCell({ className, ...props }: React.ComponentProps<"td">) {
| [role=checkbox]]:translate-y-[2px]",
+ "p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0",
className
)}
{...props}
@@ -98,7 +98,7 @@ function TableCaption({
return (
)
diff --git a/src/components/ui/tabs.tsx b/src/components/ui/tabs.tsx
index 49837b4..0a3ad10 100644
--- a/src/components/ui/tabs.tsx
+++ b/src/components/ui/tabs.tsx
@@ -1,34 +1,55 @@
"use client"
import * as React from "react"
-import * as TabsPrimitive from "@radix-ui/react-tabs"
+import { cva, type VariantProps } from "class-variance-authority"
+import { Tabs as TabsPrimitive } from "radix-ui"
import { cn } from "~/lib/utils"
function Tabs({
className,
+ orientation = "horizontal",
...props
}: React.ComponentProps) {
return (
)
}
+const tabsListVariants = cva(
+ "group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-horizontal/tabs:h-8 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none",
+ {
+ variants: {
+ variant: {
+ default: "bg-muted",
+ line: "gap-1 bg-transparent",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+ }
+)
+
function TabsList({
className,
+ variant = "default",
...props
-}: React.ComponentProps) {
+}: React.ComponentProps &
+ VariantProps) {
return (
)
@@ -42,7 +63,10 @@ function TabsTrigger({
)
}
-export { Tabs, TabsList, TabsTrigger, TabsContent }
+export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants }
diff --git a/src/components/ui/textarea.tsx b/src/components/ui/textarea.tsx
index 1c7ebff..da52002 100644
--- a/src/components/ui/textarea.tsx
+++ b/src/components/ui/textarea.tsx
@@ -7,7 +7,7 @@ function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
| |