-
+
Leafdown
diff --git a/src/components/ui/Button.tsx b/src/components/ui/Button.tsx
deleted file mode 100644
index 112d732..0000000
--- a/src/components/ui/Button.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-import { cva, type VariantProps } from "class-variance-authority";
-import { Slot } from "radix-ui";
-import type { ComponentProps } from "react";
-
-import { cn } from "@/lib/cn";
-
-const buttonVariants = cva(
- "group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 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",
- {
- variants: {
- variant: {
- default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
- outline:
- "border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
- secondary:
- "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
- ghost:
- "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
- destructive:
- "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
- link: "text-primary underline-offset-4 hover:underline",
- },
- size: {
- default:
- "h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
- xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
- sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
- lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
- icon: "size-8",
- "icon-xs":
- "size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",
- "icon-sm":
- "size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg",
- "icon-lg": "size-9",
- },
- },
- defaultVariants: {
- variant: "default",
- size: "default",
- },
- },
-);
-
-function Button({
- className,
- variant = "default",
- size = "default",
- asChild = false,
- ...props
-}: ComponentProps<"button"> &
- VariantProps & {
- asChild?: boolean;
- }) {
- const Comp = asChild ? Slot.Root : "button";
-
- return (
-
- );
-}
-
-export { Button, buttonVariants };
diff --git a/src/components/ui/Checkbox.tsx b/src/components/ui/Checkbox.tsx
deleted file mode 100644
index 9d4e40e..0000000
--- a/src/components/ui/Checkbox.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import { CheckIcon } from "lucide-react";
-import { Checkbox as CheckboxPrimitive } from "radix-ui";
-import type { ComponentProps } from "react";
-
-import { cn } from "@/lib/cn";
-
-function Checkbox({ className, ...props }: ComponentProps) {
- return (
-
-
-
-
-
- );
-}
-
-export { Checkbox };
diff --git a/src/components/ui/DropdownMenu.tsx b/src/components/ui/DropdownMenu.tsx
deleted file mode 100644
index 0fce734..0000000
--- a/src/components/ui/DropdownMenu.tsx
+++ /dev/null
@@ -1,244 +0,0 @@
-import { CheckIcon, ChevronRightIcon } from "lucide-react";
-import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui";
-import type { ComponentProps } from "react";
-
-import { cn } from "@/lib/cn";
-
-function DropdownMenu({ ...props }: ComponentProps) {
- return ;
-}
-
-function DropdownMenuPortal({ ...props }: ComponentProps) {
- return ;
-}
-
-function DropdownMenuTrigger({ ...props }: ComponentProps) {
- return ;
-}
-
-function DropdownMenuContent({
- className,
- align = "start",
- sideOffset = 4,
- ...props
-}: ComponentProps) {
- return (
-
-
-
- );
-}
-
-function DropdownMenuGroup({ ...props }: ComponentProps) {
- return ;
-}
-
-function DropdownMenuItem({
- className,
- inset,
- variant = "default",
- ...props
-}: ComponentProps & {
- inset?: boolean;
- variant?: "default" | "destructive";
-}) {
- return (
-
- );
-}
-
-function DropdownMenuCheckboxItem({
- className,
- children,
- checked,
- inset,
- ...props
-}: ComponentProps & {
- inset?: boolean;
-}) {
- return (
-
-
-
-
-
-
- {children}
-
- );
-}
-
-function DropdownMenuRadioGroup({
- ...props
-}: ComponentProps) {
- return ;
-}
-
-function DropdownMenuRadioItem({
- className,
- children,
- inset,
- ...props
-}: ComponentProps & {
- inset?: boolean;
-}) {
- return (
-
-
-
-
-
-
- {children}
-
- );
-}
-
-function DropdownMenuLabel({
- className,
- inset,
- ...props
-}: ComponentProps & {
- inset?: boolean;
-}) {
- return (
-
- );
-}
-
-function DropdownMenuSeparator({
- className,
- ...props
-}: ComponentProps) {
- return (
-
- );
-}
-
-function DropdownMenuShortcut({ className, ...props }: ComponentProps<"span">) {
- return (
-
- );
-}
-
-function DropdownMenuSub({ ...props }: ComponentProps) {
- return ;
-}
-
-function DropdownMenuSubTrigger({
- className,
- inset,
- children,
- ...props
-}: ComponentProps & {
- inset?: boolean;
-}) {
- return (
-
- {children}
-
-
- );
-}
-
-function DropdownMenuSubContent({
- className,
- ...props
-}: ComponentProps) {
- return (
-
- );
-}
-
-export {
- DropdownMenu,
- DropdownMenuCheckboxItem,
- DropdownMenuContent,
- DropdownMenuGroup,
- DropdownMenuItem,
- DropdownMenuLabel,
- DropdownMenuPortal,
- DropdownMenuRadioGroup,
- DropdownMenuRadioItem,
- DropdownMenuSeparator,
- DropdownMenuShortcut,
- DropdownMenuSub,
- DropdownMenuSubContent,
- DropdownMenuSubTrigger,
- DropdownMenuTrigger,
-};
diff --git a/src/components/ui/Input.tsx b/src/components/ui/Input.tsx
deleted file mode 100644
index 46ff7ee..0000000
--- a/src/components/ui/Input.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import type { ComponentProps } from "react";
-
-import { cn } from "@/lib/cn";
-
-function Input({ className, type, ...props }: ComponentProps<"input">) {
- return (
-
- );
-}
-
-export { Input };
diff --git a/src/components/ui/Menubar.tsx b/src/components/ui/Menubar.tsx
deleted file mode 100644
index 6d59793..0000000
--- a/src/components/ui/Menubar.tsx
+++ /dev/null
@@ -1,255 +0,0 @@
-import { CheckIcon, ChevronRightIcon } from "lucide-react";
-import { Menubar as MenubarPrimitive } from "radix-ui";
-import type { ComponentProps } from "react";
-
-import { cn } from "@/lib/cn";
-
-function Menubar({ className, ...props }: ComponentProps) {
- return (
-
- );
-}
-
-function MenubarMenu({ ...props }: ComponentProps) {
- return ;
-}
-
-function MenubarGroup({ ...props }: ComponentProps) {
- return ;
-}
-
-function MenubarPortal({ ...props }: ComponentProps) {
- return ;
-}
-
-function MenubarRadioGroup({ ...props }: ComponentProps) {
- return ;
-}
-
-function MenubarTrigger({ className, ...props }: ComponentProps) {
- return (
-
- );
-}
-
-function MenubarContent({
- className,
- align = "start",
- alignOffset = -4,
- sideOffset = 8,
- ...props
-}: ComponentProps) {
- return (
-
-
-
- );
-}
-
-function MenubarItem({
- className,
- inset,
- variant = "default",
- ...props
-}: ComponentProps & {
- inset?: boolean;
- variant?: "default" | "destructive";
-}) {
- return (
-
- );
-}
-
-function MenubarCheckboxItem({
- className,
- children,
- checked,
- inset,
- ...props
-}: ComponentProps & {
- inset?: boolean;
-}) {
- return (
-
-
-
-
-
-
- {children}
-
- );
-}
-
-function MenubarRadioItem({
- className,
- children,
- inset,
- ...props
-}: ComponentProps & {
- inset?: boolean;
-}) {
- return (
-
-
-
-
-
-
- {children}
-
- );
-}
-
-function MenubarLabel({
- className,
- inset,
- ...props
-}: ComponentProps & {
- inset?: boolean;
-}) {
- return (
-
- );
-}
-
-function MenubarSeparator({
- className,
- ...props
-}: ComponentProps) {
- return (
-
- );
-}
-
-function MenubarShortcut({ className, ...props }: ComponentProps<"span">) {
- return (
-
- );
-}
-
-function MenubarSub({ ...props }: ComponentProps) {
- return ;
-}
-
-function MenubarSubTrigger({
- className,
- inset,
- children,
- ...props
-}: ComponentProps & {
- inset?: boolean;
-}) {
- return (
-
- {children}
-
-
- );
-}
-
-function MenubarSubContent({
- className,
- ...props
-}: ComponentProps) {
- return (
-
- );
-}
-
-export {
- Menubar,
- MenubarCheckboxItem,
- MenubarContent,
- MenubarGroup,
- MenubarItem,
- MenubarLabel,
- MenubarMenu,
- MenubarPortal,
- MenubarRadioGroup,
- MenubarRadioItem,
- MenubarSeparator,
- MenubarShortcut,
- MenubarSub,
- MenubarSubContent,
- MenubarSubTrigger,
- MenubarTrigger,
-};
diff --git a/src/components/ui/Popover.tsx b/src/components/ui/Popover.tsx
deleted file mode 100644
index 274a7cd..0000000
--- a/src/components/ui/Popover.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-import { Popover as PopoverPrimitive } from "radix-ui";
-import type { ComponentProps } from "react";
-
-import { cn } from "@/lib/cn";
-
-function Popover({ ...props }: ComponentProps) {
- return ;
-}
-
-function PopoverTrigger({ ...props }: ComponentProps) {
- return ;
-}
-
-function PopoverContent({
- className,
- align = "center",
- sideOffset = 4,
- ...props
-}: ComponentProps) {
- return (
-
-
-
- );
-}
-
-function PopoverAnchor({ ...props }: ComponentProps) {
- return ;
-}
-
-function PopoverHeader({ className, ...props }: ComponentProps<"div">) {
- return (
-
- );
-}
-
-function PopoverTitle({ className, ...props }: ComponentProps<"h2">) {
- return ;
-}
-
-function PopoverDescription({ className, ...props }: ComponentProps<"p">) {
- return (
-
- );
-}
-
-export {
- Popover,
- PopoverAnchor,
- PopoverContent,
- PopoverDescription,
- PopoverHeader,
- PopoverTitle,
- PopoverTrigger,
-};
diff --git a/src/components/ui/Separator.tsx b/src/components/ui/Separator.tsx
deleted file mode 100644
index e378aa2..0000000
--- a/src/components/ui/Separator.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import { Separator as SeparatorPrimitive } from "radix-ui";
-import type { ComponentProps } from "react";
-
-import { cn } from "@/lib/cn";
-
-function Separator({
- className,
- orientation = "horizontal",
- decorative = true,
- ...props
-}: ComponentProps) {
- return (
-
- );
-}
-
-export { Separator };
diff --git a/src/components/ui/Sonner.tsx b/src/components/ui/Sonner.tsx
deleted file mode 100644
index c2bd47a..0000000
--- a/src/components/ui/Sonner.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-import {
- CircleCheckIcon,
- InfoIcon,
- Loader2Icon,
- OctagonXIcon,
- TriangleAlertIcon,
-} from "lucide-react";
-import type { CSSProperties } from "react";
-import { Toaster as Sonner, type ToasterProps } from "sonner";
-
-function Toaster(props: ToasterProps) {
- return (
- ,
- info: ,
- warning: ,
- error: ,
- loading: ,
- }}
- style={
- {
- "--normal-bg": "var(--popover)",
- "--normal-text": "var(--popover-foreground)",
- "--normal-border": "var(--border)",
- "--border-radius": "var(--radius)",
- } as CSSProperties
- }
- {...props}
- />
- );
-}
-
-export { Toaster };
diff --git a/src/components/ui/Textarea.tsx b/src/components/ui/Textarea.tsx
deleted file mode 100644
index 87db097..0000000
--- a/src/components/ui/Textarea.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import type { ComponentProps } from "react";
-
-import { cn } from "@/lib/cn";
-
-function Textarea({ className, ...props }: ComponentProps<"textarea">) {
- return (
-
- );
-}
-
-export { Textarea };
diff --git a/src/components/ui/Toggle.tsx b/src/components/ui/Toggle.tsx
deleted file mode 100644
index 7f597f0..0000000
--- a/src/components/ui/Toggle.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-import { cva, type VariantProps } from "class-variance-authority";
-import { Toggle as TogglePrimitive } from "radix-ui";
-import type { ComponentProps } from "react";
-
-import { cn } from "@/lib/cn";
-
-const toggleVariants = cva(
- "group/toggle inline-flex items-center justify-center gap-1 rounded-lg text-sm font-medium whitespace-nowrap transition-all outline-none hover:bg-muted hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 aria-pressed:bg-muted data-[state=on]:bg-muted dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
- {
- variants: {
- variant: {
- default: "bg-transparent",
- outline: "border border-input bg-transparent hover:bg-muted",
- },
- size: {
- default:
- "h-8 min-w-8 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
- sm: "h-7 min-w-7 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
- lg: "h-9 min-w-9 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
- },
- },
- defaultVariants: {
- variant: "default",
- size: "default",
- },
- },
-);
-
-function Toggle({
- className,
- variant = "default",
- size = "default",
- ...props
-}: ComponentProps & VariantProps) {
- return (
-
- );
-}
-
-export { Toggle, toggleVariants };
diff --git a/src/components/ui/ToggleGroup.tsx b/src/components/ui/ToggleGroup.tsx
deleted file mode 100644
index 50b3cbe..0000000
--- a/src/components/ui/ToggleGroup.tsx
+++ /dev/null
@@ -1,84 +0,0 @@
-import { type VariantProps } from "class-variance-authority";
-import { ToggleGroup as ToggleGroupPrimitive } from "radix-ui";
-import { type ComponentProps, type CSSProperties, createContext, useContext } from "react";
-
-import { toggleVariants } from "@/components/ui/Toggle";
-import { cn } from "@/lib/cn";
-
-const ToggleGroupContext = createContext<
- VariantProps & {
- spacing?: number;
- orientation?: "horizontal" | "vertical";
- }
->({
- size: "default",
- variant: "default",
- spacing: 2,
- orientation: "horizontal",
-});
-
-function ToggleGroup({
- className,
- variant,
- size,
- spacing = 2,
- orientation = "horizontal",
- children,
- ...props
-}: ComponentProps &
- VariantProps & {
- spacing?: number;
- orientation?: "horizontal" | "vertical";
- }) {
- return (
-
-
- {children}
-
-
- );
-}
-
-function ToggleGroupItem({
- className,
- children,
- variant = "default",
- size = "default",
- ...props
-}: ComponentProps & VariantProps) {
- const context = useContext(ToggleGroupContext);
-
- return (
-
- {children}
-
- );
-}
-
-export { ToggleGroup, ToggleGroupItem };
diff --git a/src/components/ui/Toolbar.tsx b/src/components/ui/Toolbar.tsx
deleted file mode 100644
index 8046676..0000000
--- a/src/components/ui/Toolbar.tsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import { Toolbar as ToolbarPrimitive } from "radix-ui";
-import type { ComponentProps } from "react";
-
-function Toolbar({ ...props }: ComponentProps) {
- return ;
-}
-
-function ToolbarButton({ ...props }: ComponentProps) {
- return ;
-}
-
-export { Toolbar, ToolbarButton };
diff --git a/src/components/ui/Tooltip.tsx b/src/components/ui/Tooltip.tsx
deleted file mode 100644
index 2f34371..0000000
--- a/src/components/ui/Tooltip.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-import { Tooltip as TooltipPrimitive } from "radix-ui";
-import type { ComponentProps } from "react";
-
-import { cn } from "@/lib/cn";
-
-function TooltipProvider({
- delayDuration = 0,
- ...props
-}: ComponentProps) {
- return (
-
- );
-}
-
-function Tooltip({ ...props }: ComponentProps) {
- return ;
-}
-
-function TooltipTrigger({ ...props }: ComponentProps) {
- return ;
-}
-
-function TooltipContent({
- className,
- sideOffset = 0,
- children,
- ...props
-}: ComponentProps) {
- return (
-
-
- {children}
-
-
-
- );
-}
-
-export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };
diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx
new file mode 100644
index 0000000..763d7da
--- /dev/null
+++ b/src/components/ui/button.tsx
@@ -0,0 +1,58 @@
+import { Button as ButtonPrimitive } from "@base-ui/react/button";
+import { cva, type VariantProps } from "class-variance-authority";
+
+import { cn } from "@/lib/utils";
+
+const buttonVariants = cva(
+ "group/button inline-flex shrink-0 items-center justify-center rounded-md border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 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",
+ {
+ variants: {
+ variant: {
+ default: "bg-primary text-primary-foreground hover:bg-primary/80",
+ outline:
+ "border-border bg-background shadow-xs hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
+ secondary:
+ "bg-secondary text-secondary-foreground hover:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)] aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
+ ghost:
+ "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
+ destructive:
+ "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
+ link: "text-primary underline-offset-4 hover:underline",
+ },
+ size: {
+ default:
+ "h-9 gap-1.5 px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
+ xs: "h-6 gap-1 rounded-[min(var(--radius-md),8px)] px-2 text-xs in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
+ sm: "h-8 gap-1 rounded-[min(var(--radius-md),10px)] px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5",
+ lg: "h-10 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
+ icon: "size-9",
+ "icon-xs":
+ "size-6 rounded-[min(var(--radius-md),8px)] in-data-[slot=button-group]:rounded-md [&_svg:not([class*='size-'])]:size-3",
+ "icon-sm":
+ "size-8 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-md",
+ "icon-lg": "size-10",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ size: "default",
+ },
+ },
+);
+
+function Button({
+ className,
+ variant = "default",
+ size = "default",
+ ...props
+}: ButtonPrimitive.Props & VariantProps) {
+ return (
+
+ );
+}
+
+export { Button, buttonVariants };
diff --git a/src/components/ui/Dialog.test.tsx b/src/components/ui/dialog.test.tsx
similarity index 88%
rename from src/components/ui/Dialog.test.tsx
rename to src/components/ui/dialog.test.tsx
index 861f171..b512e6e 100644
--- a/src/components/ui/Dialog.test.tsx
+++ b/src/components/ui/dialog.test.tsx
@@ -2,7 +2,7 @@ import { describe, expect, it, vi } from "vitest";
import { renderWithUser, screen } from "@/test/utils/react";
-import { Dialog, DialogContent, DialogTitle } from "./Dialog";
+import { Dialog, DialogContent, DialogTitle } from "./dialog";
const renderOpenDialog = () => {
const onOpenChange = vi.fn();
@@ -47,6 +47,9 @@ describe("Dialog", () => {
await user.click(overlay);
- expect(onOpenChange).toHaveBeenCalledWith(false);
+ expect(onOpenChange).toHaveBeenCalledWith(
+ false,
+ expect.objectContaining({ reason: "outside-press" }),
+ );
});
});
diff --git a/src/components/ui/Dialog.tsx b/src/components/ui/dialog.tsx
similarity index 51%
rename from src/components/ui/Dialog.tsx
rename to src/components/ui/dialog.tsx
index f9f2b72..cfa79f0 100644
--- a/src/components/ui/Dialog.tsx
+++ b/src/components/ui/dialog.tsx
@@ -1,9 +1,9 @@
+import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";
import { XIcon } from "lucide-react";
-import { Dialog as DialogPrimitive } from "radix-ui";
-import type { ComponentProps } from "react";
+import * as React from "react";
-import { Button } from "@/components/ui/Button";
-import { cn } from "@/lib/cn";
+import { Button } from "@/components/ui/button";
+import { cn } from "@/lib/utils";
const isWindowDragOrControlTarget = (target: EventTarget | null) =>
target instanceof Element &&
@@ -13,25 +13,42 @@ const isWindowDragOrControlTarget = (target: EventTarget | null) =>
),
);
-function Dialog({ ...props }: ComponentProps) {
- return ;
+function Dialog({ onOpenChange, ...props }: DialogPrimitive.Root.Props) {
+ return (
+ {
+ if (
+ !open &&
+ details.reason === "outside-press" &&
+ isWindowDragOrControlTarget(details.event.target)
+ ) {
+ details.cancel();
+ return;
+ }
+
+ onOpenChange?.(open, details);
+ }}
+ {...props}
+ />
+ );
}
-function DialogTrigger({ ...props }: ComponentProps) {
+function DialogTrigger({ ...props }: DialogPrimitive.Trigger.Props) {
return ;
}
-function DialogPortal({ ...props }: ComponentProps) {
+function DialogPortal({ ...props }: DialogPrimitive.Portal.Props) {
return ;
}
-function DialogClose({ ...props }: ComponentProps) {
+function DialogClose({ ...props }: DialogPrimitive.Close.Props) {
return ;
}
-function DialogOverlay({ className, ...props }: ComponentProps) {
+function DialogOverlay({ className, ...props }: DialogPrimitive.Backdrop.Props) {
return (
- & {
+}: DialogPrimitive.Popup.Props & {
showCloseButton?: boolean;
}) {
return (
- {
- onPointerDownOutside?.(event);
-
- if (!event.defaultPrevented && isWindowDragOrControlTarget(event.target)) {
- event.preventDefault();
- }
- }}
className={cn(
- "fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-popover p-4 text-sm text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none sm:max-w-sm 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",
+ "fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-6 rounded-xl bg-popover p-6 text-sm text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none sm:max-w-md 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}
>
{children}
{showCloseButton && (
-
-
+ }
+ >
+
+ Close
)}
-
+
);
}
-function DialogHeader({ className, ...props }: ComponentProps<"div">) {
+function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
return (
);
@@ -94,42 +104,34 @@ function DialogFooter({
showCloseButton = false,
children,
...props
-}: ComponentProps<"div"> & {
+}: React.ComponentProps<"div"> & {
showCloseButton?: boolean;
}) {
return (
{children}
{showCloseButton && (
-
-
-
+ }>Close
)}
);
}
-function DialogTitle({ className, ...props }: ComponentProps) {
+function DialogTitle({ className, ...props }: DialogPrimitive.Title.Props) {
return (
);
}
-function DialogDescription({
- className,
- ...props
-}: ComponentProps) {
+function DialogDescription({ className, ...props }: DialogPrimitive.Description.Props) {
return (
;
+}
+
+function DropdownMenuPortal({ ...props }: MenuPrimitive.Portal.Props) {
+ return ;
+}
+
+function DropdownMenuTrigger({ ...props }: MenuPrimitive.Trigger.Props) {
+ return ;
+}
+
+function DropdownMenuContent({
+ align = "start",
+ alignOffset = 0,
+ side = "bottom",
+ sideOffset = 4,
+ className,
+ ...props
+}: MenuPrimitive.Popup.Props &
+ Pick) {
+ return (
+
+
+
+
+
+ );
+}
+
+function DropdownMenuGroup({ ...props }: MenuPrimitive.Group.Props) {
+ return ;
+}
+
+function DropdownMenuLabel({
+ className,
+ inset,
+ ...props
+}: MenuPrimitive.GroupLabel.Props & {
+ inset?: boolean;
+}) {
+ return (
+
+ );
+}
+
+function DropdownMenuItem({
+ className,
+ inset,
+ variant = "default",
+ ...props
+}: MenuPrimitive.Item.Props & {
+ inset?: boolean;
+ variant?: "default" | "destructive";
+}) {
+ return (
+
+ );
+}
+
+function DropdownMenuSub({ ...props }: MenuPrimitive.SubmenuRoot.Props) {
+ return ;
+}
+
+function DropdownMenuSubTrigger({
+ className,
+ inset,
+ children,
+ ...props
+}: MenuPrimitive.SubmenuTrigger.Props & {
+ inset?: boolean;
+}) {
+ return (
+
+ {children}
+
+
+ );
+}
+
+function DropdownMenuSubContent({
+ align = "start",
+ alignOffset = -3,
+ side = "right",
+ sideOffset = 0,
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+function DropdownMenuCheckboxItem({
+ className,
+ children,
+ checked,
+ inset,
+ ...props
+}: MenuPrimitive.CheckboxItem.Props & {
+ inset?: boolean;
+}) {
+ return (
+
+
+
+
+
+
+ {children}
+
+ );
+}
+
+function DropdownMenuRadioGroup({ ...props }: MenuPrimitive.RadioGroup.Props) {
+ return ;
+}
+
+function DropdownMenuRadioItem({
+ className,
+ children,
+ inset,
+ ...props
+}: MenuPrimitive.RadioItem.Props & {
+ inset?: boolean;
+}) {
+ return (
+
+
+
+
+
+
+ {children}
+
+ );
+}
+
+function DropdownMenuSeparator({ className, ...props }: MenuPrimitive.Separator.Props) {
+ return (
+
+ );
+}
+
+function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<"span">) {
+ return (
+
+ );
+}
+
+export {
+ DropdownMenu,
+ DropdownMenuCheckboxItem,
+ DropdownMenuContent,
+ DropdownMenuGroup,
+ DropdownMenuItem,
+ DropdownMenuLabel,
+ DropdownMenuPortal,
+ DropdownMenuRadioGroup,
+ DropdownMenuRadioItem,
+ DropdownMenuSeparator,
+ DropdownMenuShortcut,
+ DropdownMenuSub,
+ DropdownMenuSubContent,
+ DropdownMenuSubTrigger,
+ DropdownMenuTrigger,
+};
diff --git a/src/components/ui/InputGroup.tsx b/src/components/ui/input-group.tsx
similarity index 52%
rename from src/components/ui/InputGroup.tsx
rename to src/components/ui/input-group.tsx
index 2fdcf2c..3ffc762 100644
--- a/src/components/ui/InputGroup.tsx
+++ b/src/components/ui/input-group.tsx
@@ -1,18 +1,18 @@
import { cva, type VariantProps } from "class-variance-authority";
-import type { ComponentProps } from "react";
+import * as React from "react";
-import { Button } from "@/components/ui/Button";
-import { Input } from "@/components/ui/Input";
-import { Textarea } from "@/components/ui/Textarea";
-import { cn } from "@/lib/cn";
+import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
+import { Textarea } from "@/components/ui/textarea";
+import { cn } from "@/lib/utils";
-function InputGroup({ className, ...props }: ComponentProps<"div">) {
+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",
+ "group/input-group relative flex h-9 w-full min-w-0 items-center rounded-md border border-input shadow-xs transition-[color,box-shadow] outline-none in-data-[slot=combobox-content]:focus-within:border-inherit in-data-[slot=combobox-content]:focus-within:ring-0 has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-3 has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot][aria-invalid=true]]:border-destructive has-[[data-slot][aria-invalid=true]]:ring-3 has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[>[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-[[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}
@@ -25,8 +25,8 @@ const inputGroupAddonVariants = cva(
{
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]",
+ "inline-start": "order-first pl-2 has-[>button]:-ml-1 has-[>kbd]:ml-[-0.15rem]",
+ "inline-end": "order-last pr-2 has-[>button]:-mr-1 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":
@@ -43,7 +43,7 @@ function InputGroupAddon({
className,
align = "inline-start",
...props
-}: ComponentProps<"div"> & VariantProps
) {
+}: React.ComponentProps<"div"> & VariantProps) {
return (
svg:not([class*='size-'])]:size-3.5",
+ xs: "h-6 gap-1 rounded-[calc(var(--radius)-5px)] 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-xs": "size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0",
"icon-sm": "size-8 p-0 has-[>svg]:p-0",
},
},
@@ -81,7 +81,10 @@ function InputGroupButton({
variant = "ghost",
size = "xs",
...props
-}: Omit
, "size"> & VariantProps) {
+}: Omit, "size" | "type"> &
+ VariantProps & {
+ type?: "button" | "submit" | "reset";
+ }) {
return (