Actualización shadcn/ui

This commit is contained in:
David Arranz 2025-10-21 11:30:45 +02:00
parent 7cad265aff
commit 6659962c73
39 changed files with 389 additions and 327 deletions

View File

@ -36,33 +36,33 @@
"postcss": "^8.5.3" "postcss": "^8.5.3"
}, },
"dependencies": { "dependencies": {
"@hookform/resolvers": "^5.0.1", "@hookform/resolvers": "^5.2.2",
"@radix-ui/react-accordion": "^1.2.10", "@radix-ui/react-accordion": "^1.2.12",
"@radix-ui/react-alert-dialog": "^1.1.13", "@radix-ui/react-alert-dialog": "^1.1.15",
"@radix-ui/react-aspect-ratio": "^1.1.6", "@radix-ui/react-aspect-ratio": "^1.1.7",
"@radix-ui/react-avatar": "^1.1.9", "@radix-ui/react-avatar": "^1.1.10",
"@radix-ui/react-checkbox": "^1.3.1", "@radix-ui/react-checkbox": "^1.3.3",
"@radix-ui/react-collapsible": "^1.1.10", "@radix-ui/react-collapsible": "^1.1.12",
"@radix-ui/react-context-menu": "^2.2.14", "@radix-ui/react-context-menu": "^2.2.16",
"@radix-ui/react-dialog": "^1.1.13", "@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-dropdown-menu": "^2.1.14", "@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-hover-card": "^1.1.13", "@radix-ui/react-hover-card": "^1.1.15",
"@radix-ui/react-label": "^2.1.7", "@radix-ui/react-label": "^2.1.7",
"@radix-ui/react-menubar": "^1.1.14", "@radix-ui/react-menubar": "^1.1.16",
"@radix-ui/react-navigation-menu": "^1.2.12", "@radix-ui/react-navigation-menu": "^1.2.14",
"@radix-ui/react-popover": "^1.1.13", "@radix-ui/react-popover": "^1.1.15",
"@radix-ui/react-progress": "^1.1.6", "@radix-ui/react-progress": "^1.1.7",
"@radix-ui/react-radio-group": "^1.3.6", "@radix-ui/react-radio-group": "^1.3.8",
"@radix-ui/react-scroll-area": "^1.2.8", "@radix-ui/react-scroll-area": "^1.2.10",
"@radix-ui/react-select": "^2.2.4", "@radix-ui/react-select": "^2.2.6",
"@radix-ui/react-separator": "^1.1.7", "@radix-ui/react-separator": "^1.1.7",
"@radix-ui/react-slider": "^1.3.4", "@radix-ui/react-slider": "^1.3.6",
"@radix-ui/react-slot": "^1.2.3", "@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-switch": "^1.2.4", "@radix-ui/react-switch": "^1.2.6",
"@radix-ui/react-tabs": "^1.1.11", "@radix-ui/react-tabs": "^1.1.13",
"@radix-ui/react-toggle": "^1.1.8", "@radix-ui/react-toggle": "^1.1.10",
"@radix-ui/react-toggle-group": "^1.1.9", "@radix-ui/react-toggle-group": "^1.1.11",
"@radix-ui/react-tooltip": "^1.2.6", "@radix-ui/react-tooltip": "^1.2.8",
"@tailwindcss/cli": "^4.1.5", "@tailwindcss/cli": "^4.1.5",
"add": "^2.0.6", "add": "^2.0.6",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
@ -78,14 +78,14 @@
"react": "^19.1.0", "react": "^19.1.0",
"react-day-picker": "9.11.1", "react-day-picker": "9.11.1",
"react-dom": "^19.1.0", "react-dom": "^19.1.0",
"react-hook-form": "^7.58.1", "react-hook-form": "^7.65.0",
"react-resizable-panels": "^3.0.1", "react-resizable-panels": "^3.0.6",
"recharts": "^2.15.3", "recharts": "^2.15.4",
"sonner": "^2.0.3", "sonner": "^2.0.7",
"tailwind-merge": "^3.2.0", "tailwind-merge": "^3.2.0",
"tailwindcss": "^4.1.5", "tailwindcss": "^4.1.5",
"tw-animate-css": "^1.2.9", "tw-animate-css": "^1.2.9",
"vaul": "^1.1.2", "vaul": "^1.1.2",
"zod": "^3.25.36" "zod": "^3.25.76"
} }
} }

View File

@ -1,5 +1,3 @@
"use client"
import * as React from "react" import * as React from "react"
import * as AccordionPrimitive from "@radix-ui/react-accordion" import * as AccordionPrimitive from "@radix-ui/react-accordion"
import { ChevronDownIcon } from "lucide-react" import { ChevronDownIcon } from "lucide-react"

View File

@ -1,5 +1,3 @@
"use client"
import * as React from "react" import * as React from "react"
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog" import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"

View File

@ -1,5 +1,3 @@
"use client"
import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio" import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio"
function AspectRatio({ function AspectRatio({

View File

@ -1,5 +1,3 @@
"use client"
import * as React from "react" import * as React from "react"
import * as AvatarPrimitive from "@radix-ui/react-avatar" import * as AvatarPrimitive from "@radix-ui/react-avatar"

View File

@ -5,7 +5,7 @@ import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@repo/shadcn-ui/lib/utils" import { cn } from "@repo/shadcn-ui/lib/utils"
const badgeVariants = cva( const badgeVariants = cva(
"inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none 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 transition-[color,box-shadow] overflow-hidden", "inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none 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 transition-[color,box-shadow] overflow-hidden",
{ {
variants: { variants: {
variant: { variant: {

View File

@ -1,6 +1,6 @@
import { Slot } from "@radix-ui/react-slot"
import { type VariantProps, cva } from "class-variance-authority"
import * as React from "react" import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@repo/shadcn-ui/lib/utils" import { cn } from "@repo/shadcn-ui/lib/utils"
@ -35,6 +35,7 @@ const buttonVariants = cva(
}, },
} }
) )
function Button({ function Button({
className, className,
variant, variant,
@ -46,6 +47,7 @@ function Button({
asChild?: boolean asChild?: boolean
}) { }) {
const Comp = asChild ? Slot : "button" const Comp = asChild ? Slot : "button"
return ( return (
<Comp <Comp
data-slot="button" data-slot="button"
@ -54,4 +56,5 @@ function Button({
/> />
) )
} }
export { Button, buttonVariants } export { Button, buttonVariants }

View File

@ -1,12 +1,13 @@
"use client"
import * as React from "react" import * as React from "react"
import {
ChevronDownIcon,
ChevronLeftIcon,
ChevronRightIcon,
} from "lucide-react"
import { DayButton, DayPicker, getDefaultClassNames } from "react-day-picker" import { DayButton, DayPicker, getDefaultClassNames } from "react-day-picker"
import { Button, buttonVariants } from "@repo/shadcn-ui/components/button"
import { cn } from "@repo/shadcn-ui/lib/utils" import { cn } from "@repo/shadcn-ui/lib/utils"
import { ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon } from 'lucide-react' import { Button, buttonVariants } from "@repo/shadcn-ui/components/button"
function Calendar({ function Calendar({
className, className,

View File

@ -1,75 +1,92 @@
import * as React from "react"; import * as React from "react"
import { cn } from "@repo/shadcn-ui/lib/utils"; import { cn } from "@repo/shadcn-ui/lib/utils"
function Card({ className, ...props }: React.ComponentProps<"div">) { function Card({ className, ...props }: React.ComponentProps<"div">) {
return ( return (
<div <div
data-slot='card' data-slot="card"
className={cn( className={cn(
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm", "bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
className className
)} )}
{...props} {...props}
/> />
); )
} }
function CardHeader({ className, ...props }: React.ComponentProps<"div">) { function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
return ( return (
<div <div
data-slot='card-header' data-slot="card-header"
className={cn( className={cn(
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6", "@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
className className
)} )}
{...props} {...props}
/> />
); )
} }
function CardTitle({ className, ...props }: React.ComponentProps<"div">) { function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
return ( return (
<div <div
data-slot='card-title' data-slot="card-title"
className={cn("leading-none font-semibold", className)} className={cn("leading-none font-semibold", className)}
{...props} {...props}
/> />
); )
} }
function CardDescription({ className, ...props }: React.ComponentProps<"div">) { function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
return ( return (
<div <div
data-slot='card-description' data-slot="card-description"
className={cn("text-muted-foreground text-sm", className)} className={cn("text-muted-foreground text-sm", className)}
{...props} {...props}
/> />
); )
} }
function CardAction({ className, ...props }: React.ComponentProps<"div">) { function CardAction({ className, ...props }: React.ComponentProps<"div">) {
return ( return (
<div <div
data-slot='card-action' data-slot="card-action"
className={cn("col-start-2 row-span-2 row-start-1 self-start justify-self-end", className)} className={cn(
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
className
)}
{...props} {...props}
/> />
); )
} }
function CardContent({ className, ...props }: React.ComponentProps<"div">) { function CardContent({ className, ...props }: React.ComponentProps<"div">) {
return <div data-slot='card-content' className={cn("px-6", className)} {...props} />; return (
<div
data-slot="card-content"
className={cn("px-6", className)}
{...props}
/>
)
} }
function CardFooter({ className, ...props }: React.ComponentProps<"div">) { function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
return ( return (
<div <div
data-slot='card-footer' data-slot="card-footer"
className={cn("flex items-center px-6 [.border-t]:pt-6", className)} className={cn("flex items-center px-6 [.border-t]:pt-6", className)}
{...props} {...props}
/> />
); )
} }
export { Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle }; export {
Card,
CardHeader,
CardFooter,
CardTitle,
CardAction,
CardDescription,
CardContent,
}

View File

@ -1,5 +1,3 @@
"use client"
import * as React from "react" import * as React from "react"
import useEmblaCarousel, { import useEmblaCarousel, {
type UseEmblaCarouselType, type UseEmblaCarouselType,

View File

@ -1,5 +1,3 @@
"use client"
import * as React from "react" import * as React from "react"
import * as RechartsPrimitive from "recharts" import * as RechartsPrimitive from "recharts"
@ -179,70 +177,72 @@ function ChartTooltipContent({
> >
{!nestLabel ? tooltipLabel : null} {!nestLabel ? tooltipLabel : null}
<div className="grid gap-1.5"> <div className="grid gap-1.5">
{payload.map((item, index) => { {payload
const key = `${nameKey || item.name || item.dataKey || "value"}` .filter((item) => item.type !== "none")
const itemConfig = getPayloadConfigFromPayload(config, item, key) .map((item, index) => {
const indicatorColor = color || item.payload.fill || item.color const key = `${nameKey || item.name || item.dataKey || "value"}`
const itemConfig = getPayloadConfigFromPayload(config, item, key)
const indicatorColor = color || item.payload.fill || item.color
return ( return (
<div <div
key={item.dataKey} key={item.dataKey}
className={cn( className={cn(
"[&>svg]:text-muted-foreground flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5", "[&>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" indicator === "dot" && "items-center"
)} )}
> >
{formatter && item?.value !== undefined && item.name ? ( {formatter && item?.value !== undefined && item.name ? (
formatter(item.value, item.name, item, index, item.payload) formatter(item.value, item.name, item, index, item.payload)
) : ( ) : (
<> <>
{itemConfig?.icon ? ( {itemConfig?.icon ? (
<itemConfig.icon /> <itemConfig.icon />
) : ( ) : (
!hideIndicator && ( !hideIndicator && (
<div <div
className={cn( className={cn(
"shrink-0 rounded-[2px] border-(--color-border) bg-(--color-bg)", "shrink-0 rounded-[2px] border-(--color-border) bg-(--color-bg)",
{ {
"h-2.5 w-2.5": indicator === "dot", "h-2.5 w-2.5": indicator === "dot",
"w-1": indicator === "line", "w-1": indicator === "line",
"w-0 border-[1.5px] border-dashed bg-transparent": "w-0 border-[1.5px] border-dashed bg-transparent":
indicator === "dashed", indicator === "dashed",
"my-0.5": nestLabel && indicator === "dashed", "my-0.5": nestLabel && indicator === "dashed",
}
)}
style={
{
"--color-bg": indicatorColor,
"--color-border": indicatorColor,
} as React.CSSProperties
} }
)} />
style={ )
{
"--color-bg": indicatorColor,
"--color-border": indicatorColor,
} as React.CSSProperties
}
/>
)
)}
<div
className={cn(
"flex flex-1 justify-between leading-none",
nestLabel ? "items-end" : "items-center"
)} )}
> <div
<div className="grid gap-1.5"> className={cn(
{nestLabel ? tooltipLabel : null} "flex flex-1 justify-between leading-none",
<span className="text-muted-foreground"> nestLabel ? "items-end" : "items-center"
{itemConfig?.label || item.name} )}
</span> >
<div className="grid gap-1.5">
{nestLabel ? tooltipLabel : null}
<span className="text-muted-foreground">
{itemConfig?.label || item.name}
</span>
</div>
{item.value && (
<span className="text-foreground font-mono font-medium tabular-nums">
{item.value.toLocaleString()}
</span>
)}
</div> </div>
{item.value && ( </>
<span className="text-foreground font-mono font-medium tabular-nums"> )}
{item.value.toLocaleString()} </div>
</span> )
)} })}
</div>
</>
)}
</div>
)
})}
</div> </div>
</div> </div>
) )
@ -275,31 +275,33 @@ function ChartLegendContent({
className className
)} )}
> >
{payload.map((item) => { {payload
const key = `${nameKey || item.dataKey || "value"}` .filter((item) => item.type !== "none")
const itemConfig = getPayloadConfigFromPayload(config, item, key) .map((item) => {
const key = `${nameKey || item.dataKey || "value"}`
const itemConfig = getPayloadConfigFromPayload(config, item, key)
return ( return (
<div <div
key={item.value} key={item.value}
className={cn( className={cn(
"[&>svg]:text-muted-foreground flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3" "[&>svg]:text-muted-foreground flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3"
)} )}
> >
{itemConfig?.icon && !hideIcon ? ( {itemConfig?.icon && !hideIcon ? (
<itemConfig.icon /> <itemConfig.icon />
) : ( ) : (
<div <div
className="h-2 w-2 shrink-0 rounded-[2px]" className="h-2 w-2 shrink-0 rounded-[2px]"
style={{ style={{
backgroundColor: item.color, backgroundColor: item.color,
}} }}
/> />
)} )}
{itemConfig?.label} {itemConfig?.label}
</div> </div>
) )
})} })}
</div> </div>
) )
} }

View File

@ -1,5 +1,3 @@
"use client"
import * as React from "react" import * as React from "react"
import * as CheckboxPrimitive from "@radix-ui/react-checkbox" import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
import { CheckIcon } from "lucide-react" import { CheckIcon } from "lucide-react"
@ -21,7 +19,7 @@ function Checkbox({
> >
<CheckboxPrimitive.Indicator <CheckboxPrimitive.Indicator
data-slot="checkbox-indicator" data-slot="checkbox-indicator"
className="flex items-center justify-center text-current transition-none" className="grid place-content-center text-current transition-none"
> >
<CheckIcon className="size-3.5" /> <CheckIcon className="size-3.5" />
</CheckboxPrimitive.Indicator> </CheckboxPrimitive.Indicator>

View File

@ -1,5 +1,3 @@
"use client"
import * as CollapsiblePrimitive from "@radix-ui/react-collapsible" import * as CollapsiblePrimitive from "@radix-ui/react-collapsible"
function Collapsible({ function Collapsible({

View File

@ -1,53 +1,63 @@
"use client"; "use client"
import { Command as CommandPrimitive } from "cmdk"; import * as React from "react"
import { SearchIcon } from "lucide-react"; import { Command as CommandPrimitive } from "cmdk"
import * as React from "react"; import { SearchIcon } from "lucide-react"
import { cn } from "@repo/shadcn-ui/lib/utils"
import { import {
Dialog, Dialog,
DialogContent, DialogContent,
DialogDescription, DialogDescription,
DialogHeader, DialogHeader,
DialogTitle, DialogTitle,
} from "@repo/shadcn-ui/components/dialog"; } from "@repo/shadcn-ui/components/dialog"
import { cn } from "@repo/shadcn-ui/lib/utils";
function Command({ className, ...props }: React.ComponentProps<typeof CommandPrimitive>) { function Command({
className,
...props
}: React.ComponentProps<typeof CommandPrimitive>) {
return ( return (
<CommandPrimitive <CommandPrimitive
data-slot='command' data-slot="command"
className={cn( className={cn(
"bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md", "bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md",
className className
)} )}
{...props} {...props}
/> />
); )
} }
function CommandDialog({ function CommandDialog({
title = "Command Palette", title = "Command Palette",
description = "Search for a command to run...", description = "Search for a command to run...",
children, children,
className,
showCloseButton = true,
...props ...props
}: React.ComponentProps<typeof Dialog> & { }: React.ComponentProps<typeof Dialog> & {
title?: string; title?: string
description?: string; description?: string
className?: string
showCloseButton?: boolean
}) { }) {
return ( return (
<Dialog {...props}> <Dialog {...props}>
<DialogHeader className='sr-only'> <DialogHeader className="sr-only">
<DialogTitle>{title}</DialogTitle> <DialogTitle>{title}</DialogTitle>
<DialogDescription>{description}</DialogDescription> <DialogDescription>{description}</DialogDescription>
</DialogHeader> </DialogHeader>
<DialogContent className='overflow-hidden p-0'> <DialogContent
<Command className='[&_[cmdk-group-heading]]:text-muted-foreground **:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5'> className={cn("overflow-hidden p-0", className)}
showCloseButton={showCloseButton}
>
<Command className="[&_[cmdk-group-heading]]:text-muted-foreground **:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
{children} {children}
</Command> </Command>
</DialogContent> </DialogContent>
</Dialog> </Dialog>
); )
} }
function CommandInput({ function CommandInput({
@ -55,10 +65,13 @@ function CommandInput({
...props ...props
}: React.ComponentProps<typeof CommandPrimitive.Input>) { }: React.ComponentProps<typeof CommandPrimitive.Input>) {
return ( return (
<div data-slot='command-input-wrapper' className='flex h-9 items-center gap-2 border-b px-3'> <div
<SearchIcon className='size-4 shrink-0 opacity-50' /> data-slot="command-input-wrapper"
className="flex h-9 items-center gap-2 border-b px-3"
>
<SearchIcon className="size-4 shrink-0 opacity-50" />
<CommandPrimitive.Input <CommandPrimitive.Input
data-slot='command-input' data-slot="command-input"
className={cn( className={cn(
"placeholder:text-muted-foreground flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50", "placeholder:text-muted-foreground flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50",
className className
@ -66,27 +79,35 @@ function CommandInput({
{...props} {...props}
/> />
</div> </div>
); )
} }
function CommandList({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.List>) { function CommandList({
className,
...props
}: React.ComponentProps<typeof CommandPrimitive.List>) {
return ( return (
<CommandPrimitive.List <CommandPrimitive.List
data-slot='command-list' data-slot="command-list"
className={cn("max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto", className)} className={cn(
"max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto",
className
)}
{...props} {...props}
/> />
); )
} }
function CommandEmpty({ ...props }: React.ComponentProps<typeof CommandPrimitive.Empty>) { function CommandEmpty({
...props
}: React.ComponentProps<typeof CommandPrimitive.Empty>) {
return ( return (
<CommandPrimitive.Empty <CommandPrimitive.Empty
data-slot='command-empty' data-slot="command-empty"
className='py-6 text-center text-sm' className="py-6 text-center text-sm"
{...props} {...props}
/> />
); )
} }
function CommandGroup({ function CommandGroup({
@ -95,14 +116,14 @@ function CommandGroup({
}: React.ComponentProps<typeof CommandPrimitive.Group>) { }: React.ComponentProps<typeof CommandPrimitive.Group>) {
return ( return (
<CommandPrimitive.Group <CommandPrimitive.Group
data-slot='command-group' data-slot="command-group"
className={cn( className={cn(
"text-foreground [&_[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium", "text-foreground [&_[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium",
className className
)} )}
{...props} {...props}
/> />
); )
} }
function CommandSeparator({ function CommandSeparator({
@ -111,44 +132,53 @@ function CommandSeparator({
}: React.ComponentProps<typeof CommandPrimitive.Separator>) { }: React.ComponentProps<typeof CommandPrimitive.Separator>) {
return ( return (
<CommandPrimitive.Separator <CommandPrimitive.Separator
data-slot='command-separator' data-slot="command-separator"
className={cn("bg-border -mx-1 h-px", className)} className={cn("bg-border -mx-1 h-px", className)}
{...props} {...props}
/> />
); )
} }
function CommandItem({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Item>) { function CommandItem({
className,
...props
}: React.ComponentProps<typeof CommandPrimitive.Item>) {
return ( return (
<CommandPrimitive.Item <CommandPrimitive.Item
data-slot='command-item' data-slot="command-item"
className={cn( className={cn(
"data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_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=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", "data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_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=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className className
)} )}
{...props} {...props}
/> />
); )
} }
function CommandShortcut({ className, ...props }: React.ComponentProps<"span">) { function CommandShortcut({
className,
...props
}: React.ComponentProps<"span">) {
return ( return (
<span <span
data-slot='command-shortcut' data-slot="command-shortcut"
className={cn("text-muted-foreground ml-auto text-xs tracking-widest", className)} className={cn(
"text-muted-foreground ml-auto text-xs tracking-widest",
className
)}
{...props} {...props}
/> />
); )
} }
export { export {
Command, Command,
CommandDialog, CommandDialog,
CommandInput,
CommandList,
CommandEmpty, CommandEmpty,
CommandGroup, CommandGroup,
CommandInput,
CommandItem, CommandItem,
CommandList,
CommandSeparator,
CommandShortcut, CommandShortcut,
}; CommandSeparator,
}

View File

@ -1,5 +1,3 @@
"use client"
import * as React from "react" import * as React from "react"
import * as ContextMenuPrimitive from "@radix-ui/react-context-menu" import * as ContextMenuPrimitive from "@radix-ui/react-context-menu"
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react" import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
@ -66,7 +64,7 @@ function ContextMenuSubTrigger({
data-slot="context-menu-sub-trigger" data-slot="context-menu-sub-trigger"
data-inset={inset} data-inset={inset}
className={cn( className={cn(
"focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", "focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className className
)} )}
{...props} {...props}

View File

@ -1,5 +1,3 @@
"use client"
import * as React from "react" import * as React from "react"
import * as DialogPrimitive from "@radix-ui/react-dialog" import * as DialogPrimitive from "@radix-ui/react-dialog"
import { XIcon } from "lucide-react" import { XIcon } from "lucide-react"
@ -49,8 +47,11 @@ function DialogOverlay({
function DialogContent({ function DialogContent({
className, className,
children, children,
showCloseButton = true,
...props ...props
}: React.ComponentProps<typeof DialogPrimitive.Content>) { }: React.ComponentProps<typeof DialogPrimitive.Content> & {
showCloseButton?: boolean
}) {
return ( return (
<DialogPortal data-slot="dialog-portal"> <DialogPortal data-slot="dialog-portal">
<DialogOverlay /> <DialogOverlay />
@ -63,10 +64,15 @@ function DialogContent({
{...props} {...props}
> >
{children} {children}
<DialogPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"> {showCloseButton && (
<XIcon /> <DialogPrimitive.Close
<span className="sr-only">Close</span> data-slot="dialog-close"
</DialogPrimitive.Close> className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
>
<XIcon />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
)}
</DialogPrimitive.Content> </DialogPrimitive.Content>
</DialogPortal> </DialogPortal>
) )

View File

@ -1,5 +1,3 @@
"use client"
import * as React from "react" import * as React from "react"
import { Drawer as DrawerPrimitive } from "vaul" import { Drawer as DrawerPrimitive } from "vaul"
@ -76,7 +74,10 @@ function DrawerHeader({ className, ...props }: React.ComponentProps<"div">) {
return ( return (
<div <div
data-slot="drawer-header" data-slot="drawer-header"
className={cn("flex flex-col gap-1.5 p-4", className)} className={cn(
"flex flex-col gap-0.5 p-4 group-data-[vaul-drawer-direction=bottom]/drawer-content:text-center group-data-[vaul-drawer-direction=top]/drawer-content:text-center md:gap-1.5 md:text-left",
className
)}
{...props} {...props}
/> />
) )

View File

@ -1,5 +1,3 @@
"use client"
import * as React from "react" import * as React from "react"
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu" import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react" import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
@ -211,7 +209,7 @@ function DropdownMenuSubTrigger({
data-slot="dropdown-menu-sub-trigger" data-slot="dropdown-menu-sub-trigger"
data-inset={inset} data-inset={inset}
className={cn( className={cn(
"focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8", "focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className className
)} )}
{...props} {...props}

View File

@ -1,9 +1,9 @@
import { type VariantProps, cva } from "class-variance-authority"
import { useMemo } from "react" import { useMemo } from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@repo/shadcn-ui/lib/utils"
import { Label } from "@repo/shadcn-ui/components/label" import { Label } from "@repo/shadcn-ui/components/label"
import { Separator } from "@repo/shadcn-ui/components/separator" import { Separator } from "@repo/shadcn-ui/components/separator"
import { cn } from "@repo/shadcn-ui/lib/utils"
function FieldSet({ className, ...props }: React.ComponentProps<"fieldset">) { function FieldSet({ className, ...props }: React.ComponentProps<"fieldset">) {
return ( return (
@ -198,7 +198,7 @@ function FieldError({
return null return null
} }
if (errors?.length === 1) { if (errors?.length == 1) {
return errors[0]?.message return errors[0]?.message
} }
@ -206,7 +206,7 @@ function FieldError({
<ul className="ml-4 flex list-disc flex-col gap-1"> <ul className="ml-4 flex list-disc flex-col gap-1">
{errors.map( {errors.map(
(error, index) => (error, index) =>
error?.message && <li key={`error-${index}`}>{error.message}</li> error?.message && <li key={index}>{error.message}</li>
)} )}
</ul> </ul>
) )
@ -229,10 +229,14 @@ function FieldError({
} }
export { export {
Field, FieldContent, FieldDescription, Field,
FieldLabel,
FieldDescription,
FieldError, FieldError,
FieldGroup, FieldLabel, FieldLegend, FieldGroup,
FieldLegend,
FieldSeparator, FieldSeparator,
FieldSet, FieldTitle FieldSet,
FieldContent,
FieldTitle,
} }

View File

@ -1,31 +1,33 @@
"use client"; "use client"
import * as LabelPrimitive from "@radix-ui/react-label"; import * as React from "react"
import { Slot } from "@radix-ui/react-slot"; import * as LabelPrimitive from "@radix-ui/react-label"
import * as React from "react"; import { Slot } from "@radix-ui/react-slot"
import { import {
Controller, Controller,
type ControllerProps,
type FieldPath,
type FieldValues,
FormProvider, FormProvider,
useFormContext, useFormContext,
useFormState, useFormState,
} from "react-hook-form"; type ControllerProps,
type FieldPath,
type FieldValues,
} from "react-hook-form"
import { Label } from "@repo/shadcn-ui/components/label"; import { cn } from "@repo/shadcn-ui/lib/utils"
import { cn } from "@repo/shadcn-ui/lib/utils"; import { Label } from "@repo/shadcn-ui/components/label"
const Form = FormProvider; const Form = FormProvider
type FormFieldContextValue< type FormFieldContextValue<
TFieldValues extends FieldValues = FieldValues, TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
> = { > = {
name: TName; name: TName
}; }
const FormFieldContext = React.createContext<FormFieldContextValue>({} as FormFieldContextValue); const FormFieldContext = React.createContext<FormFieldContextValue>(
{} as FormFieldContextValue
)
const FormField = < const FormField = <
TFieldValues extends FieldValues = FieldValues, TFieldValues extends FieldValues = FieldValues,
@ -37,21 +39,21 @@ const FormField = <
<FormFieldContext.Provider value={{ name: props.name }}> <FormFieldContext.Provider value={{ name: props.name }}>
<Controller {...props} /> <Controller {...props} />
</FormFieldContext.Provider> </FormFieldContext.Provider>
); )
}; }
const useFormField = () => { const useFormField = () => {
const fieldContext = React.useContext(FormFieldContext); const fieldContext = React.useContext(FormFieldContext)
const itemContext = React.useContext(FormItemContext); const itemContext = React.useContext(FormItemContext)
const { getFieldState } = useFormContext(); const { getFieldState } = useFormContext()
const formState = useFormState({ name: fieldContext.name }); const formState = useFormState({ name: fieldContext.name })
const fieldState = getFieldState(fieldContext.name, formState); const fieldState = getFieldState(fieldContext.name, formState)
if (!fieldContext) { if (!fieldContext) {
throw new Error("useFormField should be used within <FormField>"); throw new Error("useFormField should be used within <FormField>")
} }
const { id } = itemContext; const { id } = itemContext
return { return {
id, id,
@ -60,94 +62,106 @@ const useFormField = () => {
formDescriptionId: `${id}-form-item-description`, formDescriptionId: `${id}-form-item-description`,
formMessageId: `${id}-form-item-message`, formMessageId: `${id}-form-item-message`,
...fieldState, ...fieldState,
}; }
}; }
type FormItemContextValue = { type FormItemContextValue = {
id: string; id: string
}; }
const FormItemContext = React.createContext<FormItemContextValue>({} as FormItemContextValue); const FormItemContext = React.createContext<FormItemContextValue>(
{} as FormItemContextValue
)
function FormItem({ className, ...props }: React.ComponentProps<"div">) { function FormItem({ className, ...props }: React.ComponentProps<"div">) {
const id = React.useId(); const id = React.useId()
return ( return (
<FormItemContext.Provider value={{ id }}> <FormItemContext.Provider value={{ id }}>
<div data-slot='form-item' className={cn("grid gap-2", className)} {...props} /> <div
data-slot="form-item"
className={cn("grid gap-2", className)}
{...props}
/>
</FormItemContext.Provider> </FormItemContext.Provider>
); )
} }
function FormLabel({ className, ...props }: React.ComponentProps<typeof LabelPrimitive.Root>) { function FormLabel({
const { error, formItemId } = useFormField(); className,
...props
}: React.ComponentProps<typeof LabelPrimitive.Root>) {
const { error, formItemId } = useFormField()
return ( return (
<Label <Label
data-slot='form-label' data-slot="form-label"
data-error={!!error} data-error={!!error}
className={cn("data-[error=true]:text-destructive", className)} className={cn("data-[error=true]:text-destructive", className)}
htmlFor={formItemId} htmlFor={formItemId}
{...props} {...props}
/> />
); )
} }
function FormControl({ ...props }: React.ComponentProps<typeof Slot>) { function FormControl({ ...props }: React.ComponentProps<typeof Slot>) {
const { error, formItemId, formDescriptionId, formMessageId } = useFormField(); const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
return ( return (
<Slot <Slot
data-slot='form-control' data-slot="form-control"
id={formItemId} id={formItemId}
aria-describedby={!error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`} aria-describedby={
!error
? `${formDescriptionId}`
: `${formDescriptionId} ${formMessageId}`
}
aria-invalid={!!error} aria-invalid={!!error}
{...props} {...props}
/> />
); )
} }
function FormDescription({ className, ...props }: React.ComponentProps<"p">) { function FormDescription({ className, ...props }: React.ComponentProps<"p">) {
const { formDescriptionId } = useFormField(); const { formDescriptionId } = useFormField()
return ( return (
<p <p
data-slot='form-description' data-slot="form-description"
id={formDescriptionId} id={formDescriptionId}
className={cn("text-muted-foreground text-sm", className)} className={cn("text-muted-foreground text-sm", className)}
{...props} {...props}
/> />
); )
} }
function FormMessage({ className, ...props }: React.ComponentProps<"p">) { function FormMessage({ className, ...props }: React.ComponentProps<"p">) {
const { error, formMessageId } = useFormField(); const { error, formMessageId } = useFormField()
const body = error ? String(error?.message ?? "") : props.children; const body = error ? String(error?.message ?? "") : props.children
if (!body) { if (!body) {
return null; return null
} }
return ( return (
<p <p
data-slot='form-message' data-slot="form-message"
id={formMessageId} id={formMessageId}
className={cn("text-destructive text-sm", className)} className={cn("text-destructive text-sm", className)}
{...props} {...props}
> >
{body} {body}
</p> </p>
); )
} }
export { export {
useFormField,
Form, Form,
FormControl,
FormDescription,
FormField,
FormItem, FormItem,
FormLabel, FormLabel,
FormControl,
FormDescription,
FormMessage, FormMessage,
useFormField FormField,
}; }

View File

@ -1,5 +1,3 @@
"use client"
import * as React from "react" import * as React from "react"
import * as HoverCardPrimitive from "@radix-ui/react-hover-card" import * as HoverCardPrimitive from "@radix-ui/react-hover-card"

View File

@ -1,5 +1,3 @@
"use client"
import * as React from "react" import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority" import { cva, type VariantProps } from "class-variance-authority"

View File

@ -1,5 +1,3 @@
"use client"
import * as React from "react" import * as React from "react"
import * as MenubarPrimitive from "@radix-ui/react-menubar" import * as MenubarPrimitive from "@radix-ui/react-menubar"
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react" import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"

View File

@ -1,16 +1,17 @@
import * as React from "react"
import { import {
ChevronLeftIcon, ChevronLeftIcon,
ChevronRightIcon, ChevronRightIcon,
MoreHorizontalIcon, MoreHorizontalIcon,
} from "lucide-react" } from "lucide-react"
import * as React from "react"
import { Button, buttonVariants } from "@repo/shadcn-ui/components/button"
import { cn } from "@repo/shadcn-ui/lib/utils" import { cn } from "@repo/shadcn-ui/lib/utils"
import { Button, buttonVariants } from "@repo/shadcn-ui/components/button"
function Pagination({ className, ...props }: React.ComponentProps<"nav">) { function Pagination({ className, ...props }: React.ComponentProps<"nav">) {
return ( return (
<nav <nav
role="navigation"
aria-label="pagination" aria-label="pagination"
data-slot="pagination" data-slot="pagination"
className={cn("mx-auto flex w-full justify-center", className)} className={cn("mx-auto flex w-full justify-center", className)}
@ -117,6 +118,10 @@ function PaginationEllipsis({
export { export {
Pagination, Pagination,
PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious PaginationContent,
PaginationLink,
PaginationItem,
PaginationPrevious,
PaginationNext,
PaginationEllipsis,
} }

View File

@ -1,5 +1,3 @@
"use client"
import * as React from "react" import * as React from "react"
import * as PopoverPrimitive from "@radix-ui/react-popover" import * as PopoverPrimitive from "@radix-ui/react-popover"

View File

@ -1,5 +1,3 @@
"use client"
import * as React from "react" import * as React from "react"
import * as ProgressPrimitive from "@radix-ui/react-progress" import * as ProgressPrimitive from "@radix-ui/react-progress"

View File

@ -1,5 +1,3 @@
"use client"
import * as React from "react" import * as React from "react"
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group" import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"
import { CircleIcon } from "lucide-react" import { CircleIcon } from "lucide-react"

View File

@ -1,5 +1,3 @@
"use client"
import * as React from "react" import * as React from "react"
import { GripVerticalIcon } from "lucide-react" import { GripVerticalIcon } from "lucide-react"
import * as ResizablePrimitive from "react-resizable-panels" import * as ResizablePrimitive from "react-resizable-panels"
@ -39,7 +37,7 @@ function ResizableHandle({
<ResizablePrimitive.PanelResizeHandle <ResizablePrimitive.PanelResizeHandle
data-slot="resizable-handle" data-slot="resizable-handle"
className={cn( className={cn(
"bg-border focus-visible:ring-ring relative flex w-px items-center justify-center 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-offset-1 focus-visible:outline-hidden data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90", "bg-border focus-visible:ring-ring relative flex w-px items-center justify-center 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-offset-1 focus-visible:outline-hidden data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:translate-x-0 data-[panel-group-direction=vertical]:after:-translate-y-1/2 [&[data-panel-group-direction=vertical]>div]:rotate-90",
className className
)} )}
{...props} {...props}

View File

@ -1,5 +1,3 @@
"use client"
import * as React from "react" import * as React from "react"
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area" import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"

View File

@ -1,5 +1,3 @@
"use client"
import * as React from "react" import * as React from "react"
import * as SelectPrimitive from "@radix-ui/react-select" import * as SelectPrimitive from "@radix-ui/react-select"
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react" import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react"
@ -54,6 +52,7 @@ function SelectContent({
className, className,
children, children,
position = "popper", position = "popper",
align = "center",
...props ...props
}: React.ComponentProps<typeof SelectPrimitive.Content>) { }: React.ComponentProps<typeof SelectPrimitive.Content>) {
return ( return (
@ -67,6 +66,7 @@ function SelectContent({
className className
)} )}
position={position} position={position}
align={align}
{...props} {...props}
> >
<SelectScrollUpButton /> <SelectScrollUpButton />

View File

@ -1,5 +1,3 @@
"use client"
import * as React from "react" import * as React from "react"
import * as SheetPrimitive from "@radix-ui/react-dialog" import * as SheetPrimitive from "@radix-ui/react-dialog"
import { XIcon } from "lucide-react" import { XIcon } from "lucide-react"

View File

@ -1,5 +1,3 @@
"use client"
import * as React from "react" import * as React from "react"
import * as SliderPrimitive from "@radix-ui/react-slider" import * as SliderPrimitive from "@radix-ui/react-slider"
@ -53,7 +51,7 @@ function Slider({
<SliderPrimitive.Thumb <SliderPrimitive.Thumb
data-slot="slider-thumb" data-slot="slider-thumb"
key={index} key={index}
className="border-primary bg-background ring-ring/50 block size-4 shrink-0 rounded-full border shadow-sm transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50" className="border-primary ring-ring/50 block size-4 shrink-0 rounded-full border bg-white shadow-sm transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50"
/> />
))} ))}
</SliderPrimitive.Root> </SliderPrimitive.Root>

View File

@ -1,25 +1,38 @@
"use client"; import {
CircleCheckIcon,
import { useTheme } from "next-themes"; InfoIcon,
import { Toaster as Sonner, ToasterProps, toast } from "sonner"; Loader2Icon,
OctagonXIcon,
TriangleAlertIcon,
} from "lucide-react"
import { useTheme } from "next-themes"
import { Toaster as Sonner, type ToasterProps, toast } from "sonner"
const Toaster = ({ ...props }: ToasterProps) => { const Toaster = ({ ...props }: ToasterProps) => {
const { theme = "system" } = useTheme(); const { theme = "system" } = useTheme()
return ( return (
<Sonner <Sonner
theme={theme as ToasterProps["theme"]} theme={theme as ToasterProps["theme"]}
className='toaster group' className="toaster group"
icons={{
success: <CircleCheckIcon className="size-4" />,
info: <InfoIcon className="size-4" />,
warning: <TriangleAlertIcon className="size-4" />,
error: <OctagonXIcon className="size-4" />,
loading: <Loader2Icon className="size-4 animate-spin" />,
}}
style={ style={
{ {
"--normal-bg": "var(--popover)", "--normal-bg": "var(--popover)",
"--normal-text": "var(--popover-foreground)", "--normal-text": "var(--popover-foreground)",
"--normal-border": "var(--border)", "--normal-border": "var(--border)",
"--border-radius": "var(--radius)",
} as React.CSSProperties } as React.CSSProperties
} }
{...props} {...props}
/> />
); )
}; }
export { Toaster, toast }; export { Toaster, toast }

View File

@ -1,5 +1,3 @@
"use client"
import * as React from "react" import * as React from "react"
import * as SwitchPrimitive from "@radix-ui/react-switch" import * as SwitchPrimitive from "@radix-ui/react-switch"

View File

@ -1,5 +1,3 @@
"use client"
import * as React from "react" import * as React from "react"
import * as TabsPrimitive from "@radix-ui/react-tabs" import * as TabsPrimitive from "@radix-ui/react-tabs"

View File

@ -8,32 +8,40 @@ import { cn } from "@repo/shadcn-ui/lib/utils"
import { toggleVariants } from "@repo/shadcn-ui/components/toggle" import { toggleVariants } from "@repo/shadcn-ui/components/toggle"
const ToggleGroupContext = React.createContext< const ToggleGroupContext = React.createContext<
VariantProps<typeof toggleVariants> VariantProps<typeof toggleVariants> & {
spacing?: number
}
>({ >({
size: "default", size: "default",
variant: "default", variant: "default",
spacing: 0,
}) })
function ToggleGroup({ function ToggleGroup({
className, className,
variant, variant,
size, size,
spacing = 0,
children, children,
...props ...props
}: React.ComponentProps<typeof ToggleGroupPrimitive.Root> & }: React.ComponentProps<typeof ToggleGroupPrimitive.Root> &
VariantProps<typeof toggleVariants>) { VariantProps<typeof toggleVariants> & {
spacing?: number
}) {
return ( return (
<ToggleGroupPrimitive.Root <ToggleGroupPrimitive.Root
data-slot="toggle-group" data-slot="toggle-group"
data-variant={variant} data-variant={variant}
data-size={size} data-size={size}
data-spacing={spacing}
style={{ "--gap": spacing } as React.CSSProperties}
className={cn( className={cn(
"group/toggle-group flex w-fit items-center rounded-md data-[variant=outline]:shadow-xs", "group/toggle-group flex w-fit items-center gap-[--spacing(var(--gap))] rounded-md data-[spacing=default]:data-[variant=outline]:shadow-xs",
className className
)} )}
{...props} {...props}
> >
<ToggleGroupContext.Provider value={{ variant, size }}> <ToggleGroupContext.Provider value={{ variant, size, spacing }}>
{children} {children}
</ToggleGroupContext.Provider> </ToggleGroupContext.Provider>
</ToggleGroupPrimitive.Root> </ToggleGroupPrimitive.Root>
@ -55,12 +63,14 @@ function ToggleGroupItem({
data-slot="toggle-group-item" data-slot="toggle-group-item"
data-variant={context.variant || variant} data-variant={context.variant || variant}
data-size={context.size || size} data-size={context.size || size}
data-spacing={context.spacing}
className={cn( className={cn(
toggleVariants({ toggleVariants({
variant: context.variant || variant, variant: context.variant || variant,
size: context.size || size, size: context.size || size,
}), }),
"min-w-0 flex-1 shrink-0 rounded-none shadow-none first:rounded-l-md last:rounded-r-md focus:z-10 focus-visible:z-10 data-[variant=outline]:border-l-0 data-[variant=outline]:first:border-l", "w-auto min-w-0 shrink-0 px-3 focus:z-10 focus-visible:z-10",
"data-[spacing=0]:rounded-none data-[spacing=0]:shadow-none data-[spacing=0]:first:rounded-l-md data-[spacing=0]:last:rounded-r-md data-[spacing=0]:data-[variant=outline]:border-l-0 data-[spacing=0]:data-[variant=outline]:first:border-l",
className className
)} )}
{...props} {...props}

View File

@ -1,5 +1,3 @@
"use client"
import * as React from "react" import * as React from "react"
import * as TogglePrimitive from "@radix-ui/react-toggle" import * as TogglePrimitive from "@radix-ui/react-toggle"
import { cva, type VariantProps } from "class-variance-authority" import { cva, type VariantProps } from "class-variance-authority"

View File

@ -1,5 +1,3 @@
"use client"
import * as React from "react" import * as React from "react"
import * as TooltipPrimitive from "@radix-ui/react-tooltip" import * as TooltipPrimitive from "@radix-ui/react-tooltip"
@ -46,13 +44,13 @@ function TooltipContent({
data-slot="tooltip-content" data-slot="tooltip-content"
sideOffset={sideOffset} sideOffset={sideOffset}
className={cn( className={cn(
"bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-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-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance", "bg-foreground text-background animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-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-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
className className
)} )}
{...props} {...props}
> >
{children} {children}
<TooltipPrimitive.Arrow className="bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" /> <TooltipPrimitive.Arrow className="bg-foreground fill-foreground z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" />
</TooltipPrimitive.Content> </TooltipPrimitive.Content>
</TooltipPrimitive.Portal> </TooltipPrimitive.Portal>
) )

View File

@ -0,0 +1,2 @@
#/bin/sh
for file in src/components/*.tsx; do pnpm dlx shadcn@latest add -y -o $(basename "$file" .tsx); done