aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/packages/ui-new
diff options
context:
space:
mode:
Diffstat (limited to 'packages/ui-new')
-rw-r--r--packages/ui-new/components.json3
-rw-r--r--packages/ui-new/package.json5
-rw-r--r--packages/ui-new/src/components/download-monitor.tsx1
-rw-r--r--packages/ui-new/src/components/ui/badge.tsx48
-rw-r--r--packages/ui-new/src/components/ui/button.tsx44
-rw-r--r--packages/ui-new/src/components/ui/card.tsx25
-rw-r--r--packages/ui-new/src/components/ui/checkbox.tsx15
-rw-r--r--packages/ui-new/src/components/ui/dialog.tsx80
-rw-r--r--packages/ui-new/src/components/ui/input.tsx7
-rw-r--r--packages/ui-new/src/components/ui/label.tsx13
-rw-r--r--packages/ui-new/src/components/ui/scroll-area.tsx23
-rw-r--r--packages/ui-new/src/components/ui/select.tsx143
-rw-r--r--packages/ui-new/src/components/ui/separator.tsx11
-rw-r--r--packages/ui-new/src/components/ui/sonner.tsx5
-rw-r--r--packages/ui-new/src/components/ui/switch.tsx17
-rw-r--r--packages/ui-new/src/components/ui/tabs.tsx62
-rw-r--r--packages/ui-new/src/components/ui/textarea.tsx2
-rw-r--r--packages/ui-new/src/index.css176
-rw-r--r--packages/ui-new/src/pages/index.tsx2
-rw-r--r--packages/ui-new/tsconfig.app.json6
20 files changed, 280 insertions, 408 deletions
diff --git a/packages/ui-new/components.json b/packages/ui-new/components.json
index 2b0833f..f9d4fcd 100644
--- a/packages/ui-new/components.json
+++ b/packages/ui-new/components.json
@@ -1,6 +1,6 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
- "style": "new-york",
+ "style": "base-lyra",
"rsc": false,
"tsx": true,
"tailwind": {
@@ -11,6 +11,7 @@
"prefix": ""
},
"iconLibrary": "lucide",
+ "rtl": false,
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
diff --git a/packages/ui-new/package.json b/packages/ui-new/package.json
index 706c12b..fcd6aed 100644
--- a/packages/ui-new/package.json
+++ b/packages/ui-new/package.json
@@ -10,6 +10,7 @@
"preview": "vite preview"
},
"dependencies": {
+ "@base-ui/react": "^1.2.0",
"@radix-ui/react-checkbox": "^1.3.3",
"@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-label": "^2.1.8",
@@ -28,11 +29,12 @@
"lucide-react": "^0.562.0",
"marked": "^17.0.1",
"next-themes": "^0.4.6",
+ "radix-ui": "^1.4.3",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"react-router": "^7.12.0",
"sonner": "^2.0.7",
- "tailwind-merge": "^3.4.0",
+ "tailwind-merge": "^3.4.1",
"zustand": "^5.0.10"
},
"devDependencies": {
@@ -42,6 +44,7 @@
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.1.1",
"globals": "^16.5.0",
+ "shadcn": "^3.8.5",
"tailwindcss": "^4.1.18",
"tw-animate-css": "^1.4.0",
"typescript": "~5.9.3",
diff --git a/packages/ui-new/src/components/download-monitor.tsx b/packages/ui-new/src/components/download-monitor.tsx
index d67e173..f3902d9 100644
--- a/packages/ui-new/src/components/download-monitor.tsx
+++ b/packages/ui-new/src/components/download-monitor.tsx
@@ -15,6 +15,7 @@ export function DownloadMonitor() {
<span className="text-sm font-medium text-white">Downloads</span>
</div>
<button
+ type="button"
onClick={() => setIsVisible(false)}
className="text-zinc-400 hover:text-white transition-colors p-1"
>
diff --git a/packages/ui-new/src/components/ui/badge.tsx b/packages/ui-new/src/components/ui/badge.tsx
index ccfa4e7..425ab9e 100644
--- a/packages/ui-new/src/components/ui/badge.tsx
+++ b/packages/ui-new/src/components/ui/badge.tsx
@@ -1,22 +1,24 @@
-import { Slot } from "@radix-ui/react-slot";
+import { mergeProps } from "@base-ui/react/merge-props";
+import { useRender } from "@base-ui/react/use-render";
import { cva, type VariantProps } from "class-variance-authority";
-import type * as React from "react";
import { cn } from "@/lib/utils";
const badgeVariants = cva(
- "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",
+ "h-5 gap-1 rounded-none border border-transparent px-2 py-0.5 text-xs font-medium transition-all has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&>svg]:size-3! inline-flex items-center justify-center w-fit whitespace-nowrap shrink-0 [&>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 overflow-hidden group/badge",
{
variants: {
variant: {
- default:
- "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
+ default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
secondary:
- "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
+ "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
destructive:
- "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
+ "bg-destructive/10 [a]:hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 text-destructive dark:bg-destructive/20",
outline:
- "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
+ "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground",
+ ghost:
+ "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
+ link: "text-primary underline-offset-4 hover:underline",
},
},
defaultVariants: {
@@ -27,20 +29,24 @@ const badgeVariants = cva(
function Badge({
className,
- variant,
- asChild = false,
+ variant = "default",
+ render,
...props
-}: React.ComponentProps<"span"> &
- VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
- const Comp = asChild ? Slot : "span";
-
- return (
- <Comp
- data-slot="badge"
- className={cn(badgeVariants({ variant }), className)}
- {...props}
- />
- );
+}: useRender.ComponentProps<"span"> & VariantProps<typeof badgeVariants>) {
+ return useRender({
+ defaultTagName: "span",
+ props: mergeProps<"span">(
+ {
+ className: cn(badgeVariants({ variant }), className),
+ },
+ props,
+ ),
+ render,
+ state: {
+ slot: "badge",
+ variant,
+ },
+ });
}
export { Badge, badgeVariants };
diff --git a/packages/ui-new/src/components/ui/button.tsx b/packages/ui-new/src/components/ui/button.tsx
index be181b0..7dee494 100644
--- a/packages/ui-new/src/components/ui/button.tsx
+++ b/packages/ui-new/src/components/ui/button.tsx
@@ -1,32 +1,34 @@
-import { Slot } from "@radix-ui/react-slot";
+import { Button as ButtonPrimitive } from "@base-ui/react/button";
import { cva, type VariantProps } from "class-variance-authority";
-import type * as React from "react";
import { cn } from "@/lib/utils";
const buttonVariants = cva(
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-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",
+ "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:aria-invalid:border-destructive/50 rounded-none border border-transparent bg-clip-padding text-xs font-medium focus-visible:ring-1 aria-invalid:ring-1 [&_svg:not([class*='size-'])]:size-4 inline-flex items-center justify-center whitespace-nowrap transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none group/button select-none",
{
variants: {
variant: {
- default: "bg-primary text-primary-foreground hover:bg-primary/90",
- destructive:
- "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
+ default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
outline:
- "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
+ "border-border bg-background hover:bg-muted hover:text-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 aria-expanded:bg-muted aria-expanded:text-foreground",
secondary:
- "bg-secondary text-secondary-foreground hover:bg-secondary/80",
+ "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
ghost:
- "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
+ "hover:bg-muted hover:text-foreground dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground",
+ destructive:
+ "bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
- default: "h-9 px-4 py-2 has-[>svg]:px-3",
- sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
- lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
- icon: "size-9",
- "icon-sm": "size-8",
- "icon-lg": "size-10",
+ 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-none px-2 text-xs 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-none px-2.5 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-3 has-data-[icon=inline-start]:pl-3",
+ icon: "size-8",
+ "icon-xs": "size-6 rounded-none [&_svg:not([class*='size-'])]:size-3",
+ "icon-sm": "size-7 rounded-none",
+ "icon-lg": "size-9",
},
},
defaultVariants: {
@@ -40,19 +42,11 @@ function Button({
className,
variant = "default",
size = "default",
- asChild = false,
...props
-}: React.ComponentProps<"button"> &
- VariantProps<typeof buttonVariants> & {
- asChild?: boolean;
- }) {
- const Comp = asChild ? Slot : "button";
-
+}: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {
return (
- <Comp
+ <ButtonPrimitive
data-slot="button"
- data-variant={variant}
- data-size={size}
className={cn(buttonVariants({ variant, size, className }))}
{...props}
/>
diff --git a/packages/ui-new/src/components/ui/card.tsx b/packages/ui-new/src/components/ui/card.tsx
index cc1ff8a..b7084a0 100644
--- a/packages/ui-new/src/components/ui/card.tsx
+++ b/packages/ui-new/src/components/ui/card.tsx
@@ -2,12 +2,17 @@ import type * 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 (
<div
data-slot="card"
+ data-size={size}
className={cn(
- "bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
+ "ring-foreground/10 bg-card text-card-foreground gap-4 overflow-hidden rounded-none py-4 text-xs/relaxed ring-1 has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-2 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-none *:[img:last-child]:rounded-none group/card flex flex-col",
className,
)}
{...props}
@@ -20,7 +25,7 @@ function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
<div
data-slot="card-header"
className={cn(
- "@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",
+ "gap-1 rounded-none px-4 group-data-[size=sm]/card:px-3 [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3 group/card-header @container/card-header grid auto-rows-min items-start has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto]",
className,
)}
{...props}
@@ -32,7 +37,10 @@ function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-title"
- className={cn("leading-none font-semibold", className)}
+ className={cn(
+ "text-sm font-medium group-data-[size=sm]/card:text-sm",
+ className,
+ )}
{...props}
/>
);
@@ -42,7 +50,7 @@ function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-description"
- className={cn("text-muted-foreground text-sm", className)}
+ className={cn("text-muted-foreground text-xs/relaxed", className)}
{...props}
/>
);
@@ -65,7 +73,7 @@ function CardContent({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-content"
- className={cn("px-6", className)}
+ className={cn("px-4 group-data-[size=sm]/card:px-3", className)}
{...props}
/>
);
@@ -75,7 +83,10 @@ function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-footer"
- className={cn("flex items-center px-6 [.border-t]:pt-6", className)}
+ className={cn(
+ "rounded-none border-t p-4 group-data-[size=sm]/card:p-3 flex items-center",
+ className,
+ )}
{...props}
/>
);
diff --git a/packages/ui-new/src/components/ui/checkbox.tsx b/packages/ui-new/src/components/ui/checkbox.tsx
index e771797..9f22cea 100644
--- a/packages/ui-new/src/components/ui/checkbox.tsx
+++ b/packages/ui-new/src/components/ui/checkbox.tsx
@@ -1,29 +1,24 @@
"use client";
-import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
+import { Checkbox as CheckboxPrimitive } from "@base-ui/react/checkbox";
import { CheckIcon } from "lucide-react";
-import type * as React from "react";
-
import { cn } from "@/lib/utils";
-function Checkbox({
- className,
- ...props
-}: React.ComponentProps<typeof CheckboxPrimitive.Root>) {
+function Checkbox({ className, ...props }: CheckboxPrimitive.Root.Props) {
return (
<CheckboxPrimitive.Root
data-slot="checkbox"
className={cn(
- "peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
+ "border-input dark:bg-input/30 data-checked:bg-primary data-checked:text-primary-foreground dark:data-checked:bg-primary data-checked:border-primary aria-invalid:aria-checked:border-primary aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 flex size-4 items-center justify-center rounded-none border transition-colors group-has-disabled/field:opacity-50 focus-visible:ring-1 aria-invalid:ring-1 peer relative shrink-0 outline-none after:absolute after:-inset-x-3 after:-inset-y-2 disabled:cursor-not-allowed disabled:opacity-50",
className,
)}
{...props}
>
<CheckboxPrimitive.Indicator
data-slot="checkbox-indicator"
- className="grid place-content-center text-current transition-none"
+ className="[&>svg]:size-3.5 grid place-content-center text-current transition-none"
>
- <CheckIcon className="size-3.5" />
+ <CheckIcon />
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>
);
diff --git a/packages/ui-new/src/components/ui/dialog.tsx b/packages/ui-new/src/components/ui/dialog.tsx
index fc2261a..033b47c 100644
--- a/packages/ui-new/src/components/ui/dialog.tsx
+++ b/packages/ui-new/src/components/ui/dialog.tsx
@@ -1,42 +1,36 @@
-import * as DialogPrimitive from "@radix-ui/react-dialog";
+"use client";
+
+import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";
import { XIcon } from "lucide-react";
import type * as React from "react";
-
+import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
-function Dialog({
- ...props
-}: React.ComponentProps<typeof DialogPrimitive.Root>) {
+function Dialog({ ...props }: DialogPrimitive.Root.Props) {
return <DialogPrimitive.Root data-slot="dialog" {...props} />;
}
-function DialogTrigger({
- ...props
-}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
+function DialogTrigger({ ...props }: DialogPrimitive.Trigger.Props) {
return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;
}
-function DialogPortal({
- ...props
-}: React.ComponentProps<typeof DialogPrimitive.Portal>) {
+function DialogPortal({ ...props }: DialogPrimitive.Portal.Props) {
return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
}
-function DialogClose({
- ...props
-}: React.ComponentProps<typeof DialogPrimitive.Close>) {
+function DialogClose({ ...props }: DialogPrimitive.Close.Props) {
return <DialogPrimitive.Close data-slot="dialog-close" {...props} />;
}
function DialogOverlay({
className,
...props
-}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
+}: DialogPrimitive.Backdrop.Props) {
return (
- <DialogPrimitive.Overlay
+ <DialogPrimitive.Backdrop
data-slot="dialog-overlay"
className={cn(
- "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
+ "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 isolate z-50",
className,
)}
{...props}
@@ -49,16 +43,16 @@ function DialogContent({
children,
showCloseButton = true,
...props
-}: React.ComponentProps<typeof DialogPrimitive.Content> & {
+}: DialogPrimitive.Popup.Props & {
showCloseButton?: boolean;
}) {
return (
- <DialogPortal data-slot="dialog-portal">
+ <DialogPortal>
<DialogOverlay />
- <DialogPrimitive.Content
+ <DialogPrimitive.Popup
data-slot="dialog-content"
className={cn(
- "bg-background 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 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 outline-none sm:max-w-lg",
+ "bg-background data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 ring-foreground/10 grid max-w-[calc(100%-2rem)] gap-4 rounded-none p-4 text-xs/relaxed ring-1 duration-100 sm:max-w-sm fixed top-1/2 left-1/2 z-50 w-full -translate-x-1/2 -translate-y-1/2 outline-none",
className,
)}
{...props}
@@ -67,13 +61,19 @@ function DialogContent({
{showCloseButton && (
<DialogPrimitive.Close
data-slot="dialog-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"
+ render={
+ <Button
+ variant="ghost"
+ className="absolute top-2 right-2"
+ size="icon-sm"
+ />
+ }
>
<XIcon />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
)}
- </DialogPrimitive.Content>
+ </DialogPrimitive.Popup>
</DialogPortal>
);
}
@@ -82,13 +82,20 @@ function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="dialog-header"
- className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
+ className={cn("gap-1 text-left flex flex-col", className)}
{...props}
/>
);
}
-function DialogFooter({ className, ...props }: React.ComponentProps<"div">) {
+function DialogFooter({
+ className,
+ showCloseButton = false,
+ children,
+ ...props
+}: React.ComponentProps<"div"> & {
+ showCloseButton?: boolean;
+}) {
return (
<div
data-slot="dialog-footer"
@@ -97,18 +104,22 @@ function DialogFooter({ className, ...props }: React.ComponentProps<"div">) {
className,
)}
{...props}
- />
+ >
+ {children}
+ {showCloseButton && (
+ <DialogPrimitive.Close render={<Button variant="outline" />}>
+ Close
+ </DialogPrimitive.Close>
+ )}
+ </div>
);
}
-function DialogTitle({
- className,
- ...props
-}: React.ComponentProps<typeof DialogPrimitive.Title>) {
+function DialogTitle({ className, ...props }: DialogPrimitive.Title.Props) {
return (
<DialogPrimitive.Title
data-slot="dialog-title"
- className={cn("text-lg leading-none font-semibold", className)}
+ className={cn("text-sm font-medium", className)}
{...props}
/>
);
@@ -117,11 +128,14 @@ function DialogTitle({
function DialogDescription({
className,
...props
-}: React.ComponentProps<typeof DialogPrimitive.Description>) {
+}: DialogPrimitive.Description.Props) {
return (
<DialogPrimitive.Description
data-slot="dialog-description"
- className={cn("text-muted-foreground text-sm", className)}
+ className={cn(
+ "text-muted-foreground *:[a]:hover:text-foreground text-xs/relaxed *:[a]:underline *:[a]:underline-offset-3",
+ className,
+ )}
{...props}
/>
);
diff --git a/packages/ui-new/src/components/ui/input.tsx b/packages/ui-new/src/components/ui/input.tsx
index 73ea867..bb0390a 100644
--- a/packages/ui-new/src/components/ui/input.tsx
+++ b/packages/ui-new/src/components/ui/input.tsx
@@ -1,16 +1,15 @@
+import { Input as InputPrimitive } from "@base-ui/react/input";
import type * as React from "react";
import { cn } from "@/lib/utils";
function Input({ className, type, ...props }: React.ComponentProps<"input">) {
return (
- <input
+ <InputPrimitive
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 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",
+ "dark:bg-input/30 border-input 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:aria-invalid:border-destructive/50 disabled:bg-input/50 dark:disabled:bg-input/80 h-8 rounded-none border bg-transparent px-2.5 py-1 text-xs transition-colors file:h-6 file:text-xs file:font-medium focus-visible:ring-1 aria-invalid:ring-1 md:text-xs file:text-foreground placeholder:text-muted-foreground w-full min-w-0 outline-none file:inline-flex file:border-0 file:bg-transparent disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
className,
)}
{...props}
diff --git a/packages/ui-new/src/components/ui/label.tsx b/packages/ui-new/src/components/ui/label.tsx
index a3661df..9a998c7 100644
--- a/packages/ui-new/src/components/ui/label.tsx
+++ b/packages/ui-new/src/components/ui/label.tsx
@@ -1,19 +1,14 @@
-"use client";
-
-import * as LabelPrimitive from "@radix-ui/react-label";
import type * as React from "react";
import { cn } from "@/lib/utils";
-function Label({
- className,
- ...props
-}: React.ComponentProps<typeof LabelPrimitive.Root>) {
+function Label({ className, ...props }: React.ComponentProps<"label">) {
return (
- <LabelPrimitive.Root
+ // biome-ignore lint/a11y/noLabelWithoutControl: shadcn component
+ <label
data-slot="label"
className={cn(
- "flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
+ "gap-2 text-xs leading-none group-data-[disabled=true]:opacity-50 peer-disabled:opacity-50 flex items-center select-none group-data-[disabled=true]:pointer-events-none peer-disabled:cursor-not-allowed",
className,
)}
{...props}
diff --git a/packages/ui-new/src/components/ui/scroll-area.tsx b/packages/ui-new/src/components/ui/scroll-area.tsx
index da6b2e2..4a68eb2 100644
--- a/packages/ui-new/src/components/ui/scroll-area.tsx
+++ b/packages/ui-new/src/components/ui/scroll-area.tsx
@@ -1,13 +1,13 @@
-import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
-import type * as React from "react";
+"use client";
+import { ScrollArea as ScrollAreaPrimitive } from "@base-ui/react/scroll-area";
import { cn } from "@/lib/utils";
function ScrollArea({
className,
children,
...props
-}: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) {
+}: ScrollAreaPrimitive.Root.Props) {
return (
<ScrollAreaPrimitive.Root
data-slot="scroll-area"
@@ -30,26 +30,23 @@ function ScrollBar({
className,
orientation = "vertical",
...props
-}: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) {
+}: ScrollAreaPrimitive.Scrollbar.Props) {
return (
- <ScrollAreaPrimitive.ScrollAreaScrollbar
+ <ScrollAreaPrimitive.Scrollbar
data-slot="scroll-area-scrollbar"
+ data-orientation={orientation}
orientation={orientation}
className={cn(
- "flex touch-none p-px transition-colors select-none",
- orientation === "vertical" &&
- "h-full w-2.5 border-l border-l-transparent",
- orientation === "horizontal" &&
- "h-2.5 flex-col border-t border-t-transparent",
+ "data-horizontal:h-2.5 data-horizontal:flex-col data-horizontal:border-t data-horizontal:border-t-transparent data-vertical:h-full data-vertical:w-2.5 data-vertical:border-l data-vertical:border-l-transparent flex touch-none p-px transition-colors select-none",
className,
)}
{...props}
>
- <ScrollAreaPrimitive.ScrollAreaThumb
+ <ScrollAreaPrimitive.Thumb
data-slot="scroll-area-thumb"
- className="bg-border relative flex-1 rounded-full"
+ className="rounded-none bg-border relative flex-1"
/>
- </ScrollAreaPrimitive.ScrollAreaScrollbar>
+ </ScrollAreaPrimitive.Scrollbar>
);
}
diff --git a/packages/ui-new/src/components/ui/select.tsx b/packages/ui-new/src/components/ui/select.tsx
index c611948..210adba 100644
--- a/packages/ui-new/src/components/ui/select.tsx
+++ b/packages/ui-new/src/components/ui/select.tsx
@@ -1,25 +1,28 @@
-import * as SelectPrimitive from "@radix-ui/react-select";
+import { Select as SelectPrimitive } from "@base-ui/react/select";
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react";
import type * as React from "react";
-
import { cn } from "@/lib/utils";
-function Select({
- ...props
-}: React.ComponentProps<typeof SelectPrimitive.Root>) {
- return <SelectPrimitive.Root data-slot="select" {...props} />;
-}
+const Select = SelectPrimitive.Root;
-function SelectGroup({
- ...props
-}: React.ComponentProps<typeof SelectPrimitive.Group>) {
- return <SelectPrimitive.Group data-slot="select-group" {...props} />;
+function SelectGroup({ className, ...props }: SelectPrimitive.Group.Props) {
+ return (
+ <SelectPrimitive.Group
+ data-slot="select-group"
+ className={cn("scroll-my-1", className)}
+ {...props}
+ />
+ );
}
-function SelectValue({
- ...props
-}: React.ComponentProps<typeof SelectPrimitive.Value>) {
- return <SelectPrimitive.Value data-slot="select-value" {...props} />;
+function SelectValue({ className, ...props }: SelectPrimitive.Value.Props) {
+ return (
+ <SelectPrimitive.Value
+ data-slot="select-value"
+ className={cn("flex flex-1 text-left", className)}
+ {...props}
+ />
+ );
}
function SelectTrigger({
@@ -27,7 +30,7 @@ function SelectTrigger({
size = "default",
children,
...props
-}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
+}: SelectPrimitive.Trigger.Props & {
size?: "sm" | "default";
}) {
return (
@@ -35,15 +38,17 @@ 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",
+ "border-input data-placeholder:text-muted-foreground dark:bg-input/30 dark:hover:bg-input/50 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:aria-invalid:border-destructive/50 gap-1.5 rounded-none border bg-transparent py-2 pr-2 pl-2.5 text-xs transition-colors select-none focus-visible:ring-1 aria-invalid:ring-1 data-[size=default]:h-8 data-[size=sm]:h-7 data-[size=sm]:rounded-none *:data-[slot=select-value]:gap-1.5 [&_svg:not([class*='size-'])]:size-4 flex w-fit items-center justify-between whitespace-nowrap outline-none disabled:cursor-not-allowed disabled:opacity-50 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center [&_svg]:pointer-events-none [&_svg]:shrink-0",
className,
)}
{...props}
>
{children}
- <SelectPrimitive.Icon asChild>
- <ChevronDownIcon className="size-4 opacity-50" />
- </SelectPrimitive.Icon>
+ <SelectPrimitive.Icon
+ render={
+ <ChevronDownIcon className="text-muted-foreground size-4 pointer-events-none" />
+ }
+ />
</SelectPrimitive.Trigger>
);
}
@@ -51,36 +56,41 @@ function SelectTrigger({
function SelectContent({
className,
children,
- position = "item-aligned",
+ side = "bottom",
+ sideOffset = 4,
align = "center",
+ alignOffset = 0,
+ alignItemWithTrigger = true,
...props
-}: React.ComponentProps<typeof SelectPrimitive.Content>) {
+}: SelectPrimitive.Popup.Props &
+ Pick<
+ SelectPrimitive.Positioner.Props,
+ "align" | "alignOffset" | "side" | "sideOffset" | "alignItemWithTrigger"
+ >) {
return (
<SelectPrimitive.Portal>
- <SelectPrimitive.Content
- data-slot="select-content"
- 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 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
- position === "popper" &&
- "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
- className,
- )}
- position={position}
+ <SelectPrimitive.Positioner
+ side={side}
+ sideOffset={sideOffset}
align={align}
- {...props}
+ alignOffset={alignOffset}
+ alignItemWithTrigger={alignItemWithTrigger}
+ className="isolate z-50"
>
- <SelectScrollUpButton />
- <SelectPrimitive.Viewport
+ <SelectPrimitive.Popup
+ data-slot="select-content"
+ data-align-trigger={alignItemWithTrigger}
className={cn(
- "p-1",
- position === "popper" &&
- "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1",
+ "bg-popover text-popover-foreground data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-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 ring-foreground/10 min-w-36 rounded-none shadow-md ring-1 duration-100 data-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2 relative isolate z-50 max-h-(--available-height) w-(--anchor-width) origin-(--transform-origin) overflow-x-hidden overflow-y-auto data-[align-trigger=true]:animate-none",
+ className,
)}
+ {...props}
>
- {children}
- </SelectPrimitive.Viewport>
- <SelectScrollDownButton />
- </SelectPrimitive.Content>
+ <SelectScrollUpButton />
+ <SelectPrimitive.List>{children}</SelectPrimitive.List>
+ <SelectScrollDownButton />
+ </SelectPrimitive.Popup>
+ </SelectPrimitive.Positioner>
</SelectPrimitive.Portal>
);
}
@@ -88,11 +98,11 @@ function SelectContent({
function SelectLabel({
className,
...props
-}: React.ComponentProps<typeof SelectPrimitive.Label>) {
+}: SelectPrimitive.GroupLabel.Props) {
return (
- <SelectPrimitive.Label
+ <SelectPrimitive.GroupLabel
data-slot="select-label"
- className={cn("text-muted-foreground px-2 py-1.5 text-xs", className)}
+ className={cn("text-muted-foreground px-2 py-2 text-xs", className)}
{...props}
/>
);
@@ -102,25 +112,26 @@ function SelectItem({
className,
children,
...props
-}: React.ComponentProps<typeof SelectPrimitive.Item>) {
+}: SelectPrimitive.Item.Props) {
return (
<SelectPrimitive.Item
data-slot="select-item"
className={cn(
- "focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
+ "focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground gap-2 rounded-none py-2 pr-8 pl-2 text-xs [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2 relative flex w-full cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
className,
)}
{...props}
>
- <span
- data-slot="select-item-indicator"
- className="absolute right-2 flex size-3.5 items-center justify-center"
+ <SelectPrimitive.ItemText className="flex flex-1 gap-2 shrink-0 whitespace-nowrap">
+ {children}
+ </SelectPrimitive.ItemText>
+ <SelectPrimitive.ItemIndicator
+ render={
+ <span className="pointer-events-none absolute right-2 flex size-4 items-center justify-center" />
+ }
>
- <SelectPrimitive.ItemIndicator>
- <CheckIcon className="size-4" />
- </SelectPrimitive.ItemIndicator>
- </span>
- <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
+ <CheckIcon className="pointer-events-none" />
+ </SelectPrimitive.ItemIndicator>
</SelectPrimitive.Item>
);
}
@@ -128,11 +139,11 @@ function SelectItem({
function SelectSeparator({
className,
...props
-}: React.ComponentProps<typeof SelectPrimitive.Separator>) {
+}: SelectPrimitive.Separator.Props) {
return (
<SelectPrimitive.Separator
data-slot="select-separator"
- className={cn("bg-border pointer-events-none -mx-1 my-1 h-px", className)}
+ className={cn("bg-border -mx-1 h-px pointer-events-none", className)}
{...props}
/>
);
@@ -141,36 +152,36 @@ function SelectSeparator({
function SelectScrollUpButton({
className,
...props
-}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
+}: React.ComponentProps<typeof SelectPrimitive.ScrollUpArrow>) {
return (
- <SelectPrimitive.ScrollUpButton
+ <SelectPrimitive.ScrollUpArrow
data-slot="select-scroll-up-button"
className={cn(
- "flex cursor-default items-center justify-center py-1",
+ "bg-popover z-10 flex cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-4 top-0 w-full",
className,
)}
{...props}
>
- <ChevronUpIcon className="size-4" />
- </SelectPrimitive.ScrollUpButton>
+ <ChevronUpIcon />
+ </SelectPrimitive.ScrollUpArrow>
);
}
function SelectScrollDownButton({
className,
...props
-}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
+}: React.ComponentProps<typeof SelectPrimitive.ScrollDownArrow>) {
return (
- <SelectPrimitive.ScrollDownButton
+ <SelectPrimitive.ScrollDownArrow
data-slot="select-scroll-down-button"
className={cn(
- "flex cursor-default items-center justify-center py-1",
+ "bg-popover z-10 flex cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-4 bottom-0 w-full",
className,
)}
{...props}
>
- <ChevronDownIcon className="size-4" />
- </SelectPrimitive.ScrollDownButton>
+ <ChevronDownIcon />
+ </SelectPrimitive.ScrollDownArrow>
);
}
diff --git a/packages/ui-new/src/components/ui/separator.tsx b/packages/ui-new/src/components/ui/separator.tsx
index 50733e0..e91a862 100644
--- a/packages/ui-new/src/components/ui/separator.tsx
+++ b/packages/ui-new/src/components/ui/separator.tsx
@@ -1,23 +1,20 @@
"use client";
-import * as SeparatorPrimitive from "@radix-ui/react-separator";
-import type * as React from "react";
+import { Separator as SeparatorPrimitive } from "@base-ui/react/separator";
import { cn } from "@/lib/utils";
function Separator({
className,
orientation = "horizontal",
- decorative = true,
...props
-}: React.ComponentProps<typeof SeparatorPrimitive.Root>) {
+}: SeparatorPrimitive.Props) {
return (
- <SeparatorPrimitive.Root
+ <SeparatorPrimitive
data-slot="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",
+ "bg-border shrink-0 data-horizontal:h-px data-horizontal:w-full data-vertical:w-px data-vertical:self-stretch",
className,
)}
{...props}
diff --git a/packages/ui-new/src/components/ui/sonner.tsx b/packages/ui-new/src/components/ui/sonner.tsx
index c9cd094..d6e293d 100644
--- a/packages/ui-new/src/components/ui/sonner.tsx
+++ b/packages/ui-new/src/components/ui/sonner.tsx
@@ -30,6 +30,11 @@ const Toaster = ({ ...props }: ToasterProps) => {
"--border-radius": "var(--radius)",
} as React.CSSProperties
}
+ toastOptions={{
+ classNames: {
+ toast: "cn-toast",
+ },
+ }}
{...props}
/>
);
diff --git a/packages/ui-new/src/components/ui/switch.tsx b/packages/ui-new/src/components/ui/switch.tsx
index 14b3b5b..fef14e3 100644
--- a/packages/ui-new/src/components/ui/switch.tsx
+++ b/packages/ui-new/src/components/ui/switch.tsx
@@ -1,26 +1,29 @@
-import * as SwitchPrimitive from "@radix-ui/react-switch";
-import type * as React from "react";
+"use client";
+
+import { Switch as SwitchPrimitive } from "@base-ui/react/switch";
import { cn } from "@/lib/utils";
function Switch({
className,
+ size = "default",
...props
-}: React.ComponentProps<typeof SwitchPrimitive.Root>) {
+}: SwitchPrimitive.Root.Props & {
+ size?: "sm" | "default";
+}) {
return (
<SwitchPrimitive.Root
data-slot="switch"
+ data-size={size}
className={cn(
- "peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
+ "data-checked:bg-primary data-unchecked:bg-input 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:aria-invalid:border-destructive/50 dark:data-unchecked:bg-input/80 shrink-0 rounded-full border border-transparent focus-visible:ring-1 aria-invalid:ring-1 data-[size=default]:h-[18.4px] data-[size=default]:w-[32px] data-[size=sm]:h-[14px] data-[size=sm]:w-[24px] peer group/switch relative inline-flex items-center transition-all outline-none after:absolute after:-inset-x-3 after:-inset-y-2 data-disabled:cursor-not-allowed data-disabled:opacity-50",
className,
)}
{...props}
>
<SwitchPrimitive.Thumb
data-slot="switch-thumb"
- className={cn(
- "bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-4 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0",
- )}
+ className="bg-background dark:data-unchecked:bg-foreground dark:data-checked:bg-primary-foreground rounded-full group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 group-data-[size=default]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=sm]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=default]/switch:data-unchecked:translate-x-0 group-data-[size=sm]/switch:data-unchecked:translate-x-0 pointer-events-none block ring-0 transition-transform"
/>
</SwitchPrimitive.Root>
);
diff --git a/packages/ui-new/src/components/ui/tabs.tsx b/packages/ui-new/src/components/ui/tabs.tsx
index 2da77f2..6349f40 100644
--- a/packages/ui-new/src/components/ui/tabs.tsx
+++ b/packages/ui-new/src/components/ui/tabs.tsx
@@ -1,48 +1,65 @@
-"use client";
-
-import * as TabsPrimitive from "@radix-ui/react-tabs";
-import type * as React from "react";
+import { Tabs as TabsPrimitive } from "@base-ui/react/tabs";
+import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
function Tabs({
className,
+ orientation = "horizontal",
...props
-}: React.ComponentProps<typeof TabsPrimitive.Root>) {
+}: TabsPrimitive.Root.Props) {
return (
<TabsPrimitive.Root
data-slot="tabs"
- className={cn("flex flex-col gap-2", className)}
+ data-orientation={orientation}
+ className={cn(
+ "gap-2 group/tabs flex data-horizontal:flex-col",
+ className,
+ )}
{...props}
/>
);
}
+const tabsListVariants = cva(
+ "rounded-none p-[3px] group-data-horizontal/tabs:h-8 data-[variant=line]:rounded-none group/tabs-list text-muted-foreground inline-flex w-fit items-center justify-center group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col",
+ {
+ variants: {
+ variant: {
+ default: "bg-muted",
+ line: "gap-1 bg-transparent",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+ },
+);
+
function TabsList({
className,
+ variant = "default",
...props
-}: React.ComponentProps<typeof TabsPrimitive.List>) {
+}: TabsPrimitive.List.Props & VariantProps<typeof tabsListVariants>) {
return (
<TabsPrimitive.List
data-slot="tabs-list"
- className={cn(
- "bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px]",
- className,
- )}
+ data-variant={variant}
+ className={cn(tabsListVariants({ variant }), className)}
{...props}
/>
);
}
-function TabsTrigger({
- className,
- ...props
-}: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
+function TabsTrigger({ className, ...props }: TabsPrimitive.Tab.Props) {
return (
- <TabsPrimitive.Trigger
+ <TabsPrimitive.Tab
data-slot="tabs-trigger"
className={cn(
- "data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
+ "gap-1.5 rounded-none border border-transparent px-1.5 py-0.5 text-xs font-medium group-data-vertical/tabs:py-[calc(--spacing(1.25))] [&_svg:not([class*='size-'])]:size-4 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring text-foreground/60 hover:text-foreground dark:text-muted-foreground dark:hover:text-foreground relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center whitespace-nowrap transition-all group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
+ "group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent",
+ "data-active:bg-background dark:data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 data-active:text-foreground",
+ "after:bg-foreground after:absolute after:opacity-0 after:transition-opacity group-data-horizontal/tabs:after:inset-x-0 group-data-horizontal/tabs:after:bottom-[-5px] group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-0 group-data-vertical/tabs:after:-right-1 group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100",
className,
)}
{...props}
@@ -50,17 +67,14 @@ function TabsTrigger({
);
}
-function TabsContent({
- className,
- ...props
-}: React.ComponentProps<typeof TabsPrimitive.Content>) {
+function TabsContent({ className, ...props }: TabsPrimitive.Panel.Props) {
return (
- <TabsPrimitive.Content
+ <TabsPrimitive.Panel
data-slot="tabs-content"
- className={cn("flex-1 outline-none", className)}
+ className={cn("text-xs/relaxed flex-1 outline-none", className)}
{...props}
/>
);
}
-export { Tabs, TabsList, TabsTrigger, TabsContent };
+export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants };
diff --git a/packages/ui-new/src/components/ui/textarea.tsx b/packages/ui-new/src/components/ui/textarea.tsx
index 4f6221b..3c3e5d0 100644
--- a/packages/ui-new/src/components/ui/textarea.tsx
+++ b/packages/ui-new/src/components/ui/textarea.tsx
@@ -7,7 +7,7 @@ function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
<textarea
data-slot="textarea"
className={cn(
- "border-input placeholder: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 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
+ "border-input dark:bg-input/30 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:aria-invalid:border-destructive/50 disabled:bg-input/50 dark:disabled:bg-input/80 rounded-none border bg-transparent px-2.5 py-2 text-xs transition-colors focus-visible:ring-1 aria-invalid:ring-1 md:text-xs placeholder:text-muted-foreground flex field-sizing-content min-h-16 w-full outline-none disabled:cursor-not-allowed disabled:opacity-50",
className,
)}
{...props}
diff --git a/packages/ui-new/src/index.css b/packages/ui-new/src/index.css
index 917b793..8803e5e 100644
--- a/packages/ui-new/src/index.css
+++ b/packages/ui-new/src/index.css
@@ -1,5 +1,6 @@
@import "tailwindcss";
@import "tw-animate-css";
+@import "shadcn/tailwind.css";
@custom-variant dark (&:is(.dark *));
@@ -122,179 +123,4 @@
body {
@apply bg-background text-foreground;
}
-
- ::selection {
- @apply bg-indigo-500/30;
- }
-
- /* Custom Scrollbar */
- * {
- scrollbar-width: thin;
- scrollbar-color: #3f3f46 transparent;
- }
-
- ::-webkit-scrollbar {
- width: 8px;
- height: 8px;
- }
-
- ::-webkit-scrollbar-track {
- background: transparent;
- }
-
- ::-webkit-scrollbar-thumb {
- background-color: #3f3f46;
- border-radius: 4px;
- border: 2px solid transparent;
- background-clip: content-box;
- }
-
- ::-webkit-scrollbar-thumb:hover {
- background-color: #52525b;
- }
-
- ::-webkit-scrollbar-corner {
- background: transparent;
- }
-
- /* Input/Form Element Consistency */
- input[type="text"],
- input[type="number"],
- input[type="password"],
- input[type="email"],
- textarea {
- background-color: rgba(0, 0, 0, 0.4);
- border: 1px solid rgba(255, 255, 255, 0.1);
- transition:
- border-color 0.2s ease,
- box-shadow 0.2s ease;
- }
-
- input[type="text"]:focus,
- input[type="number"]:focus,
- input[type="password"]:focus,
- input[type="email"]:focus,
- textarea:focus {
- border-color: rgba(99, 102, 241, 0.5);
- box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.1);
- outline: none;
- }
-
- /* Number input - hide spinner */
- input[type="number"]::-webkit-outer-spin-button,
- input[type="number"]::-webkit-inner-spin-button {
- -webkit-appearance: none;
- margin: 0;
- }
-
- input[type="number"] {
- appearance: textfield;
- -moz-appearance: textfield;
- }
-
- /* Checkbox Styling */
- input[type="checkbox"] {
- appearance: none;
- width: 16px;
- height: 16px;
- border: 1px solid #3f3f46;
- border-radius: 4px;
- background-color: #18181b;
- cursor: pointer;
- position: relative;
- transition: all 0.15s ease;
- }
-
- input[type="checkbox"]:hover {
- border-color: #52525b;
- }
-
- input[type="checkbox"]:checked {
- background-color: #4f46e5;
- border-color: #4f46e5;
- }
-
- input[type="checkbox"]:checked::after {
- content: "";
- position: absolute;
- left: 5px;
- top: 2px;
- width: 4px;
- height: 8px;
- border: solid white;
- border-width: 0 2px 2px 0;
- transform: rotate(45deg);
- }
-
- input[type="checkbox"]:focus {
- outline: none;
- box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.3);
- }
-
- /* Custom Select/Dropdown Styles */
- select {
- appearance: none;
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%2371717a'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: right 0.5rem center;
- background-size: 1rem;
- padding-right: 2rem;
- }
-
- /* Option styling - works in WebView/Chromium */
- select option {
- background-color: #18181b;
- color: #e4e4e7;
- padding: 12px 16px;
- font-size: 13px;
- border: none;
- }
-
- select option:hover,
- select option:focus {
- background-color: #3730a3 !important;
- color: white !important;
- }
-
- select option:checked {
- background: linear-gradient(0deg, #4f46e5 0%, #4f46e5 100%);
- color: white;
- font-weight: 500;
- }
-
- select option:disabled {
- color: #52525b;
- background-color: #18181b;
- }
-
- /* Optgroup styling */
- select optgroup {
- background-color: #18181b;
- color: #a1a1aa;
- font-weight: 600;
- font-size: 11px;
- text-transform: uppercase;
- letter-spacing: 0.05em;
- padding: 8px 12px 4px;
- }
-
- /* Select focus state */
- select:focus {
- outline: none;
- border-color: #6366f1;
- box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2);
- }
-
- /* Global body styles from App.svelte */
- body {
- margin: 0;
- padding: 0;
- background: #000;
- }
-
- /* Window Drag Region */
- .drag-region {
- -webkit-app-region: drag;
- app-region: drag;
- }
}
diff --git a/packages/ui-new/src/pages/index.tsx b/packages/ui-new/src/pages/index.tsx
index 180cf0c..2b3c2b2 100644
--- a/packages/ui-new/src/pages/index.tsx
+++ b/packages/ui-new/src/pages/index.tsx
@@ -70,7 +70,7 @@ export function IndexPage() {
<img
src={settingsStore.settings.customBackgroundPath}
alt="Background"
- className="absolute inset-0 w-full h-full object-cover transition-transform duration-[20s] ease-linear hover:scale-105"
+ className="absolute inset-0 w-full h-full object-cover transition-transform duration-[20s] ease-linear"
onError={(e) => console.error("Failed to load main background:", e)}
/>
)}
diff --git a/packages/ui-new/tsconfig.app.json b/packages/ui-new/tsconfig.app.json
index ce9121a..54f0bdf 100644
--- a/packages/ui-new/tsconfig.app.json
+++ b/packages/ui-new/tsconfig.app.json
@@ -27,8 +27,8 @@
/* Paths */
"baseUrl": ".",
"paths": {
- "@/*": ["./src/*"],
- },
+ "@/*": ["./src/*"]
+ }
},
- "include": ["src"],
+ "include": ["src"]
}